mirror of
https://github.com/GSA/notifications-api.git
synced 2026-08-17 04:58:50 -04:00
Add .cost() to notification model
In the V2 API, the GET response for an individual notification returns a 'cost' value, which we can get by multiplying the billable units by the per-message rate of the supplier who sent the message. Any notifications with billable units > 0 but without a corresponding `ProviderRates` entry will blow up the application, so make sure you've got one.
This commit is contained in:
@@ -5,7 +5,7 @@ from sqlalchemy.dialects.postgresql import (
|
|||||||
UUID,
|
UUID,
|
||||||
JSON
|
JSON
|
||||||
)
|
)
|
||||||
from sqlalchemy import UniqueConstraint, and_
|
from sqlalchemy import UniqueConstraint, and_, desc
|
||||||
from sqlalchemy.orm import foreign, remote
|
from sqlalchemy.orm import foreign, remote
|
||||||
from notifications_utils.recipients import (
|
from notifications_utils.recipients import (
|
||||||
validate_email_address,
|
validate_email_address,
|
||||||
@@ -538,6 +538,21 @@ class Notification(db.Model):
|
|||||||
if personalisation:
|
if personalisation:
|
||||||
self._personalisation = encryption.encrypt(personalisation)
|
self._personalisation = encryption.encrypt(personalisation)
|
||||||
|
|
||||||
|
def cost(self):
|
||||||
|
if not self.sent_by or self.billable_units == 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
provider_rate = db.session.query(
|
||||||
|
ProviderRates
|
||||||
|
).join(ProviderDetails).filter(
|
||||||
|
ProviderDetails.identifier == self.sent_by,
|
||||||
|
ProviderRates.provider_id == ProviderDetails.id
|
||||||
|
).order_by(
|
||||||
|
desc(ProviderRates.valid_from)
|
||||||
|
).limit(1).one()
|
||||||
|
|
||||||
|
return provider_rate.rate * self.billable_units
|
||||||
|
|
||||||
|
|
||||||
class NotificationHistory(db.Model):
|
class NotificationHistory(db.Model):
|
||||||
__tablename__ = 'notification_history'
|
__tablename__ = 'notification_history'
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ from app.dao.api_key_dao import save_model_api_key
|
|||||||
from app.dao.jobs_dao import dao_create_job
|
from app.dao.jobs_dao import dao_create_job
|
||||||
from app.dao.notifications_dao import dao_create_notification
|
from app.dao.notifications_dao import dao_create_notification
|
||||||
from app.dao.invited_user_dao import save_invited_user
|
from app.dao.invited_user_dao import save_invited_user
|
||||||
|
from app.dao.provider_rates_dao import create_provider_rates
|
||||||
from app.clients.sms.firetext import FiretextClient
|
from app.clients.sms.firetext import FiretextClient
|
||||||
|
|
||||||
|
|
||||||
@@ -409,7 +410,8 @@ def sample_notification(notify_db,
|
|||||||
create=True,
|
create=True,
|
||||||
personalisation=None,
|
personalisation=None,
|
||||||
api_key_id=None,
|
api_key_id=None,
|
||||||
key_type=KEY_TYPE_NORMAL):
|
key_type=KEY_TYPE_NORMAL,
|
||||||
|
sent_by=None):
|
||||||
if created_at is None:
|
if created_at is None:
|
||||||
created_at = datetime.utcnow()
|
created_at = datetime.utcnow()
|
||||||
if service is None:
|
if service is None:
|
||||||
@@ -441,7 +443,8 @@ def sample_notification(notify_db,
|
|||||||
'personalisation': personalisation,
|
'personalisation': personalisation,
|
||||||
'notification_type': template.template_type,
|
'notification_type': template.template_type,
|
||||||
'api_key_id': api_key_id,
|
'api_key_id': api_key_id,
|
||||||
'key_type': key_type
|
'key_type': key_type,
|
||||||
|
'sent_by': sent_by
|
||||||
}
|
}
|
||||||
if job_row_number:
|
if job_row_number:
|
||||||
data['job_row_number'] = job_row_number
|
data['job_row_number'] = job_row_number
|
||||||
@@ -841,3 +844,12 @@ def sample_service_whitelist(notify_db, notify_db_session, service=None, email_a
|
|||||||
notify_db.session.add(whitelisted_user)
|
notify_db.session.add(whitelisted_user)
|
||||||
notify_db.session.commit()
|
notify_db.session.commit()
|
||||||
return whitelisted_user
|
return whitelisted_user
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope='function')
|
||||||
|
def sample_provider_rate(notify_db, notify_db_session, valid_from=None, rate=None, provider_identifier=None):
|
||||||
|
create_provider_rates(
|
||||||
|
provider_identifier=provider_identifier if provider_identifier is not None else 'mmg',
|
||||||
|
valid_from=valid_from if valid_from is not None else datetime.utcnow(),
|
||||||
|
rate=rate if rate is not None else 1,
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import uuid
|
import pytest
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
import pytest
|
from tests.app.conftest import sample_notification, sample_provider_rate
|
||||||
|
|
||||||
from app import DATETIME_FORMAT
|
|
||||||
from app.models import (
|
from app.models import (
|
||||||
Notification,
|
Notification,
|
||||||
ServiceWhitelist,
|
ServiceWhitelist,
|
||||||
@@ -37,3 +35,29 @@ def test_should_build_service_whitelist_from_email_address(email_address):
|
|||||||
def test_should_not_build_service_whitelist_from_invalid_contact(recipient_type, contact):
|
def test_should_not_build_service_whitelist_from_invalid_contact(recipient_type, contact):
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
ServiceWhitelist.from_string('service_id', recipient_type, contact)
|
ServiceWhitelist.from_string('service_id', recipient_type, contact)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('provider, billable_units, expected_cost', [
|
||||||
|
('mmg', 1, 3.5),
|
||||||
|
('firetext', 2, 5),
|
||||||
|
('ses', 0, 0)
|
||||||
|
])
|
||||||
|
def test_calculate_cost_from_notification_billable_units(
|
||||||
|
notify_db, notify_db_session, provider, billable_units, expected_cost
|
||||||
|
):
|
||||||
|
provider_rates = [
|
||||||
|
('mmg', datetime(2016, 7, 1), 1.5),
|
||||||
|
('firetext', datetime(2016, 7, 1), 2.5),
|
||||||
|
('mmg', datetime.utcnow(), 3.5),
|
||||||
|
]
|
||||||
|
for provider_identifier, valid_from, rate in provider_rates:
|
||||||
|
sample_provider_rate(
|
||||||
|
notify_db,
|
||||||
|
notify_db_session,
|
||||||
|
provider_identifier=provider_identifier,
|
||||||
|
valid_from=valid_from,
|
||||||
|
rate=rate
|
||||||
|
)
|
||||||
|
|
||||||
|
notification = sample_notification(notify_db, notify_db_session, billable_units=billable_units, sent_by=provider)
|
||||||
|
assert notification.cost() == expected_cost
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import uuid
|
|||||||
import pytest
|
import pytest
|
||||||
from flask import json
|
from flask import json
|
||||||
from jsonschema import ValidationError
|
from jsonschema import ValidationError
|
||||||
from notifications_utils.recipients import InvalidPhoneError, InvalidEmailError
|
|
||||||
|
|
||||||
from app.v2.notifications.notification_schemas import post_sms_request, post_sms_response, post_email_request, \
|
from app.v2.notifications.notification_schemas import post_sms_request, post_sms_response, post_email_request, \
|
||||||
post_email_response
|
post_email_response
|
||||||
|
|||||||
Reference in New Issue
Block a user