From c1a690b2faf6770194e7877fc95829e124da3f62 Mon Sep 17 00:00:00 2001 From: JensDiemer Date: Fri, 30 Sep 2022 20:49:26 +0200 Subject: [PATCH] Enhance Location: Better change form and list all items in this location --- src/inventory/admin/location.py | 42 +++++++++- src/inventory/locale/ca/LC_MESSAGES/django.po | 11 ++- src/inventory/locale/de/LC_MESSAGES/django.mo | Bin 6201 -> 6268 bytes src/inventory/locale/de/LC_MESSAGES/django.po | 13 +-- src/inventory/locale/en/LC_MESSAGES/django.po | 11 ++- src/inventory/locale/es/LC_MESSAGES/django.po | 11 ++- .../templates/admin/location/items.html | 18 ++++ src/inventory/tests/test_admin_location.py | 37 +++++++++ ...location_empty_change_list_1.snapshot.html | 77 ++++++++++++++++++ 9 files changed, 201 insertions(+), 19 deletions(-) create mode 100644 src/inventory/templates/admin/location/items.html create mode 100644 src/inventory/tests/test_admin_location.py create mode 100644 src/inventory/tests/test_admin_location_empty_change_list_1.snapshot.html diff --git a/src/inventory/admin/location.py b/src/inventory/admin/location.py index a321f6c..6bc2b37 100644 --- a/src/inventory/admin/location.py +++ b/src/inventory/admin/location.py @@ -1,12 +1,14 @@ from django.conf import settings from django.contrib import admin from django.db.models import Count +from django.db.models.options import Options +from django.template.loader import render_to_string from django.utils.translation import gettext_lazy as _ from import_export.admin import ImportExportMixin from import_export.resources import ModelResource from inventory.admin.base import BaseUserAdmin, LimitTreeDepthListFilter -from inventory.models import LocationModel +from inventory.models import ItemModel, LocationModel from inventory.string_utils import ltruncatechars @@ -22,6 +24,16 @@ class LocationModelAdmin(ImportExportMixin, BaseUserAdmin): def item_count(self, obj): return obj.item_count + @admin.display(description=_('ItemModel.verbose_name_plural')) + def items(self, obj): + item_qs = ItemModel.objects.filter(location=obj) + opts: Options = ItemModel._meta + context = { + 'items': item_qs, + 'opts': opts, + } + return render_to_string('admin/location/items.html', context) + @admin.display(ordering='path_str', description=_('LocationModel.verbose_name')) def location(self, obj): text = ' › '.join(obj.path) @@ -34,7 +46,33 @@ class LocationModelAdmin(ImportExportMixin, BaseUserAdmin): return qs list_display = ('location', 'create_dt', 'update_dt', 'item_count') - readonly_fields = ('item_count',) + fieldsets = ( + ( + _('Internals'), + { + 'classes': ('collapse',), + 'fields': ( + ('id', 'version'), + 'user', + ), + }, + ), + (_('Meta'), {'classes': ('collapse',), 'fields': ('create_dt', 'update_dt')}), + ( + _('Basic'), + { + 'fields': ( + 'name', + 'description', + 'tags', + 'parent', + ) + }, + ), + (_('Items in this Location'), {'fields': ('items',)}), + ) + autocomplete_fields = ('parent',) + readonly_fields = ('id', 'create_dt', 'update_dt', 'user', 'item_count', 'items') list_display_links = ('location',) list_filter = (LimitTreeDepthListFilter,) search_fields = ('name', 'description', 'tags__name') diff --git a/src/inventory/locale/ca/LC_MESSAGES/django.po b/src/inventory/locale/ca/LC_MESSAGES/django.po index 1c4a308..996c704 100644 --- a/src/inventory/locale/ca/LC_MESSAGES/django.po +++ b/src/inventory/locale/ca/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-30 20:11+0200\n" +"POT-Creation-Date: 2022-09-30 20:48+0200\n" "PO-Revision-Date: 2022-09-30 20:07+0200\n" "Last-Translator: Jaume López\n" "Language-Team: \n" @@ -54,9 +54,15 @@ msgstr "Rebuts" msgid "Handed over" msgstr "Donats" +msgid "ItemModel.verbose_name_plural" +msgstr "Elements" + msgid "LocationModel.verbose_name" msgstr "Localització" +msgid "Items in this Location" +msgstr "" + msgid "BaseModel.id.verbose_name" msgstr "ID" @@ -180,9 +186,6 @@ msgstr "Preu de cessió" msgid "ItemModel.handed_over_price.help_text" msgstr " " -msgid "ItemModel.verbose_name_plural" -msgstr "Elements" - msgid "ItemLinkModel.verbose_name" msgstr "Vincle" diff --git a/src/inventory/locale/de/LC_MESSAGES/django.mo b/src/inventory/locale/de/LC_MESSAGES/django.mo index 45da557063b80f45ddaebabb127226ab1479a3eb..7d522368a5f6a0b1e27129cb1119ed0a9e245093 100644 GIT binary patch delta 1885 zcmZA1S!_&E9LMp~ZKl-HnX0X=PSI9lsn}bJ)>3L2YpF^UGiWf>G)N>SA`#&Q6B-g8 zgm^&HWFmMWwImfHX%mShmc$a35~PAe@cs23FHYuvKj)l#@7eEMAN^}|iw*@eqe%2j-)P(d1$g4#PF57Z2L{i>R5lqB{Oy@4I?9?-iix{iuO%#vynJwW5uf zsil5IMkD*G3iS4L%7v(r`%wd{v*i=Ed<`|A=cs|2Ud~qJp(a#f%hi}jc?YKAF4R^X z#E3dPOGZn36ZPU#^x_Xp$CTdA$a7F5pM{#y7SsR_qu#%4%PpvOKcFV&rdQq1M?GJL zdOwiLQB%c!DzsGRQ8Q{rz3>Kg{|~C69FKFq6m{qVr~&W61U!jszd4PZFLMD|9MgoF z@eQOY^B9N68Po1z{ijlqp5`pkGNj&A*>bfl*I+#L>ufn_?{Bo_Ew&uO#IZONwdA`| zhw=bwB`%?!zk+;V<|;CPh`B{ZBWgzt;2WyJY=bHm z&*BJ-q1t_grPyK1qxkpIK#DOze|1xA#dK7|Wmt}W)c4(hnn4q4Wv-(dxQ!avUF&_+ zKw9nnC#WrYW_^X)inq4hfk~^W_(Dbven$=9r+vUh@9H20wFMs30MbznWg|b6$3KvzmZz1DncVyVwv?v)Rm@i)eOcHONgTAK38_mQgS6kAyG{zX@1j{Ar(iP zT^Xgb$W;=nR7Dy}=s#crF^`x`Xf^mS%y41>v7DGg=zz|RX1NP)iQCE2&-_JMC_CMQgezdc(fjkgtAIZP+(|+xoTjwcA3mie7gT;>S&jrFzQ~Gs=S- hgQ0N!?Q@|((6=_^3)BX~!L2_3j{4$QW#89ve*w&}vpE0& delta 1818 zcmZA1Sx8h-9LMqFq+^+xX=$c5s98x3nJwC)W~H`RT4_625WPeZK2#Jm8nnGcF|=S5 zm@i2b$V3#hkkay!U=T$}nE4R2P(+Jj)b}^@@1@I}`JDefXU_ef<<3z4o&3O?r0BDb zYcnN-^3mg50Pn`|#dSN@xyg73^RO3FF>bhX6EGW7uo%;@7RTcrOvmFEw_1GH;#ZM4 z;J#APvqp_@ZX_lnALrvs3FV;=D^L&IiCNf$6S39e4%7qtF&kZ6q<;>oe+g=wZK(Ff za640NrIN{w`#1@Ea0*6|O)lo)RIEn*@POUFh??m`)PrAJ`wweRi;vtdMJ2igbMPQ) zMK5E9miiGDW!9$~=ouA>eW=V!QHgE0_?X34Q3*XmCHe)m6)6dk3HdRacqJxc4Qh+F zqn>jJ16tAxRI~yiOu}v)hyAFG2T>VM937cSIV!OosNWy6xCJ$ECu%~y)~=_ke>!R< ziY?xn$WhbM9p;8+(u^ALo^^PI8fehkCycSfhDx{=hhYP{#qh`GW(4MsCc%;^Uy=Qz~T~XUu1E)#g$k`zbaG$S5Sxg8hWwa zyp4L!18aX6u*wtU&2rDI!wXa*FU=m*KyNL6k9xo-)PUcR7RjoTn=BH zOIL*2%B2p!T#Lr{iAK3@>3B zwpsiEmB3Hbga$1Bjq&=c`$MIYhIszg^gh?3GT)8iLxmck5tYyp^8_l9Q`UYCwPhE~ zOQYZNbg8$lC6pq{atcR3yl(4IFMAoqPgzMR4`z9j)7Ded#B{Bu6ozZgtqQL4rur+0 zHd3?~x>!BO|3mm%z_+G2hq6X@f@i$GthH1YQf5##Q*>#5rQsSo9PIX{mn|i#qinLf zlTh#eT*?Z{e2P|s1Ma3#v~sl+ZJiG0vY + + + {% trans "No." %} + {% trans "ItemModel.verbose_name_plural" %} + + + + {% for obj in items %} + + {{ forloop.counter }} + {{ obj }} + + {% endfor %} + + \ No newline at end of file diff --git a/src/inventory/tests/test_admin_location.py b/src/inventory/tests/test_admin_location.py new file mode 100644 index 0000000..40ee7d1 --- /dev/null +++ b/src/inventory/tests/test_admin_location.py @@ -0,0 +1,37 @@ +from unittest import mock + +from bx_django_utils.test_utils.html_assertion import ( + HtmlAssertionMixin, + assert_html_response_snapshot, +) +from django.template.defaulttags import CsrfTokenNode, NowNode +from django.test import TestCase, override_settings + +from inventory import __version__ +from inventory_project.tests.fixtures import get_normal_user + + +@override_settings(SECURE_SSL_REDIRECT=False) +class AdminTestCase(HtmlAssertionMixin, TestCase): + @classmethod + def setUpTestData(cls): + cls.normaluser = get_normal_user() + + def test_empty_change_list(self): + self.client.force_login(self.normaluser) + with mock.patch.object(NowNode, 'render', return_value='MockedNowNode'), mock.patch.object( + CsrfTokenNode, 'render', return_value='MockedCsrfTokenNode' + ): + response = self.client.get( + path='/admin/inventory/locationmodel/', + ) + assert response.status_code == 200 + self.assert_html_parts( + response, + parts=( + f'Select Location to change | PyInventory v{__version__}', + 'Add Location', + '

0 Locations

', + ), + ) + assert_html_response_snapshot(response=response, validate=False) diff --git a/src/inventory/tests/test_admin_location_empty_change_list_1.snapshot.html b/src/inventory/tests/test_admin_location_empty_change_list_1.snapshot.html new file mode 100644 index 0000000..a16e0bc --- /dev/null +++ b/src/inventory/tests/test_admin_location_empty_change_list_1.snapshot.html @@ -0,0 +1,77 @@ +
+

+ Select Location to change +

+
+ +
+
+
+ +
+
+ MockedCsrfTokenNode +

+ 0 Locations +

+
+
+
+

+ Filter +

+

+ By Limit tree depth +

+ +
+
+
+
+
\ No newline at end of file