Add client acceptance controls for AQMM and peer review workflow

This commit is contained in:
A R R R Associates
2026-07-06 18:37:34 +05:30
parent 561de117e4
commit aa32579084
10 changed files with 604 additions and 5 deletions
+58 -2
View File
@@ -12,6 +12,7 @@ from app.modules.clients.constants import (
CLIENT_TYPES,
ENGAGEMENT_MODES,
RISK_CATEGORIES,
CLIENT_ACCEPTANCE_STATUS,
)
from app.modules.clients.utils import GSTIN_RE, MOBILE_RE, PAN_RE, PIN_RE, TAN_RE, normalize_text, normalize_upper
@@ -49,6 +50,15 @@ class ClientBase(BaseModel):
risk_category: Optional[str] = None
onboarding_date: Optional[date] = None
closing_date: Optional[date] = None
acceptance_status: str = "pending_review"
acceptance_required: bool = True
independence_check_completed: bool = False
conflict_check_completed: bool = False
kyc_completed: bool = False
engagement_letter_required: bool = True
engagement_letter_received: bool = False
acceptance_review_notes: Optional[str] = None
acceptance_rejection_reason: Optional[str] = None
notes: Optional[str] = None
gst_applicable: bool = False
income_tax_applicable: bool = False
@@ -72,7 +82,7 @@ class ClientBase(BaseModel):
@field_validator(
"trade_name", "cin_llpin", "msme_no", "iec_code", "contact_person_name", "contact_person_designation",
"address_line_1", "address_line_2", "city", "state", "country", "client_category", "risk_category", "notes",
"address_line_1", "address_line_2", "city", "state", "country", "client_category", "risk_category", "acceptance_review_notes", "acceptance_rejection_reason", "notes",
mode="before",
)
@classmethod
@@ -97,6 +107,19 @@ class ClientBase(BaseModel):
raise ValueError("Invalid engagement mode.")
return value
@field_validator("acceptance_status", mode="before")
@classmethod
def clean_acceptance_status(cls, value):
value = normalize_text(value) or "pending_review"
return value.lower()
@field_validator("acceptance_status")
@classmethod
def validate_acceptance_status(cls, value):
if value not in CLIENT_ACCEPTANCE_STATUS:
raise ValueError("Invalid client acceptance status.")
return value
@field_validator("mobile", "alternate_mobile", mode="before")
@classmethod
def clean_mobile(cls, value):
@@ -193,6 +216,15 @@ class ClientUpdate(BaseModel):
risk_category: Optional[str] = None
onboarding_date: Optional[date] = None
closing_date: Optional[date] = None
acceptance_status: Optional[str] = None
acceptance_required: Optional[bool] = None
independence_check_completed: Optional[bool] = None
conflict_check_completed: Optional[bool] = None
kyc_completed: Optional[bool] = None
engagement_letter_required: Optional[bool] = None
engagement_letter_received: Optional[bool] = None
acceptance_review_notes: Optional[str] = None
acceptance_rejection_reason: Optional[str] = None
notes: Optional[str] = None
gst_applicable: Optional[bool] = None
income_tax_applicable: Optional[bool] = None
@@ -209,7 +241,7 @@ class ClientUpdate(BaseModel):
@field_validator(
"client_name", "trade_name", "cin_llpin", "msme_no", "iec_code", "contact_person_name", "contact_person_designation",
"address_line_1", "address_line_2", "city", "state", "country", "client_category", "risk_category", "notes",
"address_line_1", "address_line_2", "city", "state", "country", "client_category", "risk_category", "acceptance_review_notes", "acceptance_rejection_reason", "notes",
mode="before",
)
@classmethod
@@ -236,6 +268,21 @@ class ClientUpdate(BaseModel):
raise ValueError("Invalid engagement mode.")
return value
@field_validator("acceptance_status", mode="before")
@classmethod
def clean_acceptance_status(cls, value):
if value is None:
return None
value = normalize_text(value) or None
return value.lower() if value else None
@field_validator("acceptance_status")
@classmethod
def validate_acceptance_status(cls, value):
if value is not None and value not in CLIENT_ACCEPTANCE_STATUS:
raise ValueError("Invalid client acceptance status.")
return value
@field_validator("mobile", "alternate_mobile", mode="before")
@classmethod
def clean_mobile(cls, value):
@@ -323,6 +370,15 @@ class ClientOut(BaseModel):
risk_category: Optional[str] = None
onboarding_date: Optional[date] = None
closing_date: Optional[date] = None
acceptance_status: str = "pending_review"
acceptance_required: bool = True
independence_check_completed: bool = False
conflict_check_completed: bool = False
kyc_completed: bool = False
engagement_letter_required: bool = True
engagement_letter_received: bool = False
acceptance_review_notes: Optional[str] = None
acceptance_rejection_reason: Optional[str] = None
notes: Optional[str] = None
gst_applicable: bool
income_tax_applicable: bool