Compare commits

..

22 Commits

Author SHA1 Message Date
github-actions[bot]
fa1a9da23a
Improve stock item tracking API query (#7451) (#7453)
* Improve stock item tracking API query

- Cache related model lookups into single DB queries
- Significant improvements to query speed
- Ref: https://github.com/inventree/InvenTree/issues/7429

* Handle case where item does not exist in DB

(cherry picked from commit 79ea6897ea1cff61af00f6077f98702b223e0af7)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-06-16 18:54:11 +10:00
github-actions[bot]
fe09437214
Fix for gunicorn command (#7450) (#7452)
* Fix for gunicorn command

* Allow override of worker count

(cherry picked from commit 49f6981f463ca7b3c1808f36cccad3e0dcbecfc3)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-06-16 16:25:06 +10:00
github-actions[bot]
f1dfced89b
fix: Add installer check for python version (#7440) (#7441)
* fix: Add installer check for python version

Closes #7439
Closes #7437
Closes #7377

* fix error message

* Add color

(cherry picked from commit 960c27b1421d5abf9d85e8cdb30f058f72047e45)

Co-authored-by: Matthias Mair <code@mjmair.com>
2024-06-14 08:33:55 +10:00
github-actions[bot]
d7c76aab9d
Update link for mobile app docs (#7378) (#7381)
(cherry picked from commit 74f4b85dfd4f350db32f17d9a6fef5c9d46e0154)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-05-31 17:07:47 +10:00
github-actions[bot]
dfdaddbc7e
Catch edge case for merge_stock_items: (#7373) (#7374)
* Catch edge case for merge_stock_items:

- Use current location as backup
- Handle null location

* Fix deltas

(cherry picked from commit 9fa2735f7a357d00ada648d4b8c1ba463742e0d2)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-05-30 20:13:28 +10:00
github-actions[bot]
1f6e52138a
Plugin reload fix (#7361) (#7362)
- call registry.check_reload when registering an event
- ensure that latest versions of plugins are loaded

(cherry picked from commit 5577a086c9c4fc18e65adaee9c928b217c9a1f0f)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-05-28 01:10:36 +10:00
Oliver
e8c9ec076c
Update version.py (#7353)
Bump version to 0.15.4
2024-05-27 20:16:07 +10:00
Oliver
d4d9aa9d1b
Fixes for installer (#7344) (#7350)
* - move reqs file to contrib
- detect previously used python version
- safe extra requirements to INSTALLER_EXTRA

* add missing fi

* move site setting

Co-authored-by: Matthias Mair <code@mjmair.com>
2024-05-27 19:45:38 +10:00
github-actions[bot]
54f2072e97
Fix for 'restore' command (#7348) (#7349)
- Fix typo

(cherry picked from commit bda237a13fb335c34c5afbb54630c66d82a64cd8)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-05-27 17:11:55 +10:00
github-actions[bot]
d1042cde0e
Update docs (#7339) (#7340)
- Add note about permission denied error

(cherry picked from commit 5f9348f56d594b7215fbb2e374a9556709b85dd2)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-05-26 21:50:11 +10:00
github-actions[bot]
5f4275679d
PUI: Don't load stock test results for non-trackable part (#7327) (#7337)
(cherry picked from commit e8e64616da22300f501553eae38e9d711eb0d52d)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-05-26 20:54:45 +10:00
Oliver
1ba0bee1ea
Update version.py (#7328)
Bump version number to 0.15.3
2024-05-26 20:50:45 +10:00
Oliver
ea7aa93a28
Merge pull request from GHSA-2crp-q9pc-457j (#7320)
* Merge pull request from GHSA-2crp-q9pc-457j

* ensure API login only works if mfa is not required

* add migration to log out users

* add migration to clear users

* Use `UV_SYSTEM_PYTHON` to allow the system Python interpreter instead of `VIRTUAL_ENV` (#7317)

* Fix docs links - pin to same branch

* Handle exception on migration

* Make migration non-atomic

---------

Co-authored-by: Matthias Mair <code@mjmair.com>
Co-authored-by: Zanie Blue <contact@zanie.dev>
2024-05-24 23:36:00 +10:00
github-actions[bot]
9eccf69456
Add Meta subclass for build serializers (#7315) (#7316)
Ref: https://github.com/inventree/InvenTree/discussions/7314
(cherry picked from commit 0d46af7a74aa79bd69d05a14c1406dfa92f981b6)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-05-24 09:21:40 +10:00
github-actions[bot]
9cebfa85df
Add clearer error message for invalid SITE_URL (#7311) (#7312)
(cherry picked from commit 2fafb7f21cd3b01bf6a2b2a399c81bf64bbb184a)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-05-23 23:43:54 +10:00
github-actions[bot]
af3cf62b8e
fix: SELinux labels for Caddyfile (#7261) (#7262)
(cherry picked from commit b26640fb36a4447339f2bd944decc86d0bef1768)

Co-authored-by: Philipp Fruck <dev@p-fruck.de>
2024-05-20 09:14:57 +10:00
Oliver
f20a1245e7
Update version.py (#7252)
Bump version number to 0.15.2
2024-05-17 13:45:45 +10:00
github-actions[bot]
92a4989a8d
Fix for email template (#7249) (#7251)
- Use `line.part` instead of `part`

(cherry picked from commit 2431fc6d582978dc28c7caf23d65f2cc7af8162f)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-05-17 13:44:32 +10:00
github-actions[bot]
be3b22ce36
Docker fix (#7228) (#7229)
* Copy requirements file

* Test more files when building docker image

* Refactor install task

* Raise exception

* Run install task

* Fix typos

- The tests work!

(cherry picked from commit 2265055785c7e841219a30d1af7bac310c36bb72)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-05-15 09:24:22 +10:00
Oliver
258b8e4ecc
Update version.py
Bump version to 0.15.1
2024-05-15 09:20:13 +10:00
github-actions[bot]
7df92aad03
Fix permissions for release.yaml (#7220) (#7221)
* Fix permissions for release.yaml

- 0.15.0 release currently borked

* Move permissions to individual job targets

(cherry picked from commit 3eae5096e337a2f3e19f95d0a30a385c0291536d)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-05-14 22:11:39 +10:00
Oliver
2dac705779
Mark as release version (#7217) 2024-05-14 21:45:42 +10:00
915 changed files with 254122 additions and 418941 deletions

View File

@ -1,3 +1,5 @@
version: "3"
services:
db:
image: postgres:13
@ -11,12 +13,6 @@ services:
POSTGRES_USER: inventree_user
POSTGRES_PASSWORD: inventree_password
redis:
image: redis:7.0
restart: always
expose:
- 6379
inventree:
build:
context: ..
@ -35,8 +31,6 @@ services:
INVENTREE_DB_HOST: db
INVENTREE_DB_USER: inventree_user
INVENTREE_DB_PASSWORD: inventree_password
INVENTREE_CACHE_HOST: redis
INVENTREE_CACHE_PORT: 6379
INVENTREE_PLUGINS_ENABLED: True
INVENTREE_SITE_URL: http://localhost:8000
INVENTREE_CORS_ORIGIN_ALLOW_ALL: True

4
.github/FUNDING.yml vendored
View File

@ -1,3 +1,5 @@
polar: inventree
github: inventree
ko_fi: inventree
patreon: inventree
polar: inventree
custom: [paypal.me/inventree]

View File

@ -1 +0,0 @@
blank_issues_enabled: false

View File

@ -13,5 +13,5 @@ runs:
invoke export-records -f data.json
python3 ./src/backend/InvenTree/manage.py flush --noinput
invoke migrate
invoke import-records -c -f data.json
invoke import-records -c -f data.json
invoke import-records -f data.json
invoke import-records -f data.json

View File

@ -44,11 +44,6 @@ runs:
with:
python-version: ${{ env.python_version }}
cache: pip
cache-dependency-path: |
src/backend/requirements.txt
src/backend/requirements-dev.txt
contrib/container/requirements.txt
contrib/dev_reqs/requirements.txt
- name: Install Base Python Dependencies
if: ${{ inputs.python == 'true' }}
shell: bash
@ -88,7 +83,7 @@ runs:
# Invoke commands
- name: Install dev requirements
if: ${{ inputs.dev-install == 'true' || inputs.install == 'true' }}
if: ${{ inputs.dev-install == 'true' ||inputs.install == 'true' }}
shell: bash
run: uv pip install --require-hashes -r src/backend/requirements-dev.txt
- name: Run invoke install
@ -98,4 +93,4 @@ runs:
- name: Run invoke update
if: ${{ inputs.update == 'true' }}
shell: bash
run: invoke update --uv --skip-backup --skip-static
run: invoke update --uv

View File

@ -15,11 +15,22 @@ updates:
interval: weekly
- package-ecosystem: pip
directories:
- /contrib/container
- /docs
- /contrib/dev_reqs
- /src/backend
directory: /contrib/container
schedule:
interval: weekly
- package-ecosystem: pip
directory: /docs
schedule:
interval: weekly
- package-ecosystem: pip
directory: /.github
schedule:
interval: weekly
- package-ecosystem: pip
directory: /src/backend
schedule:
interval: weekly
groups:
@ -28,9 +39,16 @@ updates:
- "*" # Include all dependencies
- package-ecosystem: npm
directories:
- /src/frontend
- /src/backend
directory: /src/backend
schedule:
interval: weekly
groups:
dependencies:
patterns:
- "*" # Include all dependencies
- package-ecosystem: npm
directory: /src/frontend
schedule:
interval: weekly
groups:

View File

@ -71,7 +71,7 @@ def check_prohibited_tags(data):
for filename in pathlib.Path(js_i18n_dir).rglob('*.js'):
print(f"Checking file 'translated/{os.path.basename(filename)}':")
with open(filename, encoding='utf-8') as js_file:
with open(filename, 'r') as js_file:
data = js_file.readlines()
errors += check_invalid_tag(data)
@ -81,7 +81,7 @@ for filename in pathlib.Path(js_dynamic_dir).rglob('*.js'):
print(f"Checking file 'dynamic/{os.path.basename(filename)}':")
# Check that the 'dynamic' files do not contains any translated strings
with open(filename, encoding='utf-8') as js_file:
with open(filename, 'r') as js_file:
data = js_file.readlines()
invalid_tags = ['blocktrans', 'blocktranslate', 'trans', 'translate']

View File

@ -20,9 +20,9 @@ for line in str(out.decode()).split('\n'):
if len(migrations) == 0:
sys.exit(0)
print(f'There are {len(migrations)} unstaged migration files:')
print('There are {n} unstaged migration files:'.format(n=len(migrations)))
for m in migrations:
print(f' - {m}')
print(' - {m}'.format(m=m))
sys.exit(len(migrations))

View File

@ -10,7 +10,6 @@ tagged branch:
"""
import itertools
import json
import os
import re
@ -19,11 +18,8 @@ from pathlib import Path
import requests
REPO = os.getenv('GITHUB_REPOSITORY', 'inventree/inventree')
GITHUB_API_URL = os.getenv('GITHUB_API_URL', 'https://api.github.com')
def get_existing_release_tags(include_prerelease=True):
def get_existing_release_tags():
"""Request information on existing releases via the GitHub API."""
# Check for github token
token = os.getenv('GITHUB_TOKEN', None)
@ -32,7 +28,9 @@ def get_existing_release_tags(include_prerelease=True):
if token:
headers = {'Authorization': f'Bearer {token}'}
response = requests.get(f'{GITHUB_API_URL}/repos/{REPO}/releases', headers=headers)
response = requests.get(
'https://api.github.com/repos/inventree/inventree/releases', headers=headers
)
if response.status_code != 200:
raise ValueError(
@ -52,9 +50,6 @@ def get_existing_release_tags(include_prerelease=True):
print(f"Version '{tag}' did not match expected pattern")
continue
if not include_prerelease and release['prerelease']:
continue
tags.append([int(x) for x in match.groups()])
return tags
@ -78,7 +73,7 @@ def check_version_number(version_string, allow_duplicate=False):
version_tuple = [int(x) for x in match.groups()]
# Look through the existing releases
existing = get_existing_release_tags(include_prerelease=False)
existing = get_existing_release_tags()
# Assume that this is the highest release, unless told otherwise
highest_release = True
@ -89,17 +84,12 @@ def check_version_number(version_string, allow_duplicate=False):
if release > version_tuple:
highest_release = False
print(f'Found newer release: {release!s}')
print(f'Found newer release: {str(release)}')
return highest_release
if __name__ == '__main__':
# Ensure that we are running in GH Actions
if os.environ.get('GITHUB_ACTIONS', '') != 'true':
print('This script is intended to be run within a GitHub Action!')
sys.exit(1)
if 'only_version' in sys.argv:
here = Path(__file__).parent.absolute()
version_file = here.joinpath(
@ -107,18 +97,16 @@ if __name__ == '__main__':
)
text = version_file.read_text()
results = re.findall(r"""INVENTREE_API_VERSION = (.*)""", text)
# If 2. args is true lower the version number by 1
if len(sys.argv) > 2 and sys.argv[2] == 'true':
results[0] = str(int(results[0]) - 1)
print(results[0])
exit(0)
# GITHUB_REF_TYPE may be either 'branch' or 'tag'
GITHUB_REF_TYPE = os.environ['GITHUB_REF_TYPE']
# GITHUB_REF may be either 'refs/heads/<branch>' or 'refs/heads/<tag>'
GITHUB_REF = os.environ['GITHUB_REF']
GITHUB_REF_NAME = os.environ['GITHUB_REF_NAME']
GITHUB_BASE_REF = os.environ['GITHUB_BASE_REF']
# Print out version information, makes debugging actions *much* easier!
@ -134,7 +122,7 @@ if __name__ == '__main__':
version = None
with open(version_file, encoding='utf-8') as f:
with open(version_file, 'r') as f:
text = f.read()
# Extract the InvenTree software version
@ -175,7 +163,10 @@ if __name__ == '__main__':
print(f"Version number '{version}' does not match tag '{version_tag}'")
sys.exit
docker_tags = [version_tag, 'stable'] if highest_release else [version_tag]
if highest_release:
docker_tags = [version_tag, 'stable']
else:
docker_tags = [version_tag]
elif GITHUB_REF_TYPE == 'branch':
# Otherwise we know we are targeting the 'master' branch
@ -196,13 +187,10 @@ if __name__ == '__main__':
print(f"Version check passed for '{version}'!")
print(f"Docker tags: '{docker_tags}'")
target_repos = [REPO.lower(), f'ghcr.io/{REPO.lower()}']
# Ref: https://getridbug.com/python/how-to-set-environment-variables-in-github-actions-using-python/
with open(os.getenv('GITHUB_ENV'), 'a', encoding='utf-8') as env_file:
with open(os.getenv('GITHUB_ENV'), 'a') as env_file:
# Construct tag string
tag_list = [[f'{r}:{t}' for t in docker_tags] for r in target_repos]
tags = ','.join(itertools.chain(*tag_list))
tags = ','.join([f'inventree/inventree:{tag}' for tag in docker_tags])
env_file.write(f'docker_tags={tags}\n')

View File

@ -30,7 +30,7 @@ jobs:
steps:
- name: Checkout Code
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
- name: Environment Setup
uses: ./.github/actions/setup
with:

View File

@ -39,7 +39,7 @@ jobs:
docker: ${{ steps.filter.outputs.docker }}
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # pin@v3.0.2
id: filter
with:
@ -66,9 +66,9 @@ jobs:
steps:
- name: Check out repo
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
- name: Set Up Python ${{ env.python_version }}
uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f # pin@v5.1.1
uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # pin@v5.1.0
with:
python-version: ${{ env.python_version }}
- name: Version Check
@ -115,40 +115,39 @@ jobs:
- name: Run Unit Tests
run: |
echo "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" >> contrib/container/docker.dev.env
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run --rm inventree-dev-server invoke test --disable-pty
- name: Run Migration Tests
run: |
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run --rm inventree-dev-server invoke test --migrations
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke test --disable-pty
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke test --migrations --disable-pty
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml down
- name: Clean up test folder
run: |
rm -rf InvenTree/_testfolder
- name: Set up QEMU
if: github.event_name != 'pull_request'
uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # pin@v3.2.0
uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # pin@v3.0.0
- name: Set up Docker Buildx
if: github.event_name != 'pull_request'
uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # pin@v3.6.1
uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # pin@v3.3.0
- name: Set up cosign
if: github.event_name != 'pull_request'
uses: sigstore/cosign-installer@4959ce089c160fddf62f7b42464195ba1a56d382 # pin@v3.6.0
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # pin@v3.5.0
- name: Check if Dockerhub login is required
id: docker_login
run: |
if [ -z "${{ secrets.DOCKER_USERNAME }}" ]; then
echo "skip_dockerhub_login=true" >> $GITHUB_OUTPUT
echo "skip_dockerhub_login=true" >> $GITHUB_ENV
else
echo "skip_dockerhub_login=false" >> $GITHUB_OUTPUT
echo "skip_dockerhub_login=false" >> $GITHUB_ENV
fi
- name: Login to Dockerhub
if: github.event_name != 'pull_request' && steps.docker_login.outputs.skip_dockerhub_login != 'true'
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # pin@v3.3.0
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # pin@v3.1.0
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Log into registry ghcr.io
if: github.event_name != 'pull_request'
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # pin@v3.3.0
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # pin@v3.1.0
with:
registry: ghcr.io
username: ${{ github.actor }}
@ -166,7 +165,7 @@ jobs:
- name: Push Docker Images
id: push-docker
if: github.event_name != 'pull_request'
uses: docker/build-push-action@5cd11c3a4ced054e52742c5fd54dca954e0edd85 # pin@v6.7.0
uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # pin@v5.3.0
with:
context: .
file: ./contrib/container/Dockerfile

View File

@ -10,9 +10,11 @@ on:
env:
python_version: 3.9
node_version: 20
node_version: 18
# The OS version must be set per job
server_start_sleep: 60
requests_version: 2.31.0
pyyaml_version: 6.0.1
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
INVENTREE_DB_ENGINE: sqlite3
@ -38,7 +40,7 @@ jobs:
force: ${{ steps.force.outputs.force }}
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # pin@v3.0.2
id: filter
with:
@ -70,7 +72,7 @@ jobs:
needs: ["pre-commit"]
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
- name: Environment Setup
uses: ./.github/actions/setup
with:
@ -92,9 +94,9 @@ jobs:
if: needs.paths-filter.outputs.server == 'true' || needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.force == 'true'
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
- name: Set up Python ${{ env.python_version }}
uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f # pin@v5.1.1
uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # pin@v5.1.0
with:
python-version: ${{ env.python_version }}
cache: "pip"
@ -113,9 +115,9 @@ jobs:
steps:
- name: Checkout Code
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
- name: Set up Python ${{ env.python_version }}
uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f # pin@v5.1.1
uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # pin@v5.1.0
with:
python-version: ${{ env.python_version }}
- name: Check Config
@ -149,7 +151,7 @@ jobs:
version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
- name: Environment Setup
uses: ./.github/actions/setup
with:
@ -159,32 +161,20 @@ jobs:
- name: Export API Documentation
run: invoke schema --ignore-warnings --filename src/backend/InvenTree/schema.yml
- name: Upload schema
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # pin@v4.3.6
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # pin@v4.3.3
with:
name: schema.yml
path: src/backend/InvenTree/schema.yml
- name: Download public schema
if: needs.paths-filter.outputs.api == 'false'
run: |
pip install --require-hashes -r contrib/dev_reqs/requirements.txt >/dev/null 2>&1
version="$(python3 .github/scripts/version_check.py only_version ${{ needs.paths-filter.outputs.api }} 2>&1)"
version="$(python3 .github/scripts/version_check.py only_version 2>&1)"
echo "Version: $version"
url="https://raw.githubusercontent.com/inventree/schema/main/export/${version}/api.yaml"
echo "URL: $url"
code=$(curl -s -o api.yaml $url --write-out '%{http_code}' --silent)
if [ "$code" != "200" ]; then
exit 1
fi
curl -s -o api.yaml $url
echo "Downloaded api.yaml"
- name: Running OpenAPI Spec diff action
id: breaking_changes
uses: oasdiff/oasdiff-action/diff@a2ff6682b27d175162a74c09ace8771bd3d512f8 # pin@main
with:
base: 'api.yaml'
revision: 'src/backend/InvenTree/schema.yml'
format: 'html'
- name: Echoing diff to step
run: echo "${{ steps.breaking_changes.outputs.diff }}" >> $GITHUB_STEP_SUMMARY
- name: Check for differences in API Schema
if: needs.paths-filter.outputs.api == 'false'
run: |
@ -211,13 +201,12 @@ jobs:
version: ${{ needs.schema.outputs.version }}
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
name: Checkout Code
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
with:
repository: inventree/schema
token: ${{ secrets.SCHEMA_PAT }}
- name: Download schema artifact
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
with:
name: schema.yml
- name: Move schema to correct location
@ -226,9 +215,8 @@ jobs:
mkdir export/${version}
mv schema.yml export/${version}/api.yaml
- uses: stefanzweifel/git-auto-commit-action@8621497c8c39c72f3e2a999a26b4ca1b5058a842 # v5.0.1
name: Commit schema changes
with:
commit_message: "Update API schema for ${{ env.version }} / ${{ github.sha }}"
commit_message: "Update API schema for ${version}"
python:
name: Tests - inventree-python
@ -250,7 +238,7 @@ jobs:
INVENTREE_SITE_URL: http://127.0.0.1:12345
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
- name: Environment Setup
uses: ./.github/actions/setup
with:
@ -281,8 +269,7 @@ jobs:
continue-on-error: true # continue if a step fails so that coverage gets pushed
strategy:
matrix:
python_version: [3.9]
# python_version: [3.9, 3.12] # Disabled due to requirement issues
python_version: [3.9, 3.12]
env:
INVENTREE_DB_NAME: ./inventree.sqlite
@ -292,7 +279,7 @@ jobs:
python_version: ${{ matrix.python_version }}
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
- name: Environment Setup
uses: ./.github/actions/setup
with:
@ -308,7 +295,7 @@ jobs:
- name: Coverage Tests
run: invoke test --coverage
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # pin@v4.5.0
uses: codecov/codecov-action@5ecb98a3c6b747ed38dc09f787459979aebb39be # pin@v4.3.1
if: always()
with:
token: ${{ secrets.CODECOV_TOKEN }}
@ -346,7 +333,7 @@ jobs:
- 6379:6379
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
- name: Environment Setup
uses: ./.github/actions/setup
with:
@ -390,7 +377,7 @@ jobs:
- 3306:3306
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
- name: Environment Setup
uses: ./.github/actions/setup
with:
@ -429,7 +416,7 @@ jobs:
- 5432:5432
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
- name: Environment Setup
uses: ./.github/actions/setup
with:
@ -440,7 +427,7 @@ jobs:
- name: Run Tests
run: invoke test --migrations --report --coverage
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # pin@v4.5.0
uses: codecov/codecov-action@5ecb98a3c6b747ed38dc09f787459979aebb39be # pin@v4.3.1
if: always()
with:
token: ${{ secrets.CODECOV_TOKEN }}
@ -460,7 +447,7 @@ jobs:
INVENTREE_PLUGINS_ENABLED: false
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
name: Checkout Code
- name: Environment Setup
uses: ./.github/actions/setup
@ -517,7 +504,7 @@ jobs:
VITE_COVERAGE: true
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
- name: Environment Setup
uses: ./.github/actions/setup
with:
@ -535,7 +522,7 @@ jobs:
- name: Run Playwright tests
id: tests
run: cd src/frontend && npx nyc playwright test
- uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # pin@v4
- uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # pin@v4
if: ${{ !cancelled() && steps.tests.outcome == 'failure' }}
with:
name: playwright-report
@ -545,7 +532,7 @@ jobs:
if: always()
run: cd src/frontend && npx nyc report --report-dir ./coverage --temp-dir .nyc_output --reporter=lcov --exclude-after-remap false
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # pin@v4.5.0
uses: codecov/codecov-action@5ecb98a3c6b747ed38dc09f787459979aebb39be # pin@v4.3.1
if: always()
with:
token: ${{ secrets.CODECOV_TOKEN }}
@ -558,7 +545,7 @@ jobs:
timeout-minutes: 60
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
- name: Environment Setup
uses: ./.github/actions/setup
with:
@ -567,13 +554,11 @@ jobs:
run: cd src/frontend && yarn install
- name: Build frontend
run: cd src/frontend && yarn run compile && yarn run build
- name: Write version file - SHA
run: cd src/backend/InvenTree/web/static/web/.vite && echo "$GITHUB_SHA" > sha.txt
- name: Zip frontend
run: |
cd src/backend/InvenTree/web/static
zip -r frontend-build.zip web/ web/.vite
- uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # pin@v4.3.6
- uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # pin@v4.3.3
with:
name: frontend-build
path: src/backend/InvenTree/web/static/web

View File

@ -1,16 +1,13 @@
# Runs on releases
name: Publish release
name: Publish release notes
on:
release:
types: [published]
permissions:
contents: read
jobs:
stable:
runs-on: ubuntu-latest
name: Write release to stable branch
permissions:
contents: write
pull-requests: write
@ -18,7 +15,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Checkout Code
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
- name: Version Check
run: |
pip install --require-hashes -r contrib/dev_reqs/requirements.txt
@ -31,15 +28,13 @@ jobs:
branch: stable
force: true
build:
publish-build:
runs-on: ubuntu-latest
name: Build and attest frontend
permissions:
id-token: write
contents: write
attestations: write
pull-requests: write
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
- name: Environment Setup
uses: ./.github/actions/setup
with:
@ -48,38 +43,14 @@ jobs:
run: cd src/frontend && yarn install
- name: Build frontend
run: cd src/frontend && npm run compile && npm run build
- name: Create SBOM for frontend
uses: anchore/sbom-action@61119d458adab75f756bc0b9e4bde25725f86a7a # pin@v0
with:
artifact-name: frontend-build.spdx
path: src/frontend
- name: Write version file - SHA
run: cd src/backend/InvenTree/web/static/web/.vite && echo "$GITHUB_SHA" > sha.txt
- name: Write version file - TAG
run: cd src/backend/InvenTree/web/static/web/.vite && echo "${{ github.ref_name }}" > tag.txt
- name: Zip frontend
run: |
cd src/backend/InvenTree/web/static/web
zip -r ../frontend-build.zip * .vite
- name: Attest Build Provenance
id: attest
uses: actions/attest-build-provenance@6149ea5740be74af77f260b9db67e633f6b0a9a1 # pin@v1
with:
subject-path: "${{ github.workspace }}/src/backend/InvenTree/web/static/frontend-build.zip"
- name: Upload frontend
uses: svenstaro/upload-release-action@04733e069f2d7f7f0b4aebc4fbdbce8613b03ccd # pin@2.9.0
zip -r ../frontend-build.zip *
- uses: svenstaro/upload-release-action@04733e069f2d7f7f0b4aebc4fbdbce8613b03ccd # pin@2.9.0
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: src/backend/InvenTree/web/static/frontend-build.zip
asset_name: frontend-build.zip
tag: ${{ github.ref }}
overwrite: true
- name: Upload Attestation
uses: svenstaro/upload-release-action@04733e069f2d7f7f0b4aebc4fbdbce8613b03ccd # pin@2.9.0
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
asset_name: frontend-build.intoto.jsonl
file: ${{ steps.attest.outputs.bundle-path}}
tag: ${{ github.ref }}
overwrite: true

View File

@ -32,12 +32,12 @@ jobs:
steps:
- name: "Checkout code"
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3
with:
results_file: results.sarif
results_format: sarif
@ -59,7 +59,7 @@ jobs:
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
name: SARIF file
path: results.sarif
@ -67,6 +67,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@2c779ab0d087cd7fe7b826087247c2c81f27bfa6 # v3.26.5
uses: github/codeql-action/upload-sarif@b7cec7526559c32f1616476ff32d17ba4c59b2d6 # v3.25.5
with:
sarif_file: results.sarif

View File

@ -7,17 +7,16 @@ on:
env:
python_version: 3.9
node_version: 20
node_version: 18
permissions:
contents: read
jobs:
synchronize-with-crowdin:
build:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -31,7 +30,7 @@ jobs:
steps:
- name: Checkout Code
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
- name: Environment Setup
uses: ./.github/actions/setup
with:
@ -40,29 +39,16 @@ jobs:
apt-dependency: gettext
- name: Make Translations
run: invoke translate
- name: Remove compiled static files
run: rm -rf src/backend/InvenTree/static
- name: Remove all local changes that are not *.po files
- name: Commit files
run: |
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add src/backend/InvenTree/locale/en/LC_MESSAGES/django.po src/frontend/src/locales/en/messages.po
git commit -m "add translations"
git reset --hard
git reset HEAD~
- name: crowdin action
uses: crowdin/github-action@6ed209d411599a981ccb978df3be9dc9b8a81699 # pin@v2
git checkout -b l10_local
git add "*.po"
git commit -m "updated translation base"
- name: Push changes
uses: ad-m/github-push-action@d91a481090679876dfc4178fef17f286781251df # pin@v0.8.0
with:
upload_sources: true
upload_translations: false
download_translations: true
localization_branch_name: l10_crowdin
create_pull_request: true
pull_request_title: 'New Crowdin updates'
pull_request_body: 'New Crowdin translations by [Crowdin GH Action](https://github.com/crowdin/github-action)'
pull_request_base_branch_name: 'master'
pull_request_labels: 'translations'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: l10
force: true

3
.gitignore vendored
View File

@ -31,7 +31,6 @@ var/
# Django stuff:
*.log
local_settings.py
*.sqlite
*.sqlite3
*.sqlite3-journal
*.backup
@ -109,7 +108,5 @@ src/backend/InvenTree/web/static
InvenTree/web/static
# Generated docs files
docs/schema.yml
docs/docs/api/*.yml
docs/docs/api/schema/*.yml
inventree_settings.json

View File

@ -14,10 +14,7 @@ env:
- INVENTREE_BACKUP_DIR=/opt/inventree/backup
- INVENTREE_PLUGIN_FILE=/opt/inventree/plugins.txt
- INVENTREE_CONFIG_FILE=/opt/inventree/config.yaml
- APP_REPO=inventree/InvenTree
before_install: contrib/packager.io/preinstall.sh
after_install: contrib/packager.io/postinstall.sh
before_remove: contrib/packager.io/preinstall.sh
before:
- contrib/packager.io/before.sh
dependencies:
@ -35,7 +32,7 @@ dependencies:
- gettext
- nginx
- jq
- "libffi7 | libffi8"
- libffi7
targets:
ubuntu-20.04: true
debian-11: true

View File

@ -17,57 +17,52 @@ repos:
- id: check-yaml
- id: mixed-line-ending
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.1
rev: v0.4.1
hooks:
- id: ruff-format
args: [--preview]
- id: ruff
args: [
--fix,
# --unsafe-fixes,
--preview
]
- repo: https://github.com/astral-sh/uv-pre-commit
rev: 0.2.37
rev: 0.1.35
hooks:
- id: pip-compile
name: pip-compile requirements-dev.in
args: [src/backend/requirements-dev.in, -o, src/backend/requirements-dev.txt, --no-strip-extras, --generate-hashes]
args: [src/backend/requirements-dev.in, -o, src/backend/requirements-dev.txt, --python-version=3.9, --no-strip-extras, --generate-hashes]
files: src/backend/requirements-dev\.(in|txt)$
- id: pip-compile
name: pip-compile requirements.txt
args: [src/backend/requirements.in, -o, src/backend/requirements.txt, --no-strip-extras, --generate-hashes]
args: [src/backend/requirements.in, -o, src/backend/requirements.txt,--python-version=3.9, --no-strip-extras,--generate-hashes]
files: src/backend/requirements\.(in|txt)$
- id: pip-compile
name: pip-compile requirements.txt
args: [contrib/dev_reqs/requirements.in, -o, contrib/dev_reqs/requirements.txt, --no-strip-extras, --generate-hashes]
args: [contrib/dev_reqs/requirements.in, -o, contrib/dev_reqs/requirements.txt,--python-version=3.9, --no-strip-extras, --generate-hashes]
files: contrib/dev_reqs/requirements\.(in|txt)$
- id: pip-compile
name: pip-compile requirements.txt
args: [docs/requirements.in, -o, docs/requirements.txt, --no-strip-extras, --generate-hashes]
args: [docs/requirements.in, -o, docs/requirements.txt,--python-version=3.9, --no-strip-extras, --generate-hashes]
files: docs/requirements\.(in|txt)$
- id: pip-compile
name: pip-compile requirements.txt
args: [contrib/container/requirements.in, -o, contrib/container/requirements.txt, --python-version=3.11, --no-strip-extras, --generate-hashes]
args: [contrib/container/requirements.in, -o, contrib/container/requirements.txt,--python-version=3.11, --no-strip-extras, --generate-hashes]
files: contrib/container/requirements\.(in|txt)$
- repo: https://github.com/Riverside-Healthcare/djLint
rev: v1.34.1
hooks:
- id: djlint-django
- repo: https://github.com/codespell-project/codespell
rev: v2.3.0
rev: v2.2.6
hooks:
- id: codespell
additional_dependencies:
- tomli
exclude: >
(?x)^(
docs/docs/stylesheets/.*|
docs/docs/javascripts/.*|
docs/docs/webfonts/.* |
src/frontend/src/locales/.* |
pyproject.toml |
src/frontend/vite.config.ts |
)$
- repo: https://github.com/pre-commit/mirrors-prettier
rev: "v4.0.0-alpha.8"
@ -78,7 +73,7 @@ repos:
- "prettier@^2.4.1"
- "@trivago/prettier-plugin-sort-imports"
- repo: https://github.com/pre-commit/mirrors-eslint
rev: "v9.9.0"
rev: "v9.1.0"
hooks:
- id: eslint
additional_dependencies:
@ -90,7 +85,7 @@ repos:
- "@typescript-eslint/parser"
files: ^src/frontend/.*\.(js|jsx|ts|tsx)$
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.4
rev: v8.18.2
hooks:
- id: gitleaks
#- repo: https://github.com/jumanjihouse/pre-commit-hooks

26
.vscode/launch.json vendored
View File

@ -6,37 +6,19 @@
"configurations": [
{
"name": "InvenTree Server",
"type": "debugpy",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/src/backend/InvenTree/manage.py",
"args": [
"runserver",
// "0.0.0.0:8000", // expose server in network (useful for testing with mobile app)
// "--noreload" // disable auto-reload
],
"django": true,
"justMyCode": true
},
{
"name": "InvenTree Server - Tests",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/src/backend/InvenTree/manage.py",
"args": [
"test",
// "part.test_api.PartCategoryAPITest", // run only a specific test
],
"args": ["runserver"],
"django": true,
"justMyCode": true
},
{
"name": "InvenTree Server - 3rd party",
"type": "debugpy",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/src/backend/InvenTree/manage.py",
"args": [
"runserver"
],
"args": ["runserver"],
"django": true,
"justMyCode": false
},

View File

@ -39,7 +39,7 @@ InvenTree/
│ │ ├─ tsconfig.json # Settings for frontend compilation
├─ .pkgr.yml # Build definition for Debian/Ubuntu packages
├─ .pre-commit-config.yaml # Code formatter/linter configuration
├─ CONTRIBUTING.md # Contribution guidelines and overview
├─ CONTRIBUTING.md # Contirbution guidelines and overview
├─ Procfile # Process definition for Debian/Ubuntu packages
├─ README.md # General project information and overview
├─ runtime.txt # Python runtime settings for Debian/Ubuntu packages build

View File

@ -66,7 +66,7 @@ InvenTree is designed to be **extensible**, and provides multiple options for **
<li><a href="https://www.djangoproject.com/">Django</a></li>
<li><a href="https://www.django-rest-framework.org/">DRF</a></li>
<li><a href="https://django-q.readthedocs.io/">Django Q</a></li>
<li><a href="https://docs.allauth.org/">Django-Allauth</a></li>
<li><a href="https://django-allauth.readthedocs.io/">Django-Allauth</a></li>
</ul>
</details>

View File

@ -3,7 +3,6 @@ coverage:
project:
default:
target: 82%
patch: off
github_checks:
annotations: true

View File

@ -28,7 +28,6 @@ INVENTREE_DB_PASSWORD=pgpassword
# Un-comment the following lines to enable Redis cache
# Note that you will also have to run docker-compose with the --profile redis command
# Refer to settings.py for other cache options
#INVENTREE_CACHE_ENABLED=True
#INVENTREE_CACHE_HOST=inventree-cache
#INVENTREE_CACHE_PORT=6379

View File

@ -11,7 +11,6 @@
ARG base_image=python:3.11-alpine3.18
FROM ${base_image} AS inventree_base
ARG base_image
# Build arguments for this image
ARG commit_tag=""
@ -49,18 +48,13 @@ ENV INVENTREE_BACKGROUND_WORKERS="4"
ENV INVENTREE_WEB_ADDR=0.0.0.0
ENV INVENTREE_WEB_PORT=8000
LABEL org.opencontainers.image.created=${DATE} \
org.opencontainers.image.vendor="inventree" \
org.opencontainers.image.title="InvenTree backend server" \
org.opencontainers.image.description="InvenTree is the open-source inventory management system" \
org.opencontainers.image.url="https://inventree.org" \
org.opencontainers.image.documentation="https://docs.inventree.org" \
org.opencontainers.image.source="https://github.com/inventree/InvenTree" \
org.opencontainers.image.revision=${commit_hash} \
org.opencontainers.image.licenses="MIT" \
org.opencontainers.image.base.name="docker.io/library/${base_image}" \
org.opencontainers.image.version=${commit_tag}
LABEL org.label-schema.schema-version="1.0" \
org.label-schema.build-date=${DATE} \
org.label-schema.vendor="inventree" \
org.label-schema.name="inventree/inventree" \
org.label-schema.url="https://hub.docker.com/r/inventree/inventree" \
org.label-schema.vcs-url="https://github.com/inventree/InvenTree.git" \
org.label-schema.vcs-ref=${commit_tag}
# Install required system level packages
RUN apk add --no-cache \
@ -74,9 +68,8 @@ RUN apk add --no-cache \
# MySQL / MariaDB client
mariadb-client mariadb-connector-c \
&& \
# font support
apk --update --upgrade --no-cache add fontconfig ttf-freefont font-terminus font-noto font-noto-cjk font-noto-extra \
&& fc-cache -f
# fonts
apk --update --upgrade --no-cache add fontconfig ttf-freefont font-noto terminus-font && fc-cache -f
EXPOSE 8000

View File

@ -1,3 +1,5 @@
version: "3.8"
# Docker compose recipe for InvenTree development server
# - Runs PostgreSQL as the database backend
# - Uses built-in django webserver

View File

@ -1,3 +1,5 @@
version: "3.8"
# Docker compose recipe for a production-ready InvenTree setup, with the following containers:
# - PostgreSQL as the database backend
# - gunicorn as the InvenTree web server
@ -51,9 +53,14 @@ services:
restart: unless-stopped
# redis acts as database cache manager
# only runs under the "redis" profile : https://docs.docker.com/compose/profiles/
inventree-cache:
image: redis:7.0
container_name: inventree-cache
depends_on:
- inventree-db
profiles:
- redis
env_file:
- .env
expose:

View File

@ -1,7 +1,7 @@
#!/bin/ash
# Install system packages required for building InvenTree python libraries
# Note that for postgreslql, we use the version 13, which matches the version used in the InvenTree docker image
# 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 \

View File

@ -17,7 +17,6 @@ gunicorn>=22.0.0
# LDAP required packages
django-auth-ldap # Django integration for ldap auth
python-ldap # LDAP auth support
django<5.0 # Force lower to match main project
# Upgraded python package installer
uv

View File

@ -4,24 +4,19 @@ asgiref==3.8.1 \
--hash=sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47 \
--hash=sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590
# via django
django==4.2.15 \
--hash=sha256:61ee4a130efb8c451ef3467c67ca99fdce400fedd768634efc86a68c18d80d30 \
--hash=sha256:c77f926b81129493961e19c0e02188f8d07c112a1162df69bfab178ae447f94a
# via
# -r contrib/container/requirements.in
# django-auth-ldap
django==4.2.11 \
--hash=sha256:6e6ff3db2d8dd0c986b4eec8554c8e4f919b5c1ff62a5b4390c17aff2ed6e5c4 \
--hash=sha256:ddc24a0a8280a0430baa37aff11f28574720af05888c62b7cfe71d219f4599d3
# via django-auth-ldap
django-auth-ldap==4.8.0 \
--hash=sha256:4b4b944f3c28bce362f33fb6e8db68429ed8fd8f12f0c0c4b1a4344a7ef225ce \
--hash=sha256:604250938ddc9fda619f247c7a59b0b2f06e53a7d3f46a156f28aa30dd71a738
# via -r contrib/container/requirements.in
gunicorn==23.0.0 \
--hash=sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d \
--hash=sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec
# via -r contrib/container/requirements.in
gunicorn==22.0.0 \
--hash=sha256:350679f91b24062c86e386e198a15438d53a7a8207235a78ba1b53df4c4378d9 \
--hash=sha256:4a0b436239ff76fb33f11c07a16482c521a7e09c1ce3cc293c2330afe01bec63
invoke==2.2.0 \
--hash=sha256:6ea924cc53d4f78e3d98bc436b08069a03077e6f85ad1ddaa8a116d7dad15820 \
--hash=sha256:ee6cbb101af1a859c7fe84f2a264c059020b0cb7fe3535f9424300ab568f6bd5
# via -r contrib/container/requirements.in
mariadb==1.1.10 \
--hash=sha256:03d6284ef713d1cad40146576a4cc2d6cbc1662060f2a0e59b174e1694521698 \
--hash=sha256:1ce87971c02375236ff8933e6c593c748e7b2f2950b86eabfab4289fd250ea63 \
@ -34,7 +29,6 @@ mariadb==1.1.10 \
--hash=sha256:a332893e3ef7ceb7970ab4bd7c844bcb4bd68a051ca51313566f9808d7411f2d \
--hash=sha256:d7b09ec4abd02ed235257feb769f90cd4066e8f536b55b92f5166103d5b66a63 \
--hash=sha256:dff8b28ce4044574870d7bdd2d9f9f5da8e5f95a7ff6d226185db733060d1a93
# via -r contrib/container/requirements.in
mysqlclient==2.2.4 \
--hash=sha256:329e4eec086a2336fe3541f1ce095d87a6f169d1cc8ba7b04ac68bcb234c9711 \
--hash=sha256:33bc9fb3464e7d7c10b1eaf7336c5ff8f2a3d3b88bab432116ad2490beb3bf41 \
@ -45,75 +39,85 @@ mysqlclient==2.2.4 \
--hash=sha256:ac44777eab0a66c14cb0d38965572f762e193ec2e5c0723bcd11319cc5b693c5 \
--hash=sha256:d43987bb9626096a302ca6ddcdd81feaeca65ced1d5fe892a6a66b808326aa54 \
--hash=sha256:e1ebe3f41d152d7cb7c265349fdb7f1eca86ccb0ca24a90036cde48e00ceb2ab
# via -r contrib/container/requirements.in
packaging==24.1 \
--hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \
--hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124
packaging==24.0 \
--hash=sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5 \
--hash=sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9
# via
# gunicorn
# mariadb
psycopg[binary, pool]==3.2.1 \
--hash=sha256:dc8da6dc8729dacacda3cc2f17d2c9397a70a66cf0d2b69c91065d60d5f00cb7 \
--hash=sha256:ece385fb413a37db332f97c49208b36cf030ff02b199d7635ed2fbd378724175
# via -r contrib/container/requirements.in
psycopg-binary==3.2.1 \
--hash=sha256:059cbd4e6da2337e17707178fe49464ed01de867dc86c677b30751755ec1dc51 \
--hash=sha256:06a7aae34edfe179ddc04da005e083ff6c6b0020000399a2cbf0a7121a8a22ea \
--hash=sha256:0879b5d76b7d48678d31278242aaf951bc2d69ca4e4d7cef117e4bbf7bfefda9 \
--hash=sha256:0ab58213cc976a1666f66bc1cb2e602315cd753b7981a8e17237ac2a185bd4a1 \
--hash=sha256:0b018631e5c80ce9bc210b71ea885932f9cca6db131e4df505653d7e3873a938 \
--hash=sha256:101472468d59c74bb8565fab603e032803fd533d16be4b2d13da1bab8deb32a3 \
--hash=sha256:1d353e028b8f848b9784450fc2abf149d53a738d451eab3ee4c85703438128b9 \
--hash=sha256:1d6833f607f3fc7b22226a9e121235d3b84c0eda1d3caab174673ef698f63788 \
--hash=sha256:21927f41c4d722ae8eb30d62a6ce732c398eac230509af5ba1749a337f8a63e2 \
--hash=sha256:28ada5f610468c57d8a4a055a8ea915d0085a43d794266c4f3b9d02f4288f4db \
--hash=sha256:2e8213bf50af073b1aa8dc3cff123bfeedac86332a16c1b7274910bc88a847c7 \
--hash=sha256:302b86f92c0d76e99fe1b5c22c492ae519ce8b98b88d37ef74fda4c9e24c6b46 \
--hash=sha256:334046a937bb086c36e2c6889fe327f9f29bfc085d678f70fac0b0618949f674 \
--hash=sha256:33e6669091d09f8ba36e10ce678a6d9916e110446236a9b92346464a3565635e \
--hash=sha256:3c838806eeb99af39f934b7999e35f947a8e577997cc892c12b5053a97a9057f \
--hash=sha256:40bb515d042f6a345714ec0403df68ccf13f73b05e567837d80c886c7c9d3805 \
--hash=sha256:413977d18412ff83486eeb5875eb00b185a9391c57febac45b8993bf9c0ff489 \
--hash=sha256:415c3b72ea32119163255c6504085f374e47ae7345f14bc3f0ef1f6e0976a879 \
--hash=sha256:42781ba94e8842ee98bca5a7d0c44cc9d067500fedca2d6a90fa3609b6d16b42 \
--hash=sha256:463d55345f73ff391df8177a185ad57b552915ad33f5cc2b31b930500c068b22 \
--hash=sha256:4a42b8f9ab39affcd5249b45cac763ac3cf12df962b67e23fd15a2ee2932afe5 \
--hash=sha256:4c84fcac8a3a3479ac14673095cc4e1fdba2935499f72c436785ac679bec0d1a \
--hash=sha256:592b27d6c46a40f9eeaaeea7c1fef6f3c60b02c634365eb649b2d880669f149f \
--hash=sha256:62b1b7b07e00ee490afb39c0a47d8282a9c2822c7cfed9553a04b0058adf7e7f \
--hash=sha256:6418712ba63cebb0c88c050b3997185b0ef54173b36568522d5634ac06153040 \
--hash=sha256:6f9e13600647087df5928875559f0eb8f496f53e6278b7da9511b4b3d0aff960 \
--hash=sha256:7066d3dca196ed0dc6172f9777b2d62e4f138705886be656cccff2d555234d60 \
--hash=sha256:73f9c9b984be9c322b5ec1515b12df1ee5896029f5e72d46160eb6517438659c \
--hash=sha256:74d623261655a169bc84a9669890975c229f2fa6e19a7f2d10a77675dcf1a707 \
--hash=sha256:788ffc43d7517c13e624c83e0e553b7b8823c9655e18296566d36a829bfb373f \
--hash=sha256:78c2007caf3c90f08685c5378e3ceb142bafd5636be7495f7d86ec8a977eaeef \
--hash=sha256:7a84b5eb194a258116154b2a4ff2962ea60ea52de089508db23a51d3d6b1c7d1 \
--hash=sha256:7ce965caf618061817f66c0906f0452aef966c293ae0933d4fa5a16ea6eaf5bb \
--hash=sha256:84837e99353d16c6980603b362d0f03302d4b06c71672a6651f38df8a482923d \
--hash=sha256:8f28ff0cb9f1defdc4a6f8c958bf6787274247e7dfeca811f6e2f56602695fb1 \
--hash=sha256:921f0c7f39590763d64a619de84d1b142587acc70fd11cbb5ba8fa39786f3073 \
--hash=sha256:950fd666ec9e9fe6a8eeb2b5a8f17301790e518953730ad44d715b59ffdbc67f \
--hash=sha256:9a997efbaadb5e1a294fb5760e2f5643d7b8e4e3fe6cb6f09e6d605fd28e0291 \
--hash=sha256:aa3931f308ab4a479d0ee22dc04bea867a6365cac0172e5ddcba359da043854b \
--hash=sha256:af0469c00f24c4bec18c3d2ede124bf62688d88d1b8a5f3c3edc2f61046fe0d7 \
--hash=sha256:b0104a72a17aa84b3b7dcab6c84826c595355bf54bb6ea6d284dcb06d99c6801 \
--hash=sha256:b09e8a576a2ac69d695032ee76f31e03b30781828b5dd6d18c6a009e5a3d1c35 \
--hash=sha256:b140182830c76c74d17eba27df3755a46442ce8d4fb299e7f1cf2f74a87c877b \
--hash=sha256:b1f087bd84bdcac78bf9f024ebdbfacd07fc0a23ec8191448a50679e2ac4a19e \
--hash=sha256:c1d2b6438fb83376f43ebb798bf0ad5e57bc56c03c9c29c85bc15405c8c0ac5a \
--hash=sha256:cad2de17804c4cfee8640ae2b279d616bb9e4734ac3c17c13db5e40982bd710d \
--hash=sha256:cc304a46be1e291031148d9d95c12451ffe783ff0cc72f18e2cc7ec43cdb8c68 \
--hash=sha256:dc314a47d44fe1a8069b075a64abffad347a3a1d8652fed1bab5d3baea37acb2 \
--hash=sha256:f092114f10f81fb6bae544a0ec027eb720e2d9c74a4fcdaa9dd3899873136935 \
--hash=sha256:f34e369891f77d0738e5d25727c307d06d5344948771e5379ea29c76c6d84555 \
--hash=sha256:f8a509aeaac364fa965454e80cd110fe6d48ba2c80f56c9b8563423f0b5c3cfd \
--hash=sha256:f8afb07114ea9b924a4a0305ceb15354ccf0ef3c0e14d54b8dbeb03e50182dd7 \
--hash=sha256:f99e59f8a5f4dcd9cbdec445f3d8ac950a492fc0e211032384d6992ed3c17eb7
psycopg[binary, pool]==3.1.18 \
--hash=sha256:31144d3fb4c17d78094d9e579826f047d4af1da6a10427d91dfcfb6ecdf6f12b \
--hash=sha256:4d5a0a5a8590906daa58ebd5f3cfc34091377354a1acced269dd10faf55da60e
psycopg-binary==3.1.18 \
--hash=sha256:02bd4da45d5ee9941432e2e9bf36fa71a3ac21c6536fe7366d1bd3dd70d6b1e7 \
--hash=sha256:0f68ac2364a50d4cf9bb803b4341e83678668f1881a253e1224574921c69868c \
--hash=sha256:13bcd3742112446037d15e360b27a03af4b5afcf767f5ee374ef8f5dd7571b31 \
--hash=sha256:1729d0e3dfe2546d823841eb7a3d003144189d6f5e138ee63e5227f8b75276a5 \
--hash=sha256:1859aeb2133f5ecdd9cbcee155f5e38699afc06a365f903b1512c765fd8d457e \
--hash=sha256:1c9b6bd7fb5c6638cb32469674707649b526acfe786ba6d5a78ca4293d87bae4 \
--hash=sha256:247474af262bdd5559ee6e669926c4f23e9cf53dae2d34c4d991723c72196404 \
--hash=sha256:258d2f0cb45e4574f8b2fe7c6d0a0e2eb58903a4fd1fbaf60954fba82d595ab7 \
--hash=sha256:2e2484ae835dedc80cdc7f1b1a939377dc967fed862262cfd097aa9f50cade46 \
--hash=sha256:320047e3d3554b857e16c2b6b615a85e0db6a02426f4d203a4594a2f125dfe57 \
--hash=sha256:39242546383f6b97032de7af30edb483d237a0616f6050512eee7b218a2aa8ee \
--hash=sha256:3c2b039ae0c45eee4cd85300ef802c0f97d0afc78350946a5d0ec77dd2d7e834 \
--hash=sha256:3c7afcd6f1d55992f26d9ff7b0bd4ee6b475eb43aa3f054d67d32e09f18b0065 \
--hash=sha256:3e4b0bb91da6f2238dbd4fbb4afc40dfb4f045bb611b92fce4d381b26413c686 \
--hash=sha256:3e7ce4d988112ca6c75765c7f24c83bdc476a6a5ce00878df6c140ca32c3e16d \
--hash=sha256:4085f56a8d4fc8b455e8f44380705c7795be5317419aa5f8214f315e4205d804 \
--hash=sha256:4575da95fc441244a0e2ebaf33a2b2f74164603341d2046b5cde0a9aa86aa7e2 \
--hash=sha256:489aa4fe5a0b653b68341e9e44af247dedbbc655326854aa34c163ef1bcb3143 \
--hash=sha256:4e4de16a637ec190cbee82e0c2dc4860fed17a23a35f7a1e6dc479a5c6876722 \
--hash=sha256:531381f6647fc267383dca88dbe8a70d0feff433a8e3d0c4939201fea7ae1b82 \
--hash=sha256:55ff0948457bfa8c0d35c46e3a75193906d1c275538877ba65907fd67aa059ad \
--hash=sha256:59701118c7d8842e451f1e562d08e8708b3f5d14974eefbce9374badd723c4ae \
--hash=sha256:5c323103dfa663b88204cf5f028e83c77d7a715f9b6f51d2bbc8184b99ddd90a \
--hash=sha256:5d6e860edf877d4413e4a807e837d55e3a7c7df701e9d6943c06e460fa6c058f \
--hash=sha256:639dd78ac09b144b0119076783cb64e1128cc8612243e9701d1503c816750b2e \
--hash=sha256:6432047b8b24ef97e3fbee1d1593a0faaa9544c7a41a2c67d1f10e7621374c83 \
--hash=sha256:67284e2e450dc7a9e4d76e78c0bd357dc946334a3d410defaeb2635607f632cd \
--hash=sha256:6ebecbf2406cd6875bdd2453e31067d1bd8efe96705a9489ef37e93b50dc6f09 \
--hash=sha256:7121acc783c4e86d2d320a7fb803460fab158a7f0a04c5e8c5d49065118c1e73 \
--hash=sha256:74e498586b72fb819ca8ea82107747d0cb6e00ae685ea6d1ab3f929318a8ce2d \
--hash=sha256:780a90bcb69bf27a8b08bc35b958e974cb6ea7a04cdec69e737f66378a344d68 \
--hash=sha256:7ac1785d67241d5074f8086705fa68e046becea27964267ab3abd392481d7773 \
--hash=sha256:812726266ab96de681f2c7dbd6b734d327f493a78357fcc16b2ac86ff4f4e080 \
--hash=sha256:824a1bfd0db96cc6bef2d1e52d9e0963f5bf653dd5bc3ab519a38f5e6f21c299 \
--hash=sha256:87dd9154b757a5fbf6d590f6f6ea75f4ad7b764a813ae04b1d91a70713f414a1 \
--hash=sha256:887f8d856c91510148be942c7acd702ccf761a05f59f8abc123c22ab77b5a16c \
--hash=sha256:888a72c2aca4316ca6d4a619291b805677bae99bba2f6e31a3c18424a48c7e4d \
--hash=sha256:8f54978c4b646dec77fefd8485fa82ec1a87807f334004372af1aaa6de9539a5 \
--hash=sha256:91074f78a9f890af5f2c786691575b6b93a4967ad6b8c5a90101f7b8c1a91d9c \
--hash=sha256:9d684227ef8212e27da5f2aff9d4d303cc30b27ac1702d4f6881935549486dd5 \
--hash=sha256:9e24e7b6a68a51cc3b162d0339ae4e1263b253e887987d5c759652f5692b5efe \
--hash=sha256:9ffcbbd389e486d3fd83d30107bbf8b27845a295051ccabde240f235d04ed921 \
--hash=sha256:a87e9eeb80ce8ec8c2783f29bce9a50bbcd2e2342a340f159c3326bf4697afa1 \
--hash=sha256:ad35ac7fd989184bf4d38a87decfb5a262b419e8ba8dcaeec97848817412c64a \
--hash=sha256:b15e3653c82384b043d820fc637199b5c6a36b37fa4a4943e0652785bb2bad5d \
--hash=sha256:b293e01057e63c3ac0002aa132a1071ce0fdb13b9ee2b6b45d3abdb3525c597d \
--hash=sha256:b2f7f95746efd1be2dc240248cc157f4315db3fd09fef2adfcc2a76e24aa5741 \
--hash=sha256:bd27f713f2e5ef3fd6796e66c1a5203a27a30ecb847be27a78e1df8a9a5ae68c \
--hash=sha256:c38a4796abf7380f83b1653c2711cb2449dd0b2e5aca1caa75447d6fa5179c69 \
--hash=sha256:c76659ae29a84f2c14f56aad305dd00eb685bd88f8c0a3281a9a4bc6bd7d2aa7 \
--hash=sha256:c84a0174109f329eeda169004c7b7ca2e884a6305acab4a39600be67f915ed38 \
--hash=sha256:cd2a9f7f0d4dacc5b9ce7f0e767ae6cc64153264151f50698898c42cabffec0c \
--hash=sha256:d322ba72cde4ca2eefc2196dad9ad7e52451acd2f04e3688d590290625d0c970 \
--hash=sha256:d4422af5232699f14b7266a754da49dc9bcd45eba244cf3812307934cd5d6679 \
--hash=sha256:d46ae44d66bf6058a812467f6ae84e4e157dee281bfb1cfaeca07dee07452e85 \
--hash=sha256:da917f6df8c6b2002043193cb0d74cc173b3af7eb5800ad69c4e1fbac2a71c30 \
--hash=sha256:dea4a59da7850192fdead9da888e6b96166e90608cf39e17b503f45826b16f84 \
--hash=sha256:e05f6825f8db4428782135e6986fec79b139210398f3710ed4aa6ef41473c008 \
--hash=sha256:e1cf59e0bb12e031a48bb628aae32df3d0c98fd6c759cb89f464b1047f0ca9c8 \
--hash=sha256:e252d66276c992319ed6cd69a3ffa17538943954075051e992143ccbf6dc3d3e \
--hash=sha256:e262398e5d51563093edf30612cd1e20fedd932ad0994697d7781ca4880cdc3d \
--hash=sha256:e28ff8f3de7b56588c2a398dc135fd9f157d12c612bd3daa7e6ba9872337f6f5 \
--hash=sha256:eea5f14933177ffe5c40b200f04f814258cc14b14a71024ad109f308e8bad414 \
--hash=sha256:f876ebbf92db70125f6375f91ab4bc6b27648aa68f90d661b1fc5affb4c9731c \
--hash=sha256:f8ff3bc08b43f36fdc24fedb86d42749298a458c4724fb588c4d76823ac39f54
# via psycopg
psycopg-pool==3.2.2 \
--hash=sha256:273081d0fbfaced4f35e69200c89cb8fbddfe277c38cc86c235b90a2ec2c8153 \
--hash=sha256:9e22c370045f6d7f2666a5ad1b0caf345f9f1912195b0b25d0d3bcc4f3a7389c
psycopg-pool==3.2.1 \
--hash=sha256:060b551d1b97a8d358c668be58b637780b884de14d861f4f5ecc48b7563aafb7 \
--hash=sha256:6509a75c073590952915eddbba7ce8b8332a440a31e77bba69561483492829ad
# via psycopg
pyasn1==0.6.0 \
--hash=sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c \
@ -127,99 +131,90 @@ pyasn1-modules==0.4.0 \
# via python-ldap
python-ldap==3.4.4 \
--hash=sha256:7edb0accec4e037797705f3a05cbf36a9fde50d08c8f67f2aef99a2628fab828
# via
# -r contrib/container/requirements.in
# django-auth-ldap
pyyaml==6.0.2 \
--hash=sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff \
--hash=sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48 \
--hash=sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086 \
--hash=sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e \
--hash=sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133 \
--hash=sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5 \
--hash=sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484 \
--hash=sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee \
--hash=sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5 \
--hash=sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68 \
--hash=sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a \
--hash=sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf \
--hash=sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99 \
--hash=sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8 \
--hash=sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85 \
--hash=sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19 \
--hash=sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc \
--hash=sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a \
--hash=sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1 \
--hash=sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317 \
--hash=sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c \
--hash=sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631 \
--hash=sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d \
--hash=sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652 \
--hash=sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5 \
--hash=sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e \
--hash=sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b \
--hash=sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8 \
--hash=sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476 \
--hash=sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706 \
--hash=sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563 \
--hash=sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237 \
--hash=sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b \
--hash=sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083 \
--hash=sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180 \
--hash=sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425 \
--hash=sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e \
--hash=sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f \
--hash=sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725 \
--hash=sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183 \
--hash=sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab \
--hash=sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774 \
--hash=sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725 \
--hash=sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e \
--hash=sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5 \
--hash=sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d \
--hash=sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290 \
--hash=sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44 \
--hash=sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed \
--hash=sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4 \
--hash=sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba \
--hash=sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12 \
--hash=sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4
# via -r contrib/container/requirements.in
setuptools==73.0.1 \
--hash=sha256:b208925fcb9f7af924ed2dc04708ea89791e24bde0d3020b27df0e116088b34e \
--hash=sha256:d59a3e788ab7e012ab2c4baed1b376da6366883ee20d7a5fc426816e3d7b1193
# via -r contrib/container/requirements.in
sqlparse==0.5.1 \
--hash=sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4 \
--hash=sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e
# via django-auth-ldap
pyyaml==6.0.1 \
--hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \
--hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \
--hash=sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df \
--hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \
--hash=sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206 \
--hash=sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27 \
--hash=sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595 \
--hash=sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62 \
--hash=sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98 \
--hash=sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696 \
--hash=sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290 \
--hash=sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9 \
--hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \
--hash=sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6 \
--hash=sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867 \
--hash=sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47 \
--hash=sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486 \
--hash=sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6 \
--hash=sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3 \
--hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \
--hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \
--hash=sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0 \
--hash=sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c \
--hash=sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735 \
--hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \
--hash=sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28 \
--hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \
--hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \
--hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \
--hash=sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef \
--hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \
--hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \
--hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \
--hash=sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0 \
--hash=sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515 \
--hash=sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c \
--hash=sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c \
--hash=sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924 \
--hash=sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34 \
--hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \
--hash=sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859 \
--hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \
--hash=sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54 \
--hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \
--hash=sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b \
--hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \
--hash=sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa \
--hash=sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c \
--hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \
--hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \
--hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f
setuptools==69.5.1 \
--hash=sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987 \
--hash=sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32
sqlparse==0.5.0 \
--hash=sha256:714d0a4932c059d16189f58ef5411ec2287a4360f17cdd0edd2d09d4c5087c93 \
--hash=sha256:c204494cd97479d0e39f28c93d46c0b2d5959c7b9ab904762ea6c7af211c8663
# via django
typing-extensions==4.12.2 \
--hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \
--hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8
typing-extensions==4.11.0 \
--hash=sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0 \
--hash=sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a
# via
# psycopg
# psycopg-pool
uv==0.3.0 \
--hash=sha256:084551ee0743339aa5d0d4c76a94c9f9df16c33030b850f0cd98f316db7b42cc \
--hash=sha256:0da4f060d583325846cde0727a8cc0cb4e8c63b30ac9373dae213a7315056d90 \
--hash=sha256:160a1f3b01298942d6cfe21f95a9b7daa3eb73231ba1fc4689157eb9f23b3438 \
--hash=sha256:21ebc6ca30df7ff57a8e17e3abeeba8a9d1d4ac79c1adf842fa42d48a5c7f372 \
--hash=sha256:24a1388f5e285058f97576b7dfee79bb5007a712a9e368f3fcdcfeb2dfd9ce92 \
--hash=sha256:2f937ebdf9976ec1ffe7228fd608ef3e6ce2a61ed68cf7b157ae6900a9c80f41 \
--hash=sha256:39a4276afe0808ca6c033e0cd6cb73249f934b4a0c9d7b18a944f3f8ea635e27 \
--hash=sha256:3b62e44f61a154303fc9f4aa87ae54891957d49769d21dcf2be9c22e640c3e92 \
--hash=sha256:4303364d717b1def58e82b11271259d2ee3bb03da0ca6111819ee254f65b38f4 \
--hash=sha256:503fc619238550be222b41422b415677c9b8045c92a9815f80ff5d7477671fe6 \
--hash=sha256:52b3a6110705ff27462ddc68657fedf8a296ed545619a90fa73354f130ad632e \
--hash=sha256:5c826d9daace67d67790503b0c1152093b3cecd35a91de10f5bb9e26afea9de9 \
--hash=sha256:6d1025349cbaeba9a974d413795d0ce8d37de5ad7fb7654c0519968b2c083ba1 \
--hash=sha256:a15b2321444f3668bc95863d2b13ce44ea54053189427ea48d112ecd8b3d2f89 \
--hash=sha256:a71b7080ee6d7658b22f93aa750cbfd19111cd6c8ac643a73d6778598dd06559 \
--hash=sha256:b44ebf501de5eef33e4f3cf4b6ea9a458d1f1b3cf26737c25ac507ab7914076a \
--hash=sha256:d3da56b87ec5aa4f2ae572127c754655bad3820dd41a4d37ed4d5e2f67035990 \
--hash=sha256:d87ff76da5128036c05db0291db7510a85cb8efb86538e8f49adc8074bb292f0
# via -r contrib/container/requirements.in
wheel==0.44.0 \
--hash=sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f \
--hash=sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49
# via -r contrib/container/requirements.in
uv==0.1.38 \
--hash=sha256:03242a734a572733f2b9a5dbb94517e918fe26fc01114b7c51d12296dfbb8f8b \
--hash=sha256:067af2d986329db4fa3c7373017d49f0e16ddff23e483b7e5bc3a5a18ce08ea6 \
--hash=sha256:0937ad16ae0e0b6bb6dd3c386f8fb33141ad08d1762eaacffb4d2b27fb466a17 \
--hash=sha256:0e1d64ac437b0a14fbcec55b1c3f162fa24860711e0d855fcd9c672b149a122a \
--hash=sha256:1be7aa46936c0351ccb1400ea95e5381b3f05fef772fa3b9f23af728cc175dea \
--hash=sha256:309e73a3ec3a5a536a3efaf434270fc94b483069f1425765165c1c9d786c27fd \
--hash=sha256:4251f9771d392d7badc1e5fb934b397b12ca00fef9d955207ade169cc1f7e872 \
--hash=sha256:43772e7589f70e954b1ae29230e575ef9e4d8d769138a94dfa5ae7eaf1e26ac5 \
--hash=sha256:4a6024256d38b77151e32876be9fcb99cf75df7a86b26e0161cc202bed558adf \
--hash=sha256:5a98d6aacd4b57b7e00daf154919e7c9206fefdf40bd28cfb13efe0e0324d491 \
--hash=sha256:8de6dbd8f348ee90af044f4cc7b6650521d25ba2d20a813c1e157a3f90069dd9 \
--hash=sha256:9133e24db9bdd4f412eab69586d03294419825432a9a27ee1b510a4c01eb7b0b \
--hash=sha256:92f65b6e4e5c8126501785af3629dc537d7c82caa56ac9336a86929c73d0e138 \
--hash=sha256:afd85029923e712b6b2c45ddc1680c785392220876c766521e45778db3f71f8e \
--hash=sha256:b0b15e51a0f8240969bc412ed0dd60cfe3f664b30173139ef263d71c596d631f \
--hash=sha256:ea44c07605d1359a7d82bf42706dd86d341f15f4ca2e1f36e51626a7111c2ad5 \
--hash=sha256:f87c9711493c53d32012a96b49c4d53aabdf7ed666cbf2c3fb55dd402a6b31a8
wheel==0.43.0 \
--hash=sha256:465ef92c69fa5c5da2d1cf8ac40559a8c940886afcef87dcf14b9470862f1d85 \
--hash=sha256:55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81

View File

@ -1,4 +1,4 @@
# Packages needed for CI/packages
requests==2.32.3
pyyaml==6.0.2
jc==1.25.3
requests==2.31.0
pyyaml==6.0.1
jc==1.25.2

View File

@ -1,8 +1,8 @@
# This file was autogenerated by uv via the following command:
# uv pip compile contrib/dev_reqs/requirements.in -o contrib/dev_reqs/requirements.txt --no-strip-extras --generate-hashes
certifi==2024.7.4 \
--hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \
--hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90
# uv pip compile contrib/dev_reqs/requirements.in -o contrib/dev_reqs/requirements.txt --python-version=3.9 --no-strip-extras --generate-hashes
certifi==2024.2.2 \
--hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \
--hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1
# via requests
charset-normalizer==3.3.2 \
--hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
@ -100,73 +100,68 @@ idna==3.7 \
--hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \
--hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0
# via requests
jc==1.25.3 \
--hash=sha256:ea17a8578497f2da92f73924d9d403f4563ba59422fbceff7bb4a16cdf84a54f \
--hash=sha256:fa3140ceda6cba1210d1362f363cd79a0514741e8a1dd6167db2b2e2d5f24f7b
# via -r contrib/dev_reqs/requirements.in
pygments==2.18.0 \
--hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \
--hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a
jc==1.25.2 \
--hash=sha256:26e412a65a478f9da3097653db6277f915cfae5c0f0a3f42026b405936abd358 \
--hash=sha256:97ada193495f79550f06fe0cbfb119ff470bcca57c1cc593a5cdb0008720e0b3
pygments==2.17.2 \
--hash=sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c \
--hash=sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367
# via jc
pyyaml==6.0.2 \
--hash=sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff \
--hash=sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48 \
--hash=sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086 \
--hash=sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e \
--hash=sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133 \
--hash=sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5 \
--hash=sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484 \
--hash=sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee \
--hash=sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5 \
--hash=sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68 \
--hash=sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a \
--hash=sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf \
--hash=sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99 \
--hash=sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8 \
--hash=sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85 \
--hash=sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19 \
--hash=sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc \
--hash=sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a \
--hash=sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1 \
--hash=sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317 \
--hash=sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c \
--hash=sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631 \
--hash=sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d \
--hash=sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652 \
--hash=sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5 \
--hash=sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e \
--hash=sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b \
--hash=sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8 \
--hash=sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476 \
--hash=sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706 \
--hash=sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563 \
--hash=sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237 \
--hash=sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b \
--hash=sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083 \
--hash=sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180 \
--hash=sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425 \
--hash=sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e \
--hash=sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f \
--hash=sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725 \
--hash=sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183 \
--hash=sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab \
--hash=sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774 \
--hash=sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725 \
--hash=sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e \
--hash=sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5 \
--hash=sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d \
--hash=sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290 \
--hash=sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44 \
--hash=sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed \
--hash=sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4 \
--hash=sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba \
--hash=sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12 \
--hash=sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4
# via -r contrib/dev_reqs/requirements.in
requests==2.32.3 \
--hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
--hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
# via -r contrib/dev_reqs/requirements.in
pyyaml==6.0.1 \
--hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \
--hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \
--hash=sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df \
--hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \
--hash=sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206 \
--hash=sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27 \
--hash=sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595 \
--hash=sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62 \
--hash=sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98 \
--hash=sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696 \
--hash=sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290 \
--hash=sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9 \
--hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \
--hash=sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6 \
--hash=sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867 \
--hash=sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47 \
--hash=sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486 \
--hash=sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6 \
--hash=sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3 \
--hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \
--hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \
--hash=sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0 \
--hash=sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c \
--hash=sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735 \
--hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \
--hash=sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28 \
--hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \
--hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \
--hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \
--hash=sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef \
--hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \
--hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \
--hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \
--hash=sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0 \
--hash=sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515 \
--hash=sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c \
--hash=sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c \
--hash=sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924 \
--hash=sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34 \
--hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \
--hash=sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859 \
--hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \
--hash=sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54 \
--hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \
--hash=sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b \
--hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \
--hash=sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa \
--hash=sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c \
--hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \
--hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \
--hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f
requests==2.31.0 \
--hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
--hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
ruamel-yaml==0.18.6 \
--hash=sha256:57b53ba33def16c4f3d807c0ccbc00f8a6081827e81ba2491691b76882d0c636 \
--hash=sha256:8b27e6a217e786c6fbe5634d8f3f11bc63e0f80f6a5890f28863d9c45aac311b
@ -223,9 +218,9 @@ ruamel-yaml-clib==0.2.8 \
--hash=sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875 \
--hash=sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412
# via ruamel-yaml
urllib3==2.2.2 \
--hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \
--hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168
urllib3==2.2.1 \
--hash=sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d \
--hash=sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19
# via requests
xmltodict==0.13.0 \
--hash=sha256:341595a488e3e01a85a9d8911d8912fd922ede5fecc4dce437eb4b6c8d037e56 \

View File

@ -75,7 +75,6 @@ root_command() {
;;
"Debian GNU/Linux" | "debian gnu/linux" | Raspbian)
if [[ $VER == "12" ]]; then
DIST_VER="11"
SUPPORTED=true
elif [[ $VER == "11" ]]; then
SUPPORTED=true

View File

@ -5,40 +5,33 @@
set -eu
# The sha is the second element in APP_PKG_ITERATION
VERSION="$APP_PKG_VERSION-$APP_PKG_ITERATION"
echo "Setting VERSION information to $VERSION"
echo "$VERSION" > VERSION
# The sha is the second element in APP_PKG_ITERATION
SHA=$(echo $APP_PKG_ITERATION | cut -d'.' -f2)
# Download info
echo "INFO collection | Getting info from github for commit $SHA"
curl -L -s -f \
echo "Getting info from github for commit $SHA"
curl -L \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/$APP_REPO/commits/$SHA > commit.json
echo "INFO collection | Got commit.json with size $(wc -c commit.json)"
curl -L -s -f \
https://api.github.com/repos/InvenTree/InvenTree/commits/$SHA > commit.json
curl -L \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/$APP_REPO/commits/$SHA/branches-where-head > branches.json
echo "INFO collection | Got branches.json with size $(wc -c branches.json)"
curl -L -s -f \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/$APP_REPO/commits/$APP_PKG_VERSION > tag.json
echo "INFO collection | Got tag.json with size $(wc -c tag.json)"
https://api.github.com/repos/InvenTree/InvenTree/commits/$SHA/branches-where-head > branches.json
# Extract info
echo "INFO extract | Extracting info from github"
echo "Extracting info from github"
DATE=$(jq -r '.commit.committer.date' commit.json)
BRANCH=$(jq -r '.[].name' branches.json)
NODE_ID=$(jq -r '.node_id' commit.json)
SIGNATURE=$(jq -r '.commit.verification.signature' commit.json)
FULL_SHA=$(jq -r '.sha' commit.json)
echo "INFO write | Write VERSION information"
echo "$VERSION" > VERSION
echo "Write VERSION information"
echo "INVENTREE_COMMIT_HASH='$SHA'" >> VERSION
echo "INVENTREE_COMMIT_SHA='$FULL_SHA'" >> VERSION
echo "INVENTREE_COMMIT_DATE='$DATE'" >> VERSION
echo "INVENTREE_PKG_INSTALLER='PKG'" >> VERSION
echo "INVENTREE_PKG_BRANCH='$BRANCH'" >> VERSION
@ -46,22 +39,5 @@ echo "INVENTREE_PKG_TARGET='$TARGET'" >> VERSION
echo "NODE_ID='$NODE_ID'" >> VERSION
echo "SIGNATURE='$SIGNATURE'" >> VERSION
echo "INFO write | Written VERSION information"
echo "### VERSION ###"
echo "Written VERSION information"
cat VERSION
echo "### VERSION ###"
# Try to get frontend
echo "INFO frontend | Trying to get frontend"
# Check if tag sha is the same as the commit sha
TAG_SHA=$(jq -r '.sha' tag.json)
if [ "$TAG_SHA" != "$FULL_SHA" ]; then
echo "INFO frontend | Tag sha '$TAG_SHA' is not the same as commit sha $FULL_SHA, can not download frontend"
else
echo "INFO frontend | Getting frontend from github via tag"
curl https://github.com/$APP_REPO/releases/download/$APP_PKG_VERSION/frontend-build.zip -L -O -f
mkdir -p src/backend/InvenTree/web/static
echo "INFO frontend | Unzipping frontend"
unzip -qq frontend-build.zip -d src/backend/InvenTree/web/static/web
echo "INFO frontend | Unzipped frontend"
fi

View File

@ -4,8 +4,6 @@
#
Color_Off='\033[0m'
On_Red='\033[41m'
PYTHON_FROM=9
PYTHON_TO=12
function detect_docker() {
if [ -n "$(grep docker </proc/1/cgroup)" ]; then
@ -59,19 +57,6 @@ function detect_python() {
echo "# No python environment found - using environment variable: ${SETUP_PYTHON}"
fi
# Try to detect a python between 3.9 and 3.12 in reverse order
if [ -z "$(which ${SETUP_PYTHON})" ]; then
echo "# Trying to detecting python3.${PYTHON_FROM} to python3.${PYTHON_TO} - using newest version"
for i in $(seq $PYTHON_TO -1 $PYTHON_FROM); do
echo "# Checking for python3.${i}"
if [ -n "$(which python3.${i})" ]; then
SETUP_PYTHON="python3.${i}"
echo "# Found python3.${i} installed - using for setup ${SETUP_PYTHON}"
break
fi
done
fi
# Ensure python can be executed - abort if not
if [ -z "$(which ${SETUP_PYTHON})" ]; then
echo "${On_Red}"
@ -132,22 +117,22 @@ function detect_envs() {
pip install --require-hashes -r ${APP_HOME}/contrib/dev_reqs/requirements.txt -q
# Load config
export INVENTREE_CONF_DATA=$(cat ${INVENTREE_CONFIG_FILE} | jc --yaml)
local CONF=$(cat ${INVENTREE_CONFIG_FILE} | jc --yaml)
# Parse the config file
export INVENTREE_MEDIA_ROOT=$(jq -r '.[].media_root' <<< ${INVENTREE_CONF_DATA})
export INVENTREE_STATIC_ROOT=$(jq -r '.[].static_root' <<< ${INVENTREE_CONF_DATA})
export INVENTREE_BACKUP_DIR=$(jq -r '.[].backup_dir' <<< ${INVENTREE_CONF_DATA})
export INVENTREE_PLUGINS_ENABLED=$(jq -r '.[].plugins_enabled' <<< ${INVENTREE_CONF_DATA})
export INVENTREE_PLUGIN_FILE=$(jq -r '.[].plugin_file' <<< ${INVENTREE_CONF_DATA})
export INVENTREE_SECRET_KEY_FILE=$(jq -r '.[].secret_key_file' <<< ${INVENTREE_CONF_DATA})
export INVENTREE_MEDIA_ROOT=$(jq -r '.[].media_root' <<< ${CONF})
export INVENTREE_STATIC_ROOT=$(jq -r '.[].static_root' <<< ${CONF})
export INVENTREE_BACKUP_DIR=$(jq -r '.[].backup_dir' <<< ${CONF})
export INVENTREE_PLUGINS_ENABLED=$(jq -r '.[].plugins_enabled' <<< ${CONF})
export INVENTREE_PLUGIN_FILE=$(jq -r '.[].plugin_file' <<< ${CONF})
export INVENTREE_SECRET_KEY_FILE=$(jq -r '.[].secret_key_file' <<< ${CONF})
export INVENTREE_DB_ENGINE=$(jq -r '.[].database.ENGINE' <<< ${INVENTREE_CONF_DATA})
export INVENTREE_DB_NAME=$(jq -r '.[].database.NAME' <<< ${INVENTREE_CONF_DATA})
export INVENTREE_DB_USER=$(jq -r '.[].database.USER' <<< ${INVENTREE_CONF_DATA})
export INVENTREE_DB_PASSWORD=$(jq -r '.[].database.PASSWORD' <<< ${INVENTREE_CONF_DATA})
export INVENTREE_DB_HOST=$(jq -r '.[].database.HOST' <<< ${INVENTREE_CONF_DATA})
export INVENTREE_DB_PORT=$(jq -r '.[].database.PORT' <<< ${INVENTREE_CONF_DATA})
export INVENTREE_DB_ENGINE=$(jq -r '.[].database.ENGINE' <<< ${CONF})
export INVENTREE_DB_NAME=$(jq -r '.[].database.NAME' <<< ${CONF})
export INVENTREE_DB_USER=$(jq -r '.[].database.USER' <<< ${CONF})
export INVENTREE_DB_PASSWORD=$(jq -r '.[].database.PASSWORD' <<< ${CONF})
export INVENTREE_DB_HOST=$(jq -r '.[].database.HOST' <<< ${CONF})
export INVENTREE_DB_PORT=$(jq -r '.[].database.PORT' <<< ${CONF})
else
echo "# No config file found: ${INVENTREE_CONFIG_FILE}, using envs or defaults"
@ -246,11 +231,7 @@ function create_initscripts() {
}
function create_admin() {
# Create data for admin users - stop with setting SETUP_ADMIN_NOCREATION to true
if [ "${SETUP_ADMIN_NOCREATION}" == "true" ]; then
echo "# Admin creation is disabled - skipping"
return
fi
# Create data for admin user
if test -f "${SETUP_ADMIN_PASSWORD_FILE}"; then
echo "# Admin data already exists - skipping"
@ -318,17 +299,17 @@ function set_env() {
sed -i s=debug:\ True=debug:\ False=g ${INVENTREE_CONFIG_FILE}
# Database engine
sed -i s=#\ ENGINE:\ Database\ engine.\ Selection\ from:=ENGINE:\ ${INVENTREE_DB_ENGINE}=g ${INVENTREE_CONFIG_FILE}
sed -i s=#ENGINE:\ sampleengine=ENGINE:\ ${INVENTREE_DB_ENGINE}=g ${INVENTREE_CONFIG_FILE}
# Database name
sed -i s=#\ NAME:\ Database\ name=NAME:\ \'${INVENTREE_DB_NAME}\'=g ${INVENTREE_CONFIG_FILE}
sed -i s=#NAME:\ \'/path/to/database\'=NAME:\ \'${INVENTREE_DB_NAME}\'=g ${INVENTREE_CONFIG_FILE}
# Database user
sed -i s=#\ USER:\ Database\ username\ \(if\ required\)=USER:\ ${INVENTREE_DB_USER}=g ${INVENTREE_CONFIG_FILE}
sed -i s=#USER:\ sampleuser=USER:\ ${INVENTREE_DB_USER}=g ${INVENTREE_CONFIG_FILE}
# Database password
sed -i s=#\ PASSWORD:\ Database\ password\ \(if\ required\)=PASSWORD:\ ${INVENTREE_DB_PASSWORD}=g ${INVENTREE_CONFIG_FILE}
sed -i s=#PASSWORD:\ samplepassword=PASSWORD:\ ${INVENTREE_DB_PASSWORD}=g ${INVENTREE_CONFIG_FILE}
# Database host
sed -i s=#\ HOST:\ Database\ host\ address\ \(if\ required\)=HOST:\ ${INVENTREE_DB_HOST}=g ${INVENTREE_CONFIG_FILE}
sed -i s=#HOST:\ samplehost=HOST:\ ${INVENTREE_DB_HOST}=g ${INVENTREE_CONFIG_FILE}
# Database port
sed -i s=#\ PORT:\ Database\ host\ port\ \(if\ required\)=PORT:\ ${INVENTREE_DB_PORT}=g ${INVENTREE_CONFIG_FILE}
sed -i s=#PORT:\ 123456=PORT:\ ${INVENTREE_DB_PORT}=g ${INVENTREE_CONFIG_FILE}
# Fixing the permissions
chown ${APP_USER}:${APP_GROUP} ${DATA_DIR} ${INVENTREE_CONFIG_FILE}
@ -359,44 +340,3 @@ function final_message() {
echo -e " Password: ${INVENTREE_ADMIN_PASSWORD}"
echo -e "####################################################################################"
}
function update_checks() {
echo "# Running upgrade"
local old_version=$1
local old_version_rev=$(echo ${old_version} | cut -d'-' -f1 | cut -d'.' -f2)
echo "# Old version is: ${old_version} - release: ${old_version_rev}"
local ABORT=false
function check_config_value() {
local env_key=$1
local config_key=$2
local name=$3
local value=$(inventree config:get ${env_key})
if [ -z "${value}" ] || [ "$value" == "null" ]; then
value=$(jq -r ".[].${config_key}" <<< ${INVENTREE_CONF_DATA})
fi
if [ -z "${value}" ] || [ "$value" == "null" ]; then
echo "# No setting for ${name} found - please set it manually either in ${INVENTREE_CONFIG_FILE} under '${config_key}' or with 'inventree config:set ${env_key}=value'"
ABORT=true
else
echo "# Found setting for ${name} - ${value}"
fi
}
# Custom checks if old version is below 0.8.0
if [ "${old_version_rev}" -lt "9" ]; then
echo "# Old version is below 0.9.0 - You might be missing some configs"
# Check for BACKUP_DIR and SITE_URL in INVENTREE_CONF_DATA and config
check_config_value "INVENTREE_SITE_URL" "site_url" "site URL"
check_config_value "INVENTREE_BACKUP_DIR" "backup_dir" "backup dir"
if [ "${ABORT}" = true ]; then
echo "# Aborting - please set the missing values and run the update again"
exit 1
fi
echo "# All checks passed - continuing with the update"
fi
}

View File

@ -11,7 +11,7 @@ PATH=${APP_HOME}/env/bin:${APP_HOME}/:/sbin:/bin:/usr/sbin:/usr/bin:
. ${APP_HOME}/contrib/packager.io/functions.sh
# Envs that should be passed to setup commands
export SETUP_ENVS=PATH,APP_HOME,INVENTREE_MEDIA_ROOT,INVENTREE_STATIC_ROOT,INVENTREE_BACKUP_DIR,INVENTREE_SITE_URL,INVENTREE_PLUGINS_ENABLED,INVENTREE_PLUGIN_FILE,INVENTREE_CONFIG_FILE,INVENTREE_SECRET_KEY_FILE,INVENTREE_DB_ENGINE,INVENTREE_DB_NAME,INVENTREE_DB_USER,INVENTREE_DB_PASSWORD,INVENTREE_DB_HOST,INVENTREE_DB_PORT,INVENTREE_ADMIN_USER,INVENTREE_ADMIN_EMAIL,INVENTREE_ADMIN_PASSWORD,SETUP_NGINX_FILE,SETUP_ADMIN_PASSWORD_FILE,SETUP_NO_CALLS,SETUP_DEBUG,SETUP_EXTRA_PIP,SETUP_PYTHON,SETUP_ADMIN_NOCREATION
export SETUP_ENVS=PATH,APP_HOME,INVENTREE_MEDIA_ROOT,INVENTREE_STATIC_ROOT,INVENTREE_BACKUP_DIR,INVENTREE_PLUGINS_ENABLED,INVENTREE_PLUGIN_FILE,INVENTREE_CONFIG_FILE,INVENTREE_SECRET_KEY_FILE,INVENTREE_DB_ENGINE,INVENTREE_DB_NAME,INVENTREE_DB_USER,INVENTREE_DB_PASSWORD,INVENTREE_DB_HOST,INVENTREE_DB_PORT,INVENTREE_ADMIN_USER,INVENTREE_ADMIN_EMAIL,INVENTREE_ADMIN_PASSWORD,SETUP_NGINX_FILE,SETUP_ADMIN_PASSWORD_FILE,SETUP_NO_CALLS,SETUP_DEBUG,SETUP_EXTRA_PIP,SETUP_PYTHON
# Get the envs
detect_local_env
@ -24,7 +24,6 @@ export SETUP_NGINX_FILE=${SETUP_NGINX_FILE:-/etc/nginx/sites-enabled/inventree.c
export SETUP_ADMIN_PASSWORD_FILE=${CONF_DIR}/admin_password.txt
export SETUP_NO_CALLS=${SETUP_NO_CALLS:-false}
export SETUP_PYTHON=${SETUP_PYTHON:-python3.9}
export SETUP_ADMIN_NOCREATION=${SETUP_ADMIN_NOCREATION:-false}
# SETUP_DEBUG can be set to get debug info
# SETUP_EXTRA_PIP can be set to install extra pip packages
# SETUP_PYTHON can be set to use a different python version
@ -36,14 +35,6 @@ detect_initcmd
detect_ip
detect_python
# Check if we are updating and need to alert
echo "# Checking if update checks are needed"
if [ -z "$2" ]; then
echo "# Normal install - no need for checks"
else
update_checks $2
fi
# create processes
create_initscripts
create_admin

View File

@ -1,20 +0,0 @@
#!/bin/bash
#
# packager.io preinstall/preremove script
#
PATH=${APP_HOME}/env/bin:${APP_HOME}/:/sbin:/bin:/usr/sbin:/usr/bin:
# Envs that should be passed to setup commands
export SETUP_ENVS=PATH,APP_HOME,INVENTREE_MEDIA_ROOT,INVENTREE_STATIC_ROOT,INVENTREE_BACKUP_DIR,INVENTREE_PLUGINS_ENABLED,INVENTREE_PLUGIN_FILE,INVENTREE_CONFIG_FILE,INVENTREE_SECRET_KEY_FILE,INVENTREE_DB_ENGINE,INVENTREE_DB_NAME,INVENTREE_DB_USER,INVENTREE_DB_PASSWORD,INVENTREE_DB_HOST,INVENTREE_DB_PORT,INVENTREE_ADMIN_USER,INVENTREE_ADMIN_EMAIL,INVENTREE_ADMIN_PASSWORD,SETUP_NGINX_FILE,SETUP_ADMIN_PASSWORD_FILE,SETUP_NO_CALLS,SETUP_DEBUG,SETUP_EXTRA_PIP,SETUP_PYTHON
if test -f "${APP_HOME}/env/bin/pip"; then
# Check if clear-generated is available
if sudo -u ${APP_USER} --preserve-env=$SETUP_ENVS bash -c "cd ${APP_HOME} && invoke clear-generated --help" > /dev/null 2>&1; then
echo "# Clearing precompiled files"
sudo -u ${APP_USER} --preserve-env=$SETUP_ENVS bash -c "cd ${APP_HOME} && invoke clear-generated"
else
echo "# Clearing precompiled files - skipping"
fi
else
echo "# No python environment found - skipping"
fi

View File

@ -1,14 +1,8 @@
# Configuration file for Crowdin project integration
# See: https://crowdin.com/project/inventree
"commit_message": "Fix: New translations %original_file_name% from Crowdin"
"append_commit_message": false
"preserve_hierarchy": true
files:
- source: /src/backend/InvenTree/locale/en/LC_MESSAGES/django.po
dest: /%original_path%/%original_file_name%
translation: /src/backend/InvenTree/locale/%two_letters_code%/LC_MESSAGES/%original_file_name%
- source: /src/frontend/src/locales/en/messages.po
dest: /%original_path%/%original_file_name%
translation: /src/frontend/src/locales/%two_letters_code%/%original_file_name%

4
docs/.gitignore vendored
View File

@ -13,10 +13,6 @@ site/
# Generated API schema files
docs/api/schema/*.yml
# Temporary cache files
url_cache.txt
invoke-commands.txt
# Temp files
releases.json
versions.json

View File

@ -10,7 +10,7 @@ tld = os.path.abspath(os.path.join(here, '..'))
config_file = os.path.join(tld, 'mkdocs.yml')
with open(config_file, encoding='utf-8') as f:
with open(config_file, 'r') as f:
data = yaml.load(f, yaml.BaseLoader)
assert data['strict'] == 'true'

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

View File

@ -4,11 +4,7 @@ title: Internal Barcodes
## Internal Barcodes
InvenTree ships with two integrated internal formats for generating barcodes for various items which are available through the built-in InvenTree Barcode plugin. The used format can be selected through the plugin settings of the InvenTree Barcode plugin.
### 1. JSON-based QR Codes
This format uses a simple JSON-style string to uniquely identify an item in the database.
InvenTree defines an internal format for generating barcodes for various items. This format uses a simple JSON-style string to uniquely identify an item in the database.
Some simple examples of this format are shown below:
@ -16,49 +12,10 @@ Some simple examples of this format are shown below:
| --- | --- |
| Part | `{% raw %}{"part": 10}{% endraw %}` |
| Stock Item | `{% raw %}{"stockitem": 123}{% endraw %}` |
| Stock Location | `{% raw %}{"stocklocation": 1}{% endraw %}` |
| Supplier Part | `{% raw %}{"supplierpart": 99}{% endraw %}` |
The numerical ID value used is the *Primary Key* (PK) of the particular object in the database.
#### Downsides
1. The JSON format includes binary only characters (`{% raw %}{{% endraw %}` and `{% raw %}"{% endraw %}`) which requires unnecessary use of the binary QR code encoding which means fewer amount of chars can be encoded with the same version of QR code.
2. The model name key has not a fixed length. Some model names are longer than others. E.g. a part QR code with the shortest possible id requires 11 chars, while a stock location QR code with the same id would already require 20 chars, which already requires QR code version 2 and quickly version 3.
!!! info "QR code versions"
There are 40 different qr code versions from 1-40. They all can encode more data than the previous version, but require more "squares". E.g. a V1 QR codes has 21x21 "squares" while a V2 already has 25x25. For more information see [QR code comparison](https://www.qrcode.com/en/about/version.html).
For a more detailed size analysis of the JSON-based QR codes refer to [this issue](https://github.com/inventree/InvenTree/issues/6612).
### 2. Short alphanumeric QR Codes
While JSON-based QR Codes encode all necessary information, they come with the described downsides. This new, short, alphanumeric only format is build to improve those downsides. The basic format uses an alphanumeric string: `INV-??x`
- `INV-` is a constant prefix. This is configurable in the InvenTree Barcode plugins settings per instance to support environments that use multiple instances.
- `??` is a two character alphanumeric (`0-9A-Z $%*+-./:` (45 chars)) code, individual to each model.
- `x` the actual pk of the model.
Now with an overhead of 6 chars for every model, this format supports the following amount of model instances using the described QR code modes:
| QR code mode | Alphanumeric mode | Mixed mode |
| --- | --- | --- |
| v1 M ECL (15%) | `10**14` items (~3.170 items per sec for 1000 years) | `10**20` items (~3.170.979.198 items per sec for 1000 years) |
| v1 Q ECL (25%) | `10**10` items (~0.317 items per sec for 1000 years) | `10**13` items (~317 items per sec for 1000 years) |
| v1 H ECL (30%) | `10**4` items (~100 items per day for 100 days) | `10**3` items (~100 items per day for 10 days (*even worse*)) |
!!! info "QR code mixed mode"
Normally the QR code data is encoded only in one format (binary, alphanumeric, numeric). But the data can also be split into multiple chunks using different formats. This is especially useful with long model ids, because the first 6 chars can be encoded using the alphanumeric mode and the id using the more efficient numeric mode. Mixed mode is used by default, because the `qrcode` template tag uses a default value for optimize of 1.
Some simple examples of this format are shown below:
| Model Type | Example Barcode |
| --- | --- |
| Part | `INV-PA10` |
| Stock Item | `INV-SI123` |
| Stock Location | `INV-SL1` |
| Supplier Part | `INV-SP99` |
## Report Integration
This barcode format can be used to generate 1D or 2D barcodes (e.g. for [labels and reports](../report/barcodes.md))

View File

@ -26,6 +26,14 @@ To navigate to the Build Order display, select *Build* from the main navigation
{% include "img.html" %}
{% endwith %}
#### Tree View
*Tree View* also provides a tabulated view of Build Orders. Orders are displayed in a hierarchical manner, showing any parent / child relationships between different build orders.
{% with id="build_tree", url="build/build_tree.png", description="Build Tree" %}
{% include "img.html" %}
{% endwith %}
#### Calendar View
*Calendar View* shows a calendar display with upcoming build orders, based on the various dates specified for each build.
@ -66,23 +74,10 @@ Each *Build Order* has an associated *Status* flag, which indicates the state of
| Status | Description |
| ----------- | ----------- |
| `Pending` | Build order has been created, but is not yet in production |
| `Production` | Build order is currently in production |
| `On Hold` | Build order has been placed on hold, but is still active |
| `Cancelled` | Build order has been cancelled |
| `Completed` | Build order has been completed |
**Source Code**
Refer to the source code for the Build Order status codes:
::: build.status_codes.BuildStatus
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []
| `Pending` | Build has been created and build is ready for subpart allocation |
| `Production` | One or more build outputs have been created for this build |
| `Cancelled` | Build has been cancelled |
| `Completed` | Build has been completed |
### Stock Allocations
@ -104,29 +99,41 @@ For further information, refer to the [stock allocation documentation](./allocat
## Build Order Display
The detail view for a single build order provides multiple display panels, as follows:
The detail view for a single build order provides multiple display tabs, as follows:
### Build Details
The *Build Details* panel provides an overview of the Build Order:
The *Build Details* tab provides an overview of the Build Order:
{% with id="build_details", url="build/build_panel_details.png", description="Build details panel" %}
{% with id="build_details", url="build/build_details.png", description="Details tab" %}
{% include "img.html" %}
{% endwith %}
### Line Items
### Allocate Stock
The *Line Items* panel displays all the line items (as defined by the [bill of materials](./bom.md)) required to complete the build order.
The *Allocate Stock* tab provides an interface to allocate required stock (as specified by the BOM) to the build:
{% with id="build_allocate", url="build/build_panel_line_items.png", description="Build line items panel" %}
{% with id="build_allocate", url="build/build_allocate.png", description="Allocation tab" %}
{% include "img.html" %}
{% endwith %}
The allocation table (as shown above) provides an interface to allocate required stock, and also shows the stock allocation progress for each line item in the build.
The allocation table (as shown above) shows the stock allocation progress for this build. In the example above, there are two BOM lines, which have been partially allocated.
### Incomplete Outputs
!!! info "Completed Builds"
The *Allocate Stock* tab is not available if the build has been completed!
The *Incomplete Outputs* panel shows the list of in-progress [build outputs](./output.md) (created stock items) associated with this build.
### Consumed Stock
The *Consumed Stock* tab displays all stock items which have been *consumed* by this build order. These stock items remain in the database after the build order has been completed, but are no longer available for use.
- [Tracked stock items](./allocate.md#tracked-stock) are consumed by specific build outputs
- [Untracked stock items](./allocate.md#untracked-stock) are consumed by the build order
### Build Outputs
The *Build Outputs* tab shows the [build outputs](./output.md) (created stock items) associated with this build.
As shown below, there are separate panels for *incomplete* and *completed* build outputs.
{% with id="build_outputs", url="build/build_outputs.png", description="Outputs tab" %}
{% include "img.html" %}
@ -139,48 +146,11 @@ The *Incomplete Outputs* panel shows the list of in-progress [build outputs](./o
- Outputs which are "in progress" can be completed or cancelled
- Completed outputs (which are simply *stock items*) can be viewed in the stock table at the bottom of the screen
### Completed Outputs
This panel displays all the completed build outputs (stock items) which have been created by this build order:
### Allocated Stock
The *Allocated Stock* tab displays all stock items which have been *allocated* to this build order. These stock items are reserved for this build, and will be consumed when the build is completed:
{% with id="allocated_stock_table", url="build/allocated_stock_table.png", description="Allocated Stock Table" %}
{% include "img.html" %}
{% endwith %}
### Consumed Stock
The *Consumed Stock* tab displays all stock items which have been *consumed* by this build order. These stock items remain in the database after the build order has been completed, but are no longer available for use.
- [Tracked stock items](./allocate.md#tracked-stock) are consumed by specific build outputs
- [Untracked stock items](./allocate.md#untracked-stock) are consumed by the build order
### Child Builds
If there exist any build orders which are *children* of the selected build order, they are displayed in the *Child Builds* tab:
{% with id="build_childs", url="build/build_childs.png", description="Child builds panel" %}
{% include "img.html" %}
{% endwith %}
### Test Results
For *trackable* parts, test results can be recorded against each build output. These results are displayed in the *Test Results* panel:
{% with id="build_test_results", url="build/build_panel_test_results.png", description="Test Results panel" %}
{% include "img.html" %}
{% endwith %}
This table provides a summary of the test results for each build output, and allows test results to be quickly added for each build output.
### Test Statistics
For *trackable* parts, this panel displays a summary of the test results for all build outputs:
{% with id="build_test_stats", url="build/build_panel_test_statistics.png", description="Test Statistics panel" %}
{% with id="build_childs", url="build/build_childs.png", description="Child builds tab" %}
{% include "img.html" %}
{% endwith %}
@ -221,10 +191,6 @@ To create a build order for your part, you have two options:
Fill-out the form as required, then click the "Submit" button to create the build.
### Create Child Builds
When creating a new build order, you have the option to automatically generate build orders for any subassembly parts. This can be useful to create a complete tree of build orders for a complex assembly. *However*, it must be noted that any build orders created for subassemblies will use the default BOM quantity for that part. Any child build orders created in this manner must be manually reviewed, to ensure that the correct quantity is being built as per your production requirements.
## Complete Build Order
To complete a build, click on <span class='fas fa-tools'></span> icon on the build detail page, the `Complete Build` form will be displayed.
@ -268,17 +234,3 @@ Build orders may (optionally) have a target complete date specified. If this dat
- Builds can be filtered by overdue status in the build list
- Overdue builds will be displayed on the home page
## Build Order Settings
The following [global settings](../settings/global.md) are available for adjusting the behavior of build orders:
| Name | Description | Default | Units |
| ---- | ----------- | ------- | ----- |
{{ globalsetting("BUILDORDER_REFERENCE_PATTERN") }}
{{ globalsetting("BUILDORDER_REQUIRE_RESPONSIBLE") }}
{{ globalsetting("BUILDORDER_REQUIRE_ACTIVE_PART") }}
{{ globalsetting("BUILDORDER_REQUIRE_LOCKED_PART") }}
{{ globalsetting("BUILDORDER_REQUIRE_VALID_BOM") }}
{{ globalsetting("BUILDORDER_REQUIRE_CLOSED_CHILDS") }}
{{ globalsetting("PREVENT_BUILD_COMPLETION_HAVING_INCOMPLETED_TESTS") }}

View File

@ -1,15 +0,0 @@
---
title: Custom States
---
## Custom States
Several models within InvenTree support the use of custom states. The custom states are display only - the business logic is not affected by the state.
States can be added in the Admin Center under the "Custom States" section. Each state has a name, label and a color that are used to display the state in the user interface. Changes to these settings will only be reflected in the user interface after a full reload of the interface.
States need to be assigned to a model, state (for example status on a StockItem) and a logical key - that will be used for business logic. These 3 values combined need to be unique throughout the system.
Custom states can be used in the following models:
- StockItem
- Orders (PurchaseOrder, SalesOrder, ReturnOrder, ReturnOrderLine)

View File

@ -4,22 +4,4 @@ title: InvenTree Demo
## InvenTree Demo
If you are interested in trying out InvenTree, you can access the InvenTree demo instance at [https://demo.inventree.org](https://demo.inventree.org).
This page is populated with a sample dataset, which is reset every 24 hours.
You can read more about the InvenTree demo here: [https://inventree.org/demo.html](https://inventree.org/demo.html)
### User Accounts
The demo instance has a number of user accounts which you can use to explore the system:
| Username | Password | Staff Access | Enabled | Description |
| -------- | -------- | ------------ | ------- | ----------- |
| allaccess | nolimits | No | Yes | View / create / edit all pages and items |
| reader | readonly | No | Yes | Can view all pages but cannot create, edit or delete database records |
| engineer | partsonly | No | Yes | Can manage parts, view stock, but no access to purchase orders or sales orders |
| steven | wizardstaff | Yes | Yes | Staff account, can access some admin sections |
| ian | inactive | No | No | Inactive account, cannot log in |
| susan | inactive | No | No | Inactive account, cannot log in |
| admin | inventree | Yes | Yes | Superuser account, can access all parts of the system |
This page has moved to [https://inventree.org/demo.html](https://inventree.org/demo.html)

View File

@ -22,9 +22,9 @@ To setup a development environment using [docker](../start/docker.md), run the f
```bash
git clone https://github.com/inventree/InvenTree.git && cd InvenTree
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run --rm inventree-dev-server invoke install
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run --rm inventree-dev-server invoke setup-test --dev
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml up -d
docker compose run inventree-dev-server invoke install
docker compose run inventree-dev-server invoke setup-test --dev
docker compose up -d
```
### Bare Metal
@ -54,23 +54,13 @@ invoke setup-dev
InvenTree roughly follow the [GitLab flow](https://docs.gitlab.com/ee/topics/gitlab_flow.html) branching style, to allow simple management of multiple tagged releases, short-lived branches, and development on the main branch.
There are nominally 5 active branches:
- `master` - The main development branch
- `stable` - The latest stable release
- `l10n` - Translation branch: Source to Crowdin
- `l10_crowdin` - Translation branch: Source from Crowdin
- `y.y.x` - Release branch for the currently supported version (e.g. `0.5.x`)
All other branches are removed periodically by maintainers or core team members. This includes old release branches.
Do not use them as base for feature development or forks as patches from them might not be accepted without rebasing.
### Version Numbering
InvenTree version numbering follows the [semantic versioning](https://semver.org/) specification.
### Main Development Branch
### Master Branch
The HEAD of the "master" branch of InvenTree represents the current "latest" state of code development.
The HEAD of the "main" or "master" branch of InvenTree represents the current "latest" state of code development.
- All feature branches are merged into master
- All bug fixes are merged into master
@ -83,6 +73,7 @@ Feature branches should be branched *from* the *master* branch.
- One major feature per branch / pull request
- Feature pull requests are merged back *into* the master branch
- Features *may* also be merged into a release candidate branch
### Stable Branch
@ -91,28 +82,21 @@ The HEAD of the "stable" branch represents the latest stable release code.
- Versioned releases are merged into the "stable" branch
- Bug fix branches are made *from* the "stable" branch
#### Release Candidate Branches
### Bugfix Branches
- Release candidate branches are made from master, and merged into stable.
- RC branches are targeted at a major/minor version e.g. "0.5"
- When a release candidate branch is merged into *stable*, the release is tagged
#### Bugfix Branches
- If a bug is discovered in a tagged release version of InvenTree, a "bugfix" or "hotfix" branch should be made *from* that tagged release
- When approved, the branch is merged back *into* stable, with an incremented PATCH number (e.g. 0.4.1 -> 0.4.2)
- The bugfix *must* also be cherry picked into the *master* branch.
- A bugfix *might* also be backported from *master* to the *stable* branch automatically if marked with the `backport` label.
### Translation Branches
Crowdin is used for web-based translation management. The handling of files is fully automated, the `l10n` and `l10_crowdin` branches are used to manage the translation process and are not meant to be touched manually by anyone.
The translation process is as follows:
1. Commits to `master` trigger CI by GitHub Actions
2. Translation source files are created and automatically pushed to the `l10n` branch - this is the source branch for Crowdin
3. Crowdin picks up on the new source files and makes them available for translation
4. Translations made in Crowdin are automatically pushed back to the `l10_crowdin` branch by Crowdin once they are approved
5. The `l10_crowdin` branch is merged back into `master` by a maintainer periodically
## API versioning
The [API version]({{ sourcefile("src/backend/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.15.x/src/backend/InvenTree/InvenTree/api_version.py) needs to be bumped every time when the API is changed.
## Environment
@ -125,7 +109,7 @@ The core software modules are targeting the following versions:
| Python | {{ config.extra.min_python_version }} | Minimum required version |
| Invoke | {{ config.extra.min_invoke_version }} | Minimum required version |
| Django | {{ config.extra.django_version }} | Pinned version |
| Node | 20 | Only needed for frontend development |
| Node | 18 | Only needed for frontend development |
Any other software dependencies are handled by the project package config.

View File

@ -18,13 +18,12 @@ You need to make sure that you have the following tools installed before continu
#### Docker Containers
The InvenTree devcontainer setup will install the following docker containers:
The InvenTree devcontainer setup will install two docker containers:
| Container | Description |
| --- | --- |
| inventree | InvenTree host server |
| db | InvenTree database (postgresql) |
| redis | Redis server for caching |
| inventree | InvenTree server |
#### Setup/Installation
@ -67,7 +66,7 @@ If you need to process your queue with background workers, run the `worker` task
You can either only run InvenTree or use the integrated debugger for debugging. Goto the `Run and debug` side panel make sure `InvenTree Server` is selected. Click on the play button on the left.
!!! tip "Debug with 3rd party"
Sometimes you need to debug also some 3rd party packages. Just select `InvenTree Server - 3rd party`
Sometimes you need to debug also some 3rd party packages. Just select `InvenTree Servre - 3rd party`
You can now set breakpoints and vscode will automatically pause execution if that point is hit. You can see all variables available in that context and evaluate some code with the debugger console at the bottom. Use the play or step buttons to continue execution.
@ -120,9 +119,3 @@ If you are running a devcontainer in Windows, you may experience some performanc
For a significant improvement in performance, the source code should be installed into the **WSL 2** filesystem (not on your "Windows" filesystem). This will greatly improve file access performance, and also make the devcontainer much more responsive to file system changes.
You can also refer to the [Improve disk performance guide](https://code.visualstudio.com/remote/advancedcontainers/improve-performance) for more information.
### Redis Caching
The devcontainer setup provides a [redis](https://redis.io/) container which can be used for managing global cache. By default this is disabled, but it can be easily enabled for testing or developing with the [redis cache](../start/config.md#caching) enabled.
To enable the cache, locate the InvenTree configuration file (`./dev/config.yaml`) and set the `cache.enabled` setting to `True`.

View File

@ -149,7 +149,7 @@ class SampleActionPlugin(ActionMixin, InvenTreePlugin):
# metadata
AUTHOR = "Sample Author"
DESCRIPTION = "A very basic plugin with one mixin"
PUBLISH_DATE = "2222-02-22"
PUBLISH_DATE = "22.02.2222"
VERSION = "1.2.3" # We recommend semver and increase the major version with each new major release of InvenTree
WEBSITE = "https://example.com/"
LICENSE = "MIT" # use what you want - OSI approved is &hearts;

View File

@ -6,9 +6,6 @@ title: Machines
InvenTree has a builtin machine registry. There are different machine types available where each type can have different drivers. Drivers and even custom machine types can be provided by plugins.
!!! info "Requires Redis"
If the machines features is used in production setup using workers, a shared [redis cache](../../start/docker.md#redis-cache) is required to function properly.
### Registry
The machine registry is the main component which gets initialized on server start and manages all configured machines.
@ -24,13 +21,6 @@ The machine registry initialization process can be divided into three stages:
2. The driver.init_driver function is called for each used driver
3. The machine.initialize function is called for each machine, which calls the driver.init_machine function for each machine, then the machine.initialized state is set to true
#### Production setup (with a worker)
If a worker is connected, there exist multiple instances of the machine registry (one in each worker thread and one in the main thread) due to the nature of how python handles state in different processes. Therefore the machine instances and drivers are instantiated multiple times (The `__init__` method is called multiple times). But the init functions and update hooks (e.g. `init_machine`) are only called once from the main process.
The registry, driver and machine state (e.g. machine status codes, errors, ...) is stored in the cache. Therefore a shared redis cache is needed. (The local in-memory cache which is used by default is not capable to cache across multiple processes)
### Machine types
Each machine type can provide a different type of connection functionality between inventree and a physical machine. These machine types are already built into InvenTree.
@ -47,8 +37,6 @@ If you want to create your own machine type, please also take a look at the alre
```py
from django.utils.translation import gettext_lazy as _
from generic.states import ColorEnum
from plugin.machine import BaseDriver, BaseMachineType, MachineStatus
class ABCBaseDriver(BaseDriver):
@ -74,9 +62,9 @@ class ABCMachine(BaseMachineType):
base_driver = ABCBaseDriver
class ABCStatus(MachineStatus):
CONNECTED = 100, _('Connected'), ColorEnum.success
STANDBY = 101, _('Standby'), ColorEnum.success
PRINTING = 110, _('Printing'), ColorEnum.primary
CONNECTED = 100, _('Connected'), 'success'
STANDBY = 101, _('Standby'), 'success'
PRINTING = 110, _('Printing'), 'primary'
MACHINE_STATUS = ABCStatus
default_machine_status = ABCStatus.DISCONNECTED
@ -98,7 +86,6 @@ The machine type class gets instantiated for each machine on server startup and
- update
- restart
- handle_error
- clear_errors
- get_setting
- set_setting
- check_setting

View File

@ -9,14 +9,14 @@ The InvenTree server code supports an extensible plugin architecture, allowing c
Plugins can be added from multiple sources:
- Plugins can be installed in InvenTrees venv via PIP (python package manager)
- Custom plugins should be placed in the directory `./data/plugins`.
- Custom plugins should be placed in the directory `./src/backend/InvenTree/plugins`.
- InvenTree built-in plugins are located in the directory `./src/backend/InvenTree/plugin/builtin`.
For further information, read more about [installing plugins](./plugins/install.md).
### Plugin Base Class
Custom plugins must inherit from the [InvenTreePlugin class]({{ sourcefile("src/backend/InvenTree/plugin/plugin.py") }}). 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/2d1776a151721d65d0ae007049d358085b2fcfd5/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]({{ sourcefile("src/backend/InvenTree/plugin/__init__.py") }}). These include:
General classes and mechanisms are provided under the `plugin` [namespaces](https://github.com/inventree/InvenTree/blob/0.15.x/src/backend/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 [can be found here]({{ sourcefile("src/backend/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.15.x/src/backend/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]({{ sourcedir("src/backend/InvenTree/plugin/samples") }}) for further examples.
Refer to the [sample plugins](https://github.com/inventree/InvenTree/tree/master/src/backend/InvenTree/plugin/samples) for further examples.
### Plugin Config

View File

@ -15,14 +15,4 @@ POST {
}
```
### Sample Plugin
A sample action plugin is provided in the `InvenTree` source code, which can be used as a template for creating custom action plugins:
::: plugin.samples.integration.simpleactionplugin.SimpleActionPlugin
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []
For an example of a very simple action plugin, refer to `/src/backend/InvenTree/plugin/samples/integratoni/simpleactionplugin.py`

View File

@ -5,15 +5,3 @@ title: Schedule Mixin
## APICallMixin
The APICallMixin class provides basic functionality for integration with an external API.
### Sample Plugin
The following example demonstrates how to use the `APICallMixin` class to make a simple API call:
::: plugin.samples.integration.api_caller.SampleApiCallerPlugin
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []

View File

@ -2,11 +2,11 @@
title: Barcode Mixin
---
## Barcode Plugins
### Barcode Plugins
InvenTree supports decoding of arbitrary barcode data and generation of internal barcode formats via a **Barcode Plugin** interface. Barcode data POSTed to the `/api/barcode/` endpoint will be supplied to all loaded barcode plugins, and the first plugin to successfully interpret the barcode data will return a response to the client.
InvenTree supports decoding of arbitrary barcode data via a **Barcode Plugin** interface. Barcode data POSTed to the `/api/barcode/` endpoint will be supplied to all loaded barcode plugins, and the first plugin to successfully interpret the barcode data will return a response to the client.
InvenTree can generate native QR codes to represent database objects (e.g. a single StockItem). This barcode can then be used to perform quick lookup of a stock item or location in the database. A client application (for example the InvenTree mobile app) scans a barcode, and sends the barcode data to the InvenTree server. The server then uses the **InvenTreeBarcodePlugin** (found at `src/backend/InvenTree/plugin/builtin/barcodes/inventree_barcode.py`) to decode the supplied barcode data.
InvenTree can generate native QR codes to represent database objects (e.g. a single StockItem). This barcode can then be used to perform quick lookup of a stock item or location in the database. A client application (for example the InvenTree mobile app) scans a barcode, and sends the barcode data to the InvenTree server. The server then uses the **InvenTreeBarcodePlugin** (found at `/src/backend/InvenTree/plugins/barcode/inventree.py`) to decode the supplied barcode data.
Any third-party barcodes can be decoded by writing a matching plugin to decode the barcode data. These plugins could then perform a server-side action or render a JSON response back to the client for further action.
@ -24,27 +24,15 @@ POST {
}
```
### Builtin Plugin
The InvenTree server includes a builtin barcode plugin which can generate and decode the QR codes. This plugin is enabled by default.
::: plugin.builtin.barcodes.inventree_barcode.InvenTreeInternalBarcodePlugin
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []
### Example Plugin
Please find below a very simple example that is used to return a part if the barcode starts with `PART-`
### Example
Please find below a very simple example that is executed each time a barcode is scanned.
```python
from django.utils.translation import gettext_lazy as _
from InvenTree.models import InvenTreeBarcodeMixin
from plugin import InvenTreePlugin
from plugin.mixins import BarcodeMixin
from part.models import Part
class InvenTreeBarcodePlugin(BarcodeMixin, InvenTreePlugin):
@ -54,39 +42,16 @@ class InvenTreeBarcodePlugin(BarcodeMixin, InvenTreePlugin):
VERSION = "0.0.1"
AUTHOR = "Michael"
def scan(self, barcode_data):
if barcode_data.startswith("PART-"):
try:
pk = int(barcode_data.split("PART-")[1])
instance = Part.objects.get(pk=pk)
label = Part.barcode_model_type()
status = 0
def scan(self, barcode_data):
self.status = self.status+1
print('Started barcode plugin', self.status)
print(barcode_data)
response = {}
return response
return {label: instance.format_matched_response()}
except Part.DoesNotExist:
pass
```
To try it just copy the file to src/InvenTree/plugins and restart the server. Open the scan barcode window and start to scan codes or type in text manually. Each time the timeout is hit the plugin will execute and printout the result. The timeout can be changed in `Settings->Barcode Support->Barcode Input Delay`.
### Custom Internal Format
To implement a custom internal barcode format, the `generate(...)` method from the Barcode Mixin needs to be overridden. Then the plugin can be selected at `System Settings > Barcodes > Barcode Generation Plugin`.
```python
from InvenTree.models import InvenTreeBarcodeMixin
from plugin import InvenTreePlugin
from plugin.mixins import BarcodeMixin
class InvenTreeBarcodePlugin(BarcodeMixin, InvenTreePlugin):
NAME = "MyInternalBarcode"
TITLE = "My Internal Barcodes"
DESCRIPTION = "support for custom internal barcodes"
VERSION = "0.0.1"
AUTHOR = "InvenTree contributors"
def generate(self, model_instance: InvenTreeBarcodeMixin):
return f'{model_instance.barcode_model_type()}: {model_instance.pk}'
```
!!! info "Scanning implementation required"
The parsing of the custom format needs to be implemented too, so that the scanning of the generated QR codes resolves to the correct part.

View File

@ -6,24 +6,7 @@ title: Currency Exchange Mixin
The `CurrencyExchangeMixin` class enabled plugins to provide custom backends for updating currency exchange rate information.
Any implementing classes must provide the `update_exchange_rates` method.
### Builtin Plugin
The default builtin plugin for handling currency exchange rates is the `InvenTreeCurrencyExchangePlugin` class.
::: plugin.builtin.integration.currency_exchange.InvenTreeCurrencyExchange
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []
### Sample Plugin
A simple example is shown below (with fake data).
Any implementing classes must provide the `update_exchange_rates` method. A simple example is shown below (with fake data).
```python

View File

@ -15,34 +15,56 @@ When a certain (server-side) event occurs, the background worker passes the even
{% include 'img.html' %}
{% endwith %}
### Sample Plugin - All events
### Example (all events)
Implementing classes must at least provide a `process_event` function:
::: plugin.samples.event.event_sample.EventPluginSample
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []
```python
class EventPlugin(EventMixin, InvenTreePlugin):
"""
A simple example plugin which responds to events on the InvenTree server.
### Sample Plugin - Specific Events
This example simply prints out the event information.
A more complex plugin could respond to specific events however it wanted.
"""
NAME = "EventPlugin"
SLUG = "event"
TITLE = "Triggered Events"
def process_event(self, event, *args, **kwargs):
print(f"Processing triggered event: '{event}'")
```
### Example (specific events)
If you want to process just some specific events, you can also implement the `wants_process_event` function to decide if you want to process this event or not. This function will be executed synchronously, so be aware that it should contain simple logic.
Overall this function can reduce the workload on the background workers significantly since less events are queued to be processed.
::: plugin.samples.event.filtered_event_sample.FilteredEventPluginSample
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []
```python
class EventPlugin(EventMixin, InvenTreePlugin):
"""
A simple example plugin which responds to 'salesordershipment.completed' event on the InvenTree server.
This example simply prints out the event information.
A more complex plugin can run enhanced logic on this event.
"""
## Events
NAME = "EventPlugin"
SLUG = "event"
TITLE = "Triggered Events"
def wants_process_event(self, event):
"""Here you can decide if this event should be send to `process_event` or not."""
return event == "salesordershipment.completed"
def process_event(self, event, *args, **kwargs):
"""Here you can run you'r specific logic."""
print(f"Sales order was completely shipped: '{args}' '{kwargs}'")
```
### Events
Events are passed through using a string identifier, e.g. `build.completed`

View File

@ -1,19 +0,0 @@
---
title: Icon Pack Mixin
---
## IconPackMixin
The IconPackMixin class provides basic functionality for letting plugins expose custom icon packs that are available in the InvenTree UI. This is especially useful to provide a custom crafted icon pack with icons for different location types, e.g. different sizes and styles of drawers, bags, ESD bags, ... which are not available in the standard tabler icons library.
### Sample Plugin
The following example demonstrates how to use the `IconPackMixin` class to add a custom icon pack:
::: plugin.samples.icons.icon_sample.SampleIconPlugin
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []

View File

@ -74,10 +74,10 @@ Admin users can install plugins directly from the web interface, via the "Plugin
#### Local Directory
Custom plugins can be placed in the `data/plugins/` directory, where they will be automatically discovered. This can be useful for developing and testing plugins, but can prove more difficult in production (e.g. when using Docker).
Custom plugins can be placed in the `src/InvenTree/plugins/` directory, where they will be automatically discovered. This can be useful for developing and testing plugins, but can prove more difficult in production (e.g. when using Docker).
!!! info "Git Tracking"
The `data/plugins/` directory is excluded from Git version tracking - any plugin files here will be hidden from Git
The `src/backend/InvenTree/plugins/` directory is excluded from Git version tracking - any plugin files here will be hidden from Git
!!! warning "Not Recommended For Production"
Loading plugins via the local *plugins* directory is not recommended for production. If you cannot use PIP installation (above), specify a custom plugin directory (below) or use a [VCS](https://pip.pypa.io/en/stable/topics/vcs-support/) as a plugin install source.

View File

@ -172,14 +172,6 @@ InvenTree supplies the `InvenTreeLabelPlugin` out of the box, which generates a
The default plugin also features a *DEBUG* mode which generates a raw HTML output, rather than PDF. This can be handy for tracking down any template rendering errors in your labels.
::: plugin.builtin.labels.inventree_label.InvenTreeLabelPlugin
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []
### Available Data
The *label* data are supplied to the plugin in both `PDF` and `PNG` formats. This provides compatibility with a great range of label printers "out of the box". Conversion to other formats, if required, is left as an exercise for the plugin developer.

View File

@ -28,16 +28,4 @@ If a locate plugin is installed and activated, the [InvenTree mobile app](../../
### Implementation
Refer to the [InvenTree source code]({{ sourcefile("src/backend/InvenTree/plugin/samples/locate/locate_sample.py") }}) for a simple implementation example.
### Sample Plugin
A simple example is provided in the InvenTree code base:
::: plugin.samples.locate.locate_sample.SampleLocatePlugin
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []
Refer to the [InvenTree source code](https://github.com/inventree/InvenTree/blob/0.15.x/src/backend/InvenTree/plugin/samples/locate/locate_sample.py) for a simple implementation example.

View File

@ -52,18 +52,6 @@ Or to add a template file that will be rendered as javascript code, from the plu
Note : see convention for template directory above.
## Sample Plugin
A sample plugin is provided in the InvenTree code base:
::: plugin.samples.integration.custom_panel_sample.CustomPanelSample
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []
## Example Implementations
Refer to the `CustomPanelSample` example class in the `./plugin/samples/integration/` directory, for a fully worked example of how custom UI panels can be implemented.

View File

@ -14,14 +14,48 @@ A plugin which implements the ReportMixin mixin can define the `add_report_conte
Additionally the `add_label_context` method, allowing custom context data to be added to a label template at time of printing.
### Sample Plugin
### Example
A sample plugin which provides additional context data to the report templates is available:
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.15.x/src/backend/InvenTree/plugin/samples/integration/report_plugin_sample.py):
::: plugin.samples.integration.report_plugin_sample.SampleReportPlugin
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []
```python
"""Sample plugin for extending reporting functionality"""
import random
from plugin import InvenTreePlugin
from plugin.mixins import ReportMixin
from report.models import PurchaseOrderReport
class SampleReportPlugin(ReportMixin, InvenTreePlugin):
"""Sample plugin which provides extra context data to a report"""
NAME = "Sample Report Plugin"
SLUG = "reportexample"
TITLE = "Sample Report Plugin"
DESCRIPTION = "A sample plugin which provides extra context data to a report"
VERSION = "1.0"
def some_custom_function(self):
"""Some custom function which is not required for the plugin to function"""
return random.randint(0, 100)
def add_report_context(self, report_instance, model_instance, request, context):
"""Add example content to the report instance"""
# We can add any extra context data we want to the report
# Generate a random string of data
context['random_text'] = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz', k=20))
# Call a custom method
context['random_int'] = self.some_custom_function()
# We can also add extra data to the context which is specific to the report type
context['is_purchase_order'] = isinstance(report_instance, PurchaseOrderReport)
# We can also use the 'request' object to add extra context data
context['request_method'] = request.method
```

View File

@ -18,14 +18,45 @@ The ScheduleMixin class provides a plugin with the ability to call functions at
{% include 'img.html' %}
{% endwith %}
### SamplePlugin
### Example
An example of a plugin which supports scheduled tasks:
::: plugin.samples.integration.scheduled_task.ScheduledTaskPlugin
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []
```python
class ScheduledTaskPlugin(ScheduleMixin, SettingsMixin, InvenTreePlugin):
"""
Sample plugin which runs a scheduled task, and provides user configuration.
"""
NAME = "Scheduled Tasks"
SLUG = 'schedule'
SCHEDULED_TASKS = {
'global': {
'func': 'some_module.function',
'schedule': 'H', # Run every hour
},
'member': {
'func': 'foo',
'schedule': 'I', # Minutes
'minutes': 15,
},
}
SETTINGS = {
'SECRET': {
'name': 'A secret',
'description': 'User configurable value',
},
}
def foo(self):
"""
This function runs every 15 minutes
"""
secret_value = self.get_setting('SECRET')
print(f"foo - SECRET = {secret_value})
```
!!! 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/0.15.x/src/backend/InvenTree/plugin/samples/integration/scheduled_task.py).

View File

@ -15,7 +15,7 @@ The dict must be formatted similar to the following sample that shows how to use
Take a look at the settings defined in `InvenTree.common.models.InvenTreeSetting` for all possible parameters.
### Example Plugin
### Example
Below is a simple example of how a plugin can implement settings:

View File

@ -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]({{ sourcefile("src/backend/InvenTree/templates/page_base.html") }}). Look through this file to determine overridable blocks. The [stock app]({{ sourcedir("src/backend/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.15.x/src/backend/InvenTree/templates/page_base.html). Look through this file to determine overridable blocks. The [stock app](https://github.com/inventree/InvenTree/tree/master/src/backend/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.

View File

@ -9,40 +9,34 @@ 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]({{ sourcefile("src/backend/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.15.x/src/backend/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.
## Model Deletion
Any model which inherits the `PluginValidationMixin` class is exposed to the plugin system for custom deletion validation. Before the model is deleted from the database, it is first passed to the plugin ecosystem to check if it really should be deleted.
A custom plugin may implement the `validate_model_deletion` method to perform custom validation on the model instance before it is deleted.
::: plugin.base.integration.ValidationMixin.ValidationMixin.validate_model_deletion
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_sources: True
summary: False
members: []
## Model Validation
Any model which inherits the `PluginValidationMixin` mixin class is exposed to the plugin system for custom validation. Before the model is saved to the database (either when created, or updated), it is first passed to the plugin ecosystem for validation.
Any plugin which inherits the `ValidationMixin` can implement the `validate_model_instance` method, and run a custom validation routine.
::: plugin.base.integration.ValidationMixin.ValidationMixin.validate_model_instance
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_sources: True
summary: False
members: []
The `validate_model_instance` method is passed the following arguments:
| Argument | Description |
| --- | --- |
| `instance` | The model instance to be validated |
| `deltas` | A dict of field deltas (if the instance is being updated) |
```python
def validate_model_instance(self, instance, deltas=None):
"""Validate the supplied model instance.
Arguments:
instance: The model instance to be validated
deltas: A dict of field deltas (if the instance is being updated)
"""
...
```
### Error Messages
@ -58,7 +52,7 @@ To indicate a *field* validation error (i.e. the validation error applies only t
Note that an error can be which corresponds to multiple model instance fields.
### Example Plugin
### Example
Presented below is a simple working example for a plugin which implements the `validate_model_instance` method:
@ -108,70 +102,21 @@ By default, part names are not subject to any particular naming conventions or r
If the custom method determines that the part name is *objectionable*, it should throw a `ValidationError` which will be handled upstream by parent calling methods.
::: plugin.base.integration.ValidationMixin.ValidationMixin.validate_part_name
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_sources: True
summary: False
members: []
### Part IPN
Validation of the Part IPN (Internal Part Number) field is exposed to custom plugins via the `validate_part_ipn` method. Any plugins which extend the `ValidationMixin` class can implement this method, and raise a `ValidationError` if the IPN value does not match a required convention.
::: plugin.base.integration.ValidationMixin.ValidationMixin.validate_part_ipn
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_sources: True
summary: False
members: []
Validation of the Part IPN (Internal Part Number) field is exposed to custom plugins via the `validate_part_IPN` method. Any plugins which extend the `ValidationMixin` class can implement this method, and raise a `ValidationError` if the IPN value does not match a required convention.
### Part Parameter Values
[Part parameters](../../part/parameter.md) can also have custom validation rules applied, by implementing the `validate_part_parameter` method. A plugin which implements this method should raise a `ValidationError` with an appropriate message if the part parameter value does not match a required convention.
::: plugin.base.integration.ValidationMixin.ValidationMixin.validate_part_parameter
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_sources: True
summary: False
members: []
### Batch Codes
[Batch codes](../../stock/tracking.md#batch-codes) can be generated and/or validated by custom plugins.
#### Validate Batch Code
The `validate_batch_code` method allows plugins to raise an error if a batch code input by the user does not meet a particular pattern.
::: plugin.base.integration.ValidationMixin.ValidationMixin.validate_batch_code
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_sources: True
summary: False
members: []
#### Generate Batch Code
The `generate_batch_code` method can be implemented to generate a new batch code, based on a set of provided information.
::: plugin.base.integration.ValidationMixin.ValidationMixin.generate_batch_code
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_sources: True
summary: False
members: []
The `generate_batch_code` method can be implemented to generate a new batch code.
### Serial Numbers
@ -183,30 +128,17 @@ The default InvenTree [serial numbering system](../../stock/tracking.md#serial-n
Custom serial number validation can be implemented using the `validate_serial_number` method. A *proposed* serial number is passed to this method, which then has the opportunity to raise a `ValidationError` to indicate that the serial number is not valid.
::: plugin.base.integration.ValidationMixin.ValidationMixin.validate_serial_number
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_sources: True
summary: False
members: []
!!! info "Stock Item"
If the `stock_item` argument is provided, then this stock item has already been assigned with the provided serial number. This stock item should be excluded from any subsequent checks for *uniqueness*. The `stock_item` parameter is optional, and may be `None` if the serial number is being validated in a context where no stock item is available.
##### Example
A plugin which requires all serial numbers to be valid hexadecimal values may implement this method as follows:
```python
def validate_serial_number(self, serial: str, part: Part, stock_item: StockItem = None):
def validate_serial_number(self, serial: str, part: Part):
"""Validate the supplied serial number
Arguments:
serial: The proposed serial number (string)
part: The Part instance for which this serial number is being validated
stock_item: The StockItem instance for which this serial number is being validated
"""
try:
@ -222,15 +154,6 @@ While InvenTree supports arbitrary text values in the serial number fields, behi
A custom plugin can implement the `convert_serial_to_int` method to determine how a particular serial number is converted to an integer representation.
::: plugin.base.integration.ValidationMixin.ValidationMixin.convert_serial_to_int
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_sources: True
summary: False
members: []
!!! info "Not Required"
If this method is not implemented, or the serial number cannot be converted to an integer, then the sorting algorithm falls back to the text (string) value
@ -240,15 +163,6 @@ A core component of the InvenTree serial number system is the ability to *increm
For custom serial number schemes, it is important to provide a method to generate the *next* serial number given a current value. The `increment_serial_number` method can be implemented by a plugin to achieve this.
::: plugin.base.integration.ValidationMixin.ValidationMixin.increment_serial_number
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_sources: True
summary: False
members: []
!!! info "Invalid Increment"
If the provided number cannot be incremented (or an error occurs) the method should return `None`
@ -268,15 +182,3 @@ def increment_serial_number(self, serial: str):
return val
```
## Sample Plugin
A sample plugin which implements custom validation routines is provided in the InvenTree source code:
::: plugin.samples.integration.validation_sample.SampleValidatorPlugin
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []

View File

@ -14,7 +14,7 @@ Navigate to the "Settings" page and click on the "Display" tab, you should see t
{% include 'img.html' %}
{% endwith %}
The drop-down list let's you select any other color theme found in your static folder (see next section to find out how to [add color themes](#add-color-theme)). Once selected, click on the "Apply Theme" button for the new color theme to be activated.
The drop-down list let's you select any other color theme found in your static folder (see next section to find out how to [add color themes](#add-color-themes)). Once selected, click on the "Apply Theme" button for the new color theme to be activated.
!!! info "Per-user Setting"
Color themes are "user specific" which means that changing the color theme in your own settings won't affect other users.

View File

@ -57,7 +57,7 @@ def fetch_rtd_versions():
versions = sorted(versions, key=lambda x: StrictVersion(x['version']), reverse=True)
# Add "latest" version first
if not any(x['title'] == 'latest' for x in versions):
if not any((x['title'] == 'latest' for x in versions)):
versions.insert(
0,
{
@ -70,7 +70,7 @@ def fetch_rtd_versions():
# Ensure we have the 'latest' version
current_version = os.environ.get('READTHEDOCS_VERSION', None)
if current_version and not any(x['title'] == current_version for x in versions):
if current_version and not any((x['title'] == current_version for x in versions)):
versions.append({
'version': current_version,
'title': current_version,
@ -82,7 +82,7 @@ def fetch_rtd_versions():
print('Discovered the following versions:')
print(versions)
with open(output_filename, 'w', encoding='utf-8') as file:
with open(output_filename, 'w') as file:
json.dump(versions, file, indent=2)
@ -100,7 +100,7 @@ def get_release_data():
# Release information has been cached to file
print("Loading release information from 'releases.json'")
with open(json_file, encoding='utf-8') as f:
with open(json_file) as f:
return json.loads(f.read())
# Download release information via the GitHub API
@ -127,7 +127,7 @@ def get_release_data():
page += 1
# Cache these results to file
with open(json_file, 'w', encoding='utf-8') as f:
with open(json_file, 'w') as f:
print("Saving release information to 'releases.json'")
f.write(json.dumps(releases))
@ -173,7 +173,7 @@ def on_config(config, *args, **kwargs):
# Add *all* readthedocs related keys
readthedocs = {}
for key in os.environ:
for key in os.environ.keys():
if key.startswith('READTHEDOCS_'):
k = key.replace('READTHEDOCS_', '').lower()
readthedocs[k] = os.environ[key]

View File

@ -20,25 +20,8 @@ Each Purchase Order has a specific status code which indicates the current state
| --- | --- |
| Pending | The purchase order has been created, but has not been submitted to the supplier |
| In Progress | The purchase order has been issued to the supplier, and is in progress |
| On Hold | The purchase order has been placed on hold, but is still active |
| Complete | The purchase order has been completed, and is now closed |
| Cancelled | The purchase order was cancelled, and is now closed |
| Lost | The purchase order was lost, and is now closed |
| Returned | The purchase order was returned, and is now closed |
**Source Code**
Refer to the source code for the Purchase Order status codes:
::: order.status_codes.PurchaseOrderStatus
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []
Purchase Order Status supports [custom states](../concepts/custom_states.md).
### Purchase Order Currency
@ -141,14 +124,3 @@ This view can be accessed externally as an ICS calendar using a URL like the fol
`http://inventree.example.org/api/order/calendar/purchase-order/calendar.ics`
by default, completed orders are not exported. These can be included by appending `?include_completed=True` to the URL.
## Purchase Order Settings
The following [global settings](../settings/global.md) are available for purchase orders:
| Name | Description | Default | Units |
| ---- | ----------- | ------- | ----- |
{{ globalsetting("PURCHASEORDER_REFERENCE_PATTERN") }}
{{ globalsetting("PURCHASEORDER_REQUIRE_RESPONSIBLE") }}
{{ globalsetting("PURCHASEORDER_EDIT_COMPLETED_ORDERS") }}
{{ globalsetting("PURCHASEORDER_AUTO_COMPLETE") }}

View File

@ -45,24 +45,9 @@ Each Return Order has a specific status code, as follows:
| --- | --- |
| Pending | The return order has been created, but not sent to the customer |
| In Progress | The return order has been issued to the customer |
| On Hold | The return order has been placed on hold, but is still active |
| Complete | The return order was marked as complete, and is now closed |
| Cancelled | The return order was cancelled, and is now closed |
**Source Code**
Refer to the source code for the Return Order status codes:
::: order.status_codes.ReturnOrderStatus
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []
Return Order Status supports [custom states](../concepts/custom_states.md).
## Create a Return Order
From the Return Order index, click on <span class='badge inventree add'><span class='fas fa-plus-circle'></span> New Return Order</span> which opens the "Create Return Order" form.
@ -113,7 +98,7 @@ While [line items](#line-items) must reference a particular stock item, extra li
## Return Order Reports
Custom [reports](../report/templates.md) can be generated against each Return Order.
Custom [reports](../report/return_order.md) can be generated against each Return Order.
### Calendar view
@ -123,14 +108,3 @@ This view can be accessed externally as an ICS calendar using a URL like the fol
`http://inventree.example.org/api/order/calendar/return-order/calendar.ics`
by default, completed orders are not exported. These can be included by appending `?include_completed=True` to the URL.
## Return Order Settings
The following [global settings](../settings/global.md) are available for return orders:
| Name | Description | Default | Units |
| ---- | ----------- | ------- | ----- |
{{ globalsetting("RETURNORDER_ENABLED") }}
{{ globalsetting("RETURNORDER_REFERENCE_PATTERN") }}
{{ globalsetting("RETURNORDER_REQUIRE_RESPONSIBLE") }}
{{ globalsetting("RETURNORDER_EDIT_COMPLETED_ORDERS") }}

View File

@ -20,26 +20,8 @@ Each Sales Order has a specific status code, which represents the state of the o
| --- | --- |
| Pending | The sales order has been created, but has not been finalized or submitted |
| In Progress | The sales order has been issued, and is in progress |
| On Hold | The sales order has been placed on hold, but is still active |
| Shipped | The sales order has been shipped, but is not yet complete |
| Complete | The sales order is fully completed, and is now closed |
| Shipped | The sales order has been completed, and is now closed |
| Cancelled | The sales order was cancelled, and is now closed |
| Lost | The sales order was lost, and is now closed |
| Returned | The sales order was returned, and is now closed |
**Source Code**
Refer to the source code for the Sales Order status codes:
::: order.status_codes.SalesOrderStatus
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []
Sales Order Status supports [custom states](../concepts/custom_states.md).
### Sales Order Currency
@ -101,7 +83,7 @@ To view all the completed shipment, click on the <span class="badge inventree na
### Complete Order
Once all items in the sales order have been shipped, click on <span class="badge inventree add"><span class='fas fa-check-circle'></span> Complete Order</span> to mark the sales order as shipped. Confirm then click on <span class="badge inventree confirm">Submit</span> to complete the order.
Once all items in the sales order have been shipped, click on <span class="badge inventree add"><span class='fas fa-check-circle'></span> Complete Order</span> to mark the sales order as complete.
### Cancel Order
@ -185,15 +167,3 @@ All these fields can be edited by the user:
{% with id="edit-shipment", url="order/edit_shipment.png", description="Edit shipment" %}
{% include "img.html" %}
{% endwith %}
## Sales Order Settings
The following [global settings](../settings/global.md) are available for sales orders:
| Name | Description | Default | Units |
| ---- | ----------- | ------- | ----- |
{{ globalsetting("SALESORDER_REFERENCE_PATTERN") }}
{{ globalsetting("SALESORDER_REQUIRE_RESPONSIBLE") }}
{{ globalsetting("SALESORDER_DEFAULT_SHIPMENT") }}
{{ globalsetting("SALESORDER_EDIT_COMPLETED_ORDERS") }}
{{ globalsetting("SALESORDER_SHIP_COMPLETE") }}

View File

@ -47,10 +47,6 @@ If a part is designated as an *Assembly* it can be created (or built) from other
If a part is designated as a *Component* it can be used as a sub-component of an *Assembly*. [Read further information about BOM management here](../build/bom.md)
### Testable
Testable parts can have test templates defined against the part, allowing test results to be recorded against any stock items for that part. For more information on testing, refer to the [testing documentation](./test.md).
### Trackable
Trackable parts can be assigned batch numbers or serial numbers which uniquely identify a particular stock item. Trackable parts also provide other features (and restrictions) in the InvenTree ecosystem.
@ -77,15 +73,7 @@ A [Purchase Order](../order/purchase_order.md) allows parts to be ordered from a
If a part is designated as *Salable* it can be sold to external customers. Setting this flag allows parts to be added to sales orders.
## Locked Parts
Parts can be locked to prevent them from being modified. This is useful for parts which are in production and should not be changed. The following restrictions apply to parts which are locked:
- Locked parts cannot be deleted
- BOM items cannot be created, edited, or deleted when they are part of a locked assembly
- Part parameters linked to a locked part cannot be created, edited or deleted
## Active Parts
### Active
By default, all parts are *Active*. Marking a part as inactive means it is not available for many actions, but the part remains in the database. If a part becomes obsolete, it is recommended that it is marked as inactive, rather than deleting it from the database.

View File

@ -46,7 +46,7 @@ Additionally, the following information is stored for each part, in relation to
InvenTree supports pricing data in multiple currencies, allowing integration with suppliers and customers using different currency systems.
Supported currencies can be configured in the [InvenTree settings](../settings/currency.md).
Supported currencies must be configured as part of [the InvenTree setup process](../start/config.md#supported-currencies).
!!! info "Currency Support"
InvenTree provides multi-currency pricing support via the [django-money](https://django-money.readthedocs.io/en/latest/) library.

View File

@ -1,78 +0,0 @@
---
title: Part Revisions
---
## Part Revisions
When creating a complex part (such as an assembly comprised of other parts), it is often necessary to track changes to the part over time. For example, throughout the lifetime of an assembly, it may be necessary to adjust the bill of materials, or update the design of the part.
Rather than overwrite the existing part data, InvenTree allows you to create a new *revision* of the part. This allows you to track changes to the part over time, and maintain a history of the part design.
Crucially, creating a new *revision* ensures that any related data entries which refer to the original part (such as stock items, build orders, purchase orders, etc) are not affected by the change.
### Revisions are Parts
A *revision* of a part is itself a part. This means that each revision of a part has its own part number, stock items, parameters, bill of materials, etc. The only thing that differentiates a *revision* from any other part is that the *revision* is linked to the original part.
### Revision Fields
Each part has two fields which are used to track the revision of the part:
* **Revision**: The revision number of the part. This is a user-defined field, and can be any string value.
* **Revision Of**: A reference to the part of which *this* part is a revision. This field is used to keep track of the available revisions for any particular part.
### Revision Restrictions
When creating a new revision of a part, there are some restrictions which must be adhered to:
* **Circular References**: A part cannot be a revision of itself. This would create a circular reference which is not allowed.
* **Unique Revisions**: A part cannot have two revisions with the same revision number. Each revision (of a given part) must have a unique revision code.
* **Revisions of Revisions**: A single part can have multiple revisions, but a revision cannot have its own revision. This restriction is in place to prevent overly complex part relationships.
* **Template Revisions**: A part which is a [template part](./template.md) cannot have revisions. This is because the template part is used to create variants, and allowing revisions of templates would create disallowed relationship states in the database. However, variant parts are allowed to have revisions.
* **Template References**: A part which is a revision of a variant part must point to the same template as the original part. This is to ensure that the revision is correctly linked to the original part.
## Revision Settings
The following options are available to control the behavior of part revisions.
Note that these options can be changed in the InvenTree settings:
{% with id="part_revision_settings", url="part/part_revision_settings.png", description="Part revision settings" %}
{% include 'img.html' %}
{% endwith %}
* **Enable Revisions**: If this setting is enabled, parts can have revisions. If this setting is disabled, parts cannot have revisions.
* **Assembly Revisions Only**: If this setting is enabled, only assembly parts can have revisions. This is useful if you only want to track revisions of assemblies, and not individual parts.
## Create a Revision
To create a new revision for a given part, navigate to the part detail page, and click on the "Revisions" tab.
Select the "Duplicate Part" action, to create a new copy of the selected part. This will open the "Duplicate Part" form:
{% with id="part_create_revision", url="part/part_create_revision.png", description="Create part revision" %}
{% include 'img.html' %}
{% endwith %}
In this form, make the following updates:
1. Set the *Revision Of* field to the original part (the one that you are duplicating)
2. Set the *Revision* field to a unique revision number for the new part revision
Once these changes (and any other required changes) are made, press *Submit* to create the new part.
Once the form is submitted (without any errors), you will be redirected to the new part revision. Here you can see that it is linked to the original part:
{% with id="part_revision_b", url="part/part_revision_b.png", description="Revision B" %}
{% include 'img.html' %}
{% endwith %}
## Revision Navigation
When multiple revisions exist for a particular part, you can navigate between revisions using the *Select Part Revision* drop-down which renders at the top of the part page:
{% with id="part_revision_select", url="part/part_revision_select.png", description="Select part revision" %}
{% include 'img.html' %}
{% endwith %}
Note that this revision selector is only visible when multiple revisions exist for the part.

View File

@ -5,7 +5,7 @@ title: Part Scheduling
## Part Scheduling
The *Scheduling* tab provides an overview of the *predicted* future available quantity of a particular part.
The *Scheduling* tab provides an overview of the *predicted* future availabile quantity of a particular part.
The *Scheduling* tab displays a chart of estimated future part stock levels. It begins at the current date, with the current stock level. It then projects into the "future", taking information from:

View File

@ -4,7 +4,7 @@ title: Part Test Templates
## Part Test Templates
Parts which are designated as [testable](./part.md#testable) can define templates for tests which are to be performed against individual stock items corresponding to the part.
Parts which are designated as *trackable* (meaning they can be uniquely serialized) can define templates for tests which are to be performed against individual stock items corresponding to the part.
A test template defines the parameters of the test; the individual stock items can then have associated test results which correspond to a test template.

View File

@ -28,6 +28,7 @@ Details provides information about the particular part. Parts details can be dis
{% with id="part_overview", url="part/part_overview.png", description="Part details" %}
{% include 'img.html' %}
{% endwith %}
<p></p>
A Part is defined in the system by the following parameters:
@ -37,7 +38,7 @@ A Part is defined in the system by the following parameters:
**Description** - Longer form text field describing the Part
**Revision** - An optional revision code denoting the particular version for the part. Used when there are multiple revisions of the same master part object. Read [more about part revisions here](./revision.md).
**Revision** - An optional revision code denoting the particular version for the part. Used when there are multiple revisions of the same master part object.
**Keywords** - Optional few words to describe the part and make the part search more efficient.
@ -61,7 +62,7 @@ Parts can have multiple defined parameters.
If a part is a *Template Part* then the *Variants* tab will be visible.
[Read about Part templates and variants](./template.md)
[Read about Part templates](./template.md)
### Stock
@ -131,9 +132,9 @@ The *Scheduling* tab provides an overview of the *predicted* future availability
The *Stocktake* tab provide historical stock level information, based on user-provided stocktake data. Refer to the [stocktake documentation](./stocktake.md) for further information.
### Test Templates
### Tests
If a part is marked as *testable*, the user can define tests which must be performed on any stock items which are instances of this part. [Read more about testing](./test.md).
If a part is marked as *trackable*, the user can define tests which must be performed on any stock items which are instances of this part. [Read more about testing](./test.md).
### Related Parts

View File

@ -61,7 +61,7 @@ Also, dedicated settings sections were added for:
For Category section, read [Category Parameter Templates](#category-parameter-templates)
Other section allows to set the prefix of build, purchase and sales orders.
Other section allows to set the prefix of build, puchase and sales orders.
### Category Parameter Templates

View File

@ -24,7 +24,7 @@ Refer to the [report documentation](../report/report.md) for further information
!!! warning "LaTeX Support"
LaTeX report templates are no longer supported for a number of technical and ideological reasons
[#1292](https://github.com/inventree/InvenTree/pull/1292) adds support for build order / work order reports. Refer to the [report documentation](../report/templates.md) for further information.
[#1292](https://github.com/inventree/InvenTree/pull/1292) adds support for build order / work order reports. Refer to the [build report documentation](../report/build.md) for further information.
### Inherited BOM Items

View File

@ -32,7 +32,7 @@ Details on how to create and manage manufacturer parts were added
[#1462](https://github.com/inventree/InvenTree/pull/1417) adds the ability to
create a QR code containing the URL of a StockItem, which can be opened directly
on a portable device using the camera or a QR code scanner. More details [here](../report/labels.md).
on a portable device using the camera or a QR code scanner. More details [here](../report/labels.md#url-style-qr-code).
## Major Bug Fixes

View File

@ -29,5 +29,5 @@ title: Release 0.4.0
| Pull Request | Description |
| --- | --- |
| [#1823](https://github.com/inventree/InvenTree/pull/1823) | Fixes link formatting issues for ManufacturerParts |
| [#1824](https://github.com/inventree/InvenTree/pull/1824) | Selects correct currency code when creating a new PurchaseOrderLineItem |
| [#1824](https://github.com/inventree/InvenTree/pull/1824) | Selects correct curreny code when creating a new PurchaseOrderLineItem |
| [#1867](https://github.com/inventree/InvenTree/pull/1867) | Fixes long-running bug when deleting sequential items via the API |

View File

@ -53,7 +53,7 @@ This release also provides a marked improvement in unit testing and code coverag
[#2372](https://github.com/inventree/InvenTree/pull/2372) provides an overhaul of notifications, allowing users to view their notifications directly in the InvenTree interface.
### Why are you hiding my name?
[#2861](https://github.com/inventree/InvenTree/pull/2861) adds several changes to enable admins to remove more of InvenTrees branding. Change logo, hide the about-modal for all but superusers and add custom messages to login and main navbar. Check out [the docs](../start/config.md#customization-options)
[#2861](https://github.com/inventree/InvenTree/pull/2861) adds several changes to enable admins to remove more of InvenTrees branding. Change logo, hide the about-modal for all but superusers and add custom messages to login and main navbar. Check out [the docs](../start/config.md#customisation-options).
### Label Printing Plugin

186
docs/docs/report/bom.md Normal file
View File

@ -0,0 +1,186 @@
---
title: BOM Generation
---
## BOM Generation
The bill of materials is an essential part of the documentation that needs to be sent to the factory. A simple csv export is OK to be important into SMT machines. But for human readable documentation it might not be sufficient. Additional information is needed. The Inventree report system allows to generate BOM well formatted BOM reports.
### Context variables
| Variable | Description |
| --- | --- |
| bom_items | Query set that contains all BOM items |
| bom_items...sub_part | One component of the BOM |
| bom_items...quantity | Number of parts |
| bom_items...reference | Reference designators of the part |
| bom_items...substitutes | Query set that contains substitutes of the part if any exist in the BOM |
### Examples
#### BOM
The following picture shows a simple example for a PCB with just three components from two different parts.
{% with id="report-options", url="report/bom_example.png", description="BOM example" %} {% include 'img.html' %} {% endwith %}
This example has been created using the following html template:
```html
{% raw %}
{% extends "report/inventree_report_base.html" %}
{% load i18n %}
{% load report %}
{% load inventree_extras %}
{% block page_margin %}
margin-left: 2cm;
margin-right: 1cm;
margin-top: 4cm;
{% endblock %}
{% block bottom_left %}
content: "v{{report_revision}} - {% format_date date %}";
{% endblock %}
{% block bottom_center %}
content: "InvenTree v{% inventree_version %}";
{% endblock %}
{% block style %}
.header-left {
text-align: left;
float: left;
}
table {
border: 1px solid #eee;
border-radius: 3px;
border-collapse: collapse;
width: 100%;
font-size: 80%;
}
table td {
border: 1px solid #eee;
}
{% endblock %}
{% block header_content %}
<div class='header-left'>
<h3>{% trans "Bill of Materials" %}</h3>
</div>
{% endblock %}
{% block page_content %}
<table>
<tr> <td>Board</td><td>{{ part.IPN }}</td> </tr>
<tr> <td>Description</td><td>{{ part.description }}</td> </tr>
<tr> <td>User</td><td>{{ user }}</td> </tr>
<tr> <td>Date</td><td>{{ date }}</td> </tr>
<tr> <td>Number of different components (codes)</td><td>{{ bom_items.count }}</td> </tr>
</table>
<br>
<table class='table table-striped table-condensed'>
<thead>
<tr>
<th>{% trans "IPN" %}</th>
<th>{% trans "MPN" %}</th>
<th>{% trans "Manufacturer" %}</th>
<th>{% trans "Quantity" %}</th>
<th>{% trans "Reference" %}</th>
<th>{% trans "Substitute" %}</th>
</tr>
</thead>
<tbody>
{% for line in bom_items.all %}
<tr>
<td>{{ line.sub_part.IPN }}</td>
<td>{{ line.sub_part.name }}</td>
<td>
{% for manf in line.sub_part.manufacturer_parts.all %}
{{ manf.manufacturer.name }}
{% endfor %}
</td>
<td>{% decimal line.quantity %}</td>
<td>{{ line.reference }}</td>
<td>
{% for sub in line.substitutes.all %}
{{ sub.part.IPN }}<br>
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
{% endraw %}
```
#### Pick List
When all material has been allocated someone has to pick all things from the warehouse.
In case you need a printed pick list you can use the following template. This it just the
table. All other info and CSS has been left out for simplicity. Please have a look at the
BOM report for details.
{% raw %}
```html
<table class='changes-table'>
<thead>
<tr>
<th>Original IPN</th>
<th>Allocated Part</th>
<th>Location</th>
<th>PCS</th>
</tr>
</thead>
<tbody>
{% for line in build.allocated_stock.all %}
<tr>
<td> {{ line.bom_item.sub_part.IPN }} </td>
{% if line.stock_item.part.IPN != line.bom_item.sub_part.IPN %}
<td class='chg'> {{ line.stock_item.part.IPN }} </td>
{% else %}
<td> {{ line.stock_item.part.IPN }} </td>
{% endif %}
<td> {{ line.stock_item.location.pathstring }} </td>
<td> {{ line.quantity }} </td>
</tr>
{% endfor %}
</tbody>
</table>
```
{% endraw %}
Here we have a loop that runs through all allocated parts for the build. For each part
we list the original IPN from the BOM and the IPN of the allocated part. These can differ
in case you have substitutes or template/variants in the BOM. In case the parts differ
we use a different format for the table cell e.g. print bold font or red color.
For the picker we list the full path names of the stock locations and the quantity
that is needed for the build. This will result in the following printout:
{% with id="picklist", url="report/picklist.png", description="Picklist Example" %} {% include "img.html" %} {% endwith %}
For those of you who would like to replace the "/" by something else because it is hard
to read in some fonts use the following trick:
{% raw %}
```html
<td> {% for loc in line.stock_item.location.path %}{{ loc.name }}{% if not forloop.last %}-{% endif %}{% endfor %} </td>
```
{% endraw %}
Here we use location.path which is a query set that contains the location path up to the
topmost parent. We use a loop to cycle through that and print the .name of the entry followed
by a "-". The foorloop.last is a Django trick that allows us to not print the "-" after
the last entry. The result looks like here:
{% with id="picklist_with_path", url="report/picklist_with_path.png", description="Picklist Example" %} {% include "img.html" %} {% endwith %}
Finally added a `{% raw %}|floatformat:0{% endraw %}` to the quantity that removes the trailing zeros.
### Default Report Template
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/0.15.x/src/backend/InvenTree/report/templates/report/inventree_bill_of_materials_report.html) for the default test report template.

324
docs/docs/report/build.md Normal file
View File

@ -0,0 +1,324 @@
---
title: Build Order Report
---
## Build Order Report
Custom build order reports may be generated against any given [Build Order](../build/build.md). For example, build order reports can be used to generate work orders.
### Build Filters
A build order report template may define a set of filters against which [Build Order](../build/build.md) items are sorted.
### Context Variables
In addition to the default report context variables, the following context variables are made available to the build order report template for rendering:
| Variable | Description |
| --- | --- |
| build | The build object the report is being generated against |
| part | The [Part](./context_variables.md#part) object that the build references |
| line_items | A shortcut for [build.line_items](#build) |
| bom_items | A shortcut for [build.bom_items](#build) |
| build_outputs | A shortcut for [build.build_outputs](#build) |
| reference | The build order reference string |
| quantity | Build order quantity (number of assemblies being built) |
#### build
The following variables are accessed by build.variable
| Variable | Description |
| --- | --- |
| active | Boolean that tells if the build is active |
| batch | Batch code transferred to build parts (optional) |
| line_items | A query set with all the build line items associated with the build |
| bom_items | A query set with all BOM items for the part being assembled |
| build_outputs | A queryset containing all build output ([Stock Item](../stock/stock.md)) objects associated with this build |
| can_complete | Boolean that tells if the build can be completed. Means: All material allocated and all parts have been build. |
| are_untracked_parts_allocated | Boolean that tells if all bom_items have allocated stock_items. |
| creation_date | Date where the build has been created |
| completion_date | Date the build was completed (or, if incomplete, the expected date of completion) |
| completed_by | The [User](./context_variables.md#user) that completed the build |
| is_overdue | Boolean that tells if the build is overdue |
| is_complete | Boolean that tells if the build is complete |
| issued_by | The [User](./context_variables.md#user) who created the build |
| link | External URL for extra information |
| notes | Text notes |
| parent | Reference to a parent build object if this is a sub build |
| part | The [Part](./context_variables.md#part) to be built (from component BOM items) |
| quantity | Build order quantity (total number of assembly outputs) |
| completed | The number out outputs which have been completed |
| reference | Build order reference (required, must be unique) |
| required_parts | A query set with all parts that are required for the build |
| responsible | Owner responsible for completing the build. This can be a user or a group. Depending on that further context variables differ |
| sales_order | References to a [Sales Order](./context_variables.md#salesorder) object for which this build is required (e.g. the output of this build will be used to fulfil a sales order) |
| status | The status of the build. 20 means 'Production' |
| sub_build_count | Number of sub builds |
| sub_builds | Query set with all sub builds |
| target_date | Date the build will be overdue |
| take_from | [StockLocation](./context_variables.md#stocklocation) to take stock from to make this build (if blank, can take from anywhere) |
| title | The full name of the build |
| description | The description of the build |
| allocated_stock.all | A query set with all allocated stock items for the build |
As usual items in a query sets can be selected by adding a .n to the set e.g. build.required_parts.0
will result in the first part of the list. Each query set has again its own context variables.
#### line_items
The `line_items` variable is a list of all build line items associated with the selected build. The following attributes are available for each individual line_item instance:
| Attribute | Description |
| --- | --- |
| .build | A reference back to the parent build order |
| .bom_item | A reference to the BOMItem which defines this line item |
| .quantity | The required quantity which is to be allocated against this line item |
| .part | A shortcut for .bom_item.sub_part |
| .allocations | A list of BuildItem objects which allocate stock items against this line item |
| .allocated_quantity | The total stock quantity which has been allocated against this line |
| .unallocated_quantity | The remaining quantity to allocate |
| .is_fully_allocated | Boolean value, returns True if the line item has sufficient stock allocated against it |
| .is_overallocated | Boolean value, returns True if the line item has more allocated stock than is required |
#### bom_items
| Attribute | Description |
| --- | --- |
| .reference | The reference designators of the components |
| .quantity | The number of components required to build |
| .overage | The extra amount required to assembly |
| .consumable | Boolean field, True if this is a "consumable" part which is not tracked through builds |
| .sub_part | The part at this position |
| .substitutes.all | A query set with all allowed substitutes for that part |
| .note | Extra text field which can contain additional information |
#### allocated_stock.all
| Attribute | Description |
| --- | --- |
| .bom_item | The bom item where this part belongs to |
| .stock_item | The allocated [StockItem](./context_variables.md#stockitem) |
| .quantity | The number of components needed for the build (components in BOM x parts to build) |
### Example
The following example will create a report with header and BOM. In the BOM table substitutes will be listed.
{% raw %}
```html
{% extends "report/inventree_report_base.html" %}
{% load i18n %}
{% load report %}
{% load barcode %}
{% load inventree_extras %}
{% load markdownify %}
{% block page_margin %}
margin: 2cm;
margin-top: 4cm;
{% endblock %}
{% block style %}
.header-right {
text-align: right;
float: right;
}
.logo {
height: 20mm;
vertical-align: middle;
}
.details {
width: 100%;
border: 1px solid;
border-radius: 3px;
padding: 5px;
min-height: 42mm;
}
.details table {
overflow-wrap: break-word;
word-wrap: break-word;
width: 65%;
table-layout: fixed;
font-size: 75%;
}
.changes table {
overflow-wrap: break-word;
word-wrap: break-word;
width: 100%;
table-layout: fixed;
font-size: 75%;
border: 1px solid;
}
.changes-table th {
font-size: 100%;
border: 1px solid;
}
.changes-table td {
border: 1px solid;
}
.details table td:not(:last-child){
white-space: nowrap;
}
.details table td:last-child{
width: 50%;
padding-left: 1cm;
padding-right: 1cm;
}
.details-table td {
padding-left: 10px;
padding-top: 5px;
padding-bottom: 5px;
border-bottom: 1px solid #555;
}
{% endblock %}
{% block bottom_left %}
content: "v{{report_revision}} - {% format_date date %}";
{% endblock %}
{% block header_content %}
<!-- TODO - Make the company logo asset generic -->
<img class='logo' src="{% asset 'company_logo.png' %}" alt="logo" width="150">
<div class='header-right'>
<h3>
Build Order {{ build }}
</h3>
<br>
</div>
<hr>
{% endblock %}
{% block page_content %}
<div class='details'>
<table class='details-table'>
<tr>
<th>{% trans "Build Order" %}</th>
<td>{% internal_link build.get_absolute_url build %}</td>
</tr>
<tr>
<th>{% trans "Order" %}</th>
<td>{{ reference }}</td>
</tr>
<tr>
<th>{% trans "Part" %}</th>
<td>{% internal_link part.get_absolute_url part.IPN %}</td>
</tr>
<tr>
<th>{% trans "Quantity" %}</th>
<td>{{ build.quantity }}</td>
</tr>
<tr>
<th>{% trans "Description" %}</th>
<td>{{ build.title }}</td>
</tr>
<tr>
<th>{% trans "Issued" %}</th>
<td>{% format_date build.creation_date %}</td>
</tr>
<tr>
<th>{% trans "Target Date" %}</th>
<td>
{% if build.target_date %}
{% format_date build.target_date %}
{% else %}
<em>Not specified</em>
{% endif %}
</td>
</tr>
{% if build.parent %}
<tr>
<th>{% trans "Required For" %}</th>
<td>{% internal_link build.parent.get_absolute_url build.parent %}</td>
</tr>
{% endif %}
{% if build.issued_by %}
<tr>
<th>{% trans "Issued By" %}</th>
<td>{{ build.issued_by }}</td>
</tr>
{% endif %}
{% if build.responsible %}
<tr>
<th>{% trans "Responsible" %}</th>
<td>{{ build.responsible }}</td>
</tr>
{% endif %}
<tr>
<th>{% trans "Sub builds count" %}</th>
<td>{{ build.sub_build_count }}</td>
</tr>
{% if build.sub_build_count > 0 %}
<tr>
<th>{% trans "Sub Builds" %}</th>
<td>{{ build.sub_builds }}</td>
</tr>
{% endif %}
<tr>
<th>{% trans "Overdue" %}</th>
<td>{{ build.is_overdue }}</td>
</tr>
<tr>
<th>{% trans "Can complete" %}</th>
<td>{{ build.can_complete }}</td>
</tr>
</table>
</div>
<h3>{% trans "Notes" %}</h3>
{% if build.notes %}
{{ build.notes|markdownify }}
{% endif %}
<h3>{% trans "Parts" %}</h3>
<div class='changes'>
<table class='changes-table'>
<thead>
<tr>
<th>Original IPN</th>
<th>Reference</th>
<th>Replace width IPN</th>
</tr>
</thead>
<tbody>
{% for line in build.bom_items %}
<tr>
<td> {{ line.sub_part.IPN }} </td>
<td> {{ line.reference }} </td>
<td> {{ line.substitutes.all.0.part.IPN }} </td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
```
{% endraw %}
This will result a report page like this:
{% with id="report-options", url="build/report-61.png", description="Report Example Builds" %} {% include "img.html" %} {% endwith %}
### Default Report Template
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/0.15.x/src/backend/InvenTree/report/templates/report/inventree_build_order_base.html) for the default build report template.

View File

@ -2,244 +2,64 @@
title: Context Variables
---
## Context Variables
Context variables are provided to each template when it is rendered. The available context variables depend on the model type for which the template is being rendered.
### Report
### Global Context
!!! info "Specific Report Context"
Specific report types may have additional context variables, see below.
In addition to the model-specific context variables, the following global context variables are available to all templates:
Each report has access to a number of context variables by default. The following context variables are provided to every report template:
| Variable | Description |
| --- | --- |
| base_url | The base URL for the InvenTree instance |
| date | Current date, represented as a Python datetime.date object |
| datetime | Current datetime, represented as a Python datetime object |
| template | The report template instance which is being rendered against |
| template_description | Description of the report template |
| template_name | Name of the report template |
| template_revision | Revision of the report template |
| page_size | The specified page size for this report, e.g. `A4` or `Letter landscape` |
| report_template | The report template model instance |
| report_name | Name of the report template |
| report_description | Description of the report template |
| report_revision | Revision of the report template |
| request | Django request object |
| user | User who made the request to render the template |
::: report.models.ReportTemplateBase.base_context
options:
show_source: True
#### Label
### Report Context
Certain types of labels have different context variables then other labels.
In addition to the [global context](#global-context), all *report* templates have access to the following context variables:
##### Stock Item Label
The following variables are made available to the StockItem label template:
| Variable | Description |
| --- | --- |
| page_size | The page size of the report |
| landscape | Boolean value, True if the report is in landscape mode |
Note that custom plugins may also add additional context variables to the report context.
::: report.models.ReportTemplate.get_context
options:
show_source: True
### Label Context
In addition to the [global context](#global-context), all *label* templates have access to the following context variables:
| Variable | Description |
| --- | --- |
| width | The width of the label (in mm) |
| height | The height of the label (in mm) |
Note that custom plugins may also add additional context variables to the label context.
::: report.models.LabelTemplate.get_context
options:
show_source: True
## Template Types
Templates (whether for generating [reports](./report.md) or [labels](./labels.md)) are rendered against a particular "model" type. The following model types are supported, and can have templates renderer against them:
| Model Type | Description |
| --- | --- |
| [build](#build-order) | A [Build Order](../build/build.md) instance |
| [buildline](#build-line) | A [Build Order Line Item](../build/build.md) instance |
| [salesorder](#sales-order) | A [Sales Order](../order/sales_order.md) instance |
| [returnorder](#return-order) | A [Return Order](../order/return_order.md) instance |
| [purchaseorder](#purchase-order) | A [Purchase Order](../order/purchase_order.md) instance |
| [stockitem](#stock-item) | A [StockItem](../stock/stock.md#stock-item) instance |
| [stocklocation](#stock-location) | A [StockLocation](../stock/stock.md#stock-location) instance |
| [part](#part) | A [Part](../part/part.md) instance |
### Build Order
When printing a report or label against a [Build Order](../build/build.md) object, the following context variables are available:
| Variable | Description |
| --- | --- |
| bom_items | Query set of all BuildItem objects associated with the BuildOrder |
| build | The BuildOrder instance itself |
| build_outputs | Query set of all BuildItem objects associated with the BuildOrder |
| line_items | Query set of all build line items associated with the BuildOrder |
| part | The Part object which is being assembled in the build order |
| quantity | The total quantity of the part being assembled |
| reference | The reference field of the BuildOrder |
| title | The title field of the BuildOrder |
::: build.models.Build.report_context
options:
show_source: True
### Build Line
When printing a report or label against a [BuildOrderLineItem](../build/build.md) object, the following context variables are available:
| Variable | Description |
| --- | --- |
| allocated_quantity | The quantity of the part which has been allocated to this build |
| allocations | A query set of all StockItem objects which have been allocated to this build line |
| bom_item | The BomItem associated with this line item |
| build | The BuildOrder instance associated with this line item |
| build_line | The build line instance itself |
| part | The sub-part (component) associated with the linked BomItem instance |
| quantity | The quantity required for this line item |
::: build.models.BuildLine.report_context
options:
show_source: True
### Sales Order
When printing a report or label against a [SalesOrder](../order/sales_order.md) object, the following context variables are available:
| Variable | Description |
| --- | --- |
| customer | The customer object associated with the SalesOrder |
| description | The description field of the SalesOrder |
| extra_lines | Query set of all extra lines associated with the SalesOrder |
| lines | Query set of all line items associated with the SalesOrder |
| order | The SalesOrder instance itself |
| reference | The reference field of the SalesOrder |
| title | The title (string representation) of the SalesOrder |
::: order.models.Order.report_context
options:
show_source: True
### Return Order
When printing a report or label against a [ReturnOrder](../order/return_order.md) object, the following context variables are available:
| Variable | Description |
| --- | --- |
| customer | The customer object associated with the ReturnOrder |
| description | The description field of the ReturnOrder |
| extra_lines | Query set of all extra lines associated with the ReturnOrder |
| lines | Query set of all line items associated with the ReturnOrder |
| order | The ReturnOrder instance itself |
| reference | The reference field of the ReturnOrder |
| title | The title (string representation) of the ReturnOrder |
### Purchase Order
When printing a report or label against a [PurchaseOrder](../order/purchase_order.md) object, the following context variables are available:
| Variable | Description |
| --- | --- |
| description | The description field of the PurchaseOrder |
| extra_lines | Query set of all extra lines associated with the PurchaseOrder |
| lines | Query set of all line items associated with the PurchaseOrder |
| order | The PurchaseOrder instance itself |
| reference | The reference field of the PurchaseOrder |
| supplier | The supplier object associated with the PurchaseOrder |
| title | The title (string representation) of the PurchaseOrder |
### Stock Item
When printing a report or label against a [StockItem](../stock/stock.md#stock-item) object, the following context variables are available:
| Variable | Description |
| --- | --- |
| barcode_data | Generated barcode data for the StockItem |
| barcode_hash | Hash of the barcode data |
| batch | The batch code for the StockItem |
| child_items | Query set of all StockItem objects which are children of this StockItem |
| ipn | The IPN (internal part number) of the associated Part |
| installed_items | Query set of all StockItem objects which are installed in this StockItem |
| item | The StockItem object itself |
| name | The name of the associated Part |
| part | The Part object which is associated with the StockItem |
| qr_data | Generated QR code data for the StockItem |
| qr_url | Generated URL for embedding in a QR code |
| -------- | ----------- |
| item | The [StockItem](./context_variables.md#stockitem) object itself |
| part | The [Part](./context_variables.md#part) object which is referenced by the [StockItem](./context_variables.md#stockitem) object |
| name | The `name` field of the associated Part object |
| ipn | The `IPN` field of the associated Part object |
| revision | The `revision` field of the associated Part object |
| quantity | The `quantity` field of the StockItem object |
| serial | The `serial` field of the StockItem object |
| uid | The `uid` field of the StockItem object |
| tests | Dict object of TestResult data associated with the StockItem |
| parameters | Dict object containing the parameters associated with the base Part |
| quantity | The quantity of the StockItem |
| result_list | FLattened list of TestResult data associated with the stock item |
| results | Dict object of TestResult data associated with the StockItem |
| serial | The serial number of the StockItem |
| stock_item | The StockItem object itself (shadow of 'item') |
| tests | Dict object of TestResult data associated with the StockItem (shadow of 'results') |
| test_keys | List of test keys associated with the StockItem |
| test_template_list | List of test templates associated with the StockItem |
| test_templates | Dict object of test templates associated with the StockItem |
::: stock.models.StockItem.report_context
options:
show_source: True
### Stock Location
##### Stock Location Label
When printing a report or label against a [StockLocation](../stock/stock.md#stock-location) object, the following context variables are available:
The following variables are made available to the StockLocation label template:
| Variable | Description |
| --- | --- |
| location | The StockLocation object itself |
| qr_data | Formatted QR code data for the StockLocation |
| parent | The parent StockLocation object |
| stock_location | The StockLocation object itself (shadow of 'location') |
| stock_items | Query set of all StockItem objects which are located in the StockLocation |
::: stock.models.StockLocation.report_context
options:
show_source: True
### Part
When printing a report or label against a [Part](../part/part.md) object, the following context variables are available:
| Variable | Description |
| --- | --- |
| bom_items | Query set of all BomItem objects associated with the Part |
| category | The PartCategory object associated with the Part |
| description | The description field of the Part |
| IPN | The IPN (internal part number) of the Part |
| name | The name of the Part |
| parameters | Dict object containing the parameters associated with the Part |
| part | The Part object itself |
| qr_data | Formatted QR code data for the Part |
| qr_url | Generated URL for embedding in a QR code |
| revision | The revision of the Part |
| test_template_list | List of test templates associated with the Part |
| test_templates | Dict object of test templates associated with the Part |
::: part.models.Part.report_context
options:
show_source: True
## Model Variables
Additional to the context variables provided directly to each template, each model type has a number of attributes and methods which can be accessedd via the template.
For each model type, a subset of the most commonly used attributes are listed below. For a full list of attributes and methods, refer to the source code for the particular model type.
| -------- | ----------- |
| location | The [StockLocation](./context_variables.md#stocklocation) object itself |
### Parts
#### Part
!!! incomplete "TODO"
This section requires further work
Each part object has access to a lot of context variables about the part. The following context variables are provided when accessing a `Part` object from within the template.
#### Part
Each part object has access to a lot of context variables about the part. The following context variables are provided when accessing a `Part` object:
| Variable | Description |
|----------|-------------|
@ -286,7 +106,6 @@ Each part object has access to a lot of context variables about the part. The fo
#### Part Category
| Variable | Description |
|----------|-------------|
| name | Name of this category |
@ -298,7 +117,6 @@ Each part object has access to a lot of context variables about the part. The fo
#### StockItem
| Variable | Description |
|----------|-------------|
| parent | Link to another [StockItem](./context_variables.md#stockitem) from which this StockItem was created |
@ -321,7 +139,7 @@ Each part object has access to a lot of context variables about the part. The fo
| notes | Extra notes field |
| build | Link to a Build (if this stock item was created from a build) |
| is_building | Boolean field indicating if this stock item is currently being built (or is "in production") |
| purchase_order | Link to a [PurchaseOrder](./context_variables.md#purchase-order) (if this stock item was created from a PurchaseOrder) |
| purchase_order | Link to a [PurchaseOrder](./context_variables.md#purchaseorder) (if this stock item was created from a PurchaseOrder) |
| infinite | If True this [StockItem](./context_variables.md#stockitem) can never be exhausted |
| sales_order | Link to a [SalesOrder](./context_variables.md#salesorder) object (if the StockItem has been assigned to a SalesOrder) |
| purchase_price | The unit purchase price for this [StockItem](./context_variables.md#stockitem) - this is the unit price at time of purchase (if this item was purchased from an external supplier) |
@ -346,7 +164,6 @@ Each part object has access to a lot of context variables about the part. The fo
#### Company
| Variable | Description |
|----------|-------------|
| name | Name of the company |
@ -367,7 +184,6 @@ Each part object has access to a lot of context variables about the part. The fo
#### Address
| Variable | Description |
|----------|-------------|
| line1 | First line of the postal address |
@ -378,6 +194,9 @@ Each part object has access to a lot of context variables about the part. The fo
#### Contact
Contacts are added to companies. Actually the company has no link to the contacts.
You can search the company object of the contact.
| Variable | Description |
|----------|-------------|
| company | Company object where the contact belongs to |
@ -388,7 +207,6 @@ Each part object has access to a lot of context variables about the part. The fo
#### SupplierPart
| Variable | Description |
|----------|-------------|
| part | Link to the master Part (Obsolete) |
@ -408,13 +226,24 @@ Each part object has access to a lot of context variables about the part. The fo
| has_price_breaks | Whether this [SupplierPart](./context_variables.md#supplierpart) has price breaks |
| manufacturer_string | Format a MPN string for this [SupplierPart](./context_variables.md#supplierpart). Concatenates manufacture name and part number. |
### Manufacturers
!!! incomplete "TODO"
This section requires further work
#### Manufacturer
| Variable | Description |
|----------|-------------|
#### ManufacturerPart
| Variable | Description |
|----------|-------------|
### Orders
#### Purchase Order
!!! note "TODO"
This section is incomplete
The [Purchase Order](../order/purchase_order.md) context variables are described in the [Purchase Order](./purchase_order.md) section.
#### SalesOrder

View File

@ -12,13 +12,13 @@ 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]({{ sourcefile("src/backend/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.15.x/src/backend/InvenTree/report/templatetags/report.py) where these functions are defined!
## Assigning Variables
When making use of helper functions within a template, it can be useful to store the result of the function to a variable, rather than immediately rendering the output.
For example, using the [render_currency](#currency-formatting) helper function, we can store the output to a variable which can be used at a later point in the template:
For example, using the [render_currency](#rendering-currency) helper function, we can store the output to a variable which can be used at a later point in the template:
```html
{% raw %}
@ -130,8 +130,8 @@ The following keyword arguments are available to the `render_currency` function:
| --- | --- |
| currency | Specify the currency code to render in (will attempt conversion if different to provided currency) |
| decimal_places | Specify the number of decimal places to render |
| min_decimal_places | Specify the minimum number of decimal places to render |
| max_decimal_places | Specify the maximum number of decimal places to render |
| min_decimal_places | Specify the minimum number of decimal places to render (ignored if *decimal_places* is specified) |
| max_decimal_places | Specify the maximum number of decimal places to render (ignored if *decimal_places* is specified) |
| include_symbol | Include currency symbol in rendered value (default = True) |
## Maths Operations
@ -259,31 +259,6 @@ A shortcut function is provided for rendering an image associated with a Company
*Preview* and *thumbnail* image variations can be rendered for the `company_image` tag, in a similar manner to [part image variations](#image-variations)
## Icons
Some models (e.g. part categories and locations) allow to specify a custom icon. To render these icons in a report, there is a `{% raw %}{% icon location.icon %}{% endraw %}` template tag from the report template library available.
This tag renders the required html for the icon.
!!! info "Loading fonts"
Additionally the icon fonts need to be loaded into the template. This can be done using the `{% raw %}{% include_icon_fonts %}{% endraw %}` template tag inside of a style block
!!! tip "Custom classes for styling the icon further"
The icon template tag accepts an optional `class` argument which can be used to apply a custom class to the rendered icon used to style the icon further e.g. positioning it, changing it's size, ... `{% raw %}{% icon location.icon class="my-class" %}{% endraw %}`.
```html
{% raw %}
{% load report %}
{% block style %}
{% include_icon_fonts %}
{% endblock style %}
{% icon location.icon %}
{% endraw %}
```
## InvenTree Logo
A template tag is provided to load the InvenTree logo image into a report. You can render the logo using the `{% raw %}{% logo_image %}{% endraw %}` tag:
@ -297,7 +272,7 @@ A template tag is provided to load the InvenTree logo image into a report. You c
### Custom Logo
If the system administrator has enabled a [custom logo](../start/config.md#customization-options) then this logo will be used instead of the base InvenTree logo.
If the system administrator has enabled a [custom logo](../start/config.md#customisation-options), then this logo will be used instead of the base InvenTree logo.
This is a useful way to get a custom company logo into your reports.
@ -312,7 +287,7 @@ If you have a custom logo, but explicitly wish to load the InvenTree logo itself
## Report Assets
[Report Assets](./templates.md#report-assets) are files specifically uploaded by the user for inclusion in generated reports and labels.
[Report Assets](./report.md#report-assets) are files specifically uploaded by the user for inclusion in generated reports and labels.
You can add asset images to the reports and labels by using the `{% raw %}{% asset ... %}{% endraw %}` template tag:

View File

@ -11,6 +11,17 @@ Custom labels can be generated using simple HTML templates, with support for QR-
Simple (generic) label templates are supplied 'out of the box' with InvenTree - however support is provided for generation of extremely specific custom labels, to meet any particular requirement.
## Label Types
The following types of labels are available
| Label Type | Description |
| --- | --- |
| [Part Labels](./labels/part_labels.md) | Print labels for individual parts |
| [Stock Labels](./labels/stock_labels.md) | Print labels for individual stock items |
| [Location Labels](./labels/location_labels.md) | Print labels for individual stock locations
| [Build Labels](./labels/build_labels.md) | Print labels for individual build order line items |
## Label Templates
Label templates are written using a mixture of [HTML](https://www.w3schools.com/html/) and [CSS](https://www.w3schools.com/css). [Weasyprint](https://weasyprint.org/) templates support a *subset* of HTML and CSS features. In addition to supporting HTML and CSS formatting, the label templates support the Django templating engine, allowing conditional formatting of the label data.

View File

@ -0,0 +1,118 @@
---
title: Build Labels
---
## Build Line Labels
Build label templates are used to generate labels for individual build order line items.
### Creating Build Line Label Templates
Build label templates are added (and edited) via the [admin interface](../../settings/admin.md).
### Printing Build Line Labels
Build line labels are printed from the Build Order page, under the *Allocate Stock* tab. Multiple line items can be selected for printing:
{% with id='print_build_labels', url='report/label_build_print.png', description='Print build line labels' %}
{% include 'img.html' %}
{% endwith %}
### Context Data
The following context variables are made available to the Build Line label template:
| Variable | Description |
| --- | --- |
| build_line | The build_line instance |
| build | The build order to which the build_line is linked |
| bom_item | The bom_item to which the build_line is linked |
| part | The required part for this build_line instance. References bom_item.sub_part |
| quantity | The total quantity required for the build line |
| allocated_quantity | The total quantity which has been allocated against the build line |
| allocations | A queryset containing the allocations made against the build_line |
## Example
A simple example template is shown below:
```html
{% raw %}
{% extends "label/label_base.html" %}
{% load barcode report %}
{% load inventree_extras %}
{% block style %}
{{ block.super }}
.label {
margin: 1mm;
}
.qr {
height: 28mm;
width: 28mm;
position: relative;
top: 0mm;
right: 0mm;
float: right;
}
.label-table {
width: 100%;
border-collapse: collapse;
border: 1pt solid black;
}
.label-table tr {
width: 100%;
border-bottom: 1pt solid black;
padding: 2.5mm;
}
.label-table td {
padding: 3mm;
}
{% endblock style %}
{% block content %}
<div class='label'>
<table class='label-table'>
<tr>
<td>
<b>Build Order:</b> {{ build.reference }}<br>
<b>Build Qty:</b> {% decimal build.quantity %}<br>
</td>
<td>
<img class='qr' alt='build qr' src='{% qrcode build.barcode %}'>
</td>
</tr>
<tr>
<td>
<b>Part:</b> {{ part.name }}<br>
{% if part.IPN %}
<b>IPN:</b> {{ part.IPN }}<br>
{% endif %}
<b>Qty / Unit:</b> {% decimal bom_item.quantity %} {% if part.units %}[{{ part.units }}]{% endif %}<br>
<b>Qty Total:</b> {% decimal quantity %} {% if part.units %}[{{ part.units }}]{% endif %}
</td>
<td>
<img class='qr' alt='part qr' src='{% qrcode part.barcode %}'>
</td>
</tr>
</table>
</div>
{% endblock content %}
{% endraw %}
```
Which results in a label like:
{% with id='build_label_example', url='report/label_build_example.png', description='Example build line labels' %}
{% include 'img.html' %}
{% endwith %}

View File

@ -0,0 +1,24 @@
---
title: Location Labels
---
## Stock Location Labels
Stock Location label templates are used to generate labels for individual Stock Locations.
### Creating Stock Location Label Templates
Stock Location label templates are added (and edited) via the admin interface.
### Printing Stock Location Labels
To print a single label from the Stock Location detail view, select the *Print Label* option.
### Context Data
The following variables are made available to the StockLocation label template:
| Variable | Description |
| -------- | ----------- |
| location | The [StockLocation](../context_variables.md#stocklocation) object itself |

Some files were not shown because too many files have changed in this diff Show More