예제 #1
0
파일: lease.py 프로젝트: suutari-ai/mvj
    def get_queryset(self):  # noqa: C901
        """Allow filtering leases by various query parameters

        `identifier` query parameter can be used to find the Lease with the provided identifier.
        example: .../lease/?identifier=S0120-219
        `search` query parameter can be used to find leases by identifier and multiple other fields
        """
        succinct = self.request.query_params.get("succinct")

        if succinct:
            queryset = Lease.objects.succinct_select_related_and_prefetch_related()
        else:
            queryset = Lease.objects.full_select_related_and_prefetch_related()

        if self.action != "list":
            return queryset

        # Simple search
        identifier = self.request.query_params.get("identifier")
        search = self.request.query_params.get("search")

        if identifier is not None or search is not None:
            if search is None:
                search_string = identifier
                search_by_other = False
            else:
                search_string = search
                search_by_other = True

            looks_like_identifier = bool(
                re.match(r"[A-Z]\d{4}-\d+$", search_string.strip(), re.IGNORECASE)
            )

            # Search by identifier or parts of it
            if len(search_string) < 3:
                identifier_q = Q(
                    identifier__type__identifier__istartswith=search_string
                )
            elif len(search_string) == 3:
                identifier_q = Q(
                    identifier__type__identifier__iexact=search_string[:2],
                    identifier__municipality__identifier=search_string[2:3],
                )
            elif len(search_string) < 7:
                district_identifier = search_string[3:5]
                if district_identifier == "0":
                    identifier_q = Q(
                        identifier__type__identifier__iexact=search_string[:2],
                        identifier__municipality__identifier=search_string[2:3],
                        identifier__district__identifier__in=range(0, 10),
                    )
                else:
                    if district_identifier == "00":
                        district_identifier = "0"
                    else:
                        district_identifier = district_identifier.lstrip("0")

                    identifier_q = Q(
                        identifier__type__identifier__iexact=search_string[:2],
                        identifier__municipality__identifier=search_string[2:3],
                        identifier__district__identifier__startswith=district_identifier,
                    )
            elif looks_like_identifier:
                district_identifier = search_string[3:5]
                if district_identifier == "00":
                    district_identifier = "0"
                else:
                    district_identifier = district_identifier.lstrip("0")

                identifier_q = Q(
                    identifier__type__identifier__iexact=search_string[:2],
                    identifier__municipality__identifier=search_string[2:3],
                    identifier__district__identifier=district_identifier,
                    identifier__sequence__startswith=search_string[6:],
                )
            else:
                identifier_q = Q()

            other_q = Q()

            # Search also by other fields if the search string is clearly not a lease identifier
            if search_by_other and not looks_like_identifier:
                # Address
                other_q |= Q(lease_areas__addresses__address__icontains=search_string)

                # Property identifier
                other_q |= Q(lease_areas__identifier__icontains=search_string)
                normalized_identifier = normalize_property_identifier(search_string)
                if search_string != normalized_identifier:
                    other_q |= Q(
                        lease_areas__identifier__icontains=normalized_identifier
                    )

                # Tenantcontact name
                other_q |= Q(
                    tenants__tenantcontact__contact__name__icontains=search_string
                )

                if " " in search_string:
                    tenant_name_parts = search_string.split(" ", 2)
                    other_q |= Q(
                        tenants__tenantcontact__contact__first_name__icontains=tenant_name_parts[
                            0
                        ]
                    ) & Q(
                        tenants__tenantcontact__contact__last_name__icontains=tenant_name_parts[
                            1
                        ]
                    )
                    other_q |= Q(
                        tenants__tenantcontact__contact__first_name__icontains=tenant_name_parts[
                            1
                        ]
                    ) & Q(
                        tenants__tenantcontact__contact__last_name__icontains=tenant_name_parts[
                            0
                        ]
                    )
                else:
                    other_q |= Q(
                        tenants__tenantcontact__contact__first_name__icontains=search_string
                    )
                    other_q |= Q(
                        tenants__tenantcontact__contact__last_name__icontains=search_string
                    )

                # Lessor
                other_q |= Q(lessor__name__icontains=search_string)
                other_q |= Q(lessor__first_name__icontains=search_string)
                other_q |= Q(lessor__last_name__icontains=search_string)

                # Date
                try:
                    search_date = parse(
                        search_string, parserinfo=parserinfo(dayfirst=True)
                    )
                    if search_date:
                        other_q |= Q(start_date=search_date.date())
                        other_q |= Q(end_date=search_date.date())
                except ValueError:
                    pass

            queryset = queryset.filter(identifier_q | other_q)

        # Advanced search
        search_form = LeaseSearchForm(self.request.query_params)

        if search_form.is_valid():
            if search_form.cleaned_data.get("tenant_name"):
                tenant_name = search_form.cleaned_data.get("tenant_name")

                # Tenantcontact name
                q = Q(tenants__tenantcontact__contact__name__icontains=tenant_name)

                if " " in tenant_name:
                    tenant_name_parts = tenant_name.split(" ", 2)
                    q |= Q(
                        tenants__tenantcontact__contact__first_name__icontains=tenant_name_parts[
                            0
                        ]
                    ) & Q(
                        tenants__tenantcontact__contact__last_name__icontains=tenant_name_parts[
                            1
                        ]
                    )
                    q |= Q(
                        tenants__tenantcontact__contact__first_name__icontains=tenant_name_parts[
                            1
                        ]
                    ) & Q(
                        tenants__tenantcontact__contact__last_name__icontains=tenant_name_parts[
                            0
                        ]
                    )
                else:
                    q |= Q(
                        tenants__tenantcontact__contact__first_name__icontains=tenant_name
                    )
                    q |= Q(
                        tenants__tenantcontact__contact__last_name__icontains=tenant_name
                    )

                if search_form.cleaned_data.get("tenantcontact_type"):
                    q &= Q(
                        tenants__tenantcontact__type__in=search_form.cleaned_data.get(
                            "tenantcontact_type"
                        )
                    )

                if search_form.cleaned_data.get("only_past_tenants"):
                    q &= Q(tenants__tenantcontact__end_date__lte=datetime.date.today())

                if search_form.cleaned_data.get("tenant_activity"):
                    if search_form.cleaned_data.get("tenant_activity") == "past":
                        q &= Q(
                            tenants__tenantcontact__end_date__lte=datetime.date.today()
                        )

                    if search_form.cleaned_data.get("tenant_activity") == "active":
                        # No need to filter by start date because future start dates are also considered active
                        q &= Q(tenants__tenantcontact__end_date=None) | Q(
                            tenants__tenantcontact__end_date__gte=datetime.date.today()
                        )

                queryset = queryset.filter(q)

            if search_form.cleaned_data.get("sequence"):
                queryset = queryset.filter(
                    identifier__sequence=search_form.cleaned_data.get("sequence")
                )

            if search_form.cleaned_data.get("lease_start_date_start"):
                queryset = queryset.filter(
                    start_date__gte=search_form.cleaned_data.get(
                        "lease_start_date_start"
                    )
                )

            if search_form.cleaned_data.get("lease_start_date_end"):
                queryset = queryset.filter(
                    start_date__lte=search_form.cleaned_data.get("lease_start_date_end")
                )

            if search_form.cleaned_data.get("lease_end_date_start"):
                queryset = queryset.filter(
                    end_date__gte=search_form.cleaned_data.get("lease_end_date_start")
                )

            if search_form.cleaned_data.get("lease_end_date_end"):
                queryset = queryset.filter(
                    end_date__lte=search_form.cleaned_data.get("lease_end_date_end")
                )

            # Filter by active / expired only when only one of the options is set
            if bool(search_form.cleaned_data.get("only_active_leases")) ^ bool(
                search_form.cleaned_data.get("only_expired_leases")
            ):
                if search_form.cleaned_data.get("only_active_leases"):
                    # No need to filter by start date because future start dates are also considered active
                    queryset = queryset.filter(
                        Q(end_date__isnull=True)
                        | Q(end_date__gte=datetime.date.today())
                    )

                if search_form.cleaned_data.get("only_expired_leases"):
                    queryset = queryset.filter(end_date__lte=datetime.date.today())

            if "has_geometry" in search_form.cleaned_data:
                if search_form.cleaned_data.get("has_geometry") is True:
                    queryset = queryset.filter(lease_areas__geometry__isnull=False)

                if search_form.cleaned_data.get("has_geometry") is False:
                    queryset = queryset.filter(lease_areas__geometry__isnull=True)

            if search_form.cleaned_data.get("property_identifier"):
                property_identifier = search_form.cleaned_data.get(
                    "property_identifier"
                )
                normalized_identifier = normalize_property_identifier(
                    property_identifier
                )

                queryset = queryset.filter(
                    Q(lease_areas__identifier__icontains=property_identifier)
                    | Q(lease_areas__identifier__icontains=normalized_identifier)
                )

            if search_form.cleaned_data.get("address"):
                queryset = queryset.filter(
                    lease_areas__addresses__address__icontains=search_form.cleaned_data.get(
                        "address"
                    )
                )

            if search_form.cleaned_data.get("lease_state"):
                queryset = queryset.filter(
                    state__in=search_form.cleaned_data.get("lease_state")
                )

            if search_form.cleaned_data.get("business_id"):
                queryset = queryset.filter(
                    tenants__tenantcontact__contact__business_id__icontains=search_form.cleaned_data.get(
                        "business_id"
                    )
                )

            if search_form.cleaned_data.get("national_identification_number"):
                nat_id = search_form.cleaned_data.get("national_identification_number")
                queryset = queryset.filter(
                    tenants__tenantcontact__contact__national_identification_number__icontains=nat_id
                )

            if search_form.cleaned_data.get("lessor"):
                queryset = queryset.filter(
                    lessor=search_form.cleaned_data.get("lessor")
                )

            if search_form.cleaned_data.get("contract_number"):
                queryset = queryset.filter(
                    contracts__contract_number__icontains=search_form.cleaned_data.get(
                        "contract_number"
                    )
                )

            if search_form.cleaned_data.get("decision_maker"):
                queryset = queryset.filter(
                    decisions__decision_maker=search_form.cleaned_data.get(
                        "decision_maker"
                    )
                )

            if search_form.cleaned_data.get("decision_date"):
                queryset = queryset.filter(
                    decisions__decision_date=search_form.cleaned_data.get(
                        "decision_date"
                    )
                )

            if search_form.cleaned_data.get("decision_section"):
                queryset = queryset.filter(
                    decisions__section=search_form.cleaned_data.get("decision_section")
                )

            if search_form.cleaned_data.get("reference_number"):
                reference_number = search_form.cleaned_data.get("reference_number")
                queryset = queryset.filter(
                    Q(reference_number__icontains=reference_number)
                    | Q(decisions__reference_number__icontains=reference_number)
                )

            if search_form.cleaned_data.get("invoice_number"):
                queryset = queryset.filter(
                    invoices__number__icontains=search_form.cleaned_data.get(
                        "invoice_number"
                    )
                )

        return queryset.distinct()
예제 #2
0
def test_normalize_property_identifier(identifier, expected):
    assert normalize_property_identifier(identifier) == expected