PyInventory 0.22.1__tar.gz → 0.23.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyinventory-0.22.1 → pyinventory-0.23.1}/.github/workflows/tests.yml +2 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/PKG-INFO +17 -5
- {pyinventory-0.22.1 → pyinventory-0.23.1}/README.md +16 -4
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/__init__.py +1 -1
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/admin/item.py +51 -3
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/admin/memo.py +1 -2
- pyinventory-0.23.1/inventory/admin/tests/test_item.py +134 -0
- pyinventory-0.23.1/inventory/admin/tests/test_item_happy_path_1.snapshot.html +48 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/models/__init__.py +1 -1
- pyinventory-0.23.1/inventory/static/PyInventory_Logo.svg +10652 -0
- pyinventory-0.23.1/inventory/static/inventory.css +23 -0
- pyinventory-0.23.1/inventory/templates/admin/item/mass_change_category_action.html +32 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/templates/admin/base_site.html +3 -2
- pyinventory-0.23.1/inventory_project/tests/__init__.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/tests/test_admin_item_auto_group_items_1.snapshot.html +3 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/tests/test_admin_item_normal_user_create_minimal_item_2.snapshot.html +7 -8
- {pyinventory-0.22.1 → pyinventory-0.23.1}/pyproject.toml +2 -4
- {pyinventory-0.22.1 → pyinventory-0.23.1}/uv.lock +166 -102
- pyinventory-0.22.1/inventory/admin/tagulous_fix.py +0 -45
- {pyinventory-0.22.1 → pyinventory-0.23.1}/.editorconfig +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/.gitignore +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/.idea/.gitignore +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/.pre-commit-config.yaml +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/.pre-commit-hooks.yaml +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/.run/Template Django tests.run.xml +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/.run/Template Python.run.xml +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/.run/manage.py --help.run.xml +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/.run/manage.py make_messages.run.xml +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/.run/manage.py update_req.run.xml +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/.run/unittests ___all___.run.xml +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/AUTHORS +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/LICENSE +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/dist/.gitignore +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/admin/__init__.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/admin/base.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/admin/location.py +0 -0
- {pyinventory-0.22.1/inventory/management → pyinventory-0.23.1/inventory/admin/tests}/__init__.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/apps.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/checks.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/ckeditor_upload.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/constants.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/context_processors.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/forms.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/locale/ca/LC_MESSAGES/django.mo +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/locale/ca/LC_MESSAGES/django.po +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/locale/de/LC_MESSAGES/django.mo +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/locale/de/LC_MESSAGES/django.po +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/locale/en/LC_MESSAGES/django.mo +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/locale/en/LC_MESSAGES/django.po +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/locale/es/LC_MESSAGES/django.mo +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/locale/es/LC_MESSAGES/django.po +0 -0
- {pyinventory-0.22.1/inventory/management/commands → pyinventory-0.23.1/inventory/management}/__init__.py +0 -0
- {pyinventory-0.22.1/inventory/migrations → pyinventory-0.23.1/inventory/management/commands}/__init__.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/management/commands/seed_data.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/management/commands/tree.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/middlewares.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/migrations/0001_initial.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/migrations/0002_auto_20201017_2211.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/migrations/0003_auto_20201024_1830.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/migrations/0004_item_user_images.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/migrations/0005_serve_uploads_by_django_tools.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/migrations/0006_refactor_image_model.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/migrations/0007_add_file_attachment.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/migrations/0008_last_check_datetime.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/migrations/0009_add_memo.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/migrations/0010_version_protect_models.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/migrations/0011_parent_tree1.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/migrations/0012_parent_tree2.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/migrations/0013_alter_itemmodel_location.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/migrations/0014_alter_itemmodel_description_and_more.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/migrations/0015_itemmaincategory_itemmodel_category.py +0 -0
- {pyinventory-0.22.1/inventory/tests/fixtures → pyinventory-0.23.1/inventory/migrations}/__init__.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/models/base.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/models/item.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/models/links.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/models/location.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/models/memo.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/parent_tree.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/permissions.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/persistent_filters.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/request_dict.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/signals.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/string_utils.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/templates/admin/item/related_items.html +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/templates/admin/location/items.html +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/tests/__init__.py +0 -0
- {pyinventory-0.22.1/inventory_project/settings → pyinventory-0.23.1/inventory/tests/fixtures}/__init__.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/tests/fixtures/users.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/tests/test_admin_location.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/tests/test_admin_location_empty_change_list_1.snapshot.html +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/tests/test_item_images.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/tests/test_link_model.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/tests/test_management_command_seed_data.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/tests/test_management_command_tree.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/tests/test_parent_tree.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory/tests/test_parent_tree_model.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/__init__.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/__main__.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/middlewares.py +0 -0
- {pyinventory-0.22.1/inventory_project/tests → pyinventory-0.23.1/inventory_project/settings}/__init__.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/settings/local.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/settings/prod.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/settings/tests.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/templates/admin/login.html +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/tests/fixtures.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/tests/mocks.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/tests/playwright_utils.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/tests/test_admin.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/tests/test_admin_item.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/tests/test_admin_item_login_1.snapshot.html +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/tests/test_admin_item_normal_user_create_minimal_item_1.snapshot.html +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/tests/test_admin_memo.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/tests/test_admin_memo_normal_user_create_minimal_item_1.snapshot.html +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/tests/test_admin_superuser_admin_index_1.snapshot.html +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/tests/test_inventory_commands.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/tests/test_inventory_commands_help_1.snapshot.txt +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/tests/test_migrations.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/tests/test_models_item.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/tests/test_playwright_admin.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/tests/test_project_setup.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/tests/test_readme_history.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/urls.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/inventory_project/wsgi.py +0 -0
- {pyinventory-0.22.1 → pyinventory-0.23.1}/manage.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyInventory
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.23.1
|
|
4
4
|
Summary: Web based management to catalog things including state and location etc. using Python/Django.
|
|
5
5
|
Project-URL: Documentation, https://github.com/jedie/PyInventory
|
|
6
6
|
Project-URL: Source, https://github.com/jedie/PyInventory
|
|
@@ -28,7 +28,10 @@ Requires-Dist: pillow
|
|
|
28
28
|
Requires-Dist: requests
|
|
29
29
|
Description-Content-Type: text/markdown
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
<h1>
|
|
32
|
+
<img src="https://raw.githubusercontent.com/jedie/PyInventory/main/inventory/static/PyInventory_Logo.svg" width="96px" alt="Logo">
|
|
33
|
+
PyInventory
|
|
34
|
+
</h1>
|
|
32
35
|
|
|
33
36
|
Web based management to catalog things including state and location etc. using Python/Django.
|
|
34
37
|
Store information in WYSIWYG-HTML-Editor field and tag them and add Files, Images and Links to them.
|
|
@@ -196,6 +199,15 @@ To make a new release, do this:
|
|
|
196
199
|
|
|
197
200
|
[comment]: <> (✂✂✂ auto generated history start ✂✂✂)
|
|
198
201
|
|
|
202
|
+
* [v0.23.1](https://github.com/jedie/PyInventory/compare/v0.23.0...v0.23.1)
|
|
203
|
+
* 2025-11-28 - Update README.md
|
|
204
|
+
* 2025-11-28 - Add logo
|
|
205
|
+
* [v0.23.0](https://github.com/jedie/PyInventory/compare/v0.22.1...v0.23.0)
|
|
206
|
+
* 2025-11-25 - Enhance 'Change category for selected items' and add tests for it
|
|
207
|
+
* 2025-11-25 - Update requirements
|
|
208
|
+
* 2025-11-25 - Remove django-tagulous work-a-round, because it's fixed.
|
|
209
|
+
* 2025-11-19 - Add admin action to change the category of selected items
|
|
210
|
+
* 2025-11-19 - Remove "GHSA-4xh5-x5gv-qwph" exception
|
|
199
211
|
* [v0.22.1](https://github.com/jedie/PyInventory/compare/v0.22.0...v0.22.1)
|
|
200
212
|
* 2025-11-18 - Fix #207 "All" Category can't be selected
|
|
201
213
|
* 2025-11-18 - Update requirements
|
|
@@ -203,6 +215,9 @@ To make a new release, do this:
|
|
|
203
215
|
* 2025-10-16 - Add tests for PersistentRelatedFieldListFilter
|
|
204
216
|
* 2025-09-21 - NEW: Add a persistent "Main Category"
|
|
205
217
|
* 2025-09-21 - fix for django-admin-sortable2/issues/363
|
|
218
|
+
|
|
219
|
+
<details><summary>Expand older history entries ...</summary>
|
|
220
|
+
|
|
206
221
|
* [v0.21.4](https://github.com/jedie/PyInventory/compare/v0.21.3...v0.21.4)
|
|
207
222
|
* 2025-09-21 - Because of PyPi download errors: release as v0.21.4
|
|
208
223
|
* [v0.21.3](https://github.com/jedie/PyInventory/compare/v0.21.2...v0.21.3)
|
|
@@ -217,9 +232,6 @@ To make a new release, do this:
|
|
|
217
232
|
* 2025-09-20 - pre-commit: remove "default_install_hook_types"
|
|
218
233
|
* 2025-09-20 - Remove obsolete config files
|
|
219
234
|
* 2025-09-20 - Update ReadmeHistoryTestCase
|
|
220
|
-
|
|
221
|
-
<details><summary>Expand older history entries ...</summary>
|
|
222
|
-
|
|
223
235
|
* [v0.21.2](https://github.com/jedie/PyInventory/compare/v0.21.1...v0.21.2)
|
|
224
236
|
* 2025-09-09 - Update project, e.g.: Darker -> Ruff and fix tests
|
|
225
237
|
* 2025-05-01 - Fix local dev server: Don't enforce https
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
<h1>
|
|
2
|
+
<img src="https://raw.githubusercontent.com/jedie/PyInventory/main/inventory/static/PyInventory_Logo.svg" width="96px" alt="Logo">
|
|
3
|
+
PyInventory
|
|
4
|
+
</h1>
|
|
2
5
|
|
|
3
6
|
Web based management to catalog things including state and location etc. using Python/Django.
|
|
4
7
|
Store information in WYSIWYG-HTML-Editor field and tag them and add Files, Images and Links to them.
|
|
@@ -166,6 +169,15 @@ To make a new release, do this:
|
|
|
166
169
|
|
|
167
170
|
[comment]: <> (✂✂✂ auto generated history start ✂✂✂)
|
|
168
171
|
|
|
172
|
+
* [v0.23.1](https://github.com/jedie/PyInventory/compare/v0.23.0...v0.23.1)
|
|
173
|
+
* 2025-11-28 - Update README.md
|
|
174
|
+
* 2025-11-28 - Add logo
|
|
175
|
+
* [v0.23.0](https://github.com/jedie/PyInventory/compare/v0.22.1...v0.23.0)
|
|
176
|
+
* 2025-11-25 - Enhance 'Change category for selected items' and add tests for it
|
|
177
|
+
* 2025-11-25 - Update requirements
|
|
178
|
+
* 2025-11-25 - Remove django-tagulous work-a-round, because it's fixed.
|
|
179
|
+
* 2025-11-19 - Add admin action to change the category of selected items
|
|
180
|
+
* 2025-11-19 - Remove "GHSA-4xh5-x5gv-qwph" exception
|
|
169
181
|
* [v0.22.1](https://github.com/jedie/PyInventory/compare/v0.22.0...v0.22.1)
|
|
170
182
|
* 2025-11-18 - Fix #207 "All" Category can't be selected
|
|
171
183
|
* 2025-11-18 - Update requirements
|
|
@@ -173,6 +185,9 @@ To make a new release, do this:
|
|
|
173
185
|
* 2025-10-16 - Add tests for PersistentRelatedFieldListFilter
|
|
174
186
|
* 2025-09-21 - NEW: Add a persistent "Main Category"
|
|
175
187
|
* 2025-09-21 - fix for django-admin-sortable2/issues/363
|
|
188
|
+
|
|
189
|
+
<details><summary>Expand older history entries ...</summary>
|
|
190
|
+
|
|
176
191
|
* [v0.21.4](https://github.com/jedie/PyInventory/compare/v0.21.3...v0.21.4)
|
|
177
192
|
* 2025-09-21 - Because of PyPi download errors: release as v0.21.4
|
|
178
193
|
* [v0.21.3](https://github.com/jedie/PyInventory/compare/v0.21.2...v0.21.3)
|
|
@@ -187,9 +202,6 @@ To make a new release, do this:
|
|
|
187
202
|
* 2025-09-20 - pre-commit: remove "default_install_hook_types"
|
|
188
203
|
* 2025-09-20 - Remove obsolete config files
|
|
189
204
|
* 2025-09-20 - Update ReadmeHistoryTestCase
|
|
190
|
-
|
|
191
|
-
<details><summary>Expand older history entries ...</summary>
|
|
192
|
-
|
|
193
205
|
* [v0.21.2](https://github.com/jedie/PyInventory/compare/v0.21.1...v0.21.2)
|
|
194
206
|
* 2025-09-09 - Update project, e.g.: Darker -> Ruff and fix tests
|
|
195
207
|
* 2025-05-01 - Fix local dev server: Don't enforce https
|
|
@@ -2,8 +2,11 @@ import logging
|
|
|
2
2
|
|
|
3
3
|
import tagulous
|
|
4
4
|
from adminsortable2.admin import SortableAdminBase, SortableAdminMixin, SortableInlineAdminMixin
|
|
5
|
+
from django import forms
|
|
5
6
|
from django.conf import settings
|
|
6
|
-
from django.contrib import admin
|
|
7
|
+
from django.contrib import admin, messages
|
|
8
|
+
from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME
|
|
9
|
+
from django.shortcuts import render
|
|
7
10
|
from django.template.loader import render_to_string
|
|
8
11
|
from django.urls import reverse
|
|
9
12
|
from django.utils.html import format_html
|
|
@@ -18,7 +21,6 @@ from inventory.admin.base import (
|
|
|
18
21
|
LimitTreeDepthListFilter,
|
|
19
22
|
UserInlineMixin,
|
|
20
23
|
)
|
|
21
|
-
from inventory.admin.tagulous_fix import TagulousModelAdminFix
|
|
22
24
|
from inventory.models import ItemLinkModel, ItemModel
|
|
23
25
|
from inventory.models.item import ItemFileModel, ItemImageModel, ItemMainCategory
|
|
24
26
|
from inventory.persistent_filters import PersistentRelatedFieldListFilter
|
|
@@ -51,8 +53,53 @@ class ItemModelResource(ModelResource):
|
|
|
51
53
|
model = ItemModel
|
|
52
54
|
|
|
53
55
|
|
|
56
|
+
class ChangeCategoryForm(forms.Form):
|
|
57
|
+
category = forms.ModelChoiceField(
|
|
58
|
+
queryset=ItemMainCategory.objects.all(),
|
|
59
|
+
label=_('New category'),
|
|
60
|
+
required=True,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@admin.action(description=_('Change category for selected items'))
|
|
65
|
+
def mass_change_category_action(modeladmin, request, queryset):
|
|
66
|
+
item_count = queryset.count()
|
|
67
|
+
assert item_count > 0, 'No items selected for mass category change.'
|
|
68
|
+
if 'category' in request.POST:
|
|
69
|
+
form = ChangeCategoryForm(request.POST)
|
|
70
|
+
if form.is_valid():
|
|
71
|
+
category = form.cleaned_data['category']
|
|
72
|
+
updated = queryset.update(category=category)
|
|
73
|
+
messages.info(
|
|
74
|
+
request,
|
|
75
|
+
_('%(count)d items have been assigned to the category "%(category)s".')
|
|
76
|
+
% {'count': updated, 'category': str(category)},
|
|
77
|
+
)
|
|
78
|
+
return None
|
|
79
|
+
else:
|
|
80
|
+
form = ChangeCategoryForm()
|
|
81
|
+
|
|
82
|
+
# Collect currently used categories from selected items:
|
|
83
|
+
used_categories = queryset.order_by('category__name').values_list('category__name', flat=True).distinct()
|
|
84
|
+
|
|
85
|
+
return render(
|
|
86
|
+
request,
|
|
87
|
+
'admin/item/mass_change_category_action.html',
|
|
88
|
+
context={
|
|
89
|
+
'title': _('Change category for selected items'),
|
|
90
|
+
'opts': modeladmin.model._meta,
|
|
91
|
+
'item_count': item_count,
|
|
92
|
+
'items': queryset,
|
|
93
|
+
'used_categories': used_categories,
|
|
94
|
+
'form': form,
|
|
95
|
+
'action_checkbox_name': ACTION_CHECKBOX_NAME,
|
|
96
|
+
**modeladmin.admin_site.each_context(request),
|
|
97
|
+
},
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
54
101
|
@admin.register(ItemModel)
|
|
55
|
-
class ItemModelAdmin(
|
|
102
|
+
class ItemModelAdmin(ImportExportMixin, SortableAdminBase, BaseUserAdmin):
|
|
56
103
|
@admin.display(description=_('Related items'))
|
|
57
104
|
def related_items(self, obj):
|
|
58
105
|
if obj.pk is None:
|
|
@@ -167,6 +214,7 @@ class ItemModelAdmin(TagulousModelAdminFix, ImportExportMixin, SortableAdminBase
|
|
|
167
214
|
autocomplete_fields = ('parent', 'location')
|
|
168
215
|
readonly_fields = ('id', 'create_dt', 'update_dt', 'user', 'related_items')
|
|
169
216
|
inlines = (ItemImageModelInline, ItemFileModelInline, ItemLinkModelInline)
|
|
217
|
+
actions = (mass_change_category_action,)
|
|
170
218
|
|
|
171
219
|
|
|
172
220
|
tagulous.admin.enhance(ItemModel, ItemModelAdmin)
|
|
@@ -8,7 +8,6 @@ from import_export.admin import ImportExportMixin
|
|
|
8
8
|
from import_export.resources import ModelResource
|
|
9
9
|
|
|
10
10
|
from inventory.admin.base import BaseFileModelInline, BaseImageModelInline, BaseUserAdmin, UserInlineMixin
|
|
11
|
-
from inventory.admin.tagulous_fix import TagulousModelAdminFix
|
|
12
11
|
from inventory.models import MemoLinkModel, MemoModel
|
|
13
12
|
from inventory.models.memo import MemoFileModel, MemoImageModel
|
|
14
13
|
|
|
@@ -35,7 +34,7 @@ class MemoModelResource(ModelResource):
|
|
|
35
34
|
|
|
36
35
|
|
|
37
36
|
@admin.register(MemoModel)
|
|
38
|
-
class MemoModelAdmin(
|
|
37
|
+
class MemoModelAdmin(ImportExportMixin, SortableAdminBase, BaseUserAdmin):
|
|
39
38
|
def get_max_order(self, request, obj=None):
|
|
40
39
|
# Work-a-round for: https://github.com/jrief/django-admin-sortable2/issues/341
|
|
41
40
|
return 0
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
from unittest import mock
|
|
2
|
+
from uuid import UUID
|
|
3
|
+
|
|
4
|
+
from bx_django_utils.test_utils.html_assertion import HtmlAssertionMixin, assert_html_response_snapshot
|
|
5
|
+
from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME
|
|
6
|
+
from django.template.defaulttags import CsrfTokenNode, NowNode
|
|
7
|
+
from django.test import TestCase, override_settings
|
|
8
|
+
from django.urls import reverse
|
|
9
|
+
from model_bakery import baker
|
|
10
|
+
|
|
11
|
+
from inventory.admin.item import mass_change_category_action
|
|
12
|
+
from inventory.models import ItemMainCategory, ItemModel
|
|
13
|
+
from inventory_project.tests.fixtures import get_normal_user
|
|
14
|
+
from inventory_project.tests.mocks import MockInventoryVersionString
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@override_settings(SECURE_SSL_REDIRECT=False)
|
|
18
|
+
class MassChangeCategoryActionAdminTest(HtmlAssertionMixin, TestCase):
|
|
19
|
+
maxDiff = None
|
|
20
|
+
|
|
21
|
+
def test_happy_path(self):
|
|
22
|
+
normaluser = get_normal_user()
|
|
23
|
+
self.client.force_login(normaluser)
|
|
24
|
+
|
|
25
|
+
category1 = baker.make(ItemMainCategory, order=0, id=1, name='Category 1')
|
|
26
|
+
category2 = baker.make(ItemMainCategory, order=1, id=2, name='Category 2')
|
|
27
|
+
baker.make(
|
|
28
|
+
ItemModel,
|
|
29
|
+
name='A',
|
|
30
|
+
user=normaluser,
|
|
31
|
+
id=UUID('80dddef9-0000-0000-0000-000000000001'),
|
|
32
|
+
category=category1,
|
|
33
|
+
).full_clean()
|
|
34
|
+
baker.make(
|
|
35
|
+
ItemModel,
|
|
36
|
+
name='B',
|
|
37
|
+
user=normaluser,
|
|
38
|
+
id=UUID('80dddef9-0000-0000-0000-000000000002'),
|
|
39
|
+
category=category1,
|
|
40
|
+
).full_clean()
|
|
41
|
+
baker.make(
|
|
42
|
+
ItemModel,
|
|
43
|
+
name='C',
|
|
44
|
+
user=normaluser,
|
|
45
|
+
id=UUID('80dddef9-0000-0000-0000-000000000003'),
|
|
46
|
+
category=category2,
|
|
47
|
+
).full_clean()
|
|
48
|
+
baker.make(
|
|
49
|
+
ItemModel,
|
|
50
|
+
name='D',
|
|
51
|
+
user=normaluser,
|
|
52
|
+
id=UUID('80dddef9-0000-0000-0000-000000000004'),
|
|
53
|
+
category=category2,
|
|
54
|
+
).full_clean()
|
|
55
|
+
|
|
56
|
+
url = reverse('admin:inventory_itemmodel_changelist')
|
|
57
|
+
self.assertEqual(url, '/admin/inventory/itemmodel/')
|
|
58
|
+
|
|
59
|
+
########################################################################################
|
|
60
|
+
# Snapshot the Form:
|
|
61
|
+
with (
|
|
62
|
+
mock.patch.object(NowNode, 'render', return_value='MockedNowNode'),
|
|
63
|
+
mock.patch.object(CsrfTokenNode, 'render', return_value='MockedCsrfTokenNode'),
|
|
64
|
+
MockInventoryVersionString(),
|
|
65
|
+
):
|
|
66
|
+
response = self.client.post(
|
|
67
|
+
'/admin/inventory/itemmodel/',
|
|
68
|
+
data={
|
|
69
|
+
ACTION_CHECKBOX_NAME: [
|
|
70
|
+
'80dddef9-0000-0000-0000-000000000002',
|
|
71
|
+
'80dddef9-0000-0000-0000-000000000003',
|
|
72
|
+
],
|
|
73
|
+
'action': mass_change_category_action.__name__,
|
|
74
|
+
},
|
|
75
|
+
)
|
|
76
|
+
self.assertEqual(response.status_code, 200)
|
|
77
|
+
self.assertTemplateUsed(response, 'admin/item/mass_change_category_action.html')
|
|
78
|
+
self.assert_html_parts(
|
|
79
|
+
response,
|
|
80
|
+
parts=(
|
|
81
|
+
'<title>Change category for selected items | PyInventory vMockedVersionString</title>',
|
|
82
|
+
'<p>Number of selected items: 2</p>',
|
|
83
|
+
'<label for="id_category">New category:</label>',
|
|
84
|
+
'<input type="hidden" name="action" value="mass_change_category_action">',
|
|
85
|
+
),
|
|
86
|
+
)
|
|
87
|
+
assert_html_response_snapshot(response, query_selector='#content', validate=False)
|
|
88
|
+
|
|
89
|
+
########################################################################################
|
|
90
|
+
# Perform the action
|
|
91
|
+
|
|
92
|
+
def get_info():
|
|
93
|
+
return list(ItemModel.objects.order_by('pk').values_list('pk', 'category__name'))
|
|
94
|
+
|
|
95
|
+
before = get_info()
|
|
96
|
+
|
|
97
|
+
response = self.client.post(
|
|
98
|
+
'/admin/inventory/itemmodel/',
|
|
99
|
+
data={
|
|
100
|
+
ACTION_CHECKBOX_NAME: [
|
|
101
|
+
'80dddef9-0000-0000-0000-000000000002',
|
|
102
|
+
'80dddef9-0000-0000-0000-000000000003',
|
|
103
|
+
],
|
|
104
|
+
'action': mass_change_category_action.__name__,
|
|
105
|
+
'category': category2.pk,
|
|
106
|
+
},
|
|
107
|
+
)
|
|
108
|
+
self.assertRedirects(response, '/admin/inventory/itemmodel/', fetch_redirect_response=False)
|
|
109
|
+
self.assert_messages(
|
|
110
|
+
response,
|
|
111
|
+
expected_messages=[
|
|
112
|
+
'2 items have been assigned to the category "Category 2".',
|
|
113
|
+
],
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
after = get_info()
|
|
117
|
+
self.assertEqual(
|
|
118
|
+
before,
|
|
119
|
+
[
|
|
120
|
+
(UUID('80dddef9-0000-0000-0000-000000000001'), 'Category 1'),
|
|
121
|
+
(UUID('80dddef9-0000-0000-0000-000000000002'), 'Category 1'),
|
|
122
|
+
(UUID('80dddef9-0000-0000-0000-000000000003'), 'Category 2'),
|
|
123
|
+
(UUID('80dddef9-0000-0000-0000-000000000004'), 'Category 2'),
|
|
124
|
+
],
|
|
125
|
+
)
|
|
126
|
+
self.assertEqual(
|
|
127
|
+
after,
|
|
128
|
+
[
|
|
129
|
+
(UUID('80dddef9-0000-0000-0000-000000000001'), 'Category 1'), # Not selected
|
|
130
|
+
(UUID('80dddef9-0000-0000-0000-000000000002'), 'Category 2'), # Changed
|
|
131
|
+
(UUID('80dddef9-0000-0000-0000-000000000003'), 'Category 2'), # Already there
|
|
132
|
+
(UUID('80dddef9-0000-0000-0000-000000000004'), 'Category 2'), # Not selected
|
|
133
|
+
],
|
|
134
|
+
)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<div class="colM" id="content">
|
|
2
|
+
<h1>
|
|
3
|
+
Change category for selected items
|
|
4
|
+
</h1>
|
|
5
|
+
<p>
|
|
6
|
+
Number of selected items: 2
|
|
7
|
+
</p>
|
|
8
|
+
<p>
|
|
9
|
+
Currently used categories are:
|
|
10
|
+
</p>
|
|
11
|
+
<ul>
|
|
12
|
+
<li>
|
|
13
|
+
Category 1
|
|
14
|
+
</li>
|
|
15
|
+
<li>
|
|
16
|
+
Category 2
|
|
17
|
+
</li>
|
|
18
|
+
</ul>
|
|
19
|
+
<form method="post">
|
|
20
|
+
MockedCsrfTokenNode
|
|
21
|
+
<div>
|
|
22
|
+
<p>
|
|
23
|
+
<label for="id_category">
|
|
24
|
+
New category:
|
|
25
|
+
</label>
|
|
26
|
+
<select id="id_category" name="category" required="">
|
|
27
|
+
<option selected="" value="">
|
|
28
|
+
---------
|
|
29
|
+
</option>
|
|
30
|
+
<option value="1">
|
|
31
|
+
Category 1
|
|
32
|
+
</option>
|
|
33
|
+
<option value="2">
|
|
34
|
+
Category 2
|
|
35
|
+
</option>
|
|
36
|
+
</select>
|
|
37
|
+
</p>
|
|
38
|
+
<input name="action" type="hidden" value="mass_change_category_action"/>
|
|
39
|
+
<input name="_selected_action" type="hidden" value="80dddef9-0000-0000-0000-000000000002"/>
|
|
40
|
+
<input name="_selected_action" type="hidden" value="80dddef9-0000-0000-0000-000000000003"/>
|
|
41
|
+
<input type="submit" value="Yes, I’m sure"/>
|
|
42
|
+
<a class="button cancel-link" href="/admin/inventory/itemmodel/">
|
|
43
|
+
No, take me back
|
|
44
|
+
</a>
|
|
45
|
+
</div>
|
|
46
|
+
</form>
|
|
47
|
+
<br class="clear"/>
|
|
48
|
+
</div>
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
from inventory.models.item import ItemFileModel, ItemImageModel, ItemLinkModel, ItemModel # noqa
|
|
1
|
+
from inventory.models.item import ItemFileModel, ItemImageModel, ItemLinkModel, ItemModel, ItemMainCategory # noqa
|
|
2
2
|
from inventory.models.location import LocationModel # noqa
|
|
3
3
|
from inventory.models.memo import MemoFileModel, MemoImageModel, MemoLinkModel, MemoModel # noqa
|