Skip to content
Snippets Groups Projects
Select Git revision
  • 6346fc6182e0ec322d070bc2c77e00493abd2017
  • test default protected
  • master protected
  • original
  • pirati-backup protected
  • beta-2
  • beta-1
  • v3.1.4
  • v3.1.3
  • v3.1.2
  • v3.1.1
  • v3.1.0
  • v3.0.16
  • v3.0.15
  • v3.0.14
  • v3.0.13
  • v3.0.12
  • v3.0.11
  • v3.0.10
  • v3.0.9
  • v3.0.8
  • v3.0.7
  • v3.0.6
  • v3.0.5
  • v3.0.4
25 results

manage.py

Blame
  • admin.py 16.47 KiB
    import copy
    import json
    import logging
    import typing
    
    import requests
    from admin_auto_filters.filters import AutocompleteFilterFactory
    from django.conf import settings
    from django.contrib import admin
    from django.contrib.auth.models import Permission
    from django.db import models
    from django.utils.html import format_html
    from nested_admin import NestedModelAdmin, NestedStackedInline, NestedTabularInline
    from rangefilter.filters import DateRangeFilter
    
    from shared.admin import FieldsetInlineOrder, MarkdownxGuardedModelAdmin
    
    from .forms import (
        AtLeastOneRequiredInlineFormSet,
        ContractAdminForm,
        ContractFileAdminForm,
        SigneeAdminForm,
    )
    from .models import (
        Contract,
        ContractApproval,
        Contractee,
        ContracteeSignature,
        ContracteeSignatureRepresentative,
        ContractFile,
        ContractFilingArea,
        ContractIntent,
        ContractIssue,
        ContractType,
        Signee,
        SigneeSignature,
        SigneeSignatureRepresentative,
    )
    
    logger = logging.getLogger()
    
    
    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 = lambda request, obj: True,
    ) -> 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)
                ):
                    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(change_permission)
                ):
                    return False
    
                return super().has_change_permission(request, obj)
    
        return Mixin
    
    
    get_obj_contract = lambda request, obj: obj.contract
    
    
    class OwnPermissionsMixin(
        permissions_mixin_factory(
            "contracts.edit_others",
            "contracts.delete_others",
            obj_conditional=lambda request, obj: obj.created_by != request.user,
        )
    ):
        def 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",
        obj_conditional=lambda request, obj: get_obj_contract(obj).is_approved,
    )
    
    
    ParentContractOwnPermissionsMixin = permissions_mixin_factory(
        "contracts.edit_others",
        "contracts.delete_others",
        obj_conditional=lambda request, obj: get_obj_contract(obj).created_by
        != request.user,
    )
    
    
    # BEGIN Contracts
    
    
    class ContractFileAdmin(
        IndexHiddenModelAdmin,
        ParentContractApprovedPermissionsMixin,
        ParentContractOwnPermissionsMixin,
    ):
        form = ContractFileAdminForm
    
    
    class ContracteeSignatureRepresentativeInline(NestedStackedInline):
        model = ContracteeSignatureRepresentative
        extra = 1
        formset = AtLeastOneRequiredInlineFormSet
    
    
    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 ContractApprovalInline(NestedTabularInline):
        model = ContractApproval
        extra = 0
    
    
    class ContractIntentInline(NestedTabularInline):
        model = ContractIntent
        extra = 0
    
    
    class ContractAdmin(
        OwnPermissionsMixin,
        permissions_mixin_factory(
            "contracts.edit_when_approved",
            "contracts.delete_when_approved",
            obj_conditional=lambda request, obj: obj.is_approved,
        ),
        MarkdownxGuardedModelAdmin,
        NestedModelAdmin,
    ):
        form = ContractAdminForm
    
        search_fields = ("name",)
    
        readonly_fields = (
            "created_by",
            "created_on",
            "updated_on",
        )
        autocomplete_fields = (
            "primary_contract",
            "types",
            "filing_area",
            "issues",
        )
    
        inlines = (
            ContractFileInline,
            ContracteeSignatureInline,
            SigneeSignatureInline,
            ContractApprovalInline,
            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",
                            "is_valid",
                            "primary_contract",
                        ]
                    },
                ),
                (
                    "Data",
                    {
                        "fields": [
                            "valid_start_date",
                            "valid_end_date",
                        ]
                    },
                ),
                (
                    "Náklady",
                    {
                        "fields": [
                            "cost_amount",
                            "cost_unit",
                            "cost_unit_other",
                        ]
                    },
                ),
                (
                    "Odkazy",
                    {
                        "fields": [
                            "tender_url",
                        ]
                    },
                ),
                (
                    "Fyzický dokument",
                    {
                        "fields": [
                            "paper_form_state",
                            "paper_form_person_responsible",
                            "filing_area",
                        ]
                    },
                ),
                (
                    "Doplňující informace",
                    {
                        "fields": [
                            "issues",
                            "notes",
                            "created_by",
                            "created_on",
                            "updated_on",
                        ]
                    },
                ),
            ]
    
            if (
                obj is None  # Creating confidential data, creator will be request.user
                or obj.created_by == request.user
                or request.user.has_perm("contracts.view_confidential")
            ):
                fieldsets[0][1]["fields"].insert(
                    fieldsets[0][1]["fields"].index("is_public") + 1,
                    "publishing_rejection_comment",
                )
    
            if obj is not None and request.user.has_perm("contracts.approve"):
                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.INLINE,
                FieldsetInlineOrder.FIELDSET,
                FieldsetInlineOrder.FIELDSET,
            ]
    
            if context["user"].has_perm("contracts.approve"):
                order.insert(11, FieldsetInlineOrder.FIELDSET)
    
            return order
    
        def get_queryset(self, request):
            queryset = super().get_queryset(request)
    
            if not request.user.has_perm("contracts.view_confidential"):
                # Allow user to view their own objects, even if not public
                queryset = queryset.filter(
                    models.Q(is_public=True) | models.Q(created_by=request.user)
                )
    
            if not request.user.has_perm("contracts.approve"):
                queryset = queryset.filter(
                    models.Q(is_approved=True) | models.Q(created_by=request.user)
                )
    
            return queryset
    
        def save_model(self, request, obj, form, change):
            is_new = obj.created_by is None
    
            # Need to generate primary keys first
            parent_save_response = super().save_model(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
    
            from users.models import User
    
            if is_new:
                try:
                    sso_ids = []
    
                    for user in User.objects.filter(is_staff=True).all():
                        if user.is_superuser or user.has_perm("contracts.approve"):
                            sso_ids.append(user.sso_id)
    
                    requests.post(
                        settings.NASTENKA_API_URL,
                        data=json.dumps(
                            {
                                "name": f"Nová smlouva ke schválení - {obj.name}",
                                "description": (
                                    obj.summary
                                    if obj.summary is not None
                                    else "Bez popisu."
                                ),
                                "contract_id": obj.id,
                                "sso_ids": sso_ids,
                            }
                        ),
                        headers={
                            "Authorization": f"Token {settings.NASTENKA_API_TOKEN}",
                            "Content-Type": "application/json",
                        },
                    )
                except Exception as exception:
                    logger.error(
                        "Failed to synchronizace Nástěnka notices: %s", str(exception)
                    )
    
            return parent_save_response
    
        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")
            ):
                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")
            ):
                return False
    
            return super().has_change_permission(request, obj)
    
        list_filter = (
            AutocompleteFilterFactory("Typ", "types"),
            AutocompleteFilterFactory("Spisovna", "filing_area"),
            AutocompleteFilterFactory("Problém", "issues"),
            AutocompleteFilterFactory(
                "Naše smluvná strana", "contractee_signatures__contractee"
            ),
            AutocompleteFilterFactory("Jiná smluvní strana", "signee_signatures__signee"),
            "is_approved",
            "is_valid",
            "is_public",
            "paper_form_state",
            ("all_parties_sign_date", DateRangeFilter),
            ("valid_start_date", DateRangeFilter),
            ("valid_end_date", DateRangeFilter),
        )
    
        list_display = (
            "name",
            "is_approved",
            "is_public",
            "created_on",
        )
    
    
    class ContractTypeAdmin(MarkdownxGuardedModelAdmin):
        model = ContractType
        search_fields = ("name",)
    
    
    class ContractIssueAdmin(MarkdownxGuardedModelAdmin):
        model = ContractIssue
        search_fields = ("name",)
    
    
    class ContractFilingAreaAdmin(MarkdownxGuardedModelAdmin):
        model = ContractFilingArea
        search_fields = (
            "name",
            "person_responsible",
        )
    
    
    # END Contracts
    
    # BEGIN Signing parties
    
    
    class ContracteeAdmin(OwnPermissionsMixin, MarkdownxGuardedModelAdmin):
        model = Contractee
    
        fields = (
            "name",
            "address_street_with_number",
            "address_district",
            "address_zip",
            "address_country",
            "ico_number",
            "department",
        )
        search_fields = (
            "name",
            "department",
        )
    
    
    class SigneeAdmin(OwnPermissionsMixin, MarkdownxGuardedModelAdmin):
        model = Signee
    
        fields = (
            "name",
            "entity_type",
            "address_street_with_number",
            "address_district",
            "address_zip",
            "address_country",
            "ico_number",
            "date_of_birth",
            "department",
        )
        search_fields = (
            "name",
            "department",
        )
    
        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",
            ]
    
            if (
                obj is None  # Creating
                or obj.entity_has_public_address
                or request.user.has_perm("contracts.view_confidential")
            ):
                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("contracts.edit_signee"):
                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 request, obj: obj.signee.contract
    get_obj_contractee_contract = lambda request, obj: obj.contractee.contract
    
    
    class SigneeSignatureRepresentativeAdmin(
        IndexHiddenModelAdmin,
        permissions_mixin_factory(
            "contracts.edit_when_approved",
            "contracts.delete_when_approved",
            obj_conditional=lambda request, obj: get_obj_signee_contract(obj).is_approved,
        ),
        permissions_mixin_factory(
            "contracts.edit_others",
            "contracts.delete_others",
            obj_conditional=lambda request, obj: get_obj_contractee_contract(obj).created_by
            != request.user,
        ),
    ):
        pass
    
    
    class ContracteeSignatureRepresentativeAdmin(
        IndexHiddenModelAdmin,
        permissions_mixin_factory(
            "contracts.edit_when_approved",
            "contracts.delete_when_approved",
            obj_conditional=lambda request, obj: get_obj_contractee_contract(
                obj
            ).is_approved,
        ),
        permissions_mixin_factory(
            "contracts.edit_others",
            "contracts.delete_others",
            obj_conditional=lambda request, obj: get_obj_contractee_contract(obj).created_by
            != request.user,
        ),
    ):
        pass
    
    
    # END Signing parties
    
    
    class ContractSubmodelAdmin(
        IndexHiddenModelAdmin,
        ParentContractApprovedPermissionsMixin,
        ParentContractOwnPermissionsMixin,
    ):
        pass
    
    
    admin.site.register(Permission)
    
    for model in (
        SigneeSignature,
        ContracteeSignature,
        ContractApproval,
        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)