Skip to content

Commit b15421c

Browse files
authored
Merge pull request #2 from Ifechukwu001/feat/user-kyc
KYC and NOK Management
2 parents 651168f + 61a1fb9 commit b15421c

26 files changed

+591
-34
lines changed

src/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
__name__ = "df-wallet-user-service"
22
__display_name__ = "DF Wallet User Service API"
33
__description__ = "Developers Foundry Wallet System User Service RESTful API"
4-
__version__ = "1.1.0"
4+
__version__ = "1.2.0"
55
__author__ = "Ogidi Ifechukwu ([email protected])"

src/api/constants/activity_types.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ class ActivityTypes(TypedDict):
1717
LIST_WITHDRAW_ACCOUNTS: str
1818
FETCH_WITHDRAW_ACCOUNT: str
1919
DELETE_WITHDRAW_ACCOUNT: str
20+
FETCH_NOK: str
21+
UPDATE_NOK: str
22+
FETCH_KYC: str
23+
UPDATE_KYC: str
2024

2125

2226
ACTIVITY_TYPES: ActivityTypes = {
@@ -35,6 +39,10 @@ class ActivityTypes(TypedDict):
3539
"LIST_WITHDRAW_ACCOUNTS": "List withdraw accounts",
3640
"FETCH_WITHDRAW_ACCOUNT": "Get withdraw account",
3741
"DELETE_WITHDRAW_ACCOUNT": "Delete withdraw account",
42+
"FETCH_NOK": "Fetch Next Of Kin",
43+
"UPDATE_NOK": "Update Next Of Kin",
44+
"FETCH_KYC": "Fetch KYC Information",
45+
"UPDATE_KYC": "Update KYC Information",
3846
}
3947

4048
__all__ = ["ACTIVITY_TYPES"]

src/api/constants/messages.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,20 @@ class AccountMessages(TypedDict):
4040
UPDATED: str
4141

4242

43+
class NextOfKinMessages(TypedDict):
44+
FETCHED: str
45+
UPDATED: str
46+
47+
48+
class KYCInformationMessages(TypedDict):
49+
FETCHED: str
50+
UPDATED: str
51+
52+
4353
class CommonMessages(TypedDict):
4454
INTERNAL_SERVER_ERROR: str
4555
JWT_GENERATED: str
56+
VALIDATION_ERROR: str
4657

4758

4859
class Messages(TypedDict):
@@ -51,6 +62,8 @@ class Messages(TypedDict):
5162
OTP: OtpMessages
5263
USER: UserMessages
5364
ACCOUNT: AccountMessages
65+
NOK: NextOfKinMessages
66+
KYC: KYCInformationMessages
5467
COMMON: CommonMessages
5568

5669

@@ -104,13 +117,22 @@ class DynamicMessages(TypedDict):
104117
"SAVED": "Withdrawal account details saved succesfully",
105118
"UPDATED": "User Withdraw account updated successfully",
106119
},
120+
"NOK": {
121+
"FETCHED": "Next of Kin fetched successfully",
122+
"UPDATED": "Next of Kin updated successfully",
123+
},
124+
"KYC": {
125+
"FETCHED": "KYC Information fetched successfully",
126+
"UPDATED": "KYC Information updated successfully",
127+
},
107128
"COMMON": {
108129
"INTERNAL_SERVER_ERROR": "Something went wrong",
109130
"JWT_GENERATED": "JWT was generated",
131+
"VALIDATION_ERROR": "Validation errors",
110132
},
111133
}
112134

113-
DYNAMIC_MESSSAGES: DynamicMessages = {
135+
DYNAMIC_MESSAGES: DynamicMessages = {
114136
"COMMON": {
115137
"FETCHED_SUCCESS": lambda x: f"{x} fetched successfully",
116138
"FETCHED_FAILED": lambda x: f"{x} fetch failed",
@@ -122,4 +144,4 @@ class DynamicMessages(TypedDict):
122144
},
123145
}
124146

125-
__all__ = ["DYNAMIC_MESSSAGES", "MESSAGES"]
147+
__all__ = ["DYNAMIC_MESSAGES", "MESSAGES"]

src/api/controllers/UserController.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from src.utils.svcs import Service
55
from src.utils.logger import Logger
6+
from src.api.constants.messages import MESSAGES, DYNAMIC_MESSAGES
67
from src.api.services.UserService import UserService
78
from src.api.utils.response_format import error_response, success_response
89
from src.api.models.payload.requests.Pin import Pin
@@ -21,17 +22,17 @@ async def get_user(self, id: str) -> tuple:
2122
user = await self.user_service.get_user_information(id)
2223
if not user:
2324
return error_response(
24-
message="User does not exists", status_code=HTTPStatus.NOT_FOUND
25+
message=MESSAGES["USER"]["DOESNT_EXIST"],
26+
status_code=HTTPStatus.NOT_FOUND,
2527
)
2628
return success_response(
27-
message="Successfully retrieved user detail",
29+
message=DYNAMIC_MESSAGES["COMMON"]["FETCHED_SUCCESS"]("User"),
2830
data=user,
2931
status_code=HTTPStatus.OK,
3032
)
3133

3234
async def update_user(self, id: str, user_data: UpdateUserRequest) -> tuple:
33-
user_data._id = id
34-
updated_user = await self.user_service.update(user_data)
35+
updated_user = await self.user_service.update(id, user_data)
3536
if not updated_user["is_success"]:
3637
return error_response(
3738
message=updated_user["message"], status_code=HTTPStatus.BAD_REQUEST
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from http import HTTPStatus
2+
from typing import Annotated
3+
4+
from src.utils.svcs import Service
5+
from src.utils.logger import Logger
6+
from src.api.constants.messages import DYNAMIC_MESSAGES
7+
from src.api.utils.response_format import error_response, success_response
8+
from src.api.services.UserKYCService import UserKYCService
9+
from src.api.models.payload.requests.UserKYCRequest import UserKYCRequest
10+
11+
12+
@Service()
13+
class UserKYCController:
14+
def __init__(
15+
self,
16+
logger: Annotated[Logger, "UserKYCController"],
17+
kyc_service: UserKYCService,
18+
) -> None:
19+
self.logger = logger
20+
self.kyc_service = kyc_service
21+
22+
async def get_user_kyc(self, user_id: str) -> tuple:
23+
kyc = await self.kyc_service.fetch_details(user_id)
24+
return success_response(
25+
message=DYNAMIC_MESSAGES["COMMON"]["FETCHED_SUCCESS"]("KYC Information"),
26+
data=kyc,
27+
status_code=HTTPStatus.OK,
28+
)
29+
30+
async def update_user_kyc(self, user_id: str, kyc_details: UserKYCRequest) -> tuple:
31+
updated_kyc = await self.kyc_service.update_details(user_id, kyc_details)
32+
if not updated_kyc["is_success"]:
33+
return error_response(
34+
message=updated_kyc["message"], status_code=HTTPStatus.BAD_REQUEST
35+
)
36+
return success_response(
37+
message=updated_kyc["message"], status_code=HTTPStatus.OK
38+
)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from http import HTTPStatus
2+
from typing import Annotated
3+
4+
from src.utils.svcs import Service
5+
from src.utils.logger import Logger
6+
from src.api.constants.messages import DYNAMIC_MESSAGES
7+
from src.api.utils.response_format import error_response, success_response
8+
from src.api.services.UserNOKService import UserNOKService
9+
from src.api.models.payload.requests.UserNOKRequest import UserNOKRequest
10+
11+
12+
@Service()
13+
class UserNOKController:
14+
def __init__(
15+
self,
16+
logger: Annotated[Logger, "UserNOKController"],
17+
nok_service: UserNOKService,
18+
) -> None:
19+
self.logger = logger
20+
self.nok_service = nok_service
21+
22+
async def get_user_nok(self, user_id: str) -> tuple:
23+
nok = await self.nok_service.fetch_details(user_id)
24+
return success_response(
25+
message=DYNAMIC_MESSAGES["COMMON"]["FETCHED_SUCCESS"]("Next of Kin"),
26+
data=nok,
27+
status_code=HTTPStatus.OK,
28+
)
29+
30+
async def update_user_nok(self, user_id: str, nok_details: UserNOKRequest) -> tuple:
31+
updated_nok = await self.nok_service.update_details(user_id, nok_details)
32+
if not updated_nok["is_success"]:
33+
return error_response(
34+
message=updated_nok["message"], status_code=HTTPStatus.BAD_REQUEST
35+
)
36+
return success_response(
37+
message=updated_nok["message"], status_code=HTTPStatus.OK
38+
)

src/api/models/payload/requests/UpdateUserRequest.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55

66
class UpdateUserRequest(BaseModel):
7-
_id: str
87
first_name: str | None = None
98
last_name: str | None = None
109
address: str | None = None
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from pydantic import BaseModel
2+
3+
from src.api.enums.DocumentType import DocumentType
4+
5+
6+
class UserKYCRequest(BaseModel):
7+
bvn: str | None = None
8+
document_type: DocumentType | None = None
9+
document_id: str | None = None
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from pydantic import EmailStr, BaseModel
2+
3+
from src.api.enums.NextOfKinRelationship import NextOfKinRelationship
4+
5+
6+
class UserNOKRequest(BaseModel):
7+
first_name: str | None = None
8+
last_name: str | None = None
9+
address: str | None = None
10+
phone_number: str | None = None
11+
email: EmailStr | None = None
12+
relationship: NextOfKinRelationship | None = None
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from ninja import ModelSchema
2+
3+
from src.api.models.postgres import UserKYCInformation
4+
5+
6+
class UserKYCResponse(ModelSchema):
7+
class Meta:
8+
model = UserKYCInformation
9+
fields = (
10+
"id",
11+
"bvn",
12+
"is_bvn_verified",
13+
"document_type",
14+
"document_id",
15+
"is_document_verified",
16+
)
17+
fields_optional = (
18+
"bvn",
19+
"is_bvn_verified",
20+
"document_type",
21+
"document_id",
22+
"is_document_verified",
23+
)

0 commit comments

Comments
 (0)