""" Data models for request and response validation. """ from dataclasses import dataclass, field, asdict from typing import List, Dict, Any, Optional, TypeVar, Type, cast from datetime import datetime import json T = TypeVar('T', bound='BaseModel') class BaseModel: """Base model with serialization capabilities.""" def __init__(self): self.type_field = None def to_dict(self) -> Dict[str, Any]: """Convert model to dictionary.""" result = {k: v for k, v in asdict(self).items() if v is not None} # Handle special case for type_field if hasattr(self, 'type_field') and self.type_field is not None: result['$type'] = self.type_field del result['type_field'] return result def to_json(self) -> str: """Convert model to JSON string.""" return json.dumps(self.to_dict()) @classmethod def from_dict(cls: Type[T], data: Dict[str, Any]) -> T: """Create model instance from dictionary.""" # Handle special case for $type field if '$type' in data: data_copy = data.copy() data_copy['type_field'] = data_copy.pop('$type') data = data_copy return cls(**{k: v for k, v in data.items() if k in cls.__annotations__}) @dataclass class EligibilityCheckRequest(BaseModel): """Model for eligibility check request.""" type_field: str # This will be mapped to $type in JSON transactionId: str countryCode: str customerId: str accountId: str lienAmount: float channel: str msisdn: Optional[str] = None @dataclass class EligibleOffer(BaseModel): """Model for eligible offer.""" minamount: float maxamount: float productId: int offerid: int Tenor: int @dataclass class EligibilityCheckResponse(BaseModel): """Model for eligibility check response.""" customerId: str transactionId: str eligibleOffers: List[Dict[str, Any]] resultCode: str resultDescription: str msisdn: Optional[str] = None @dataclass class SelectOffersRequest(BaseModel): """Model for select offers request.""" requestId: str transactionId: str customerId: str accountId: str msisdn: str requestedAmount: float productid: str channel: str @dataclass class Offer(BaseModel): """Model for offer details.""" offerId: str productId: str amount: float upfrontPayment: float interestRate: float Interest: float ManagementRate: float ManagementFee: float InsuranceRate: float InsuranceFee: float VATRate: float VATamount: float recommendedRepaymentDates: List[str] installmentAmount: float totalRepaymentAmount: float @dataclass class SelectOffersResponse(BaseModel): """Model for select offers response.""" requestId: str transactionId: str customerId: str accountId: str offers: List[Dict[str, Any]] resultCode: str resultDescription: str outstandingDebtAmount: Optional[float] = 0 @dataclass class ProvideLoanRequest(BaseModel): """Model for provide loan request.""" type_field: str # This will be mapped to $type in JSON requestId: str transactionId: str customerId: str accountId: str productId: str lienAmount: float requestedAmount: float collectionType: int loanType: int channel: str msisdn: Optional[str] = None @dataclass class ProvideLoanResponse(BaseModel): """Model for provide loan response.""" requestId: str transactionId: str customerId: str accountId: str resultCode: str resultDescription: str msisdn: Optional[str] = None @dataclass class LoanInformationRequest(BaseModel): """Model for loan information request.""" type_field: str # This will be mapped to $type in JSON transactionId: str customerId: str channel: str msisdn: Optional[str] = None @dataclass class Loan(BaseModel): """Model for loan details.""" debtId: str loanDate: str dueDate: str currentLoanAmount: float initialLoanAmount: float defaultFee: float continiousFee: float productId: str @dataclass class LoanInformationResponse(BaseModel): """Model for loan information response.""" customerId: str loans: List[Dict[str, Any]] resultCode: str resultDescription: str totalDebtAmount: Optional[float] = None @dataclass class RepaymentRequest(BaseModel): """Model for repayment request.""" type_field: str # This will be mapped to $type in JSON transactionId: str customerId: str debtId: str productId: str channel: str msisdn: Optional[str] = None @dataclass class RepaymentResponse(BaseModel): """Model for repayment response.""" customerId: str productId: str debtId: str resultCode: str resultDescription: str @dataclass class CustomerConsentRequest(BaseModel): """Model for customer consent request.""" type_field: str # This will be mapped to $type in JSON transactionId: str customerId: str accountId: str requestTime: str consentType: str channel: str @dataclass class CustomerConsentResponse(BaseModel): """Model for customer consent response.""" resultCode: str resultDescription: str @dataclass class NotificationCallbackRequest(BaseModel): """Model for notification callback request.""" fbnTransactionId: str transactionId: str customerId: str accountId: str debtId: str transactionType: str amountProvided: float amountCollected: float responseCode: str responseDescription: str @dataclass class NotificationCallbackResponse(BaseModel): """Model for notification callback response.""" resultCode: str resultDescription: str @dataclass class RACCheckRequest(BaseModel): """Model for RAC check request.""" transactionId: str fbnTransactionId: str customerId: str accountId: str RAC_Array: List[str] @dataclass class RACResponse(BaseModel): """Model for RAC response details.""" SalaryAccount: Optional[str] = None BVN: Optional[str] = None BVNAttachedtoAccount: Optional[str] = None CRMS: Optional[str] = None CRC: Optional[str] = None AccountStatus: Optional[str] = None Lien: Optional[str] = None NoBounchedCheck: Optional[str] = None Whitelist: Optional[str] = None NoPastDueSalaryLoan: Optional[str] = None NoPastDueOtherLoan: Optional[str] = None @dataclass class RACCheckResponse(BaseModel): """Model for RAC check response.""" RACResponse: Dict[str, Any] resultCode: str resultDescription: str @dataclass class DisbursementRequest(BaseModel): """Model for disbursement request.""" requestId: str debtId: str transactionId: str customerId: str accountId: str productId: str provideAmount: float countryId: str collectAmountInterest: Optional[float] = None collectAmountMgtFee: Optional[float] = None collectAmountInsurance: Optional[float] = None collectAmountVAT: Optional[float] = None comment: Optional[str] = None @dataclass class DisbursementResponse(BaseModel): """Model for disbursement response.""" requestId: str debtId: str transactionId: str customerId: str accountId: str productId: str provideAmount: float resultCode: str resultDescription: str collectAmountInterest: Optional[float] = None collectAmountMgtFee: Optional[float] = None collectAmountInsurance: Optional[float] = None collectAmountVAT: Optional[float] = None @dataclass class CollectLoanRequest(BaseModel): """Model for collect loan request.""" transactionId: str fbnTransactionId: str debtId: str customerId: str accountId: str productId: str collectAmount: float collectionMethod: int lienAmount: float countryId: str penalCharge: Optional[float] = 0.0 comment: Optional[str] = None @dataclass class CollectLoanResponse(BaseModel): """Model for collect loan response.""" transactionId: str debtId: str customerId: str accountId: str productId: str collectAmount: float lienAmount: float resultCode: str resultDescription: str penalCharge: Optional[float] = 0.0 @dataclass class TransactionCheckRequest(BaseModel): """Model for transaction check request.""" counter: str TransactionId: str requestID: str customerId: str accountId: str countryId: str transactionType: str @dataclass class TransactionCheckResponse(BaseModel): """Model for transaction check response.""" type_field: str # This will be mapped to $type in JSON nativeId: str customerId: str accountId: str providedAmount: float collectedAmount: float resultCode: str resultDescription: str @dataclass class PenalChargeRequest(BaseModel): """Model for penal charge request.""" transactionId: str fbnTransactionId: str debtId: str customerId: str accountId: str penalCharge: float lienAmount: float countryId: str comment: Optional[str] = None @dataclass class PenalChargeResponse(BaseModel): """Model for penal charge response.""" resultCode: str resultDescription: str @dataclass class RevokeEnableConsentRequest(BaseModel): """Model for revoke/enable consent request.""" transactionId: str fbnTransactionId: str customerId: str accountId: str processTime: str consentType: str countryId: str comment: Optional[str] = None @dataclass class RevokeEnableConsentResponse(BaseModel): """Model for revoke/enable consent response.""" type_field: str # This will be mapped to $type in JSON customerId: str accountId: str resultCode: str resultDescription: str @dataclass class ValidateTokenRequest(BaseModel): """Model for validate token request.""" RequestId: str UserId: str CountryId: str TokenCode: str @dataclass class ValidateTokenResponse(BaseModel): """Model for validate token response.""" Authenticated: bool AuthenticatedMessage: str ResponseCode: str ResponseMessage: str RequestId: str @dataclass class LienCheckRequest(BaseModel): """Model for lien check request.""" transactionId: str customerId: str accountId: str countryId: str @dataclass class LienCheckResponse(BaseModel): """Model for lien check response.""" lienAmount: float resultCode: str resultDescription: str @dataclass class NewTransactionCheckRequest(BaseModel): """Model for new transaction check request.""" transactionId: str debtId: str transactionType: str fbnTransactionId: str origTransactionId: str customerId: str @dataclass class TransactionData(BaseModel): """Model for transaction data.""" transactionId: str providedAmount: float collectedAmount: float resultCode: str resultDescription: str @dataclass class NewTransactionCheckResponse(BaseModel): """Model for new transaction check response.""" transactionId: str data: Dict[str, Any] resultCode: str resultDescription: str @dataclass class SMSRequest(BaseModel): """Model for SMS request.""" text: str dest: str unicode: bool @dataclass class SMSResponse(BaseModel): """Model for SMS response.""" data: str statusCode: int IsSuccessful: bool errorMessage: Optional[str] = None