diff --git a/.env b/.env index 58887a98f..54a17528a 100644 --- a/.env +++ b/.env @@ -26,12 +26,8 @@ DEFAULT_THEME=Vakantieverhuur DEFAULT_REASON=SIG melding VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_URL=https://api.acceptatie.toeristischeverhuur.nl/api/ VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_ACCESS_TOKEN=SECRET_ACCESS_TOKEN -VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_HEALTH_CHECK_BAG_ID=0503100000000209 -VAKANTIEVERHUUR_REGISTRATIE_API_URL=https://acceptatie.toeristischeverhuur.nl/ext/api/Registrations/ -VAKANTIEVERHUUR_REGISTRATIE_API_ACCESS_TOKEN=SECRET_ACCESS_TOKEN -VAKANTIEVERHUUR_REGISTRATIE_API_HEALTH_CHECK_BSN=999999990 -VAKANTIEVERHUUR_REGISTRATIE_API_HEALTH_CHECK_BAG_ID=0503100000000209 -VAKANTIEVERHUUR_REGISTRATIE_API_HEALTH_CHECK_REGISTRATION_NUMBER=05034542BC484F3891BB +VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_BAG_ID=0503100000000209 +VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_BSN=999999990 ZAKEN_CONTAINER_HOST=http://zaak-gateway:8000 DEFAULT_SCHEDULE_ACTIONS=Huisbezoek,Hercontrole diff --git a/app/apps/addresses/serializers.py b/app/apps/addresses/serializers.py index 9848a4d15..6213e6404 100644 --- a/app/apps/addresses/serializers.py +++ b/app/apps/addresses/serializers.py @@ -120,3 +120,17 @@ class MeldingenSerializer(serializers.Serializer): totalPages = serializers.IntegerField() totalRecords = serializers.IntegerField() data = serializers.ListField(child=serializers.DictField()) + + +class RegistrationNumberSerializer(serializers.Serializer): + registrationNumber = serializers.CharField(required=True) + + +class RegistrationDetailsSerializer(serializers.Serializer): + registrationNumber = serializers.CharField(required=True) + requester = serializers.DictField() + rentalHouse = serializers.DictField() + requestForOther = serializers.BooleanField() + requestForBedAndBreakfast = serializers.BooleanField() + createdAt = serializers.DateTimeField() + agreementDate = serializers.DateTimeField() diff --git a/app/apps/addresses/views.py b/app/apps/addresses/views.py index 47d108492..c2fe0e4ef 100644 --- a/app/apps/addresses/views.py +++ b/app/apps/addresses/views.py @@ -7,6 +7,8 @@ GetResidentsSerializer, HousingCorporationSerializer, MeldingenSerializer, + RegistrationDetailsSerializer, + RegistrationNumberSerializer, ResidentsSerializer, ) from apps.cases.models import Advertisement @@ -22,7 +24,11 @@ from rest_framework.response import Response from rest_framework.viewsets import ViewSet from utils.api_queries_brp import get_brp_by_nummeraanduiding_id -from utils.api_queries_toeristische_verhuur import get_vakantieverhuur_meldingen +from utils.api_queries_toeristische_verhuur import ( + get_vakantieverhuur_meldingen, + get_vakantieverhuur_registration, + get_vakantieverhuur_registrations_by_bag_id, +) logger = logging.getLogger(__name__) @@ -243,3 +249,66 @@ def meldingen(self, request, bag_id): {"error": "Toeristische verhuur meldingen could not be obtained"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR, ) + + @extend_schema( + description="Gets all registrations for holiday rental by bag_id", + responses={status.HTTP_200_OK: RegistrationDetailsSerializer(many=True)}, + ) + @action( + detail=True, + url_path="registrations", + methods=["get"], + pagination_class=None, + ) + def registrations(self, request, bag_id): + try: + ( + registrations_data, + status_code, + ) = get_vakantieverhuur_registrations_by_bag_id( + bag_id, + ) + serialized_registrations = RegistrationNumberSerializer( + data=registrations_data, many=True + ) + serialized_registrations.is_valid(raise_exception=True) + + # Fetch details for each registration number + detailed_registrations = [] + for registration in serialized_registrations.data: + # Remove spaces from registration number + registration_number = registration["registrationNumber"].replace( + " ", "" + ) + try: + # Fetch detailed data for the current registrationNumber + ( + registration_details, + detail_status_code, + ) = get_vakantieverhuur_registration(registration_number) + if detail_status_code == 200: # Only append if successful + detailed_registrations.append(registration_details) + else: + print( + f"Failed to fetch details for {registration_number}. Status: {detail_status_code}" + ) + except Exception as e: + print(f"Error fetching details for {registration_number}: {e}") + + # Sort detailed_registrations by 'createdAt' with the newest first + detailed_registrations = sorted( + detailed_registrations, + key=lambda x: x.get("createdAt", ""), + reverse=True, + ) + + serializer = RegistrationDetailsSerializer( + detailed_registrations, many=True + ) + + return Response(serializer.data, status=status_code) + except Exception: + return Response( + {"error": "Toeristische verhuur registrations could not be obtained"}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR, + ) diff --git a/app/apps/health/health_checks.py b/app/apps/health/health_checks.py index 8e5282db6..e71a26a7d 100644 --- a/app/apps/health/health_checks.py +++ b/app/apps/health/health_checks.py @@ -13,10 +13,9 @@ do_bag_search_pdok_by_bag_id, ) from utils.api_queries_toeristische_verhuur import ( - get_bag_vakantieverhuur_registrations, - get_bsn_vakantieverhuur_registrations, get_vakantieverhuur_meldingen, - get_vakantieverhuur_registration, + get_vakantieverhuur_registrations_by_bag_id, + get_vakantieverhuur_registrations_by_bsn_number, ) logger = logging.getLogger(__name__) @@ -265,22 +264,15 @@ class VakantieVerhuurRegistratieCheck(BaseHealthCheckBackend): def check_status(self): try: - registration = get_vakantieverhuur_registration( - settings.VAKANTIEVERHUUR_REGISTRATIE_API_HEALTH_CHECK_REGISTRATION_NUMBER - ) - assert bool( - registration - ), "The registration data is empty and could not be retrieved" - - bsn_registrations = get_bsn_vakantieverhuur_registrations( - settings.VAKANTIEVERHUUR_REGISTRATIE_API_HEALTH_CHECK_BSN + bsn_registrations = get_vakantieverhuur_registrations_by_bsn_number( + settings.VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_BSN ) assert ( len(bsn_registrations) > 0 ), "The registration data is empty and could not be retrieved using the BSN number" - bag_registrations = get_bag_vakantieverhuur_registrations( - settings.VAKANTIEVERHUUR_REGISTRATIE_API_HEALTH_CHECK_BAG_ID + bag_registrations = get_vakantieverhuur_registrations_by_bag_id( + settings.VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_BAG_ID ) assert ( len(bag_registrations) > 0 @@ -311,7 +303,7 @@ def check_status(self): try: get_vakantieverhuur_meldingen( - settings.VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_HEALTH_CHECK_BAG_ID, + settings.VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_BAG_ID, query_params=params, use_retry=False, ) diff --git a/app/apps/workflow/admin.py b/app/apps/workflow/admin.py index 32477fda5..042ca718e 100644 --- a/app/apps/workflow/admin.py +++ b/app/apps/workflow/admin.py @@ -15,6 +15,13 @@ def force_update_workflows(modeladmin, request, queryset): task_update_workflow.delay(workflow.id) +@admin.action(description="Complete subworkflows if there are no open tasks") +def complete_sub_workflow(modeladmin, request, queryset): + for workflow in queryset.all(): + wf = workflow.get_or_restore_workflow_state() + workflow.complete_sub_workflow(wf) + + @admin.action(description="Remove workflows for closed cases") def remove_workflows_for_closed_cases(modeladmin, request, queryset): queryset.filter( @@ -91,6 +98,7 @@ class CaseWorkflowAdmin(admin.ModelAdmin): migrate_worflows_to_latest, force_update_workflows, remove_workflows_for_closed_cases, + complete_sub_workflow, ) def issues(self, obj): diff --git a/app/apps/workflow/models.py b/app/apps/workflow/models.py index 501a7c631..f19e94064 100644 --- a/app/apps/workflow/models.py +++ b/app/apps/workflow/models.py @@ -509,6 +509,16 @@ def complete_workflow(self): def update_tasks(self, wf): self.set_absolete_tasks_to_completed(wf) self.create_user_tasks(wf) + self.complete_sub_workflow(wf) + + # The sub_workflow.bpmn has multiple flows inside, so spiff does not know when the workflow is completed. + def complete_sub_workflow(self, wf): + if ( + self.workflow_type == self.WORKFLOW_TYPE_SUB + and len(wf.get_ready_user_tasks()) == 0 + ): + self.completed = True + self.save() @staticmethod def get_task_by_task_id(id): @@ -558,7 +568,6 @@ def save_workflow_state(self, wf): self.data.update(wf.last_task.data) completed = False - if wf.is_completed() and not self.completed: completed = True self.completed = True @@ -688,7 +697,7 @@ def has_a_timer_event_fired(self): event_definition = task.task_spec.event_definition has_fired = event_definition.has_fired(task) if has_fired: - logger.info( + logger.warning( f"TimerEventDefinition for task '{task.task_spec.name}' has expired. Workflow with id '{self.id}', needs an update" ) return True diff --git a/app/apps/workflow/tasks.py b/app/apps/workflow/tasks.py index b97ea076f..78f167524 100644 --- a/app/apps/workflow/tasks.py +++ b/app/apps/workflow/tasks.py @@ -41,6 +41,9 @@ def task_update_workflows(self): workflow_instances = CaseWorkflow.objects.filter(completed=False) for workflow in workflow_instances: if workflow.has_a_timer_event_fired(): + logger.warning( + f"task_update_workflows: workflow with id '{workflow.id}', has a timer event fired" + ) task_update_workflow.delay(workflow.id) return f"task_update_workflows complete: count '{workflow_instances.count()}'" diff --git a/app/config/settings.py b/app/config/settings.py index 4a172ca6b..8f35e2031 100644 --- a/app/config/settings.py +++ b/app/config/settings.py @@ -515,7 +515,6 @@ def get_redis_url(): } CELERY_TASK_TRACK_STARTED = True -CELERY_TASK_TIME_LIMIT = 30 * 60 CELERY_BROKER_URL = get_redis_url() CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP = True BROKER_CONNECTION_MAX_RETRIES = None @@ -523,7 +522,7 @@ def get_redis_url(): BROKER_URL = CELERY_BROKER_URL CELERY_TASK_TRACK_STARTED = True CELERY_RESULT_BACKEND = "django-db" -CELERY_TASK_TIME_LIMIT = 30 * 60 +CELERY_TASK_TIME_LIMIT = 5400 # 1,5 hours CELERY_BEAT_SCHEDULE = { "queue_every_five_mins": { "task": "apps.health.tasks.query_every_five_mins", @@ -531,6 +530,7 @@ def get_redis_url(): }, } + CELERY_BROKER_TRANSPORT_OPTIONS = { "socket_keepalive": True, "socket_keepalive_options": { @@ -560,22 +560,11 @@ def get_redis_url(): VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_ACCESS_TOKEN = os.getenv( "VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_ACCESS_TOKEN" ) -VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_HEALTH_CHECK_BAG_ID = os.getenv( - "VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_HEALTH_CHECK_BAG_ID", "0503100000000209" -) - -VAKANTIEVERHUUR_REGISTRATIE_API_URL = os.getenv("VAKANTIEVERHUUR_REGISTRATIE_API_URL") -VAKANTIEVERHUUR_REGISTRATIE_API_ACCESS_TOKEN = os.getenv( - "VAKANTIEVERHUUR_REGISTRATIE_API_ACCESS_TOKEN" -) -VAKANTIEVERHUUR_REGISTRATIE_API_HEALTH_CHECK_BSN = os.getenv( - "VAKANTIEVERHUUR_REGISTRATIE_API_HEALTH_CHECK_BSN" -) -VAKANTIEVERHUUR_REGISTRATIE_API_HEALTH_CHECK_BAG_ID = os.getenv( - "VAKANTIEVERHUUR_REGISTRATIE_API_HEALTH_CHECK_BAG_ID" +VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_BAG_ID = os.getenv( + "VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_BAG_ID", "0503100000000209" ) -VAKANTIEVERHUUR_REGISTRATIE_API_HEALTH_CHECK_REGISTRATION_NUMBER = os.getenv( - "VAKANTIEVERHUUR_REGISTRATIE_API_HEALTH_CHECK_REGISTRATION_NUMBER" +VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_BSN = os.getenv( + "VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_BSN" ) DEFAULT_AUTO_FIELD = "django.db.models.AutoField" diff --git a/app/utils/api_queries_toeristische_verhuur.py b/app/utils/api_queries_toeristische_verhuur.py index 8e3e0f290..bf5fd3698 100644 --- a/app/utils/api_queries_toeristische_verhuur.py +++ b/app/utils/api_queries_toeristische_verhuur.py @@ -39,57 +39,61 @@ def _get_vakantieverhuur_meldingen_internal(): return _get_vakantieverhuur_meldingen_internal() -@retry(stop=stop_after_attempt(3), after=after_log(logger, logging.ERROR)) +@retry(stop=stop_after_attempt(1), after=after_log(logger, logging.ERROR)) def get_vakantieverhuur_registration(registration_number): """ Get the Vakantieverhuur registration """ - header = {"x-api-key": settings.VAKANTIEVERHUUR_REGISTRATIE_API_ACCESS_TOKEN} - url = ( - f"{settings.VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_URL}{registration_number}" - ) + header = { + "x-api-key": settings.VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_ACCESS_TOKEN + } + url = f"{settings.VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_URL}registrations/{registration_number}" response = requests.get( url=url, headers=header, - verify="/usr/local/share/ca-certificates/adp_rootca.crt", + timeout=30, ) response.raise_for_status() - return response.json() + return response.json(), response.status_code @retry(stop=stop_after_attempt(3), after=after_log(logger, logging.ERROR)) -def get_bsn_vakantieverhuur_registrations(bsn_number): +def get_vakantieverhuur_registrations_by_bag_id(bag_id): """ - Get the Vakantieverhuur registrations using a BSN number + Get the Vakantieverhuur registration by bag_id """ - header = {"x-api-key": settings.VAKANTIEVERHUUR_REGISTRATIE_API_ACCESS_TOKEN} - url = f"{settings.VAKANTIEVERHUUR_REGISTRATIE_API_URL}bsn/{bsn_number}" + header = { + "x-api-key": settings.VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_ACCESS_TOKEN + } + url = f"{settings.VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_URL}registrations/adresseerbaarObjectIdentificatie/{bag_id}" response = requests.get( url=url, headers=header, - verify="/usr/local/share/ca-certificates/adp_rootca.crt", + timeout=30, ) response.raise_for_status() - return response.json() + return response.json(), response.status_code @retry(stop=stop_after_attempt(3), after=after_log(logger, logging.ERROR)) -def get_bag_vakantieverhuur_registrations(bag_id): +def get_vakantieverhuur_registrations_by_bsn_number(bsn_number): """ - Get the Vakantieverhuur registrations using a BSN number + Get the Vakantieverhuur registration by bsn_number """ - header = {"x-api-key": settings.VAKANTIEVERHUUR_REGISTRATIE_API_ACCESS_TOKEN} - url = f"{settings.VAKANTIEVERHUUR_REGISTRATIE_API_URL}bagid/{bag_id}" + header = { + "x-api-key": settings.VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_ACCESS_TOKEN + } + url = f"{settings.VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_URL}registrations/bsn/{bsn_number}" response = requests.get( url=url, headers=header, - verify="/usr/local/share/ca-certificates/adp_rootca.crt", + timeout=30, ) response.raise_for_status() - return response.json() + return response.json(), response.status_code