mirror of
https://github.com/GSA/notifications-api.git
synced 2026-09-11 02:23:32 -04:00
letter_job cleanup
This commit is contained in:
@@ -139,7 +139,6 @@ def register_blueprint(application):
|
|||||||
from app.inbound_number.rest import inbound_number_blueprint
|
from app.inbound_number.rest import inbound_number_blueprint
|
||||||
from app.inbound_sms.rest import inbound_sms as inbound_sms_blueprint
|
from app.inbound_sms.rest import inbound_sms as inbound_sms_blueprint
|
||||||
from app.job.rest import job_blueprint
|
from app.job.rest import job_blueprint
|
||||||
from app.letters.rest import letter_job
|
|
||||||
from app.notifications.notifications_ses_callback import (
|
from app.notifications.notifications_ses_callback import (
|
||||||
ses_callback_blueprint,
|
ses_callback_blueprint,
|
||||||
)
|
)
|
||||||
@@ -225,9 +224,6 @@ def register_blueprint(application):
|
|||||||
email_branding_blueprint.before_request(requires_admin_auth)
|
email_branding_blueprint.before_request(requires_admin_auth)
|
||||||
application.register_blueprint(email_branding_blueprint, url_prefix='/email-branding')
|
application.register_blueprint(email_branding_blueprint, url_prefix='/email-branding')
|
||||||
|
|
||||||
letter_job.before_request(requires_admin_auth)
|
|
||||||
application.register_blueprint(letter_job)
|
|
||||||
|
|
||||||
billing_blueprint.before_request(requires_admin_auth)
|
billing_blueprint.before_request(requires_admin_auth)
|
||||||
application.register_blueprint(billing_blueprint)
|
application.register_blueprint(billing_blueprint)
|
||||||
|
|
||||||
|
|||||||
@@ -2,23 +2,13 @@ import uuid
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from notifications_utils.letter_timings import (
|
|
||||||
CANCELLABLE_JOB_LETTER_STATUSES,
|
|
||||||
letter_can_be_cancelled,
|
|
||||||
)
|
|
||||||
from sqlalchemy import and_, asc, desc, func
|
from sqlalchemy import and_, asc, desc, func
|
||||||
|
|
||||||
from app import db
|
from app import db
|
||||||
from app.dao.dao_utils import autocommit
|
|
||||||
from app.dao.templates_dao import dao_get_template_by_id
|
|
||||||
from app.models import (
|
from app.models import (
|
||||||
JOB_STATUS_CANCELLED,
|
|
||||||
JOB_STATUS_FINISHED,
|
JOB_STATUS_FINISHED,
|
||||||
JOB_STATUS_PENDING,
|
JOB_STATUS_PENDING,
|
||||||
JOB_STATUS_SCHEDULED,
|
JOB_STATUS_SCHEDULED,
|
||||||
LETTER_TYPE,
|
|
||||||
NOTIFICATION_CANCELLED,
|
|
||||||
NOTIFICATION_CREATED,
|
|
||||||
FactNotificationStatus,
|
FactNotificationStatus,
|
||||||
Job,
|
Job,
|
||||||
Notification,
|
Notification,
|
||||||
@@ -183,40 +173,6 @@ def dao_get_jobs_older_than_data_retention(notification_types):
|
|||||||
return jobs
|
return jobs
|
||||||
|
|
||||||
|
|
||||||
@autocommit
|
|
||||||
def dao_cancel_letter_job(job):
|
|
||||||
number_of_notifications_cancelled = Notification.query.filter(
|
|
||||||
Notification.job_id == job.id
|
|
||||||
).update({'status': NOTIFICATION_CANCELLED,
|
|
||||||
'updated_at': datetime.utcnow(),
|
|
||||||
'billable_units': 0})
|
|
||||||
job.job_status = JOB_STATUS_CANCELLED
|
|
||||||
dao_update_job(job)
|
|
||||||
return number_of_notifications_cancelled
|
|
||||||
|
|
||||||
|
|
||||||
def can_letter_job_be_cancelled(job):
|
|
||||||
template = dao_get_template_by_id(job.template_id)
|
|
||||||
if template.template_type != LETTER_TYPE:
|
|
||||||
return False, "Only letter jobs can be cancelled through this endpoint. This is not a letter job."
|
|
||||||
|
|
||||||
notifications = Notification.query.filter(
|
|
||||||
Notification.job_id == job.id
|
|
||||||
).all()
|
|
||||||
count_notifications = len(notifications)
|
|
||||||
if job.job_status != JOB_STATUS_FINISHED or count_notifications != job.notification_count:
|
|
||||||
return False, "We are still processing these letters, please try again in a minute."
|
|
||||||
count_cancellable_notifications = len([
|
|
||||||
n for n in notifications if n.status in CANCELLABLE_JOB_LETTER_STATUSES
|
|
||||||
])
|
|
||||||
if count_cancellable_notifications != job.notification_count or not letter_can_be_cancelled(
|
|
||||||
NOTIFICATION_CREATED, job.created_at
|
|
||||||
):
|
|
||||||
return False, "It’s too late to cancel sending, these letters have already been sent."
|
|
||||||
|
|
||||||
return True, None
|
|
||||||
|
|
||||||
|
|
||||||
def find_jobs_with_missing_rows():
|
def find_jobs_with_missing_rows():
|
||||||
# Jobs can be a maximum of 100,000 rows. It typically takes 10 minutes to create all those notifications.
|
# Jobs can be a maximum of 100,000 rows. It typically takes 10 minutes to create all those notifications.
|
||||||
# Using 20 minutes as a condition seems reasonable.
|
# Using 20 minutes as a condition seems reasonable.
|
||||||
|
|||||||
@@ -63,12 +63,6 @@ def cancel_job(service_id, job_id):
|
|||||||
return get_job_by_service_and_job_id(service_id, job_id)
|
return get_job_by_service_and_job_id(service_id, job_id)
|
||||||
|
|
||||||
|
|
||||||
# TODO: return deprecation notice
|
|
||||||
# @job_blueprint.route('/<job_id>/cancel-letter-job', methods=['POST'])
|
|
||||||
# def cancel_letter_job(service_id, job_id):
|
|
||||||
# pass
|
|
||||||
|
|
||||||
|
|
||||||
@job_blueprint.route('/<job_id>/notifications', methods=['GET'])
|
@job_blueprint.route('/<job_id>/notifications', methods=['GET'])
|
||||||
def get_all_notifications_for_service_job(service_id, job_id):
|
def get_all_notifications_for_service_job(service_id, job_id):
|
||||||
data = notifications_filter_schema.load(request.args)
|
data = notifications_filter_schema.load(request.args)
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
letter_references = {
|
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
||||||
"description": "list of letter notification references",
|
|
||||||
"type": "object",
|
|
||||||
"title": "references",
|
|
||||||
"properties": {
|
|
||||||
"references": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^[0-9A-Z]{16}$"
|
|
||||||
},
|
|
||||||
"minItems": 1
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"required": ["references"]
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
from flask import Blueprint
|
|
||||||
|
|
||||||
from app.v2.errors import register_errors
|
|
||||||
|
|
||||||
letter_job = Blueprint("letter-job", __name__)
|
|
||||||
register_errors(letter_job)
|
|
||||||
|
|
||||||
# too many references will make SQS error (as the task can only be 256kb)
|
|
||||||
# Maybe doesn't matter anymore with Redis as the celery backing store
|
|
||||||
MAX_REFERENCES_PER_TASK = 5000
|
|
||||||
|
|
||||||
|
|
||||||
# TODO: return deprecation notice
|
|
||||||
# @letter_job.route('/letters/returned', methods=['POST'])
|
|
||||||
# def create_process_returned_letters_job():
|
|
||||||
# references = validate(request.get_json(), letter_references)['references']
|
|
||||||
|
|
||||||
# for start_index in range(0, len(references), MAX_REFERENCES_PER_TASK):
|
|
||||||
# process_returned_letters_list.apply_async(
|
|
||||||
# args=(references[start_index:start_index + MAX_REFERENCES_PER_TASK], ),
|
|
||||||
# queue=QueueNames.DATABASE,
|
|
||||||
# compression='zlib'
|
|
||||||
# )
|
|
||||||
|
|
||||||
# return jsonify(references=references), 200
|
|
||||||
@@ -1331,12 +1331,6 @@ NOTIFICATION_STATUS_TYPES_ENUM = db.Enum(*NOTIFICATION_STATUS_TYPES, name='notif
|
|||||||
NOTIFICATION_STATUS_LETTER_ACCEPTED = 'accepted'
|
NOTIFICATION_STATUS_LETTER_ACCEPTED = 'accepted'
|
||||||
NOTIFICATION_STATUS_LETTER_RECEIVED = 'received'
|
NOTIFICATION_STATUS_LETTER_RECEIVED = 'received'
|
||||||
|
|
||||||
# TODO: delete these keywords for postage
|
|
||||||
FIRST_CLASS = 'first'
|
|
||||||
SECOND_CLASS = 'second'
|
|
||||||
EUROPE = 'europe'
|
|
||||||
REST_OF_WORLD = 'rest-of-world'
|
|
||||||
|
|
||||||
|
|
||||||
class NotificationStatusTypes(db.Model):
|
class NotificationStatusTypes(db.Model):
|
||||||
__tablename__ = 'notification_status_types'
|
__tablename__ = 'notification_status_types'
|
||||||
|
|||||||
@@ -721,14 +721,6 @@ def create_one_off_notification(service_id):
|
|||||||
return jsonify(resp), 201
|
return jsonify(resp), 201
|
||||||
|
|
||||||
|
|
||||||
# TODO: return deprecation notice
|
|
||||||
# @service_blueprint.route('/<uuid:service_id>/send-pdf-letter', methods=['POST'])
|
|
||||||
# def create_pdf_letter(service_id):
|
|
||||||
# data = validate(request.get_json(), send_pdf_letter_request)
|
|
||||||
# resp = send_pdf_letter_notification(service_id, data)
|
|
||||||
# return jsonify(resp), 201
|
|
||||||
|
|
||||||
|
|
||||||
@service_blueprint.route('/<uuid:service_id>/email-reply-to', methods=["GET"])
|
@service_blueprint.route('/<uuid:service_id>/email-reply-to', methods=["GET"])
|
||||||
def get_email_reply_to_addresses(service_id):
|
def get_email_reply_to_addresses(service_id):
|
||||||
result = dao_get_reply_to_by_service_id(service_id)
|
result = dao_get_reply_to_by_service_id(service_id)
|
||||||
|
|||||||
@@ -20,35 +20,6 @@ def get_notification_by_id(notification_id):
|
|||||||
return jsonify(notification.serialize()), 200
|
return jsonify(notification.serialize()), 200
|
||||||
|
|
||||||
|
|
||||||
# TODO: return deprecation notice
|
|
||||||
# @v2_notification_blueprint.route('/<notification_id>/pdf', methods=['GET'])
|
|
||||||
# def get_pdf_for_notification(notification_id):
|
|
||||||
# _data = {"notification_id": notification_id}
|
|
||||||
# validate(_data, notification_by_id)
|
|
||||||
# notification = notifications_dao.get_notification_by_id(
|
|
||||||
# notification_id, authenticated_service.id, _raise=True
|
|
||||||
# )
|
|
||||||
|
|
||||||
# if notification.notification_type != LETTER_TYPE:
|
|
||||||
# raise BadRequestError(message="Notification is not a letter")
|
|
||||||
|
|
||||||
# if notification.status == NOTIFICATION_VIRUS_SCAN_FAILED:
|
|
||||||
# raise BadRequestError(message='File did not pass the virus scan')
|
|
||||||
|
|
||||||
# if notification.status == NOTIFICATION_TECHNICAL_FAILURE:
|
|
||||||
# raise BadRequestError(message='PDF not available for letters in status {}'.format(notification.status))
|
|
||||||
|
|
||||||
# if notification.status == NOTIFICATION_PENDING_VIRUS_CHECK:
|
|
||||||
# raise PDFNotReadyError()
|
|
||||||
|
|
||||||
# try:
|
|
||||||
# pdf_data, metadata = get_letter_pdf_and_metadata(notification)
|
|
||||||
# except Exception:
|
|
||||||
# raise PDFNotReadyError()
|
|
||||||
|
|
||||||
# return send_file(path_or_file=BytesIO(pdf_data), mimetype='application/pdf')
|
|
||||||
|
|
||||||
|
|
||||||
@v2_notification_blueprint.route("", methods=['GET'])
|
@v2_notification_blueprint.route("", methods=['GET'])
|
||||||
def get_notifications():
|
def get_notifications():
|
||||||
_data = request.args.to_dict(flat=False)
|
_data = request.args.to_dict(flat=False)
|
||||||
|
|||||||
@@ -66,41 +66,6 @@ POST_NOTIFICATION_JSON_PARSE_DURATION_SECONDS = Histogram(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# TODO: return deprecation message
|
|
||||||
# @v2_notification_blueprint.route('/{}'.format(LETTER_TYPE), methods=['POST'])
|
|
||||||
# def post_precompiled_letter_notification():
|
|
||||||
# request_json = get_valid_json()
|
|
||||||
# if 'content' not in (request_json or {}):
|
|
||||||
# return post_notification(LETTER_TYPE)
|
|
||||||
|
|
||||||
# form = validate(request_json, post_precompiled_letter_request)
|
|
||||||
|
|
||||||
# # Check permission to send letters
|
|
||||||
# check_service_has_permission(LETTER_TYPE, authenticated_service.permissions)
|
|
||||||
|
|
||||||
# check_rate_limiting(authenticated_service, api_user)
|
|
||||||
|
|
||||||
# template = get_precompiled_letter_template(authenticated_service.id)
|
|
||||||
|
|
||||||
# # For precompiled letters the to field will be set to Provided as PDF until the validation passes,
|
|
||||||
# # then the address of the letter will be set as the to field
|
|
||||||
# form['personalisation'] = {
|
|
||||||
# 'address_line_1': 'Provided as PDF'
|
|
||||||
# }
|
|
||||||
|
|
||||||
# notification = process_letter_notification(
|
|
||||||
# letter_data=form,
|
|
||||||
# api_key=api_user,
|
|
||||||
# service=authenticated_service,
|
|
||||||
# template=template,
|
|
||||||
# template_with_content=None, # not required for precompiled
|
|
||||||
# reply_to_text='', # not required for precompiled
|
|
||||||
# precompiled=True
|
|
||||||
# )
|
|
||||||
|
|
||||||
# return jsonify(notification), 201
|
|
||||||
|
|
||||||
|
|
||||||
@v2_notification_blueprint.route('/<notification_type>', methods=['POST'])
|
@v2_notification_blueprint.route('/<notification_type>', methods=['POST'])
|
||||||
def post_notification(notification_type):
|
def post_notification(notification_type):
|
||||||
with POST_NOTIFICATION_JSON_PARSE_DURATION_SECONDS.time():
|
with POST_NOTIFICATION_JSON_PARSE_DURATION_SECONDS.time():
|
||||||
|
|||||||
@@ -291,41 +291,6 @@ def test_should_process_email_job_with_sender_id(email_job_with_placeholders, mo
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@freeze_time("2016-01-01 11:09:00.061258")
|
|
||||||
def test_should_process_letter_job(sample_letter_job, mocker):
|
|
||||||
csv = """address_line_1,address_line_2,address_line_3,address_line_4,postcode,name
|
|
||||||
A1,A2,A3,A4,A_POST,Alice
|
|
||||||
"""
|
|
||||||
s3_mock = mocker.patch('app.celery.tasks.s3.get_job_and_metadata_from_s3',
|
|
||||||
return_value=(csv, {"sender_id": None}))
|
|
||||||
process_row_mock = mocker.patch('app.celery.tasks.process_row')
|
|
||||||
mocker.patch('app.celery.tasks.create_uuid', return_value="uuid")
|
|
||||||
|
|
||||||
process_job(sample_letter_job.id)
|
|
||||||
|
|
||||||
s3_mock.assert_called_once_with(
|
|
||||||
service_id=str(sample_letter_job.service.id),
|
|
||||||
job_id=str(sample_letter_job.id)
|
|
||||||
)
|
|
||||||
|
|
||||||
row_call = process_row_mock.mock_calls[0][1]
|
|
||||||
assert row_call[0].index == 0
|
|
||||||
assert row_call[0].recipient == ['A1', 'A2', 'A3', 'A4', None, None, 'A_POST', None]
|
|
||||||
assert row_call[0].personalisation == {
|
|
||||||
'addressline1': 'A1',
|
|
||||||
'addressline2': 'A2',
|
|
||||||
'addressline3': 'A3',
|
|
||||||
'addressline4': 'A4',
|
|
||||||
'postcode': 'A_POST'
|
|
||||||
}
|
|
||||||
assert row_call[2] == sample_letter_job
|
|
||||||
assert row_call[3] == sample_letter_job.service
|
|
||||||
|
|
||||||
assert process_row_mock.call_count == 1
|
|
||||||
|
|
||||||
assert sample_letter_job.job_status == 'finished'
|
|
||||||
|
|
||||||
|
|
||||||
def test_should_process_all_sms_job(sample_job_with_placeholdered_template,
|
def test_should_process_all_sms_job(sample_job_with_placeholdered_template,
|
||||||
mocker):
|
mocker):
|
||||||
mocker.patch('app.celery.tasks.s3.get_job_and_metadata_from_s3',
|
mocker.patch('app.celery.tasks.s3.get_job_and_metadata_from_s3',
|
||||||
|
|||||||
@@ -407,25 +407,6 @@ def sample_scheduled_job(sample_template_with_placeholders):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_letter_job(sample_letter_template):
|
|
||||||
service = sample_letter_template.service
|
|
||||||
data = {
|
|
||||||
'id': uuid.uuid4(),
|
|
||||||
'service_id': service.id,
|
|
||||||
'service': service,
|
|
||||||
'template_id': sample_letter_template.id,
|
|
||||||
'template_version': sample_letter_template.version,
|
|
||||||
'original_file_name': 'some.csv',
|
|
||||||
'notification_count': 1,
|
|
||||||
'created_at': datetime.utcnow(),
|
|
||||||
'created_by': service.created_by,
|
|
||||||
}
|
|
||||||
job = Job(**data)
|
|
||||||
dao_create_job(job)
|
|
||||||
return job
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
@pytest.fixture(scope='function')
|
||||||
def sample_notification_with_job(notify_db_session):
|
def sample_notification_with_job(notify_db_session):
|
||||||
service = create_service(check_if_service_exists=True)
|
service = create_service(check_if_service_exists=True)
|
||||||
|
|||||||
@@ -289,7 +289,7 @@ def test_get_rates_for_billing(notify_db_session):
|
|||||||
create_rate(start_date=datetime.utcnow(), value=33, notification_type='email')
|
create_rate(start_date=datetime.utcnow(), value=33, notification_type='email')
|
||||||
rates = get_rates_for_billing()
|
rates = get_rates_for_billing()
|
||||||
|
|
||||||
assert len(rates) == 2
|
assert len(rates) == 3
|
||||||
|
|
||||||
|
|
||||||
@freeze_time('2017-06-01 12:00')
|
@freeze_time('2017-06-01 12:00')
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ from freezegun import freeze_time
|
|||||||
from sqlalchemy.exc import IntegrityError
|
from sqlalchemy.exc import IntegrityError
|
||||||
|
|
||||||
from app.dao.jobs_dao import (
|
from app.dao.jobs_dao import (
|
||||||
can_letter_job_be_cancelled,
|
|
||||||
dao_cancel_letter_job,
|
|
||||||
dao_create_job,
|
dao_create_job,
|
||||||
dao_get_future_scheduled_job_by_id_and_service_id,
|
dao_get_future_scheduled_job_by_id_and_service_id,
|
||||||
dao_get_job_by_service_id_and_job_id,
|
dao_get_job_by_service_id_and_job_id,
|
||||||
@@ -359,98 +357,6 @@ def assert_job_stat(job, result, sent, delivered, failed):
|
|||||||
assert result.failed == failed
|
assert result.failed == failed
|
||||||
|
|
||||||
|
|
||||||
@freeze_time('2019-06-13 13:00')
|
|
||||||
def test_dao_cancel_letter_job_cancels_job_and_returns_number_of_cancelled_notifications(
|
|
||||||
sample_letter_template
|
|
||||||
):
|
|
||||||
job = create_job(template=sample_letter_template, notification_count=1, job_status='finished')
|
|
||||||
notification = create_notification(template=job.template, job=job, status='created')
|
|
||||||
result = dao_cancel_letter_job(job)
|
|
||||||
assert result == 1
|
|
||||||
assert notification.status == 'cancelled'
|
|
||||||
assert job.job_status == 'cancelled'
|
|
||||||
|
|
||||||
|
|
||||||
@freeze_time('2019-06-13 13:00')
|
|
||||||
def test_can_letter_job_be_cancelled_returns_true_if_job_can_be_cancelled(sample_letter_template):
|
|
||||||
job = create_job(template=sample_letter_template, notification_count=1, job_status='finished')
|
|
||||||
create_notification(template=job.template, job=job, status='created')
|
|
||||||
result, errors = can_letter_job_be_cancelled(job)
|
|
||||||
assert result
|
|
||||||
assert not errors
|
|
||||||
|
|
||||||
|
|
||||||
@freeze_time('2019-06-13 13:00')
|
|
||||||
def test_can_letter_job_be_cancelled_returns_false_and_error_message_if_notification_status_sending(
|
|
||||||
sample_letter_template
|
|
||||||
):
|
|
||||||
job = create_job(template=sample_letter_template, notification_count=2, job_status='finished')
|
|
||||||
create_notification(template=job.template, job=job, status='sending')
|
|
||||||
create_notification(template=job.template, job=job, status='created')
|
|
||||||
result, errors = can_letter_job_be_cancelled(job)
|
|
||||||
assert not result
|
|
||||||
assert errors == "It’s too late to cancel sending, these letters have already been sent."
|
|
||||||
|
|
||||||
|
|
||||||
def test_can_letter_job_be_cancelled_returns_false_and_error_message_if_letters_already_sent_to_dvla(
|
|
||||||
sample_letter_template
|
|
||||||
):
|
|
||||||
with freeze_time('2019-06-13 13:00'):
|
|
||||||
job = create_job(template=sample_letter_template, notification_count=1, job_status='finished')
|
|
||||||
letter = create_notification(template=job.template, job=job, status='created')
|
|
||||||
|
|
||||||
with freeze_time('2019-06-13 22:32'):
|
|
||||||
result, errors = can_letter_job_be_cancelled(job)
|
|
||||||
assert not result
|
|
||||||
assert errors == "It’s too late to cancel sending, these letters have already been sent."
|
|
||||||
assert letter.status == 'created'
|
|
||||||
assert job.job_status == 'finished'
|
|
||||||
|
|
||||||
|
|
||||||
@freeze_time('2019-06-13 13:00')
|
|
||||||
def test_can_letter_job_be_cancelled_returns_false_and_error_message_if_not_a_letter_job(
|
|
||||||
sample_template
|
|
||||||
):
|
|
||||||
job = create_job(template=sample_template, notification_count=1, job_status='finished')
|
|
||||||
create_notification(template=job.template, job=job, status='created')
|
|
||||||
result, errors = can_letter_job_be_cancelled(job)
|
|
||||||
assert not result
|
|
||||||
assert errors == "Only letter jobs can be cancelled through this endpoint. This is not a letter job."
|
|
||||||
|
|
||||||
|
|
||||||
@freeze_time('2019-06-13 13:00')
|
|
||||||
def test_can_letter_job_be_cancelled_returns_false_and_error_message_if_job_not_finished(
|
|
||||||
sample_letter_template
|
|
||||||
):
|
|
||||||
job = create_job(template=sample_letter_template, notification_count=1, job_status="in progress")
|
|
||||||
create_notification(template=job.template, job=job, status='created')
|
|
||||||
result, errors = can_letter_job_be_cancelled(job)
|
|
||||||
assert not result
|
|
||||||
assert errors == "We are still processing these letters, please try again in a minute."
|
|
||||||
|
|
||||||
|
|
||||||
@freeze_time('2019-06-13 13:00')
|
|
||||||
def test_can_letter_job_be_cancelled_returns_false_and_error_message_if_notifications_not_in_db_yet(
|
|
||||||
sample_letter_template
|
|
||||||
):
|
|
||||||
job = create_job(template=sample_letter_template, notification_count=2, job_status='finished')
|
|
||||||
create_notification(template=job.template, job=job, status='created')
|
|
||||||
result, errors = can_letter_job_be_cancelled(job)
|
|
||||||
assert not result
|
|
||||||
assert errors == "We are still processing these letters, please try again in a minute."
|
|
||||||
|
|
||||||
|
|
||||||
def test_can_letter_job_be_cancelled_respects_bst(sample_letter_template):
|
|
||||||
job = create_job(template=sample_letter_template, created_at=datetime(2020, 4, 9, 23, 30), job_status='finished')
|
|
||||||
create_notification(template=job.template, job=job, status='created', created_at=datetime(2020, 4, 9, 23, 32))
|
|
||||||
|
|
||||||
with freeze_time('2020-04-10 10:00'):
|
|
||||||
result, errors = can_letter_job_be_cancelled(job)
|
|
||||||
|
|
||||||
assert not errors
|
|
||||||
assert result
|
|
||||||
|
|
||||||
|
|
||||||
def test_find_jobs_with_missing_rows(sample_email_template):
|
def test_find_jobs_with_missing_rows(sample_email_template):
|
||||||
healthy_job = create_job(template=sample_email_template,
|
healthy_job = create_job(template=sample_email_template,
|
||||||
notification_count=3,
|
notification_count=3,
|
||||||
|
|||||||
Reference in New Issue
Block a user