Skip to content

Commit

Permalink
Hl 1280 one application batch (#2956)
Browse files Browse the repository at this point in the history
* feat: migration changes for one-application batch

* feat: create 1-application batch after open case

* feat: update batch status after decision is sent

* fix: conflicting migrations
  • Loading branch information
rikuke committed Apr 29, 2024
1 parent dee7db9 commit 05daaa1
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 48 deletions.
103 changes: 65 additions & 38 deletions backend/benefit/applications/api/v1/ahjo_integration_views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
from datetime import datetime, timezone

from django.db import transaction
from django.http import FileResponse
from django.shortcuts import get_object_or_404
from drf_spectacular.types import OpenApiTypes
Expand All @@ -16,8 +17,9 @@
AhjoCallBackStatus,
AhjoRequestType,
AhjoStatus as AhjoStatusEnum,
ApplicationBatchStatus,
)
from applications.models import AhjoStatus, Application, Attachment
from applications.models import AhjoStatus, Application, ApplicationBatch, Attachment
from common.permissions import SafeListPermission
from shared.audit_log import audit_logging
from shared.audit_log.enums import Operation
Expand Down Expand Up @@ -133,6 +135,7 @@ def post(self, request, *args, **kwargs):
elif callback_data["message"] == AhjoCallBackStatus.FAILURE:
return self.handle_failure_callback(application, callback_data)

@transaction.atomic
def handle_success_callback(
self,
request,
Expand All @@ -141,41 +144,52 @@ def handle_success_callback(
request_type: AhjoRequestType,
) -> Response:
try:
if request_type == AhjoRequestType.OPEN_CASE:
self._handle_open_case_success(application, callback_data)
ahjo_status = AhjoStatusEnum.CASE_OPENED
info = f"Application ahjo_case_guid and ahjo_case_id were updated by Ahjo \
with request id: {callback_data['requestId']}"
elif request_type == AhjoRequestType.DELETE_APPLICATION:
self._handle_delete_callback()
ahjo_status = AhjoStatusEnum.DELETE_REQUEST_RECEIVED
info = f"Application was marked for cancellation in Ahjo with request id: {callback_data['requestId']}"
elif request_type == AhjoRequestType.SEND_DECISION_PROPOSAL:
ahjo_status = AhjoStatusEnum.DECISION_PROPOSAL_ACCEPTED
info = "Decision proposal was sent to Ahjo"
elif request_type == AhjoRequestType.UPDATE_APPLICATION:
self._handle_update_or_add_records_success(application, callback_data)
ahjo_status = AhjoStatusEnum.UPDATE_REQUEST_RECEIVED
info = f"Updated application records were sent to Ahjo with request id: {callback_data['requestId']}"
elif request_type == AhjoRequestType.ADD_RECORDS:
self._handle_update_or_add_records_success(application, callback_data)
ahjo_status = AhjoStatusEnum.NEW_RECORDS_RECEIVED
info = f"A attachments were sent as records to Ahjo with request id: {callback_data['requestId']}"
else:
raise AhjoCallbackError(
f"Unknown request type {request_type} in the Ahjo callback"
with transaction.atomic():
if request_type == AhjoRequestType.OPEN_CASE:
self._handle_open_case_success(application, callback_data)
ahjo_status = AhjoStatusEnum.CASE_OPENED
info = f"Application ahjo_case_guid and ahjo_case_id were updated by Ahjo \
with request id: {callback_data['requestId']}"
elif request_type == AhjoRequestType.DELETE_APPLICATION:
self._handle_delete_callback()
ahjo_status = AhjoStatusEnum.DELETE_REQUEST_RECEIVED
info = f"Application was marked for cancellation \
in Ahjo with request id: {callback_data['requestId']}"
elif request_type == AhjoRequestType.SEND_DECISION_PROPOSAL:
self.handle_decision_proposal_success(application)
ahjo_status = AhjoStatusEnum.DECISION_PROPOSAL_ACCEPTED
info = "Decision proposal was sent to Ahjo"
elif request_type == AhjoRequestType.UPDATE_APPLICATION:
self._handle_update_or_add_records_success(
application, callback_data
)
ahjo_status = AhjoStatusEnum.UPDATE_REQUEST_RECEIVED
info = f"Updated application records were sent to Ahjo \
with request id: {callback_data['requestId']}"
elif request_type == AhjoRequestType.ADD_RECORDS:
self._handle_update_or_add_records_success(
application, callback_data
)
ahjo_status = AhjoStatusEnum.NEW_RECORDS_RECEIVED
info = f"A attachments were sent as records to Ahjo \
with request id: {callback_data['requestId']}"
else:
raise AhjoCallbackError(
f"Unknown request type {request_type} in the Ahjo callback"
)
AhjoStatus.objects.create(application=application, status=ahjo_status)

audit_logging.log(
request.user,
"",
Operation.UPDATE,
application,
additional_information=info,
)
AhjoStatus.objects.create(application=application, status=ahjo_status)

audit_logging.log(
request.user,
"",
Operation.UPDATE,
application,
additional_information=info,
)

return Response({"message": "Callback received"}, status=status.HTTP_200_OK)
return Response(
{"message": "Callback received"}, status=status.HTTP_200_OK
)
except AhjoCallbackError as e:
return Response(
{"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR
Expand All @@ -196,8 +210,12 @@ def _handle_update_or_add_records_success(
cb_records = callback_data.get("records", [])
self._save_version_series_id(application, cb_records)

@transaction.atomic
def _handle_open_case_success(self, application: Application, callback_data: dict):
"""Update the application with the case id (diaarinumero) and case guid from the Ahjo callback data."""
"""Update the application with the case id (diaarinumero) and case guid from the Ahjo callback data.
If the application has attachments with a matching hash value, save the version series id for each attachment.
Create a new single-application ApplicationBatch for the application and set the batch_id for the application.
"""
if callback_data["caseGuid"]:
application.ahjo_case_guid = callback_data["caseGuid"]
if callback_data["caseId"]:
Expand All @@ -206,6 +224,13 @@ def _handle_open_case_success(self, application: Application, callback_data: dic

self._save_version_series_id(application, cb_records)

handler = application.calculation.handler

batch = ApplicationBatch.objects.create(
handler=handler, auto_generated_by_ahjo=True
)
application.batch_id = batch.id

application.save()
return application

Expand All @@ -230,9 +255,11 @@ def _save_version_series_id(
attachment.ahjo_version_series_id = cb_record.get("versionSeriesId")
attachment.save()

def handle_decision_proposal_success(self):
# do anything that needs to be done when Ahjo accepts a decision proposal
pass
def handle_decision_proposal_success(self, application: Application):
# do anything that needs to be done when Ahjo has received a decision proposal request
batch = application.batch
batch.status = ApplicationBatchStatus.AWAITING_AHJO_DECISION
batch.save()

def _log_failure_details(self, application, callback_data):
LOGGER.error(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Generated by Django 3.2.23 on 2024-04-26 04:32

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('applications', '0067_add_handler_to_application'),
]

operations = [
migrations.AddField(
model_name='applicationbatch',
name='auto_generated_by_ahjo',
field=models.BooleanField(blank=True, default=False, verbose_name='Batch created through Ahjo integration'),
),
migrations.AlterField(
model_name='applicationbatch',
name='decision_maker_name',
field=models.CharField(blank=True, max_length=128, null=True, verbose_name="decision maker's name in Ahjo"),
),
migrations.AlterField(
model_name='applicationbatch',
name='decision_maker_title',
field=models.CharField(blank=True, max_length=64, null=True, verbose_name="decision maker's title in Ahjo"),
),
migrations.AlterField(
model_name='applicationbatch',
name='expert_inspector_email',
field=models.EmailField(blank=True, max_length=254, null=True, verbose_name="Expert inspector's email address"),
),
migrations.AlterField(
model_name='applicationbatch',
name='expert_inspector_name',
field=models.CharField(blank=True, max_length=128, null=True, verbose_name="Expert inspector's name"),
),
migrations.AlterField(
model_name='applicationbatch',
name='expert_inspector_title',
field=models.CharField(blank=True, max_length=64, null=True, verbose_name="Expert inspector's title"),
),
migrations.AlterField(
model_name='applicationbatch',
name='p2p_checker_name',
field=models.CharField(blank=True, max_length=64, null=True, verbose_name="P2P acceptor's title"),
),
migrations.AlterField(
model_name='applicationbatch',
name='p2p_inspector_email',
field=models.EmailField(blank=True, max_length=254, null=True, verbose_name="P2P inspector's email address"),
),
migrations.AlterField(
model_name='applicationbatch',
name='p2p_inspector_name',
field=models.CharField(blank=True, max_length=128, null=True, verbose_name="P2P inspector's name"),
),
migrations.AlterField(
model_name='applicationbatch',
name='proposal_for_decision',
field=models.CharField(blank=True, choices=[('accepted', 'Decided Accepted'), ('rejected', 'Decided Rejected')], max_length=64, null=True, verbose_name='proposal for decision'),
),
migrations.AlterField(
model_name='applicationbatch',
name='section_of_the_law',
field=models.CharField(blank=True, max_length=16, null=True, verbose_name='section of the law in Ahjo decision'),
),
]
39 changes: 30 additions & 9 deletions backend/benefit/applications/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,9 @@ class ApplicationBatch(UUIDModel, TimeStampedModel):
Represents grouping of applications for:
* Decision making in Ahjo
* Transferring payment data to Talpa
If Ahjo automation / integration is in use, a single application batch will be created for each
application, after a case has been opened in Ahjo after which auto_generated_by ahjo is set to True.
"""

handler = models.ForeignKey(
Expand All @@ -603,18 +606,29 @@ class ApplicationBatch(UUIDModel, TimeStampedModel):

proposal_for_decision = models.CharField(
max_length=64,
blank=True,
null=True,
verbose_name=_("proposal for decision"),
choices=AhjoDecision.choices,
)

decision_maker_title = models.CharField(
max_length=64, blank=True, verbose_name=_("decision maker's title in Ahjo")
max_length=64,
blank=True,
null=True,
verbose_name=_("decision maker's title in Ahjo"),
)
decision_maker_name = models.CharField(
max_length=128, blank=True, verbose_name=_("decision maker's name in Ahjo")
max_length=128,
blank=True,
null=True,
verbose_name=_("decision maker's name in Ahjo"),
)
section_of_the_law = models.CharField(
max_length=16, blank=True, verbose_name=_("section of the law in Ahjo decision")
max_length=16,
blank=True,
null=True,
verbose_name=_("section of the law in Ahjo decision"),
)
decision_date = models.DateField(
verbose_name=_("date of the decision in Ahjo"),
Expand All @@ -623,23 +637,30 @@ class ApplicationBatch(UUIDModel, TimeStampedModel):
validators=[validate_decision_date],
)
p2p_inspector_name = models.CharField(
max_length=128, blank=True, verbose_name=_("P2P inspector's name")
max_length=128, blank=True, null=True, verbose_name=_("P2P inspector's name")
)
p2p_inspector_email = models.EmailField(
blank=True, verbose_name=_("P2P inspector's email address")
blank=True, null=True, verbose_name=_("P2P inspector's email address")
)
p2p_checker_name = models.CharField(
max_length=64, blank=True, verbose_name=_("P2P acceptor's title")
max_length=64, blank=True, null=True, verbose_name=_("P2P acceptor's title")
)

expert_inspector_name = models.CharField(
max_length=128, blank=True, verbose_name=_("Expert inspector's name")
max_length=128, blank=True, null=True, verbose_name=_("Expert inspector's name")
)
expert_inspector_email = models.EmailField(
blank=True, verbose_name=_("Expert inspector's email address")
blank=True, null=True, verbose_name=_("Expert inspector's email address")
)

expert_inspector_title = models.CharField(
max_length=64, blank=True, verbose_name=_("Expert inspector's title")
max_length=64, blank=True, null=True, verbose_name=_("Expert inspector's title")
)

auto_generated_by_ahjo = models.BooleanField(
blank=True,
default=False,
verbose_name=_("Batch created through Ahjo integration"),
)

def clean(self):
Expand Down
26 changes: 25 additions & 1 deletion backend/benefit/applications/tests/test_ahjo_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,18 @@
AhjoCallBackStatus,
AhjoRequestType,
AhjoStatus as AhjoStatusEnum,
ApplicationBatchStatus,
ApplicationStatus,
AttachmentType,
BenefitType,
)
from applications.models import AhjoDecisionText, AhjoStatus, Application, Attachment
from applications.models import (
AhjoDecisionText,
AhjoStatus,
Application,
ApplicationBatch,
Attachment,
)
from applications.services.ahjo_integration import (
ACCEPTED_TITLE,
export_application_batch,
Expand Down Expand Up @@ -429,6 +436,10 @@ def ahjo_callback_payload():
AhjoRequestType.DELETE_APPLICATION,
AhjoStatusEnum.DELETE_REQUEST_RECEIVED,
),
(
AhjoRequestType.SEND_DECISION_PROPOSAL,
AhjoStatusEnum.DECISION_PROPOSAL_ACCEPTED,
),
],
)
@pytest.mark.django_db
Expand All @@ -452,6 +463,11 @@ def test_ahjo_callback_success(
ahjo_callback_payload["message"] = AhjoCallBackStatus.SUCCESS
ahjo_callback_payload["records"][0]["hashValue"] = attachment_hash_value

if request_type == AhjoRequestType.SEND_DECISION_PROPOSAL:
batch = ApplicationBatch.objects.create()
decided_application.batch_id = batch.id
decided_application.save()

url = _get_callback_url(request_type, decided_application)
response = ahjo_client.post(url, **auth_headers, data=ahjo_callback_payload)

Expand All @@ -468,11 +484,19 @@ def test_ahjo_callback_success(
attachment.ahjo_version_series_id
== ahjo_callback_payload["records"][0]["versionSeriesId"]
)
batch = decided_application.batch
assert batch.auto_generated_by_ahjo
assert batch.handler == decided_application.calculation.handler
assert batch.status == ApplicationBatchStatus.DRAFT
if request_type == AhjoRequestType.UPDATE_APPLICATION:
assert (
attachment.ahjo_version_series_id
== ahjo_callback_payload["records"][0]["versionSeriesId"]
)
if request_type == AhjoRequestType.SEND_DECISION_PROPOSAL:
batch = decided_application.batch
assert batch.status == ApplicationBatchStatus.AWAITING_AHJO_DECISION

assert decided_application.ahjo_status.latest().status == ahjo_status


Expand Down

0 comments on commit 05daaa1

Please sign in to comment.