diff --git a/docs/api/enforcement.yaml b/docs/api/enforcement.yaml index ee23d1fa..e7e0af7b 100644 --- a/docs/api/enforcement.yaml +++ b/docs/api/enforcement.yaml @@ -386,6 +386,16 @@ paths: given, defaults to current time. type: string format: date-time + details: + description: >- + Optional additional details. Takes as argument a list of preferred details. + The details are: operator, time_start and permissions. + type: array + items: + type: string + default: [] + example: ["operator", "time_start", "permissions"] + responses: '200': description: OK. Validity check succeeded. @@ -454,11 +464,53 @@ paths: nullable: true time: description: >- - Time used in the check. It will either be equal + Time used in the check. It will either be equal to the time value provided in the request or the current time if none was provided. type: string format: date-time + operator: + description: >- + If 'operator' in details, returns the operator + of the allowed parking. + type: string + nullable: true + time_start: + description: >- + If 'time_start' in details, returns the time_start + of the allowed parking. + type: string + format: date-time + nullable: true + permissions: + description: >- + If 'permissions' in details, returns the active permissions + for the registration number. + type: object + properties: + event_areas: + description: >- + List of event area IDs to which the registration number has permissions. + type: array + items: + type: string + zones: + description: List of zones to which the registration number has permissions. + type: array + items: + type: integer + permits: + description: List of active permits for the registration number. + type: array + items: + type: object + properties: + external_id: + type: string + subjects: &permitSubjects + $ref: '#/components/schemas/PermitSubjects' + targets: &permitAreas + $ref: '#/components/schemas/PermitAreas' '400': $ref: '#/components/responses/BadRequest' '401': diff --git a/parkings/api/enforcement/check_parking.py b/parkings/api/enforcement/check_parking.py index 12499717..da3e6c7b 100644 --- a/parkings/api/enforcement/check_parking.py +++ b/parkings/api/enforcement/check_parking.py @@ -8,12 +8,22 @@ from rest_framework.response import Response from ...models import ( - EventArea, EventParking, Parking, ParkingCheck, PaymentZone, PermitArea, - PermitLookupItem) + EventArea, EventParking, Parking, ParkingCheck, PaymentZone, Permit, + PermitArea, PermitLookupItem) from ...models.constants import GK25FIN_SRID, WGS84_SRID from .permissions import IsEnforcer +class PermitPermissionsSerializer(serializers.ModelSerializer): + class Meta: + model = Permit + fields = [ + "external_id", + "subjects", + "areas" + ] + + class AwareDateTimeField(serializers.DateTimeField): default_error_messages = dict( serializers.DateField.default_error_messages, @@ -35,6 +45,7 @@ class CheckParkingSerializer(serializers.Serializer): registration_number = serializers.CharField(max_length=20) location = LocationSerializer() time = AwareDateTimeField(required=False) + details = serializers.ListSerializer(child=serializers.CharField(), required=False) class CheckParking(generics.GenericAPIView): @@ -62,7 +73,7 @@ def post(self, request): area = get_permit_area(gk25_location, domain) event_area = get_event_area(gk25_location, domain) - (allowed_by, parking, end_time) = check_parking( + (allowed_by, parking, end_time, active_parkings, permit_lookup_items, active_event_parkings) = check_parking( registration_number, zone, area, time, domain, event_area) allowed = bool(allowed_by) @@ -71,8 +82,20 @@ def post(self, request): # one that has just expired, i.e. was valid a few minutes # ago (where "a few minutes" is the grace duration) past_time = time - get_grace_duration() - (_allowed_by, parking, end_time) = check_parking( - registration_number, zone, area, past_time, domain, event_area) + ( + _allowed_by, + parking, + end_time, + active_parkings, + permit_lookup_items, + active_event_parkings + ) = check_parking( + registration_number, + zone, area, + past_time, + domain, + event_area + ) result = { "allowed": allowed, @@ -84,6 +107,24 @@ def post(self, request): }, "time": time, } + + operator_detail, time_start_detail, permissions_detail = get_details(params) + + if operator_detail: + result["operator"] = parking.operator.name if allowed and parking and parking.operator else None + + if time_start_detail: + result["time_start"] = parking.time_start if allowed and parking and parking.time_start else None + + if permissions_detail: + result["permissions"] = { + "zones": list({p.zone.number for p in active_parkings}), + "permits": [ + PermitPermissionsSerializer(item.permit).data for item in permit_lookup_items + ], + "event_areas": list({e_p.event_area.id for e_p in active_event_parkings}) + } + filter = { "performer": request.user, "time": time, @@ -93,6 +134,7 @@ def post(self, request): "result": result, "allowed": allowed } + if isinstance(parking, Parking): filter["found_parking"] = parking if isinstance(parking, EventParking): @@ -102,6 +144,22 @@ def post(self, request): return Response(result) +def get_details(params): + details = params.get("details", []) + operator = False + time_start = False + permissions = False + + for detail in [d.lower() for d in details]: + if detail == "operator": + operator = True + if detail == "time_start": + time_start = True + if detail == "permissions": + permissions = True + return operator, time_start, permissions + + def get_location(params): longitude = params["location"]["longitude"] latitude = params["location"]["latitude"] @@ -151,8 +209,15 @@ def check_parking(registration_number, zone, area, time, domain, event_area): :type area: str|None :type domain: parkings.models.EnforcementDomain :type time: datetime.datetime - :rtype: (str, Parking|None, datetime.datetime) + :rtype: (str, Parking|None, datetime.datetime, ParkingQuerySet, PermitLookupItemQuerySet, EventParkingQuerySet) """ + permit_lookup_items = ( + PermitLookupItem.objects + .active() + .by_time(time) + .by_subject(registration_number) + .filter(permit__domain=domain)) + active_parkings = ( Parking.objects .registration_number_like(registration_number) @@ -160,39 +225,37 @@ def check_parking(registration_number, zone, area, time, domain, event_area): .only("id", "zone", "time_end") .filter(domain=domain)) + active_event_parkings = ( + EventParking.objects + .registration_number_like(registration_number) + .valid_at(time) + .only("id", "time_end") + .filter(domain=domain)) + for parking in active_parkings: if zone is None or parking.zone.number <= zone: - return ("parking", parking, parking.time_end) + return ("parking", + parking, + parking.time_end, + active_parkings, + permit_lookup_items, + active_event_parkings) if area: - permit_end_time = ( - PermitLookupItem.objects - .active() - .by_time(time) - .by_subject(registration_number) - .by_area(area) - .values_list("end_time", flat=True) - .filter(permit__domain=domain) - .first()) - + permit_end_time = permit_lookup_items.by_area(area).values_list("end_time", flat=True).first() if permit_end_time: - return ("permit", None, permit_end_time) + return ("permit", None, permit_end_time, active_parkings, permit_lookup_items, active_event_parkings) - active_event_parking = ( - EventParking.objects - .registration_number_like(registration_number) - .valid_at(time) - .only("id", "time_end") - .filter(domain=domain)).first() - - if active_event_parking: + for active_event_parking in active_event_parkings: if active_event_parking.event_area == event_area: - return ("event parking", active_event_parking, active_event_parking.time_end) - else: - # Event parking not parked in the assigned event area, i.e., not allowed. - return (None, active_event_parking, active_event_parking.time_end) - - return (None, None, None) + return ("event_parking", + active_event_parking, + active_event_parking.time_end, + active_parkings, + permit_lookup_items, + active_event_parkings) + + return (None, None, None, active_parkings, permit_lookup_items, active_event_parkings) def get_grace_duration(default=datetime.timedelta(minutes=15)): diff --git a/parkings/tests/api/enforcement/test_check_parking.py b/parkings/tests/api/enforcement/test_check_parking.py index f6a2ea8b..1fe26a1c 100644 --- a/parkings/tests/api/enforcement/test_check_parking.py +++ b/parkings/tests/api/enforcement/test_check_parking.py @@ -2,6 +2,7 @@ import datetime import json +from copy import deepcopy from datetime import timedelta import pytest @@ -53,14 +54,23 @@ (26.8, 64.1), # South West corner ] +GEOM_3 = [ + (23.8, 64.3), # North West corner + (24.0, 64.3), # North East corner + (24.0, 64.1), # South East corner + (23.8, 64.1), # South West corner +] + -def create_permit_area(client=None, domain=None, allowed_user=None): +def create_permit_area(client=None, domain=None, allowed_user=None, identifier="A", name="Kamppi", geom=None): assert client or (domain and allowed_user) + if geom is None: + geom = create_area_geom() area = PermitArea.objects.create( domain=(domain or client.enforcer.enforced_domain), - identifier="A", - name="Kamppi", - geom=create_area_geom()) + identifier=identifier, + name=name, + geom=geom) area.allowed_users.add(allowed_user or client.auth_user) return area @@ -77,21 +87,22 @@ def create_area_geom(geom=GEOM_1): return MultiPolygon(polygons) -def create_permit(domain, permit_series=None, end_time=None): +def create_permit(domain, permit_series=None, end_time=None, registration_number="ABC-123", area="A", start_time=None): end_time = end_time or timezone.now() + datetime.timedelta(days=1) - start_time = timezone.now() + if not start_time: + start_time = timezone.now() series = permit_series or create_permit_series(active=True) subjects = [ { "end_time": str(end_time), "start_time": str(start_time), - "registration_number": "ABC-123", + "registration_number": registration_number, } ] - areas = [{"area": "A", "end_time": str(end_time), "start_time": str(start_time)}] + areas = [{"area": area, "end_time": str(end_time), "start_time": str(start_time)}] - Permit.objects.create( + return Permit.objects.create( domain=domain, series=series, external_id=12345, subjects=subjects, areas=areas ) @@ -109,32 +120,145 @@ def test_check_parking_allowed_event_parking(enforcer_api_client, event_parking_ registration_number=event_parking.registration_number).first().result["allowed"] is True -def test_check_parking_not_allowed_event_parking( +def test_check_parking_allowed_event_parking_details( + enforcer_api_client, event_parking_factory, enforcer, event_area_factory): + event_area = event_area_factory.create(geom=create_area_geom(), domain=enforcer.enforced_domain) + event_parking = event_parking_factory(registration_number="ABC-123", + domain=enforcer.enforced_domain, event_area=event_area) + data = deepcopy(PARKING_DATA) + data["details"] = ["operator", "time_start", "permissions"] + response = enforcer_api_client.post(list_url, data=data) + + assert response.status_code == HTTP_200_OK + assert response.data["allowed"] is True + assert response.data["end_time"] == event_parking.time_end + assert response.data["permissions"]["event_areas"][0] == event_area.id + assert response.data["operator"] == event_parking.operator.name + assert response.data["time_start"] == event_parking.time_start + assert ParkingCheck.objects.filter( + registration_number=event_parking.registration_number).first().result["allowed"] is True + + +def test_check_parking_not_allowed_event_parking_details( enforcer_api_client, event_parking_factory, enforcer, event_area_factory): event_area = event_area_factory.create(geom=create_area_geom(), domain=enforcer.enforced_domain) event_parking_factory(registration_number="CBA-123", domain=enforcer.enforced_domain, event_area=event_area) - response = enforcer_api_client.post(list_url, data=PARKING_DATA) + data = deepcopy(PARKING_DATA) + data["details"] = ["operator", "time_start", "permissions"] + + response = enforcer_api_client.post(list_url, data=data) assert response.status_code == HTTP_200_OK assert response.data["allowed"] is False assert response.data["end_time"] is None - + assert response.data["permissions"]["event_areas"] == [] + assert response.data["permissions"]["zones"] == [] + assert response.data["operator"] is None + assert response.data["time_start"] is None assert ParkingCheck.objects.filter( registration_number=PARKING_DATA["registration_number"]).first().result["allowed"] is False -def test_check_event_parking_parked_in_wrong_event_area( +def test_check_event_parking_parked_in_wrong_event_area_include_details( enforcer_api_client, event_parking_factory, enforcer, event_area_factory): event_area_1 = event_area_factory.create(geom=create_area_geom(), domain=enforcer.enforced_domain) event_area_2 = event_area_factory.create(geom=create_area_geom(geom=GEOM_2), domain=enforcer.enforced_domain) # Parked inside event_area_2, i.e., inside GEOM_2, but event_area_1 is assigned location = Point(PARKING_DATA_2["location"]["longitude"], PARKING_DATA_2["location"]["latitude"], srid=WGS84_SRID) - event_parking = event_parking_factory(registration_number="ABC-123", - domain=enforcer.enforced_domain, event_area=event_area_1, location=location) - response = enforcer_api_client.post(list_url, data=PARKING_DATA_2) + event_parking_factory(registration_number="ABC-123", domain=enforcer.enforced_domain, + event_area=event_area_1, location=location) + data = deepcopy(PARKING_DATA_2) + data["details"] = ["operator", "time_start", "permissions"] + response = enforcer_api_client.post(list_url, data=data) + assert response.status_code == HTTP_200_OK assert response.data["location"]["event_area"] == event_area_2.id assert response.data["allowed"] is False - assert response.data["end_time"] == event_parking.time_end + assert response.data["end_time"] is None + assert len(response.data["permissions"]["event_areas"]) == 1 + assert event_area_1.id in response.data["permissions"]["event_areas"] + assert response.data["permissions"]["zones"] == [] + assert response.data["operator"] is None + assert response.data["time_start"] is None + assert ParkingCheck.objects.filter( + registration_number=PARKING_DATA["registration_number"]).first().result["allowed"] is False + + +def test_check_parking_not_allowed_parking_and_event_parking_permission_details( + enforcer_api_client, event_parking_factory, operator, enforcer, event_area_factory, parking_factory): + # In this very improbable scenario, the registration number has an active parking and active event parking, + # but the vehicle is parked outside the active zone and event area. + event_area = event_area_factory.create(geom=create_area_geom(geom=GEOM_2), domain=enforcer.enforced_domain) + event_parking_factory(registration_number="ABC-123", + domain=enforcer.enforced_domain, event_area=event_area) + create_payment_zone(domain=enforcer.enforced_domain) + zone = create_payment_zone(geom=create_area_geom(geom=GEOM_2), number=2, code="2", domain=enforcer.enforced_domain) + parking = parking_factory(registration_number="ABC-123", operator=operator, zone=zone, domain=zone.domain) + data = deepcopy(PARKING_DATA) + data["details"] = ["time_start", "operator", "permissions"] + response = enforcer_api_client.post(list_url, data=data) + + assert response.status_code == HTTP_200_OK + assert response.data["allowed"] is False + assert response.data["permissions"]["event_areas"] == [event_area.id] + assert response.data["permissions"]["zones"] == [parking.zone.number] + assert response.data["operator"] is None + assert response.data["time_start"] is None + assert ParkingCheck.objects.filter( + registration_number=PARKING_DATA["registration_number"]).first().result["allowed"] is False + + +def test_check_parking_not_allowed_multiple_active_parkings_and_permits_permissions_details( + enforcer_api_client, + event_parking_factory, + operator, enforcer, + event_area_factory, + parking_factory +): + # In this very improbable scenario, the registration number has two active event parkings, active parkings + # and permits, but the vehicle is parked outside its active parkings and permits. + event_area_1 = event_area_factory.create(geom=create_area_geom(geom=GEOM_3), domain=enforcer.enforced_domain) + event_parking_factory(registration_number="ABC-123", + domain=enforcer.enforced_domain, event_area=event_area_1) + event_area_2 = event_area_factory.create(geom=create_area_geom(geom=GEOM_2), domain=enforcer.enforced_domain) + event_parking_factory(registration_number="ABC-123", + domain=enforcer.enforced_domain, event_area=event_area_2) + + zone_1 = create_payment_zone(domain=enforcer.enforced_domain) + zone_2 = create_payment_zone(geom=create_area_geom(geom=GEOM_2), number=2, + code="2", domain=enforcer.enforced_domain) + zone_3 = create_payment_zone(geom=create_area_geom(geom=GEOM_3), number=3, + code="3", domain=enforcer.enforced_domain) + parking_factory(registration_number="ABC-123", operator=operator, zone=zone_2, domain=zone_1.domain) + parking_factory(registration_number="ABC-123", operator=operator, zone=zone_3, domain=zone_2.domain) + + create_permit_area(enforcer_api_client, geom=create_area_geom(geom=GEOM_2)) + create_permit_area(enforcer_api_client, identifier="B", name="Kauppatori", geom=create_area_geom(geom=GEOM_3)) + + permit_1 = create_permit(domain=enforcer_api_client.enforcer.enforced_domain, + start_time=timezone.now() - datetime.timedelta(days=1)) + permit_2 = create_permit(domain=enforcer_api_client.enforcer.enforced_domain, area="B", + start_time=timezone.now() - datetime.timedelta(days=1)) + + data = deepcopy(PARKING_DATA) + data["details"] = ["time_start", "operator", "permissions"] + response = enforcer_api_client.post(list_url, data=data) + + assert response.status_code == HTTP_200_OK + assert response.data["allowed"] is False + assert response.data["location"]["payment_zone"] == zone_1.number + assert len(response.data["permissions"]["event_areas"]) == 2 + assert event_area_1.id in response.data["permissions"]["event_areas"] + assert event_area_2.id in response.data["permissions"]["event_areas"] + assert len(response.data["permissions"]["zones"]) == 2 + assert zone_2.number in response.data["permissions"]["zones"] + assert zone_3.number in response.data["permissions"]["zones"] + assert len(response.data["permissions"]["permits"]) == 2 + assert response.data["permissions"]["permits"][0]["subjects"] == permit_1.subjects + assert response.data["permissions"]["permits"][0]["areas"] == permit_1.areas + assert response.data["permissions"]["permits"][1]["subjects"] == permit_2.subjects + assert response.data["permissions"]["permits"][1]["areas"] == permit_2.areas + assert response.data["operator"] is None + assert response.data["time_start"] is None assert ParkingCheck.objects.filter( registration_number=PARKING_DATA["registration_number"]).first().result["allowed"] is False @@ -143,13 +267,13 @@ def test_check_event_parking_outside_event_area( enforcer_api_client, event_parking_factory, enforcer, event_area_factory): event_area = event_area_factory.create(geom=create_area_geom(), domain=enforcer.enforced_domain) location = Point(PARKING_DATA_2["location"]["longitude"], PARKING_DATA_2["location"]["latitude"], srid=WGS84_SRID) - event_parking = event_parking_factory(registration_number="ABC-123", - domain=enforcer.enforced_domain, event_area=event_area, location=location) + event_parking_factory(registration_number="ABC-123", + domain=enforcer.enforced_domain, event_area=event_area, location=location) response = enforcer_api_client.post(list_url, data=PARKING_DATA_2) assert response.status_code == HTTP_200_OK assert response.data["location"]["event_area"] is None assert response.data["allowed"] is False - assert response.data["end_time"] == event_parking.time_end + assert response.data["end_time"] is None assert ParkingCheck.objects.filter( registration_number=PARKING_DATA["registration_number"]).first().result["allowed"] is False @@ -188,6 +312,81 @@ def test_check_parking_valid_parking(operator, enforcer, enforcer_api_client, pa assert response.data["end_time"] == parking.time_end +def test_check_parking_details_operator_parameter(operator, enforcer, enforcer_api_client, parking_factory): + zone = create_payment_zone(domain=enforcer.enforced_domain) + parking = parking_factory(registration_number="ABC-123", operator=operator, zone=zone, domain=zone.domain) + data = deepcopy(PARKING_DATA) + data["details"] = ["operator"] + response = enforcer_api_client.post(list_url, data=data) + + assert response.status_code == HTTP_200_OK + assert response.data["operator"] == operator.name + assert response.data["allowed"] is True + assert response.data["end_time"] == parking.time_end + assert ParkingCheck.objects.filter( + registration_number=PARKING_DATA["registration_number"]).first().result["allowed"] is True + + +def test_check_parking_details_time_start_parameter(operator, enforcer, enforcer_api_client, parking_factory): + zone = create_payment_zone(domain=enforcer.enforced_domain) + parking = parking_factory(registration_number="ABC-123", operator=operator, zone=zone, domain=zone.domain) + data = deepcopy(PARKING_DATA) + data["details"] = ["time_start"] + response = enforcer_api_client.post(list_url, data=data) + + assert response.status_code == HTTP_200_OK + assert response.data["time_start"] == parking.time_start + assert response.data["allowed"] is True + assert response.data["end_time"] == parking.time_end + assert ParkingCheck.objects.filter( + registration_number=PARKING_DATA["registration_number"]).first().result["allowed"] is True + + +def test_check_parking_details_permissions_parameter(operator, enforcer, enforcer_api_client, parking_factory): + zone = create_payment_zone(domain=enforcer.enforced_domain) + parking = parking_factory(registration_number="ABC-123", operator=operator, zone=zone, domain=zone.domain) + data = deepcopy(PARKING_DATA) + data["details"] = ["permissions"] + response = enforcer_api_client.post(list_url, data=data) + + assert response.status_code == HTTP_200_OK + assert response.data["permissions"]["zones"] == [parking.zone.number] + assert response.data["permissions"]["event_areas"] == [] + assert response.data["allowed"] is True + assert response.data["end_time"] == parking.time_end + + +def test_check_parking_details_parking_not_allowed(operator, enforcer, enforcer_api_client, parking_factory): + data = deepcopy(PARKING_DATA) + data["details"] = ["operator", "time_start", "permissions"] + response = enforcer_api_client.post(list_url, data=data) + + assert response.status_code == HTTP_200_OK + assert response.data["allowed"] is False + assert response.data["operator"] is None + assert response.data["time_start"] is None + assert response.data["permissions"]["zones"] == [] + assert ParkingCheck.objects.filter( + registration_number=PARKING_DATA["registration_number"]).first().result["allowed"] is False + + +def test_check_parking_details_invalid_zone(operator, enforcer, enforcer_api_client, parking_factory): + create_payment_zone(domain=enforcer.enforced_domain) + zone = create_payment_zone(geom=create_area_geom(geom=GEOM_2), number=2, code="2", domain=enforcer.enforced_domain) + parking = parking_factory(registration_number="ABC-123", operator=operator, zone=zone, domain=zone.domain) + data = deepcopy(PARKING_DATA) + data["details"] = ["operator", "time_start", "permissions"] + + response = enforcer_api_client.post(list_url, data=data) + + assert response.status_code == HTTP_200_OK + assert response.data["allowed"] is False + assert response.data["end_time"] is None + assert response.data["permissions"]["zones"] == [parking.zone.number] + assert response.data["operator"] is None + assert response.data["time_start"] is None + + def test_check_parking_invalid_time_parking(operator, enforcer, enforcer_api_client, history_parking_factory): zone = create_payment_zone(domain=enforcer.enforced_domain) history_parking_factory(registration_number="ABC-123", operator=operator, zone=zone, domain=zone.domain) @@ -219,6 +418,72 @@ def test_check_parking_valid_permit(enforcer_api_client, staff_user): assert response.data["allowed"] is True +def test_check_parking_valid_parking_permit_details(enforcer_api_client, staff_user): + create_permit_area(enforcer_api_client) + permit = create_permit(domain=enforcer_api_client.enforcer.enforced_domain) + data = deepcopy(PARKING_DATA) + data["details"] = ["operator", "time_start", "permissions"] + response = enforcer_api_client.post(list_url, data=data) + + assert response.status_code == HTTP_200_OK + assert response.data["allowed"] is True + assert response.data["operator"] is None + assert response.data["time_start"] is None + assert response.data["permissions"]["zones"] == [] + assert response.data["permissions"]["event_areas"] == [] + assert len(response.data["permissions"]["permits"]) == 1 + assert response.data["permissions"]["permits"][0]["subjects"] == permit.subjects + assert response.data["permissions"]["permits"][0]["areas"] == permit.areas + assert ParkingCheck.objects.filter( + registration_number=PARKING_DATA["registration_number"]).first().result["allowed"] is True + + +def test_check_parking_invalid_location_multiple_permit_details(enforcer_api_client, staff_user): + create_permit_area(enforcer_api_client) + create_permit_area(enforcer_api_client, identifier="B", name="Kauppatori", geom=create_area_geom(geom=GEOM_2)) + + permit_1 = create_permit(domain=enforcer_api_client.enforcer.enforced_domain, + start_time=timezone.now() - datetime.timedelta(days=1)) + permit_2 = create_permit(domain=enforcer_api_client.enforcer.enforced_domain, area="B", + start_time=timezone.now() - datetime.timedelta(days=1)) + + data = deepcopy(INVALID_PARKING_DATA) + data["details"] = ["permissions"] + response = enforcer_api_client.post(list_url, data=data) + assert response.status_code == HTTP_200_OK + assert response.data["allowed"] is False + assert len(response.data["permissions"]["permits"]) == 2 + assert response.data["permissions"]["permits"][0]["subjects"] == permit_1.subjects + assert response.data["permissions"]["permits"][0]["areas"] == permit_1.areas + assert response.data["permissions"]["permits"][1]["subjects"] == permit_2.subjects + assert response.data["permissions"]["permits"][1]["areas"] == permit_2.areas + assert ParkingCheck.objects.filter( + registration_number=PARKING_DATA["registration_number"]).first().result["allowed"] is False + + +def test_check_parking_valid_parking_with_permit_details(enforcer_api_client, parking_factory, operator): + create_permit_area(enforcer_api_client, identifier="B", name="Kauppatori", geom=create_area_geom(geom=GEOM_2)) + + permit_1 = create_permit(domain=enforcer_api_client.enforcer.enforced_domain, + start_time=timezone.now() - datetime.timedelta(days=1), area="B") + + zone = create_payment_zone(domain=enforcer_api_client.enforcer.enforced_domain) + parking = parking_factory(registration_number="ABC-123", operator=operator, zone=zone, domain=zone.domain) + data = deepcopy(PARKING_DATA) + data["details"] = ["time_start", "operator", "permissions"] + response = enforcer_api_client.post(list_url, data=data) + assert response.status_code == HTTP_200_OK + assert response.data["allowed"] is True + assert len(response.data["permissions"]["permits"]) == 1 + assert response.data["permissions"]["permits"][0]["subjects"] == permit_1.subjects + assert response.data["permissions"]["permits"][0]["areas"] == permit_1.areas + assert response.data["permissions"]["zones"] == [parking.zone.number] + assert response.data["time_start"] == parking.time_start + assert response.data["operator"] == parking.operator.name + assert ParkingCheck.objects.filter( + registration_number=PARKING_DATA["registration_number"]).first().result["allowed"] is True + + def test_check_parking_invalid_time_permit(enforcer_api_client, staff_user): create_permit_area(enforcer_api_client) end_time = timezone.now() - datetime.timedelta(days=1)