-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Port lite licence usage reporting task to celery
- Loading branch information
1 parent
f241451
commit 49cf2e6
Showing
8 changed files
with
186 additions
and
244 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
import urllib.parse | ||
from typing import List, MutableMapping, Tuple | ||
from mail.enums import ReceptionStatusEnum | ||
|
||
from celery import shared_task | ||
from celery.utils.log import get_task_logger | ||
from django.conf import settings | ||
from django.utils import timezone | ||
from rest_framework.status import HTTP_207_MULTI_STATUS, HTTP_208_ALREADY_REPORTED | ||
|
||
from mail import requests as mail_requests | ||
from mail.models import LicenceIdMapping, UsageData | ||
from mail.libraries.usage_data_decomposition import build_json_payload_from_data_blocks, split_edi_data_by_id | ||
|
||
|
||
logger = get_task_logger(__name__) | ||
|
||
|
||
# Send Usage Figures to LITE API | ||
def get_lite_api_url(): | ||
"""The URL for the licence usage callback, from the LITE_API_URL setting. | ||
If the configured URL has no path, use `/licences/hmrc-integration/`. | ||
""" | ||
url = settings.LITE_API_URL | ||
components = urllib.parse.urlparse(url) | ||
|
||
if components.path in ("", "/"): | ||
components = components._replace(path="/licences/hmrc-integration/") | ||
url = urllib.parse.urlunparse(components) | ||
|
||
return url | ||
|
||
|
||
def parse_response(response) -> Tuple[MutableMapping, List[str], List[str]]: | ||
response = response.json() | ||
licences = response["licences"] | ||
|
||
accepted_licences = [ | ||
LicenceIdMapping.objects.get(lite_id=licence.get("id")).reference | ||
for licence in licences["accepted"] | ||
if licence.get("id") | ||
] | ||
rejected_licences = [ | ||
LicenceIdMapping.objects.get(lite_id=licence.get("id")).reference | ||
for licence in licences["rejected"] | ||
if licence.get("id") | ||
] | ||
|
||
return response, accepted_licences, rejected_licences | ||
|
||
|
||
def save_response(lite_usage_data: UsageData, accepted_licences, rejected_licences, response): | ||
lite_usage_data.lite_accepted_licences = accepted_licences | ||
lite_usage_data.lite_rejected_licences = rejected_licences | ||
lite_usage_data.lite_sent_at = timezone.now() | ||
lite_usage_data.lite_response = response | ||
|
||
if not lite_usage_data.has_spire_data: | ||
lite_usage_data.mail.status = ReceptionStatusEnum.REPLY_RECEIVED | ||
lite_usage_data.mail.save() | ||
|
||
lite_usage_data.save() | ||
|
||
|
||
def _handle_exception(message, lite_usage_data_id): | ||
error_message = f"Failed to send LITE UsageData [{lite_usage_data_id}] to LITE API -> {message} " | ||
raise Exception(error_message) | ||
|
||
|
||
MAX_ATTEMPTS = 3 | ||
|
||
|
||
@shared_task( | ||
autoretry_for=(Exception,), | ||
max_retries=MAX_ATTEMPTS, | ||
retry_backoff=True, | ||
) | ||
def send_licence_usage_figures_to_lite_api(lite_usage_data_id): | ||
"""Sends HMRC Usage figure updates to LITE""" | ||
|
||
logger.info("Preparing LITE UsageData [%s] for LITE API", lite_usage_data_id) | ||
|
||
try: | ||
lite_usage_data = UsageData.objects.get(id=lite_usage_data_id) | ||
licences = UsageData.licence_ids | ||
except UsageData.DoesNotExist: # noqa | ||
_handle_exception( | ||
f"LITE UsageData [{lite_usage_data_id}] does not exist.", | ||
lite_usage_data_id, | ||
) | ||
|
||
# Extract usage details of Licences issued from LITE | ||
_, data = split_edi_data_by_id(lite_usage_data.mail.edi_data, lite_usage_data) | ||
payload = build_json_payload_from_data_blocks(data) | ||
|
||
# We only process usage data for active licences so below error is unlikely | ||
if len(payload["licences"]) == 0: | ||
logger.error("Licences is blank in payload for %s", lite_usage_data, exc_info=True) | ||
return | ||
|
||
payload["usage_data_id"] = lite_usage_data_id | ||
lite_api_url = get_lite_api_url() | ||
logger.info("Sending LITE UsageData [%s] figures for Licences [%s] to LITE API", lite_usage_data_id, licences) | ||
|
||
try: | ||
lite_usage_data.lite_payload = payload | ||
lite_usage_data.save() | ||
|
||
response = mail_requests.put( | ||
lite_api_url, | ||
lite_usage_data.lite_payload, | ||
hawk_credentials=settings.HAWK_LITE_HMRC_INTEGRATION_CREDENTIALS, | ||
timeout=settings.LITE_API_REQUEST_TIMEOUT, | ||
) | ||
except Exception as exc: # noqa | ||
_handle_exception( | ||
f"An unexpected error occurred when sending LITE UsageData [{lite_usage_data_id}] to LITE API -> " | ||
f"{type(exc).__name__}: {exc}", | ||
lite_usage_data_id, | ||
) | ||
|
||
if response.status_code not in [HTTP_207_MULTI_STATUS, HTTP_208_ALREADY_REPORTED]: | ||
_handle_exception( | ||
f"An unexpected response was received when sending LITE UsageData [{lite_usage_data_id}] to " | ||
f"LITE API -> status=[{response.status_code}], message=[{response.text}]", | ||
lite_usage_data_id, | ||
) | ||
|
||
if response.status_code == HTTP_207_MULTI_STATUS: | ||
try: | ||
response, accepted_licences, rejected_licences = parse_response(response) | ||
except Exception as exc: # noqa | ||
_handle_exception( | ||
f"An unexpected error occurred when parsing the response for LITE UsageData " | ||
f"[{lite_usage_data_id}] -> {type(exc).__name__}: {exc}", | ||
lite_usage_data_id, | ||
) | ||
save_response(lite_usage_data, accepted_licences, rejected_licences, response) | ||
|
||
logger.info("Successfully sent LITE UsageData [%s] to LITE API", lite_usage_data_id) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import pytest | ||
import os | ||
|
||
@pytest.fixture(autouse=True) | ||
def celery_sync(settings): | ||
settings.CELERY_TASK_ALWAYS_EAGER = True |
Oops, something went wrong.