From 8b410e8876835133b7f18e42754da7c793ce950f Mon Sep 17 00:00:00 2001 From: Pea Tyczynska Date: Fri, 14 Sep 2018 17:26:43 +0100 Subject: [PATCH 01/10] Add new letter rates from 1st of October 2018 --- migrations/versions/0226_new_letter_rates.py | 53 ++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 migrations/versions/0226_new_letter_rates.py diff --git a/migrations/versions/0226_new_letter_rates.py b/migrations/versions/0226_new_letter_rates.py new file mode 100644 index 000000000..7e57d388f --- /dev/null +++ b/migrations/versions/0226_new_letter_rates.py @@ -0,0 +1,53 @@ +"""empty message + +Revision ID: 0226_new_letter_rates +Revises: 0225_another_letter_org + +""" + +revision = '0226_new_letter_rates' +down_revision = '0225_another_letter_org' + +import uuid +from datetime import datetime +from alembic import op + + +start = datetime(2018, 10, 1, 0, 0, tzinfo=timezone.utc) + +NEW_RATES = [ + (uuid.uuid4(), start, 1, 0.30, True, 'second'), + (uuid.uuid4(), start, 1, 0.30, False, 'second'), + (uuid.uuid4(), start, 2, 0.35, True, 'second'), + (uuid.uuid4(), start, 2, 0.35, False, 'second'), + (uuid.uuid4(), start, 3, 0.40, True, 'second'), + (uuid.uuid4(), start, 3, 0.40, False, 'second'), + (uuid.uuid4(), start, 4, 0.45, True, 'second'), + (uuid.uuid4(), start, 4, 0.45, False, 'second'), + (uuid.uuid4(), start, 5, 0.50, True, 'second'), + (uuid.uuid4(), start, 5, 0.50, False, 'second'), + (uuid.uuid4(), start, 1, 0.56, True, 'first'), + (uuid.uuid4(), start, 1, 0.56, False, 'first'), + (uuid.uuid4(), start, 2, 0.61, True, 'first'), + (uuid.uuid4(), start, 2, 0.61, False, 'first'), + (uuid.uuid4(), start, 3, 0.66, True, 'first'), + (uuid.uuid4(), start, 3, 0.66, False, 'first'), + (uuid.uuid4(), start, 4, 0.71, True, 'first'), + (uuid.uuid4(), start, 4, 0.71, False, 'first'), + (uuid.uuid4(), start, 5, 0.76, True, 'first'), + (uuid.uuid4(), start, 5, 0.76, False, 'first'), + +] + + +def upgrade(): + conn = op.get_bind() + for id, start_date, sheet_count, rate, crown, post_class in NEW_RATES: + conn.execute(""" + INSERT INTO letter_rates (id, start_date, sheet_count, rate, crown, post_class) + VALUES ('{}', '{}', '{}', '{}', '{}', '{}') + """.format(id, start_date, sheet_count, rate, crown, post_class)) + + +def downgrade(): + pass From b3191dbc2a8f87b8d03852c0c5818259ec7e097e Mon Sep 17 00:00:00 2001 From: Pea Tyczynska Date: Fri, 14 Sep 2018 17:52:16 +0100 Subject: [PATCH 02/10] Filter letter rates by post_class in get_rate Also adjust existing tests. --- app/dao/fact_billing_dao.py | 14 ++++++++++---- migrations/versions/0226_new_letter_rates.py | 3 ++- tests/app/celery/test_reporting_tasks.py | 9 +++++---- tests/app/dao/test_ft_billing_dao.py | 2 +- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/app/dao/fact_billing_dao.py b/app/dao/fact_billing_dao.py index 367b3e628..3719cc06c 100644 --- a/app/dao/fact_billing_dao.py +++ b/app/dao/fact_billing_dao.py @@ -195,7 +195,7 @@ def fetch_billing_data_for_day(process_day, service_id=None): def get_rates_for_billing(): non_letter_rates = [(r.notification_type, r.valid_from, r.rate) for r in Rate.query.order_by(desc(Rate.valid_from)).all()] - letter_rates = [(r.start_date, r.crown, r.sheet_count, r.rate) for r in + letter_rates = [(r.start_date, r.crown, r.sheet_count, r.rate, r.post_class) for r in LetterRate.query.order_by(desc(LetterRate.start_date)).all()] return non_letter_rates, letter_rates @@ -211,11 +211,16 @@ def get_service_ids_that_need_billing_populated(start_date, end_date): ).distinct().all() -def get_rate(non_letter_rates, letter_rates, notification_type, date, crown=None, letter_page_count=None): +def get_rate( + non_letter_rates, letter_rates, notification_type, date, crown=None, letter_page_count=None, post_class='second' +): if notification_type == LETTER_TYPE: if letter_page_count == 0: return 0 - return next(r[3] for r in letter_rates if date > r[0] and crown == r[1] and letter_page_count == r[2]) + return next( + r[3] for r in letter_rates if date > r[0] and crown == r[1] + and letter_page_count == r[2] and post_class == r[4] + ) elif notification_type == SMS_TYPE: return next(r[2] for r in non_letter_rates if notification_type == r[0] and date > r[1]) else: @@ -229,7 +234,8 @@ def update_fact_billing(data, process_day): data.notification_type, process_day, data.crown, - data.letter_page_count) + data.letter_page_count, + "second") billing_record = create_billing_record(data, rate, process_day) table = FactBilling.__table__ ''' diff --git a/migrations/versions/0226_new_letter_rates.py b/migrations/versions/0226_new_letter_rates.py index 7e57d388f..54c45bacc 100644 --- a/migrations/versions/0226_new_letter_rates.py +++ b/migrations/versions/0226_new_letter_rates.py @@ -9,11 +9,12 @@ revision = '0226_new_letter_rates' down_revision = '0225_another_letter_org' import uuid +import pytz from datetime import datetime from alembic import op -start = datetime(2018, 10, 1, 0, 0, tzinfo=timezone.utc) +start = datetime(2018, 10, 1, 0, 0, tzinfo=pytz.utc) NEW_RATES = [ (uuid.uuid4(), start, 1, 0.30, True, 'second'), diff --git a/tests/app/celery/test_reporting_tasks.py b/tests/app/celery/test_reporting_tasks.py index a4a21afd7..9b371bf9d 100644 --- a/tests/app/celery/test_reporting_tasks.py +++ b/tests/app/celery/test_reporting_tasks.py @@ -23,7 +23,7 @@ def test_reporting_should_have_decorated_tasks_functions(): assert create_nightly_billing.__wrapped__.__name__ == 'create_nightly_billing' -def mocker_get_rate(non_letter_rates, letter_rates, notification_type, date, crown=None, rate_multiplier=None): +def mocker_get_rate(non_letter_rates, letter_rates, notification_type, date, crown=None, rate_multiplier=None, post_class="second"): if notification_type == LETTER_TYPE: return Decimal(2.1) elif notification_type == SMS_TYPE: @@ -319,9 +319,10 @@ def test_get_rate_for_letter_latest(notify_db_session): non_letter_rates = [(r.notification_type, r.valid_from, r.rate) for r in Rate.query.order_by(desc(Rate.valid_from)).all()] - # letter rates should be passed into the get_rate function as a tuple of start_date, crown, sheet_count & rate - new_letter_rate = (datetime(2017, 12, 1), True, 1, Decimal(0.33)) - old_letter_rate = (datetime(2016, 12, 1), True, 1, Decimal(0.30)) + # letter rates should be passed into the get_rate function as a tuple of start_date, crown, sheet_count, + # rate and post_class + new_letter_rate = (datetime(2017, 12, 1), True, 1, Decimal(0.33), 'second') + old_letter_rate = (datetime(2016, 12, 1), True, 1, Decimal(0.30), 'second') letter_rates = [new_letter_rate, old_letter_rate] rate = get_rate(non_letter_rates, letter_rates, LETTER_TYPE, datetime(2018, 1, 1), True, 1) diff --git a/tests/app/dao/test_ft_billing_dao.py b/tests/app/dao/test_ft_billing_dao.py index 1eeabeff0..a51feb2ea 100644 --- a/tests/app/dao/test_ft_billing_dao.py +++ b/tests/app/dao/test_ft_billing_dao.py @@ -228,7 +228,7 @@ def test_get_rates_for_billing(notify_db_session): non_letter_rates, letter_rates = get_rates_for_billing() assert len(non_letter_rates) == 3 - assert len(letter_rates) == 10 + assert len(letter_rates) == 30 def test_get_rate(notify_db_session): From 39ebfb68263142bda1dac398b8544990da4acde1 Mon Sep 17 00:00:00 2001 From: Pea Tyczynska Date: Mon, 17 Sep 2018 14:12:06 +0100 Subject: [PATCH 03/10] Test filtering letter_rates by post_class --- tests/app/celery/test_reporting_tasks.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/app/celery/test_reporting_tasks.py b/tests/app/celery/test_reporting_tasks.py index 9b371bf9d..096ca73d6 100644 --- a/tests/app/celery/test_reporting_tasks.py +++ b/tests/app/celery/test_reporting_tasks.py @@ -23,7 +23,9 @@ def test_reporting_should_have_decorated_tasks_functions(): assert create_nightly_billing.__wrapped__.__name__ == 'create_nightly_billing' -def mocker_get_rate(non_letter_rates, letter_rates, notification_type, date, crown=None, rate_multiplier=None, post_class="second"): +def mocker_get_rate( + non_letter_rates, letter_rates, notification_type, date, crown=None, rate_multiplier=None, post_class="second" +): if notification_type == LETTER_TYPE: return Decimal(2.1) elif notification_type == SMS_TYPE: @@ -329,6 +331,21 @@ def test_get_rate_for_letter_latest(notify_db_session): assert rate == Decimal(0.33) +@pytest.mark.parametrize( + "letter_post_class,expected_rate", [("first", 0.42), ("second", 0.33)] +) +def test_get_rate_filters_letters_byl_post_class(notify_db_session, letter_post_class, expected_rate): + non_letter_rates = [(r.notification_type, r.valid_from, r.rate) for r in + Rate.query.order_by(desc(Rate.valid_from)).all()] + + letter_rates = [ + (datetime(2017, 12, 1), True, 1, Decimal(0.42), 'first'), + (datetime(2017, 12, 1), True, 1, Decimal(0.33), 'second') + ] + rate = get_rate(non_letter_rates, letter_rates, LETTER_TYPE, datetime(2018, 1, 1), True, 1, letter_post_class) + assert rate == Decimal(expected_rate) + + def test_get_rate_for_sms_and_email(notify_db, notify_db_session): sms_rate = Rate(valid_from=datetime(2017, 12, 1), rate=Decimal(0.15), From 85e57025b281d87b0052a4fe6a3ffd85f3fd0664 Mon Sep 17 00:00:00 2001 From: Pea Tyczynska Date: Thu, 20 Sep 2018 14:34:46 +0100 Subject: [PATCH 04/10] Define MMG inbound credentials for local in Development environment --- app/config.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/config.py b/app/config.py index ef5fef795..ae7788d34 100644 --- a/app/config.py +++ b/app/config.py @@ -342,6 +342,9 @@ class Development(Config): SECRET_KEY = 'dev-notify-secret-key' DANGEROUS_SALT = 'dev-notify-salt' + MMG_INBOUND_SMS_AUTH = ['testkey'] + MMG_INBOUND_SMS_USERNAME = ['username'] + NOTIFY_ENVIRONMENT = 'development' NOTIFY_LOG_PATH = 'application.log' NOTIFICATION_QUEUE_PREFIX = 'development' @@ -392,8 +395,6 @@ class Test(Development): SMS_INBOUND_WHITELIST = ['203.0.113.195'] FIRETEXT_INBOUND_SMS_AUTH = ['testkey'] - MMG_INBOUND_SMS_AUTH = ['testkey'] - MMG_INBOUND_SMS_USERNAME = ['username'] TEMPLATE_PREVIEW_API_HOST = 'http://localhost:9999' From 0c0166922c7d505df329e98ee2ccc8e77ff114a8 Mon Sep 17 00:00:00 2001 From: Pea Tyczynska Date: Thu, 20 Sep 2018 14:39:33 +0100 Subject: [PATCH 05/10] Update migration number and get rid of explicit UTC zoning therein --- ...6_new_letter_rates.py => 0229_new_letter_rates.py} | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) rename migrations/versions/{0226_new_letter_rates.py => 0229_new_letter_rates.py} (88%) diff --git a/migrations/versions/0226_new_letter_rates.py b/migrations/versions/0229_new_letter_rates.py similarity index 88% rename from migrations/versions/0226_new_letter_rates.py rename to migrations/versions/0229_new_letter_rates.py index 54c45bacc..2b20816b4 100644 --- a/migrations/versions/0226_new_letter_rates.py +++ b/migrations/versions/0229_new_letter_rates.py @@ -1,20 +1,19 @@ """empty message -Revision ID: 0226_new_letter_rates -Revises: 0225_another_letter_org +Revision ID: 0229_new_letter_rates +Revises: 0228_notification_postage """ -revision = '0226_new_letter_rates' -down_revision = '0225_another_letter_org' +revision = '0229_new_letter_rates' +down_revision = '0228_notification_postage' import uuid -import pytz from datetime import datetime from alembic import op -start = datetime(2018, 10, 1, 0, 0, tzinfo=pytz.utc) +start = datetime(2018, 9, 30, 23, 0) NEW_RATES = [ (uuid.uuid4(), start, 1, 0.30, True, 'second'), From 86533c236635fb8f849e2dc40c35d772682a7193 Mon Sep 17 00:00:00 2001 From: Pea Tyczynska Date: Thu, 20 Sep 2018 14:47:06 +0100 Subject: [PATCH 06/10] Do not update the rate that doesn't change --- migrations/versions/0229_new_letter_rates.py | 1 - 1 file changed, 1 deletion(-) diff --git a/migrations/versions/0229_new_letter_rates.py b/migrations/versions/0229_new_letter_rates.py index 2b20816b4..58618c7fa 100644 --- a/migrations/versions/0229_new_letter_rates.py +++ b/migrations/versions/0229_new_letter_rates.py @@ -16,7 +16,6 @@ from alembic import op start = datetime(2018, 9, 30, 23, 0) NEW_RATES = [ - (uuid.uuid4(), start, 1, 0.30, True, 'second'), (uuid.uuid4(), start, 1, 0.30, False, 'second'), (uuid.uuid4(), start, 2, 0.35, True, 'second'), (uuid.uuid4(), start, 2, 0.35, False, 'second'), From eed1d83187e3d379cf8332741196b4c45d0a078a Mon Sep 17 00:00:00 2001 From: Pea Tyczynska Date: Thu, 20 Sep 2018 15:49:15 +0100 Subject: [PATCH 07/10] Test that get_rate gets right rate based on post_class and date --- tests/app/celery/test_reporting_tasks.py | 15 --------------- tests/app/dao/test_ft_billing_dao.py | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/tests/app/celery/test_reporting_tasks.py b/tests/app/celery/test_reporting_tasks.py index 096ca73d6..f21de04c2 100644 --- a/tests/app/celery/test_reporting_tasks.py +++ b/tests/app/celery/test_reporting_tasks.py @@ -331,21 +331,6 @@ def test_get_rate_for_letter_latest(notify_db_session): assert rate == Decimal(0.33) -@pytest.mark.parametrize( - "letter_post_class,expected_rate", [("first", 0.42), ("second", 0.33)] -) -def test_get_rate_filters_letters_byl_post_class(notify_db_session, letter_post_class, expected_rate): - non_letter_rates = [(r.notification_type, r.valid_from, r.rate) for r in - Rate.query.order_by(desc(Rate.valid_from)).all()] - - letter_rates = [ - (datetime(2017, 12, 1), True, 1, Decimal(0.42), 'first'), - (datetime(2017, 12, 1), True, 1, Decimal(0.33), 'second') - ] - rate = get_rate(non_letter_rates, letter_rates, LETTER_TYPE, datetime(2018, 1, 1), True, 1, letter_post_class) - assert rate == Decimal(expected_rate) - - def test_get_rate_for_sms_and_email(notify_db, notify_db_session): sms_rate = Rate(valid_from=datetime(2017, 12, 1), rate=Decimal(0.15), diff --git a/tests/app/dao/test_ft_billing_dao.py b/tests/app/dao/test_ft_billing_dao.py index a51feb2ea..c8c5627b4 100644 --- a/tests/app/dao/test_ft_billing_dao.py +++ b/tests/app/dao/test_ft_billing_dao.py @@ -4,6 +4,8 @@ from decimal import Decimal from datetime import datetime, timedelta from freezegun import freeze_time +import pytest + from app import db from app.dao.fact_billing_dao import ( delete_billing_data_for_service_for_day, @@ -248,6 +250,20 @@ def test_get_rate(notify_db_session): assert letter_rate == Decimal('0.3') +@pytest.mark.parametrize("letter_post_class,expected_rate", [("first", "0.61"), ("second", "0.35")]) +def test_get_rate_filters_letters_by_post_class(notify_db_session, letter_post_class, expected_rate): + non_letter_rates, letter_rates = get_rates_for_billing() + rate = get_rate(non_letter_rates, letter_rates, "letter", datetime(2018, 10, 1), True, 2, letter_post_class) + assert rate == Decimal(expected_rate) + + +@pytest.mark.parametrize("date,expected_rate", [(datetime(2018, 9, 30), '0.33'), (datetime(2018, 10, 1), '0.35')]) +def test_get_rate_chooses_right_rate_depending_on_date(notify_db_session, date, expected_rate): + non_letter_rates, letter_rates = get_rates_for_billing() + rate = get_rate(non_letter_rates, letter_rates, "letter", date, True, 2, "second") + assert rate == Decimal(expected_rate) + + def test_get_rate_for_letters_when_page_count_is_zero(notify_db_session): non_letter_rates, letter_rates = get_rates_for_billing() letter_rate = get_rate(non_letter_rates=non_letter_rates, letter_rates=letter_rates, From 08fec8f928526793ce77cf44c17693fd623728c3 Mon Sep 17 00:00:00 2001 From: Pea Tyczynska Date: Fri, 21 Sep 2018 11:32:12 +0100 Subject: [PATCH 08/10] Fix tests - update number fo letter rates in test --- migrations/versions/0229_new_letter_rates.py | 1 - tests/app/dao/test_ft_billing_dao.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/migrations/versions/0229_new_letter_rates.py b/migrations/versions/0229_new_letter_rates.py index 58618c7fa..69867f5c6 100644 --- a/migrations/versions/0229_new_letter_rates.py +++ b/migrations/versions/0229_new_letter_rates.py @@ -35,7 +35,6 @@ NEW_RATES = [ (uuid.uuid4(), start, 4, 0.71, False, 'first'), (uuid.uuid4(), start, 5, 0.76, True, 'first'), (uuid.uuid4(), start, 5, 0.76, False, 'first'), - ] diff --git a/tests/app/dao/test_ft_billing_dao.py b/tests/app/dao/test_ft_billing_dao.py index c8c5627b4..26a1efe07 100644 --- a/tests/app/dao/test_ft_billing_dao.py +++ b/tests/app/dao/test_ft_billing_dao.py @@ -230,7 +230,7 @@ def test_get_rates_for_billing(notify_db_session): non_letter_rates, letter_rates = get_rates_for_billing() assert len(non_letter_rates) == 3 - assert len(letter_rates) == 30 + assert len(letter_rates) == 29 def test_get_rate(notify_db_session): From 165b65612e9dec8982a5c6fe06287ae2ed582483 Mon Sep 17 00:00:00 2001 From: Pea Tyczynska Date: Mon, 24 Sep 2018 14:52:06 +0100 Subject: [PATCH 09/10] Change how rates are filtered by date to equal or greater --- app/dao/fact_billing_dao.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/dao/fact_billing_dao.py b/app/dao/fact_billing_dao.py index 3719cc06c..0c8d636a8 100644 --- a/app/dao/fact_billing_dao.py +++ b/app/dao/fact_billing_dao.py @@ -218,11 +218,11 @@ def get_rate( if letter_page_count == 0: return 0 return next( - r[3] for r in letter_rates if date > r[0] and crown == r[1] + r[3] for r in letter_rates if date >= r[0] and crown == r[1] and letter_page_count == r[2] and post_class == r[4] ) elif notification_type == SMS_TYPE: - return next(r[2] for r in non_letter_rates if notification_type == r[0] and date > r[1]) + return next(r[2] for r in non_letter_rates if notification_type == r[0] and date >= r[1]) else: return 0 From ea3144c3fdf95388e23ca08d49ca96cca922c732 Mon Sep 17 00:00:00 2001 From: Pea Tyczynska Date: Mon, 24 Sep 2018 14:52:41 +0100 Subject: [PATCH 10/10] Add downgrade steps to new rates migration, add end_date to old rates and refactor migration statements for security good practice --- migrations/versions/0229_new_letter_rates.py | 74 +++++++++++++------- 1 file changed, 50 insertions(+), 24 deletions(-) diff --git a/migrations/versions/0229_new_letter_rates.py b/migrations/versions/0229_new_letter_rates.py index 69867f5c6..bb146bf01 100644 --- a/migrations/versions/0229_new_letter_rates.py +++ b/migrations/versions/0229_new_letter_rates.py @@ -11,41 +11,67 @@ down_revision = '0228_notification_postage' import uuid from datetime import datetime from alembic import op +from sqlalchemy.sql import text -start = datetime(2018, 9, 30, 23, 0) + +START = datetime(2018, 9, 30, 23, 0) NEW_RATES = [ - (uuid.uuid4(), start, 1, 0.30, False, 'second'), - (uuid.uuid4(), start, 2, 0.35, True, 'second'), - (uuid.uuid4(), start, 2, 0.35, False, 'second'), - (uuid.uuid4(), start, 3, 0.40, True, 'second'), - (uuid.uuid4(), start, 3, 0.40, False, 'second'), - (uuid.uuid4(), start, 4, 0.45, True, 'second'), - (uuid.uuid4(), start, 4, 0.45, False, 'second'), - (uuid.uuid4(), start, 5, 0.50, True, 'second'), - (uuid.uuid4(), start, 5, 0.50, False, 'second'), - (uuid.uuid4(), start, 1, 0.56, True, 'first'), - (uuid.uuid4(), start, 1, 0.56, False, 'first'), - (uuid.uuid4(), start, 2, 0.61, True, 'first'), - (uuid.uuid4(), start, 2, 0.61, False, 'first'), - (uuid.uuid4(), start, 3, 0.66, True, 'first'), - (uuid.uuid4(), start, 3, 0.66, False, 'first'), - (uuid.uuid4(), start, 4, 0.71, True, 'first'), - (uuid.uuid4(), start, 4, 0.71, False, 'first'), - (uuid.uuid4(), start, 5, 0.76, True, 'first'), - (uuid.uuid4(), start, 5, 0.76, False, 'first'), + (uuid.uuid4(), START, 1, 0.30, False, 'second'), + (uuid.uuid4(), START, 2, 0.35, True, 'second'), + (uuid.uuid4(), START, 2, 0.35, False, 'second'), + (uuid.uuid4(), START, 3, 0.40, True, 'second'), + (uuid.uuid4(), START, 3, 0.40, False, 'second'), + (uuid.uuid4(), START, 4, 0.45, True, 'second'), + (uuid.uuid4(), START, 4, 0.45, False, 'second'), + (uuid.uuid4(), START, 5, 0.50, True, 'second'), + (uuid.uuid4(), START, 5, 0.50, False, 'second'), + (uuid.uuid4(), START, 1, 0.56, True, 'first'), + (uuid.uuid4(), START, 1, 0.56, False, 'first'), + (uuid.uuid4(), START, 2, 0.61, True, 'first'), + (uuid.uuid4(), START, 2, 0.61, False, 'first'), + (uuid.uuid4(), START, 3, 0.66, True, 'first'), + (uuid.uuid4(), START, 3, 0.66, False, 'first'), + (uuid.uuid4(), START, 4, 0.71, True, 'first'), + (uuid.uuid4(), START, 4, 0.71, False, 'first'), + (uuid.uuid4(), START, 5, 0.76, True, 'first'), + (uuid.uuid4(), START, 5, 0.76, False, 'first'), ] def upgrade(): conn = op.get_bind() + conn.execute(text(""" + update + letter_rates + set + end_date = :start + where + rate != 0.30 + """), start=START) + for id, start_date, sheet_count, rate, crown, post_class in NEW_RATES: - conn.execute(""" + conn.execute(text(""" INSERT INTO letter_rates (id, start_date, sheet_count, rate, crown, post_class) - VALUES ('{}', '{}', '{}', '{}', '{}', '{}') - """.format(id, start_date, sheet_count, rate, crown, post_class)) + VALUES (:id, :start_date, :sheet_count, :rate, :crown, :post_class) + """), id=id, start_date=start_date, sheet_count=sheet_count, rate=rate, crown=crown, post_class=post_class) def downgrade(): - pass + conn = op.get_bind() + conn.execute(text(""" + delete from + letter_rates + where + start_date = :start + """), start=START) + + conn.execute(text(""" + update + letter_rates + set + end_date = null + where + end_date = :start + """), start=START)