diff --git a/app/models.py b/app/models.py index 6cbd0723fb..9fe3f01116 100644 --- a/app/models.py +++ b/app/models.py @@ -65,6 +65,8 @@ DELIVERY_STATUS_CALLBACK_TYPE = "delivery_status" COMPLAINT_CALLBACK_TYPE = "complaint" SERVICE_CALLBACK_TYPES = [DELIVERY_STATUS_CALLBACK_TYPE, COMPLAINT_CALLBACK_TYPE] +DEFAULT_SMS_ANNUAL_LIMIT = 25000 +DEFAULT_EMAIL_ANNUAL_LIMIT = 10000000 sms_sending_vehicles = db.Enum(*[vehicle.value for vehicle in SmsSendingVehicles], name="sms_sending_vehicles") @@ -565,6 +567,8 @@ class Service(BaseModel, Versioned): sensitive_service = db.Column(db.Boolean, nullable=True) organisation_id = db.Column(UUID(as_uuid=True), db.ForeignKey("organisation.id"), index=True, nullable=True) organisation = db.relationship("Organisation", backref="services") + email_annual_limit = db.Column(db.BigInteger, nullable=False, default=DEFAULT_EMAIL_ANNUAL_LIMIT) + sms_annual_limit = db.Column(db.BigInteger, nullable=False, default=DEFAULT_SMS_ANNUAL_LIMIT) email_branding = db.relationship( "EmailBranding", @@ -608,6 +612,8 @@ def from_json(cls, data): fields.pop("letter_contact_block", None) fields.pop("email_branding", None) fields["sms_daily_limit"] = fields.get("sms_daily_limit", 100) + fields["email_annual_limit"] = fields.get("email_annual_limit", DEFAULT_EMAIL_ANNUAL_LIMIT) + fields["sms_annual_limit"] = fields.get("sms_annual_limit", DEFAULT_SMS_ANNUAL_LIMIT) return cls(**fields) diff --git a/app/schemas.py b/app/schemas.py index b39f471776..4a87de9c0f 100644 --- a/app/schemas.py +++ b/app/schemas.py @@ -268,6 +268,8 @@ class ServiceSchema(BaseSchema, UUIDsAsStringsMixin): go_live_at = field_for(models.Service, "go_live_at", format="%Y-%m-%d %H:%M:%S.%f") organisation_notes = field_for(models.Service, "organisation_notes") sensitive_service = field_for(models.Service, "sensitive_service") + email_annual_limit = field_for(models.Service, "email_annual_limit") + sms_annual_limit = field_for(models.Service, "sms_annual_limit") def get_letter_logo_filename(self, service): return service.letter_branding and service.letter_branding.filename diff --git a/app/service/rest.py b/app/service/rest.py index e599d772a1..dac3b81f38 100644 --- a/app/service/rest.py +++ b/app/service/rest.py @@ -276,6 +276,8 @@ def update_service(service_id): service_name_changed = fetched_service.name != req_json.get("name", fetched_service.name) message_limit_changed = fetched_service.message_limit != req_json.get("message_limit", fetched_service.message_limit) sms_limit_changed = fetched_service.sms_daily_limit != req_json.get("sms_daily_limit", fetched_service.sms_daily_limit) + email_annual_limit_changed = fetched_service.email_annual_limit != req_json.get("email_annual_limit", fetched_service.email_annual_limit) + sms_annual_limit_changed = fetched_service.sms_annual_limit != req_json.get("sms_annual_limit", fetched_service.sms_annual_limit) current_data = dict(service_schema.dump(fetched_service).items()) current_data.update(request.get_json()) @@ -304,6 +306,12 @@ def update_service(service_id): redis_store.delete(over_sms_daily_limit_cache_key(service_id)) if not fetched_service.restricted: _warn_service_users_about_sms_limit_changed(service_id, current_data) + # if sms_annual_limit_changed: + # TODO: Delete cache for sms annual limit (if used) + # TODO: Warn users about SMS annual limit change + # if email_annual_limit_changed: + # TODO: Delete cache for email annual limit (if used) + # TODO: Warn users about email annual limit change if service_going_live: _warn_services_users_about_going_live(service_id, current_data) @@ -329,6 +337,14 @@ def update_service(service_id): return jsonify(data=service_schema.dump(fetched_service)), 200 +def _warn_service_users_about_annual_email_limit_changed(service_id, data): + pass + + +def _warn_service_users_about_annual_sms_limit_changed(service_id, data): + pass + + def _warn_service_users_about_message_limit_changed(service_id, data): send_notification_to_service_users( service_id=service_id, diff --git a/migrations/versions/0462_add_annual_limit_column.py b/migrations/versions/0462_add_annual_limit_column.py new file mode 100644 index 0000000000..e40368cfb2 --- /dev/null +++ b/migrations/versions/0462_add_annual_limit_column.py @@ -0,0 +1,58 @@ +""" +Revision ID: 0462_add_annual_limit_column +Revises: 0461_add_rtl_column_templates +Create Date: 2024-06-27 13:32:00 +""" +import os + +from app import config + +import sqlalchemy as sa +from alembic import op + +revision = "0462_add_annual_limit_column" +down_revision = "0461_add_rtl_column_templates" + +cfg = config.configs[os.environ["NOTIFY_ENVIRONMENT"]] # type: ignore +default_email_annual_limit = str(cfg.SERVICE_ANNUAL_EMAIL_LIMIT) +default_sms_annual_limit = str(cfg.SERVICE_ANNUAL_SMS_LIMIT) + + +def upgrade(): + # Add the new column to the templates table + op.add_column("services", sa.Column("email_annual_limit", sa.BigInteger(), nullable=True, server_default=default_email_annual_limit)) + op.add_column("services", sa.Column("sms_annual_limit", sa.BigInteger(), nullable=True, server_default=default_sms_annual_limit)) + # Add the new column to the templates_history table + op.add_column("services_history", sa.Column("email_annual_limit", sa.BigInteger(), nullable=True, server_default=default_email_annual_limit)) + op.add_column("services_history", sa.Column("sms_annual_limit", sa.BigInteger(), nullable=True, server_default=default_sms_annual_limit)) + + # Set the default values for existing services + op.execute(f""" + UPDATE services + SET email_annual_limit = {default_email_annual_limit}, + sms_annual_limit = {default_sms_annual_limit} + """ + ) + # Since sms / email annual limit have been statically set to 25k and 10mil respectively + # we can update all service history rows safely + op.execute(f""" + UPDATE services_history + SET email_annual_limit = {default_email_annual_limit}, + sms_annual_limit = {default_sms_annual_limit} + """ + ) + + op.alter_column("services", "email_annual_limit", nullable=False) + op.alter_column("services", "sms_annual_limit", nullable=False) + op.alter_column("services_history", "email_annual_limit", nullable=False) + op.alter_column("services_history", "sms_annual_limit", nullable=False) + + +def downgrade(): + # Remove the column from the services table + op.drop_column("services", "email_annual_limit") + op.drop_column("services", "sms_annual_limit") + + # Remove the column from the services_history table + op.drop_column("services_history", "email_annual_limit") + op.drop_column("services_history", "sms_annual_limit")