Compare commits

..

107 Commits

Author SHA1 Message Date
Matthias Mair
9b759d2689 backport reqres token fix to 0.17.x (#9685)
backports the fix from https://github.com/inventree/InvenTree/pull/9585
2025-05-21 07:43:59 +02:00
github-actions[bot]
7959b6e597 Update 0111_auto_20230521_1350.py (#9659) (#9660)
Make data migration non atomic

(cherry picked from commit aec1de6eb3)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-05-14 12:59:26 +01:00
Oliver
d8b1ac5962 Update version.py (#9658)
Bump version to 0.17.12
2025-05-14 11:30:02 +01:00
github-actions[bot]
b705deaf54 Update config.md (#9638) (#9640)
Added clarification on how to change the timezone correctly. The documentation -- if carefully read -- explains how to change the timezone but it can be easily missed. I also explicitly mentioned the specific variable that must be set to change the timezone from UTC

(cherry picked from commit 34db1a2a49)

Co-authored-by: aluminum-ice <12374267+aluminum-ice@users.noreply.github.com>
2025-05-07 07:51:48 +01:00
Matthias Mair
807694d840 [0.17.x] bump docs deps (#9581) (#9590)
* bump docs deps (#9581)

* bumpd docs deps

* fix https://github.com/inventree/InvenTree/security/dependabot/196

(cherry picked from commit cbac1f736c)

# Conflicts:
#	docs/requirements.txt

* fix req
2025-04-29 19:14:24 +01:00
github-actions[bot]
af8a2f14a5 fix(backend): Make task registering more robust (#9586) (#9605)
* Make task registering more robust
See https://github.com/inventree/InvenTree/issues/9579

* add unit test

(cherry picked from commit 9f0354b315)

Co-authored-by: Matthias Mair <code@mjmair.com>
2025-04-29 12:36:55 +01:00
Matthias Mair
7090950066 feat(docs): include docs in release (#9524) (#9578)
* add build step for docs

* various fixes after live-testing  (#349)

(cherry picked from commit 40ded29b35)
2025-04-25 07:17:27 +10:00
github-actions[bot]
e2a092ea04 Remove trailing slash from SITE_URL (#9559) (#9560)
- ref: https://github.com/inventree/InvenTree/discussions/9552
- ref: https://stackoverflow.com/questions/56404930/when-trying-set-corsheaders-in-settings-py-file

(cherry picked from commit 527652007e)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-04-22 12:50:17 +10:00
Oliver
f2770f0711 Url fix 2 (#9548) (#9550)
* Logic fix

* Playwright test

* Revert "Playwright test"

This reverts commit a63b23961e.

* Simplify test

* Cleanup test
2025-04-21 21:56:55 +10:00
github-actions[bot]
86513844f2 Fix for URL validation (#9539) (#9540)
* FIx for URL validation

* Further fixes

(cherry picked from commit 8d48f9cecd)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-04-20 08:31:42 +10:00
Oliver
230ddd926f Update version.py (#9468) 2025-04-07 10:15:39 +10:00
Oliver
8d206bd311 [UI] Row hover (#9465) (#9466)
* [UI] Row hover (#9465)

* Add red color

* Improve table cursor

- Show "pointer" (hand) icon when actions available
- Improve context menu

* Fix import
2025-04-06 15:21:17 +10:00
Oliver
cf60d809da Notification permissions (#9449) (#9464)
* Updated type hints

* Fix tooltip bug

* Check user when sending notification

* Fix test

* Update unit test

* More unit test fixes

* Tweak playwright tests
2025-04-05 22:09:35 +11:00
github-actions[bot]
b1a264bf2a Handle potential null header (#9462) (#9463)
(cherry picked from commit f66efa7733)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-04-05 09:52:47 +11:00
github-actions[bot]
1dd056fdf2 Wrap values() call in list to fix type error (#9460) (#9461)
(cherry picked from commit 721f56f36e)

Co-authored-by: Joe Rogers <1337joe@users.noreply.github.com>
2025-04-05 09:20:38 +11:00
github-actions[bot]
2a9d737157 Report cache fix (#9447) (#9448)
* Adjust allowed CORS headers

* Disable caching in template preview

(cherry picked from commit c4f98cd6a1)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-04-03 15:21:57 +11:00
github-actions[bot]
00470a844c Update overdue order notification (#9444) (#9445)
* Update overdue order notification

- Check individual line items too

* Fix typo

(cherry picked from commit 67bdf3162a)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-04-03 11:30:22 +11:00
github-actions[bot]
5e26394500 Serialize stock fix (#9441) (#9443)
* Fix bug which hid the "serialize stock" button

* Add playwright tests

* Adjust check

(cherry picked from commit a18b18a3fd)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-04-03 09:04:15 +11:00
github-actions[bot]
3c71d62d27 Docs tweak (#9422) (#9424)
(cherry picked from commit e30786b068)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-03-31 19:06:54 +11:00
github-actions[bot]
d881037bde [UI] Improve order parts wizard (#9389) (#9421)
* [UI] Improve order parts wizard

- Enhance placeholder text
- Precalculate order quantity

* Tweak playwright tests

* Simplify tests

(cherry picked from commit 66d5180d8f)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-03-31 18:47:50 +11:00
github-actions[bot]
9a58d87eec fixed small bug in doc report sample templates (#9415) (#9418)
* Add part full name to supplier part table

* Add context variables for sales order report to the docs

* Added more context variables on orders to the docs

* fixed small bug in doc report sample templates

(cherry picked from commit 7b994a3d07)

Co-authored-by: Michael <michael@buchmann.ruhr>
2025-03-31 07:59:19 +11:00
github-actions[bot]
1019e9cc8d Docker updates (#9414) (#9417)
* Typo fix

* Examples to .env file

(cherry picked from commit b116e09717)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-03-31 07:59:05 +11:00
Oliver
8b59d8c04a Improve custom maintenance mode backend (#9396) (#9397)
* Improve custom maintenance mode backend (#9396)

* Improve custom maintenance mode backend

- Utilizing global settings functions
- Will use global cache if available
- Fewer DB hits per request

* Twaeak query limits

* Tweak test
2025-03-27 19:53:16 +11:00
github-actions[bot]
ccaf3459ce use dayjs in datefield (#9380) (#9381)
(cherry picked from commit 2bd26c0f49)

Co-authored-by: Jacob Felknor <jacobfelknor073@gmail.com>
2025-03-26 10:56:33 +11:00
Oliver
4987149979 Bug fix for activating plugins via UI (#9338) (#9370) 2025-03-24 22:08:38 +11:00
github-actions[bot]
02876f3c54 [UI] Edit fix (#9367) (#9368)
* Fix for editing stock location

* Fix for editing part category

(cherry picked from commit 8997f193c9)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-03-24 20:45:58 +11:00
Oliver
ff4df83ccd Update version.py (#9325)
Bump version number to 0.17.10
2025-03-17 23:33:26 +11:00
Oliver
0491b10438 Tweak for data import (#9010) (#9322)
- Do not override specified default values
2025-03-17 23:11:31 +11:00
Oliver
92f6f8b1f7 [Bug] Import fix (#9008) (#9321)
* [Bug] mport fix (#9008)

* Better handling of request object in serializers

* Pass request object through

- Required to extract user information

* Strip column header during import

- Prevent mismatch due to whitespace

* Fix for "minimum stock" field

* Fix for part serializer

* Extract default values on import

* Remove outdated migration message

* Bump API version

* Reintroduce typo

- To prevent API change
2025-03-17 21:11:27 +11:00
github-actions[bot]
3ffbb1cfc7 Fix currency rendering (#9308) (#9310)
- Closes https://github.com/inventree/InvenTree/issues/9300

(cherry picked from commit 4eaa5880c1)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-03-16 08:56:57 +11:00
github-actions[bot]
2f1e3817f1 Prevent sentry reporting in test mode (#9304) (#9306)
(cherry picked from commit cdb445583b)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-03-15 23:04:00 +11:00
Oliver
af0a2822d1 Call machine func (#9191) (#9298)
* Force label printing to background worker

* Refactor "check_reload" state of machine registry

- In line with plugin registry
- More work can be done here (i.e. session caching)

* Better handling of call_plugin_function

* Wrapper for calling machine function

* Use AttributeError instead

* Simplify function offloading

* Check plugin registry hash when reloading machine registry

* Cleanup

* Fixes

* Adjust unit test

* Cleanup

* Allow running in foreground if background worker not running

* Simplify call structure
2025-03-14 13:40:37 +11:00
Oliver
75420fc97e Update version.py (#9297)
Bump version number to 0.17.9
2025-03-14 09:28:55 +11:00
Oliver
3cae0d5066 Fix asset file serving (#9295)
- Backport of https://github.com/inventree/InvenTree/pull/9292
2025-03-14 09:04:42 +11:00
github-actions[bot]
21d266ab95 Auto-fill currency for new supplier part (#9286) (#9287)
- Closes https://github.com/inventree/InvenTree/issues/9284

(cherry picked from commit 7a43c3a83e)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-03-13 02:02:49 +11:00
github-actions[bot]
1ae27a6b77 Ignore sentry for TemplateSyntaxError (#9239) (#9241)
- Getting flodded with reports of users misapplied template filters

(cherry picked from commit 017d96f64e)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-03-05 22:01:12 +11:00
github-actions[bot]
b18ac57fb8 Tracking api fix (#9238) (#9240)
* [Bug] Fix search for StockTrackingList

- Removed invalid field

* Add unit test coverage for failing condition

* Fix 'notes' field for extra line item API

(cherry picked from commit 21ae1138ce)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-03-05 22:00:47 +11:00
github-actions[bot]
053b37ec3a Fix font size in location column (#9230) (#9231)
(cherry picked from commit d5a176c121)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-03-04 23:30:28 +11:00
github-actions[bot]
6fa6063639 [UI] Table Update (#9220) (#9221)
- Retain user selection for pageSize

(cherry picked from commit 8cee2e36ca)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-03-03 19:16:53 +11:00
github-actions[bot]
9b68dea26d Remove restriction on row action (#9201) (#9202)
(cherry picked from commit 92a9423c21)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-02-28 16:49:41 +11:00
github-actions[bot]
9d21776c86 Add 'note' field to form (#9186) (#9188)
(cherry picked from commit 92edbf41ab)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-02-26 14:14:30 +11:00
github-actions[bot]
4c9f042f8c Handle case of null stock location (#9183) (#9187)
(cherry picked from commit 94c2157d3c)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-02-26 09:31:58 +11:00
github-actions[bot]
3625b8f14c Use ref pattern on PO duplicate (#9100) (#9147)
* use ref pattern on PO duplicate

* use ref patterns on duplicate for other types of orders

* revert unintentional change to pre-commit

* add playwright tests

---------

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
(cherry picked from commit 2cabd02c6b)

Co-authored-by: Jacob Felknor <jacobfelknor073@gmail.com>
2025-02-22 20:46:00 +11:00
Oliver
cd41ca2a87 Batch code backport (#9138)
* Batch code fix (#9123)

* Fix batch code assignment when receiving items

* Add playwright tests

* Harden playwright tests

* Refactoring

* Handle undefined values

* Fix conflicts
2025-02-22 11:52:16 +11:00
github-actions[bot]
8a2fce9c36 Barcode validation fix (#9127) (#9130)
* Fix logic for adding items to SalesOrder

* Same thing for purchase orders

* Update serializers.py

Revert typo fix

- Otherwise, we need to do an API bump and the PR can't be back-ported!

(cherry picked from commit bc9dbf7df4)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-02-21 22:22:45 +11:00
github-actions[bot]
ee87cd7b23 Ignore inactive parts (#9125) (#9128)
(cherry picked from commit 6930ae7122)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-02-21 21:06:28 +11:00
Oliver
940abaa179 [UI] Pricing chart fixes (#9119) (#9124)
* Fix default values for pricing override

* Fix broken calculation for sale pricing

- Was previously excluding COMPLETED orders

* Fix for PricingOverviewPanel

* Fix for InvenTreeMoneySerializer

- Numbers should be represented as numbers!

* Front-end wrangling too

* Fix unit test
2025-02-21 20:39:20 +11:00
Oliver
7fefa5c213 Update version.py (#9112)
Bump version number to 0.17.8
2025-02-20 11:57:56 +11:00
github-actions[bot]
28726db86f Bug fix for receiving line item event (#9071) (#9072)
- Use StockItem ID correctly
- Provide line ID

(cherry picked from commit f27a84a7e5)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-02-13 14:46:55 +11:00
Oliver
eef1aad464 Update version.py (#9067)
Bump version number to 0.17.7
2025-02-12 17:14:45 +11:00
github-actions[bot]
3b6b41976f Fix for data import (#9060) (#9065)
- Prevent shadow overwrite of default_values dict
- Remove dead code

(cherry picked from commit 7049e84ac3)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-02-12 07:31:16 +11:00
Oliver
407ccb7bd2 [Backport] Update supported postgres-cli version to 15 (#9042)
* Update supported postgres-cli version to 15

* Update docs
2025-02-07 13:58:40 +11:00
Oliver
d7ed114e2c Adjust playwright testing (#9043)
* Adjust playwright testing

- Backporting critical playwright changes

* Fix for test

* Remove problematic test
2025-02-07 12:49:00 +11:00
Matthias Mair
c7a0265794 feat(backend): Improve error with missing manifest (#8957) (#9036)
* package tag results better

* Add docs for missing frontend

* better error indication
Fixes #8875

* fix test assertations

* fix test exception

* group setup admin stuff

* add operations supgourp

* add basic structure

* move error code

* fix link

* fix grammar issues

(cherry picked from commit bbeaf0e791)

# Conflicts:
#	docs/docs/faq.md

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-02-05 13:55:04 +11:00
Oliver
5bc56c826a Update version.py (#9019)
Bump version number

Co-authored-by: Matthias Mair <code@mjmair.com>
2025-02-05 12:52:56 +11:00
github-actions[bot]
1b42c00747 Enhance creation of default settings (#9028) (#9029)
- Remove cache requirement
- Replaces https://github.com/inventree/InvenTree/pull/9021

(cherry picked from commit 445fa45394)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-02-04 23:04:01 +11:00
github-actions[bot]
0f9bddbcd2 Report bugfix (#9013) (#9014)
- Ensure default label templates exist
- Ensure default report templates exist

(cherry picked from commit 2a6434ead8)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-02-03 08:03:59 +11:00
github-actions[bot]
b0fc42d906 Debounce checkLoginState to prevent unexpected redirection during testing (#9012) (#9016)
(cherry picked from commit e93b9692a1)

Co-authored-by: Dean <me@dgardiner.net>
2025-02-03 08:03:40 +11:00
github-actions[bot]
993849813f Select first and only pending shipment for sales order barcode allocation (#8984) (#8986)
(cherry picked from commit ede30cec7a507aab9c063fc44ab5d9e70ec902d6)

Co-authored-by: Dean <me@dgardiner.net>
2025-01-29 22:35:51 +11:00
github-actions[bot]
453c726d1e Fix for chart rendering (#8981) (#8982)
- Graphs like numbers, not strings, I guess...

(cherry picked from commit 0c56a3132b)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-01-29 17:43:33 +11:00
Oliver
b6ca9ec6a4 Update version.py
Bump version number to 0.17.5
2025-01-28 20:04:50 +11:00
Oliver
de431b8e3d Update version.py (#8964)
Bump version number to 0.17.4
2025-01-28 19:52:48 +11:00
Oliver
918adfb67f Update docker build workflow (#8971)
* Update docker build workflow

- Use depot action
- Much faster builds

* Remove # noqa strings
2025-01-28 19:05:49 +11:00
github-actions[bot]
c89fe44fea SalesOrder migration unit test (#8814) (#8961)
* Unit test for SalesOrder data migration

* make field checks more stable

* Adjust migration  strategy

* Fix for data migration

* Simplify login test for playwright

---------

Co-authored-by: Matthias Mair <code@mjmair.com>
(cherry picked from commit a13f5681a1)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-01-27 22:54:12 +11:00
github-actions[bot]
8baafed49f Add check for minimum invoke version (#8952) (#8954)
(cherry picked from commit d5928f038d)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-01-26 11:49:50 +11:00
github-actions[bot]
abddfb0b04 Docs updates: (#8951) (#8953)
* Docs updates:

- Fix error related to key access
- Fix rendering of settings tables
- Add setting key as mouseover text

* Revert config

(cherry picked from commit 640d5852e4)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-01-26 11:26:23 +11:00
github-actions[bot]
4a3035ec85 Plugin reload fix (#8922) (#8936)
* Add option to disable auto-reload of dev server

* Force plugin reload

* Add unit testing for plugin reload

- Requires modifications to registry.py

(cherry picked from commit 8e8b7158b7)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-01-22 17:01:34 +11:00
github-actions[bot]
0ebcff1a16 Include location detail in build output table (#8923) (#8927)
* Include location detail in build output table

* Raise validation error if trying to split an in-production item

(cherry picked from commit 68d3620bb2)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-01-21 01:47:56 +11:00
github-actions[bot]
ee06e466ca Import fix (#8924) (#8926)
* Exclude "tags" fields from data import

- May reintroduce at a later date
- Currently, no support for editing tags in frontend

* Refactor

(cherry picked from commit 2575c7276c)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-01-21 01:34:34 +11:00
github-actions[bot]
7140ea8f43 Allow CORS for /plugin/ URLs (#8898) (#8900)
- Ref: https://github.com/inventree/inventree-order-history/issues/17#issuecomment-2591275055

(cherry picked from commit 5de65891c3)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-01-15 18:03:30 +11:00
github-actions[bot]
a0d6ae2a54 fix(plugin): Ensure plugins are only installed if not deactivated (#8893) (#8901)
Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
(cherry picked from commit fbe2131fa5)

Co-authored-by: Matthias Mair <code@mjmair.com>
2025-01-15 15:01:41 +11:00
github-actions[bot]
74d8fe688e Upload timeout (#8895) (#8899)
* Increase upload timeout for attachments

* Increase default API timeout

- To account for distant connections

* Use longer timeout when uploading files

* Debug for RTD testing

* Adjust commit extraction

* Cleanup debug output

* Include more vars in output

* Move debug output to top of file

* Add useful link

(cherry picked from commit c7e960728d)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-01-15 14:46:32 +11:00
Oliver
99f9a3271b Ignore RTD version check (#8884)
* Ignore RTD version check

- Handled internally by readthedocs

* Add link ignore
2025-01-12 13:56:05 +11:00
github-actions[bot]
295318ad18 Add Serbian to LanguageContext.tsx (#8880) (#8881) is
(cherry picked from commit c75630d1bd)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-01-12 10:17:05 +11:00
Oliver
c26f5bd74f Update version.py (#8859)
Bump version number to 0.17.3
2025-01-08 13:16:59 +11:00
Oliver
4b564929d2 Extended error handling for get_user_color_theme (#8854) 2025-01-07 23:53:10 +11:00
github-actions[bot]
8576fbbade Ensure error is raised (#8849) (#8850)
(cherry picked from commit 3a62bdd276)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-01-07 17:31:59 +11:00
github-actions[bot]
6045925ebe Order creation fix (#8846) (#8847)
* Bug fix for PurchaseOrder

- Correctly record the user who created a PO
- Code refactoring

* Updated unit tests

(cherry picked from commit dcf0bb103e)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-01-07 15:03:18 +11:00
github-actions[bot]
3715c42fed Fix for test results in stock item report context (#8843) (#8844)
- Allow for "cascade" installed items
- i.e. support multi-level installed items

(cherry picked from commit 94f7890a41)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-01-07 10:40:08 +11:00
github-actions[bot]
4c6e3490c0 Navigate to index when deleting a company (#8831) (#8833)
(cherry picked from commit ae1f9bf274)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-01-05 22:51:55 +11:00
github-actions[bot]
91c095a011 Fix for buggy Caddyfile (#8830) (#8832)
(cherry picked from commit decccf8163)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-01-05 22:33:22 +11:00
github-actions[bot]
d42e3087a8 Fix package install in envs using python lower than 3.12 on debian like OSs (#8793) (#8813)
* do not install with uv for now - fixes #8789
#8742 #8495 #8494

* Ensure errors are raised if install / update fails

(cherry picked from commit d7939efaa9)

Co-authored-by: Matthias Mair <code@mjmair.com>
2025-01-01 10:32:16 +11:00
github-actions[bot]
4f7a12bd70 Allow barcode linking for stock location (#8802) (#8810)
(cherry picked from commit 16e9729308)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-12-31 16:01:15 +11:00
github-actions[bot]
5048c1d667 Update .env file (#8799) (#8808)
* Update .env file

- No functional changes
- Improved file comments

* Update .env

Improved comment

(cherry picked from commit 74cd0b9aed)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-12-31 14:50:33 +11:00
github-actions[bot]
0a522709b1 Add FAQ on cookie setting change (#8805) (#8807)
(cherry picked from commit 7419944301)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-12-31 14:44:10 +11:00
github-actions[bot]
c32362456b Add documentation on transferring media files (#8803) (#8806)
(cherry picked from commit c917c64aa1)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-12-31 14:43:54 +11:00
github-actions[bot]
4d07a49dfd Caddyfile documentation (#8798) (#8800)
* basic mixin file

* Add basic check for model type support

* Enhanced documentation for Caddyfile

* Additional documentation around proxy server

* Remove code from other PR

(cherry picked from commit ecc1c937ed)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-12-31 13:47:07 +11:00
github-actions[bot]
ef5fd93207 [Setup] Support X-Forwarded-Proto header (#8790) (#8797)
* Remove use_x_forwarded_port setting

- As per the docs, this is ignored in favour of use_x_forwarded_host
- So, is not being used anyway

* Add note on x_forwarded_host option

* Add warning message if SITE_URL not provided

* Add support for SECURE_PROXY_SSL_HEADER

* Update configuration template file

* Update SITE_URL docs

* Remove line

* Re-add use_x_forwarded_port

* Docs tweak

* Improve wording

* Fix broken link

(cherry picked from commit 23e4f2f2a2)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-12-31 12:50:51 +11:00
github-actions[bot]
df7204a334 [Docs] Update FAQ (#8777) (#8778)
* Update FAQ

* Add links to FAQ

* Extra info

* Extend documentation for debug options

(cherry picked from commit b0ce67fcd7)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-12-27 19:13:56 +11:00
Oliver
a70382ac7a Update version.py (#8776)
Bump version number to 0.17.2
2024-12-27 14:32:26 +11:00
github-actions[bot]
eed6223187 Fix default value for SESSION_COOKIE_SECURE (#8767) (#8769)
- Default value was previously 'True'
- Documentation indicated that it was 'False'
- Value in config_template.yaml was 'False' (but commented out)

(cherry picked from commit d4ee8c53b2)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-12-26 22:40:26 +11:00
github-actions[bot]
cab7a06146 Zero stock fix (#8766) (#8768)
* Change backend validation

- Allow stock adjustments with zero quantity

* Frontend changes

(cherry picked from commit ae7f4e33d5)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-12-26 11:26:04 +11:00
Matthias Mair
40245a6c4a [0.17.x] Fix REST registration endpoint (#8738) (#8763)
* Fix REST registration endpoint (#8738)

* Re-add html account base
Fixes #8690

* fix base template

* override dj-rest-auth pattern to fix fixed token model reference

* pin req

* fix urls.py

* move definition out to separate file

* fix possible issues where email is not enabled but UI shows that registration is enabled

* fix import order

* fix token recovery

* make sure registration redirects

* fix name change

* fix import name

* adjust description

* cleanup

* bum api version

* add test for registration

* add test for registration requirements

* fix merge issues

* fix merge from https://github.com/inventree/InvenTree/pull/8724
2024-12-25 11:38:02 +11:00
github-actions[bot]
3cb806d20a Handle error when loading icon pack (#8753) (#8755)
* Handle error when loading icon pack

* Update

(cherry picked from commit 8fcebefa0b)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-12-24 10:29:24 +11:00
github-actions[bot]
8f1bf95463 Add separate dialog for 'Ship Order' button (#8734) (#8735)
(cherry picked from commit 0bcad6b340)

Co-authored-by: Joe Rogers <1337joe@users.noreply.github.com>
2024-12-22 16:12:57 +11:00
github-actions[bot]
4019dc9c9c Forms fixes (#8722) (#8729)
* Refactor form fields

- Allow error message to be passed through via field definition
- Return error information to onFormError

* Fix debounce issue for text fields

* Fix for useForm hook

* Badge fix

- Fix badge rendering for SalesOrderShipment

* Cleanup unit test

(cherry picked from commit aabcf52cd2)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-12-20 15:52:06 +11:00
github-actions[bot]
70f17997eb [UI] Link fix (#8726) (#8728)
- Fixes anchor issues in stock tracking table

(cherry picked from commit 68ac4118e9)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-12-20 12:28:49 +11:00
github-actions[bot]
2d773a7b3e Badge fix (#8725) (#8727)
- Fix badge rendering for SalesOrderShipment

(cherry picked from commit 130bc84b44)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-12-20 12:21:42 +11:00
Oliver
39211ff4b6 Fix MFA auth flow (#8720) (#8724)
* Re-add html account base
Fixes #8690

* fix base template

Co-authored-by: Matthias Mair <code@mjmair.com>
2024-12-20 09:12:14 +11:00
github-actions[bot]
e37ff5c3d5 [UI] Enhanced null checks (#8706) (#8711)
* Extra null check in SettingList.tsx

* Null checks on error responses

(cherry picked from commit 378d69f0b3)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-12-19 01:01:51 +11:00
github-actions[bot]
6bd32c9236 Image upload error (#8700) (#8704)
* Add helper function for displaying API error message

* Provide feedback on image upload

* Update notification

(cherry picked from commit 1eaf3a4594)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-12-19 00:16:39 +11:00
github-actions[bot]
04aec83e95 Cast barcode scan IDs to list (#8701) (#8702)
- Fixes issues with limitations on old MySQL server

(cherry picked from commit 4569fd273d)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-12-18 17:04:18 +11:00
github-actions[bot]
b57d035f7f Fix for table update (#8698) (#8699)
- Retain data when updating a single record
- Fixes https://github.com/inventree/InvenTree/issues/8693

(cherry picked from commit 1910612725)

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2024-12-18 15:39:37 +11:00
Oliver
3ac49441ca Update version.py (#8689)
Bump version number to 0.17.1
2024-12-17 22:31:20 +11:00
github-actions[bot]
156c3cc9b2 Bump mkdocs-material from 9.5.48 to 9.5.49 in /docs in the dependencies group across 1 directory (#8675) (#8678)
* Bump mkdocs-material

Bumps the dependencies group with 1 update in the /docs directory: [mkdocs-material](https://github.com/squidfunk/mkdocs-material).

Updates `mkdocs-material` from 9.5.48 to 9.5.49
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.5.48...9.5.49)

---
updated-dependencies:
- dependency-name: mkdocs-material
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix req

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Matthias Mair <code@mjmair.com>
(cherry picked from commit 1518475d51)

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-17 09:16:26 +11:00
github-actions[bot]
52a26c9887 Bump the dependencies group with 5 updates (#8673) (#8679)
Bumps the dependencies group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) | `3.7.1` | `3.8.0` |
| [anchore/sbom-action](https://github.com/anchore/sbom-action) | `0.17.8` | `0.17.9` |
| [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance) | `2.0.1` | `2.1.0` |
| [github/codeql-action](https://github.com/github/codeql-action) | `3.27.6` | `3.27.9` |
| [crowdin/github-action](https://github.com/crowdin/github-action) | `2.4.0` | `2.5.0` |

Updates `docker/setup-buildx-action` from 3.7.1 to 3.8.0
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](c47758b77c...6524bf65af)

Updates `anchore/sbom-action` from 0.17.8 to 0.17.9
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md)
- [Commits](55dc4ee224...df80a981bc)

Updates `actions/attest-build-provenance` from 2.0.1 to 2.1.0
- [Release notes](https://github.com/actions/attest-build-provenance/releases)
- [Changelog](https://github.com/actions/attest-build-provenance/blob/main/RELEASE.md)
- [Commits](c4fbc64884...7668571508)

Updates `github/codeql-action` from 3.27.6 to 3.27.9
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](aa57810251...df409f7d92)

Updates `crowdin/github-action` from 2.4.0 to 2.5.0
- [Release notes](https://github.com/crowdin/github-action/releases)
- [Commits](a9ffb7d5ac...8dfaf9c206)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: dependencies
- dependency-name: anchore/sbom-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dependencies
- dependency-name: actions/attest-build-provenance
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: dependencies
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dependencies
- dependency-name: crowdin/github-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
(cherry picked from commit 1e4e3e65cc)

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-17 09:16:23 +11:00
Oliver
667e0a1bee Update version number (#8676) 2024-12-17 09:15:43 +11:00
3839 changed files with 1028941 additions and 561971 deletions

View File

@@ -1,43 +0,0 @@
# Dockerfile for the InvenTree devcontainer
# In contrast with the "production" image (which is based on an Alpine image)
# we use a Debian-based image for the devcontainer
FROM mcr.microsoft.com/devcontainers/python:3.11-bookworm@sha256:5140e54af7a0399a4932dd4c4653d085fcf451b093d7424867df1828ffbb9b81
# InvenTree paths
ENV INVENTREE_HOME="/home/inventree"
ENV INVENTREE_DATA_DIR="${INVENTREE_HOME}/dev"
ENV INVENTREE_STATIC_ROOT="${INVENTREE_DATA_DIR}/static"
ENV INVENTREE_MEDIA_ROOT="${INVENTREE_DATA_DIR}/media"
ENV INVENTREE_BACKUP_DIR="${INVENTREE_DATA_DIR}/backup"
ENV INVENTREE_PLUGIN_DIR="${INVENTREE_DATA_DIR}/plugins"
ENV INVENTREE_CONFIG_FILE="${INVENTREE_DATA_DIR}/config.yaml"
ENV INVENTREE_SECRET_KEY_FILE="${INVENTREE_DATA_DIR}/secret_key.txt"
ENV INVENTREE_OIDC_PRIVATE_KEY_FILE="${INVENTREE_DATA_DIR}/oidc.pem"
# Required for running playwright within devcontainer
ENV DISPLAY=:0
ENV LIBGL_ALWAYS_INDIRECT=1
COPY contrib/container/init.sh ./
RUN chmod +x init.sh
# Install required base packages
RUN apt update && apt install -y \
python3.11-dev python3.11-venv \
postgresql-client \
libldap2-dev libsasl2-dev \
libpango1.0-0 libcairo2 \
poppler-utils weasyprint
# Install packages required for frontend development
RUN apt install -y \
yarn nodejs npm
# Update to the latest stable node version
RUN npm install -g n --ignore-scripts && n lts
RUN yarn config set network-timeout 600000 -g
ENTRYPOINT ["/bin/bash", "./init.sh"]

View File

@@ -38,17 +38,11 @@
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [5173, 5432, 6379, 8000, 8080],
"forwardPorts": [5173, 8000, 8080],
"portsAttributes": {
"5173": {
"label": "Vite Server"
},
"5432": {
"label": "PostgreSQL Database"
},
"6379": {
"label": "Redis Server"
},
"8000": {
"label": "InvenTree Server"
},

View File

@@ -1,11 +1,11 @@
services:
db:
image: postgres:15
image: postgres:13
restart: unless-stopped
ports:
expose:
- 5432/tcp
volumes:
- ../dev-db/:/var/lib/postgresql/data:z
- inventreedatabase:/var/lib/postgresql/data:z
environment:
POSTGRES_DB: inventree
POSTGRES_USER: inventree_user
@@ -14,33 +14,36 @@ services:
redis:
image: redis:7.0
restart: always
ports:
expose:
- 6379
inventree:
ports:
- 8000:8000
build:
context: ..
dockerfile: .devcontainer/Dockerfile
dockerfile: ../InvenTree/contrib/container/Dockerfile
target: dev
args:
base_image: "mcr.microsoft.com/vscode/devcontainers/base:alpine-3.18"
data_dir: "dev"
volumes:
- ../:/home/inventree:z
- /tmp/.X11-unix:/tmp/.X11-unix
environment:
INVENTREE_DEBUG: True
INVENTREE_DB_ENGINE: postgresql
INVENTREE_DB_NAME: inventree
INVENTREE_DB_HOST: db
INVENTREE_DB_USER: inventree_user
INVENTREE_DB_PASSWORD: inventree_password
INVENTREE_DEBUG: True
INVENTREE_CACHE_HOST: redis
INVENTREE_CACHE_PORT: 6379
INVENTREE_PLUGINS_ENABLED: True
INVENTREE_SITE_URL: http://localhost:8000
INVENTREE_CORS_ORIGIN_ALLOW_ALL: True
INVENTREE_PY_ENV: /home/inventree/dev/venv
INVENTREE_DEVCONTAINER: True
depends_on:
- db
volumes:
inventreedatabase:

View File

@@ -1,7 +1,4 @@
#!/bin/bash
set -e
echo "Running postCreateCommand.sh ..."
# Avoiding Dubious Ownership in Dev Containers for setup commands that use git
git config --global --add safe.directory /home/inventree
@@ -10,25 +7,6 @@ git config --global --add safe.directory /home/inventree
python3 -m venv /home/inventree/dev/venv --system-site-packages --upgrade-deps
. /home/inventree/dev/venv/bin/activate
# remove existing gitconfig created by "Avoiding Dubious Ownership" step
# so that it gets copied from host to the container to have your global
# git config in container
rm -f /home/vscode/.gitconfig
# Fix issue related to CFFI version mismatch
pip uninstall cffi -y
sudo apt remove --purge -y python3-cffi
pip install --no-cache-dir --force-reinstall --ignore-installed cffi
# Upgrade pip
python3 -m pip install --upgrade pip
# Ensure the correct invoke is available
pip3 install --ignore-installed --upgrade invoke Pillow
# install base level packages
pip3 install -Ur contrib/container/requirements.txt --require-hashes
# Run initial InvenTree server setup
invoke update -s
@@ -37,3 +15,8 @@ invoke dev.setup-dev
# Install required frontend packages
invoke int.frontend-install
# remove existing gitconfig created by "Avoiding Dubious Ownership" step
# so that it gets copied from host to the container to have your global
# git config in container
rm -f /home/vscode/.gitconfig

View File

@@ -1,79 +0,0 @@
trigger:
batch: true
branches:
include:
- master
- stable
- refs/tags/*
paths:
include:
- src/backend
pool:
vmImage: ubuntu-latest
strategy:
matrix:
Python39:
PYTHON_VERSION: '3.11'
maxParallel: 3
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '$(PYTHON_VERSION)'
architecture: 'x64'
- task: PythonScript@0
displayName: 'Export project path'
inputs:
scriptSource: 'inline'
script: |
"""Search all subdirectories for `manage.py`."""
from glob import iglob
from os import path
# Python >= 3.5
manage_py = next(iglob(path.join('**', 'manage.py'), recursive=True), None)
if not manage_py:
raise SystemExit('Could not find a Django project')
project_location = path.dirname(path.abspath(manage_py))
print('Found Django project in', project_location)
print('##vso[task.setvariable variable=projectRoot]{}'.format(project_location))
- script: |
python -m pip install --upgrade pip setuptools wheel uv
uv pip install --require-hashes -r src/backend/requirements.txt
uv pip install --require-hashes -r src/backend/requirements-dev.txt
sudo apt-get install poppler-utils
sudo apt-get install libpoppler-dev
uv pip install unittest-xml-reporting coverage invoke
displayName: 'Install prerequisites'
env:
UV_SYSTEM_PYTHON: 1
- script: |
pushd '$(projectRoot)'
invoke update --uv
coverage run manage.py test --testrunner xmlrunner.extra.djangotestrunner.XMLTestRunner --no-input
coverage xml -i
displayName: 'Run tests'
env:
INVENTREE_DB_ENGINE: sqlite3
INVENTREE_DB_NAME: inventree
INVENTREE_MEDIA_ROOT: ./media
INVENTREE_STATIC_ROOT: ./static
INVENTREE_BACKUP_DIR: ./backup
INVENTREE_SITE_URL: http://localhost:8000
INVENTREE_PLUGINS_ENABLED: true
UV_SYSTEM_PYTHON: 1
INVENTREE_DEBUG: true
INVENTREE_LOG_LEVEL: INFO
- task: PublishTestResults@2
inputs:
testResultsFiles: "**/TEST-*.xml"
testRunTitle: 'Python $(PYTHON_VERSION)'
condition: succeededOrFailed()
- task: PublishCodeCoverageResults@2
inputs:
summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/coverage.xml'

71
.devops/testing_ci.yml Normal file
View File

@@ -0,0 +1,71 @@
# Python Django
# Test a Django project on multiple versions of Python.
# Add steps that analyze code, save build artifacts, deploy, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/python
trigger:
- master
pool:
vmImage: ubuntu-latest
strategy:
matrix:
Python39:
PYTHON_VERSION: '3.9'
maxParallel: 3
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '$(PYTHON_VERSION)'
architecture: 'x64'
- task: PythonScript@0
displayName: 'Export project path'
inputs:
scriptSource: 'inline'
script: |
"""Search all subdirectories for `manage.py`."""
from glob import iglob
from os import path
# Python >= 3.5
manage_py = next(iglob(path.join('**', 'manage.py'), recursive=True), None)
if not manage_py:
raise SystemExit('Could not find a Django project')
project_location = path.dirname(path.abspath(manage_py))
print('Found Django project in', project_location)
print('##vso[task.setvariable variable=projectRoot]{}'.format(project_location))
- script: |
python -m pip install --upgrade pip setuptools wheel
pip install --require-hashes -r requirements.txt
pip install --require-hashes -r requirements-dev.txt
pip install unittest-xml-reporting coverage invoke
sudo apt-get install poppler-utils
sudo apt-get install libpoppler-dev
displayName: 'Install prerequisites'
- script: |
pushd '$(projectRoot)'
invoke update
coverage run manage.py test --testrunner xmlrunner.extra.djangotestrunner.XMLTestRunner --no-input
coverage xml -i
displayName: 'Run tests'
env:
INVENTREE_DB_ENGINE: sqlite3
INVENTREE_DB_NAME: inventree
INVENTREE_MEDIA_ROOT: ./media
INVENTREE_STATIC_ROOT: ./static
INVENTREE_BACKUP_DIR: ./backup
INVENTREE_PLUGINS_ENABLED: true
- task: PublishTestResults@2
inputs:
testResultsFiles: "**/TEST-*.xml"
testRunTitle: 'Python $(PYTHON_VERSION)'
condition: succeededOrFailed()
- task: PublishCodeCoverageResults@1
inputs:
codeCoverageTool: Cobertura
summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/coverage.xml'

View File

@@ -6,7 +6,7 @@ body:
id: no-duplicate-issues
attributes:
label: "Please verify that this bug has NOT been raised before."
description: "Search in the issues sections by clicking [HERE](https://github.com/inventree/inventree/issues?q=) and read the [Frequently Asked Questions](https://docs.inventree.org/en/latest/sref/faq)!"
description: "Search in the issues sections by clicking [HERE](https://github.com/inventree/inventree/issues?q=) and read the [Frequently Asked Questions](https://docs.inventree.org/en/latest/faq/)!"
options:
- label: "I checked and didn't find a similar issue"
required: true
@@ -37,15 +37,15 @@ body:
label: "Expected behaviour"
description: "A clear and concise description of what you expected to happen."
placeholder: "..."
- type: dropdown
- type: checkboxes
id: deployment
attributes:
label: "Deployment Method"
options:
- Docker
- Package
- Bare metal
- Other - added info in Steps to Reproduce
- label: "Docker"
- label: "Package"
- label: "Bare metal"
- label: "Other - added info in Steps to Reproduce"
- type: textarea
id: version-info
validations:
@@ -54,25 +54,13 @@ body:
label: "Version Information"
description: "The version info block."
placeholder: "You can get this by going to the `About InvenTree` section in the upper right corner and clicking on the `copy version information` button"
- type: dropdown
id: tried-reproduce
- type: checkboxes
id: can-reproduce
attributes:
label: Try to reproduce on the demo site
description: You can sign in at [InvenTree Demo](https://demo.inventree.org) with admin:inventree. Note that this instance runs on the latest dev version, so your bug may be fixed there.
label: "Please verify if you can reproduce this bug on the demo site."
description: "You can sign in at [InvenTree Demo](https://demo.inventree.org) with admin:inventree. Note that this instance runs on the latest dev version, so your bug may be fixed there."
options:
- I did not try to reproduce
- I tried to reproduce
validations:
required: true
- type: dropdown
id: result-reproduce
attributes:
label: Is the bug reproducible on the demo site?
options:
- Not reproducible
- Reproducible
validations:
required: true
- label: "I can reproduce this bug on the demo site."
- type: textarea
id: logs
attributes:

View File

@@ -35,9 +35,7 @@ runs:
using: 'composite'
steps:
- name: Checkout Code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
with:
persist-credentials: false
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # pin@v4.1.1
# Python installs
- name: Set up Python ${{ env.python_version }}
@@ -57,16 +55,14 @@ runs:
run: |
python3 -m pip install -U pip
pip3 install -U invoke wheel
pip3 install 'uv>=0.9.6'
pip3 install 'uv<0.3.0'
- name: Allow uv to use the system Python by default
run: echo "UV_SYSTEM_PYTHON=1" >> $GITHUB_ENV
shell: bash
- name: Install Specific Python Dependencies
if: ${{ inputs.pip-dependency }}
shell: bash
run: uv pip install ${PIP_DEPS}
env:
PIP_DEPS: ${{ inputs.pip-dependency }}
run: uv pip install ${{ inputs.pip-dependency }}
# NPM installs
- name: Install node.js ${{ env.node_version }}
@@ -74,16 +70,21 @@ runs:
uses: actions/setup-node@1a4442cacd436585916779262731d5b162bc6ec7 # pin to v3.8.2
with:
node-version: ${{ env.node_version }}
cache: 'npm'
cache-dependency-path: src/backend/package-lock.json
- name: Install npm packages
if: ${{ inputs.npm == 'true' }}
shell: bash
run: cd src/backend && npm install
# OS installs
- name: Install OS Dependencies
if: ${{ inputs.apt-dependency }}
shell: bash
run: |
sudo apt-get update
sudo apt-get install ${APT_DEPS}
sudo apt-get install ${APT_DEPS}
env:
APT_DEPS: ${{ inputs.apt-dependency }}
sudo apt-get install ${{ inputs.apt-dependency }}
sudo apt-get install ${{ inputs.apt-dependency }}
# Invoke commands
- name: Install dev requirements

View File

@@ -4,8 +4,6 @@ updates:
directory: /
schedule:
interval: weekly
cooldown:
default-days: 7
groups:
dependencies:
patterns:
@@ -15,42 +13,26 @@ updates:
directory: /contrib/container
schedule:
interval: weekly
cooldown:
default-days: 7
- package-ecosystem: docker
directory: /.devcontainer
schedule:
interval: weekly
cooldown:
default-days: 7
- package-ecosystem: pip
directories:
- /contrib/container
- /docs
- /contrib/dev_reqs
- /contrib/container
- /src/backend
schedule:
interval: weekly
day: friday
cooldown:
default-days: 7
groups:
dependencies:
patterns:
- "*" # Include all dependencies
assignees:
- "matmair"
versioning-strategy: increase
- package-ecosystem: npm
directories:
- /src/frontend
- /src/backend
schedule:
interval: weekly
cooldown:
default-days: 7
groups:
dependencies:
patterns:

103
.github/scripts/check_js_templates.py vendored Normal file
View File

@@ -0,0 +1,103 @@
"""Test that the "translated" javascript files to not contain template tags which need to be determined at "run time".
This is because the "translated" javascript files are compiled into the "static" directory.
They should only contain template tags that render static information.
"""
import os
import pathlib
import re
import sys
here = os.path.abspath(os.path.dirname(__file__))
template_dir = os.path.abspath(os.path.join(here, '..', 'InvenTree', 'templates'))
# We only care about the 'translated' files
js_i18n_dir = os.path.join(template_dir, 'js', 'translated')
js_dynamic_dir = os.path.join(template_dir, 'js', 'dynamic')
errors = 0
print('=================================')
print('Checking static javascript files:')
print('=================================')
def check_invalid_tag(data):
"""Check for invalid tags."""
pattern = r'{%(\w+)'
err_count = 0
for idx, line in enumerate(data):
results = re.findall(pattern, line)
for result in results:
err_count += 1
print(f' - Error on line {idx + 1}: %{{{result[0]}')
return err_count
def check_prohibited_tags(data):
"""Check for prohibited tags."""
allowed_tags = [
'if',
'elif',
'else',
'endif',
'for',
'endfor',
'trans',
'load',
'include',
'url',
]
pattern = r'{% (\w+)\s'
err_count = 0
for idx, line in enumerate(data):
for tag in re.findall(pattern, line):
if tag not in allowed_tags:
print(f" > Line {idx + 1} contains prohibited template tag '{tag}'")
err_count += 1
return err_count
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:
data = js_file.readlines()
errors += check_invalid_tag(data)
errors += check_prohibited_tags(data)
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:
data = js_file.readlines()
invalid_tags = ['blocktrans', 'blocktranslate', 'trans', 'translate']
err_count = 0
for idx, line in enumerate(data):
for tag in invalid_tags:
tag = '{% ' + tag
if tag in line:
err_count += 1
print(f" > Error on line {idx + 1}: Prohibited tag '{tag}' found")
if errors > 0:
print(f'Found {errors} incorrect template tags')
sys.exit(errors)

View File

@@ -10,14 +10,12 @@ tagged branch:
"""
import argparse
import itertools
import json
import os
import re
import sys
from pathlib import Path
from typing import Optional
import requests
@@ -25,93 +23,7 @@ REPO = os.getenv('GITHUB_REPOSITORY', 'inventree/inventree')
GITHUB_API_URL = os.getenv('GITHUB_API_URL', 'https://api.github.com')
def get_src_dir() -> Path:
"""Return the path to the InvenTree source directory."""
here = Path(__file__).parent.absolute()
src_dir = here.joinpath('..', '..', 'src', 'backend', 'InvenTree', 'InvenTree')
if not src_dir.exists():
raise FileNotFoundError(
f"Could not find InvenTree source directory: '{src_dir}'"
)
return src_dir
def get_inventree_version() -> str:
"""Return the InvenTree version string."""
src_dir = get_src_dir()
version_file = src_dir.joinpath('version.py')
if not version_file.exists():
raise FileNotFoundError(
f"Could not find InvenTree version file: '{version_file}'"
)
with open(version_file, encoding='utf-8') as f:
text = f.read()
# Extract the InvenTree software version
results = re.findall(r"""INVENTREE_SW_VERSION = '(.*)'""", text)
if len(results) != 1:
raise ValueError(f'Could not find INVENTREE_SW_VERSION in {version_file}')
return results[0]
def get_api_version() -> str:
"""Return the InvenTree API version string."""
src_dir = get_src_dir()
api_version_file = src_dir.joinpath('api_version.py')
if not api_version_file.exists():
raise FileNotFoundError(
f"Could not find InvenTree API version file: '{api_version_file}'"
)
with open(api_version_file, encoding='utf-8') as f:
text = f.read()
# Extract the InvenTree software version
results = re.findall(r"""INVENTREE_API_VERSION = (.*)""", text)
if len(results) != 1:
raise ValueError(
f'Could not find INVENTREE_API_VERSION in {api_version_file}'
)
return results[0].strip().strip('"').strip("'")
def version_number_to_tuple(version_string: str) -> tuple[int, int, int, str]:
"""Validate a version number string, and convert to a tuple of integers.
e.g. 1.1.0
e.g. 1.1.0 dev
e.g. 1.2.3-rc2
"""
pattern = r'^(\d+)\.(\d+)\.(\d+)[\s-]?(.*)?$'
match = re.match(pattern, version_string)
if not match or len(match.groups()) < 3:
raise ValueError(
f"Version string '{version_string}' did not match required pattern"
)
result = tuple(int(x) for x in match.groups()[:3])
# Add optional prerelease tag
if len(match.groups()) > 3:
result += (match.groups()[3] or '',)
else:
result += ('',)
return result
def get_existing_release_tags(include_prerelease: bool = True):
def get_existing_release_tags(include_prerelease=True):
"""Request information on existing releases via the GitHub API."""
# Check for github token
token = os.getenv('GITHUB_TOKEN', None)
@@ -134,16 +46,16 @@ def get_existing_release_tags(include_prerelease: bool = True):
for release in data:
tag = release['tag_name'].strip()
match = re.match(r'^.*(\d+)\.(\d+)\.(\d+).*$', tag)
version_tuple = version_number_to_tuple(tag)
if len(match.groups()) != 3:
print(f"Version '{tag}' did not match expected pattern")
continue
if len(version_tuple) >= 4 and version_tuple[3]:
# Skip prerelease tags
if not include_prerelease:
print('-- skipping prerelease tag:', tag)
continue
if not include_prerelease and release['prerelease']:
continue
tags.append(tag)
tags.append([int(x) for x in match.groups()])
return tags
@@ -155,7 +67,15 @@ def check_version_number(version_string, allow_duplicate=False):
"""
print(f"Checking version '{version_string}'")
version_tuple = version_number_to_tuple(version_string)
# Check that the version string matches the required format
match = re.match(r'^(\d+)\.(\d+)\.(\d+)(?: dev)?$', version_string)
if not match or len(match.groups()) != 3:
raise ValueError(
f"Version string '{version_string}' did not match required pattern"
)
version_tuple = [int(x) for x in match.groups()]
# Look through the existing releases
existing = get_existing_release_tags(include_prerelease=False)
@@ -163,68 +83,35 @@ def check_version_number(version_string, allow_duplicate=False):
# Assume that this is the highest release, unless told otherwise
highest_release = True
# A non-standard tag cannot be the 'highest' release
if len(version_tuple) >= 4 and version_tuple[3]:
highest_release = False
print(f"-- Version tag '{version_string}' cannot be the highest release")
for release in existing:
if version_string == release and not allow_duplicate:
if release == version_tuple and not allow_duplicate:
raise ValueError(f"Duplicate release '{version_string}' exists!")
release_tuple = version_number_to_tuple(release)
if release_tuple > version_tuple:
if release > version_tuple:
highest_release = False
print(f'Found newer release: {release!s}')
if highest_release:
print(f"-- Version '{version_string}' is the highest release")
return highest_release
def main() -> bool:
"""Run the version check."""
parser = argparse.ArgumentParser(description='InvenTree Version Check')
parser.add_argument(
'--show-version',
action='store_true',
help='Print the InvenTree version and exit',
)
parser.add_argument(
'--show-api-version',
action='store_true',
help='Print the InvenTree API version and exit',
)
parser.add_argument(
'--decrement-api',
type=str,
default='false',
help='Decrement the API version by 1 and print',
)
args = parser.parse_args()
inventree_version = get_inventree_version()
inventree_api_version = int(get_api_version())
if args.show_version:
print(inventree_version)
sys.exit(0)
if args.show_api_version:
if str(args.decrement_api).strip().lower() == 'true':
inventree_api_version -= 1
print(inventree_api_version)
sys.exit(0)
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!')
return False
sys.exit(1)
print('Running InvenTree version check...')
if 'only_version' in sys.argv:
here = Path(__file__).parent.absolute()
version_file = here.joinpath(
'..', '..', 'src', 'backend', 'InvenTree', 'InvenTree', 'api_version.py'
)
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']
@@ -240,10 +127,26 @@ def main() -> bool:
print(f'GITHUB_REF_TYPE: {GITHUB_REF_TYPE}')
print(f'GITHUB_BASE_REF: {GITHUB_BASE_REF}')
print(
f"InvenTree Version: '{inventree_version}' - {version_number_to_tuple(inventree_version)}"
here = Path(__file__).parent.absolute()
version_file = here.joinpath(
'..', '..', 'src', 'backend', 'InvenTree', 'InvenTree', 'version.py'
)
print(f"InvenTree API Version: '{inventree_api_version}'")
version = None
with open(version_file, encoding='utf-8') as f:
text = f.read()
# Extract the InvenTree software version
results = re.findall(r"""INVENTREE_SW_VERSION = '(.*)'""", text)
if len(results) != 1:
print(f'Could not find INVENTREE_SW_VERSION in {version_file}')
sys.exit(1)
version = results[0]
print(f"InvenTree Version: '{version}'")
# Check version number and look for existing versions
# If a release is found which matches the current tag, throw an error
@@ -258,22 +161,18 @@ def main() -> bool:
if GITHUB_BASE_REF == 'stable':
allow_duplicate = True
highest_release = check_version_number(
inventree_version, allow_duplicate=allow_duplicate
)
highest_release = check_version_number(version, allow_duplicate=allow_duplicate)
# Determine which docker tag we are going to use
docker_tags: Optional[list[str]] = None
docker_tags = None
if GITHUB_REF_TYPE == 'tag':
# GITHUB_REF should be of the form /refs/heads/<tag>
version_tag: str = GITHUB_REF.split('/')[-1]
version_tag = GITHUB_REF.split('/')[-1]
print(f"Checking requirements for tagged release - '{version_tag}':")
if version_tag != inventree_version:
print(
f"Version number '{inventree_version}' does not match tag '{version_tag}'"
)
if version_tag != version:
print(f"Version number '{version}' does not match tag '{version_tag}'")
sys.exit
docker_tags = [version_tag, 'stable'] if highest_release else [version_tag]
@@ -281,21 +180,20 @@ def main() -> bool:
elif GITHUB_REF_TYPE == 'branch':
# Otherwise we know we are targeting the 'master' branch
docker_tags = ['latest']
highest_release = False
else:
print('Unsupported branch / version combination:')
print(f'InvenTree Version: {inventree_version}')
print(f'InvenTree Version: {version}')
print('GITHUB_REF_TYPE:', GITHUB_REF_TYPE)
print('GITHUB_BASE_REF:', GITHUB_BASE_REF)
print('GITHUB_REF:', GITHUB_REF)
return False
sys.exit(1)
if docker_tags is None:
print('Docker tags could not be determined')
return False
sys.exit(1)
print(f"Version check passed for '{inventree_version}'!")
print(f"Version check passed for '{version}'!")
print(f"Docker tags: '{docker_tags}'")
target_repos = [REPO.lower(), f'ghcr.io/{REPO.lower()}']
@@ -310,11 +208,3 @@ def main() -> bool:
if GITHUB_REF_TYPE == 'tag' and highest_release:
env_file.write('stable_release=true\n')
return True
if __name__ == '__main__':
rslt = main()
if rslt is not True:
print('Version check failed!')
sys.exit(1)

View File

@@ -9,7 +9,7 @@ on:
- l10
env:
python_version: 3.11
python_version: 3.9
permissions:
contents: read
@@ -22,8 +22,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
INVENTREE_DB_NAME: "./test_db.sqlite"
INVENTREE_DB_ENGINE: django.db.backends.sqlite3
INVENTREE_DEBUG: true
INVENTREE_LOG_LEVEL: INFO
INVENTREE_DEBUG: info
INVENTREE_MEDIA_ROOT: ./media
INVENTREE_STATIC_ROOT: ./static
INVENTREE_BACKUP_DIR: ./backup
@@ -31,10 +30,7 @@ jobs:
steps:
- name: Checkout Code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
with:
persist-credentials: false
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
- name: Environment Setup
uses: ./.github/actions/setup
with:

View File

@@ -39,9 +39,7 @@ jobs:
docker: ${{ steps.filter.outputs.docker }}
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
with:
persist-credentials: false
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # pin@v3.0.2
id: filter
with:
@@ -55,11 +53,12 @@ jobs:
# Build the docker image
build:
name: Docker Build Test
needs: paths-filter
if: needs.paths-filter.outputs.docker == 'true' || github.event_name == 'release' || github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'full-run')
if: needs.paths-filter.outputs.docker == 'true' || github.event_name == 'release' || github.event_name == 'push'
permissions:
contents: read
packages: write
id-token: write
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
python_version: "3.11"
@@ -67,14 +66,21 @@ jobs:
steps:
- name: Check out repo
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
- name: Set Up Python ${{ env.python_version }}
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # pin@v5.3.0
with:
persist-credentials: false
python-version: ${{ env.python_version }}
- name: Version Check
run: |
pip install --require-hashes -r contrib/dev_reqs/requirements.txt
python3 .github/scripts/version_check.py
echo "git_commit_hash=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
echo "git_commit_date=$(git show -s --format=%ci)" >> $GITHUB_ENV
- name: Test Docker Image
id: test-docker
run: |
docker build . --target production --tag inventree-test -f contrib/container/Dockerfile
docker run --rm inventree-test invoke version
docker run --rm inventree-test invoke --version
docker run --rm inventree-test invoke --list
docker run --rm inventree-test gunicorn --version
@@ -90,10 +96,7 @@ jobs:
- name: Update Docker Image
run: |
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke install
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke version
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke update
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke backup
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke restore
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke dev.setup-dev
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml up -d
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke wait
@@ -109,72 +112,25 @@ jobs:
test -f data/config.yaml
test -f data/plugins.txt
test -f data/secret_key.txt
test -f data/oidc.pem
- 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 dev.test --disable-pty --translations
# Run migration test
migration_test:
name: Migration Test
needs: paths-filter
if: needs.paths-filter.outputs.docker == 'true' || github.event_name == 'release' || github.event_name == 'push'
permissions:
contents: read
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
python_version: "3.11"
runs-on: ubuntu-latest # in the future we can try to use alternative runners here
steps:
- name: Check out repo
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
with:
persist-credentials: false
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run --rm inventree-dev-server invoke dev.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 update
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run --rm inventree-dev-server invoke dev.setup-dev
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run --rm inventree-dev-server invoke dev.test --migrations --translations
# Build and publish
publish:
name: Publish Docker Image
needs: [build, migration_test]
permissions:
contents: read
packages: write
id-token: write
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
python_version: "3.11"
runs-on: ubuntu-latest # in the future we can try to use alternative runners here
steps:
- name: Check out repo
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
with:
persist-credentials: false
- name: Set Up Python ${{ env.python_version }}
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # pin@v6.1.0
with:
python-version: ${{ env.python_version }}
- name: Version Check
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run --rm inventree-dev-server invoke dev.test --migrations
- name: Clean up test folder
run: |
pip install --require-hashes -r contrib/dev_reqs/requirements.txt
python3 .github/scripts/version_check.py
echo "git_commit_hash=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
echo "git_commit_date=$(git show -s --format=%ci)" >> $GITHUB_ENV
rm -rf InvenTree/_testfolder
- name: Set up QEMU
if: github.event_name != 'pull_request'
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # pin@v3.7.0
uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # pin@v3.2.0
- name: Set up Docker Buildx
if: github.event_name != 'pull_request'
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # pin@v3.11.1
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # pin@v3.8.0
- name: Set up cosign
if: github.event_name != 'pull_request'
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # pin@v4.0.0
uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # pin@v3.7.0
- name: Check if Dockerhub login is required
id: docker_login
run: |
@@ -185,14 +141,14 @@ jobs:
fi
- name: Login to Dockerhub
if: github.event_name != 'pull_request' && steps.docker_login.outputs.skip_dockerhub_login != 'true'
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # pin@v3.6.0
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # pin@v3.3.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@5e57cd118135c172c3672efd75eb46360885c0ef # pin@v3.6.0
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # pin@v3.3.0
with:
registry: ghcr.io
username: ${{ github.actor }}
@@ -201,16 +157,18 @@ jobs:
- name: Extract Docker metadata
if: github.event_name != 'pull_request'
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # pin@v5.10.0
uses: docker/metadata-action@369eb591f429131d6889c46b94e711f089e6ca96 # pin@v5.6.1
with:
images: |
inventree/inventree
ghcr.io/${{ github.repository }}
- uses: depot/setup-action@b0b1ea4f69e92ebf5dea3f8713a1b0c37b2126a5 # pin@v1
- uses: depot/setup-action@v1
- name: Push Docker Images
id: push-docker
if: github.event_name != 'pull_request'
uses: depot/build-push-action@9785b135c3c76c33db102e45be96a25ab55cd507 # pin@v1
uses: depot/build-push-action@v1
with:
project: jczzbjkk68
context: .

View File

@@ -9,7 +9,7 @@ on:
branches-ignore: ["l10*"]
env:
python_version: 3.11
python_version: 3.9
node_version: 20
# The OS version must be set per job
server_start_sleep: 60
@@ -17,11 +17,10 @@ env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
INVENTREE_DB_ENGINE: sqlite3
INVENTREE_DB_NAME: inventree
INVENTREE_MEDIA_ROOT: /home/runner/work/InvenTree/test_inventree_media
INVENTREE_STATIC_ROOT: /home/runner/work/InvenTree/test_inventree_static
INVENTREE_BACKUP_DIR: /home/runner/work/InvenTree/test_inventree_backup
INVENTREE_MEDIA_ROOT: ../test_inventree_media
INVENTREE_STATIC_ROOT: ../test_inventree_static
INVENTREE_BACKUP_DIR: ../test_inventree_backup
INVENTREE_SITE_URL: http://localhost:8000
INVENTREE_DEBUG: true
permissions:
contents: read
@@ -37,13 +36,9 @@ jobs:
frontend: ${{ steps.filter.outputs.frontend }}
api: ${{ steps.filter.outputs.api }}
force: ${{ steps.force.outputs.force }}
cicd: ${{ steps.filter.outputs.cicd }}
requirements: ${{ steps.filter.outputs.requirements }}
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
with:
persist-credentials: false
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # pin@v3.0.2
id: filter
with:
@@ -61,13 +56,6 @@ jobs:
- 'src/backend/InvenTree/InvenTree/api_version.py'
frontend:
- 'src/frontend/**'
cicd:
- '.github/workflows/**'
requirements:
- 'src/backend/requirements.txt'
- 'src/backend/requirements-dev.txt'
- 'docs/requirements.txt'
- 'contrib/dev_reqs/requirements.txt'
- name: Is CI being forced?
run: echo "force=true" >> $GITHUB_OUTPUT
id: force
@@ -75,18 +63,38 @@ jobs:
contains(github.event.pull_request.labels.*.name, 'dependency') ||
contains(github.event.pull_request.labels.*.name, 'full-run')
pre-commit:
name: Style [pre-commit]
runs-on: ubuntu-24.04
needs: paths-filter
if: needs.paths-filter.outputs.cicd == 'true' || needs.paths-filter.outputs.server == 'true' || needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.requirements == 'true' || needs.paths-filter.outputs.force == 'true'
javascript:
name: Style - Classic UI [JS]
runs-on: ubuntu-20.04
needs: ["pre-commit"]
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
- name: Environment Setup
uses: ./.github/actions/setup
with:
persist-credentials: false
npm: true
install: true
- name: Check Templated JS Files
run: |
cd .github/scripts
python3 check_js_templates.py
- name: Lint Javascript Files
run: |
python src/backend/InvenTree/manage.py prerender
cd src/backend && npx eslint InvenTree/InvenTree/static_i18n/i18n/*.js
pre-commit:
name: Style [pre-commit]
runs-on: ubuntu-20.04
needs: paths-filter
if: needs.paths-filter.outputs.server == 'true' || needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.force == 'true'
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
- name: Set up Python ${{ env.python_version }}
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # pin@v6.1.0
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # pin@v5.3.0
with:
python-version: ${{ env.python_version }}
cache: "pip"
@@ -97,40 +105,17 @@ jobs:
pip install --require-hashes -r contrib/dev_reqs/requirements.txt
python3 .github/scripts/version_check.py
typecheck:
name: Style [Typecheck]
runs-on: ubuntu-24.04
needs: [paths-filter, pre-commit]
if: needs.paths-filter.outputs.server == 'true' || needs.paths-filter.outputs.requirements == 'true' || needs.paths-filter.outputs.force == 'true'
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
with:
persist-credentials: false
- name: Environment Setup
id: setup
uses: ./.github/actions/setup
with:
apt-dependency: gettext poppler-utils
dev-install: true
update: true
- name: Check types
run: |
ty check --python ${Python_ROOT_DIR}/bin/python3
mkdocs:
name: Style [Documentation]
runs-on: ubuntu-24.04
runs-on: ubuntu-20.04
needs: paths-filter
steps:
- name: Checkout Code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
with:
persist-credentials: false
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
- name: Set up Python ${{ env.python_version }}
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # pin@v6.1.0
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # pin@v5.3.0
with:
python-version: ${{ env.python_version }}
- name: Check Config
@@ -139,7 +124,7 @@ jobs:
pip install --require-hashes -r docs/requirements.txt
python docs/ci/check_mkdocs_config.py
- name: Check Links
uses: gaurav-nelson/github-action-markdown-link-check@5c5dfc0ac2e225883c0e5f03a85311ec2830d368 # pin@v1
uses: gaurav-nelson/github-action-markdown-link-check@5c5dfc0ac2e225883c0e5f03a85311ec2830d368 # v1
with:
folder-path: docs
config-file: docs/mlc_config.json
@@ -148,7 +133,7 @@ jobs:
schema:
name: Tests - API Schema Documentation
runs-on: ubuntu-24.04
runs-on: ubuntu-20.04
needs: paths-filter
if: needs.paths-filter.outputs.server == 'true' || needs.paths-filter.outputs.force == 'true'
env:
@@ -164,9 +149,7 @@ jobs:
version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
with:
persist-credentials: false
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
- name: Environment Setup
uses: ./.github/actions/setup
with:
@@ -176,17 +159,15 @@ jobs:
- name: Export API Documentation
run: invoke dev.schema --ignore-warnings --filename src/backend/InvenTree/schema.yml
- name: Upload schema
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # pin@v5.0.0
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # pin@v4.4.3
with:
name: schema.yml
path: src/backend/InvenTree/schema.yml
- name: Download public schema
env:
API: ${{ needs.paths-filter.outputs.api }}
run: |
pip install --require-hashes -r contrib/dev_reqs/requirements.txt >/dev/null 2>&1
version="$(python3 .github/scripts/version_check.py --show-api-version --decrement-api=${API} 2>&1)"
echo "API Version: $version"
version="$(python3 .github/scripts/version_check.py only_version ${{ needs.paths-filter.outputs.api }} 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)
@@ -196,16 +177,13 @@ jobs:
echo "Downloaded api.yaml"
- name: Running OpenAPI Spec diff action
id: breaking_changes
uses: oasdiff/oasdiff-action/diff@1c611ffb1253a72924624aa4fb662e302b3565d3 # pin@main
uses: oasdiff/oasdiff-action/diff@1c611ffb1253a72924624aa4fb662e302b3565d3 # pin@main
with:
base: "api.yaml"
revision: "src/backend/InvenTree/schema.yml"
format: "html"
base: 'api.yaml'
revision: 'src/backend/InvenTree/schema.yml'
format: 'html'
- name: Echoing diff to step
continue-on-error: true
env:
DIFF: ${{ steps.breaking_changes.outputs.diff }}
run: echo "${DIFF}" >> $GITHUB_STEP_SUMMARY
run: echo "${{ steps.breaking_changes.outputs.diff }}" >> $GITHUB_STEP_SUMMARY
- name: Check for differences in API Schema
if: needs.paths-filter.outputs.api == 'false'
@@ -214,81 +192,53 @@ jobs:
diff -u src/backend/InvenTree/schema.yml api.yaml && echo "no difference in API schema " || exit 2
- name: Check schema - including warnings
run: invoke dev.schema
continue-on-error: true
- name: Extract version for publishing
id: version
if: github.ref == 'refs/heads/master' && needs.paths-filter.outputs.api == 'true'
run: |
pip install --require-hashes -r contrib/dev_reqs/requirements.txt >/dev/null 2>&1
version="$(python3 .github/scripts/version_check.py --show-api-version 2>&1)"
echo "API Version: $version"
version="$(python3 .github/scripts/version_check.py only_version 2>&1)"
echo "Version: $version"
echo "version=$version" >> "$GITHUB_OUTPUT"
- name: Extract settings / tags
run: invoke int.export-definitions --basedir docs
- name: Upload settings
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # pin@v5.0.0
with:
name: inventree_settings.json
path: docs/generated/inventree_settings.json
- name: Upload tags
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # pin@v5.0.0
with:
name: inventree_tags.yml
path: docs/generated/inventree_tags.yml
- name: Upload filters
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # pin@v5.0.0
with:
name: inventree_filters.yml
path: docs/generated/inventree_filters.yml
schema-push:
name: Push new schema
runs-on: ubuntu-24.04
runs-on: ubuntu-20.04
needs: [paths-filter, schema]
if: needs.schema.result == 'success' && github.ref == 'refs/heads/master' && needs.paths-filter.outputs.api == 'true' && github.repository_owner == 'inventree'
env:
version: ${{ needs.schema.outputs.version }}
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
name: Checkout Code
with:
repository: inventree/schema
token: ${{ secrets.SCHEMA_PAT }}
persist-credentials: true
- name: Create artifact directory
run: mkdir -p artifact
- name: Download schema artifact
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # pin@v6.0.0
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
with:
path: artifact
merge-multiple: true
- name: Move files to correct location
name: schema.yml
- name: Move schema to correct location
run: |
echo "Version: ${version}"
echo "before move"
ls -la artifact
echo "Version: $version"
mkdir export/${version}
mv artifact/schema.yml export/${version}/api.yaml
mv artifact/inventree_settings.json export/${version}/inventree_settings.json
mv artifact/inventree_tags.yml export/${version}/inventree_tags.yml
mv artifact/inventree_filters.yml export/${version}/inventree_filters.yml
echo "after move"
ls -la artifact
rm -rf artifact
- uses: stefanzweifel/git-auto-commit-action@28e16e81777b558cc906c8750092100bbb34c5e3 # pin@v7.0.0
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 }}"
python:
name: Tests - inventree-python
runs-on: ubuntu-24.04
runs-on: ubuntu-20.04
needs: ["pre-commit", "paths-filter"]
if: needs.paths-filter.outputs.server == 'true' || needs.paths-filter.outputs.force == 'true'
env:
WRAPPER_NAME: inventree-python
wrapper_name: inventree-python
INVENTREE_DB_ENGINE: django.db.backends.sqlite3
INVENTREE_DB_NAME: ../inventree_unit_test_db.sqlite3
INVENTREE_ADMIN_USER: testuser
@@ -298,57 +248,51 @@ jobs:
INVENTREE_PYTHON_TEST_USERNAME: testuser
INVENTREE_PYTHON_TEST_PASSWORD: testpassword
INVENTREE_SITE_URL: http://127.0.0.1:12345
INVENTREE_DEBUG: true
INVENTREE_LOG_LEVEL: WARNING
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
with:
persist-credentials: false
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
- name: Environment Setup
uses: ./.github/actions/setup
with:
apt-dependency: gettext poppler-utils
dev-install: true
update: true
- name: Download Python Code For `${WRAPPER_NAME}`
run: git clone --depth 1 https://github.com/inventree/${WRAPPER_NAME} ./${WRAPPER_NAME}
npm: true
- name: Download Python Code For `${{ env.wrapper_name }}`
run: git clone --depth 1 https://github.com/inventree/${{ env.wrapper_name }} ./${{ env.wrapper_name }}
- name: Start InvenTree Server
run: |
invoke dev.delete-data -f
invoke dev.import-fixtures
invoke dev.server -a 127.0.0.1:12345 &
invoke wait
- name: Run Tests For `${WRAPPER_NAME}`
- name: Run Tests For `${{ env.wrapper_name }}`
run: |
cd ${WRAPPER_NAME}
cd ${{ env.wrapper_name }}
invoke check-server
coverage run -m unittest discover -s test/
coverage:
name: Tests - DB [SQLite] + Coverage ${{ matrix.python_version }}
runs-on: ubuntu-24.04
runs-on: ubuntu-20.04
needs: ["pre-commit", "paths-filter"]
if: needs.paths-filter.outputs.server == 'true' || needs.paths-filter.outputs.force == 'true'
continue-on-error: true # continue if a step fails so that coverage gets pushed
strategy:
matrix:
python_version: [3.11]
# python_version: [3.11, 3.14] # Disabled due to requirement issues
python_version: [3.9]
# python_version: [3.9, 3.12] # Disabled due to requirement issues
env:
INVENTREE_DB_NAME: ./inventree.sqlite
INVENTREE_DB_ENGINE: sqlite3
INVENTREE_PLUGINS_ENABLED: true
INVENTREE_CONSOLE_LOG: false
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
python_version: ${{ matrix.python_version }}
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
with:
persist-credentials: false
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
- name: Environment Setup
uses: ./.github/actions/setup
with:
@@ -362,57 +306,18 @@ jobs:
- name: Check Migration Files
run: python3 .github/scripts/check_migration_files.py
- name: Coverage Tests
run: invoke dev.test --check --coverage --translations
- name: Upload raw coverage to artifacts
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # pin@v5.0.0
with:
name: coverage
path: .coverage
retention-days: 14
run: invoke dev.test --coverage
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # pin@v5.5.1
uses: codecov/codecov-action@7f8b4b4bde536c465e797be725718b88c5d95e0e # pin@v5.1.1
if: always()
with:
token: ${{ secrets.CODECOV_TOKEN }}
slug: inventree/InvenTree
flags: backend
performance:
name: Tests - Performance
runs-on: ubuntu-24.04
needs: ["pre-commit", "paths-filter"]
if: needs.paths-filter.outputs.server == 'true' || needs.paths-filter.outputs.force == 'true'
permissions:
contents: read
id-token: write
env:
INVENTREE_DB_NAME: inventree_unit_test_db.sqlite
INVENTREE_DB_ENGINE: sqlite3
INVENTREE_PLUGINS_ENABLED: true
INVENTREE_CONSOLE_LOG: false
INVENTREE_AUTO_UPDATE: true
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
with:
persist-credentials: false
- name: Environment Setup
uses: ./.github/actions/setup
with:
apt-dependency: gettext poppler-utils
dev-install: true
update: true
- name: Performance Reporting
uses: CodSpeedHQ/action@346a2d8a8d9d38909abd0bc3d23f773110f076ad # pin@v4
with:
mode: simulation
run: inv dev.test --pytest
postgres:
name: Tests - DB [PostgreSQL]
runs-on: ubuntu-24.04
runs-on: ubuntu-20.04
needs: ["pre-commit", "paths-filter"]
if: needs.paths-filter.outputs.server == 'true' || needs.paths-filter.outputs.force == 'true'
@@ -422,15 +327,13 @@ jobs:
INVENTREE_DB_PASSWORD: password
INVENTREE_DB_HOST: "127.0.0.1"
INVENTREE_DB_PORT: 5432
INVENTREE_DEBUG: true
INVENTREE_LOG_LEVEL: INFO
INVENTREE_CONSOLE_LOG: false
INVENTREE_DEBUG: info
INVENTREE_CACHE_HOST: localhost
INVENTREE_PLUGINS_ENABLED: true
services:
postgres:
image: postgres:17
image: postgres:14
env:
POSTGRES_USER: inventree
POSTGRES_PASSWORD: password
@@ -438,14 +341,12 @@ jobs:
- 5432:5432
redis:
image: redis:8
image: redis
ports:
- 6379:6379
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
with:
persist-credentials: false
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
- name: Environment Setup
uses: ./.github/actions/setup
with:
@@ -454,13 +355,13 @@ jobs:
dev-install: true
update: true
- name: Run Tests
run: invoke dev.test --check --translations
run: invoke dev.test
- name: Data Export Test
uses: ./.github/actions/migration
mysql:
name: Tests - DB [MySQL]
runs-on: ubuntu-24.04
runs-on: ubuntu-20.04
needs: ["pre-commit", "paths-filter"]
if: needs.paths-filter.outputs.server == 'true' || needs.paths-filter.outputs.force == 'true'
@@ -472,14 +373,12 @@ jobs:
INVENTREE_DB_PASSWORD: password
INVENTREE_DB_HOST: "127.0.0.1"
INVENTREE_DB_PORT: 3306
INVENTREE_DEBUG: true
INVENTREE_LOG_LEVEL: WARNING
INVENTREE_CONSOLE_LOG: false
INVENTREE_DEBUG: info
INVENTREE_PLUGINS_ENABLED: true
services:
mysql:
image: mysql:9
image: mysql:latest
env:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: ${{ env.INVENTREE_DB_NAME }}
@@ -491,9 +390,7 @@ jobs:
- 3306:3306
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
with:
persist-credentials: false
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
- name: Environment Setup
uses: ./.github/actions/setup
with:
@@ -502,7 +399,7 @@ jobs:
dev-install: true
update: true
- name: Run Tests
run: invoke dev.test --check --translations
run: invoke dev.test
- name: Data Export Test
uses: ./.github/actions/migration
@@ -519,13 +416,12 @@ jobs:
INVENTREE_DB_PASSWORD: password
INVENTREE_DB_HOST: "127.0.0.1"
INVENTREE_DB_PORT: 5432
INVENTREE_DEBUG: False
INVENTREE_LOG_LEVEL: WARNING
INVENTREE_DEBUG: info
INVENTREE_PLUGINS_ENABLED: false
services:
postgres:
image: postgres:17
image: postgres:14
env:
POSTGRES_USER: inventree
POSTGRES_PASSWORD: password
@@ -533,9 +429,7 @@ jobs:
- 5432:5432
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
with:
persist-credentials: false
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
- name: Environment Setup
uses: ./.github/actions/setup
with:
@@ -544,9 +438,9 @@ jobs:
dev-install: true
update: true
- name: Run Tests
run: invoke dev.test --check --migrations --report --coverage --translations
run: invoke dev.test --migrations --report --coverage
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # pin@v5.5.1
uses: codecov/codecov-action@7f8b4b4bde536c465e797be725718b88c5d95e0e # pin@v5.1.1
if: always()
with:
token: ${{ secrets.CODECOV_TOKEN }}
@@ -562,14 +456,11 @@ jobs:
env:
INVENTREE_DB_ENGINE: sqlite3
INVENTREE_DB_NAME: /home/runner/work/InvenTree/db.sqlite3
INVENTREE_DEBUG: true
INVENTREE_LOG_LEVEL: WARNING
INVENTREE_DEBUG: info
INVENTREE_PLUGINS_ENABLED: false
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
with:
persist-credentials: false
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
name: Checkout Code
- name: Environment Setup
uses: ./.github/actions/setup
@@ -578,6 +469,12 @@ jobs:
- name: Fetch Database
run: git clone --depth 1 https://github.com/inventree/test-db ./test-db
- name: Latest Database
run: |
cp test-db/latest.sqlite3 /home/runner/work/InvenTree/db.sqlite3
chmod +rw /home/runner/work/InvenTree/db.sqlite3
invoke migrate
- name: 0.10.0 Database
run: |
rm /home/runner/work/InvenTree/db.sqlite3
@@ -592,6 +489,13 @@ jobs:
chmod +rw /home/runner/work/InvenTree/db.sqlite3
invoke migrate
- name: 0.12.0 Database
run: |
rm /home/runner/work/InvenTree/db.sqlite3
cp test-db/stable_0.12.0.sqlite3 /home/runner/work/InvenTree/db.sqlite3
chmod +rw /home/runner/work/InvenTree/db.sqlite3
invoke migrate
- name: 0.13.5 Database
run: |
rm /home/runner/work/InvenTree/db.sqlite3
@@ -599,89 +503,54 @@ jobs:
chmod +rw /home/runner/work/InvenTree/db.sqlite3
invoke migrate
- name: 0.16.0 Database
run: |
rm /home/runner/work/InvenTree/db.sqlite3
cp test-db/stable_0.16.0.sqlite3 /home/runner/work/InvenTree/db.sqlite3
chmod +rw /home/runner/work/InvenTree/db.sqlite3
invoke migrate
- name: 0.17.0 Database
run: |
rm /home/runner/work/InvenTree/db.sqlite3
cp test-db/stable_0.17.0.sqlite3 /home/runner/work/InvenTree/db.sqlite3
chmod +rw /home/runner/work/InvenTree/db.sqlite3
invoke migrate
web_ui:
name: Tests - Web UI
runs-on: ubuntu-24.04
platform_ui:
name: Tests - Platform UI
runs-on: ubuntu-20.04
timeout-minutes: 60
needs: ["pre-commit", "paths-filter"]
if: needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.force == 'true'
services:
postgres:
image: postgres:17
env:
POSTGRES_DB: inventree
POSTGRES_USER: inventree_user
POSTGRES_PASSWORD: inventree_password
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U testuser"
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
INVENTREE_DB_ENGINE: postgresql
INVENTREE_DB_NAME: inventree
INVENTREE_DB_HOST: "127.0.0.1"
INVENTREE_DB_PORT: 5432
INVENTREE_DB_USER: inventree_user
INVENTREE_DB_PASSWORD: inventree_password
INVENTREE_DEBUG: true
INVENTREE_DB_ENGINE: sqlite3
INVENTREE_DB_NAME: /home/runner/work/InvenTree/db.sqlite3
INVENTREE_DEBUG: True
INVENTREE_PLUGINS_ENABLED: false
VITE_COVERAGE_BUILD: true
VITE_COVERAGE: true
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
with:
persist-credentials: false
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
- name: Environment Setup
uses: ./.github/actions/setup
with:
npm: true
install: true
update: true
apt-dependency: postgresql-client libpq-dev
pip-dependency: psycopg2
- name: Set up test data
run: |
invoke dev.setup-test -iv
invoke int.rebuild-thumbnails
run: invoke dev.setup-test -i
- name: Rebuild thumbnails
run: invoke int.rebuild-thumbnails
- name: Install dependencies
run: |
invoke int.frontend-compile --extract
cd src/frontend && npx playwright install --with-deps
run: invoke int.frontend-compile
- name: Install Playwright Browsers
run: cd src/frontend && npx playwright install --with-deps
- name: Run Playwright tests
id: tests
run: cd src/frontend && npx nyc playwright test
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # pin@v5.0.0
- uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # pin@v4
if: ${{ !cancelled() && steps.tests.outcome == 'failure' }}
with:
name: playwright-report
path: src/frontend/playwright-report/
retention-days: 14
- name: Report coverage
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@5a1091511ad55cbe89839c7260b706298ca349f7 # pin@v5.5.1
uses: codecov/codecov-action@7f8b4b4bde536c465e797be725718b88c5d95e0e # pin@v5.1.1
if: always()
with:
token: ${{ secrets.CODECOV_TOKEN }}
slug: inventree/InvenTree
flags: web
flags: pui
- name: Upload bundler info
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
@@ -690,15 +559,13 @@ jobs:
yarn install
yarn run build
web_ui_build:
name: Build - Web UI
runs-on: ubuntu-24.04
platform_ui_build:
name: Build - UI Platform
runs-on: ubuntu-20.04
timeout-minutes: 60
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
with:
persist-credentials: false
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
- name: Environment Setup
uses: ./.github/actions/setup
with:
@@ -713,32 +580,8 @@ jobs:
run: |
cd src/backend/InvenTree/web/static
zip -r frontend-build.zip web/ web/.vite
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # pin@v5.0.0
- uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # pin@v4.4.3
with:
name: frontend-build
path: src/backend/InvenTree/web/static/web
include-hidden-files: true
zizmor:
name: Security [Zizmor]
runs-on: ubuntu-24.04
needs: ["pre-commit", "paths-filter"]
if: needs.paths-filter.outputs.cicd == 'true' || needs.paths-filter.outputs.force == 'true'
permissions:
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
with:
persist-credentials: false
- uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # pin@v2
- name: Run zizmor
run: uvx zizmor --format sarif . > results.sarif
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@fdbfb4d2750291e159f0156def62b853c2798ca2 # pin@v3
with:
sarif_file: results.sarif
category: zizmor

View File

@@ -7,7 +7,7 @@ on:
permissions:
contents: read
env:
python_version: 3.11
python_version: 3.9
jobs:
stable:
@@ -20,15 +20,13 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Checkout Code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
with:
persist-credentials: false
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
- name: Version Check
run: |
pip install --require-hashes -r contrib/dev_reqs/requirements.txt
python3 .github/scripts/version_check.py
- name: Push to Stable Branch
uses: ad-m/github-push-action@77c5b412c50b723d2a4fbc6d71fb5723bcd439aa # pin@v1.0.0
uses: ad-m/github-push-action@d91a481090679876dfc4178fef17f286781251df # pin@v0.8.0
if: env.stable_release == 'true'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
@@ -43,9 +41,7 @@ jobs:
contents: write
attestations: write
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
with:
persist-credentials: false
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
- name: Environment Setup
uses: ./.github/actions/setup
with:
@@ -55,28 +51,26 @@ jobs:
- name: Build frontend
run: cd src/frontend && npm run compile && npm run build
- name: Create SBOM for frontend
uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # pin@v0
uses: anchore/sbom-action@df80a981bc6edbc4e220a492d3cbe9f5547a6e75 # 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 "${REF_NAME}" > tag.txt
env:
REF_NAME: ${{ github.ref_name }}
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@977bb373ede98d70efdf65b84cb5f73e068dcc2a # pin@v1
uses: actions/attest-build-provenance@7668571508540a607bdfd90a87a560489fe372eb # pin@v1
with:
subject-path: "${{ github.workspace }}/src/backend/InvenTree/web/static/frontend-build.zip"
- name: Upload frontend
uses: svenstaro/upload-release-action@6b7fa9f267e90b50a19fef07b3596790bb941741 # pin@2.11.3
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
@@ -84,7 +78,7 @@ jobs:
tag: ${{ github.ref }}
overwrite: true
- name: Upload Attestation
uses: svenstaro/upload-release-action@6b7fa9f267e90b50a19fef07b3596790bb941741 # pin@2.11.3
uses: svenstaro/upload-release-action@04733e069f2d7f7f0b4aebc4fbdbce8613b03ccd # pin@2.9.0
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
asset_name: frontend-build.intoto.jsonl
@@ -107,7 +101,7 @@ jobs:
INVENTREE_DEBUG: true
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
with:
persist-credentials: false
- name: Environment Setup
@@ -121,13 +115,17 @@ jobs:
pip install --require-hashes -r docs/requirements.txt
- name: Build documentation
run: |
invoke build-docs --mkdocs
invoke migrate
invoke int.export-definitions --basedir "docs"
invoke dev.schema --filename docs/schema.yml --ignore-warnings
python docs/extract_schema.py docs/schema.yml
mkdocs build -f docs/mkdocs.yml
- name: Zip build docs
run: |
cd docs/site
zip -r docs-html.zip *
- name: Publish documentation
uses: svenstaro/upload-release-action@6b7fa9f267e90b50a19fef07b3596790bb941741 # pin@2.11.3
uses: svenstaro/upload-release-action@04733e069f2d7f7f0b4aebc4fbdbce8613b03ccd # pin@2.9.0
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: docs/site/docs-html.zip

View File

@@ -32,12 +32,12 @@ jobs:
steps:
- name: "Checkout code"
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
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@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.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@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5
uses: github/codeql-action/upload-sarif@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9
with:
sarif_file: results.sarif

View File

@@ -16,7 +16,7 @@ jobs:
pull-requests: write
steps:
- uses: actions/stale@997185467fa4f803885201cee163a9f38240193d # pin@v10.1.1
- uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # pin@v9.0.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: "This issue seems stale. Please react to show this is still important."

View File

@@ -6,7 +6,7 @@ on:
- master
env:
python_version: 3.11
python_version: 3.9
node_version: 20
permissions:
@@ -23,8 +23,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
INVENTREE_DB_NAME: "./test_db.sqlite"
INVENTREE_DB_ENGINE: django.db.backends.sqlite3
INVENTREE_DEBUG: true
INVENTREE_LOG_LEVEL: INFO
INVENTREE_DEBUG: info
INVENTREE_MEDIA_ROOT: ./media
INVENTREE_STATIC_ROOT: ./static
INVENTREE_BACKUP_DIR: ./backup
@@ -32,13 +31,12 @@ jobs:
steps:
- name: Checkout Code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # pin@v6.0.1
with:
persist-credentials: false
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
- name: Environment Setup
uses: ./.github/actions/setup
with:
install: true
npm: true
apt-dependency: gettext
- name: Make Translations
run: invoke dev.translate
@@ -49,14 +47,11 @@ jobs:
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
echo "Adding commit (or ignoring if no changes)"
git commit -m "add translations" || true
echo "Removing all other changes"
git reset --hard
echo "Resetting to HEAD~"
git reset HEAD~ || true
git reset HEAD~
- name: crowdin action
uses: crowdin/github-action@60debf382ee245b21794321190ad0501db89d8c1 # pin@v2
uses: crowdin/github-action@8dfaf9c206381653e3767e3cb5ea5f08b45f02bf # pin@v2
with:
upload_sources: true
upload_translations: false

View File

@@ -9,9 +9,7 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
with:
persist-credentials: false
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # pin@v4.1.1
- name: Setup
run: pip install --require-hashes -r requirements-dev.txt
- name: Update requirements.txt

22
.gitignore vendored
View File

@@ -7,7 +7,6 @@ __pycache__/
.Python
env/
inventree-env/
.venv/
./build/
.cache/
develop-eggs/
@@ -19,6 +18,7 @@ share/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
@@ -37,11 +37,6 @@ local_settings.py
*.backup
*.old
# Files generated by profiling tools
*.prof
*.log
*.sql
# Files used for testing
inventree-demo-dataset/
inventree-data/
@@ -51,17 +46,18 @@ inventree_media
inventree_static
static_i18n
# Local config files
# Local config file
config.yaml
plugins.txt
secret_key.txt
oidc.pem
# Default data file
data.json
*.json.tmp
*.tmp.json
# Key file
secret_key.txt
# IDE / development files
.idea/
*.code-workspace
@@ -85,7 +81,6 @@ js_tmp/
# Development files
dev/
dev-db/
data/
env/
@@ -117,5 +112,8 @@ api.yaml
src/backend/InvenTree/web/static
InvenTree/web/static
# performance test results
.codspeed/
# Generated docs files
docs/schema.yml
docs/docs/api/*.yml
docs/docs/api/schema/*.yml
inventree_settings.json

View File

@@ -2,8 +2,10 @@ name: inventree
description: Open Source Inventory Management System
homepage: https://inventree.org
notifications: true
buildpack: https://github.com/matmair/null-buildpack#master
buildpack: https://github.com/mjmair/heroku-buildpack-python#v216-mjmair
env:
- STACK=heroku-20
- DISABLE_COLLECTSTATIC=1
- INVENTREE_DB_ENGINE=sqlite3
- INVENTREE_DB_NAME=database.sqlite3
- INVENTREE_PLUGINS_ENABLED
@@ -20,9 +22,9 @@ before:
- contrib/packager.io/before.sh
dependencies:
- curl
- "python3.11 | python3.12 | python3.13 | python3.14"
- "python3.11-venv | python3.12-venv | python3.13-venv | python3.14-venv"
- "python3.11-dev | python3.12-dev | python3.13-dev | python3.14-dev"
- "python3.9 | python3.10 | python3.11"
- "python3.9-venv | python3.10-venv | python3.11-venv"
- "python3.9-dev | python3.10-dev | python3.11-dev"
- python3-pip
- python3-cffi
- python3-brotli
@@ -35,6 +37,5 @@ dependencies:
- jq
- "libffi7 | libffi8"
targets:
ubuntu-22.04: true
ubuntu-24.04: true
debian-12: true
ubuntu-20.04: true
debian-11: true

View File

@@ -10,26 +10,25 @@ exclude: |
)$
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
exclude: mkdocs.yml
- id: mixed-line-ending
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.8
rev: v0.7.3
hooks:
- id: ruff-format
args: [--preview]
- id: ruff-check
- id: ruff
args: [
--fix,
# --unsafe-fixes,
--preview
]
- repo: https://github.com/astral-sh/uv-pre-commit
rev: 0.9.16
rev: 0.5.1
hooks:
- id: pip-compile
name: pip-compile requirements-dev.in
@@ -41,22 +40,22 @@ repos:
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, -b, src/backend/requirements.txt]
args: [contrib/dev_reqs/requirements.in, -o, contrib/dev_reqs/requirements.txt, --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, -b, src/backend/requirements.txt]
args: [docs/requirements.in, -o, docs/requirements.txt, --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, -b, src/backend/requirements.txt]
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.36.4
rev: v1.36.1
hooks:
- id: djlint-django
- repo: https://github.com/codespell-project/codespell
rev: v2.4.1
rev: v2.3.0
hooks:
- id: codespell
additional_dependencies:
@@ -71,16 +70,15 @@ repos:
src/frontend/vite.config.ts |
)$
- repo: https://github.com/biomejs/pre-commit
rev: v2.3.8
rev: "v0.5.0"
hooks:
- id: biome-check
additional_dependencies: ["@biomejs/biome@1.9.4"]
files: ^src/frontend/.*\.(js|ts|tsx)$
- repo: https://github.com/gitleaks/gitleaks
rev: v8.30.0
rev: v8.21.2
hooks:
- id: gitleaks
language_version: 1.25.4
#- repo: https://github.com/jumanjihouse/pre-commit-hooks
# rev: 3.0.0
# hooks:

28
.vscode/launch.json vendored
View File

@@ -11,7 +11,7 @@
"program": "${workspaceFolder}/src/backend/InvenTree/manage.py",
"args": [
"runserver",
"0.0.0.0:8000", // expose server in network (useful for testing with mobile app)
// "0.0.0.0:8000", // expose server in network (useful for testing with mobile app)
// "--noreload" // disable auto-reload
],
"django": true,
@@ -35,31 +35,7 @@
"request": "launch",
"program": "${workspaceFolder}/src/backend/InvenTree/manage.py",
"args": [
"runserver",
"0.0.0.0:8000"
],
"django": true,
"justMyCode": false
},
{
"name": "InvenTree invoke schema",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/.venv/lib/python3.11/site-packages/invoke/__main__.py",
"cwd": "${workspaceFolder}",
"args": [
"dev.schema","--ignore-warnings"
],
"justMyCode": false
},
{
"name": "schema generation",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/src/backend/InvenTree/manage.py",
"args": [
"schema",
"--file","src/frontend/schema.yml"
"runserver"
],
"django": true,
"justMyCode": false

View File

@@ -1,66 +0,0 @@
# Changelog
All notable changes to this project will be documented in this file (starting with 1.0.0).
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased - YYYY-MM-DD
### Breaking Changes
- [#10699](https://github.com/inventree/InvenTree/pull/10699) removes the `PartParameter` and `PartParameterTempalate` models (and associated API endpoints). These have been replaced with generic `Parameter` and `ParameterTemplate` models (and API endpoints). Any external client applications which made use of the old endpoints will need to be updated.
### Added
- Adds "Category" columns to BOM and Build Item tables and APIs in [#10722](https://github.com/inventree/InvenTree/pull/10772)
- Adds generic "Parameter" and "ParameterTemplate" models (and associated API endpoints) in [#10699](https://github.com/inventree/InvenTree/pull/10699)
- Adds parameter support for multiple new model types in [#10699](https://github.com/inventree/InvenTree/pull/10699)
- Allows report generator to produce PDF input controls in [#10969](https://github.com/inventree/InvenTree/pull/10969)
- UI overhaul of parameter management in [#10699](https://github.com/inventree/InvenTree/pull/10699)
### Changed
-
### Removed
- Removed python 3.9 / 3.10 support as part of Django 5.2 upgrade in [#10730](https://github.com/inventree/InvenTree/pull/10730)
- Removed the "PartParameter" and "PartParameterTemplate" models (and associated API endpoints) in [#10699](https://github.com/inventree/InvenTree/pull/10699)
- Removed the "ManufacturerPartParameter" model (and associated API endpoints) [#10699](https://github.com/inventree/InvenTree/pull/10699)
## 1.1.0 - 2025-11-02
### Added
- Added `order_queryset` report helper function in [#10439](https://github.com/inventree/InvenTree/pull/10439)
- Added `SupplierMixin` to import data from suppliers in [#9761](https://github.com/inventree/InvenTree/pull/9761)
- Added much more detailed status information for machines to the API endpoint (including backend and frontend changes) in [#10381](https://github.com/inventree/InvenTree/pull/10381)
- Added ability to partially complete and partially scrap build outputs in [#10499](https://github.com/inventree/InvenTree/pull/10499)
- Added support for Redis ACL user-based authentication in [#10551](https://github.com/inventree/InvenTree/pull/10551)
- Expose stock adjustment forms to the UI plugin context in [#10584](https://github.com/inventree/InvenTree/pull/10584)
- Allow stock adjustments for "in production" items in [#10600](https://github.com/inventree/InvenTree/pull/10600)
- Adds optional shipping address against individual sales order shipments in [#10650](https://github.com/inventree/InvenTree/pull/10650)
- Adds UI elements to "check" and "uncheck" sales order shipments in [#10654](https://github.com/inventree/InvenTree/pull/10654)
- Allow assigning project codes to order line items in [#10657](https://github.com/inventree/InvenTree/pull/10657)
- Added support for webauthn login for the frontend in [#9729](https://github.com/inventree/InvenTree/pull/9729)
- Added support for Debian 12, Ubuntu 22.04 and Ubuntu 24.04 in the installer and package in [#10705](https://github.com/inventree/InvenTree/pull/10705)
- Support for S3 and SFTP storage backends for media and static files ([#10140](https://github.com/inventree/InvenTree/pull/10140))
- Adds hooks for custom UI spotlight actions in [#10720](https://github.com/inventree/InvenTree/pull/10720)
- Support uploading attachments against SupplierPart in [#10724](https://github.com/inventree/InvenTree/pull/10724)
### Changed
- Changed site URL check to allow protocol mismatches if `INVENTREE_SITE_LAX_PROTOCOL` is set to `True` (default) in [#10454](https://github.com/inventree/InvenTree/pull/10454)
- Changed call signature of `get_global_setting` to use `environment_key` instead of `enviroment_key` in [#10557](https://github.com/inventree/InvenTree/pull/10557)
## 1.0.0 - 2025-09-15
The first "stable" release following semver but not extensively other than the previous releases. The use of 1.0 indicates the stability that users already expect from InvenTree.
An overarching theme of this release is the complete switch to a new UI framework and paradigm (PUI). The old templating based UI (CUI) is now removed. This makes major improvements in the security and portability of InvenTree possible.
Our blog holds [a few articles](https://inventree.org/blog/2024/09/23/ui-roadmap) on the topic. This journey started in [March 2022](https://github.com/inventree/InvenTree/issues/2789) and was announced [in 2023](https://inventree.org/blog/2023/08/28/react).
Specific entries to the changelog will be kept for all stable channel minor releases, for changes in 1.0 please refer to the [blog posts](https://inventree.org/blog/2025/09/15/1.0.0) and the [milestone](https://github.com/inventree/InvenTree/milestone/17)

View File

@@ -1,128 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
support AT inventree DOR org.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

View File

@@ -9,7 +9,6 @@
[![Documentation Status](https://readthedocs.org/projects/inventree/badge/?version=latest)](https://inventree.readthedocs.io/en/latest/?badge=latest)
![Docker Build](https://github.com/inventree/inventree/actions/workflows/docker.yaml/badge.svg)
[![Netlify Status](https://api.netlify.com/api/v1/badges/9bbb2101-0a4d-41e7-ad56-b63fb6053094/deploy-status)](https://app.netlify.com/sites/inventree/deploys)
[![Performance Testing](https://dev.azure.com/InvenTree/InvenTree%20test%20statistics/_apis/build/status%2Fmatmair.InvenTree?branchName=testing)](https://dev.azure.com/InvenTree/InvenTree%20test%20statistics/_build/latest?definitionId=3&branchName=testing)
[![OpenSSF Best Practices](https://bestpractices.coreinfrastructure.org/projects/7179/badge)](https://bestpractices.coreinfrastructure.org/projects/7179)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/inventree/InvenTree/badge)](https://securityscorecards.dev/viewer/?uri=github.com/inventree/InvenTree)
@@ -53,10 +52,10 @@ Want to see what we are working on? Check out the [roadmap tag](https://github.c
InvenTree is designed to be **extensible**, and provides multiple options for **integration** with external applications or addition of custom plugins:
* [InvenTree API](https://docs.inventree.org/en/latest/api/)
* [Python module](https://docs.inventree.org/en/latest/api/python/)
* [Plugin interface](https://docs.inventree.org/en/latest/plugins/)
* [Third party tools](https://docs.inventree.org/en/latest/plugins/integrate/)
* [InvenTree API](https://docs.inventree.org/en/latest/api/api/)
* [Python module](https://docs.inventree.org/en/latest/api/python/python/)
* [Plugin interface](https://docs.inventree.org/en/latest/extend/plugins)
* [Third party tools](https://docs.inventree.org/en/latest/extend/integrate)
<!-- TechStack -->
### :space_invader: Tech Stack
@@ -83,7 +82,16 @@ InvenTree is designed to be **extensible**, and provides multiple options for **
</details>
<details>
<summary>Client</summary>
<summary>Client - CUI</summary>
<ul>
<li><a href="https://getbootstrap.com/">Bootstrap</a></li>
<li><a href="https://jquery.com/">jQuery</a></li>
<li><a href="https://bootstrap-table.com/">Bootstrap-Table</a></li>
</ul>
</details>
<details>
<summary>Client - PUI</summary>
<ul>
<li><a href="https://react.dev/">React</a></li>
<li><a href="https://lingui.dev/">Lingui</a></li>
@@ -130,7 +138,7 @@ Refer to the [getting started guide](https://docs.inventree.org/en/latest/start/
<!-- Mobile App -->
## :iphone: Mobile App
InvenTree is supported by a [companion mobile app](https://docs.inventree.org/en/latest/app/) which allows users access to stock control information and functionality.
InvenTree is supported by a [companion mobile app](https://docs.inventree.org/app/) which allows users access to stock control information and functionality.
<div align="center"><h4>
<a href="https://play.google.com/store/apps/details?id=inventree.inventree_app">Android Play Store</a>
@@ -138,17 +146,10 @@ InvenTree is supported by a [companion mobile app](https://docs.inventree.org/en
<a href="https://apps.apple.com/au/app/inventree/id1581731101#?platform=iphone">Apple App Store</a>
</h4></div>
<!-- Security -->
## :lock: Code of Conduct & Security Policy
The InvenTree project team is committed to providing a safe and welcoming environment for all users. Please read our [Code of Conduct](CODE_OF_CONDUCT.md) for more information.
InvenTree is following industry best practices for security. Our security policy is included [in this repo](SECURITY.md). We provide dedicated security pages on [our documentation site](https://docs.inventree.org/en/latest/security/).
<!-- Contributing -->
## :wave: Contributing
Contributions are welcomed and encouraged. Please help to make this project even better! Refer to the [contribution page](https://docs.inventree.org/en/latest/develop/contributing/).
Contributions are welcomed and encouraged. Please help to make this project even better! Refer to the [contribution page](CONTRIBUTING.md).
<!-- Translation -->
## :scroll: Translation
@@ -164,7 +165,7 @@ If you use InvenTree and find it to be useful, please consider [sponsoring the p
## :gem: Acknowledgements
We want to acknowledge [PartKeepr](https://github.com/partkeepr/PartKeepr) as a valuable predecessor and inspiration.
Find a full list of used third-party libraries in the license information dialog of your instance.
Find a full list of used third-party libraries in [our documentation](https://docs.inventree.org/en/latest/credits/).
## :heart: Support
@@ -180,26 +181,17 @@ Find a full list of used third-party libraries in the license information dialog
<a href="https://github.com/PricelessToolkit"><img src="https://github.com/PricelessToolkit.png" width="60px" alt="" /></a>
<a href="https://github.com/cabottech"><img src="https://github.com/cabottech.png" width="60px" alt="Cabot Technologies" /></a>
<a href="https://github.com/markus-k"><img src="https://github.com/markus-k.png" width="60px" alt="Markus Kasten" /></a>
<a href="https://github.com/jefffhaynes"><img src="https://github.com/jefffhaynes.png" width="60px" alt="Jeff Haynes" /></a>
<a href="https://github.com/dnviti"><img src="https://github.com/dnviti.png" width="60px" alt="Daniele Viti" /></a>
<a href="https://github.com/Islendur"><img src="https://github.com/Islendur.png" width="60px" alt="Islendur" /></a>
<a href="https://github.com/Gibeon-NL"><img src="https://github.com/Gibeon-NL.png" width="60px" alt="Gibeon-NL" /></a>
<a href="https://github.com/Motrac-Research-Engineering"><img src="https://github.com/Motrac-Research-Engineering.png" width="60px" alt="Motrac Research" /></a>
<a href="https://github.com/trytuna"><img src="https://github.com/trytuna.png" width="60px" alt="Timo Scrappe" /></a>
<a href="https://github.com/ATLAS2246"><img src="https://github.com/ATLAS2246.png" width="60px" alt="ATLAS2246" /></a>
<a href="https://github.com/Kedarius"><img src="https://github.com/Kedarius.png" width="60px" alt="Radek Hladik" /></a>
<a href="https://github.com/jefffhaynes"><img src="https://github.com/jefffhaynes.png" width="60px" alt="Jess Haynes" /></a>
</p>
<p>With ongoing resources provided by:</p>
<p align="center">
<a href="https://depot.dev?utm_source=inventree"><img src="https://depot.dev/badges/built-with-depot.svg" alt="Built with Depot" /></a>
<a href="https://inventree.org/digitalocean">
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" width="201px" alt="Servers by Digital Ocean">
</a>
<a href="https://www.netlify.com"> <img src="https://www.netlify.com/v3/img/components/netlify-color-bg.svg" alt="Deploys by Netlify" /> </a>
<a href="https://crowdin.com"> <img src="https://crowdin.com/images/crowdin-logo.svg" alt="Translation by Crowdin" /> </a> <br>
<a href="https://crowdin.com"> <img src="https://crowdin.com/images/crowdin-logo.svg" alt="Translation by Crowdin" /> </a>
</p>

23
RELEASE.md Normal file
View File

@@ -0,0 +1,23 @@
## Release Checklist
Checklist of steps to perform at each code release
### Update Version String
Update `INVENTREE_SW_VERSION` in [version.py](https://github.com/inventree/InvenTree/blob/master/src/backend/InvenTree/InvenTree/version.py)
### Increment API Version
If the API has changed, ensure that the API version number is incremented.
### Translation Files
Merge the crowdin translation updates into master branch
### Python Library Release
Create new release for the [InvenTree python library](https://github.com/inventree/inventree-python)
## App Release
Create new versioned release for the InvenTree mobile app.

View File

@@ -1,9 +1,7 @@
# Security Policy
The InvenTree team take all security vulnerabilities seriously. Thank you for improving the security of our open source software.
We appreciate your efforts and responsible disclosure and will make every effort to acknowledge your contributions.
The general project security policies and processes are documented in [our documentation](https://docs.inventree.org/en/stable/security/).
## Reporting a Vulnerability
@@ -13,13 +11,7 @@ Please report security vulnerabilities by emailing the InvenTree team at:
security@inventree.org
```
Someone from the InvenTree development team will acknowledge your email as soon as possible (normally within a week), and indicate the next steps in handling your security report.
Someone from the InvenTree development team will acknowledge your email as soon as possible, and indicate the next steps in handling your security report.
The team will endeavour to keep you informed of the progress towards a fix for the issue, and subsequent release to the stable and development code branches. Where possible, the issue will be resolved within 90 days of reporting.
### Public Disclosure
Using GitHub's security advisory system, we will publish a public disclosure of the issue once it has been acknowledged, reproduced and resolved.
We support assigning CVEs to security issues where appropriate.
The project can be identified by the CPE code ``cpe:2.3:a:inventree_project:inventree:``.

View File

@@ -2,7 +2,7 @@ coverage:
status:
project:
default:
target: 85%
target: 82%
patch: off
github_checks:
@@ -22,61 +22,15 @@ flag_management:
statuses:
- type: project
target: 40%
- name: web
- name: pui
carryforward: true
statuses:
- type: project
target: 45%
component_management:
default_rules:
statuses:
- type: project
target: auto
branches:
- "!main"
individual_components:
- component_id: backend-apps
name: Backend Apps
paths:
- src/backend/InvenTree/build/**
- src/backend/InvenTree/company/**
- src/backend/InvenTree/data_exporter/**
- src/backend/InvenTree/importer/**
- src/backend/InvenTree/machine/**
- src/backend/InvenTree/order/**
- src/backend/InvenTree/part/**
- src/backend/InvenTree/plugin/**
- src/backend/InvenTree/report/**
- src/backend/InvenTree/stock/**
- src/backend/InvenTree/users/**
- src/backend/InvenTree/web/**
statuses:
- type: project
target: 90%
- component_id: backend-general
name: Backend General
paths:
- src/backend/InvenTree/generic/**
- src/backend/InvenTree/common/**
statuses:
- type: project
target: 92% # 95%
- type: patch
target: 95%
- component_id: web
name: Frontend
paths:
- src/frontend/**
statuses:
- type: project
target: 68% # 90%
- type: patch
target: 80%
comment:
require_bundle_changes: True
bundle_change_threshold: "1Kb"
layout: "header, diff, flags, components"
bundle_analysis:
warning_threshold: "5%"

1
config/.gitignore vendored
View File

@@ -1 +0,0 @@
*

View File

@@ -1 +0,0 @@
This folder is recommended for configuration values and excluded from change tracking in git

View File

@@ -13,11 +13,6 @@ INVENTREE_SITE_URL="http://inventree.localhost"
#INVENTREE_SITE_URL="http://192.168.1.2" # You can specify a local IP address here
#INVENTREE_SITE_URL="https://inventree.my-domain.com" # Or a public domain name (which you control)
# InvenTree proxy forwarding settings
INVENTREE_USE_X_FORWARDED_HOST=True
INVENTREE_USE_X_FORWARDED_PORT=True
INVENTREE_USE_X_FORWARDED_PROTO=True
# Specify the location of the external data volume
# By default, placed in local directory 'inventree-data'
INVENTREE_EXT_VOLUME=./inventree-data
@@ -28,8 +23,7 @@ INVENTREE_LOG_LEVEL=WARNING
# Enable custom plugins?
INVENTREE_PLUGINS_ENABLED=True
# Run database migrations automatically?
# Note: This does not negate the need to run "invoke update"
# Run migrations automatically?
INVENTREE_AUTO_UPDATE=True
# InvenTree superuser account details

View File

@@ -30,9 +30,9 @@
}
# The default server address is configured in the .env file
# If not specified, the proxy listens for all http/https traffic
# If not specified, the default address is used - http://inventree.localhost
# If you need to listen on multiple addresses, or use a different port, you can modify this section directly
{$INVENTREE_SITE_URL:"http://, https://"} {
{$INVENTREE_SITE_URL:http://inventree.localhost} {
import log_common inventree
encode gzip

View File

@@ -9,7 +9,9 @@
# - Runs InvenTree web server under django development server
# - Monitors source files for any changes, and live-reloads server
FROM python:3.11-slim-trixie@sha256:1d6131b5d479888b43200645e03a78443c7157efbdb730e6b48129740727c312 AS inventree_base
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=""
@@ -18,9 +20,9 @@ ARG commit_date=""
ARG data_dir="data"
ENV PYTHONUNBUFFERED=1
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
ENV INVOKE_RUN_SHELL="/bin/bash"
ENV PYTHONUNBUFFERED 1
ENV PIP_DISABLE_PIP_VERSION_CHECK 1
ENV INVOKE_RUN_SHELL="/bin/ash"
ENV INVENTREE_DOCKER="true"
@@ -37,7 +39,6 @@ ENV INVENTREE_BACKEND_DIR="${INVENTREE_HOME}/src/backend"
# InvenTree configuration files
ENV INVENTREE_CONFIG_FILE="${INVENTREE_DATA_DIR}/config.yaml"
ENV INVENTREE_SECRET_KEY_FILE="${INVENTREE_DATA_DIR}/secret_key.txt"
ENV INVENTREE_OIDC_PRIVATE_KEY_FILE="${INVENTREE_DATA_DIR}/oidc.pem"
ENV INVENTREE_PLUGIN_FILE="${INVENTREE_DATA_DIR}/plugins.txt"
# Worker configuration (can be altered by user)
@@ -48,7 +49,8 @@ ENV INVENTREE_BACKGROUND_WORKERS="4"
ENV INVENTREE_WEB_ADDR=0.0.0.0
ENV INVENTREE_WEB_PORT=8000
LABEL org.opencontainers.image.vendor="inventree" \
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" \
@@ -56,76 +58,64 @@ LABEL org.opencontainers.image.vendor="inventree" \
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}
# Install basic system level packages
RUN apt-get update && apt-get install -y --no-install-recommends \
git gettext libldap2 wget curl ssh \
# Weasyprint requirements : https://doc.courtbouillon.org/weasyprint/stable/first_steps.html#alpine-3-12
weasyprint libpango-1.0-0 libcairo2 poppler-utils \
# Database client libraries
postgresql-client mariadb-client \
# font support
fontconfig fonts-freefont-ttf fonts-terminus fonts-noto-core fonts-noto-cjk \
# Cleanup
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Remove heavy python packages installed by weasyprint (that we don't need)
RUN rm -rf /usr/lib/python3/dist-packages/numpy \
&& rm -rf /usr/lib/python3/dist-packages/scipy \
&& rm -rf /usr/lib/python3/dist-packages/sympy
# Install required system level packages
RUN apk add --no-cache \
git gettext py-cryptography \
# Image format support
libjpeg libwebp zlib \
# Weasyprint requirements : https://doc.courtbouillon.org/weasyprint/stable/first_steps.html#alpine-3-12
py3-pip py3-pillow py3-cffi py3-brotli pango poppler-utils openldap \
# Postgres client
postgresql15-client \
# 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
EXPOSE 8000
# Fix invoke command path for InvenTree environment check
RUN python -m pip install --no-cache-dir -U invoke
RUN mkdir -p ${INVENTREE_HOME}
WORKDIR ${INVENTREE_HOME}
COPY contrib/container/requirements.txt base_requirements.txt
COPY src/backend/requirements.txt ./
COPY contrib/container/install_build_packages.sh .
RUN chmod +x install_build_packages.sh
COPY tasks.py \
src/backend/requirements.txt \
contrib/container/gunicorn.conf.py \
contrib/container/init.sh \
./
# For ARMv7 architecture, add the piwheels repo (for cryptography library)
# Otherwise, we have to build from source, which is difficult
# Ref: https://github.com/inventree/InvenTree/pull/4598
RUN if [ `apk --print-arch` = "armv7" ]; then \
printf "[global]\nextra-index-url=https://www.piwheels.org/simple\n" > /etc/pip.conf ; \
fi
COPY tasks.py contrib/container/gunicorn.conf.py contrib/container/init.sh ./
RUN chmod +x init.sh
ENTRYPOINT ["/bin/bash", "./init.sh"]
ENTRYPOINT ["/bin/ash", "./init.sh"]
# Multi-stage build to compile project requirements
FROM inventree_base AS builder_stage
FROM inventree_base AS prebuild
# Copy source files
ENV PATH=/root/.local/bin:$PATH
RUN ./install_build_packages.sh --no-cache --virtual .build-deps && \
pip install --user --require-hashes -r base_requirements.txt --no-cache && \
pip install --user --require-hashes -r requirements.txt --no-cache && \
apk --purge del .build-deps
# Frontend builder image:
FROM prebuild AS frontend
RUN apk add --no-cache --update nodejs npm yarn
RUN yarn config set network-timeout 600000 -g
COPY src ${INVENTREE_HOME}/src
COPY tasks.py ${INVENTREE_HOME}/tasks.py
# Install backend build dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
pkg-config build-essential \
libldap2-dev libsasl2-dev libssl-dev \
libmariadb-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Build and install python dependencies
RUN pip install --user --require-hashes -r base_requirements.txt --no-cache-dir && \
pip install --user --require-hashes -r requirements.txt --no-cache-dir && \
pip cache purge && \
rm -rf /root/.cache/pip
# Install frontend build dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
nodejs npm \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN npm install -g n yarn --ignore-scripts && \
yarn config set network-timeout 600000 -g
RUN bash -c "n lts"
RUN cd "${INVENTREE_HOME}" && invoke int.frontend-compile --extract
RUN cd ${INVENTREE_HOME} && invoke int.frontend-compile
# InvenTree production image:
# - Copies required files from local directory
@@ -138,26 +128,34 @@ ENV INVENTREE_DEBUG=False
ENV INVENTREE_COMMIT_HASH="${commit_hash}"
ENV INVENTREE_COMMIT_DATE="${commit_date}"
# use dependencies and compiled wheels from the prebuild image
ENV PATH=/root/.local/bin:$PATH
COPY --from=prebuild /root/.local /root/.local
# Copy source code
COPY src/backend/InvenTree ${INVENTREE_BACKEND_DIR}/InvenTree
COPY src/backend/requirements.txt ${INVENTREE_BACKEND_DIR}/requirements.txt
# Copy compiled dependencies from prebuild image
ENV PATH=/root/.local/bin:$PATH
COPY --from=builder_stage ${INVENTREE_BACKEND_DIR}/InvenTree/web/static/web ${INVENTREE_BACKEND_DIR}/InvenTree/web/static/web
COPY --from=builder_stage /root/.local /root/.local
COPY --from=frontend ${INVENTREE_BACKEND_DIR}/InvenTree/web/static/web ${INVENTREE_BACKEND_DIR}/InvenTree/web/static/web
# Launch the production server
CMD ["sh", "-c", "exec gunicorn -c ./gunicorn.conf.py InvenTree.wsgi -b ${INVENTREE_WEB_ADDR}:${INVENTREE_WEB_PORT} --chdir ${INVENTREE_BACKEND_DIR}/InvenTree"]
CMD gunicorn -c ./gunicorn.conf.py InvenTree.wsgi -b 0.0.0.0:8000 --chdir ${INVENTREE_BACKEND_DIR}/InvenTree
FROM builder_stage AS dev
ENV PATH=/root/.local/bin:$PATH
FROM inventree_base AS dev
# Vite server (for local frontend development)
EXPOSE 5173
# Install packages required for building python packages
RUN ./install_build_packages.sh
RUN pip install --require-hashes -r base_requirements.txt --no-cache
# Install nodejs / npm / yarn
RUN apk add --no-cache --update nodejs npm yarn
RUN yarn config set network-timeout 600000 -g
# The development image requires the source code to be mounted to /home/inventree/
# So from here, we don't actually "do" anything, apart from some file management
@@ -170,7 +168,7 @@ ENV INVENTREE_PY_ENV="${INVENTREE_DATA_DIR}/env"
WORKDIR ${INVENTREE_HOME}
# Entrypoint ensures that we are running in the python virtual environment
ENTRYPOINT ["/bin/bash", "./contrib/container/init.sh"]
ENTRYPOINT ["/bin/ash", "./contrib/container/init.sh"]
# Launch the development server
CMD ["invoke", "dev.server", "-a", "${INVENTREE_WEB_ADDR}:${INVENTREE_WEB_PORT}"]
CMD ["invoke", "server", "-a", "${INVENTREE_WEB_ADDR}:${INVENTREE_WEB_PORT}"]

View File

@@ -18,7 +18,7 @@ services:
# Use PostgreSQL as the database backend
# Note: This can be changed to a different backend if required
inventree-dev-db:
image: postgres:17
image: postgres:13
expose:
- 5432/tcp
environment:

View File

@@ -32,17 +32,11 @@
# INVENTREE_TAG=0.7.5
#
# ----------------------------
# Docker compose customization
# ----------------------------
# If you wish to customize the docker-compose script, you should only do so if you understand the stack!
# Do not expect support for customizations that are not part of the standard InvenTree setup!
services:
# Database service
# Use PostgreSQL as the database backend
inventree-db:
image: postgres:17
image: postgres:13
container_name: inventree-db
expose:
- ${INVENTREE_DB_PORT:-5432}/tcp
@@ -58,7 +52,7 @@ services:
# redis acts as database cache manager
inventree-cache:
image: redis:7-alpine
image: redis:7.0
container_name: inventree-cache
env_file:
- .env
@@ -101,7 +95,6 @@ services:
restart: unless-stopped
# caddy acts as reverse proxy and static file server
# You can adjust the ports that the proxy listens on via the .env file
# https://hub.docker.com/_/caddy
inventree-proxy:
container_name: inventree-proxy
@@ -110,8 +103,8 @@ services:
depends_on:
- inventree-server
ports:
- ${INVENTREE_HTTP_PORT:-80}:80
- ${INVENTREE_HTTPS_PORT:-443}:443
- ${INVENTREE_WEB_PORT:-80}:80
- 443:443
env_file:
- .env
volumes:
@@ -121,3 +114,17 @@ services:
- ${INVENTREE_EXT_VOLUME}:/var/log:z
- ${INVENTREE_EXT_VOLUME}:/data:z
- ${INVENTREE_EXT_VOLUME}:/config:z
# alternative: run nginx as reverse proxy
# inventree-proxy:
# container_name: inventree-proxy
# image: nginx:stable
# restart: always
# depends_on:
# - inventree-server
# ports:
# - ${INVENTREE_WEB_PORT:-80}:80
# - 443:443
# volumes:
# - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro,z
# - ${INVENTREE_EXT_VOLUME}:/var/www:z

View File

@@ -1,11 +1,9 @@
# InvenTree environment variables for a development setup
# These variables will be used by the docker-compose.yml file
INVENTREE_SITE_URL=http://localhost:8000
# Set DEBUG to True for a development setup
INVENTREE_DEBUG=True
INVENTREE_LOG_LEVEL=WARNING
INVENTREE_LOG_LEVEL=INFO
INVENTREE_DB_LOGGING=False
# Database configuration options

View File

@@ -19,7 +19,7 @@ threads = 4
# Worker timeout (default = 90 seconds)
timeout = os.environ.get('INVENTREE_GUNICORN_TIMEOUT', '90')
timeout = os.environ.get('INVENTREE_GUNICORN_TIMEOUT', 90)
# Number of worker processes
workers = os.environ.get('INVENTREE_GUNICORN_WORKERS', None)
@@ -40,18 +40,3 @@ max_requests_jitter = 50
# preload app so that the ready functions are only executed once
preload_app = True
def post_fork(server, worker):
"""Post-fork hook to set up logging for each worker."""
from django.conf import settings
if not settings.TRACING_ENABLED:
return
# Instrument gunicorm
from InvenTree.tracing import setup_instruments, setup_tracing
# Run tracing/logging instrumentation
setup_tracing(**settings.TRACING_DETAILS)
setup_instruments(settings.DB_ENGINE)

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/ash
# exit when any command fails
set -e
@@ -40,17 +40,14 @@ if [[ -n "$INVENTREE_PY_ENV" ]]; then
if test -d "$INVENTREE_PY_ENV"; then
# venv already exists
echo "Using Python virtual environment: ${INVENTREE_PY_ENV}"
source ${INVENTREE_PY_ENV}/bin/activate
else
# Setup a virtual environment (within the provided directory)
# Setup a virtual environment (within the "data/env" directory)
echo "Running first time setup for python environment"
python3 -m venv ${INVENTREE_PY_ENV} --system-site-packages --upgrade-deps
# Ensure invoke tool is installed locally
source ${INVENTREE_PY_ENV}/bin/activate
python3 -m pip install --ignore-installed --upgrade invoke
fi
# Now activate the venv
source ${INVENTREE_PY_ENV}/bin/activate
fi
cd ${INVENTREE_HOME}

View File

@@ -0,0 +1,12 @@
#!/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
apk add gcc g++ musl-dev openssl-dev libffi-dev cargo python3-dev openldap-dev \
libstdc++ build-base linux-headers py3-grpcio \
jpeg-dev openjpeg-dev libwebp-dev zlib-dev \
sqlite sqlite-dev \
mariadb-connector-c-dev mariadb-client mariadb-dev \
postgresql15-dev postgresql-libs \
$@

View File

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

View File

@@ -1,129 +1,129 @@
# This file was autogenerated by uv via the following command:
# uv pip compile contrib/container/requirements.in -o contrib/container/requirements.txt --python-version=3.11 --no-strip-extras --generate-hashes -b src/backend/requirements.txt
asgiref==3.10.0 \
--hash=sha256:aef8a81283a34d0ab31630c9b7dfe70c812c95eba78171367ca8745e88124734 \
--hash=sha256:d89f2d8cd8b56dada7d52fa7dc8075baa08fb836560710d38c292a7a3f78c04e
# uv pip compile contrib/container/requirements.in -o contrib/container/requirements.txt --python-version=3.11 --no-strip-extras --generate-hashes
asgiref==3.8.1 \
--hash=sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47 \
--hash=sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590
# via django
django==5.2.9 \
--hash=sha256:16b5ccfc5e8c27e6c0561af551d2ea32852d7352c67d452ae3e76b4f6b2ca495 \
--hash=sha256:3a4ea88a70370557ab1930b332fd2887a9f48654261cdffda663fef5976bb00a
django==4.2.17 \
--hash=sha256:3a93350214ba25f178d4045c0786c61573e7dbfa3c509b3551374f1e11ba8de0 \
--hash=sha256:6b56d834cc94c8b21a8f4e775064896be3b4a4ca387f2612d4406a5927cd2fdc
# via
# -r contrib/container/requirements.in
# django-auth-ldap
django-auth-ldap==5.2.0 \
--hash=sha256:08ba6efc0340d9874725a962311b14991e29a33593eb150a8fb640709dbfa80f \
--hash=sha256:7dc6eb576ba36051850b580e4bdf4464e04bbe7367c3827a3121b4d7c51fb175
django-auth-ldap==5.1.0 \
--hash=sha256:9c607e8d9c53cf2a0ccafbe0acfc33eb1d1fd474c46ec52d30aee0dca1da9668 \
--hash=sha256:a5f7bdb54b2ab80e4e9eb080cd3e06e89e4c9d2d534ddb39b66cd970dd6d3536
# via -r contrib/container/requirements.in
gunicorn==23.0.0 \
--hash=sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d \
--hash=sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec
# via -r contrib/container/requirements.in
invoke==2.2.1 \
--hash=sha256:2413bc441b376e5cd3f55bb5d364f973ad8bdd7bf87e53c79de3c11bf3feecc8 \
--hash=sha256:515bf49b4a48932b79b024590348da22f39c4942dff991ad1fb8b8baea1be707
invoke==2.2.0 \
--hash=sha256:6ea924cc53d4f78e3d98bc436b08069a03077e6f85ad1ddaa8a116d7dad15820 \
--hash=sha256:ee6cbb101af1a859c7fe84f2a264c059020b0cb7fe3535f9424300ab568f6bd5
# via -r contrib/container/requirements.in
mariadb==1.1.14 \
--hash=sha256:0f5fc74023f2e479be159542633f8b5865fee18a36e5a6d4e262387b39a692ee \
--hash=sha256:1a50b4612c0dd5b69690cebb34cef552a7f64dcadeb5aa91d70cd99bf01bc5b3 \
--hash=sha256:3d2c795cde606f4e12c0d73282b062433f414cae035675b0d81f2d65c9b79ac5 \
--hash=sha256:3f6fdc4ded5e0500a6a29bf0c8bf1be94189dcef5a8d5e0e154a4b3456f86bcc \
--hash=sha256:4c7f33578da163a1b79929aae241f5f981d7b9d5a94d89e589aad7ec58e313ea \
--hash=sha256:55ddbe5272c292cbcb2968d87681b5d2b327e65646a015e324b8eeb804d14531 \
--hash=sha256:5b514362ba3ad3ef7ada91bc8a8b3b4c0e5144efce96b5bffa3dbc46b8af7d7a \
--hash=sha256:6659725837e48fa6af05e20128fb525029f706f1921d5dbf639a25b2f80b9f93 \
--hash=sha256:685a1ad2a24fd0aae1c4416fe0ac794adc84ab9209c8d0c57078f770d39731db \
--hash=sha256:7fd603c5cf23c47ef0d28fdc2b4b79919ee7f75d00ed070d3cd1054dcf816aeb \
--hash=sha256:932a95016b7e9b8d78893aa5ee608e74199e3c6dd607dbe5e4da2010a4f67b88 \
--hash=sha256:98d552a8bb599eceaa88f65002ad00bd88aeed160592c273a7e5c1d79ab733dd \
--hash=sha256:e6d702a53eccf20922e47f2f45cfb5c7a0c2c6c0a46e4ee2d8a80d0ff4a52f34
mariadb==1.1.11 \
--hash=sha256:0f8de8d66ca71bd102f34a970a331b7d75bdf7f8050d80e37cdcc6ff3c85cf7a \
--hash=sha256:2e72ea65f1d7d8563ee84e172f2a583193092bdb6ff83c470ca9722873273ecc \
--hash=sha256:3f64b520089cb60c4f8302f365ed0ae057c4c859ab70fc8b1c4358192c3c8f27 \
--hash=sha256:579420293fa790d5ae0a6cb4bdb7e8be8facc2ceefb6123c2b0e8042b3fa725d \
--hash=sha256:6f28d8ccc597a3a1368be14078110f743900dbb3b0c7f1cce3072d83bec59c8a \
--hash=sha256:c1992ebf9c6f012ac158e33fef9f2c4ba899f721064c4ae3a3489233793296c0 \
--hash=sha256:cf6647cee081e21d0994b409ba8c8fa2077f3972f1de3627c5502fb31d14f806 \
--hash=sha256:d7302ccd15f0beee7b286885cbf6ac71ddc240374691d669784d99f89ba34d79 \
--hash=sha256:dbc4cf0e302ca82d46f9431a0b04f048e9c21ee56d6f3162c29605f84d63b40c \
--hash=sha256:e94f1738bec09c97b601ddbb1908eb24524ba4630f507a775d82ffdb6c5794b3 \
--hash=sha256:f6dfdc954edf02b6519419a054798cda6034dc459d1d482e3329e37aa27d34f0
# via -r contrib/container/requirements.in
mysqlclient==2.2.7 \
--hash=sha256:199dab53a224357dd0cb4d78ca0e54018f9cee9bf9ec68d72db50e0a23569076 \
--hash=sha256:201a6faa301011dd07bca6b651fe5aaa546d7c9a5426835a06c3172e1056a3c5 \
--hash=sha256:24ae22b59416d5fcce7e99c9d37548350b4565baac82f95e149cac6ce4163845 \
--hash=sha256:2e3c11f7625029d7276ca506f8960a7fd3c5a0a0122c9e7404e6a8fe961b3d22 \
--hash=sha256:4b4c0200890837fc64014cc938ef2273252ab544c1b12a6c1d674c23943f3f2e \
--hash=sha256:92af368ed9c9144737af569c86d3b6c74a012a6f6b792eb868384787b52bb585 \
--hash=sha256:977e35244fe6ef44124e9a1c2d1554728a7b76695598e4b92b37dc2130503069 \
--hash=sha256:a22d99d26baf4af68ebef430e3131bb5a9b722b79a9fcfac6d9bbf8a88800687
mysqlclient==2.2.6 \
--hash=sha256:3da70a07753ba6be881f7d75e795e254f6a0c12795778034acc69769b0649d37 \
--hash=sha256:43c5b30be0675080b9c815f457d73397f0442173e7be83d089b126835e2617ae \
--hash=sha256:794857bce4f9a1903a99786dd29ad7887f45a870b3d11585b8c51c4a753c4174 \
--hash=sha256:b0a5cddf1d3488b254605041070086cac743401d876a659a72d706a0d89c8ebb \
--hash=sha256:c0b46d9b78b461dbb62482089ca8040fa916595b1b30f831ebbd1b0a82b43d53 \
--hash=sha256:e940b41d85dfd7b190fa47d52f525f878cfa203d4653bf6a35b271b3c3be125b \
--hash=sha256:e94a92858203d97fd584bdb6d7ee8c56f2590db8d77fd44215c0dcf5e739bc37 \
--hash=sha256:f3efb849d6f7ef4b9788a0eda2e896b975e0ebf1d6bf3dcabea63fd698e5b0b5
# via -r contrib/container/requirements.in
packaging==25.0 \
--hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484 \
--hash=sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f
packaging==24.2 \
--hash=sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759 \
--hash=sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f
# via
# gunicorn
# mariadb
psycopg[binary, pool]==3.2.12 \
--hash=sha256:85c08d6f6e2a897b16280e0ff6406bef29b1327c045db06d21f364d7cd5da90b \
--hash=sha256:8a1611a2d4c16ae37eada46438be9029a35bb959bb50b3d0e1e93c0f3d54c9ee
psycopg[binary, pool]==3.2.3 \
--hash=sha256:644d3973fe26908c73d4be746074f6e5224b03c1101d302d9a53bf565ad64907 \
--hash=sha256:a5764f67c27bec8bfac85764d23c534af2c27b893550377e37ce59c12aac47a2
# via -r contrib/container/requirements.in
psycopg-binary==3.2.12 \
--hash=sha256:095ccda59042a1239ac2fefe693a336cb5cecf8944a8d9e98b07f07e94e2b78d \
--hash=sha256:0afb71a99871a41dd677d207c6a988d978edde5d6a018bafaed4f9da45357055 \
--hash=sha256:100fdfee763d701f6da694bde711e264aca4c2bc84fb81e1669fb491ce11d219 \
--hash=sha256:13cd057f406d2c8063ae8b489395b089a7f23c39aff223b5ea39f0c4dd640550 \
--hash=sha256:15e226f0d8af85cc8b2435b2e9bc6f0d40febc79eef76cf20fceac4d902a6a7b \
--hash=sha256:16db2549a31ccd4887bef05570d95036813ce25fd9810b523ba1c16b0f6cfd90 \
--hash=sha256:1c1dbeb8e97d00a33dfa9987776ce3d1c1e4cc251dfbd663b8f9e173f5c89d17 \
--hash=sha256:1d7cedecbe0bb60a2e72b1613fba4072a184a6472d6cc9aa99e540217f544e3e \
--hash=sha256:2598d0e4f2f258da13df0560187b3f1dfc9b8688c46b9d90176360ae5212c3fc \
--hash=sha256:26b5927b5880b396231ab6190ee5c8fb47ed3f459b53504ed5419faaf16d3bfb \
--hash=sha256:294f08b014f08dfd3c9b72408f5e1a0fd187bd86d7a85ead651e32dbd47aa038 \
--hash=sha256:2aa80ca8d17266507bef853cecefa7d632ffd087883ee7ca92b8a7ea14a1e581 \
--hash=sha256:2d55009eeddbef54c711093c986daaf361d2c4210aaa1ee905075a3b97a62441 \
--hash=sha256:310c95a68a9b948b89d6d187622757d57b6c26cece3c3f7c2cbb645ee36531b2 \
--hash=sha256:32b3e12d9441508f9c4e1424f4478b1a518a90a087cd54be3754e74954934194 \
--hash=sha256:356b4266e5cde7b5bbcf232f549dedf7fbed4983daa556042bdec397780e044d \
--hash=sha256:385c7b5cfffac115f413b8e32c941c85ea0960e0b94a6ef43bb260f774c54893 \
--hash=sha256:3c1e38b1eda54910628f68448598139a9818973755abf77950057372c1fe89a6 \
--hash=sha256:3e9c9e64fb7cda688e9488402611c0be2c81083664117edcc709d15f37faa30f \
--hash=sha256:442f20153415f374ae5753ca618637611a41a3c58c56d16ce55f845d76a3cf7b \
--hash=sha256:489b154891f1c995355adeb1077ee3479e9c9bada721b93270c20243bbad6542 \
--hash=sha256:48a8e29f3e38fcf8d393b8fe460d83e39c107ad7e5e61cd3858a7569e0554a39 \
--hash=sha256:49582c3b6d578bdaab2932b59f70b1bd93351ed4d594b2c97cea1611633c9de1 \
--hash=sha256:58ed30d33c25d7dc8d2f06285e88493147c2a660cc94713e4b563a99efb80a1f \
--hash=sha256:5b6e505618cb376a7a7d6af86833a8f289833fe4cc97541d7100745081dc31bd \
--hash=sha256:66a031f22e4418016990446d3e38143826f03ad811b9f78f58e2afbc1d343f7a \
--hash=sha256:6a898717ab560db393355c6ecf39b8c534f252afc3131480db1251e061090d3a \
--hash=sha256:7130effd0517881f3a852eff98729d51034128f0737f64f0d1c7ea8343d77bd7 \
--hash=sha256:72fd979e410ba7805462817ef8ed6f37dd75f9f4ae109bdb8503e013ccecb80b \
--hash=sha256:77690f0bf08356ca00fc357f50a5980c7a25f076c2c1f37d9d775a278234fefd \
--hash=sha256:79de3cc5adbf51677009a8fda35ac9e9e3686d5595ab4b0c43ec7099ece6aeb5 \
--hash=sha256:7b9a99ded7d19b24d3b6fa632b58e52bbdecde7e1f866c3b23d0c27b092af4e3 \
--hash=sha256:802bd01fb18a0acb0dea491f69a9a2da6034f33329a62876ab5b558a1fb66b45 \
--hash=sha256:8335d989a4e94df2ccd8a1acbba9d03c4157ea8d73b65b79d447c6dc10b001d8 \
--hash=sha256:89b3c5201ca616d69ca0c3c0003ca18f7170a679c445c7e386ebfb4f29aa738e \
--hash=sha256:8ffe75fe6be902dadd439adf4228c98138a992088e073ede6dd34e7235f4e03e \
--hash=sha256:909de94de7dd4d6086098a5755562207114c9638ec42c52d84c8a440c45fe084 \
--hash=sha256:940ac69ef6e89c17b3d30f3297a2ad03efdd06a4b1857f81bc533a9108a90eb9 \
--hash=sha256:95f2806097a49bfd57e0c6a178f77b99487c53c157d9d507aee9c40dd58efdb4 \
--hash=sha256:9c674887d1e0d4384c06c822bc7fcfede4952742e232ec1e76b5a6ae39a3ddd4 \
--hash=sha256:9fdf3a0c24822401c60c93640da69b3dfd4d9f29c3a8d797244fe22bfe592823 \
--hash=sha256:ab02b7d138768fd6ac4230e45b073f7b9fd688d88c04f24c34df4a250a94d066 \
--hash=sha256:acb1811219a4144539f0baee224a11a2aa323a739c349799cf52f191eb87bc52 \
--hash=sha256:bfd632f7038c76b0921f6d5621f5ba9ecabfad3042fa40e5875db11771d2a5de \
--hash=sha256:ce68839da386f137bc8d814fdbeede8f89916b8605e3593a85b504a859243af9 \
--hash=sha256:d369e79ad9647fc8217cbb51bbbf11f9a1ffca450be31d005340157ffe8e91b3 \
--hash=sha256:dc68094e00a5a7e8c20de1d3a0d5e404a27f522e18f8eb62bbbc9f865c3c81ef \
--hash=sha256:deeb06b7141f3a577c3aa8562307e2747580ae43d705a0482603a2c1f110d046 \
--hash=sha256:e0b5ccd03ca4749b8f66f38608ccbcb415cbd130d02de5eda80d042b83bee90e \
--hash=sha256:ea049c8d33c4f4e6b030d5a68123c0ccd2ffb77d4035f073db97187b49b6422f \
--hash=sha256:ea9751310b840186379c949ede5a5129b31439acdb929f3003a8685372117ed8 \
--hash=sha256:ec82fa5134517af44e28a30c38f34384773a0422ffd545fd298433ea9f2cc5a9 \
--hash=sha256:eedc410f82007038030650aa58f620f9fe0009b9d6b04c3dc71cbd3bae5b2675 \
--hash=sha256:ef40601b959cc1440deaf4d53472ab54fa51036c37189cf3fe5500559ac25347 \
--hash=sha256:ef92d5ba6213de060d1390b1f71f5c3b2fbb00b4d55edee39f3b07234538b64a \
--hash=sha256:efab679a2c7d1bf7d0ec0e1ecb47fe764945eff75bb4321f2e699b30a12db9b3 \
--hash=sha256:f33c9e12ed05e579b7fb3c8fdb10a165f41459394b8eb113e7c377b2bd027f61 \
--hash=sha256:f3bae4be7f6781bf6c9576eedcd5e1bb74468126fa6de991e47cdb1a8ea3a42a \
--hash=sha256:f6ba1fe35fd215813dac4544a5ffc90f13713b29dd26e9e5be97ba53482bf6d6 \
--hash=sha256:f7c81bc60560be9eb3c23601237765069ebfa9881097ce19ca6b5ea17c5faa8f \
--hash=sha256:f8107968a9eadb451cfa6cf86036006fdde32a83cd39c26c9ca46765e653b547 \
--hash=sha256:f821e0c8a8fdfddfa71acb4f462d7a4c5aae1655f3f5e078970dbe9f19027386
psycopg-binary==3.2.3 \
--hash=sha256:0463a11b1cace5a6aeffaf167920707b912b8986a9c7920341c75e3686277920 \
--hash=sha256:05a1bdce30356e70a05428928717765f4a9229999421013f41338d9680d03a63 \
--hash=sha256:06b5cc915e57621eebf2393f4173793ed7e3387295f07fed93ed3fb6a6ccf585 \
--hash=sha256:07d019a786eb020c0f984691aa1b994cb79430061065a694cf6f94056c603d26 \
--hash=sha256:09baa041856b35598d335b1a74e19a49da8500acedf78164600694c0ba8ce21b \
--hash=sha256:1303bf8347d6be7ad26d1362af2c38b3a90b8293e8d56244296488ee8591058e \
--hash=sha256:192a5f8496e6e1243fdd9ac20e117e667c0712f148c5f9343483b84435854c78 \
--hash=sha256:1985ab05e9abebfbdf3163a16ebb37fbc5d49aff2bf5b3d7375ff0920bbb54cd \
--hash=sha256:1f8b0d0e99d8e19923e6e07379fa00570be5182c201a8c0b5aaa9a4d4a4ea20b \
--hash=sha256:257c4aea6f70a9aef39b2a77d0658a41bf05c243e2bf41895eb02220ac6306f3 \
--hash=sha256:261f0031ee6074765096a19b27ed0f75498a8338c3dcd7f4f0d831e38adf12d1 \
--hash=sha256:2773f850a778575dd7158a6dd072f7925b67f3ba305e2003538e8831fec77a1d \
--hash=sha256:2a29f5294b0b6360bfda69653697eff70aaf2908f58d1073b0acd6f6ab5b5a4f \
--hash=sha256:2bb342a01c76f38a12432848e6013c57eb630103e7556cf79b705b53814c3949 \
--hash=sha256:2c0419cdad8c70eaeb3116bb28e7b42d546f91baf5179d7556f230d40942dc78 \
--hash=sha256:3bffb61e198a91f712cc3d7f2d176a697cb05b284b2ad150fb8edb308eba9002 \
--hash=sha256:41fdec0182efac66b27478ac15ef54c9ebcecf0e26ed467eb7d6f262a913318b \
--hash=sha256:48f8ca6ee8939bab760225b2ab82934d54330eec10afe4394a92d3f2a0c37dd6 \
--hash=sha256:4926ea5c46da30bec4a85907aa3f7e4ea6313145b2aa9469fdb861798daf1502 \
--hash=sha256:4c57615791a337378fe5381143259a6c432cdcbb1d3e6428bfb7ce59fff3fb5c \
--hash=sha256:4e76ce2475ed4885fe13b8254058be710ec0de74ebd8ef8224cf44a9a3358e5f \
--hash=sha256:5361ea13c241d4f0ec3f95e0bf976c15e2e451e9cc7ef2e5ccfc9d170b197a40 \
--hash=sha256:5905729668ef1418bd36fbe876322dcb0f90b46811bba96d505af89e6fbdce2f \
--hash=sha256:5938b257b04c851c2d1e6cb2f8c18318f06017f35be9a5fe761ee1e2e344dfb7 \
--hash=sha256:5e37d5027e297a627da3551a1e962316d0f88ee4ada74c768f6c9234e26346d9 \
--hash=sha256:64a607e630d9f4b2797f641884e52b9f8e239d35943f51bef817a384ec1678fe \
--hash=sha256:64dc6e9ec64f592f19dc01a784e87267a64a743d34f68488924251253da3c818 \
--hash=sha256:69320f05de8cdf4077ecd7fefdec223890eea232af0d58f2530cbda2871244a0 \
--hash=sha256:6d8f2144e0d5808c2e2aed40fbebe13869cd00c2ae745aca4b3b16a435edb056 \
--hash=sha256:700679c02f9348a0d0a2adcd33a0275717cd0d0aee9d4482b47d935023629505 \
--hash=sha256:709447bd7203b0b2debab1acec23123eb80b386f6c29e7604a5d4326a11e5bd6 \
--hash=sha256:71adcc8bc80a65b776510bc39992edf942ace35b153ed7a9c6c573a6849ce308 \
--hash=sha256:71db8896b942770ed7ab4efa59b22eee5203be2dfdee3c5258d60e57605d688c \
--hash=sha256:74fbf5dd3ef09beafd3557631e282f00f8af4e7a78fbfce8ab06d9cd5a789aae \
--hash=sha256:79498df398970abcee3d326edd1d4655de7d77aa9aecd578154f8af35ce7bbd2 \
--hash=sha256:7ad357e426b0ea5c3043b8ec905546fa44b734bf11d33b3da3959f6e4447d350 \
--hash=sha256:7d784f614e4d53050cbe8abf2ae9d1aaacf8ed31ce57b42ce3bf2a48a66c3a5c \
--hash=sha256:80a2337e2dfb26950894c8301358961430a0304f7bfe729d34cc036474e9c9b1 \
--hash=sha256:824c867a38521d61d62b60aca7db7ca013a2b479e428a0db47d25d8ca5067410 \
--hash=sha256:842da42a63ecb32612bb7f5b9e9f8617eab9bc23bd58679a441f4150fcc51c96 \
--hash=sha256:8b7be9a6c06518967b641fb15032b1ed682fd3b0443f64078899c61034a0bca6 \
--hash=sha256:9099e443d4cc24ac6872e6a05f93205ba1a231b1a8917317b07c9ef2b955f1f4 \
--hash=sha256:94253be2b57ef2fea7ffe08996067aabf56a1eb9648342c9e3bad9e10c46e045 \
--hash=sha256:949551752930d5e478817e0b49956350d866b26578ced0042a61967e3fcccdea \
--hash=sha256:96334bb64d054e36fed346c50c4190bad9d7c586376204f50bede21a913bf942 \
--hash=sha256:965455eac8547f32b3181d5ec9ad8b9be500c10fe06193543efaaebe3e4ce70c \
--hash=sha256:967b47a0fd237aa17c2748fdb7425015c394a6fb57cdad1562e46a6eb070f96d \
--hash=sha256:9994f7db390c17fc2bd4c09dca722fd792ff8a49bb3bdace0c50a83f22f1767d \
--hash=sha256:9b60b465773a52c7d4705b0a751f7f1cdccf81dd12aee3b921b31a6e76b07b0e \
--hash=sha256:aeddf7b3b3f6e24ccf7d0edfe2d94094ea76b40e831c16eff5230e040ce3b76b \
--hash=sha256:c64c4cd0d50d5b2288ab1bcb26c7126c772bbdebdfadcd77225a77df01c4a57e \
--hash=sha256:cb987f14af7da7c24f803111dbc7392f5070fd350146af3345103f76ea82e339 \
--hash=sha256:dc4fa2240c9fceddaa815a58f29212826fafe43ce80ff666d38c4a03fb036955 \
--hash=sha256:e56b1fd529e5dde2d1452a7d72907b37ed1b4f07fdced5d8fb1e963acfff6749 \
--hash=sha256:e8630943143c6d6ca9aefc88bbe5e76c90553f4e1a3b2dc339e67dc34aa86f7e \
--hash=sha256:e8eb9a4e394926b93ad919cad1b0a918e9b4c846609e8c1cfb6b743683f64da0 \
--hash=sha256:e90352d7b610b4693fad0feea48549d4315d10f1eba5605421c92bb834e90170 \
--hash=sha256:f0b018e37608c3bfc6039a1dc4eb461e89334465a19916be0153c757a78ea426 \
--hash=sha256:f73adc05452fb85e7a12ed3f69c81540a8875960739082e6ea5e28c373a30774 \
--hash=sha256:fa33ead69ed133210d96af0c63448b1385df48b9c0247eda735c5896b9e6dbbf \
--hash=sha256:fc6d87a1c44df8d493ef44988a3ded751e284e02cdf785f746c2d357e99782a6 \
--hash=sha256:fd40af959173ea0d087b6b232b855cfeaa6738f47cb2a0fd10a7f4fa8b74293f \
--hash=sha256:fd65774ed7d65101b314808b6893e1a75b7664f680c3ef18d2e5c84d570fa393 \
--hash=sha256:fda0162b0dbfa5eaed6cdc708179fa27e148cb8490c7d62e5cf30713909658ea
# via psycopg
psycopg-pool==3.2.7 \
--hash=sha256:4b47bb59d887ef5da522eb63746b9f70e2faf967d34aac4f56ffc65e9606728f \
--hash=sha256:a77d531bfca238e49e5fb5832d65b98e69f2c62bfda3d2d4d833696bdc9ca54b
psycopg-pool==3.2.4 \
--hash=sha256:61774b5bbf23e8d22bedc7504707135aaf744679f8ef9b3fe29942920746a6ed \
--hash=sha256:f6a22cff0f21f06d72fb2f5cb48c618946777c49385358e0c88d062c59cbd224
# via psycopg
pyasn1==0.6.1 \
--hash=sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629 \
@@ -131,124 +131,103 @@ pyasn1==0.6.1 \
# via
# pyasn1-modules
# python-ldap
pyasn1-modules==0.4.2 \
--hash=sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a \
--hash=sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6
pyasn1-modules==0.4.1 \
--hash=sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd \
--hash=sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c
# via python-ldap
python-ldap==3.4.5 \
--hash=sha256:b2f6ef1c37fe2c6a5a85212efe71311ee21847766a7d45fcb711f3b270a5f79a
python-ldap==3.4.4 \
--hash=sha256:7edb0accec4e037797705f3a05cbf36a9fde50d08c8f67f2aef99a2628fab828
# via
# -r contrib/container/requirements.in
# django-auth-ldap
pyyaml==6.0.3 \
--hash=sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c \
--hash=sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a \
--hash=sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3 \
--hash=sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956 \
--hash=sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6 \
--hash=sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c \
--hash=sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65 \
--hash=sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a \
--hash=sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0 \
--hash=sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b \
--hash=sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1 \
--hash=sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6 \
--hash=sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7 \
--hash=sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e \
--hash=sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007 \
--hash=sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310 \
--hash=sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4 \
--hash=sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9 \
--hash=sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295 \
--hash=sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea \
--hash=sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0 \
--hash=sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e \
--hash=sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac \
--hash=sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9 \
--hash=sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7 \
--hash=sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35 \
--hash=sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb \
--hash=sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b \
--hash=sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69 \
--hash=sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5 \
--hash=sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b \
--hash=sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c \
--hash=sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369 \
--hash=sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd \
--hash=sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824 \
--hash=sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198 \
--hash=sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065 \
--hash=sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c \
--hash=sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c \
--hash=sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764 \
--hash=sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196 \
--hash=sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b \
--hash=sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00 \
--hash=sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac \
--hash=sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8 \
--hash=sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e \
--hash=sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28 \
--hash=sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3 \
--hash=sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5 \
--hash=sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4 \
--hash=sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b \
--hash=sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf \
--hash=sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5 \
--hash=sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702 \
--hash=sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8 \
--hash=sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788 \
--hash=sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da \
--hash=sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d \
--hash=sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc \
--hash=sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c \
--hash=sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba \
--hash=sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f \
--hash=sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917 \
--hash=sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5 \
--hash=sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26 \
--hash=sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f \
--hash=sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b \
--hash=sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be \
--hash=sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c \
--hash=sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3 \
--hash=sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6 \
--hash=sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926 \
--hash=sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0
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==80.9.0 \
--hash=sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922 \
--hash=sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c
setuptools==75.6.0 \
--hash=sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6 \
--hash=sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d
# via -r contrib/container/requirements.in
sqlparse==0.5.3 \
--hash=sha256:09f67787f56a0b16ecdbde1bfc7f5d9c3371ca683cfeaa8e6ff60b4807ec9272 \
--hash=sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca
# via django
typing-extensions==4.15.0 \
--hash=sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466 \
--hash=sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548
typing-extensions==4.12.2 \
--hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \
--hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8
# via
# psycopg
# psycopg-pool
uv==0.9.8 \
--hash=sha256:0f03bc413c933dbf850ad0dc2dba3df6b80c860a5c65cd767add49da19dadef0 \
--hash=sha256:14670bf55ecb5cfd0f3654fbf51c58a21dec3ad8ab531079b3ed8599271dc77b \
--hash=sha256:1b8b5bdcda3e10ea70b618d0609acddc5c725cb58d4caf933030ddedd7c2e98f \
--hash=sha256:40253d00c1e900a0a61b132b1e0dd4aa83575cfd5302d3671899b6de29b1ef67 \
--hash=sha256:50d130c46d97d7f10675ebea8608b7b4722c84b5745cd1bb0c8ae6d7984c05d5 \
--hash=sha256:543693def38fa41b9706aba391111fe8d9dd6be86899d76f9581faf045ac1cb6 \
--hash=sha256:5af28f1645eb3c50fd34a78508792db2d0799816f4eb5f55e1e6e2c724dfb125 \
--hash=sha256:6a01d7cd41953ffac583139b10ad1df004a67c0246a6b694eb5bcdbc8c99deaf \
--hash=sha256:6df2e16f6df32018047c60bab2c0284868ad5c309addba9183ea2eeb71746bf0 \
--hash=sha256:7038a552159f2291dd0d1f4f66a36261b5f3ed5fcd92e2869186f8e910b2c935 \
--hash=sha256:75671150d6eb9d5ee829e1fdb8cf86b8e44a66d27cbb996fe807e986c4107b5d \
--hash=sha256:87c3b65b6d5fcbdeab199d54c74fbf75de19cb534a690c936c5616478a038576 \
--hash=sha256:99b18bfe92c33c3862b65d74677697e799763e669e0064685f405e7e27517f25 \
--hash=sha256:9f2f3576c4518ff4f15e48dbca70585a513523c4738bc8cc2e48b20fd1190ce3 \
--hash=sha256:a4010b3fdabbb3c4f2cf2f7aa3bf6002d00049dcbc54ce0ee5ada32a933b2290 \
--hash=sha256:bb0f8e83c2a2fc5a802e930cc8a7b71ab068180300a3f27ba38037f9fcb3d430 \
--hash=sha256:cdbfadca9522422ab9820f5ada071c9c5c869bcd6fee719d20d91d5ec85b2a7d \
--hash=sha256:d93a2227d23e81ab3a16c30363559afc483e8aca40ea9343b3f326a9a41718c9 \
--hash=sha256:f52c6a99197028a314d4c1825f7ccb696eb9a88b822d2e2f17046266c75e543e
uv==0.5.7 \
--hash=sha256:071b57c934bdee8d7502a70e9ea0739a10e9b2d1d0c67e923a09e7a23d9a181b \
--hash=sha256:13961a8116515eb288c4f91849fba11ebda0dfeec44cc356e388b3b03b2dbbe1 \
--hash=sha256:1c5b89c64fb627f52f1e9c9bbc4dcc7bae29c4c5ab8eff46da3c966bbd4caed2 \
--hash=sha256:27c630780e1856a70fbeb267e1ed6835268a1b50963ab9a984fafa4184389def \
--hash=sha256:46b03a9a78438219fb3060c096773284e2f22417a9c1f8fdd602f0650b3355c2 \
--hash=sha256:4d22a5046a6246af85c92257d110ed8fbcd98b16824e4efa9d825d001222b2cb \
--hash=sha256:737a06b15c4e6b8ab7dd0a577ba766380bda4c18ba4ecfcfff37d336f1b03a00 \
--hash=sha256:747c011da9f631354a1c89b62b19b8572e040d3fe01c6fb8d650facc7a09fdbb \
--hash=sha256:76b514c79136e779cccf90cce5d60f317a0d42074e9f4c059f198ef435f2f6ab \
--hash=sha256:78c3c040e52c09a410b9788656d6e760d557f223058537081cb03a3e25ce89de \
--hash=sha256:a141b40444c4184efba9fdc10abb3c1cff32154c7f8b0ad46ddc180d65a82d90 \
--hash=sha256:a45648db157d2aaff859fe71ec738efea09b972b8864feb2fd61ef856a15b24f \
--hash=sha256:a4fc62749bda8e7ae62212b1d85cdf6c7bad41918b3c8ac5a6d730dd093d793d \
--hash=sha256:b79e32438390add793bebc41b0729054e375be30bc53f124ee212d9c97affc39 \
--hash=sha256:ba25eb99891b95b5200d5e369b788d443fae370b097e7268a71e9ba753f2af3f \
--hash=sha256:c1e7b5bcc8b380e333e948c01f6f4c6203067b5de60a05f8ed786332af7a9132 \
--hash=sha256:d0600d2b2fbd9a9446bfbb7f03d88bc3d0293b949ce40e326429dd4fe246c926 \
--hash=sha256:fb4a3ccbe13072b98919413ac8378dd3e2b5480352f75c349a4f71f423801485
# via -r contrib/container/requirements.in
wheel==0.45.1 \
--hash=sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729 \

View File

@@ -23,7 +23,7 @@ port = 127.0.0.1:9001
; InvenTree Web Server Process
[program:inventree-server]
user=inventree
directory=/home/inventree/src/src/backend/InvenTree
directory=/home/inventree/src/InvenTree
command=/home/inventree/env/bin/gunicorn -c gunicorn.conf.py InvenTree.wsgi
startsecs=10
autostart=true
@@ -36,7 +36,7 @@ stdout_logfile=/home/inventree/log/server.out.log
; InvenTree Background Worker Process
[program:inventree-cluster]
user=inventree
directory=/home/inventree/src/src/backend/InvenTree
directory=/home/inventree/src/InvenTree
command=/home/inventree/env/bin/python manage.py qcluster
startsecs=10
autostart=true

View File

@@ -1,4 +1,4 @@
# Packages needed for CI/packages
requests==2.32.5
pyyaml==6.0.3
jc==1.25.6
requests==2.32.3
pyyaml==6.0.2
jc==1.25.4

View File

@@ -1,287 +1,239 @@
# 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 -b src/backend/requirements.txt
certifi==2025.10.5 \
--hash=sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de \
--hash=sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43
# uv pip compile contrib/dev_reqs/requirements.in -o contrib/dev_reqs/requirements.txt --no-strip-extras --generate-hashes
certifi==2024.8.30 \
--hash=sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 \
--hash=sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9
# via requests
charset-normalizer==3.4.4 \
--hash=sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad \
--hash=sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93 \
--hash=sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394 \
--hash=sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89 \
--hash=sha256:0f04b14ffe5fdc8c4933862d8306109a2c51e0704acfa35d51598eb45a1e89fc \
--hash=sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86 \
--hash=sha256:194f08cbb32dc406d6e1aea671a68be0823673db2832b38405deba2fb0d88f63 \
--hash=sha256:1bee1e43c28aa63cb16e5c14e582580546b08e535299b8b6158a7c9c768a1f3d \
--hash=sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f \
--hash=sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8 \
--hash=sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0 \
--hash=sha256:2677acec1a2f8ef614c6888b5b4ae4060cc184174a938ed4e8ef690e15d3e505 \
--hash=sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161 \
--hash=sha256:2aaba3b0819274cc41757a1da876f810a3e4d7b6eb25699253a4effef9e8e4af \
--hash=sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152 \
--hash=sha256:2c9d3c380143a1fedbff95a312aa798578371eb29da42106a29019368a475318 \
--hash=sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72 \
--hash=sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4 \
--hash=sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e \
--hash=sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3 \
--hash=sha256:44c2a8734b333e0578090c4cd6b16f275e07aa6614ca8715e6c038e865e70576 \
--hash=sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c \
--hash=sha256:4902828217069c3c5c71094537a8e623f5d097858ac6ca8252f7b4d10b7560f1 \
--hash=sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8 \
--hash=sha256:4fe7859a4e3e8457458e2ff592f15ccb02f3da787fcd31e0183879c3ad4692a1 \
--hash=sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2 \
--hash=sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44 \
--hash=sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26 \
--hash=sha256:5947809c8a2417be3267efc979c47d76a079758166f7d43ef5ae8e9f92751f88 \
--hash=sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016 \
--hash=sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede \
--hash=sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf \
--hash=sha256:5cb4d72eea50c8868f5288b7f7f33ed276118325c1dfd3957089f6b519e1382a \
--hash=sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc \
--hash=sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0 \
--hash=sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84 \
--hash=sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db \
--hash=sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1 \
--hash=sha256:6aee717dcfead04c6eb1ce3bd29ac1e22663cdea57f943c87d1eab9a025438d7 \
--hash=sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed \
--hash=sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8 \
--hash=sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133 \
--hash=sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e \
--hash=sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef \
--hash=sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14 \
--hash=sha256:778d2e08eda00f4256d7f672ca9fef386071c9202f5e4607920b86d7803387f2 \
--hash=sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0 \
--hash=sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d \
--hash=sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828 \
--hash=sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f \
--hash=sha256:7c308f7e26e4363d79df40ca5b2be1c6ba9f02bdbccfed5abddb7859a6ce72cf \
--hash=sha256:7fa17817dc5625de8a027cb8b26d9fefa3ea28c8253929b8d6649e705d2835b6 \
--hash=sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328 \
--hash=sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090 \
--hash=sha256:837c2ce8c5a65a2035be9b3569c684358dfbf109fd3b6969630a87535495ceaa \
--hash=sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381 \
--hash=sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c \
--hash=sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb \
--hash=sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc \
--hash=sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a \
--hash=sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec \
--hash=sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc \
--hash=sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac \
--hash=sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e \
--hash=sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313 \
--hash=sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569 \
--hash=sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3 \
--hash=sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d \
--hash=sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525 \
--hash=sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894 \
--hash=sha256:a8bf8d0f749c5757af2142fe7903a9df1d2e8aa3841559b2bad34b08d0e2bcf3 \
--hash=sha256:a9768c477b9d7bd54bc0c86dbaebdec6f03306675526c9927c0e8a04e8f94af9 \
--hash=sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a \
--hash=sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9 \
--hash=sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14 \
--hash=sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25 \
--hash=sha256:b5d84d37db046c5ca74ee7bb47dd6cbc13f80665fdde3e8040bdd3fb015ecb50 \
--hash=sha256:b7cf1017d601aa35e6bb650b6ad28652c9cd78ee6caff19f3c28d03e1c80acbf \
--hash=sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1 \
--hash=sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3 \
--hash=sha256:c4ef880e27901b6cc782f1b95f82da9313c0eb95c3af699103088fa0ac3ce9ac \
--hash=sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e \
--hash=sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815 \
--hash=sha256:cb01158d8b88ee68f15949894ccc6712278243d95f344770fa7593fa2d94410c \
--hash=sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6 \
--hash=sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6 \
--hash=sha256:cd09d08005f958f370f539f186d10aec3377d55b9eeb0d796025d4886119d76e \
--hash=sha256:cd4b7ca9984e5e7985c12bc60a6f173f3c958eae74f3ef6624bb6b26e2abbae4 \
--hash=sha256:ce8a0633f41a967713a59c4139d29110c07e826d131a316b50ce11b1d79b4f84 \
--hash=sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69 \
--hash=sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15 \
--hash=sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191 \
--hash=sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0 \
--hash=sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897 \
--hash=sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd \
--hash=sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2 \
--hash=sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794 \
--hash=sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d \
--hash=sha256:e912091979546adf63357d7e2ccff9b44f026c075aeaf25a52d0e95ad2281074 \
--hash=sha256:eaabd426fe94daf8fd157c32e571c85cb12e66692f15516a83a03264b08d06c3 \
--hash=sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224 \
--hash=sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838 \
--hash=sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a \
--hash=sha256:f155a433c2ec037d4e8df17d18922c3a0d9b3232a396690f17175d2946f0218d \
--hash=sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d \
--hash=sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f \
--hash=sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8 \
--hash=sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490 \
--hash=sha256:f8e160feb2aed042cd657a72acc0b481212ed28b1b9a95c0cee1621b524e1966 \
--hash=sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9 \
--hash=sha256:fa09f53c465e532f4d3db095e0c55b615f010ad81803d383195b6b5ca6cbf5f3 \
--hash=sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e \
--hash=sha256:fd44c878ea55ba351104cb93cc85e74916eb8fa440ca7903e57575e97394f608
charset-normalizer==3.4.0 \
--hash=sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621 \
--hash=sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6 \
--hash=sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8 \
--hash=sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912 \
--hash=sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c \
--hash=sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b \
--hash=sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d \
--hash=sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d \
--hash=sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95 \
--hash=sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e \
--hash=sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565 \
--hash=sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64 \
--hash=sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab \
--hash=sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be \
--hash=sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e \
--hash=sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907 \
--hash=sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0 \
--hash=sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2 \
--hash=sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62 \
--hash=sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62 \
--hash=sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23 \
--hash=sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc \
--hash=sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284 \
--hash=sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca \
--hash=sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455 \
--hash=sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858 \
--hash=sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b \
--hash=sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594 \
--hash=sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc \
--hash=sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db \
--hash=sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b \
--hash=sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea \
--hash=sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6 \
--hash=sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920 \
--hash=sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749 \
--hash=sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7 \
--hash=sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd \
--hash=sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99 \
--hash=sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242 \
--hash=sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee \
--hash=sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129 \
--hash=sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2 \
--hash=sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51 \
--hash=sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee \
--hash=sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8 \
--hash=sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b \
--hash=sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613 \
--hash=sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742 \
--hash=sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe \
--hash=sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3 \
--hash=sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5 \
--hash=sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631 \
--hash=sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7 \
--hash=sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15 \
--hash=sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c \
--hash=sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea \
--hash=sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417 \
--hash=sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250 \
--hash=sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88 \
--hash=sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca \
--hash=sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa \
--hash=sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99 \
--hash=sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149 \
--hash=sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41 \
--hash=sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574 \
--hash=sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0 \
--hash=sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f \
--hash=sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d \
--hash=sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654 \
--hash=sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3 \
--hash=sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19 \
--hash=sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90 \
--hash=sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578 \
--hash=sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9 \
--hash=sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1 \
--hash=sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51 \
--hash=sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719 \
--hash=sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236 \
--hash=sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a \
--hash=sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c \
--hash=sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade \
--hash=sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944 \
--hash=sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc \
--hash=sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6 \
--hash=sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6 \
--hash=sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27 \
--hash=sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6 \
--hash=sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2 \
--hash=sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12 \
--hash=sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf \
--hash=sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114 \
--hash=sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7 \
--hash=sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf \
--hash=sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d \
--hash=sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b \
--hash=sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed \
--hash=sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03 \
--hash=sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4 \
--hash=sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67 \
--hash=sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365 \
--hash=sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a \
--hash=sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748 \
--hash=sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b \
--hash=sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079 \
--hash=sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482
# via requests
idna==3.11 \
--hash=sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea \
--hash=sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902
idna==3.10 \
--hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \
--hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3
# via requests
jc==1.25.6 \
--hash=sha256:27f58befc7ae0a4c63322926c5f1ec892e3eac4a065eff3b07cfe420a6924a07 \
--hash=sha256:7367b59e6e0da8babeede1e5b0da083f3c5aa6b6e585b4aed28dd7c4b2d76162
jc==1.25.4 \
--hash=sha256:1e4f45d2e5b72cf9d300b0d9df0578c0d3b553843e3ad37a525d93bb0e94aca1 \
--hash=sha256:a32eaf029c56b582dadae48895f20784d0f84f2fa28a8e2b32f377a8bffa8b39
# via -r contrib/dev_reqs/requirements.in
pygments==2.19.2 \
--hash=sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887 \
--hash=sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b
pygments==2.18.0 \
--hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \
--hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a
# via jc
pyyaml==6.0.3 \
--hash=sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c \
--hash=sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a \
--hash=sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3 \
--hash=sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956 \
--hash=sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6 \
--hash=sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c \
--hash=sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65 \
--hash=sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a \
--hash=sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0 \
--hash=sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b \
--hash=sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1 \
--hash=sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6 \
--hash=sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7 \
--hash=sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e \
--hash=sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007 \
--hash=sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310 \
--hash=sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4 \
--hash=sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9 \
--hash=sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295 \
--hash=sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea \
--hash=sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0 \
--hash=sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e \
--hash=sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac \
--hash=sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9 \
--hash=sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7 \
--hash=sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35 \
--hash=sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb \
--hash=sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b \
--hash=sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69 \
--hash=sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5 \
--hash=sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b \
--hash=sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c \
--hash=sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369 \
--hash=sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd \
--hash=sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824 \
--hash=sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198 \
--hash=sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065 \
--hash=sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c \
--hash=sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c \
--hash=sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764 \
--hash=sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196 \
--hash=sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b \
--hash=sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00 \
--hash=sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac \
--hash=sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8 \
--hash=sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e \
--hash=sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28 \
--hash=sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3 \
--hash=sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5 \
--hash=sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4 \
--hash=sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b \
--hash=sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf \
--hash=sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5 \
--hash=sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702 \
--hash=sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8 \
--hash=sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788 \
--hash=sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da \
--hash=sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d \
--hash=sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc \
--hash=sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c \
--hash=sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba \
--hash=sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f \
--hash=sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917 \
--hash=sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5 \
--hash=sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26 \
--hash=sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f \
--hash=sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b \
--hash=sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be \
--hash=sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c \
--hash=sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3 \
--hash=sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6 \
--hash=sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926 \
--hash=sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0
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.5 \
--hash=sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6 \
--hash=sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf
requests==2.32.3 \
--hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
--hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
# via -r contrib/dev_reqs/requirements.in
ruamel-yaml==0.18.15 \
--hash=sha256:148f6488d698b7a5eded5ea793a025308b25eca97208181b6a026037f391f701 \
--hash=sha256:dbfca74b018c4c3fba0b9cc9ee33e53c371194a9000e694995e620490fd40700
ruamel-yaml==0.18.6 \
--hash=sha256:57b53ba33def16c4f3d807c0ccbc00f8a6081827e81ba2491691b76882d0c636 \
--hash=sha256:8b27e6a217e786c6fbe5634d8f3f11bc63e0f80f6a5890f28863d9c45aac311b
# via jc
ruamel-yaml-clib==0.2.15 \
--hash=sha256:014181cdec565c8745b7cbc4de3bf2cc8ced05183d986e6d1200168e5bb59490 \
--hash=sha256:04d21dc9c57d9608225da28285900762befbb0165ae48482c15d8d4989d4af14 \
--hash=sha256:05c70f7f86be6f7bee53794d80050a28ae7e13e4a0087c1839dcdefd68eb36b6 \
--hash=sha256:0ba6604bbc3dfcef844631932d06a1a4dcac3fee904efccf582261948431628a \
--hash=sha256:11e5499db1ccbc7f4b41f0565e4f799d863ea720e01d3e99fa0b7b5fcd7802c9 \
--hash=sha256:1b45498cc81a4724a2d42273d6cfc243c0547ad7c6b87b4f774cb7bcc131c98d \
--hash=sha256:1bb7b728fd9f405aa00b4a0b17ba3f3b810d0ccc5f77f7373162e9b5f0ff75d5 \
--hash=sha256:1f66f600833af58bea694d5892453f2270695b92200280ee8c625ec5a477eed3 \
--hash=sha256:27dc656e84396e6d687f97c6e65fb284d100483628f02d95464fd731743a4afe \
--hash=sha256:2812ff359ec1f30129b62372e5f22a52936fac13d5d21e70373dbca5d64bb97c \
--hash=sha256:2b216904750889133d9222b7b873c199d48ecbb12912aca78970f84a5aa1a4bc \
--hash=sha256:331fb180858dd8534f0e61aa243b944f25e73a4dae9962bd44c46d1761126bbf \
--hash=sha256:3cb75a3c14f1d6c3c2a94631e362802f70e83e20d1f2b2ef3026c05b415c4900 \
--hash=sha256:3eb199178b08956e5be6288ee0b05b2fb0b5c1f309725ad25d9c6ea7e27f962a \
--hash=sha256:424ead8cef3939d690c4b5c85ef5b52155a231ff8b252961b6516ed7cf05f6aa \
--hash=sha256:45702dfbea1420ba3450bb3dd9a80b33f0badd57539c6aac09f42584303e0db6 \
--hash=sha256:468858e5cbde0198337e6a2a78eda8c3fb148bdf4c6498eaf4bc9ba3f8e780bd \
--hash=sha256:46895c17ead5e22bea5e576f1db7e41cb273e8d062c04a6a49013d9f60996c25 \
--hash=sha256:46e4cc8c43ef6a94885f72512094e482114a8a706d3c555a34ed4b0d20200600 \
--hash=sha256:480894aee0b29752560a9de46c0e5f84a82602f2bc5c6cde8db9a345319acfdf \
--hash=sha256:4b293a37dc97e2b1e8a1aec62792d1e52027087c8eea4fc7b5abd2bdafdd6642 \
--hash=sha256:4be366220090d7c3424ac2b71c90d1044ea34fca8c0b88f250064fd06087e614 \
--hash=sha256:4d1032919280ebc04a80e4fb1e93f7a738129857eaec9448310e638c8bccefcf \
--hash=sha256:4d3b58ab2454b4747442ac76fab66739c72b1e2bb9bd173d7694b9f9dbc9c000 \
--hash=sha256:4dcec721fddbb62e60c2801ba08c87010bd6b700054a09998c4d09c08147b8fb \
--hash=sha256:512571ad41bba04eac7268fe33f7f4742210ca26a81fe0c75357fa682636c690 \
--hash=sha256:542d77b72786a35563f97069b9379ce762944e67055bea293480f7734b2c7e5e \
--hash=sha256:56ea19c157ed8c74b6be51b5fa1c3aff6e289a041575f0556f66e5fb848bb137 \
--hash=sha256:5d3c9210219cbc0f22706f19b154c9a798ff65a6beeafbf77fc9c057ec806f7d \
--hash=sha256:5fea0932358e18293407feb921d4f4457db837b67ec1837f87074667449f9401 \
--hash=sha256:617d35dc765715fa86f8c3ccdae1e4229055832c452d4ec20856136acc75053f \
--hash=sha256:64da03cbe93c1e91af133f5bec37fd24d0d4ba2418eaf970d7166b0a26a148a2 \
--hash=sha256:65f48245279f9bb301d1276f9679b82e4c080a1ae25e679f682ac62446fac471 \
--hash=sha256:6f1d38cbe622039d111b69e9ca945e7e3efebb30ba998867908773183357f3ed \
--hash=sha256:713cd68af9dfbe0bb588e144a61aad8dcc00ef92a82d2e87183ca662d242f524 \
--hash=sha256:71845d377c7a47afc6592aacfea738cc8a7e876d586dfba814501d8c53c1ba60 \
--hash=sha256:753faf20b3a5906faf1fc50e4ddb8c074cb9b251e00b14c18b28492f933ac8ef \
--hash=sha256:7e74ea87307303ba91073b63e67f2c667e93f05a8c63079ee5b7a5c8d0d7b043 \
--hash=sha256:88eea8baf72f0ccf232c22124d122a7f26e8a24110a0273d9bcddcb0f7e1fa03 \
--hash=sha256:923816815974425fbb1f1bf57e85eca6e14d8adc313c66db21c094927ad01815 \
--hash=sha256:9b6f7d74d094d1f3a4e157278da97752f16ee230080ae331fcc219056ca54f77 \
--hash=sha256:a8220fd4c6f98485e97aea65e1df76d4fed1678ede1fe1d0eed2957230d287c4 \
--hash=sha256:ab0df0648d86a7ecbd9c632e8f8d6b21bb21b5fc9d9e095c796cacf32a728d2d \
--hash=sha256:ac9b8d5fa4bb7fd2917ab5027f60d4234345fd366fe39aa711d5dca090aa1467 \
--hash=sha256:badd1d7283f3e5894779a6ea8944cc765138b96804496c91812b2829f70e18a7 \
--hash=sha256:bdc06ad71173b915167702f55d0f3f027fc61abd975bd308a0968c02db4a4c3e \
--hash=sha256:bf0846d629e160223805db9fe8cc7aec16aaa11a07310c50c8c7164efa440aec \
--hash=sha256:bfd309b316228acecfa30670c3887dcedf9b7a44ea39e2101e75d2654522acd4 \
--hash=sha256:c583229f336682b7212a43d2fa32c30e643d3076178fb9f7a6a14dde85a2d8bd \
--hash=sha256:cb15a2e2a90c8475df45c0949793af1ff413acfb0a716b8b94e488ea95ce7cff \
--hash=sha256:d290eda8f6ada19e1771b54e5706b8f9807e6bb08e873900d5ba114ced13e02c \
--hash=sha256:da3d6adadcf55a93c214d23941aef4abfd45652110aed6580e814152f385b862 \
--hash=sha256:dcc7f3162d3711fd5d52e2267e44636e3e566d1e5675a5f0b30e98f2c4af7974 \
--hash=sha256:def5663361f6771b18646620fca12968aae730132e104688766cf8a3b1d65922 \
--hash=sha256:e5e9f630c73a490b758bf14d859a39f375e6999aea5ddd2e2e9da89b9953486a \
--hash=sha256:e9fde97ecb7bb9c41261c2ce0da10323e9227555c674989f8d9eb7572fc2098d \
--hash=sha256:ef71831bd61fbdb7aa0399d5c4da06bea37107ab5c79ff884cc07f2450910262 \
--hash=sha256:f4421ab780c37210a07d138e56dd4b51f8642187cdfb433eb687fe8c11de0144 \
--hash=sha256:f6d3655e95a80325b84c4e14c080b2470fe4f33b6846f288379ce36154993fb1 \
--hash=sha256:fd4c928ddf6bce586285daa6d90680b9c291cfd045fc40aad34e445d57b1bf51 \
--hash=sha256:fe239bdfdae2302e93bd6e8264bd9b71290218fff7084a9db250b55caaccf43f
ruamel-yaml-clib==0.2.12 \
--hash=sha256:040ae85536960525ea62868b642bdb0c2cc6021c9f9d507810c0c604e66f5a7b \
--hash=sha256:0467c5965282c62203273b838ae77c0d29d7638c8a4e3a1c8bdd3602c10904e4 \
--hash=sha256:0b7e75b4965e1d4690e93021adfcecccbca7d61c7bddd8e22406ef2ff20d74ef \
--hash=sha256:11f891336688faf5156a36293a9c362bdc7c88f03a8a027c2c1d8e0bcde998e5 \
--hash=sha256:20b0f8dc160ba83b6dcc0e256846e1a02d044e13f7ea74a3d1d56ede4e48c632 \
--hash=sha256:22353049ba4181685023b25b5b51a574bce33e7f51c759371a7422dcae5402a6 \
--hash=sha256:32621c177bbf782ca5a18ba4d7af0f1082a3f6e517ac2a18b3974d4edf349680 \
--hash=sha256:3bc2a80e6420ca8b7d3590791e2dfc709c88ab9152c00eeb511c9875ce5778bf \
--hash=sha256:3eac5a91891ceb88138c113f9db04f3cebdae277f5d44eaa3651a4f573e6a5da \
--hash=sha256:4a6679521a58256a90b0d89e03992c15144c5f3858f40d7c18886023d7943db6 \
--hash=sha256:4c8c5d82f50bb53986a5e02d1b3092b03622c02c2eb78e29bec33fd9593bae1a \
--hash=sha256:5a0e060aace4c24dcaf71023bbd7d42674e3b230f7e7b97317baf1e953e5b519 \
--hash=sha256:6442cb36270b3afb1b4951f060eccca1ce49f3d087ca1ca4563a6eb479cb3de6 \
--hash=sha256:6c8fbb13ec503f99a91901ab46e0b07ae7941cd527393187039aec586fdfd36f \
--hash=sha256:749c16fcc4a2b09f28843cda5a193e0283e47454b63ec4b81eaa2242f50e4ccd \
--hash=sha256:7dd5adc8b930b12c8fc5b99e2d535a09889941aa0d0bd06f4749e9a9397c71d2 \
--hash=sha256:811ea1594b8a0fb466172c384267a4e5e367298af6b228931f273b111f17ef52 \
--hash=sha256:932205970b9f9991b34f55136be327501903f7c66830e9760a8ffb15b07f05cd \
--hash=sha256:943f32bc9dedb3abff9879edc134901df92cfce2c3d5c9348f172f62eb2d771d \
--hash=sha256:95c3829bb364fdb8e0332c9931ecf57d9be3519241323c5274bd82f709cebc0c \
--hash=sha256:96777d473c05ee3e5e3c3e999f5d23c6f4ec5b0c38c098b3a5229085f74236c6 \
--hash=sha256:a274fb2cb086c7a3dea4322ec27f4cb5cc4b6298adb583ab0e211a4682f241eb \
--hash=sha256:a606ef75a60ecf3d924613892cc603b154178ee25abb3055db5062da811fd969 \
--hash=sha256:ab007f2f5a87bd08ab1499bdf96f3d5c6ad4dcfa364884cb4549aa0154b13a28 \
--hash=sha256:bb43a269eb827806502c7c8efb7ae7e9e9d0573257a46e8e952f4d4caba4f31e \
--hash=sha256:bc5f1e1c28e966d61d2519f2a3d451ba989f9ea0f2307de7bc45baa526de9e45 \
--hash=sha256:bd0a08f0bab19093c54e18a14a10b4322e1eacc5217056f3c063bd2f59853ce4 \
--hash=sha256:beffaed67936fbbeffd10966a4eb53c402fafd3d6833770516bf7314bc6ffa12 \
--hash=sha256:bf165fef1f223beae7333275156ab2022cffe255dcc51c27f066b4370da81e31 \
--hash=sha256:cf12567a7b565cbf65d438dec6cfbe2917d3c1bdddfce84a9930b7d35ea59642 \
--hash=sha256:d84318609196d6bd6da0edfa25cedfbabd8dbde5140a0a23af29ad4b8f91fb1e \
--hash=sha256:d85252669dc32f98ebcd5d36768f5d4faeaeaa2d655ac0473be490ecdae3c285 \
--hash=sha256:e143ada795c341b56de9418c58d028989093ee611aa27ffb9b7f609c00d813ed \
--hash=sha256:e188d2699864c11c36cdfdada94d781fd5d6b0071cd9c427bceb08ad3d7c70e1 \
--hash=sha256:e2f1c3765db32be59d18ab3953f43ab62a761327aafc1594a2a1fbe038b8b8a7 \
--hash=sha256:e5b8daf27af0b90da7bb903a876477a9e6d7270be6146906b276605997c7e9a3 \
--hash=sha256:e7e3736715fbf53e9be2a79eb4db68e4ed857017344d697e8b9749444ae57475 \
--hash=sha256:e8c4ebfcfd57177b572e2040777b8abc537cdef58a2120e830124946aa9b42c5 \
--hash=sha256:f66efbc1caa63c088dead1c4170d148eabc9b80d95fb75b6c92ac0aad2437d76 \
--hash=sha256:fc4b630cd3fa2cf7fce38afa91d7cfe844a9f75d7f0f36393fa98815e911d987 \
--hash=sha256:fd5415dded15c3822597455bc02bcd66e81ef8b7a48cb71a33628fc9fdde39df
# via ruamel-yaml
urllib3==2.6.0 \
--hash=sha256:c90f7a39f716c572c4e3e58509581ebd83f9b59cced005b7db7ad2d22b0db99f \
--hash=sha256:cb9bcef5a4b345d5da5d145dc3e30834f58e8018828cbc724d30b4cb7d4d49f1
urllib3==2.2.3 \
--hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \
--hash=sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9
# via requests
xmltodict==1.0.2 \
--hash=sha256:54306780b7c2175a3967cad1db92f218207e5bc1aba697d887807c0fb68b7649 \
--hash=sha256:62d0fddb0dcbc9f642745d8bbf4d81fd17d6dfaec5a15b5c1876300aad92af0d
xmltodict==0.14.2 \
--hash=sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553 \
--hash=sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac
# via jc

View File

@@ -1,9 +1,9 @@
#!/usr/bin/env bash
# This script was generated by bashly 1.3.3 (https://bashly.dev)
# This script was generated by bashly 1.1.1 (https://bashly.dannyb.co)
# Modifying it manually is not recommended
if ((BASH_VERSINFO[0] < 4 || (BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] < 2))); then
printf "bash version 4.2 or higher is required\n" >&2
if [[ "${BASH_VERSINFO:-0}" -lt 4 ]]; then
printf "bash version 4 or higher is required\n" >&2
exit 1
fi
@@ -15,7 +15,7 @@ root_command() {
no_call=${args[--no-call]}
dry_run=${args[--dry-run]}
REQS="wget apt-transport-https curl gpg"
REQS="wget apt-transport-https"
function do_call() {
if [[ $dry_run ]]; then
@@ -56,16 +56,17 @@ root_command() {
get_distribution
echo "### Detected distribution: $OS $VER"
SUPPORTED=true # is this OS supported?
NEEDS_LIBSSL1_1=false # does this OS need libssl1.1?
DIST_OS=${OS,,}
DIST_VER=$VER
case "$OS" in
Ubuntu)
if [[ $VER == "24.04" ]]; then
SUPPORTED=true
elif [[ $VER == "22.04" ]]; then
if [[ $VER == "22.04" ]]; then
SUPPORTED=true
NEEDS_LIBSSL1_1=true
DIST_VER="20.04"
elif [[ $VER == "20.04" ]]; then
SUPPORTED=true
else
@@ -74,6 +75,7 @@ root_command() {
;;
"Debian GNU/Linux" | "debian gnu/linux" | Raspbian)
if [[ $VER == "12" ]]; then
DIST_VER="11"
SUPPORTED=true
elif [[ $VER == "11" ]]; then
SUPPORTED=true
@@ -109,6 +111,15 @@ root_command() {
fi
done
if [[ $NEEDS_LIBSSL1_1 == "true" ]]; then
echo "### Installing libssl1.1"
echo "deb http://security.ubuntu.com/ubuntu focal-security main" | sudo tee /etc/apt/sources.list.d/focal-security.list
do_call "sudo apt-get update"
do_call "sudo apt-get install libssl1.1"
sudo rm /etc/apt/sources.list.d/focal-security.list
fi
echo "### Getting and adding key"
curl -fsSL https://dl.packager.io/srv/$publisher/InvenTree/key | gpg --dearmor | tee /etc/apt/trusted.gpg.d/pkgr-inventree.gpg > /dev/null
echo "### Adding package source"
@@ -135,7 +146,15 @@ version_command() {
}
install.sh_usage() {
printf "install.sh - Interactive installer for InvenTree\n\n"
if [[ -n $long_usage ]]; then
printf "install.sh - Interactive installer for InvenTree\n"
echo
else
printf "install.sh - Interactive installer for InvenTree\n"
echo
fi
printf "%s\n" "Usage:"
printf " install.sh [SOURCE] [PUBLISHER] [OPTIONS]\n"
@@ -143,7 +162,7 @@ install.sh_usage() {
printf " install.sh --version | -v\n"
echo
if [[ -n "$long_usage" ]]; then
if [[ -n $long_usage ]]; then
printf "%s\n" "Options:"
printf " %s\n" "--no-call, -n"
@@ -165,13 +184,13 @@ install.sh_usage() {
printf " %s\n" "SOURCE"
printf " Package source that should be used\n"
printf " %s\n" "Allowed: stable, master, main"
printf " %s\n" "Default: stable"
printf " Allowed: stable, master, main\n"
printf " Default: stable\n"
echo
printf " %s\n" "PUBLISHER"
printf " Publisher that should be used\n"
printf " %s\n" "Default: inventree"
printf " Default: inventree\n"
echo
printf "%s\n" "Examples:"
@@ -184,14 +203,11 @@ install.sh_usage() {
}
normalize_input() {
local arg passthru flags
passthru=false
local arg flags
while [[ $# -gt 0 ]]; do
arg="$1"
if [[ $passthru == true ]]; then
input+=("$arg")
elif [[ $arg =~ ^(--[a-zA-Z0-9_\-]+)=(.+)$ ]]; then
if [[ $arg =~ ^(--[a-zA-Z0-9_\-]+)=(.+)$ ]]; then
input+=("${BASH_REMATCH[1]}")
input+=("${BASH_REMATCH[2]}")
elif [[ $arg =~ ^(-[a-zA-Z0-9])=(.+)$ ]]; then
@@ -202,9 +218,6 @@ normalize_input() {
for ((i = 0; i < ${#flags}; i++)); do
input+=("-${flags:i:1}")
done
elif [[ "$arg" == "--" ]]; then
passthru=true
input+=("$arg")
else
input+=("$arg")
fi
@@ -213,11 +226,37 @@ normalize_input() {
done
}
inspect_args() {
if ((${#args[@]})); then
readarray -t sorted_keys < <(printf '%s\n' "${!args[@]}" | sort)
echo args:
for k in "${sorted_keys[@]}"; do echo "- \${args[$k]} = ${args[$k]}"; done
else
echo args: none
fi
if ((${#other_args[@]})); then
echo
echo other_args:
echo "- \${other_args[*]} = ${other_args[*]}"
for i in "${!other_args[@]}"; do
echo "- \${other_args[$i]} = ${other_args[$i]}"
done
fi
if ((${#deps[@]})); then
readarray -t sorted_keys < <(printf '%s\n' "${!deps[@]}" | sort)
echo
echo deps:
for k in "${sorted_keys[@]}"; do echo "- \${deps[$k]} = ${deps[$k]}"; done
fi
}
parse_requirements() {
while [[ $# -gt 0 ]]; do
key="$1"
case "$key" in
case "${1:-}" in
--version | -v)
version_command
exit
@@ -262,10 +301,11 @@ parse_requirements() {
*)
if [[ -z ${args['source']+x} ]]; then
args['source']=$1
shift
elif [[ -z ${args['publisher']+x} ]]; then
args['publisher']=$1
shift
else
@@ -281,7 +321,7 @@ parse_requirements() {
[[ -n ${args['source']:-} ]] || args['source']="stable"
[[ -n ${args['publisher']:-} ]] || args['publisher']="inventree"
if [[ -n ${args['source']:-} ]] && [[ ! ${args['source']:-} =~ ^(stable|master|main)$ ]]; then
if [[ -n ${args['source']} ]] && [[ ! ${args['source']} =~ ^(stable|master|main)$ ]]; then
printf "%s\n" "source must be one of: stable, master, main" >&2
exit 1
fi
@@ -289,19 +329,18 @@ parse_requirements() {
}
initialize() {
declare -g version="2.0"
version="2.0"
long_usage=''
set -e
}
run() {
declare -g long_usage=''
declare -g -A args=()
declare -g -A deps=()
declare -g -a env_var_names=()
declare -g -a input=()
declare -A args=()
declare -A deps=()
declare -a other_args=()
declare -a input=()
normalize_input "$@"
parse_requirements "${input[@]}"
@@ -310,6 +349,5 @@ run() {
esac
}
command_line_args=("$@")
initialize
run "${command_line_args[@]}"
run "$@"

View File

@@ -5,7 +5,7 @@ publisher=${args[publisher]}
no_call=${args[--no-call]}
dry_run=${args[--dry-run]}
REQS="wget apt-transport-https curl gpg"
REQS="wget apt-transport-https"
function do_call() {
if [[ $dry_run ]]; then
@@ -46,16 +46,17 @@ echo "### Installer for InvenTree - source: $publisher/$source_url"
get_distribution
echo "### Detected distribution: $OS $VER"
SUPPORTED=true # is this OS supported?
NEEDS_LIBSSL1_1=false # does this OS need libssl1.1?
DIST_OS=${OS,,}
DIST_VER=$VER
case "$OS" in
Ubuntu)
if [[ $VER == "24.04" ]]; then
SUPPORTED=true
elif [[ $VER == "22.04" ]]; then
if [[ $VER == "22.04" ]]; then
SUPPORTED=true
NEEDS_LIBSSL1_1=true
DIST_VER="20.04"
elif [[ $VER == "20.04" ]]; then
SUPPORTED=true
else
@@ -99,6 +100,15 @@ for pkg in $REQS; do
fi
done
if [[ $NEEDS_LIBSSL1_1 == "true" ]]; then
echo "### Installing libssl1.1"
echo "deb http://security.ubuntu.com/ubuntu focal-security main" | sudo tee /etc/apt/sources.list.d/focal-security.list
do_call "sudo apt-get update"
do_call "sudo apt-get install libssl1.1"
sudo rm /etc/apt/sources.list.d/focal-security.list
fi
echo "### Getting and adding key"
curl -fsSL https://dl.packager.io/srv/$publisher/InvenTree/key | gpg --dearmor | tee /etc/apt/trusted.gpg.d/pkgr-inventree.gpg > /dev/null
echo "### Adding package source"

View File

@@ -4,8 +4,8 @@
#
Color_Off='\033[0m'
On_Red='\033[41m'
PYTHON_FROM=11
PYTHON_TO=15
PYTHON_FROM=9
PYTHON_TO=12
function detect_docker() {
if [ -n "$(grep docker </proc/1/cgroup)" ]; then
@@ -61,7 +61,7 @@ function detect_python() {
echo "# POI07| No python environment found - using environment variable: ${SETUP_PYTHON}"
fi
# Try to detect a python between lowest and highest supported in reverse order
# Try to detect a python between 3.9 and 3.12 in reverse order
if [ -z "$(which ${SETUP_PYTHON})" ]; then
echo "# POI07| Trying to detecting python3.${PYTHON_FROM} to python3.${PYTHON_TO} - using newest version"
for i in $(seq $PYTHON_TO -1 $PYTHON_FROM); do
@@ -79,7 +79,7 @@ function detect_python() {
echo "${On_Red}"
echo "# POI07| Python ${SETUP_PYTHON} not found - aborting!"
echo "# POI07| Please ensure python can be executed with the command '$SETUP_PYTHON' by the current user '$USER'."
echo "# POI07| If you are using a different python version, please set the environment variable SETUP_PYTHON to the correct command - eg. 'python3.11'."
echo "# POI07| If you are using a different python version, please set the environment variable SETUP_PYTHON to the correct command - eg. 'python3.10'."
echo "${Color_Off}"
exit 1
fi
@@ -120,18 +120,6 @@ function detect_local_env() {
echo "# POI02| Printing local envs - after #++#"
printenv
fi
# Print branch and dir from VERSION file
if [ -f "${APP_HOME}/VERSION" ]; then
echo "# POI02| Loading environment variables from VERSION file"
content=$(cat "${APP_HOME}/VERSION")
# use grep to get the branch and target
INVENTREE_PKG_BRANCH=($(echo $content | grep -oP 'INVENTREE_PKG_BRANCH=\K[^ ]+'))
INVENTREE_PKG_TARGET=($(echo $content | grep -oP 'INVENTREE_PKG_TARGET=\K[^ ]+'))
echo "Running in a package environment build on branch $INVENTREE_PKG_BRANCH for target $INVENTREE_PKG_TARGET"
else
echo "# POI02| VERSION file not found"
fi
}
function detect_envs() {
@@ -166,18 +154,6 @@ function detect_envs() {
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})
# Parse site URL if not already set
if [ -z "${INVENTREE_SITE_URL}" ]; then
# Try to read out the app config
if [ -n "$(inventree config:get INVENTREE_SITE_URL)" ]; then
echo "# POI03| Getting site URL from app config"
export INVENTREE_SITE_URL=$(inventree config:get INVENTREE_SITE_URL)
else
echo "# POI03| Getting site URL from config file"
export INVENTREE_SITE_URL=$(jq -r '.[].site_url' <<< ${INVENTREE_CONF_DATA})
fi
fi
else
echo "# POI03| No config file found: ${INVENTREE_CONFIG_FILE}, using envs or defaults"
@@ -193,7 +169,6 @@ function detect_envs() {
export INVENTREE_PLUGINS_ENABLED=true
export INVENTREE_PLUGIN_FILE=${CONF_DIR}/plugins.txt
export INVENTREE_SECRET_KEY_FILE=${CONF_DIR}/secret_key.txt
export INVENTREE_OIDC_PRIVATE_KEY_FILE=${CONF_DIR}/oidc.pem
export INVENTREE_DB_ENGINE=${INVENTREE_DB_ENGINE:-sqlite3}
export INVENTREE_DB_NAME=${INVENTREE_DB_NAME:-${DATA_DIR}/database.sqlite3}
@@ -202,8 +177,6 @@ function detect_envs() {
export INVENTREE_DB_HOST=${INVENTREE_DB_HOST:-samplehost}
export INVENTREE_DB_PORT=${INVENTREE_DB_PORT:-123456}
export INVENTREE_SITE_URL=${INVENTREE_SITE_URL:-http://${INVENTREE_IP}}
export SETUP_CONF_LOADED=true
fi
@@ -223,7 +196,6 @@ function detect_envs() {
fi
echo "# POI03| INVENTREE_DB_HOST=${INVENTREE_DB_HOST}"
echo "# POI03| INVENTREE_DB_PORT=${INVENTREE_DB_PORT}"
echo "# POI03| INVENTREE_SITE_URL=${INVENTREE_SITE_URL}"
}
function create_initscripts() {
@@ -327,8 +299,8 @@ function update_or_install() {
# Run update as app user
echo "# POI12| Updating InvenTree"
sudo -u ${APP_USER} --preserve-env=$SETUP_ENVS bash -c "cd ${APP_HOME} && pip install wheel python-dotenv"
sudo -u ${APP_USER} --preserve-env=$SETUP_ENVS bash -c "cd ${APP_HOME} && set -e && invoke update | sed -e 's/^/# POI12| u | /;'"
sudo -u ${APP_USER} --preserve-env=$SETUP_ENVS bash -c "cd ${APP_HOME} && pip install wheel"
sudo -u ${APP_USER} --preserve-env=$SETUP_ENVS bash -c "cd ${APP_HOME} && invoke update | sed -e 's/^/# POI12| u | /;'"
# Make sure permissions are correct again
echo "# POI12| Set permissions for data dir and media: ${DATA_DIR}"
@@ -355,8 +327,6 @@ function set_env() {
sed -i s=#plugin_file:\ \'/path/to/plugins.txt\'=plugin_file:\ \'${INVENTREE_PLUGIN_FILE}\'=g ${INVENTREE_CONFIG_FILE}
# Secret key file
sed -i s=#secret_key_file:\ \'/etc/inventree/secret_key.txt\'=secret_key_file:\ \'${INVENTREE_SECRET_KEY_FILE}\'=g ${INVENTREE_CONFIG_FILE}
# OIDC private key file
sed -i s=#oidc_private_key_file:\ \'/etc/inventree/oidc.pem\'=oidc_private_key_file:\ \'${INVENTREE_OIDC_PRIVATE_KEY_FILE}\'=g ${INVENTREE_CONFIG_FILE}
# Debug mode
sed -i s=debug:\ True=debug:\ False=g ${INVENTREE_CONFIG_FILE}
@@ -388,15 +358,10 @@ function set_site() {
# Check if INVENTREE_SITE_URL in inventree config
if [ -z "$(inventree config:get INVENTREE_SITE_URL)" ]; then
# Prefer current INVENTREE_SITE_URL if set
if [ -n "${INVENTREE_SITE_URL}" ]; then
inventree config:set INVENTREE_SITE_URL=${INVENTREE_SITE_URL}
else
echo "# POI14| Setting up InvenTree site URL"
inventree config:set INVENTREE_SITE_URL=http://${INVENTREE_IP}
fi
echo "# POI14| Setting up InvenTree site URL"
inventree config:set INVENTREE_SITE_URL=http://${INVENTREE_IP}
else
echo "# POI14| Site URL already set to '$INVENTREE_SITE_URL' - skipping"
echo "# POI14| Site URL already set - skipping"
fi
}
@@ -405,16 +370,11 @@ function final_message() {
echo -e "####################################################################################"
echo -e "This InvenTree install uses nginx, the settings for the webserver can be found in"
echo -e "${SETUP_NGINX_FILE}"
echo -e "Try opening InvenTree with any of \n${INVENTREE_SITE_URL} , http://localhost/ or http://${INVENTREE_IP}/ \n"
# Print admin user data only if set
if [ -n "${INVENTREE_ADMIN_USER}" ]; then
echo -e "Admin user data:"
echo -e " Email: ${INVENTREE_ADMIN_EMAIL}"
echo -e " Username: ${INVENTREE_ADMIN_USER}"
echo -e " Password: ${INVENTREE_ADMIN_PASSWORD}"
else
echo -e "No admin set during this operation - depending on the deployment method a admin user might have been created with an initial password saved in `$SETUP_ADMIN_PASSWORD_FILE`"
fi
echo -e "Try opening InvenTree with either\nhttp://localhost/ or http://${INVENTREE_IP}/\n"
echo -e "Admin user data:"
echo -e " Email: ${INVENTREE_ADMIN_EMAIL}"
echo -e " Username: ${INVENTREE_ADMIN_USER}"
echo -e " Password: ${INVENTREE_ADMIN_PASSWORD}"
echo -e "####################################################################################"
}

View File

@@ -14,7 +14,7 @@ echo "# POI01| Importing functions"
echo "# POI01| Functions imported"
# 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,INVENTREE_SITE_URL,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_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
# Get the envs
detect_local_env
@@ -26,17 +26,17 @@ export DATA_DIR=${APP_HOME}/data
export SETUP_NGINX_FILE=${SETUP_NGINX_FILE:-/etc/nginx/sites-enabled/inventree.conf}
export SETUP_ADMIN_PASSWORD_FILE=${CONF_DIR}/admin_password.txt
export SETUP_NO_CALLS=${SETUP_NO_CALLS:-false}
export SETUP_PYTHON=${SETUP_PYTHON:-python3.11}
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
# get base info
detect_ip
detect_envs
detect_docker
detect_initcmd
detect_ip
detect_python
# Check if we are updating and need to alert

View File

@@ -6,7 +6,7 @@ echo "# PRI01| Running preinstall script - start - $(date)"
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,INVENTREE_SITE_URL,SETUP_NGINX_FILE,SETUP_ADMIN_PASSWORD_FILE,SETUP_NO_CALLS,SETUP_DEBUG,SETUP_EXTRA_PIP,SETUP_PYTHON
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

5
docs/.gitignore vendored
View File

@@ -20,10 +20,5 @@ invoke-commands.txt
# Temp files
releases.json
versions.json
inventree_filters.yml
inventree_settings.json
observed_settings.json
inventree_tags.yml
.vscode/
generated/

View File

@@ -4,92 +4,32 @@
This repository hosts the [official documentation](https://inventree.readthedocs.io/) for [InvenTree](https://github.com/inventree/inventree), an open source inventory management system.
## Prerequisites
To serve this documentation locally (e.g. for development), you will need to have Python 3 installed on your system.
InvenTree uses [MkDocs](https://www.mkdocs.org/) to convert [Markdown](https://www.mkdocs.org/user-guide/writing-your-docs/#writing-with-markdown) format `.md` files into HTML suitable for viewing in a web browser.
## Setup
!!! info "Prerequisites"
To build and serve this documentation locally (e.g. for development), you will need:
* Python 3 installed on your system.
* An existing InvenTree installation containing the virtual environment that was created during installation.
These instructions assume you followed the [InvenTree bare metal installation instructions](./docs/start/install.md), so you'll have an `inventree` user, a home directory at `/home/inventree`, the InvenTree source code cloned from [GitHub](https://github.com/inventree/inventree) into `/home/inventree/src`, and a virtual environment at `/home/inventree/env`. If you installed InvenTree some other way, this might vary, and you'll have to adjust these instructions accordingly.
!!! warning "Your InvenTree install will be updated!"
Some of the commands that follow will make changes to your install, for example, by running any pending database migrations. There's a small risk this may cause issues with your existing installation. If you can't risk this, consider setting up a separate InvenTree installation specifically for documentation development.
## Building the documentation locally
To build the documentation locally, run these commands as the `inventree` user:
Run the following commands from the top-level project directory:
```
$ cd /home/inventree
$ source env/bin/activate
```
!!! info "(env) prefix"
The shell prompt should now display the `(env)` prefix, showing that you are operating within the context of the python virtual environment
You can now install the additional packages needed by mkdocs:
```
$ cd src
$ git clone https://github.com/inventree/inventree
$ pip install --require-hashes -r docs/requirements.txt
```
## Schema generation
## Serve Locally
Building the documentation requires extracting the API schema from the source code.
!!! tip
This command is only required when building the documentation for the first time, or when changes have been made to the API schema.
To serve the pages locally, run the following command (from the top-level project directory):
```
$ invoke build-docs
$ mkdocs serve -f docs/mkdocs.yml -a localhost:8080
```
You will see output similar to this (truncated for brevity):
```
Running InvenTree database migrations...
Exporting definitions...
Exporting settings definition to '/home/inventree/src/docs/generated/inventree_settings.json'...
Exported InvenTree settings definitions to '/home/inventree/src/docs/generated/inventree_settings.json'
Exported InvenTree tag definitions to '/home/inventree/src/docs/generated/inventree_tags.yml'
Exported InvenTree filter definitions to '/home/inventree/src/docs/generated/inventree_filters.yml'
Exported InvenTree report context definitions to '/home/inventree/src/docs/generated/inventree_report_context.json'
Exporting definitions complete
Exporting schema file to '/home/inventree/src/docs/generated/schema.yml'
## Edit Documentation Files
Schema export completed: /home/inventree/src/docs/generated/schema.yml
Documentation build complete, but mkdocs not requested
```
## Viewing the documentation
Generate the HTML files from the markdown source files, and start the MkDocs webpage server:
```
$ mkdocs serve -f docs/mkdocs.yml
```
You can then point your web browser at http://localhost:8080/
Alternatively, you can use the `invoke` command:
```
$ invoke dev.docs-server
```
If you need to, use the `-a` option after `mkdocs` or `invoke` to set the address and port. Run `invoke dev.docs-server --help` for details.
## Editing the Documentation Files
Once the server is running, it will monitor the documentation files for changes, and regenerate the HTML pages as required. Refresh your web browser to see the changes.
Once the server is running, it will monitor the documentation files for any changes, and update the served pages.
### Admonitions
"Admonition" blocks can be added to the documentation source as follows:
"Admonition" blocks can be added as follow:
```
!!! info "This is the admonition block title"
This is the admonition block content
@@ -119,24 +59,18 @@ Click [here](/part/views)
### Images
Images are served from the `./docs/assets/images` folder and can be added as follows:
Images are served from the `./docs/assets/images` folder and can be added as follow:
```
{{ image("image_name.png", base="subfolder", title="Image title") }}
{% with id="image_id", url="folder/image_name.png", description="Text shown if image is not loaded properly" %}
{% include 'img.html' %}
{% endwith %}
```
See the `image` macro in `./docs/main.py` for more information.
### Icons
Icons can be rendered (using the [tabler icon set](https://tabler.io/icons)) as follows:
```
{{ icon("brand-github", color="red")}}
```
See the `icon` macro in `./docs/main.py` for more information.
Replace:
* `image_id` with a short unique identifier for the image (most commonly, `image_id` is same as `image_name`)
* `folder` with the folder in `docs/assets/images` in which the image is stored
* `image_name` with the name of the image
* `.png` with the image extension (PNG or JPEG are preferred formats)
### Global variables

View File

@@ -0,0 +1,5 @@
{% set url = 'app/' + url %}
{% with id=id, url=url, maxheight="240px", description="" %}
{% include "img.html" %}
{% endwith %}

30
docs/_includes/img.html Normal file
View File

@@ -0,0 +1,30 @@
{% if 'http' in url %}
{% set img_url = url %}
{% else %}
{% set img_url = config.assets_dir + '/images/' + url %}
{% endif %}
<figure class='image image-inventree'>
{% if id %}
<!-- The link that, when clicked, will display the image in full screen -->
<a href="#{{ id }}">
{% elif img_url %}
<a href="{{ img_url }}">
{% endif %}
<img class='img-inline' src='{{ img_url }}' alt='{{ description }}' title='{{ description }}'
{% if maxwidth or maxheight %}style='
{% if maxwidth %} max-width:{{ maxwidth }};{% endif %}
{% if maxheight %} max-height: {{ maxheight }};{% endif %}
'{% endif %}
>
{% if id or img_url %}
</a>
{% endif %}
{% if id %}
<!-- The full screen image, hidden by default -->
<a href="#_" class="overlay" id="{{ id }}">
<img src="{{ img_url }}" alt="{{ description }}" />
</a>
{% endif %}
</figure>

View File

@@ -20,7 +20,8 @@
<div class="md-grid md-typeset">
<div class="mdx-hero"></div>
<h1>
<i class="ti ti-search"></i> Page not found
<span class='fas fa-search'></span>
Page not found
</h1>
</div>
</section>

View File

@@ -7,7 +7,7 @@
{% block content %}
{{ page.content }}
<style>
h1 {
@@ -15,8 +15,6 @@
}
</style>
<h2 id="intuitive-inventory-management">InvenTree - Intuitive Inventory Management</h2>
<!-- Hero for landing page -->
<section class="mdx-container">
<div class="md-grid md-typeset">
@@ -26,24 +24,24 @@
<div class="mdx-hero__content">
<a href="https://inventree.org" title="InvenTree Website" class="md-button">
<i class='ti ti-world'></i> Website
<span class='fas fa-globe'></span> Website
</a>
<a href="start" title="Install InvenTree" class="md-button">
<i class='ti ti-server-bolt'></i> Install
<a href="start/intro" title="Install InvenTree" class="md-button">
<span class='fas fa-server'></span> Install
</a>
<a href="app" title="InvenTree mobile app" class="md-button">
<i class='ti ti-device-mobile'></i> Mobile App
<a href="app/app" title="InvenTree mobile app" class="md-button">
<span class='fas fa-mobile-alt'></span> Mobile App
</a>
<a href="https://crowdin.com/project/inventree" title="Help translate InvenTree" class="md-button">
<i class='ti ti-language'></i> Translate
<span class='fas fa-language'></span> Translate
</a>
<a href="https://github.com/inventree/inventree" title="Explore InvenTree source code" class="md-button md-button">
<i class='ti ti-code-circle'></i> Source Code
<span class='fab fa-github'></span> Source Code
</a>
</div>
</div>
</div>
</section>
{{ page.content }}
{% endblock content %}

View File

@@ -4,10 +4,10 @@
<table>
<thead>
<tr>
<th>{{ icon("clipboard") }}</span> Release</th>
<th>{{ icon("calendar") }} Date</th>
<th>{{ icon("brand-github") }} GitHub</th>
<th>{{ icon("brand-docker") }} Docker</th>
<th><span class='fas fa-clipboard-list'></span> Release</th>
<th><span class='fas fa-calendar-alt'></span> Date</th>
<th><span class='fab fa-github'></span> GitHub</th>
<th><span class='fab fa-docker'></span> Docker</th>
</tr>
</thead>
<tbody>

121
docs/docs/api/api.md Normal file
View File

@@ -0,0 +1,121 @@
---
title: InvenTree API
---
## InvenTree API
InvenTree provides a powerful REST API for interacting with inventory data on the server. Low-level data access and manipulation is available, with integrated user authentication and data validation.
!!! info "Django REST Framework"
The InvenTree API is based on the powerful and flexible [Django REST Framework](https://www.django-rest-framework.org/).
## Documentation
The API is self-documenting, and the documentation is provided alongside any InvenTree installation instance. If (for example) you have an InvenTree instance running at `http://127.0.0.1:8000` then the API documentation is available at `http://127.0.0.1:8000/api-doc/`
{% with id="api_doc", url="api/api_doc.png", description="API documentation" %}
{% include 'img.html' %}
{% endwith %}
### Schema Description
The API schema is also documented in the [API Schema](./schema.md) page.
### Generating Schema File
If you want to generate the API schema file yourself (for example to use with an external client, use the `invoke dev.schema` command. Run with the `-help` command to see available options.
```
invoke dev.schema -help
```
## Authentication
Users must be authenticated to gain access to the InvenTree API. The API accepts either basic username:password authentication, or token authentication. Token authentication is recommended as it provides much faster API access.
!!! warning "Permissions"
API access is restricted based on the permissions assigned to the user.
### Basic Auth
Users can authenticate against the API using basic authentication - specifically a valid combination of `username` and `password` credentials.
### Tokens
Each user is assigned an authentication token which can be used to access the API. This token is persistent for that user (unless invalidated by an administrator) and can be used across multiple sessions.
!!! info "Token Administration"
User tokens can be created and/or invalidated via the Admin interface.
### Requesting a Token
If a user does not know their access token, it can be requested via the API interface itself, using a basic authentication request.
To obtain a valid token, perform a GET request to `/api/user/token/`. No data are required, but a valid username / password combination must be supplied in the authentication headers.
!!! info "Credentials"
Ensure that a valid username:password combination are supplied as basic authorization headers.
Once a valid token is received from the server, subsequent API requests should be performed using that token.
If the supplied user credentials are validated, the server will respond with:
```
HTTP_200_OK
{
token: "usertokendatastring",
}
```
### Using a Token
After reception of a valid authentication token, it can be subsequently used to perform token-based authentication.
The token value sent to the server must be of the format `Token <TOKEN-VALUE>` (without the `<` and `>` characters).
**Example: Javascript**
```javascript
var token = "MY-TOKEN-VALUE-HERE";
$.ajax({
url: "http://localhost:8080/api/part/",
type: 'GET',
headers: {"Authorization": `Token ${token}`}
});
```
**Example: Python (Requests)**
```python
import requests
token = 'MY-TOKEN-VALUE-HERE'
data = { ... }
headers = {
'AUTHORIZATION': f'Token {token}'
}
response = request.get('http://localhost:8080/api/part/', data=data, headers=headers)
```
## Authorization
### User Roles
Users can only perform REST API actions which align with their assigned [role permissions](../settings/permissions.md#roles).
Once a user has *authenticated* via the API, a list of the available roles can be retrieved from:
`/api/user/roles/`
For example, when accessing the API from a *superuser* account:
{% with id="api_roles", url="api/api_roles.png", description="API superuser roles" %}
{% include 'img.html' %}
{% endwith %}
Or, when accessing the API from an account which has read-only permissions:
{% with id="api_roles_2", url="api/api_roles_2.png", description="API user roles" %}
{% include 'img.html' %}
{% endwith %}
### Permission Denied
If an API action outside of the user's role(s) is attempted, the server will respond with a 403 permission error message.

View File

@@ -4,7 +4,7 @@ title: Interactive API
## Interactive API
If the server is running in [Debug Mode](../start/index.md#debug-mode) then an interactive version of the API is available using a browser.
If the server is running in [Debug Mode](../start/intro.md#debug-mode) then an interactive version of the API is available using a browser.
!!! info "Debug Mode"
This interactive API is only available when running the server in debug mode
@@ -16,16 +16,22 @@ If the server is running in [Debug Mode](../start/index.md#debug-mode) then an i
Various list endpoints can be displayed as shown below:
{{ image("api/api_browse.png", "List API") }}
{% with id="api_browse", url="api/api_browse.png", description="List API" %}
{% include 'img.html' %}
{% endwith %}
### Filtering
List views can be filtered interactively:
{{ image("api/api_filters.png", "Filter API") }}
{% with id="api_filter", url="api/api_filters.png", description="Filter API" %}
{% include 'img.html' %}
{% endwith %}
### Detail View
Detail view endpoints can also be displayed:
{{ image("api/api_detail.png", "Detail API") }}
{% with id="api_detail", url="api/api_detail.png", description="Detail API" %}
{% include 'img.html' %}
{% endwith %}

View File

@@ -6,7 +6,7 @@ title: Bulk Deletion
While deleting items individually via the API is supported, it can prove inefficient (time consuming) when multiple items are to be deleted sequentially.
For example, if the user wishes to delete a large number items (such as lines from a [Bill of Materials](../manufacturing/bom.md)), these items are deleted sequentially, with each `DELETE` separate request requiring network transfer, database access, cleanup, etc.
For example, if the user wishes to delete a large number items (such as lines from a [Bill of Materials](../build/bom.md)), these items are deleted sequentially, with each `DELETE` separate request requiring network transfer, database access, cleanup, etc.
A much more efficient approach is to allow for "bulk deletion" of multiple database items in a single transaction. This means that only one network request is required, and only a single database access request.

View File

@@ -1,161 +0,0 @@
---
title: InvenTree API
---
## InvenTree API
InvenTree provides a powerful REST API for interacting with inventory data on the server. Low-level data access and manipulation is available, with integrated user authentication and data validation.
!!! info "Django REST Framework"
The InvenTree API is based on the powerful and flexible [Django REST Framework](https://www.django-rest-framework.org/).
## Documentation
The API is self-documenting, and the documentation is provided alongside any InvenTree installation instance. If (for example) you have an InvenTree instance running at `http://127.0.0.1:8000` then the API documentation is available at `http://127.0.0.1:8000/api-doc/`
{{ image("api/api_doc.png", "API documentation") }}
### Browseble API
If [debug mode](../start/index.md#debug-mode) is enabled, the API can be browsed directly from the web interface. This provides a simple way to explore the API and test out different endpoints. Simply navigate your web browser to any API endpoint, and the API will be displayed in a human-readable format.
### Schema Description
The API schema is also documented in the [API Schema](./schema.md) page.
### Generating Schema File
If you want to generate the API schema file yourself. For example, to use with an external client, use the `invoke dev.schema` command. Run with the `-help` command to see available options.
```
invoke dev.schema -help
```
## Authentication
Users must be authenticated to gain access to the InvenTree API. The API accepts either basic username:password authentication, or token authentication. Token authentication is recommended as it provides much faster API access.
!!! warning "Permissions"
API access is restricted based on the permissions assigned to the user or scope of the application.
### Basic Auth
Users can authenticate against the API using basic authentication - specifically a valid combination of `username` and `password` credentials.
### Tokens
Each user is assigned an authentication token which can be used to access the API. This token is persistent for that user (unless invalidated by an administrator) and can be used across multiple sessions.
!!! info "Token Administration"
User tokens can be created and/or invalidated via the user settings, [Admin Center](../settings/admin.md#admin-center) or admin interface.
#### Requesting a Token
If a user does not know their access token, it can be requested via the API interface itself, using a basic authentication request.
To obtain a valid token, perform a GET request to `/api/user/token/`. No data are required, but a valid username / password combination must be supplied in the authentication headers.
!!! info "Credentials"
Ensure that a valid username:password combination are supplied as basic authorization headers.
Once a valid token is received from the server, subsequent API requests should be performed using that token.
If the supplied user credentials are validated, the server will respond with:
```
HTTP_200_OK
{
token: "usertokendatastring",
}
```
#### Using a Token
After reception of a valid authentication token, it can be subsequently used to perform token-based authentication.
The token value sent to the server must be of the format `Token <TOKEN-VALUE>` (without the `<` and `>` characters).
**Example: Javascript**
```javascript
var token = "MY-TOKEN-VALUE-HERE";
$.ajax({
url: "http://localhost:8080/api/part/",
type: 'GET',
headers: {"Authorization": `Token ${token}`}
});
```
**Example: Python (Requests)**
```python
import requests
token = 'MY-TOKEN-VALUE-HERE'
data = { ... }
headers = {
'AUTHORIZATION': f'Token {token}'
}
response = request.get('http://localhost:8080/api/part/', data=data, headers=headers)
```
### oAuth2 and OIDC
!!! warning "Experimental"
This is an experimental feature that needs to be specifically enabled. See [Experimental features](../settings/experimental.md) for more information.
InvenTree has built-in support for using [oAuth2](https://oauth.net/2/) and OpenID Connect (OIDC) for authentication to the API. This enables using the instance as a very limited identity provider.
A default application using a public client with PKCE enabled ships with each instance. Intended to be used with the python api and configured with very wide scopes this can also be used for quick tests - the client_id is `zDFnsiRheJIOKNx6aCQ0quBxECg1QBHtVFDPloJ6`.
#### Managing applications
Superusers can register new applications and manage existing ones using a small application under the subpath `/o/applications/`.
It is recommended to:
- read the spec (RFC 6749 / 6750) and/or best practices (RFC 9700) before choosing client types
- chose scopes as narrow as possible
- configure redirection URIs as exact as possible
#### Scopes
InvenTree's oAuth scopes are strongly related to the [user roles](#user-roles).
Names consist of 1. type, 2. kind and 3. (opt) role, separated by colons.
There are 3 types:
- a: administrative scopes - used for administrating the server - these can be staff or superuser scopes
- g: general scopes - give wide access to the basic building blocks of InvenTree
- r: role scopes - map to specific actions (2) and roles (3)
Examples:
```bash
a:superuser
g:read
r:change:part
r:delete:stock
```
!!! info "Read the API docs"
The API [documentation](#documentation) and [schema](./schema.md) list the required scopes for every API endpoint / interaction in the security sections.
## Authorization
### User Roles
Users can only perform REST API actions which align with their assigned [role permissions](../settings/permissions.md#roles).
Once a user has *authenticated* via the API, a list of the available roles can be retrieved from:
`/api/user/roles/`
For example, when accessing the API from a *superuser* account:
{{ image("api/api_roles.png", "API superuser roles") }}
Or, when accessing the API from an account which has read-only permissions:
{{ image("api/api_roles_2.png", "API user roles") }}
### Permission Denied
If an API action outside of the user's role(s) is attempted, the server will respond with a 403 permission error message.

View File

@@ -4,7 +4,7 @@ title: Model Metadata
## Model Metadata
The API is *self describing* in that it provides metadata about the various fields available at any given endpoint. External applications (such as the [python interface](../api/python/index.md)) can introspect the API to determine information about the model fields.
The API is *self describing* in that it provides metadata about the various fields available at any given endpoint. External applications (such as the [python interface](../api/python/python.md)) can introspect the API to determine information about the model fields.
!!! tip "API Forms"
The various forms implemented in the InvenTree web interface make heavy use of this metadata feature
@@ -13,9 +13,11 @@ The API is *self describing* in that it provides metadata about the various fiel
To request metadata about a particular API endpoint, simply perform an `OPTIONS` method request against the API URL.
For example, to view the metadata available for creating a new [Part Category](../part/index.md#part-category), an `OPTIONS` request to `/api/part/category/` yields:
For example, to view the metadata available for creating a new [Part Category](../part/part.md#part-category), an `OPTIONS` request to `/api/part/category/` yields:
{{ image("api/api_category_options.png", "Part category options") }}
{% with id="api_cat_options", url="api/api_category_options.png", description="Part category options" %}
{% include 'img.html' %}
{% endwith %}
You can see here a detailed list of the various fields which are available for this API endpoint.
@@ -31,7 +33,9 @@ The `OPTIONS` endpoint provides the following information:
Specific details are provided on the available attributes of each field:
{{ image("api/api_metadata_fields.png", "Metadata fields") }}
{% with id="api_fields", url="api/api_metadata_fields.png", description="Metadata fields" %}
{% include 'img.html' %}
{% endwith %}
### Field Types
@@ -78,5 +82,10 @@ Field *label* and *help text* values are localized using the [community contribu
For example, the same forms (in the web interface) are served via identical API requests, with the locale information determined "on the fly":
{{ image("api/api_english.png", "API forms (english)") }}
{{ image("api/api_german.png", "API forms (german)") }}
{% with id="api_english", url="api/api_english.png", description="API forms (english)" %}
{% include 'img.html' %}
{% endwith %}
{% with id="api_german", url="api/api_german.png", description="API forms (german)" %}
{% include 'img.html' %}
{% endwith %}

View File

@@ -6,7 +6,7 @@ title: Python Currency Support
InvenTree provides native support for multiple currencies, which can mean that data require conversion between these currencies, at defined exchange rates.
The InvenTree server maintains a set of exchange rates, which are updated periodically. These exchange rates are available via the [InvenTree API](../index.md), and can be used by the Python bindings.
The InvenTree server maintains a set of exchange rates, which are updated periodically. These exchange rates are available via the [InvenTree API](../api.md), and can be used by the Python bindings.
### CurrencyManager Class

View File

@@ -67,7 +67,7 @@ print("Minimum stock:", part.minimum_stock)
### Adding Parameters
Each [part](../../part/index.md) can have multiple [parameters](../../concepts/parameters.md). For the example of the sofa (above) *length* and *weight* make sense. Each parameter has a parameter template that combines the parameter name with a unit. So we first have to create the parameter templates and afterwards add the parameter values to the sofa.
Each [part](../../part/part.md) can have multiple [parameters](../../part/parameter.md). For the example of the sofa (above) *length* and *weight* make sense. Each parameter has a parameter template that combines the parameter name with a unit. So we first have to create the parameter templates and afterwards add the parameter values to the sofa.
```python
from inventree.part import Parameter
@@ -190,7 +190,7 @@ item.transferStock(loc, quantity=50)
### Delete a Part
To delete a [Part instance](../../part/index.md), first in needs to be marked as *inactive* (otherwise it will throw an error):
To delete a [Part instance](../../part/part.md), first in needs to be marked as *inactive* (otherwise it will throw an error):
```python
from inventree.part import Part

View File

@@ -1,167 +0,0 @@
---
title: Python Interface
---
## Python Module
A [Python module](https://github.com/inventree/inventree-python) is provided for rapid development of third party scripts or applications using the REST API. The python module handles authentication and API transactions, providing an extremely clean interface for interacting with and manipulating database data.
### Features
- Automatic authentication management using token-based authentication
- Pythonic data access
- Native file uploads
- Powerful functions for accessing related model data
### Installation
The inventree python interface can be easily installed via the [PIP package manager](https://pypi.org/project/inventree/):
```
pip3 install inventree
```
!!! tip "Upgrading"
To upgrade to the latest version, run `pip install --upgrade inventree`
Alternatively, it can downloaded and installed from source, from [GitHub](https://github.com/inventree/inventree-python).
### Authentication
Authentication against an InvenTree server is simple:
#### Basic Auth
Connect using your username/password as follows:
```python
from inventree.api import InvenTreeAPI
SERVER_ADDRESS = 'http://127.0.0.1:8000'
MY_USERNAME = 'not_my_real_username'
MY_PASSWORD = 'not_my_real_password'
api = InvenTreeAPI(SERVER_ADDRESS, username=MY_USERNAME, password=MY_PASSWORD)
```
#### Token Auth
Alternatively, if you already have an access token:
```python
api = InvenTreeAPI(SERVER_ADDRESS, token=MY_TOKEN)
```
#### Environment Variables
Authentication variables can also be set using environment variables:
- `INVENTREE_API_HOST`
- `INVENTREE_API_USERNAME`
- `INVENTREE_API_PASSWORD`
- `INVENTREE_API_TOKEN`
And simply connect as follows:
```python
api = InvenTreeAPI()
```
### Retrieving Data
Once a connection is established to the InvenTree server, querying individual items is simple.
#### Single Item
If the primary-key of an object is already known, retrieving it from the database is performed as follows:
```python
from inventree.part import PartCategory
category = PartCategory(api, 10)
```
#### Multiple Items
Database items can be queried by using the `list` method for the given class. Note that arbitrary filter parameters can be applied (as specified by the [InvenTree API](../index.md)) to filter the returned results.
```python
from inventree.part import Part
from inventree.stock import StockItem
parts = Part.list(api, category=10, assembly=True)
items = StockItem.list(api, location=4, part=24)
```
The `items` variable above provides a list of `StockItem` objects.
#### Filtering by parent
In tree based models the child items could be filtered by using the parent keyword:
```python
from inventree.part import PartCategory
child_categories = PartCategory.list(api, parent=10)
```
The top level items can can be queried by passing empty string as a parent filter:
```python
from inventree.part import PartCategory
parent_categories = PartCategory.list(api, parent='')
```
### Item Attributes
The available model attributes are determined by introspecting [API metadata](../metadata.md). To view the fields (attributes) available for a given database model type within the python interface, use the `fieldNames` and `fieldInfo` methods, as below:
```python
from inventree.api import InvenTreeAPI
from inventree.part import Part
api = InvenTreeAPI("http://localhost:8000", username="admin", password="inventree")
fields = Part.fieldNames(api)
for field in Part.fieldNames(api):
print(field, '->', Part.fieldInfo(field, api))
```
```
active -> {'type': 'boolean', 'required': True, 'read_only': False, 'label': 'Active', 'help_text': 'Is this part active?', 'default': True, 'max_length': None}
allocated_to_build_orders -> {'type': 'float', 'required': True, 'read_only': True, 'label': 'Allocated to build orders'}
allocated_to_sales_orders -> {'type': 'float', 'required': True, 'read_only': True, 'label': 'Allocated to sales orders'}
assembly -> {'type': 'boolean', 'required': True, 'read_only': False, 'label': 'Assembly', 'help_text': 'Can this part be built from other parts?', 'default': False, 'max_length': None}
category -> {'type': 'related field', 'required': True, 'read_only': False, 'label': 'Category', 'model': 'partcategory', 'api_url': '/api/part/category/', 'filters': {}, 'help_text': 'Part category', 'max_length': None}
component -> {'type': 'boolean', 'required': True, 'read_only': False, 'label': 'Component', 'help_text': 'Can this part be used to build other parts?', 'default': True, 'max_length': None}
default_expiry -> {'type': 'integer', 'required': True, 'read_only': False, 'label': 'Default Expiry', 'help_text': 'Expiry time (in days) for stock items of this part', 'min_value': 0, 'max_value': 2147483647, 'default': 0, 'max_length': None}
...
variant_stock -> {'type': 'float', 'required': True, 'read_only': True, 'label': 'Variant stock'}
```
### Item Methods
Once an object has been retrieved from the database, its related objects can be returned with the provided helper methods:
```python
part = Part(api, 25)
stock_items = part.getStockItems()
```
Some classes also have helper functions for performing certain actions, such as uploading file attachments or test results:
```python
stock_item = StockItem(api, 1001)
stock_item.uploadTestResult("Firmware", True, value="0x12345678", attachment="device_firmware.bin")
```
#### Discovering Methods
You can determine the available methods by either [reading the source code](https://github.com/inventree/inventree-python) or using the `dir()` function in an interactive terminal.
### Further Reading
The [InvenTree Python Interface](https://github.com/inventree/inventree-python) is open source, and well documented. The best way to learn is to read through the source code and try for yourself!

View File

@@ -0,0 +1,167 @@
---
title: Python Interface
---
## Python Module
A [Python module](https://github.com/inventree/inventree-python) is provided for rapid development of third party scripts or applications using the REST API. The python module handles authentication and API transactions, providing an extremely clean interface for interacting with and manipulating database data.
### Features
- Automatic authentication management using token-based authentication
- Pythonic data access
- Native file uploads
- Powerful functions for accessing related model data
### Installation
The inventree python interface can be easily installed via the [PIP package manager](https://pypi.org/project/inventree/):
```
pip3 install inventree
```
!!! tip "Upgrading"
To upgrade to the latest version, run `pip install --upgrade inventree`
Alternatively, it can downloaded and installed from source, from [GitHub](https://github.com/inventree/inventree-python).
### Authentication
Authentication against an InvenTree server is simple:
#### Basic Auth
Connect using your username/password as follows:
```python
from inventree.api import InvenTreeAPI
SERVER_ADDRESS = 'http://127.0.0.1:8000'
MY_USERNAME = 'not_my_real_username'
MY_PASSWORD = 'not_my_real_password'
api = InvenTreeAPI(SERVER_ADDRESS, username=MY_USERNAME, password=MY_PASSWORD)
```
#### Token Auth
Alternatively, if you already have an access token:
```python
api = InvenTreeAPI(SERVER_ADDRESS, token=MY_TOKEN)
```
#### Environment Variables
Authentication variables can also be set using environment variables:
- `INVENTREE_API_HOST`
- `INVENTREE_API_USERNAME`
- `INVENTREE_API_PASSWORD`
- `INVENTREE_API_TOKEN`
And simply connect as follows:
```python
api = InvenTreeAPI()
```
### Retrieving Data
Once a connection is established to the InvenTree server, querying individual items is simple.
#### Single Item
If the primary-key of an object is already known, retrieving it from the database is performed as follows:
```python
from inventree.part import PartCategory
category = PartCategory(api, 10)
```
#### Multiple Items
Database items can be queried by using the `list` method for the given class. Note that arbitrary filter parameters can be applied (as specified by the [InvenTree API](../api.md)) to filter the returned results.
```python
from inventree.part import Part
from inventree.stock import StockItem
parts = Part.list(api, category=10, assembly=True)
items = StockItem.list(api, location=4, part=24)
```
The `items` variable above provides a list of `StockItem` objects.
#### Filtering by parent
In tree based models the child items could be filtered by using the parent keyword:
```python
from inventree.part import PartCategory
child_categories = PartCategory.list(api, parent=10)
```
The top level items can can be queried by passing empty string as a parent filter:
```python
from inventree.part import PartCategory
parent_categories = PartCategory.list(api, parent='')
```
### Item Attributes
The available model attributes are determined by introspecting [API metadata](../metadata.md). To view the fields (attributes) available for a given database model type within the python interface, use the `fieldNames` and `fieldInfo` methods, as below:
```python
from inventree.api import InvenTreeAPI
from inventree.part import Part
api = InvenTreeAPI("http://localhost:8000", username="admin", password="inventree")
fields = Part.fieldNames(api)
for field in Part.fieldNames(api):
print(field, '->', Part.fieldInfo(field, api))
```
```
active -> {'type': 'boolean', 'required': True, 'read_only': False, 'label': 'Active', 'help_text': 'Is this part active?', 'default': True, 'max_length': None}
allocated_to_build_orders -> {'type': 'float', 'required': True, 'read_only': True, 'label': 'Allocated to build orders'}
allocated_to_sales_orders -> {'type': 'float', 'required': True, 'read_only': True, 'label': 'Allocated to sales orders'}
assembly -> {'type': 'boolean', 'required': True, 'read_only': False, 'label': 'Assembly', 'help_text': 'Can this part be built from other parts?', 'default': False, 'max_length': None}
category -> {'type': 'related field', 'required': True, 'read_only': False, 'label': 'Category', 'model': 'partcategory', 'api_url': '/api/part/category/', 'filters': {}, 'help_text': 'Part category', 'max_length': None}
component -> {'type': 'boolean', 'required': True, 'read_only': False, 'label': 'Component', 'help_text': 'Can this part be used to build other parts?', 'default': True, 'max_length': None}
default_expiry -> {'type': 'integer', 'required': True, 'read_only': False, 'label': 'Default Expiry', 'help_text': 'Expiry time (in days) for stock items of this part', 'min_value': 0, 'max_value': 2147483647, 'default': 0, 'max_length': None}
...
variant_stock -> {'type': 'float', 'required': True, 'read_only': True, 'label': 'Variant stock'}
```
### Item Methods
Once an object has been retrieved from the database, its related objects can be returned with the provided helper methods:
```python
part = Part(api, 25)
stock_items = part.getStockItems()
```
Some classes also have helper functions for performing certain actions, such as uploading file attachments or test results:
```python
stock_item = StockItem(api, 1001)
stock_item.uploadTestResult("Firmware", True, value="0x12345678", attachment="device_firmware.bin")
```
#### Discovering Methods
You can determine the available methods by either [reading the source code](https://github.com/inventree/inventree-python) or using the `dir()` function in an interactive terminal.
### Further Reading
The [InvenTree Python Interface](https://github.com/inventree/inventree-python) is open source, and well documented. The best way to learn is to read through the source code and try for yourself!

View File

@@ -7,7 +7,7 @@ The API schema as documented below is generated using the [drf-spectactular](htt
## API Version
This documentation is for API version: `352`
This documentation is for API version: `171`
!!! tip "API Schema History"
We track API schema changes, and provide a snapshot of each API schema version in the [API schema repository](https://github.com/inventree/schema/).

33
docs/docs/app/app.md Normal file
View File

@@ -0,0 +1,33 @@
---
title: InvenTree Mobile App
---
{% with directory="appgallery", per_page=2 %}
{% include "carousel.html" %}
{% endwith %}
-----
The InvenTree Mobile App brings stock control to your pocket. Integrating seamlessly with the [InvenTree API](../api/api.md), the app provides immediate access to inventory data without requiring physical access to a computer.
Native barcode support provides a multitude of context-sensitive stock control actions, allowing streamlined inventory management at your fingertips. The app has been optimized for speed, providing instant access to stock knowledge and handy on-site functionality.
## Features
- View and edit part and stock information with a blazingly fast interface
- Perform stock control actions on the go
- Barcode integrations simply stock operations
- Receive purchase orders and check in stock items
- And many more!
## Download
The InvenTree app can be downloaded from either the Android or Apple app stores, or accessed via the links below:
### Android
<span class='fab fa-android'></span> [Android Play Store](https://play.google.com/store/apps/details?id=inventree.inventree_app).
### iOS
<span class='fab fa-apple'></span> [Apple App Store](https://apps.apple.com/au/app/inventree/id1581731101#?platform=iphone)

View File

@@ -53,7 +53,9 @@ If a match is found, the app will navigate to the relevant page.
From the [Stock Location detail page](./stock.md#stock-location-view), multiple barcode actions may be available:
{{ image("app/barcode_stock_location_actions.png", "Stock location barcode actions") }}
{% with id="location-actions", url="app/barcode_stock_location_actions.png", maxheight="240px", description="Stock location barcode actions" %}
{% include 'img.html' %}
{% endwith %}
#### Assign Barcode
@@ -73,9 +75,11 @@ the *Scan Items Into Location* action allows you to scan items into the selected
### Stock Item Actions
From the [Stock Item detail page](./stock.md#details-tab), the following barcode actions may be available:
From the [Stock Item detail page](./stock.md#stock-item-detail-view), the following barcode actions may be available:
{{ image("app/barcode_stock_item_actions.png", "Stock item barcode actions") }}
{% with id="item-actions", url="app/barcode_stock_item_actions.png", maxheight="240px", description="Stock item barcode actions" %}
{% include 'img.html' %}
{% endwith %}
#### Assign Barcode
@@ -89,7 +93,9 @@ Scan the selected stock item into a stock location. Scanning a valid barcode ass
From the [Part detail page](./part.md#part-detail-view), the following barcode actions are available:
{{ image("app/barcode_part_actions.png", "Part barcode actions") }}
{% with id="part-actions", url="app/barcode_part_actions.png", maxheight="240px", description="Part barcode actions" %}
{% include 'img.html' %}
{% endwith %}
#### Assign Barcode
@@ -99,7 +105,9 @@ Assign a custom barcode to the selected part. Scanning a barcode (which is not a
From the [Purchase Order detail page](./po.md#purchase-order-detail) page, the following barcode actions are available:
{{ image("app/barcode_po_actions.png", "Purchase order barcode actions") }}
{% with id="po-actions", url="app/barcode_po_actions.png", maxheight="240px", description="Purchase order barcode actions" %}
{% include 'img.html' %}
{% endwith %}
#### Scan Received Parts

View File

@@ -8,20 +8,27 @@ Use of the InvenTree app assumes that you (the user) have access to an InvenTree
When first running the app, no profile has been configured. The *server* icon in the top-right corner of the home screen is <span style='color: red'>red</span>, indicating that there is no connection to an InvenTree server:
{{ image("app/initial.png", "No server configured") }}
{% with id="no_server", url="app/initial.png", maxheight="240px", description="No server configured" %}
{% include "img.html" %}
{% endwith %}
Press on the server icon to navigate to the server selection view:
{{ image("app/no_profiles.png", "No server configured") }}
{% with id="no_profiles", url="app/no_profiles.png", maxheight="240px", description="No server configured" %}
{% include "img.html" %}
{% endwith %}
### Create Server
!!! success "Server Profiles"
The app supports multiple server profiles, providing simple switching between different InvenTree servers and/or account profiles.
Press the {{ icon("circle-plus", color="blue") }} button in the bottom-right corner of the screen to create a new server profile.
Press the <span class='fas fa-plus-circle blue'></span> button in the bottom-right corner of the screen to create a new server profile.
{{ image("app/add_server_profile.png", "Add server profile") }}
{% with id="add_profile", url="app/add_server_profile.png", maxheight="240px", description="Add server" %}
{% include 'img.html' %}
{% endwith %}
Enter the required server details:
@@ -38,18 +45,24 @@ Once the server profile is created, you need to connect to the server. Simply sh
Alternatively, long press on the server profile to activate the context menu, then select *Connect to Server*.
When the app successfully connects to the server, a success message is briefly displayed at the bottom of the screen. A green {{ icon("circle-check", color="green") }} icon next to the server profile indicate that the profile is currently *selected* and also the connection was successful.
When the app successfully connects to the server, a success message is briefly displayed at the bottom of the screen. A green <span class='fas fa-check-circle green'></span> icon next to the server profile indicate that the profile is currently *selected* and also the connection was successful.
{{ image("app/connected.png", "Connected to server") }}
{% with id="connected", url="app/connected.png", maxheight="240px", description="Connected to server" %}
{% include 'img.html' %}
{% endwith %}
### Connection Failure
If (for whatever reason) the app does not successfully connect to the InvenTree server, a failure message is displayed, and a red {{ icon("circle-x", color="red") }} icon is displayed next to the server profile.
If (for whatever reason) the app does not successfully connect to the InvenTree server, a failure message is displayed, and a red <span class='fas fa-times-circle red'></span> icon is displayed next to the server profile.
{{ image("app/unauthorized.png", "Connection failure") }}
{% with id="failed", url="app/unauthorized.png", maxheight="240px", description="Connection failure" %}
{% include 'img.html' %}
{% endwith %}
In this case, the error message displayed at the bottom of the screen provides context as to why the app could not successfully connect to the server.
To edit the server profile details, long press on the server profile, and select *Edit Server Profile*:
{{ image("app/edit_server.png", "Edit server profile") }}
{% with id="edit", url="app/edit_server.png", maxheight="240px", description="Edit server profile" %}
{% include 'img.html' %}
{% endwith %}

View File

@@ -1,33 +0,0 @@
---
title: InvenTree Mobile App
---
{% with directory="appgallery", per_page=2 %}
{% include "carousel.html" %}
{% endwith %}
-----
The InvenTree Mobile App brings stock control to your pocket. Integrating seamlessly with the [InvenTree API](../api/index.md), the app provides immediate access to inventory data without requiring physical access to a computer.
Native barcode support provides a multitude of context-sensitive stock control actions, allowing streamlined inventory management at your fingertips. The app has been optimized for speed, providing instant access to stock knowledge and handy on-site functionality.
## Features
- View and edit part and stock information with a blazingly fast interface
- Perform stock control actions on the go
- Barcode integrations simply stock operations
- Receive purchase orders and check in stock items
- And many more!
## Download
The InvenTree app can be downloaded from either the Android or Apple app stores, or accessed via the links below:
### Android
<span class='fab fa-android'></span> [Android Play Store](https://play.google.com/store/apps/details?id=inventree.inventree_app).
### iOS
<span class='fab fa-apple'></span> [Apple App Store](https://apps.apple.com/au/app/inventree/id1581731101#?platform=iphone)

View File

@@ -7,13 +7,17 @@ title: App Navigation
The app *home screen* provides quick-access buttons for stock view and actions:
{{ image("app/home.png", "Home screen") }}
{% with id="home", url="app/home.png", maxheight="240px", description="Home screen" %}
{% include 'img.html' %}
{% endwith %}
## Tab Display
Some screens provide multiple tabbed views, which are displayed at the top of the screen:
{{ image("app/app_tabs.png", "App tabs") }}
{% with id="global_nav", url="app/app_tabs.png", maxheight="240px", description="App tabs" %}
{% include 'img.html' %}
{% endwith %}
Tabs can be navigated by pressing on the text of each tab, or by scrolling the screen left or right.
@@ -21,13 +25,17 @@ Tabs can be navigated by pressing on the text of each tab, or by scrolling the s
The *Global Action* buttons are visible on most screens, displayed in the bottom left corner of the screen:
{{ image("app/app_global_navigation.png", "Global navigation actions") }}
{% with id="global_nav", url="app/app_global_navigation.png", maxheight="240px", description="Global navigation actions" %}
{% include 'img.html' %}
{% endwith %}
### Open Drawer Menu
The {{ icon("list") }} action opens the *Drawer Menu*, which is a quick-access menu for global navigation:
The <span class='fas fa-list'></span> action opens the *Drawer Menu*, which is a quick-access menu for global navigation:
{{ image("app/drawer.png", "Open drawer menu") }}
{% with id="drawer", url="app/drawer.png", maxheight="240px", description="Open drawer menu" %}
{% include 'img.html' %}
{% endwith %}
The *Drawer Menu* can be accessed in the following ways:
@@ -36,17 +44,19 @@ The *Drawer Menu* can be accessed in the following ways:
### Search
The {{ icon("search", title="Search") }} action opens the [Search](./search.md) screen
The <span class='fas fa-search'></span> action opens the [Search](./search.md) screen
### Scan Barcode
The {{ icon("barcode", title="Scan") }} action opens the [barcode scan](./barcode.md#global-scan) window, which allows quick access to the barcode scanning functionality.
The <span class='fas fa-qrcode'></span> action opens the [barcode scan](./barcode.md#global-scan) window, which allows quick access to the barcode scanning functionality.
## Context Actions
Within a given view, certain context actions may be available. If there are contextual actions which can be performed, they are displayed in the bottom right corner:
{{ image("app/context_actions.png", "Context actions") }}
{% with id="drawer", url="app/context_actions.png", maxheight="240px", description="Context actions" %}
{% include 'img.html' %}
{% endwith %}
!!! tip "Barcode Actions"
Available barcode actions are displayed in a separate context action menu

View File

@@ -10,7 +10,9 @@ From the *home screen*, select *Parts* to open the top-level part category view.
The *Details* tab shows information about the selected part category. In particular, it shows the name and description of the category, a link to the parent category (if available) and a list of subcategories.
{{ image("app/part_category_detail.png", "Part Category") }}
{% with id="part-category", url="part_category_detail.png" %}
{% include "app_img.html" %}
{% endwith %}
#### Parent Category
@@ -24,35 +26,47 @@ If the current category has any subcategories, these are listed here. Select any
The *Parts* tab displays all the parts available in this category. Tap a displayed part to navigate to the part detail view.
{{ image("app/category_parts_tab.png", "Category Parts") }}
{% with id="cat-parts", url="category_parts_tab.png" %}
{% include "app_img.html" %}
{% endwith %}
The list of available parts can be filtered using the input box at the top of the screen:
{{ image("app/category_parts_filter.png", "Category Parts Filter") }}
{% with id="cat-parts-filter", url="category_parts_filter.png" %}
{% include "app_img.html" %}
{% endwith %}
### Context Actions
The following *Context Actions* are available for the selected category:
{{ image("app/category_actions_tab.png", "Category Actions") }}
{% with id="cat-actions", url="category_actions_tab.png" %}
{% include "app_img.html" %}
{% endwith %}
#### New Category
Create a new subcategory under the current category:
{{ image("app/new_category.jpg", "New Category") }}
{% with id="cat-new-cat", url="new_category.jpg" %}
{% include "app_img.html" %}
{% endwith %}
#### New Part
Create a new part within the current category:
{{ image("app/new_part.jpg", "New Part") }}
{% with id="cat-new-part", url="new_part.jpg" %}
{% include "app_img.html" %}
{% endwith %}
### Edit Category
Select the *Edit* button in the top right corner of the screen to edit the details for the selected part category:
{{ image("app/part_category_edit.jpg", "Edit Category") }}
{% with id="cat-edit", url="part_category_edit.jpg" %}
{% include "app_img.html" %}
{% endwith %}
!!! info "Permission Required"
If the user does not have permission to edit part details, this button will be hidden
@@ -63,7 +77,9 @@ In the part category display screen, there are three tabs of information availab
The *Part Detail* view displays information about a single part:
{{ image("app/part_details.png", "Part Detail") }}
{% with id="part-details", url="part_details.png" %}
{% include "app_img.html" %}
{% endwith %}
### Details Tab
@@ -81,13 +97,17 @@ The *stock* tile shows the total quantity of stock available for the part. Tap o
Tap on the *notes* tile to view (and edit) the notes for this part:
{{ image("app/part_notes.jpg", "Part Notes") }}
{% with id="part-notes", url="part_notes.jpg" %}
{% include "app_img.html" %}
{% endwith %}
#### Attachments
Tap on the *attachments* tile to view the file attachments for this part:
{{ image("app/part_attachments.jpg", "Part Attachments") }}
{% with id="part-attachments", url="part_attachments.jpg" %}
{% include "app_img.html" %}
{% endwith %}
New attachments can be uploaded by tapping on the icons in the top right of the screen.
@@ -97,7 +117,9 @@ Select a particular attachment file to downloaded it to the local device.
The *Stock* tab displays all the stock items available for this part. Tap on a particular stock item to navigate to a detail view for that item.
{{ image("app/part_stock.png", "Part Stock") }}
{% with id="part-stock", url="part_stock.png" %}
{% include "app_img.html" %}
{% endwith %}
The list of available stock items can be filtered using the input box at the top of the screen.
@@ -109,13 +131,17 @@ The *Actions* tab displays the available actions for the selected part:
Create a new stock item for this part:
{{ image("app/new_stock_item.jpg", "New Stock Item") }}
{% with id="part-stock-new", url="new_stock_item.jpg" %}
{% include "app_img.html" %}
{% endwith %}
### Edit Part
To edit the part details, select the *Edit* button in the top right corner of the screen:
{{ image("app/part_edit.jpg", "Edit Part") }}
{% with id="part-edit", url="part_edit.jpg" %}
{% include "app_img.html" %}
{% endwith %}
!!! info "Permission Required"
If the user does not have permission to edit part details, this button will be hidden
@@ -124,6 +150,8 @@ To edit the part details, select the *Edit* button in the top right corner of th
Tap the image of the part (displayed at the top left of the screen) to launch the part image view:
{{ image("app/part_image.jpg", "Part Image") }}
{% with id="part-image", url="part_image.jpg" %}
{% include "app_img.html" %}
{% endwith %}
A full-screen view of the image is displayed. The user can also upload a new image for the part, either selecting an image from the device, or taking a new picture with the device's camera.

View File

@@ -6,7 +6,9 @@ title: Purchase Orders
The purchase order list display lists all purchase orders:
{{ image("app/po_list.png", "Purchase order list") }}
{% with id="po_list", url="app/po_list.png", maxheight="240px", description="Purchase order list" %}
{% include "img.html" %}
{% endwith %}
Select an individual purchase order to display the detail view for that order.
@@ -16,19 +18,25 @@ Displayed purchase orders can be subsequently filtered using the search input at
## Purchase Order Detail
{{ image("app/po_detail.png", "Purchase order detail") }}
{% with id="po_detail", url="app/po_detail.png", maxheight="240px", description="Purchase order details" %}
{% include "img.html" %}
{% endwith %}
### Edit Order Details
From the detail view, select the *Edit* button in the top-right of the screen. This opens the purchase order editing display:
{{ image("app/po_edit.png", "Edit purchase order") }}
{% with id="edit_po", url="app/po_edit.png", maxheight="240px", description="Edit purchase order" %}
{% include "img.html" %}
{% endwith %}
### Line Items
The *Line Items* tab shows the line items associated with this purchase order:
{{ image("app/po_lines.png", "Purchase order line items") }}
{% with id="po_lines", url="app/po_lines.png", maxheight="240px", description="Purchase order line items" %}
{% include "img.html" %}
{% endwith %}
Long press on a particular line item to receive the item into stock.
@@ -36,4 +44,6 @@ Long press on a particular line item to receive the item into stock.
Once items have been received into stock against a particular purchase order, they are displayed in the *Stock Items* tab:
{{ image("app/po_stock.png", "Purchase order stock items") }}
{% with id="po_stock", url="app/po_stock.png", maxheight="240px", description="Purchase order stock items" %}
{% include "img.html" %}
{% endwith %}

View File

@@ -6,5 +6,10 @@ title: App Search
The global search screen provides quick search functionality across the connected InvenTree database. Entering a search term will return multiple search results, as shown in the examples below:
{{ image("app/search_1.png", "Search results") }}
{{ image("app/search_2.png", "Search results") }}
{% with id="search_1", url="app/search_1.png", maxheight="240px", description="Search results" %}
{% include 'img.html' %}
{% endwith %}
{% with id="search_2", url="app/search_2.png", maxheight="240px", description="Search results" %}
{% include 'img.html' %}
{% endwith %}

View File

@@ -17,13 +17,18 @@ The main settings view is shown below, and provides the following options:
| [Part](#part-settings) | Configure part management options |
| About | Display app version information |
{{ image("app/settings.png", "Settings view") }}
{% with id="settings_view", url="app/settings.png", maxheight="240px", description="Settings view" %}
{% include 'img.html' %}
{% endwith %}
## App Settings
The *App Settings* view provides configuration options for the InvenTree app:
{{ image("app/app_settings.png", "App settings") }}
{% with id="app_settings", url="app/app_settings.png", maxheight="240px", description="App Settings" %}
{% include 'img.html' %}
{% endwith %}
### App Settings
@@ -52,7 +57,9 @@ Configure audible app notifications:
The *Barcode Settings* view allows you to configure options relating to [barcode scanning](./barcode.md):
{{ image("app/barcode_settings.png", "Barcode settings") }}
{% with id="barcode_settings", url="app/barcode_settings.png", maxheight="240px", description="Barcode Settings" %}
{% include 'img.html' %}
{% endwith %}
| Option | Description |
| --- | --- |
@@ -63,7 +70,9 @@ The *Barcode Settings* view allows you to configure options relating to [barcode
The *Home Screen* view allows you to configure display options for the app 'home screen':
{{ image("app/home_settings.png", "Home screen settings") }}
{% with id="home_settings", url="app/home_settings.png", maxheight="240px", description="Home Screen Settings" %}
{% include 'img.html' %}
{% endwith %}
| Option | Description |
| --- | --- |

View File

@@ -6,7 +6,9 @@ title: Sales Orders
The sales order list display shows all sales orders:
{{ image("app/so_list.png", "Sales order list") }}
{% with id="so_list", url="app/so_list.png", maxheight="240px", description="Sales order list" %}
{% include "img.html" %}
{% endwith %}
Select an individual sales order to display the detail view for that order.
@@ -18,7 +20,9 @@ Displayed sales orders can be subsequently filtered using the search input at th
Select an individual order to show the detailed view for that order:
{{ image("app/so_detail.png", "Sales order detail") }}
{% with id="so_detail", url="app/so_detail.png", maxheight="240px", description="Sales order details" %}
{% include "img.html" %}
{% endwith %}
### Edit Order Details
@@ -28,4 +32,6 @@ From the detail view, select the *Edit* button in the top-right of the screen. T
View the line items associated with the selected order:
{{ image("app/so_lines.png", "Sales order line items") }}
{% with id="so_lines", url="app/so_lines.png", maxheight="240px", description="Sales order lines" %}
{% include "img.html" %}
{% endwith %}

View File

@@ -10,7 +10,9 @@ From the *home screen*, select *Stock* to open the top-level stock location view
The *Details* tab shows information about the selected stock location.
{{ image("app/location_detail.png", "Stock Location") }}
{% with id="loc-detail", url="location_detail.png" %}
{% include "app_img.html" %}
{% endwith %}
#### Parent Location
@@ -24,29 +26,44 @@ If the current stock location has any sublocations, they are listed here. Select
The *Stock* tab displays all the stock items available in this location. Tap a displayed stock item to navigate to the stock item detail view.
{{ image("app/location_stock.png", "Location Stock") }}
{% with id="loc-stock", url="location_stock.png" %}
{% include "app_img.html" %}
{% endwith %}
The list of available stock items can be filtered using the input box at the top of the screen:
{{ image("app/location_stock_filter.jpg", "Location Stock Filter") }}
{% with id="loc-filter", url="location_stock_filter.jpg" %}
{% include "app_img.html" %}
{% endwith %}
### Context Actions
The following *Context Actions* are available for the selected location:
{{ image("app/location_actions.png", "Location Actions") }}
{% with id="loc-actions", url="location_actions.png" %}
{% include "app_img.html" %}
{% endwith %}
#### New Location
Create a new location under the current location:
{{ image("app/new_location.jpg", "New Location") }}
{% with id="loc-new", url="new_location.jpg" %}
{% include "app_img.html" %}
{% endwith %}
#### New Stock Item
Create a new stock item in the current location:
{{ image("app/new_stock_item_from_location.jpg", "New Stock Item") }}
{% with id="loc-new-stock", url="new_stock_item_from_location.jpg" %}
{% include "app_img.html" %}
{% endwith %}
#### Scan Stock Items Into Location
@@ -57,7 +74,10 @@ Use the barcode scanner to scan a stock item into the current location.
The *Stock Item Detail* view displays information about a single stock item:
{{ image("app/stock_detail.png", "Stock Item") }}
{% with id="stock-detail", url="stock_detail.png" %}
{% include "app_img.html" %}
{% endwith %}
### Details Tab
@@ -79,34 +99,44 @@ Tap on the notes tile to display and edit the notes for this stock item
The *actions* tab displays the available actions for the selected stock item:
{{ image("app/stock_actions.png", "Stock Actions") }}
{% with id="stock-actions", url="stock_actions.png" %}
{% include "app_img.html" %}
{% endwith %}
#### Count Stock
Select the *Count Stock* action to validate the current number of items in stock. Use this option to perform a quick stocktake!
{{ image("app/stock_count.png", "Count Stock") }}
{% with id="stock-count", url="stock_count.png" %}
{% include "app_img.html" %}
{% endwith %}
!!! info "Serialized Stock"
The *count stock* action is not available for serialized stock items, as they have a fixed quantity of 1
#### Remove Stock
Select this action to remove a certain quantity from the selected stock item. For example, if there are 12 items available, and you take 3 items, the listed quantity will be reduced to 9 items.
Select this action to remove a certain quantity from the selected stock item. For example, if there are 12 items available, and you take 3 items, the listed quantity will be reduced to 9 itemes.
{{ image("app/stock_remove.png", "Remove Stock") }}
{% with id="stock-remove", url="stock_remove.png" %}
{% include "app_img.html" %}
{% endwith %}
#### Add Stock
Select this action to add a certain quantity to the selected stock item. For example, if there are 12 items available, and you add 3 items, the listed quantity will be increased to 15 items.
{{ image("app/stock_add.png", "Add Stock") }}
{% with id="stock-add", url="stock_add.png" %}
{% include "app_img.html" %}
{% endwith %}
#### Transfer Stock
Transfer (move) the stock item to a new location:
{{ image("app/stock_transfer.png", "Transfer Stock") }}
{% with id="stock-transfer", url="stock_transfer.png" %}
{% include "app_img.html" %}
{% endwith %}
#### Scan Into Location
@@ -122,13 +152,20 @@ This barcode can then be used to track the stock item.
#### Print Label
If the server supports [label printing plugins](../plugins/mixins/label.md), then an option to print a label for the selected stock item:
If the server supports [label printing plugins](../extend/plugins/label.md), then an option to print a label for the selected stock item:
{{ image("app/stock_print_label_1.png", "Print Label") }}
{{ image("app/stock_print_label_2.png", "Print Label") }}
{% with id="label_print_1", url="stock_print_label_1.png", description="Print label via plugin" %}
{% include 'app_img.html' %}
{% endwith %}
{% with id="label_print_2", url="stock_print_label_2.png", description="Print label via plugin" %}
{% include 'app_img.html' %}
{% endwith %}
### Edit Stock Item
To edit the stock item details, select the *Edit* button in the top right corner of the screen:
{{ image("app/stock_edit.jpg", "Edit Stock Item") }}
{% with id="stock-edit", url="stock_edit.jpg" %}
{% include "app_img.html" %}
{% endwith %}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 408 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 223 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 53 KiB

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