-
Tomáš Valenta authoredTomáš Valenta authored
admin.py 13.94 KiB
import copy
import typing
from django.contrib import admin
from django.contrib.auth.models import Permission
from django.utils.html import format_html
from import_export import resources
from nested_admin import NestedModelAdmin, NestedStackedInline, NestedTabularInline
from rangefilter.filters import DateRangeFilter
from shared.admin import FieldsetInlineOrder, MarkdownxGuardedModelAdmin
from .forms import ContractAdminForm, ContractFileAdminForm, SigneeAdminForm
from .models import (
Contract,
Contractee,
ContracteeSignature,
ContracteeSignatureRepresentative,
ContractFile,
ContractFilingArea,
ContractIntent,
ContractIssue,
ContractType,
Signee,
SigneeSignature,
SigneeSignatureRepresentative,
)
class ContractResource(resources.ModelResource):
class Meta:
model = Contract
class IndexHiddenModelAdmin(MarkdownxGuardedModelAdmin):
def has_module_permission(self, request):
return False
def permissions_mixin_factory(
change_permission: str,
delete_permission: str,
obj_conditional: typing.Callable,
change_attr_func: typing.Callable = lambda obj: obj,
delete_attr_func: typing.Callable = lambda obj: obj,
) -> object:
class Mixin:
def has_change_permission(self, request, obj=None) -> bool:
if (
obj is not None
and obj_conditional(request, obj)
and not request.user.has_perm(change_permission, change_attr_func(obj))
):
return False
return super().has_change_permission(request, obj)
def has_delete_permission(self, request, obj=None) -> bool:
if (
obj is not None
and obj_conditional(request, obj)
and not request.user.has_perm(delete_permission, delete_attr_func(obj))
):
return False
return super().has_change_permission(request, obj)
return Mixin
get_obj_contract = lambda obj: obj.contract
class OwnPermissionsMixin(
permissions_mixin_factory(
"contracts.edit_others",
"contracts.delete_others",
lambda request, obj: obj.created_by != request.user,
)
):
def own_permissions_mixin_save_model(self, request, obj, form, change):
if obj.created_by is None:
obj.created_by = request.user
return super().save_model(request, obj, form, change)
ParentContractApprovedPermissionsMixin = permissions_mixin_factory(
"contracts.edit_when_approved",
"contracts.delete_when_approved",
lambda request, obj: get_obj_contract(obj).is_approved,
get_obj_contract,
get_obj_contract,
)
ParentContractOwnPermissionsMixin = permissions_mixin_factory(
"contracts.edit_others",
"contracts.delete_others",
lambda request, obj: get_obj_contract(obj).created_by != request.user,
get_obj_contract,
get_obj_contract,
)
# BEGIN Contracts
class ContractFileAdmin(
IndexHiddenModelAdmin,
ParentContractApprovedPermissionsMixin,
ParentContractOwnPermissionsMixin,
):
form = ContractFileAdminForm
class ContracteeSignatureRepresentativeInline(NestedStackedInline):
model = ContracteeSignatureRepresentative
extra = 0
class ContracteeSignatureInline(NestedStackedInline):
model = ContracteeSignature
autocomplete_fields = ("contractee",)
inlines = (ContracteeSignatureRepresentativeInline,)
extra = 0
class SigneeSignatureRepresentativeInline(NestedStackedInline):
model = SigneeSignatureRepresentative
extra = 0
class SigneeSignatureInline(NestedStackedInline):
model = SigneeSignature
autocomplete_fields = ("signee",)
inlines = (SigneeSignatureRepresentativeInline,)
extra = 0
class ContractFileInline(NestedTabularInline):
model = ContractFile
form = ContractFileAdminForm
extra = 0
class ContractIntentInline(NestedTabularInline):
model = ContractIntent
extra = 0
class ContractAdmin(
OwnPermissionsMixin,
permissions_mixin_factory(
"contracts.edit_when_approved",
"contracts.delete_when_approved",
lambda request, obj: obj.is_approved,
),
MarkdownxGuardedModelAdmin,
NestedModelAdmin,
):
form = ContractAdminForm
readonly_fields = ("created_by",)
autocomplete_fields = (
"types",
"filing_area",
"issues",
)
inlines = (
ContractFileInline,
ContracteeSignatureInline,
SigneeSignatureInline,
ContractIntentInline,
)
def get_form(self, request, *args, **kwargs) -> ContractAdminForm:
form = super().get_form(request, *args, **kwargs)
form.current_user = request.user
return form
def get_fieldsets(self, request, obj=None) -> list:
fieldsets = [
(
"Základní informace",
{
"fields": [
"name",
"id_number",
"types",
"summary",
"is_public",
"legal_state",
"primary_contract",
]
},
),
(
"Data",
{
"fields": [
"valid_start_date",
"valid_end_date",
]
},
),
(
"Náklady",
{
"fields": [
"cost_amount",
"cost_unit",
]
},
),
(
"Odkazy",
{
"fields": [
"tender_url",
"agreement_url",
]
},
),
(
"Fyzický dokument",
{
"fields": [
"paper_form_state",
"filing_area",
]
},
),
(
"Doplňující informace",
{
"fields": [
"issues",
"notes",
]
},
),
]
if (
obj is None # Creating confidential data, creator will be request.user
or obj.created_by == request.user
or request.user.has_perm("view_confidential", obj)
):
fieldsets[0][1]["fields"].insert(
fieldsets[0][1]["fields"].index("is_public") + 1,
"publishing_rejection_comment",
)
if request.user.has_perm("approve", self):
fieldsets.insert(
5,
("Schválení", {"fields": ["is_approved"]}),
)
return fieldsets
def get_fieldsets_and_inlines_order(self, context) -> list:
order = [
FieldsetInlineOrder.FIELDSET,
FieldsetInlineOrder.FIELDSET,
FieldsetInlineOrder.FIELDSET,
FieldsetInlineOrder.INLINE,
FieldsetInlineOrder.INLINE,
FieldsetInlineOrder.INLINE,
FieldsetInlineOrder.FIELDSET,
FieldsetInlineOrder.INLINE,
FieldsetInlineOrder.FIELDSET,
FieldsetInlineOrder.FIELDSET,
]
if context["user"].has_perm("approve", self):
order.insert(10, FieldsetInlineOrder.FIELDSET)
return order
def get_queryset(self, request):
queryset = super().get_queryset(request)
if not request.user.has_perm("contracts.view_confidential"):
queryset = queryset.filter(is_public=True)
if not request.user.has_perm("contracts.approve"):
queryset = queryset.filter(is_approved=True)
return queryset
def save_model(self, request, obj, form, change):
if obj.valid_start_date is None:
last_signature_date = None
for signature_set in (
obj.contractee_signatures.all(),
obj.signee_signatures.all(),
):
for signature in signature_set:
if (
last_signature_date is None
or last_signature_date < signature.date
):
last_signature_date = signature.date
obj.valid_start_date = last_signature_date
return super().save_model(request, obj, form, change)
def has_change_permission(self, request, obj=None):
if (
obj is not None
and obj.is_approved
and not request.user.has_perm("contracts.edit_when_approved", obj)
):
return False
return super().has_change_permission(request, obj)
def has_delete_permission(self, request, obj=None):
if (
obj is not None
and obj.is_approved
and not request.user.has_perm("contracts.delete_when_approved", obj)
):
return False
return super().has_change_permission(request, obj)
list_filter = (
"types",
"is_approved",
"legal_state",
"is_public",
"paper_form_state",
"issues",
("all_parties_sign_date", DateRangeFilter),
("valid_start_date", DateRangeFilter),
("valid_end_date", DateRangeFilter),
)
list_display = (
"name",
"is_approved",
"is_public",
)
class ContractTypeAdmin(MarkdownxGuardedModelAdmin):
model = ContractType
ordering = ("name",)
search_fields = ("name",)
class ContractIssueAdmin(MarkdownxGuardedModelAdmin):
model = ContractIssue
ordering = ("name",)
search_fields = ("name",)
class ContractFilingAreaAdmin(MarkdownxGuardedModelAdmin):
model = ContractFilingArea
ordering = ("name",)
search_fields = (
"name",
"person_responsible",
)
# END Contracts
# BEGIN Signing parties
class ContracteeAdmin(OwnPermissionsMixin, MarkdownxGuardedModelAdmin):
model = Contractee
search_fields = (
"name",
"department",
"role",
)
ordering = ("name",)
class SigneeAdmin(OwnPermissionsMixin, MarkdownxGuardedModelAdmin):
model = Signee
search_fields = (
"name",
"department",
"role",
)
ordering = ("name",)
form = SigneeAdminForm
readonly_fields = ("load_ares_data_button",)
list_filter = ("entity_type",)
list_display = ("name", "entity_type")
def get_fields(self, request, obj=None):
fields = [
"name",
"entity_type",
"ico_number",
"department",
"role",
]
if (
obj is None # Creating
or obj.entity_has_public_address
or request.user.has_perm("contracts.view_confidential", obj)
):
entity_type_index = fields.index("entity_type") + 1
fields[entity_type_index:entity_type_index] = [
"address_street_with_number",
"address_district",
"address_zip",
"address_country",
]
fields.insert(
fields.index("department"),
"date_of_birth",
)
if obj is None or request.user.has_perm( # Allowed to create
"contracts.edit_signee", obj
):
fields.insert(fields.index("ico_number"), "load_ares_data_button")
return fields
def load_ares_data_button(self, obj):
return format_html(
'<button type="button" id="load_ares_data">Načíst data</button>'
)
load_ares_data_button.allow_tags = True
load_ares_data_button.short_description = "ARES"
get_obj_signee_contract = lambda obj: obj.signee.contract
get_obj_contractee_contract = lambda obj: obj.contractee.contract
class SigneeSignatureRepresentativeAdmin(
IndexHiddenModelAdmin,
permissions_mixin_factory(
"contracts.edit_when_approved",
"contracts.delete_when_approved",
lambda request, obj: get_obj_signee_contract(obj).is_approved,
get_obj_signee_contract,
get_obj_signee_contract,
),
permissions_mixin_factory(
"contracts.edit_others",
"contracts.delete_others",
lambda request, obj: get_obj_contractee_contract(obj).created_by
!= request.user,
get_obj_signee_contract,
get_obj_signee_contract,
),
):
pass
class ContracteeSignatureRepresentativeAdmin(
IndexHiddenModelAdmin,
permissions_mixin_factory(
"contracts.edit_when_approved",
"contracts.delete_when_approved",
lambda request, obj: get_obj_contractee_contract(obj).is_approved,
get_obj_contractee_contract,
get_obj_contractee_contract,
),
permissions_mixin_factory(
"contracts.edit_others",
"contracts.delete_others",
lambda request, obj: get_obj_contractee_contract(obj).created_by
!= request.user,
get_obj_contractee_contract,
get_obj_contractee_contract,
),
):
pass
# END Signing parties
class ContractSubmodelAdmin(
IndexHiddenModelAdmin,
ParentContractApprovedPermissionsMixin,
ParentContractOwnPermissionsMixin,
):
pass
admin.site.register(Permission)
for model in (
SigneeSignature,
ContracteeSignature,
ContractIntent,
):
admin.site.register(model, ContractSubmodelAdmin)
admin.site.register(SigneeSignatureRepresentative, SigneeSignatureRepresentativeAdmin)
admin.site.register(
ContracteeSignatureRepresentative, ContracteeSignatureRepresentativeAdmin
)
admin.site.register(ContractType, ContractTypeAdmin)
admin.site.register(ContractIssue, ContractIssueAdmin)
admin.site.register(ContractFile, ContractFileAdmin)
admin.site.register(ContractFilingArea, ContractFilingAreaAdmin)
admin.site.register(Contractee, ContracteeAdmin)
admin.site.register(Signee, SigneeAdmin)
admin.site.register(Contract, ContractAdmin)