Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -527,9 +527,14 @@ def create_provider_privileges(
'pk': {'S': f'{compact}#PROVIDER#{provider_id}'},
'sk': {'S': f'{compact}#PROVIDER'},
},
'UpdateExpression': 'ADD #privilegeJurisdictions :newJurisdictions',
'UpdateExpression': 'ADD #privilegeJurisdictions :newJurisdictions '
'SET dateOfUpdate = :dateOfUpdate, providerDateOfUpdate = :providerDateOfUpdate',
'ExpressionAttributeNames': {'#privilegeJurisdictions': 'privilegeJurisdictions'},
'ExpressionAttributeValues': {':newJurisdictions': {'SS': jurisdiction_postal_abbreviations}},
'ExpressionAttributeValues': {
':newJurisdictions': {'SS': jurisdiction_postal_abbreviations},
':dateOfUpdate': {'S': now.isoformat()},
':providerDateOfUpdate': {'S': now.isoformat()},
Comment thread
coderabbitai[bot] marked this conversation as resolved.
},
}
}
)
Expand Down Expand Up @@ -902,9 +907,13 @@ def end_military_affiliation(self, compact: str, provider_id: str) -> None:
'pk': {'S': provider_serialized_record['pk']},
'sk': {'S': provider_serialized_record['sk']},
},
'UpdateExpression': ('SET dateOfUpdate = :dateOfUpdate REMOVE militaryStatus, militaryStatusNote'),
'UpdateExpression': (
'SET dateOfUpdate = :dateOfUpdate, providerDateOfUpdate = :providerDateOfUpdate '
'REMOVE militaryStatus, militaryStatusNote'
),
'ExpressionAttributeValues': {
':dateOfUpdate': {'S': self.config.current_standard_datetime.isoformat()},
':providerDateOfUpdate': {'S': self.config.current_standard_datetime.isoformat()},
},
Comment thread
coderabbitai[bot] marked this conversation as resolved.
'ConditionExpression': 'attribute_exists(pk)',
}
Expand Down Expand Up @@ -1477,6 +1486,22 @@ def deactivate_privilege(
},
},
},
# Update dateOfUpdate and providerDateOfUpdate on the top-level provider record
{
'Update': {
'TableName': self.config.provider_table.name,
'Key': {
'pk': {'S': f'{compact}#PROVIDER#{provider_id}'},
'sk': {'S': f'{compact}#PROVIDER'},
},
'UpdateExpression': 'SET dateOfUpdate = :dateOfUpdate, '
'providerDateOfUpdate = :providerDateOfUpdate',
'ExpressionAttributeValues': {
':dateOfUpdate': {'S': self.config.current_standard_datetime.isoformat()},
':providerDateOfUpdate': {'S': self.config.current_standard_datetime.isoformat()},
},
Comment thread
coderabbitai[bot] marked this conversation as resolved.
},
},
# Create a history record, reflecting this change
{
'Put': {
Expand Down Expand Up @@ -1560,10 +1585,20 @@ def _generate_set_provider_encumbered_status_item(
# licenses and providers share the same encumbered status enum
provider_encumbered_status: LicenseEncumberedStatusEnum,
):
return self._generate_encumbered_status_update_item(
data=provider_data,
encumbered_status=provider_encumbered_status,
)
data_record = provider_data.serialize_to_database_record()
return {
'Update': {
'TableName': self.config.provider_table.name,
'Key': {'pk': {'S': data_record['pk']}, 'sk': {'S': data_record['sk']}},
'UpdateExpression': 'SET encumberedStatus = :status, dateOfUpdate = :dateOfUpdate, '
'providerDateOfUpdate = :providerDateOfUpdate',
'ExpressionAttributeValues': {
':status': {'S': provider_encumbered_status},
':dateOfUpdate': {'S': self.config.current_standard_datetime.isoformat()},
':providerDateOfUpdate': {'S': self.config.current_standard_datetime.isoformat()},
},
},
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

def _generate_put_transaction_item(self, item: dict):
return {'Put': {'TableName': self.config.provider_table.name, 'Item': TypeSerializer().serialize(item)['M']}}
Expand Down Expand Up @@ -2965,10 +3000,12 @@ def _get_provider_record_transaction_items_for_jurisdiction_with_no_known_licens
},
'UpdateExpression': 'SET '
'currentHomeJurisdiction = :currentHomeJurisdiction, '
'dateOfUpdate = :dateOfUpdate',
'dateOfUpdate = :dateOfUpdate, '
'providerDateOfUpdate = :providerDateOfUpdate',
'ExpressionAttributeValues': {
':currentHomeJurisdiction': {'S': selected_jurisdiction},
':dateOfUpdate': {'S': self.config.current_standard_datetime.isoformat()},
':providerDateOfUpdate': {'S': self.config.current_standard_datetime.isoformat()},
},
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -341,3 +341,31 @@ def test_no_notification_when_jurisdiction_config_not_found(self, mock_send_new_
# Verify no emails were sent
mock_send_old_state.assert_not_called()
mock_send_new_state.assert_not_called()

def test_provider_date_of_update_is_set_after_home_jurisdiction_change(self):
"""Test that providerDateOfUpdate is updated on the provider record after a home jurisdiction change
to a jurisdiction with no known license (Update expression path)."""
from cc_common.config import config

self.test_data_generator.put_default_provider_record_in_provider_table(
value_overrides={
'currentHomeJurisdiction': 'oh',
},
date_of_update_override='2020-01-01T00:00:00+00:00',
)

config.data_client.update_provider_home_state_jurisdiction(
compact=DEFAULT_COMPACT,
provider_id=DEFAULT_PROVIDER_ID,
selected_jurisdiction='tx',
)

provider_record = self._provider_table.get_item(
Key={
'pk': f'{DEFAULT_COMPACT}#PROVIDER#{DEFAULT_PROVIDER_ID}',
'sk': f'{DEFAULT_COMPACT}#PROVIDER',
}
)['Item']

self.assertEqual(DEFAULT_DATE_OF_UPDATE_TIMESTAMP, provider_record['dateOfUpdate'])
self.assertEqual(DEFAULT_DATE_OF_UPDATE_TIMESTAMP, provider_record['providerDateOfUpdate'])
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,12 @@ def _generate_test_body():
class TestPostPrivilegeEncumbrance(TstFunction):
"""Test suite for privilege encumbrance endpoints."""

def _when_testing_privilege_encumbrance(self, body_overrides: dict | None = None):
self.test_data_generator.put_default_provider_record_in_provider_table()
def _when_testing_privilege_encumbrance(
self, body_overrides: dict | None = None, date_of_update_override: str | None = None
):
self.test_data_generator.put_default_provider_record_in_provider_table(
date_of_update_override=date_of_update_override,
)
test_privilege_record = self.test_data_generator.put_default_privilege_record_in_provider_table()

body = _generate_test_body()
Expand Down Expand Up @@ -300,14 +304,39 @@ def test_privilege_encumbrance_handler_handles_event_publishing_failure(self, mo
encumbrance_handler(event, self.mock_context)
self.assertEqual('Event publishing failed', str(context.exception))

def test_privilege_encumbrance_updates_provider_date_of_update(self):
"""Test that encumbering a privilege updates providerDateOfUpdate on the provider record."""
from handlers.encumbrance import encumbrance_handler

event, test_privilege_record = self._when_testing_privilege_encumbrance(
date_of_update_override='2020-01-01T00:00:00+00:00',
)

response = encumbrance_handler(event, self.mock_context)
self.assertEqual(200, response['statusCode'], msg=json.loads(response['body']))

provider_record = self._provider_table.get_item(
Key={
'pk': f'{test_privilege_record.compact}#PROVIDER#{test_privilege_record.providerId}',
'sk': f'{test_privilege_record.compact}#PROVIDER',
}
)['Item']

self.assertEqual(DEFAULT_DATE_OF_UPDATE_TIMESTAMP, provider_record['dateOfUpdate'])
self.assertEqual(DEFAULT_DATE_OF_UPDATE_TIMESTAMP, provider_record['providerDateOfUpdate'])


@mock_aws
@patch('cc_common.config._Config.current_standard_datetime', datetime.fromisoformat(DEFAULT_DATE_OF_UPDATE_TIMESTAMP))
class TestPostLicenseEncumbrance(TstFunction):
"""Test suite for license encumbrance endpoints."""

def _when_testing_valid_license_encumbrance(self, body_overrides: dict | None = None):
self.test_data_generator.put_default_provider_record_in_provider_table()
def _when_testing_valid_license_encumbrance(
self, body_overrides: dict | None = None, date_of_update_override: str | None = None
):
self.test_data_generator.put_default_provider_record_in_provider_table(
date_of_update_override=date_of_update_override,
)
test_license_record = self.test_data_generator.put_default_license_record_in_provider_table()

body = _generate_test_body()
Expand Down Expand Up @@ -513,18 +542,44 @@ def test_license_encumbrance_handler_returns_400_if_encumbrance_date_in_future(s
response_body,
)

def test_license_encumbrance_updates_provider_date_of_update(self):
"""Test that encumbering a license updates providerDateOfUpdate on the provider record."""
from handlers.encumbrance import encumbrance_handler

event, test_license_record = self._when_testing_valid_license_encumbrance(
date_of_update_override='2020-01-01T00:00:00+00:00',
)

response = encumbrance_handler(event, self.mock_context)
self.assertEqual(200, response['statusCode'], msg=json.loads(response['body']))

provider_record = self._provider_table.get_item(
Key={
'pk': f'{test_license_record.compact}#PROVIDER#{test_license_record.providerId}',
'sk': f'{test_license_record.compact}#PROVIDER',
}
)['Item']

self.assertEqual(DEFAULT_DATE_OF_UPDATE_TIMESTAMP, provider_record['dateOfUpdate'])
self.assertEqual(DEFAULT_DATE_OF_UPDATE_TIMESTAMP, provider_record['providerDateOfUpdate'])


@mock_aws
@patch('cc_common.config._Config.current_standard_datetime', datetime.fromisoformat(DEFAULT_DATE_OF_UPDATE_TIMESTAMP))
class TestPatchPrivilegeEncumbranceLifting(TstFunction):
"""Test suite for privilege encumbrance lifting endpoints."""

def _setup_privilege_with_adverse_action(
self, adverse_action_overrides=None, privilege_overrides=None, license_overrides=None
self,
adverse_action_overrides=None,
privilege_overrides=None,
license_overrides=None,
date_of_update_override: str | None = None,
):
"""Helper method to set up a privilege with an adverse action for testing."""
self.test_data_generator.put_default_provider_record_in_provider_table(
value_overrides={'encumberedStatus': 'encumbered'}
value_overrides={'encumberedStatus': 'encumbered'},
date_of_update_override=date_of_update_override,
)
test_privilege_record = self.test_data_generator.put_default_privilege_record_in_provider_table(
value_overrides=privilege_overrides or {'encumberedStatus': 'encumbered'}
Expand Down Expand Up @@ -892,16 +947,41 @@ def test_privilege_encumbrance_lifting_handler_handles_event_publishing_failure(
encumbrance_handler(event, self.mock_context)
self.assertEqual('Event publishing failed', str(context.exception))

def test_should_update_provider_date_of_update_when_last_privilege_encumbrance_is_lifted(self):
Comment thread
jlkravitz marked this conversation as resolved.
"""Test that lifting the last privilege encumbrance updates providerDateOfUpdate on the provider record."""
from handlers.encumbrance import encumbrance_handler

privilege_record, adverse_action = self._setup_privilege_with_adverse_action(
date_of_update_override='2020-01-01T00:00:00+00:00',
)
event = self._generate_lift_encumbrance_event(privilege_record, adverse_action)

response = encumbrance_handler(event, self.mock_context)
self.assertEqual(200, response['statusCode'])

provider_record = self._provider_table.get_item(
Key={
'pk': f'{privilege_record.compact}#PROVIDER#{privilege_record.providerId}',
'sk': f'{privilege_record.compact}#PROVIDER',
}
)['Item']

self.assertEqual(DEFAULT_DATE_OF_UPDATE_TIMESTAMP, provider_record['dateOfUpdate'])
self.assertEqual(DEFAULT_DATE_OF_UPDATE_TIMESTAMP, provider_record['providerDateOfUpdate'])


@mock_aws
@patch('cc_common.config._Config.current_standard_datetime', datetime.fromisoformat(DEFAULT_DATE_OF_UPDATE_TIMESTAMP))
class TestPatchLicenseEncumbranceLifting(TstFunction):
"""Test suite for license encumbrance lifting endpoints."""

def _setup_license_with_adverse_action(self, adverse_action_overrides=None, license_overrides=None):
def _setup_license_with_adverse_action(
self, adverse_action_overrides=None, license_overrides=None, date_of_update_override: str | None = None
):
"""Helper method to set up a license with an adverse action for testing."""
self.test_data_generator.put_default_provider_record_in_provider_table(
value_overrides={'encumberedStatus': 'encumbered'}
value_overrides={'encumberedStatus': 'encumbered'},
date_of_update_override=date_of_update_override,
)
test_license_record = self.test_data_generator.put_default_license_record_in_provider_table(
value_overrides=license_overrides or {'encumberedStatus': 'encumbered'}
Expand Down Expand Up @@ -1177,6 +1257,28 @@ def test_should_not_update_provider_record_when_encumbered_privilege_exists(self
loaded_provider_data = provider_records.get_provider_record()
self.assertEqual(LicenseEncumberedStatusEnum.ENCUMBERED, loaded_provider_data.encumberedStatus)

def test_should_update_provider_date_of_update_when_last_license_encumbrance_is_lifted(self):
"""Test that lifting the last license encumbrance updates providerDateOfUpdate on the provider record."""
from handlers.encumbrance import encumbrance_handler

license_record, adverse_action = self._setup_license_with_adverse_action(
date_of_update_override='2020-01-01T00:00:00+00:00',
)
event = self._generate_lift_encumbrance_event(license_record, adverse_action)

response = encumbrance_handler(event, self.mock_context)
self.assertEqual(200, response['statusCode'])

provider_record = self._provider_table.get_item(
Key={
'pk': f'{license_record.compact}#PROVIDER#{license_record.providerId}',
'sk': f'{license_record.compact}#PROVIDER',
}
)['Item']

self.assertEqual(DEFAULT_DATE_OF_UPDATE_TIMESTAMP, provider_record['dateOfUpdate'])
self.assertEqual(DEFAULT_DATE_OF_UPDATE_TIMESTAMP, provider_record['providerDateOfUpdate'])

def test_should_return_access_denied_if_compact_admin_attempts_to_lift_license_encumbrance(self):
"""Verifying that only state admins are allowed to lift license encumbrances"""
from handlers.encumbrance import encumbrance_handler
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ def _assert_the_privilege_was_deactivated(self):
expected_provider['privileges'][0]['dateOfUpdate'] = '2024-11-08T23:59:59+00:00'
# remove activeSince Field, since the privilege in this case would not be active
del expected_provider['privileges'][0]['activeSince']
# deactivating a privilege now also updates the provider record's dateOfUpdate
expected_provider['dateOfUpdate'] = '2024-11-08T23:59:59+00:00'

body = json.loads(resp['body'])
self.assertEqual(expected_provider, body)
Expand Down Expand Up @@ -301,3 +303,37 @@ def test_privilege_purchase_message_handler_sends_email(self):
privilege_purchase_message_handler(purchase_event, self.mock_context)

mock_email_service_client.send_privilege_purchase_email.assert_called_once()

@patch('cc_common.config._Config.email_service_client')
def test_deactivate_privilege_updates_provider_date_of_update(self, mock_email_service_client): # noqa: ARG002 unused-argument
"""Test that deactivating a privilege updates dateOfUpdate and providerDateOfUpdate on the provider record."""
from common_test.test_constants import DEFAULT_DATE_OF_UPDATE_TIMESTAMP, DEFAULT_PROVIDER_ID
from handlers.privileges import deactivate_privilege

self._load_provider_data()

with open('../common/tests/resources/api-event.json') as f:
event = json.load(f)

event['requestContext']['authorizer']['claims']['scope'] = 'openid email aslp/admin'
event['requestContext']['authorizer']['claims']['sub'] = TEST_STAFF_USER_ID
event['pathParameters'] = {
'compact': 'aslp',
'providerId': DEFAULT_PROVIDER_ID,
'jurisdiction': 'ne',
'licenseType': 'slp',
}
event['body'] = json.dumps({'deactivationNote': TEST_NOTE})

resp = deactivate_privilege(event, self.mock_context)
self.assertEqual(200, resp['statusCode'])

provider_record = self._provider_table.get_item(
Key={
'pk': f'aslp#PROVIDER#{DEFAULT_PROVIDER_ID}',
'sk': 'aslp#PROVIDER',
}
)['Item']

self.assertEqual(DEFAULT_DATE_OF_UPDATE_TIMESTAMP, provider_record['dateOfUpdate'])
self.assertEqual(DEFAULT_DATE_OF_UPDATE_TIMESTAMP, provider_record['providerDateOfUpdate'])
Original file line number Diff line number Diff line change
Expand Up @@ -495,3 +495,28 @@ def test_patch_provider_military_affiliation_creates_provider_update_record(self
self.assertEqual(['militaryStatus', 'militaryStatusNote'], update_data.removedValues)
# Verify updated values is empty (no fields were updated, only removed)
self.assertEqual({}, update_data.updatedValues)

def test_patch_provider_military_affiliation_updates_provider_date_of_update(self):
"""Test that ending military affiliation updates providerDateOfUpdate on the provider record."""
from handlers.provider_users import provider_users_api_handler

test_provider = self.test_data_generator.put_default_provider_record_in_provider_table(
value_overrides={'militaryStatus': 'declined'},
date_of_update_override='2020-01-01T00:00:00+00:00',
)
self.test_data_generator.put_default_military_affiliation_in_provider_table()

event = self._generate_path_api_event(test_provider)

resp = provider_users_api_handler(event, self.mock_context)
self.assertEqual(200, resp['statusCode'])

provider_record = self._provider_table.get_item(
Key={
'pk': f'{TEST_COMPACT}#PROVIDER#{test_provider.providerId}',
'sk': f'{TEST_COMPACT}#PROVIDER',
}
)['Item']

self.assertEqual(DEFAULT_DATE_OF_UPDATE_TIMESTAMP, provider_record['dateOfUpdate'])
self.assertEqual(DEFAULT_DATE_OF_UPDATE_TIMESTAMP, provider_record['providerDateOfUpdate'])
Loading
Loading