Skip to content

Commit

Permalink
Ticket 115 - Update LEI to meet character restrictions (#117)
Browse files Browse the repository at this point in the history
closes [#115
](#115)

---------

Co-authored-by: Nargis Sultani <[email protected]>
  • Loading branch information
nargis-sultani and Nargis Sultani authored Mar 15, 2024
1 parent 89d7df2 commit 236c19f
Show file tree
Hide file tree
Showing 7 changed files with 540 additions and 378 deletions.
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": "[email protected]",
"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

0 comments on commit 236c19f

Please sign in to comment.