import datetime import re from dateutil.relativedelta import relativedelta from pydantic import ( BaseModel, computed_field, Field, ValidationInfo, model_validator, ConfigDict ) import pandas as pd class CustomAppFormUpload(BaseModel): model_config = ConfigDict(arbitrary_types_allowed=True) # application_summary_full_name: str | None = Field(None, alias="full_name") # application_summary_bank_name: str | None = Field(None, alias="bank_name") # application_summary_employer_name: str | None = Field(None, alias="employer_name") # application_summary_complete_address: str | None = Field(None, alias="complete_address") application_summary_full_name: str = Field(alias="full_name") application_summary_bank_name: str = Field(alias="bank_name") application_summary_employer_name: str = Field(alias="employer_name") application_summary_complete_address: str = Field(alias="complete_address") full_name_err_msgs: str | None = None bank_name_err_msgs: str | None = None employer_name_err_msgs: str | None = None complete_employee_address_err_msgs: str | None = None validation_policy_status_df: pd.DataFrame = pd.DataFrame( columns=["Policy", "Value", "Status", "Message"]) # is_incomplete: bool = False @model_validator(mode="after") def validate_full_name(self, info: ValidationInfo): """Validate provided applicant's full name""" try: err_msgs = [] full_name_val = self.application_summary_full_name if not full_name_val: err_msgs.append("Applicant's full name not present") full_name_val_len = 0 if full_name_val: full_name_val_len = len(full_name_val) if not full_name_val and not ( full_name_val_len >= 2 and full_name_val_len <= 61 ): err_msgs.append( "Full name must have a length of at least 2 & at most 61" ) if not full_name_val or len(full_name_val.strip().split(" ")) < 2: err_msgs.append( "Full name must consist of at least 2 words (first name + last name)" ) if err_msgs: self.full_name_err_msgs = ", ".join(err_msgs) else: self.full_name_err_msgs = None return self except Exception as e: # logger.exception(e, exc_info=True) # return None raise @model_validator(mode="after") def validate_bank_name(self, info: ValidationInfo): """Validate provided bank name""" try: err_msgs = [] bank_name_val = self.application_summary_bank_name if not bank_name_val: err_msgs.append("Bank name not present") bank_name_val_len = 0 if bank_name_val: bank_name_val_len = len(bank_name_val) if not bank_name_val and not ( bank_name_val_len >= 4 and bank_name_val_len <= 50 ): err_msgs.append( "Bank name must have a length of at least 4 & at most 50" ) if err_msgs: self.bank_name_err_msgs = ", ".join(err_msgs) else: self.bank_name_err_msgs = None return self except Exception as e: # logger.exception(e, exc_info=True) # return None raise @model_validator(mode="after") def validate_employer_name(self, info: ValidationInfo): """Validate provided employer name""" try: err_msgs = [] employer_name_val = self.application_summary_employer_name if not employer_name_val: err_msgs.append("Employer name not present") # # Allowed: letters, numbers, spaces, and common name punctuation # pattern = r"^[A-Za-z0-9&\-,.()'/@ ]{2,100}$" # if not re.match(pattern, employer_name_val): # err_msgs.append("Employer name contains invalid characters") if not re.search(r"[A-Za-z]", employer_name_val): err_msgs.append( "Employer name must contain at least one letter") if employer_name_val.strip() == "": err_msgs.append("Employer name cannot be only whitespace") self.employer_name_err_msgs = ", ".join( err_msgs) if err_msgs else None return self except Exception as e: # logger.exception(e, exc_info=True) # return None raise @model_validator(mode="after") def validate_complete_address(self, info: ValidationInfo): try: err_msgs = [] val = self.application_summary_complete_address if not val: err_msgs.append("Applicant's address not present") length = len(val) if val else 0 if not (10 <= length <= 300): err_msgs.append( "Applicant's complete address must have a length of at least 10 & at most 300" ) self.complete_employee_address_err_msgs = ( ", ".join(err_msgs) if err_msgs else None ) return self except Exception as e: # logger.exception(e, exc_info=True) # return None raise @computed_field @property def is_incomplete(self) -> bool: if any([ self.full_name_err_msgs, self.bank_name_err_msgs, self.employer_name_err_msgs, self.complete_employee_address_err_msgs, ]): return True return False