Add a platform admin page to submit returned letter references

A platform admin form accepts a list of references (one per line)
received from DVLA and sends them to the API to update notification
statuses.

References we get from DVLA start with `NOTIFY00\d`, which isn't
part of the reference we store in the database, so we remove them
before sending the data to the API.

The new `returned-letter` status should be treated as `delivered`
for now until we decide a way to display returned letters to users.
This commit is contained in:
Alexey Bezhan
2018-09-06 16:34:23 +01:00
parent afe6d04d96
commit b75681dfbc
11 changed files with 124 additions and 8 deletions

View File

@@ -385,6 +385,7 @@ def format_notification_status(status, template_type):
'sent': 'Delivered',
'pending-virus-check': 'Pending virus check',
'virus-scan-failed': 'Virus detected',
'returned-letter': 'Delivered',
}
}[template_type].get(status, status)
@@ -410,6 +411,7 @@ def format_notification_status_as_field_status(status, notification_type):
'accepted': None,
'pending-virus-check': None,
'virus-scan-failed': 'error',
'returned-letter': None,
}
}.get(
notification_type,

View File

@@ -1067,3 +1067,12 @@ class ServiceDataRetentionEditForm(StripWhitespaceForm):
validators=[validators.NumberRange(min=3, max=90,
message="Must be between 3 and 90")],
)
class ReturnedLettersForm(StripWhitespaceForm):
references = TextAreaField(
u'Letter references',
validators=[
DataRequired(message="Cant be empty"),
]
)

View File

@@ -1,16 +1,19 @@
import itertools
import re
from datetime import datetime
from flask import abort, render_template, request, url_for
from flask import abort, flash, redirect, render_template, request, url_for
from flask_login import login_required
from notifications_python_client.errors import HTTPError
from app import (
complaint_api_client,
letter_jobs_client,
platform_stats_api_client,
service_api_client,
)
from app.main import main
from app.main.forms import DateFilterForm
from app.main.forms import DateFilterForm, ReturnedLettersForm
from app.statistics_utils import (
get_formatted_percentage,
get_formatted_percentage_two_dp,
@@ -202,6 +205,41 @@ def platform_admin_list_complaints():
)
@main.route("/platform-admin/returned-letters", methods=["GET", "POST"])
@login_required
@user_is_platform_admin
def platform_admin_returned_letters():
form = ReturnedLettersForm()
if form.validate_on_submit():
references = [
re.sub('NOTIFY00[0-9]', '', r.strip())
for r in form.references.data.split('\n')
if r.strip()
]
try:
letter_jobs_client.submit_returned_letters(references)
except HTTPError as error:
if error.status_code == 400:
error_references = [
re.match('references (.*) does not match', e['message']).group(1)
for e in error.message
]
form.references.errors.append("Invalid references: {}".format(', '.join(error_references)))
else:
raise error
else:
flash('Submitted {} letter references'.format(len(references)), 'default')
return redirect(
url_for('.platform_admin_returned_letters')
)
return render_template(
'views/platform-admin/returned-letters.html',
form=form,
)
def sum_service_usage(service):
total = 0
for notification_type in service['statistics'].keys():

View File

@@ -81,6 +81,7 @@ class HeaderNavigation(Navigation):
'organisations',
'platform_admin',
'platform_admin_list_complaints',
'platform_admin_returned_letters',
'suspend_service',
'trial_services',
'update_email_branding',
@@ -440,6 +441,7 @@ class MainNavigation(Navigation):
'organisations',
'platform_admin',
'platform_admin_list_complaints',
'platform_admin_returned_letters',
'pricing',
'privacy',
'public_agreement',
@@ -624,6 +626,7 @@ class CaseworkNavigation(Navigation):
'organisations',
'platform_admin',
'platform_admin_list_complaints',
'platform_admin_returned_letters',
'pricing',
'privacy',
'public_agreement',
@@ -848,6 +851,7 @@ class OrgNavigation(Navigation):
'organisations',
'platform_admin',
'platform_admin_list_complaints',
'platform_admin_returned_letters',
'pricing',
'privacy',
'public_agreement',

View File

@@ -14,3 +14,9 @@ class LetterJobsClient(NotifyAdminAPIClient):
url='/send-letter-jobs',
data={"job_ids": job_ids}
)['data']
def submit_returned_letters(self, references):
return self.post(
url='/letters/returned',
data={'references': references}
)

View File

@@ -21,7 +21,8 @@
('Letter jobs', url_for('main.letter_jobs')),
('Inbound SMS numbers', url_for('main.inbound_sms_admin')),
('Find users by email', url_for('main.find_users_by_email')),
('Email Complaints', url_for('main.platform_admin_list_complaints'))
('Email Complaints', url_for('main.platform_admin_list_complaints')),
('Returned letters', url_for('main.platform_admin_returned_letters')),
] %}
<li>
<a href="{{ url }}">

View File

@@ -0,0 +1,21 @@
{% extends "views/platform-admin/_base_template.html" %}
{% from "components/textbox.html" import textbox %}
{% from "components/page-footer.html" import page_footer %}
{% block per_page_title %}
{{ page_title|capitalize }}
{% endblock %}
{% block platform_admin_content %}
<div class="grid-row">
<div class="column-two-thirds">
<h1 class="heading-large">Submit returned letters</h1>
<form method="post" novalidate>
{{ textbox(form.references, width='1-1', rows=8) }}
{{ page_footer("Submit") }}
</form>
</div>
</div>
{% endblock %}

View File

@@ -39,7 +39,7 @@ from orderedset._orderedset import OrderedSet
from werkzeug.datastructures import MultiDict
SENDING_STATUSES = ['created', 'pending', 'sending', 'pending-virus-check']
DELIVERED_STATUSES = ['delivered', 'sent']
DELIVERED_STATUSES = ['delivered', 'sent', 'returned-letter']
FAILURE_STATUSES = ['failed', 'temporary-failure', 'permanent-failure', 'technical-failure', 'virus-scan-failed']
REQUESTED_STATUSES = SENDING_STATUSES + DELIVERED_STATUSES + FAILURE_STATUSES