Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
mhieta committed Dec 9, 2024
2 parents 21ae404 + 432be26 commit ce5a820
Show file tree
Hide file tree
Showing 19 changed files with 283 additions and 72 deletions.
2 changes: 1 addition & 1 deletion .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ INSTALL_PRECOMMIT=True
WAIT_FOR_IT_ADDRESS=parking-permits-database:5432

# OIDC auth settings
TOKEN_AUTH_ACCEPTED_AUDIENCE=parking-permits-api-dev
TOKEN_AUTH_ACCEPTED_AUDIENCE=parking-permits-api-dev,parking-permits-api-test
TOKEN_AUTH_ACCEPTED_SCOPE_PREFIX=access,gdprquery,gdprdelete
TOKEN_AUTH_AUTHSERVER_URL=https://tunnistus.test.hel.ninja/auth/realms/helsinki-tunnistus
TOKEN_AUTH_REQUIRE_SCOPE_PREFIX=True
Expand Down
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.5.0] - 2024-12-09

### Added

- Add support for webshop permit preliminary status ([d8b3846](https://github.com/City-of-Helsinki/parking-permits/commit/d8b38460c1ef77d83cd05117308f1ed5ff1d4dc2))
- Enable login for both Tunnistamo and KeyCloak ([3365134](https://github.com/City-of-Helsinki/parking-permits/commit/3365134237d0c4672a1b147d353a7bc4b00876db))
- Add management command to change consent_low_emission_accepted to False ([03e440e](https://github.com/City-of-Helsinki/parking-permits/commit/03e440e703d422d53bae973d99b27f3fd0b5a1b5))
- Allow StatusLog searches ([a7d35c2](https://github.com/City-of-Helsinki/parking-permits/commit/a7d35c2e9022c8abf6ac8cf66af35519dad0116c))
- Add id to OrderItemAdmin list display ([021c8da](https://github.com/City-of-Helsinki/parking-permits/commit/021c8da55acad6c4256c7090d3e07d0d1934db6e))

### Changed

- Update OIDC auth accepted audience format to list ([3b81294](https://github.com/City-of-Helsinki/parking-permits/commit/3b81294ef2750a84e66b210be3972c04c4bc9807))
- Update customer permit tests ([31128aa](https://github.com/City-of-Helsinki/parking-permits/commit/31128aa0ad39c4bd2752793f682bdf5c5591590d))
- Update Django Admin search fields ([37bd5d9](https://github.com/City-of-Helsinki/parking-permits/commit/37bd5d960acae3b5331f61fc327f76294e8791b2))
- Update existing draft permit if it exists ([c0ca12a](https://github.com/City-of-Helsinki/parking-permits/commit/c0ca12acfd6c56f1255754d61054099e6649b3b1))
- Update permit renewal end time calculation ([a0d4528](https://github.com/City-of-Helsinki/parking-permits/commit/a0d4528da7a815e5350f3d08d2357508345c18a8))
- Update Django Admin fields and ordering ([40257ca](https://github.com/City-of-Helsinki/parking-permits/commit/40257ca87dee3cbb243788829f3d31acbf5aa662))

### Fixed

- Fix a date bug where there might be gaps in days sent to Talpa ([3d1122c](https://github.com/City-of-Helsinki/parking-permits/commit/3d1122c42fcc3bbe9a6f7ef9c1069670dbc94e34))
- Increase Gunicorn header size limit ([e2d9803](https://github.com/City-of-Helsinki/parking-permits/commit/e2d98030108d8d410dcd8ce9a4523ba319623a37))
- Limit order items refunding to one time only ([81e4368](https://github.com/City-of-Helsinki/parking-permits/commit/81e43688f54274828d02d8e6ad5bc85036999e83))
- Update open-ended permit months left calculation ([24a8e9e](https://github.com/City-of-Helsinki/parking-permits/commit/24a8e9ed6f7911a7faa439064cb7d82e838b1ffb))

## [1.4.0] - 2024-11-25

### Added
Expand Down
1 change: 1 addition & 0 deletions gunicorn.conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

wsgi_app = "project.wsgi"
bind = "0.0.0.0:8888"
limit_request_field_size = 65536

accesslog = "-" # '-' makes gunicorn log to stdout
errorlog = "-" # '-' makes gunicorn log to stderr
94 changes: 78 additions & 16 deletions parking_permits/admin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from django.contrib.admin.sites import NotRegistered
from django.contrib.gis import admin
from django.urls import reverse
from django.utils.html import format_html
from django_db_logger.models import StatusLog

from parking_permits.models import (
Address,
Expand Down Expand Up @@ -28,7 +30,14 @@

@admin.register(Address)
class AddressAdmin(admin.GISModelAdmin):
search_fields = ("street_name", "street_name_sv", "city", "city_sv")
search_fields = (
"id",
"street_name",
"street_name_sv",
"city",
"city_sv",
"postal_code",
)
list_display = (
"id",
"street_name",
Expand All @@ -47,6 +56,7 @@ class AddressAdmin(admin.GISModelAdmin):

@admin.register(Announcement)
class AnnouncementAdmin(admin.ModelAdmin):
search_fields = ("id", "subject_en", "subject_fi", "subject_sv")
list_display = (
"id",
"subject_en",
Expand All @@ -67,7 +77,13 @@ class CompanyAdmin(admin.ModelAdmin):

@admin.register(Customer)
class CustomerAdmin(admin.ModelAdmin):
search_fields = ("first_name", "last_name")
search_fields = (
"id",
"first_name",
"last_name",
"national_id_number",
"email",
)
list_display = (
"__str__",
"id",
Expand All @@ -90,7 +106,11 @@ class DrivingClassAdmin(admin.ModelAdmin):

@admin.register(DrivingLicence)
class DrivingLicenceAdmin(admin.ModelAdmin):
search_fields = ("customer__first_name", "customer__last_name")
search_fields = (
"customer__first_name",
"customer__last_name",
"customer__national_id_number",
)
list_display = ("id", "customer", "start_date", "end_date", "active")
list_select_related = ("customer",)

Expand Down Expand Up @@ -139,10 +159,6 @@ class ParkingPermitAdmin(admin.ModelAdmin):
)
list_filter = ("contract_type", "status")
list_select_related = ("customer", "vehicle", "parking_zone")
ordering = (
"customer__first_name",
"customer__last_name",
)
raw_id_fields = (
"address",
"customer",
Expand All @@ -163,6 +179,7 @@ def latest_order(self, instance):
class ParkingPermitEventAdmin(admin.ModelAdmin):
date_hierarchy = "created_at"
search_fields = (
"parking_permit__id",
"parking_permit__customer__first_name",
"parking_permit__customer__last_name",
"parking_permit__customer__national_id_number",
Expand All @@ -178,6 +195,7 @@ class ParkingPermitEventAdmin(admin.ModelAdmin):

@admin.register(ParkingZone)
class ParkingZoneAdmin(admin.GISModelAdmin):
search_fields = ("name", "description", "description_sv")
list_display = ("id", "name", "description", "description_sv")
ordering = ("name",)

Expand All @@ -203,7 +221,9 @@ def get_form(self, request, obj=None, **kwargs):

@admin.register(Refund)
class RefundAdmin(admin.ModelAdmin):
search_fields = ("name", "iban", "orders__id")
list_display = (
"id",
"name",
"iban",
"get_orders",
Expand Down Expand Up @@ -250,6 +270,7 @@ class AccountingAdmin(admin.ModelAdmin):

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
search_fields = ("zone__name",)
list_display = (
"zone",
"type",
Expand All @@ -271,6 +292,14 @@ class ProductAdmin(admin.ModelAdmin):

@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
search_fields = (
"id",
"customer__last_name",
"customer__first_name",
"customer__national_id_number",
"talpa_order_id",
"vehicles",
)
list_filter = ("status", "type")
list_display = (
"id",
Expand All @@ -281,19 +310,14 @@ class OrderAdmin(admin.ModelAdmin):
"parking_zone_name",
"vehicles",
"get_vat_percents",
"talpa_order_id",
)
list_select_related = ("customer",)
readonly_fields = (
"talpa_order_id",
"total_payment_price",
"get_vat_percents",
)
search_fields = (
"customer__last_name",
"customer__first_name",
"customer__national_id_number",
"talpa_order_id",
)
raw_id_fields = (
"customer",
"created_by",
Expand All @@ -313,8 +337,17 @@ def get_vat_percents(self, obj):

@admin.register(OrderItem)
class OrderItemAdmin(admin.ModelAdmin):
search_fields = (
"id",
"order__id",
"talpa_order_item_id",
"order__talpa_order_id",
"subscription__talpa_subscription_id",
"permit__id",
)
raw_id_fields = ("permit", "order", "product", "subscription")
list_display = (
"id",
"order",
"subscription",
"product",
Expand All @@ -323,6 +356,7 @@ class OrderItemAdmin(admin.ModelAdmin):
"payment_unit_price",
"quantity",
"get_vat_percent",
"talpa_order_item_id",
)
list_select_related = ("order", "subscription", "product", "permit")
readonly_fields = ("talpa_order_item_id",)
Expand All @@ -335,21 +369,26 @@ def get_vat_percent(self, obj):

@admin.register(ParkingPermitExtensionRequest)
class ParkingPermitExtensionRequestAdmin(admin.ModelAdmin):
raw_id_fields = ("permit", "order")
list_filter = ("status",)
ordering = ("-created_at",)
search_fields = (
"permit__id",
"permit__customer__first_name",
"permit__customer__last_name",
"permit__vehicle__registration_number",
)
raw_id_fields = ("permit", "order")
list_filter = ("status",)
ordering = ("-created_at",)
list_display = ("permit", "status", "month_count")
list_select_related = True


@admin.register(Subscription)
class SubscriptionAdmin(admin.ModelAdmin):
search_fields = (
"id",
"talpa_subscription_id",
"order_items__talpa_order_item_id",
)
list_filter = ("status",)
list_display = (
"id",
Expand All @@ -374,7 +413,9 @@ def get_talpa_order_item_id(self, obj):

@admin.register(TemporaryVehicle)
class TemporaryVehicleAdmin(admin.ModelAdmin):
search_fields = ("id", "vehicle__registration_number")
list_display = (
"id",
"vehicle",
"start_time",
"end_time",
Expand All @@ -385,9 +426,30 @@ class TemporaryVehicleAdmin(admin.ModelAdmin):

@admin.register(VehicleUser)
class VehicleUserAdmin(admin.ModelAdmin):
search_fields = (
"national_id_number",
"vehicles__registration_number",
)
list_display = ("national_id_number", "get_vehicles")
ordering = ("national_id_number",)

@admin.display(description="Vehicles")
def get_vehicles(self, obj):
return [vehicle.registration_number for vehicle in obj.vehicles.all()]


# Importing the default StatusLogAdmin will automatically register the StatusLog model
from django_db_logger.admin import StatusLogAdmin # noqa: F401, E402

# Unregister the StatusLog model from the admin site registry
try:
admin.site.unregister(StatusLog)
except NotRegistered:
pass


# Create application specific StatusLogAdmin
@admin.register(StatusLog)
class ParkingPermitsStatusLogAdmin(StatusLogAdmin):
search_fields = ("msg",) # Add search field for the message
list_per_page = 30
15 changes: 12 additions & 3 deletions parking_permits/admin_resolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -517,10 +517,10 @@ def resolve_create_resident_permit(obj, info, permit, audit_msg: AuditMsg = None
_("Vehicle registration number is mandatory for the permit")
)

has_valid_permit = active_permits.filter(
valid_permit_exists = active_permits.filter(
vehicle__registration_number=registration_number
).exists()
if has_valid_permit:
if valid_permit_exists:
raise CreatePermitError(
_("User already has a valid permit for the given vehicle.")
)
Expand Down Expand Up @@ -578,10 +578,19 @@ def resolve_create_resident_permit(obj, info, permit, audit_msg: AuditMsg = None
]:
permit_status = ParkingPermitStatus.VALID

permit_id = permit.get("id")
# always update existing draft permit if it exists for the given vehicle
draft_permits = customer.permits.fixed_period().filter(
vehicle__registration_number=registration_number,
status__in=[ParkingPermitStatus.DRAFT, ParkingPermitStatus.PRELIMINARY],
)
if draft_permits.exists():
permit_id = draft_permits.first().id

primary_vehicle = active_permits_count == 0
# only create a new permit when it doesn't exist
parking_permit, permit_created = ParkingPermit.objects.update_or_create(
pk=permit.get("id"),
pk=permit_id,
defaults={
"contract_type": ContractType.FIXED_PERIOD,
"customer": customer,
Expand Down
14 changes: 9 additions & 5 deletions parking_permits/customer_permit.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
IMMEDIATELY = ParkingPermitStartType.IMMEDIATELY
OPEN_ENDED = ContractType.OPEN_ENDED
DRAFT = ParkingPermitStatus.DRAFT
PRELIMINARY = ParkingPermitStatus.PRELIMINARY
VALID = ParkingPermitStatus.VALID
PAYMENT_IN_PROGRESS = ParkingPermitStatus.PAYMENT_IN_PROGRESS
CANCELLED = ParkingPermitStatus.CANCELLED
Expand All @@ -65,7 +66,8 @@ class CustomerPermit:
def __init__(self, customer_id):
self.customer = Customer.objects.get(id=customer_id)
self.customer_permit_query = ParkingPermit.objects.filter(
customer=self.customer, status__in=[VALID, PAYMENT_IN_PROGRESS, DRAFT]
customer=self.customer,
status__in=[VALID, PAYMENT_IN_PROGRESS, DRAFT, PRELIMINARY],
)

def create_permit_extension_request(
Expand Down Expand Up @@ -276,7 +278,7 @@ def create(self, address_id, registration):

def delete(self, permit_id):
permit = ParkingPermit.objects.get(customer=self.customer, id=permit_id)
if permit.status != DRAFT:
if permit.status not in [DRAFT, PRELIMINARY]:
raise PermitCanNotBeDeleted(_("Non draft permit can not be deleted"))
OrderItem.objects.filter(permit=permit).delete()
permit.delete()
Expand Down Expand Up @@ -332,7 +334,7 @@ def update(self, data, permit_id=None):

# Second permit can not be open ended if primary permit valid or processing and is fixed period
if (
primary.status != DRAFT
primary.status not in [DRAFT, PRELIMINARY]
and primary.contract_type == FIXED_PERIOD
and contract_type != FIXED_PERIOD
):
Expand All @@ -344,7 +346,7 @@ def update(self, data, permit_id=None):
if permit_id:
permit, is_primary = self._get_permit(permit_id)

if permit.status != DRAFT:
if permit.status not in [DRAFT, PRELIMINARY]:
raise NonDraftPermitUpdateError(
_("This is not a draft permit and can not be edited")
)
Expand Down Expand Up @@ -424,7 +426,9 @@ def _get_address_apartments(self, address: Address):
return customer.other_address_apartment, customer.other_address_apartment_sv

def _update_fields_to_all_draft(self, data):
permits = self.customer_permit_query.filter(status=DRAFT).all()
permits = self.customer_permit_query.filter(
status__in=[DRAFT, PRELIMINARY]
).all()
return [self._update_permit(permit, data) for permit in permits]

def _update_permit(self, permit: ParkingPermit, data: dict):
Expand Down
Loading

0 comments on commit ce5a820

Please sign in to comment.