feat(finance/admin): unified statement view (#6)
This PR replaces the separate admin views for unsubmitted, submitted and confirmed statements by one common view. To distinguish the state, we now display a colored badge in the changelist. The default permissions for the `Standard` group are changed so that normal users can continue to view statements they are related to when these are submitted or confirmed.main
parent
3b8964fbb0
commit
5d4f29be89
@ -0,0 +1,28 @@
|
|||||||
|
# Generated by Django 4.2.20 on 2025-10-12 19:16
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('finance', '0011_remove_statement_confirmed_and_submitted'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='StatementOnExcursionProxy',
|
||||||
|
fields=[
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Statement',
|
||||||
|
'verbose_name_plural': 'Statements',
|
||||||
|
'abstract': False,
|
||||||
|
'proxy': True,
|
||||||
|
'default_permissions': ('add_global', 'change_global', 'view_global', 'delete_global', 'list_global', 'view'),
|
||||||
|
'indexes': [],
|
||||||
|
'constraints': [],
|
||||||
|
},
|
||||||
|
bases=('finance.statement',),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -0,0 +1,121 @@
|
|||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.db import migrations
|
||||||
|
from django.contrib.auth.management import create_permissions
|
||||||
|
|
||||||
|
STANDARD_PERMS = [
|
||||||
|
('members', 'view_member'),
|
||||||
|
('members', 'view_freizeit'),
|
||||||
|
('members', 'add_global_freizeit'),
|
||||||
|
('members', 'view_memberwaitinglist'),
|
||||||
|
('members', 'view_memberunconfirmedproxy'),
|
||||||
|
('mailer', 'view_message'),
|
||||||
|
('mailer', 'add_global_message'),
|
||||||
|
('finance', 'view_statement'),
|
||||||
|
('finance', 'add_global_statement'),
|
||||||
|
]
|
||||||
|
|
||||||
|
FINANCE_PERMS = [
|
||||||
|
('finance', 'view_bill'),
|
||||||
|
('finance', 'view_ledger'),
|
||||||
|
('finance', 'add_ledger'),
|
||||||
|
('finance', 'change_ledger'),
|
||||||
|
('finance', 'delete_ledger'),
|
||||||
|
('finance', 'view_global_statement'),
|
||||||
|
('finance', 'change_global_statement'),
|
||||||
|
('finance', 'process_statementsubmitted'),
|
||||||
|
('finance', 'may_manage_confirmed_statements'),
|
||||||
|
('finance', 'view_transaction'),
|
||||||
|
('finance', 'change_transaction'),
|
||||||
|
('finance', 'add_transaction'),
|
||||||
|
('finance', 'delete_transaction'),
|
||||||
|
('members', 'list_global_freizeit'),
|
||||||
|
('members', 'view_global_freizeit'),
|
||||||
|
]
|
||||||
|
|
||||||
|
WAITINGLIST_PERMS = [
|
||||||
|
('members', 'view_global_memberwaitinglist'),
|
||||||
|
('members', 'list_global_memberwaitinglist'),
|
||||||
|
('members', 'change_global_memberwaitinglist'),
|
||||||
|
('members', 'delete_global_memberwaitinglist'),
|
||||||
|
]
|
||||||
|
|
||||||
|
TRAINING_PERMS = [
|
||||||
|
('members', 'change_global_member'),
|
||||||
|
('members', 'list_global_member'),
|
||||||
|
('members', 'view_global_member'),
|
||||||
|
('members', 'add_global_membertraining'),
|
||||||
|
('members', 'change_global_membertraining'),
|
||||||
|
('members', 'list_global_membertraining'),
|
||||||
|
('members', 'view_global_membertraining'),
|
||||||
|
('members', 'view_trainingcategory'),
|
||||||
|
('members', 'add_trainingcategory'),
|
||||||
|
('members', 'change_trainingcategory'),
|
||||||
|
('members', 'delete_trainingcategory'),
|
||||||
|
]
|
||||||
|
|
||||||
|
REGISTRATION_PERMS = [
|
||||||
|
('members', 'may_manage_all_registrations'),
|
||||||
|
('members', 'change_memberunconfirmedproxy'),
|
||||||
|
('members', 'delete_memberunconfirmedproxy'),
|
||||||
|
]
|
||||||
|
|
||||||
|
MATERIAL_PERMS = [
|
||||||
|
('members', 'list_global_member'),
|
||||||
|
('material', 'view_materialpart'),
|
||||||
|
('material', 'change_materialpart'),
|
||||||
|
('material', 'add_materialpart'),
|
||||||
|
('material', 'delete_materialpart'),
|
||||||
|
('material', 'view_materialcategory'),
|
||||||
|
('material', 'change_materialcategory'),
|
||||||
|
('material', 'add_materialcategory'),
|
||||||
|
('material', 'delete_materialcategory'),
|
||||||
|
('material', 'view_ownership'),
|
||||||
|
('material', 'change_ownership'),
|
||||||
|
('material', 'add_ownership'),
|
||||||
|
('material', 'delete_ownership'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_group_perms(apps, schema_editor, name, perm_names):
|
||||||
|
"""
|
||||||
|
Ensure the group `name` has the permissions `perm_names`. If the group does not
|
||||||
|
exist, create it with the given permissions, otherwise add the missing ones.
|
||||||
|
|
||||||
|
This only adds permissions, already existing ones that are not listed here are not
|
||||||
|
removed.
|
||||||
|
"""
|
||||||
|
db_alias = schema_editor.connection.alias
|
||||||
|
Group = apps.get_model("auth", "Group")
|
||||||
|
Permission = apps.get_model("auth", "Permission")
|
||||||
|
perms = [ Permission.objects.get(codename=codename, content_type__app_label=app_label) for app_label, codename in perm_names ]
|
||||||
|
try:
|
||||||
|
g = Group.objects.using(db_alias).get(name=name)
|
||||||
|
for perm in perms:
|
||||||
|
g.permissions.add(perm)
|
||||||
|
g.save()
|
||||||
|
# This case is only executed if users have manually removed one of the standard groups.
|
||||||
|
except Group.DoesNotExist: # pragma: no cover
|
||||||
|
g = Group.objects.using(db_alias).create(name=name)
|
||||||
|
g.permissions.set(perms)
|
||||||
|
g.save()
|
||||||
|
|
||||||
|
|
||||||
|
def update_default_permission_groups(apps, schema_editor):
|
||||||
|
ensure_group_perms(apps, schema_editor, "Standard", STANDARD_PERMS)
|
||||||
|
ensure_group_perms(apps, schema_editor, "Finance", FINANCE_PERMS)
|
||||||
|
ensure_group_perms(apps, schema_editor, "Waitinglist", WAITINGLIST_PERMS)
|
||||||
|
ensure_group_perms(apps, schema_editor, "Trainings", TRAINING_PERMS)
|
||||||
|
ensure_group_perms(apps, schema_editor, "Registrations", REGISTRATION_PERMS)
|
||||||
|
ensure_group_perms(apps, schema_editor, "Material", MATERIAL_PERMS)
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('finance', '0012_statementonexcursionproxy'),
|
||||||
|
('members', '0044_membertraining_activity_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(update_default_permission_groups, migrations.RunPython.noop),
|
||||||
|
]
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
span.statement-unsubmitted, span.statement-submitted, span.statement-confirmed {
|
||||||
|
color: black;
|
||||||
|
padding: 4px;
|
||||||
|
padding-left: 6px;
|
||||||
|
padding-right: 6px;
|
||||||
|
border-radius: 10px;
|
||||||
|
width: 20px;
|
||||||
|
min-width: 20px;
|
||||||
|
max-width: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.statement-submitted {
|
||||||
|
background-color: #e8e8bd;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.statement-unsubmitted {
|
||||||
|
background-color: #f0dada;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.statement-confirmed {
|
||||||
|
background-color: #e0eec5;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
{% extends "admin/change_form_object_tools.html" %}
|
||||||
|
{% load i18n admin_urls rules %}
|
||||||
|
|
||||||
|
{% block object-tools-items %}
|
||||||
|
|
||||||
|
{% if original.confirmed and perms.finance.may_manage_confirmed_statements %}
|
||||||
|
<li>
|
||||||
|
{% url opts|admin_urlname:'unconfirm' original.pk|admin_urlquote as invite_url %}
|
||||||
|
<a class="historylink" href="{% add_preserved_filters invite_url %}">{% trans 'Unconfirm' %}</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{% url opts|admin_urlname:'summary' original.pk|admin_urlquote as invite_url %}
|
||||||
|
<a class="historylink" target="_blank" href="{% add_preserved_filters invite_url %}">{% trans 'Download summary' %}</a>
|
||||||
|
</li>
|
||||||
|
{% elif original.submitted and perms.finance.process_statementsubmitted %}
|
||||||
|
<script>
|
||||||
|
function requestWithCurrentURL(path) {
|
||||||
|
var xpath = path + "?redirectTo=" + window.location.href;
|
||||||
|
location.href = xpath;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
{% url opts|admin_urlname:'reduce_transactions' original.pk|admin_urlquote as invite_url %}
|
||||||
|
<a value="hi" onclick='requestWithCurrentURL("{% add_preserved_filters invite_url %}")'>
|
||||||
|
{% trans 'Reduce transactions' %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{% url opts|admin_urlname:'overview' original.pk|admin_urlquote as invite_url %}
|
||||||
|
<a class="historylink" href="{% add_preserved_filters invite_url %}">{% trans 'Overview' %}</a>
|
||||||
|
</li>
|
||||||
|
{% elif not original.submitted %}
|
||||||
|
<li>
|
||||||
|
{% url opts|admin_urlname:'submit' original.pk|admin_urlquote as invite_url %}
|
||||||
|
<a class="historylink" href="{% add_preserved_filters invite_url %}">{% trans 'Submit' %}</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{{block.super}}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
Loading…
Reference in New Issue