Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
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
@@ -1,26 +1,15 @@
# ruff: noqa: N801, N815, ARG002 invalid-name unused-kwargs
from marshmallow import Schema, validates_schema
from marshmallow.fields import Boolean, Email, List, Nested, String
from marshmallow.validate import Length, OneOf
from marshmallow.validate import Length

from cc_common.config import config
from cc_common.data_model.schema.base_record import ForgivingSchema
from cc_common.data_model.schema.compact.common import (
COMPACT_TYPE,
ConfiguredStateSchema,
validate_no_duplicates_in_configured_states,
)


class CompactOptionsResponseSchema(ForgivingSchema):
"""Used to enforce which fields are returned in compact objects for the GET /purchase/privileges/options endpoint"""

compactAbbr = String(required=True, allow_none=False, validate=OneOf(config.compacts))
compactName = String(required=True, allow_none=False)
type = String(required=True, allow_none=False, validate=OneOf([COMPACT_TYPE]))
isSandbox = Boolean(required=True, allow_none=False)


class CompactConfigurationResponseSchema(ForgivingSchema):
"""Schema for API responses from GET /v1/compacts/{compact}"""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,10 @@
from marshmallow.validate import OneOf

from cc_common.config import config
from cc_common.data_model.schema.common import CCEnum

COMPACT_TYPE = 'compact'


class PaymentProcessorType(CCEnum):
AUTHORIZE_DOT_NET_TYPE = 'authorize.net'


class ConfiguredStateSchema(Schema):
"""
Schema for individual configured state entries in a compact configuration.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,64 +1,9 @@
# ruff: noqa: N801, N802, N815, ARG002 invalid-name unused-kwargs

from collections import UserDict

from cc_common.data_model.schema.common import CCDataClass
from cc_common.data_model.schema.jurisdiction.record import JurisdictionRecordSchema


class JurisdictionJurisprudenceRequirements(UserDict):
"""
Jurisdiction jurisprudence requirements data model. Used to access variables without needing to know
the underlying key structure.
"""

@property
def required(self) -> bool:
return self['required']


class Jurisdiction(UserDict):
"""
Jurisdiction configuration data model. Used to access variables without needing to know
the underlying key structure.

Deprecated: This is a legacy class maintained for backward compatibility. For new code, prefer using
JurisdictionConfigurationData instead.
"""

@property
def jurisdiction_name(self) -> str:
return self['jurisdictionName']

@property
def postal_abbreviation(self) -> str:
return self['postalAbbreviation']

@property
def compact(self) -> str:
return self['compact']

@property
def jurisprudence_requirements(self) -> JurisdictionJurisprudenceRequirements:
return JurisdictionJurisprudenceRequirements(self.data['jurisprudenceRequirements'])

@property
def jurisdiction_operations_team_emails(self) -> list[str] | None:
return self.get('jurisdictionOperationsTeamEmails')

@property
def jurisdiction_adverse_actions_notification_emails(self) -> list[str] | None:
return self.get('jurisdictionAdverseActionsNotificationEmails')

@property
def jurisdiction_summary_report_notification_emails(self) -> list[str] | None:
return self.get('jurisdictionSummaryReportNotificationEmails')

@property
def licensee_registration_enabled(self):
return self.get('licenseeRegistrationEnabled', False)


# data class-based implementation
class JurisdictionConfigurationData(CCDataClass):
"""
Expand All @@ -84,10 +29,6 @@ def postalAbbreviation(self) -> str:
def compact(self) -> str:
return self._data['compact']

@property
def jurisprudenceRequirements(self) -> dict:
return self._data['jurisprudenceRequirements']

@property
def jurisdictionOperationsTeamEmails(self) -> list[str]:
return self._data.get('jurisdictionOperationsTeamEmails', [])
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,10 @@
# ruff: noqa: N801, N802, N815, ARG002 invalid-name unused-kwargs
from marshmallow import Schema
from marshmallow.fields import Boolean, Email, List, Nested, String
from marshmallow.fields import Boolean, Email, List, String
from marshmallow.validate import Length, OneOf

from cc_common.config import config
from cc_common.data_model.schema.base_record import ForgivingSchema
from cc_common.data_model.schema.jurisdiction.common import JURISDICTION_TYPE


class JurisdictionJurisprudenceRequirementsResponseSchema(ForgivingSchema):
required = Boolean(required=True, allow_none=False)
linkToDocumentation = String(required=False, allow_none=True)


class JurisdictionOptionsResponseSchema(ForgivingSchema):
"""
Used to enforce which fields are returned in jurisdiction objects for the
GET /purchase/privileges/options endpoint
"""

type = String(required=True, allow_none=False, validate=OneOf([JURISDICTION_TYPE]))
jurisdictionName = String(required=True, allow_none=False)
postalAbbreviation = String(required=True, allow_none=False, validate=OneOf(config.jurisdictions))
compact = String(required=True, allow_none=False, validate=OneOf(config.compacts))
jurisprudenceRequirements = Nested(
JurisdictionJurisprudenceRequirementsResponseSchema(), required=True, allow_none=False
)


class CompactJurisdictionsStaffUsersResponseSchema(ForgivingSchema):
Expand Down Expand Up @@ -70,9 +49,6 @@ class CompactJurisdictionConfigurationResponseSchema(ForgivingSchema):
required=True,
allow_none=False,
)
jurisprudenceRequirements = Nested(
JurisdictionJurisprudenceRequirementsResponseSchema(), required=True, allow_none=False
)
licenseeRegistrationEnabled = Boolean(required=True, allow_none=False)


Expand All @@ -83,9 +59,6 @@ class PutCompactJurisdictionConfigurationRequestSchema(Schema):
"""

licenseeRegistrationEnabled = Boolean(required=True, allow_none=False)
jurisprudenceRequirements = Nested(
JurisdictionJurisprudenceRequirementsResponseSchema(), required=True, allow_none=False
)
jurisdictionOperationsTeamEmails = List(
Email(required=True, allow_none=False), required=True, allow_none=False, validate=Length(min=1)
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
# ruff: noqa: N801, N815, ARG002 invalid-name unused-kwargs
from marshmallow import Schema, pre_dump
from marshmallow.fields import Boolean, Email, List, Nested, String
from marshmallow import pre_dump
from marshmallow.fields import Boolean, Email, List, String
from marshmallow.validate import Length, OneOf

from cc_common.config import config
from cc_common.data_model.schema.base_record import BaseRecordSchema
from cc_common.data_model.schema.jurisdiction.common import JURISDICTION_TYPE


class JurisdictionJurisprudenceRequirementsRecordSchema(Schema):
required = Boolean(required=True, allow_none=False)
linkToDocumentation = String(required=False, allow_none=True)


@BaseRecordSchema.register_schema(JURISDICTION_TYPE)
class JurisdictionRecordSchema(BaseRecordSchema):
"""Schema for the root jurisdiction configuration records"""
Expand All @@ -35,9 +30,6 @@ class JurisdictionRecordSchema(BaseRecordSchema):
allow_none=False,
)
licenseeRegistrationEnabled = Boolean(required=True, allow_none=False)
jurisprudenceRequirements = Nested(
JurisdictionJurisprudenceRequirementsRecordSchema(), required=True, allow_none=False
)

# Generated fields
pk = String(required=True, allow_none=False)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# ruff: noqa: F403, F405 star import of test constants file
import json
from datetime import date, datetime
from decimal import Decimal

from boto3.dynamodb.conditions import Key
from cc_common.data_model.provider_record_util import ProviderUserRecords
Expand Down Expand Up @@ -532,22 +531,11 @@ def generate_default_compact_configuration(value_overrides: dict | None = None)
default_compact_config = {
'compactAbbr': DEFAULT_COMPACT,
'compactName': 'Cosmetology',
'compactCommissionFee': {
'feeAmount': Decimal('10.00'),
'feeType': 'FLAT_RATE',
},
'compactOperationsTeamEmails': ['ops@example.com'],
'compactAdverseActionsNotificationEmails': ['adverse@example.com'],
'compactSummaryReportNotificationEmails': ['summary@example.com'],
'licenseeRegistrationEnabled': True,
'configuredStates': [],
'transactionFeeConfiguration': {
'licenseeCharges': {
'active': True,
'chargeAmount': Decimal('10.00'),
'chargeType': 'FLAT_FEE_PER_PRIVILEGE',
},
},
}
if value_overrides:
default_compact_config.update(value_overrides)
Expand Down Expand Up @@ -582,10 +570,6 @@ def generate_default_jurisdiction_configuration(
'compact': 'cosm',
'postalAbbreviation': 'ky',
'jurisdictionName': 'Kentucky',
'jurisprudenceRequirements': {
'required': True,
'linkToDocumentation': 'https://example.com/jurisprudence',
},
'jurisdictionOperationsTeamEmails': ['state-ops@example.com'],
'jurisdictionAdverseActionsNotificationEmails': ['state-adverse@example.com'],
'jurisdictionSummaryReportNotificationEmails': ['state-summary@example.com'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,5 @@
"jurisdictionAdverseActionsNotificationEmails": ["some-adverse-actions-notification-team@test.com"],
"jurisdictionSummaryReportNotificationEmails": ["some-summary-report-notification-team@test.com"],
"licenseeRegistrationEnabled": true,
"jurisprudenceRequirements": {
"required": true
},
"dateOfUpdate": "2024-10-04T12:34:56+00:00"
}
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ def _make_license_data(self, *, license_status='active', date_of_expiration='210
'homeAddressCity': 'Columbus',
'homeAddressState': 'OH',
'homeAddressPostalCode': '43215',
'licenseNumber': 'LIC12345'
'licenseNumber': 'LIC12345',
}

def test_expired_license_status_corrected_to_inactive(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,6 @@ def _when_testing_put_jurisdiction_configuration(self, create_compact=True):
'jurisdictionAdverseActionsNotificationEmails': jurisdiction_config.jurisdictionAdverseActionsNotificationEmails,
'jurisdictionSummaryReportNotificationEmails': jurisdiction_config.jurisdictionSummaryReportNotificationEmails,
'licenseeRegistrationEnabled': jurisdiction_config.licenseeRegistrationEnabled,
'jurisprudenceRequirements': jurisdiction_config.jurisprudenceRequirements,
},
cls=ResponseEncoder,
)
Expand Down Expand Up @@ -713,7 +712,6 @@ def test_get_jurisdiction_configuration_returns_empty_jurisdiction_configuration
'jurisdictionName': 'Kentucky',
'jurisdictionOperationsTeamEmails': [],
'jurisdictionSummaryReportNotificationEmails': [],
'jurisprudenceRequirements': {'linkToDocumentation': None, 'required': False},
'licenseeRegistrationEnabled': False,
'postalAbbreviation': 'ky',
},
Expand Down Expand Up @@ -745,7 +743,6 @@ def test_get_jurisdiction_configuration_returns_configuration_if_exists(self):
{
'compact': test_jurisdiction_config.compact,
'jurisdictionName': test_jurisdiction_config.jurisdictionName,
'jurisprudenceRequirements': test_jurisdiction_config.jurisprudenceRequirements,
'postalAbbreviation': test_jurisdiction_config.postalAbbreviation,
'jurisdictionOperationsTeamEmails': test_jurisdiction_config.jurisdictionOperationsTeamEmails,
'jurisdictionAdverseActionsNotificationEmails': test_jurisdiction_config.jurisdictionAdverseActionsNotificationEmails,
Expand Down Expand Up @@ -801,37 +798,6 @@ def test_put_jurisdiction_configuration_stores_jurisdiction_configuration(self):

self.assertEqual(jurisdiction_config.to_dict(), stored_jurisdiction_data.to_dict())

def test_put_jurisdiction_configuration_accepts_null_values_for_optional_fields(self):
"""Test putting a jurisdiction configuration accepts null values for optional fields."""
from cc_common.data_model.schema.jurisdiction import JurisdictionConfigurationData
from cc_common.utils import ResponseEncoder
from handlers.compact_configuration import compact_configuration_api_handler

event, jurisdiction_config = self._when_testing_put_jurisdiction_configuration()

# Modify the body to include null values for optional fields
body = json.loads(event['body'])

# Set linkToDocumentation to null
body['jurisprudenceRequirements'] = {'required': True, 'linkToDocumentation': None}

event['body'] = json.dumps(body, cls=ResponseEncoder)

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

# Verify the configuration was stored with null values
serialized_jurisdiction_config = jurisdiction_config.serialize_to_database_record()
db_response = self.config.compact_configuration_table.get_item(
Key={'pk': serialized_jurisdiction_config['pk'], 'sk': serialized_jurisdiction_config['sk']}
)

stored_jurisdiction_data = JurisdictionConfigurationData.from_database_record(db_response['Item'])
stored_dict = stored_jurisdiction_data.to_dict()

# Verify the optional fields have null values
self.assertIsNone(stored_dict['jurisprudenceRequirements']['linkToDocumentation'])

def test_put_jurisdiction_configuration_rejects_disabling_licensee_registration(self):
"""Test that a jurisdiction configuration update is rejected if trying to disable licensee registration after enabling it."""
from handlers.compact_configuration import compact_configuration_api_handler
Expand Down
Loading
Loading