Skip to content

Commit

Permalink
feat: HL 1453 ahjo retry and other fixes (#3414)
Browse files Browse the repository at this point in the history
* feat: print application numbers on request

* chore: move application queries to a class

* chore: test ahjo_status is correct after request

* fix: raise and log error if no batch

* feat: add decision_details_request_sent status

* fix: missing parenthesis from ahjo  delete query

* chore: refactor query parameter resolver

* feat: db query for retrying failed ahjo requests

* feat: retry query for decision proposal

* feat: command option for ahjo request retry

* feat: schedule retries to run hourly

* fix: missing parameter

* fix: missing import

* fix: failing test
  • Loading branch information
rikuke authored Oct 14, 2024
1 parent e33c704 commit bfa6591
Show file tree
Hide file tree
Showing 15 changed files with 1,027 additions and 179 deletions.
5 changes: 5 additions & 0 deletions backend/benefit/applications/api/v1/ahjo_integration_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ def handle_success_callback(
{"message": "Callback received"}, status=status.HTTP_200_OK
)
except AhjoCallbackError as e:
LOGGER.error(str(e))
return Response(
{"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR
)
Expand Down Expand Up @@ -329,6 +330,10 @@ def _save_version_series_id(

def handle_decision_proposal_success(self, application: Application):
# do anything that needs to be done when Ahjo has received a decision proposal request
if not application.batch:
raise AhjoCallbackError(
f"Application {application.id} has no batch when Ahjo has received a decision proposal request"
)
batch = application.batch
batch.status = ApplicationBatchStatus.AWAITING_AHJO_DECISION
batch.save()
Expand Down
3 changes: 3 additions & 0 deletions backend/benefit/applications/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,9 @@ class AhjoStatus(models.TextChoices):
REMOVED_IN_AHJO = "removed", _("Decision cancelled in Ahjo")
SIGNED_IN_AHJO = "signed", _("Decision signed and completed in Ahjo")
UPDATED_IN_AHJO = "updated", _("Decision updated in Ahjo")
DECISION_DETAILS_REQUEST_SENT = "decision_details_request_sent", _(
"Decision details request sent"
)
DETAILS_RECEIVED_FROM_AHJO = "details_received", _(
"Decision details received from Ahjo"
)
Expand Down
28 changes: 28 additions & 0 deletions backend/benefit/applications/jobs/hourly/hourly_ahjo_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,35 @@ class Job(HourlyJob):
def execute(self):
call_command("refresh_ahjo_token")

retry_threshold = 1

if settings.ENABLE_AHJO_AUTOMATION:
call_command(
"send_ahjo_requests",
request_type=AhjoRequestType.OPEN_CASE,
retry_failed_older_than_hours=retry_threshold,
)
call_command(
"send_ahjo_requests",
request_type=AhjoRequestType.SEND_DECISION_PROPOSAL,
retry_failed_older_than_hours=retry_threshold,
)
call_command(
"send_ahjo_requests",
request_type=AhjoRequestType.UPDATE_APPLICATION,
retry_failed_older_than_hours=retry_threshold,
)

call_command(
"send_ahjo_requests",
request_type=AhjoRequestType.DELETE_APPLICATION,
retry_failed_older_than_hours=retry_threshold,
)
call_command(
"send_ahjo_requests", request_type=AhjoRequestType.GET_DECISION_DETAILS
)
call_command(
"send_ahjo_requests",
request_type=AhjoRequestType.GET_DECISION_DETAILS,
retry_failed_older_than_hours=retry_threshold,
)
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
ApplicationStatus,
)
from applications.models import AhjoStatus, Application
from applications.services.ahjo_application_service import AhjoApplicationsService
from applications.services.ahjo_authentication import (
AhjoToken,
AhjoTokenExpiredException,
Expand All @@ -39,6 +40,7 @@ class Command(BaseCommand):
{AhjoRequestType.OPEN_CASE}, {AhjoRequestType.SEND_DECISION_PROPOSAL}, \
{AhjoRequestType.ADD_RECORDS}, {AhjoRequestType.UPDATE_APPLICATION}, \
{AhjoRequestType.GET_DECISION_DETAILS}, {AhjoRequestType.DELETE_APPLICATION}"
is_retry = False

def add_arguments(self, parser):
parser.add_argument(
Expand All @@ -60,58 +62,14 @@ def add_arguments(self, parser):
help="Run the command without making actual changes",
)

def get_applications_for_request(
self, request_type: AhjoRequestType
) -> QuerySet[Application]:
if request_type == AhjoRequestType.OPEN_CASE:
applications = Application.objects.get_by_statuses(
[
ApplicationStatus.HANDLING,
ApplicationStatus.ACCEPTED,
ApplicationStatus.REJECTED,
],
[AhjoStatusEnum.SUBMITTED_BUT_NOT_SENT_TO_AHJO],
True,
)
elif request_type == AhjoRequestType.SEND_DECISION_PROPOSAL:
applications = Application.objects.get_for_ahjo_decision()

elif request_type == AhjoRequestType.ADD_RECORDS:
applications = Application.objects.with_non_downloaded_attachments()

elif request_type == AhjoRequestType.UPDATE_APPLICATION:
applications = Application.objects.get_by_statuses(
[ApplicationStatus.ACCEPTED, ApplicationStatus.REJECTED],
[AhjoStatusEnum.DECISION_PROPOSAL_ACCEPTED],
False,
)
elif request_type == AhjoRequestType.GET_DECISION_DETAILS:
applications = Application.objects.get_by_statuses(
[ApplicationStatus.ACCEPTED, ApplicationStatus.REJECTED],
[AhjoStatusEnum.SIGNED_IN_AHJO],
False,
)
elif request_type == AhjoRequestType.DELETE_APPLICATION:
applications = Application.objects.get_by_statuses(
[
ApplicationStatus.ACCEPTED,
ApplicationStatus.CANCELLED,
ApplicationStatus.REJECTED,
ApplicationStatus.HANDLING,
ApplicationStatus.DRAFT,
ApplicationStatus.RECEIVED,
],
AhjoStatusEnum.SCHEDULED_FOR_DELETION,
False,
)

# Only send applications that have automation enabled
applications_with_ahjo_automation = applications.filter(
handled_by_ahjo_automation=True
parser.add_argument(
"--retry-failed-older-than",
type=int,
default=0,
help="Retry sending requests for applications that have \
not moved to the next status in the last x hours",
)

return applications_with_ahjo_automation

def handle(self, *args, **options):
try:
ahjo_auth_token = get_token()
Expand All @@ -125,8 +83,14 @@ def handle(self, *args, **options):
number_to_process = options["number"]
dry_run = options["dry_run"]
request_type = options["request_type"]
retry_failed_older_than_hours = options["retry_failed_older_than"]

if retry_failed_older_than_hours > 0:
self.is_retry = True

applications = self.get_applications_for_request(request_type)
applications = AhjoApplicationsService.get_applications_for_request(
request_type, retry_failed_older_than_hours
)

if not applications:
self.stdout.write(self._print_with_timestamp("No applications to process"))
Expand All @@ -135,8 +99,11 @@ def handle(self, *args, **options):
applications = applications[:number_to_process]

if dry_run:
message_start = "retry" if self.is_retry else "send"

self.stdout.write(
f"Would send {request_type} requests for {len(applications)} applications to Ahjo"
f"Would {message_start} sending {request_type} \
requests for {len(applications)} applications to Ahjo"
)

for application in applications:
Expand All @@ -159,12 +126,15 @@ def run_requests(
successful_applications = []
failed_applications = []

self.stdout.write(
self._print_with_timestamp(
f"Sending {ahjo_request_type} request to Ahjo \
for {len(applications)} applications"
)
application_numbers = ", ".join(
str(app.application_number) for app in applications
)
message_start = "Retrying" if self.is_retry else "Sending"

message = f"{message_start} {ahjo_request_type} request to Ahjo \
for {len(applications)} applications: {application_numbers}"

self.stdout.write(self._print_with_timestamp(message))

request_handler = self._get_request_handler(ahjo_request_type)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Generated by Django 4.2.11 on 2024-10-03 07:44

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("applications", "0084_ahjostatus_validation_error_from_ahjo"),
]

operations = [
migrations.AlterField(
model_name="ahjostatus",
name="status",
field=models.CharField(
choices=[
(
"submitted_but_not_sent_to_ahjo",
"Submitted but not sent to AHJO",
),
(
"request_to_open_case_sent",
"Request to open the case sent to AHJO",
),
("case_opened", "Case opened in AHJO"),
("update_request_sent", "Update request sent"),
("update_request_received", "Update request received"),
("decision_proposal_sent", "Decision proposal sent"),
("decision_proposal_accepted", "Decision proposal accepted"),
("decision_proposal_rejected", "Decision proposal rejected"),
("scheduled_for_deletion", "Scheduled for deletion"),
("delete_request_sent", "Delete request sent"),
("delete_request_received", "Delete request received"),
("new_record_request_sent", "New record request sent"),
("new_record_received", "New record received by Ahjo"),
("removed", "Decision cancelled in Ahjo"),
("signed", "Decision signed and completed in Ahjo"),
("updated", "Decision updated in Ahjo"),
("decision_details_request_sent", "Decision details request sent"),
("details_received", "Decision details received from Ahjo"),
],
default="submitted_but_not_sent_to_ahjo",
max_length=64,
verbose_name="status",
),
),
]
Loading

0 comments on commit bfa6591

Please sign in to comment.