Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ticket 115 - Update LEI to meet character restrictions #117

Merged
merged 2 commits into from
Mar 15, 2024
Merged
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
778 changes: 450 additions & 328 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ packages = [{ include = "regtech-user-fi-management" }]

[tool.poetry.dependencies]
python = "^3.11"
fastapi = "^0.104.1"
fastapi = "^0.109.1"
uvicorn = "^0.22.0"
python-dotenv = "^1.0.0"
python-keycloak = "^3.0.0"
Expand Down
2 changes: 1 addition & 1 deletion src/entities/models/dao.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class FinancialInstitutionDao(AuditMixin, Base):
__tablename__ = "financial_institutions"
version: Mapped[int] = mapped_column(nullable=False, default=0)
__mapper_args__ = {"version_id_col": version, "version_id_generator": False}
lei: Mapped[str] = mapped_column(unique=True, index=True, primary_key=True)
lei: Mapped[str] = mapped_column(String(20), unique=True, index=True, primary_key=True)
name: Mapped[str] = mapped_column(index=True)
is_active: Mapped[bool] = mapped_column(index=True)
domains: Mapped[List["FinancialInstitutionDomainDao"]] = relationship(
Expand Down
7 changes: 7 additions & 0 deletions src/entities/models/dto.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@ def validate_fi(self) -> "FinancialInstitutionDto":
raise ValueError(
f"Invalid tax_id {self.tax_id}. FinancialInstitution tax_id must conform to XX-XXXXXXX pattern."
)
if self.lei:
match = re.match(r"^([a-zA-Z0-9]{20})", self.lei)
if not match:
raise ValueError(
f"Invalid lei {self.lei}. FinancialInstitution lei must be 20 characaters long and contain only "
"letters and numbers."
)
return self

class Config:
Expand Down
2 changes: 1 addition & 1 deletion tests/api/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def get_institutions_mock(mocker: MockerFixture, authed_user_mock: Mock) -> Mock
mock.return_value = [
FinancialInstitutionDao(
name="Test Bank 123",
lei="TESTBANK123",
lei="TESTBANK123000000000",
is_active=True,
domains=[FinancialInstitutionDomainDao(domain="test.bank", lei="TESTBANK123")],
tax_id="12-3456789",
Expand Down
75 changes: 54 additions & 21 deletions tests/api/routers/test_institutions_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def test_invalid_tax_id(self, mocker: MockerFixture, app_fixture: FastAPI, authe
"/v1/institutions/",
json={
"name": "testName",
"lei": "testLei",
"lei": "TESTBANK123000000000",
"is_active": True,
"tax_id": "123456789",
"rssd_id": 12344,
Expand All @@ -69,13 +69,46 @@ def test_invalid_tax_id(self, mocker: MockerFixture, app_fixture: FastAPI, authe
)
assert res.status_code == 422

def test_invalid_lei(self, mocker: MockerFixture, app_fixture: FastAPI, authed_user_mock: Mock):
client = TestClient(app_fixture)
res = client.post(
"/v1/institutions/",
json={
"name": "testName",
"lei": "test_Lei",
"is_active": True,
"tax_id": "12-3456789",
"rssd_id": 12344,
"primary_federal_regulator_id": "FRI2",
"hmda_institution_type_id": "HIT2",
"sbl_institution_type_ids": ["SIT2"],
"hq_address_street_1": "Test Address Street 1",
"hq_address_street_2": "",
"hq_address_city": "Test City 1",
"hq_address_state_code": "VA",
"hq_address_zip": "00000",
"parent_lei": "PARENTTESTBANK123",
"parent_legal_name": "PARENT TEST BANK 123",
"parent_rssd_id": 12345,
"top_holder_lei": "TOPHOLDERLEI123",
"top_holder_legal_name": "TOP HOLDER LEI 123",
"top_holder_rssd_id": 123456,
},
)
assert (
res.json()["detail"][0]["msg"]
== "Value error, Invalid lei test_Lei. FinancialInstitution lei must be 20 characaters long and contain "
"only letters and numbers."
)
assert res.status_code == 422

def test_create_institution_authed(self, mocker: MockerFixture, app_fixture: FastAPI, authed_user_mock: Mock):
upsert_institution_mock = mocker.patch("entities.repos.institutions_repo.upsert_institution")
upsert_institution_mock.return_value = FinancialInstitutionDao(
name="testName",
lei="testLei",
lei="testLEI0000000000000",
is_active=True,
domains=[FinancialInstitutionDomainDao(domain="test.bank", lei="TESTBANK123")],
domains=[FinancialInstitutionDomainDao(domain="test.bank", lei="testLEI0000000000000")],
tax_id="12-3456789",
rssd_id=1234,
primary_federal_regulator_id="FRI2",
Expand Down Expand Up @@ -103,7 +136,7 @@ def test_create_institution_authed(self, mocker: MockerFixture, app_fixture: Fas
"/v1/institutions/",
json={
"name": "testName",
"lei": "testLei",
"lei": "testLEI0000000000000",
"is_active": True,
"tax_id": "12-3456789",
"rssd_id": 12344,
Expand Down Expand Up @@ -132,7 +165,7 @@ def test_create_institution_only_required_fields(
upsert_institution_mock = mocker.patch("entities.repos.institutions_repo.upsert_institution")
upsert_institution_mock.return_value = FinancialInstitutionDao(
name="testName",
lei="testLei",
lei="testLEI0000000000000",
is_active=True,
hq_address_street_1="Test Address Street 1",
hq_address_city="Test City 1",
Expand All @@ -147,7 +180,7 @@ def test_create_institution_only_required_fields(
"/v1/institutions/",
json={
"name": "testName",
"lei": "testLei",
"lei": "testLEI0000000000000",
"is_active": True,
"hq_address_street_1": "Test Address Street 1",
"hq_address_city": "Test City 1",
Expand All @@ -167,7 +200,7 @@ def test_create_institution_missing_required_field(
"/v1/institutions/",
json={
"name": "testName",
"lei": "testLei",
"lei": "testLEI0000000000000",
"hq_address_street_1": "Test Address Street 1",
"hq_address_city": "Test City 1",
"hq_address_state_code": "VA",
Expand All @@ -183,7 +216,7 @@ def test_create_institution_missing_sbl_type_free_form(
"/v1/institutions/",
json={
"name": "testName",
"lei": "testLei",
"lei": "testLEI0000000000000",
"is_active": True,
"hq_address_street_1": "Test Address Street 1",
"hq_address_city": "Test City 1",
Expand Down Expand Up @@ -211,7 +244,7 @@ def test_create_institution_authed_no_permission(self, app_fixture: FastAPI, aut
"/v1/institutions/",
json={
"name": "testName",
"lei": "testLei",
"lei": "testLEI0000000000000",
"is_active": True,
"tax_id": "12-3456789",
"rssd_id": 12344,
Expand Down Expand Up @@ -243,9 +276,9 @@ def test_get_institution_authed(self, mocker: MockerFixture, app_fixture: FastAP
get_institution_mock = mocker.patch("entities.repos.institutions_repo.get_institution")
get_institution_mock.return_value = FinancialInstitutionDao(
name="Test Bank 123",
lei="TESTBANK123",
lei="TESTBANK123000000000",
is_active=True,
domains=[FinancialInstitutionDomainDao(domain="test.bank", lei="TESTBANK123")],
domains=[FinancialInstitutionDomainDao(domain="test.bank", lei="TESTBANK123000000000")],
tax_id="12-3456789",
rssd_id=1234,
primary_federal_regulator_id="FRI1",
Expand Down Expand Up @@ -340,9 +373,9 @@ def test_get_associated_institutions(
get_institutions_mock.return_value = [
FinancialInstitutionDao(
name="Test Bank 123",
lei="TESTBANK123",
lei="TESTBANK123000000000",
is_active=True,
domains=[FinancialInstitutionDomainDao(domain="test123.bank", lei="TESTBANK123")],
domains=[FinancialInstitutionDomainDao(domain="test123.bank", lei="TESTBANK123000000000")],
tax_id="12-3456789",
rssd_id=1234,
primary_federal_regulator_id="FRI1",
Expand All @@ -365,9 +398,9 @@ def test_get_associated_institutions(
),
FinancialInstitutionDao(
name="Test Bank 234",
lei="TESTBANK234",
lei="TESTBANK234000000000",
is_active=True,
domains=[FinancialInstitutionDomainDao(domain="test234.bank", lei="TESTBANK234")],
domains=[FinancialInstitutionDomainDao(domain="test234.bank", lei="TESTBANK234000000000")],
tax_id="12-3456879",
rssd_id=6879,
primary_federal_regulator_id="FRI1",
Expand All @@ -394,7 +427,7 @@ def test_get_associated_institutions(
"preferred_username": "test_user",
"email": "test@test234.bank",
"sub": "testuser123",
"institutions": ["/TESTBANK123", "/TESTBANK234"],
"institutions": ["/TESTBANK123000000000", "/TESTBANK234000000000"],
}
auth_mock.return_value = (
AuthCredentials(["authenticated"]),
Expand All @@ -403,10 +436,10 @@ def test_get_associated_institutions(
client = TestClient(app_fixture)
res = client.get("/v1/institutions/associated")
assert res.status_code == 200
get_institutions_mock.assert_called_once_with(ANY, ["TESTBANK123", "TESTBANK234"])
get_institutions_mock.assert_called_once_with(ANY, ["TESTBANK123000000000", "TESTBANK234000000000"])
data = res.json()
inst1 = next(filter(lambda inst: inst["lei"] == "TESTBANK123", data))
inst2 = next(filter(lambda inst: inst["lei"] == "TESTBANK234", data))
inst1 = next(filter(lambda inst: inst["lei"] == "TESTBANK123000000000", data))
inst2 = next(filter(lambda inst: inst["lei"] == "TESTBANK234000000000", data))
assert inst1["approved"] is False
assert inst2["approved"] is True

Expand Down Expand Up @@ -466,9 +499,9 @@ def test_get_sbl_types(self, mocker: MockerFixture, app_fixture: FastAPI, authed
get_institution_mock.return_value = FinancialInstitutionDao(
version=inst_version,
name="Test Bank 123",
lei="TESTBANK123",
lei="TESTBANK123000000000",
is_active=True,
domains=[FinancialInstitutionDomainDao(domain="test.bank", lei="TESTBANK123")],
domains=[FinancialInstitutionDomainDao(domain="test.bank", lei="TESTBANK123000000000")],
tax_id="12-3456789",
rssd_id=1234,
primary_federal_regulator_id="FRI1",
Expand Down
Loading
Loading