diff --git a/app/models.py b/app/models.py index ad3262be8..e6a0f77fa 100644 --- a/app/models.py +++ b/app/models.py @@ -903,7 +903,7 @@ class TemplateBase(db.Model): postage = db.Column(db.String, nullable=True) CheckConstraint(""" CASE WHEN template_type = 'letter' THEN - postage is not null and postage in ('first', 'second') + postage is not null and postage in ('first', 'second', 'europe', 'rest-of-world') ELSE postage is null END @@ -1353,10 +1353,13 @@ DVLA_RESPONSE_STATUS_SENT = 'Sent' FIRST_CLASS = 'first' SECOND_CLASS = 'second' -POSTAGE_TYPES = [FIRST_CLASS, SECOND_CLASS] +EUROPE = 'europe' +REST_OF_WORLD = 'rest-of-world' RESOLVE_POSTAGE_FOR_FILE_NAME = { FIRST_CLASS: 1, - SECOND_CLASS: 2 + SECOND_CLASS: 2, + EUROPE: 'E', + REST_OF_WORLD: 'N', } @@ -1433,7 +1436,7 @@ class Notification(db.Model): postage = db.Column(db.String, nullable=True) CheckConstraint(""" CASE WHEN notification_type = 'letter' THEN - postage is not null and postage in ('first', 'second') + postage is not null and postage in ('first', 'second', 'europe', 'rest-of-world') ELSE postage is null END @@ -1698,13 +1701,6 @@ class NotificationHistory(db.Model, HistoryModel): created_by_id = db.Column(UUID(as_uuid=True), nullable=True) postage = db.Column(db.String, nullable=True) - CheckConstraint(""" - CASE WHEN notification_type = 'letter' THEN - postage is not null and postage in ('first', 'second') - ELSE - postage is null - END - """) document_download_count = db.Column(db.Integer, nullable=True) diff --git a/app/schema_validation/__init__.py b/app/schema_validation/__init__.py index e1995f528..0ddd51f16 100644 --- a/app/schema_validation/__init__.py +++ b/app/schema_validation/__init__.py @@ -34,8 +34,8 @@ def validate_schema_email_address(instance): @format_checker.checks('postage', raises=ValidationError) def validate_schema_postage(instance): if isinstance(instance, str): - if instance not in ["first", "second"]: - raise ValidationError("invalid. It must be either first or second.") + if instance not in ["first", "second", "europe", "rest-of-world"]: + raise ValidationError("invalid. It must be first, second, europe or rest-of-world.") return True diff --git a/migrations/versions/0321_update_postage_constraint_1.py b/migrations/versions/0321_update_postage_constraint_1.py new file mode 100644 index 000000000..32e7f186a --- /dev/null +++ b/migrations/versions/0321_update_postage_constraint_1.py @@ -0,0 +1,80 @@ +""" + +Revision ID: 0321_update_postage_constraint_1 +Revises: 0320_optimise_notifications +Create Date: 2020-03-11 12:01:41.533192 + +""" +from alembic import op +import sqlalchemy as sa + + +revision = '0321_update_postage_constraint_1' +down_revision = '0320_optimise_notifications' + + +def upgrade(): + op.drop_constraint('chk_notifications_postage_null', 'notifications') + op.execute(""" + ALTER TABLE notifications ADD CONSTRAINT "chk_notifications_postage_null" + CHECK ( + CASE WHEN notification_type = 'letter' THEN + postage is not null and postage in ('first', 'second', 'europe', 'rest-of-world') + ELSE + postage is null + END + ) + NOT VALID + """) + op.drop_constraint('chk_notification_history_postage_null', 'notification_history') + + +def downgrade(): + pass + # To downgrade this migration and migrations 0320 and 0321 * LOCALLY ONLY * use the following code. + # This should not be used in production - it will lock the tables for a long time + # + # op.drop_constraint('chk_notifications_postage_null', 'notifications') + # op.drop_constraint('chk_templates_postage', 'templates') + # op.drop_constraint('chk_templates_history_postage', 'templates_history') + # + # op.execute(""" + # ALTER TABLE notifications ADD CONSTRAINT "chk_notifications_postage_null" + # CHECK ( + # CASE WHEN notification_type = 'letter' THEN + # postage is not null and postage in ('first', 'second') + # ELSE + # postage is null + # END + # ) + # """) + # op.execute(""" + # ALTER TABLE notification_history ADD CONSTRAINT "chk_notification_history_postage_null" + # CHECK ( + # CASE WHEN notification_type = 'letter' THEN + # postage is not null and postage in ('first', 'second') + # ELSE + # postage is null + # END + # ) + # """) + # op.execute(""" + # ALTER TABLE templates ADD CONSTRAINT "chk_templates_postage" + # CHECK ( + # CASE WHEN template_type = 'letter' THEN + # postage is not null and postage in ('first', 'second') + # ELSE + # postage is null + # END + # ) + # """) + # op.execute(""" + # ALTER TABLE templates_history ADD CONSTRAINT "chk_templates_history_postage" + # CHECK ( + # CASE WHEN template_type = 'letter' THEN + # postage is not null and postage in ('first', 'second') + # ELSE + # postage is null + # END + # ) + # """) diff --git a/migrations/versions/0322_update_postage_constraint_2.py b/migrations/versions/0322_update_postage_constraint_2.py new file mode 100644 index 000000000..a715fb25c --- /dev/null +++ b/migrations/versions/0322_update_postage_constraint_2.py @@ -0,0 +1,45 @@ +""" + +Revision ID: 0322_update_postage_constraint_2 +Revises: 0321_update_postage_constraint_1 +Create Date: 2020-03-12 12:01:41.533192 + +""" +from alembic import op +import sqlalchemy as sa + + +revision = '0322_update_postage_constraint_2' +down_revision = '0321_update_postage_constraint_1' + + +def upgrade(): + op.drop_constraint('chk_templates_postage', 'templates') + op.drop_constraint('chk_templates_history_postage', 'templates_history') + + op.execute(""" + ALTER TABLE templates ADD CONSTRAINT "chk_templates_postage" + CHECK ( + CASE WHEN template_type = 'letter' THEN + postage is not null and postage in ('first', 'second', 'europe', 'rest-of-world') + ELSE + postage is null + END + ) + NOT VALID + """) + op.execute(""" + ALTER TABLE templates_history ADD CONSTRAINT "chk_templates_history_postage" + CHECK ( + CASE WHEN template_type = 'letter' THEN + postage is not null and postage in ('first', 'second', 'europe', 'rest-of-world') + ELSE + postage is null + END + ) + NOT VALID + """) + + +def downgrade(): + pass diff --git a/migrations/versions/0323_update_postage_constraint_3.py b/migrations/versions/0323_update_postage_constraint_3.py new file mode 100644 index 000000000..0143b4aa9 --- /dev/null +++ b/migrations/versions/0323_update_postage_constraint_3.py @@ -0,0 +1,23 @@ +""" + +Revision ID: 0323_update_postage_constraint_3 +Revises: 0322_update_postage_constraint_2 +Create Date: 2020-03-12 12:01:41.533192 + +""" +from alembic import op +import sqlalchemy as sa + + +revision = '0323_update_postage_constraint_3' +down_revision = '0322_update_postage_constraint_2' + + +def upgrade(): + op.execute('ALTER TABLE notifications VALIDATE CONSTRAINT "chk_notifications_postage_null"') + op.execute('ALTER TABLE templates VALIDATE CONSTRAINT "chk_templates_postage"') + op.execute('ALTER TABLE templates_history VALIDATE CONSTRAINT "chk_templates_history_postage"') + + +def downgrade(): + pass diff --git a/tests/app/service/test_rest.py b/tests/app/service/test_rest.py index 637683453..bc1fc6955 100644 --- a/tests/app/service/test_rest.py +++ b/tests/app/service/test_rest.py @@ -2313,7 +2313,8 @@ def test_create_pdf_letter(mocker, sample_service_full_permissions, client, fake {"postage": "third", "filename": "string", "created_by": "string", "file_id": "string", "recipient_address": "Some Address"}, [ - {'error': 'ValidationError', 'message': 'postage invalid. It must be either first or second.'} + {'error': 'ValidationError', + 'message': 'postage invalid. It must be first, second, europe or rest-of-world.'} ] ) ]) diff --git a/tests/app/v2/notifications/test_post_letter_notifications.py b/tests/app/v2/notifications/test_post_letter_notifications.py index fc80ecef7..e3d0dc164 100644 --- a/tests/app/v2/notifications/test_post_letter_notifications.py +++ b/tests/app/v2/notifications/test_post_letter_notifications.py @@ -597,7 +597,7 @@ def test_post_letter_notification_throws_error_for_invalid_postage(client, notif assert response.status_code == 400, response.get_data(as_text=True) resp_json = json.loads(response.get_data(as_text=True)) - assert resp_json['errors'][0]['message'] == "postage invalid. It must be either first or second." + assert resp_json['errors'][0]['message'] == "postage invalid. It must be first, second, europe or rest-of-world." assert not Notification.query.first()