Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 31b0367e6a | |||
| 89760f81ed | |||
| 701840abd1 | |||
| df6c42ca2d | |||
| a321832d43 | |||
| d7b8addeb6 |
@@ -1,4 +1,5 @@
|
||||
from flask import session, jsonify
|
||||
from app.models.loan import Loan
|
||||
from app.models.transaction_offers import TransactionOffer
|
||||
from app.utils.logger import logger
|
||||
from app.api.services.base_service import BaseService
|
||||
@@ -50,6 +51,12 @@ class EligibilityCheckService(BaseService):
|
||||
return ResponseHelper.error(result_description="Invalid Customer or Account")
|
||||
|
||||
db.session.flush()
|
||||
|
||||
# Determine Loan count
|
||||
is_eligible = EligibilityCheckService.check_loan_limits(customer_id)
|
||||
|
||||
if not is_eligible:
|
||||
return ResponseHelper.error(result_description="Max loan count reached")
|
||||
|
||||
# Call RACCheck
|
||||
response = SimbrellaIntegration.rac_check(
|
||||
@@ -58,7 +65,7 @@ class EligibilityCheckService(BaseService):
|
||||
transaction_id = transaction.transaction_id,
|
||||
)
|
||||
|
||||
# this chck for error is not valid
|
||||
# this chek for error is not valid
|
||||
if response.status_code != 200:
|
||||
return ResponseHelper.error(result_description="RACCheck failed")
|
||||
|
||||
@@ -146,4 +153,33 @@ class EligibilityCheckService(BaseService):
|
||||
except Exception as e:
|
||||
logger.error(f"An error occurred: {str(e)}", exc_info=True)
|
||||
db.session.rollback()
|
||||
return ResponseHelper.internal_server_error()
|
||||
return ResponseHelper.internal_server_error()
|
||||
|
||||
|
||||
@staticmethod
|
||||
def check_loan_limits(customer_id):
|
||||
"""
|
||||
Checks if a customer has exceeded the loan limits for given offer.
|
||||
"""
|
||||
loan = Loan.get_customer_last_loan(customer_id)
|
||||
|
||||
if not loan:
|
||||
return True
|
||||
|
||||
offer_id = loan.offer_id[:5]
|
||||
|
||||
offer = Offer.get_offer_by_id(offer_id)
|
||||
if not offer:
|
||||
logger.error(f"Offer not found for offer_id: {offer_id} (customer_id: {customer_id})")
|
||||
return False
|
||||
|
||||
daily_count = TransactionOffer.get_daily_loan_count(customer_id, offer_id)
|
||||
|
||||
|
||||
logger.error(f"daily_count: {daily_count}, Max: {offer.max_daily_loans}")
|
||||
|
||||
if offer.max_daily_loans is not None and daily_count >= offer.max_daily_loans:
|
||||
return False
|
||||
|
||||
|
||||
return True
|
||||
|
||||
@@ -13,7 +13,7 @@ class Account(db.Model):
|
||||
status = db.Column(db.String(20), default='active')
|
||||
lien_amount = db.Column(db.Float, default=0.0)
|
||||
created_at = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = db.Column(db.DateTime(timezone=True), onupdate=func.now())
|
||||
updated_at = db.Column(db.DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
|
||||
customer = relationship(
|
||||
"Customer",
|
||||
@@ -27,7 +27,9 @@ class Account(db.Model):
|
||||
account = cls(
|
||||
id=id,
|
||||
customer_id=customer_id,
|
||||
account_type=account_type
|
||||
account_type=account_type,
|
||||
created_at=datetime.now(timezone.utc),
|
||||
updated_at=datetime.now(timezone.utc)
|
||||
)
|
||||
|
||||
try:
|
||||
|
||||
@@ -14,7 +14,7 @@ class Charge(db.Model):
|
||||
description = db.Column(db.Text, nullable=True)
|
||||
due = db.Column(db.Integer, nullable=False)
|
||||
created_at = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = db.Column(db.DateTime(timezone=True), onupdate=func.now())
|
||||
updated_at = db.Column(db.DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
offer = relationship(
|
||||
"Offer",
|
||||
primaryjoin="Charge.offer_id == Offer.id",
|
||||
@@ -57,7 +57,9 @@ class Charge(db.Model):
|
||||
code = code,
|
||||
percent = percent,
|
||||
description = description,
|
||||
due = due_days
|
||||
due = due_days,
|
||||
created_at=datetime.now(timezone.utc),
|
||||
updated_at=datetime.now(timezone.utc)
|
||||
)
|
||||
|
||||
db.session.add(charge_obj)
|
||||
|
||||
@@ -12,7 +12,7 @@ class Customer(db.Model):
|
||||
msisdn = db.Column(db.String(20), unique=True, nullable=False)
|
||||
country_code = db.Column(db.String(3), nullable=False)
|
||||
created_at = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = db.Column(db.DateTime(timezone=True), onupdate=func.now())
|
||||
updated_at = db.Column(db.DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
accounts = relationship(
|
||||
"Account",
|
||||
primaryjoin="Customer.id == Account.customer_id",
|
||||
@@ -47,7 +47,13 @@ class Customer(db.Model):
|
||||
raise ValueError("Customer already exists")
|
||||
|
||||
# Create the customer
|
||||
customer = cls(id=id, msisdn=msisdn, country_code=country_code)
|
||||
customer = cls(
|
||||
id=id,
|
||||
msisdn=msisdn,
|
||||
country_code=country_code,
|
||||
created_at=datetime.now(timezone.utc),
|
||||
updated_at=datetime.now(timezone.utc)
|
||||
)
|
||||
try:
|
||||
db.session.add(customer)
|
||||
|
||||
|
||||
+4
-2
@@ -39,7 +39,7 @@ class Loan(db.Model):
|
||||
tenor = db.Column(db.Integer, nullable=True)
|
||||
due_date = db.Column(db.DateTime, nullable=True)
|
||||
created_at = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = db.Column(db.DateTime(timezone=True), onupdate=func.now())
|
||||
updated_at = db.Column(db.DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
eligible_amount = db.Column(db.Float, nullable=True, default=0.0)
|
||||
disburse_date = db.Column(db.DateTime, nullable=True)
|
||||
disburse_verify = db.Column(db.DateTime, nullable=True)
|
||||
@@ -109,7 +109,9 @@ class Loan(db.Model):
|
||||
due_date=due_date,
|
||||
tenor = tenor,
|
||||
status = status,
|
||||
eligible_amount =eligible_amount
|
||||
eligible_amount =eligible_amount,
|
||||
created_at=datetime.now(timezone.utc),
|
||||
updated_at=datetime.now(timezone.utc)
|
||||
)
|
||||
|
||||
try:
|
||||
|
||||
@@ -18,7 +18,7 @@ class LoanCharge(db.Model):
|
||||
due = db.Column(db.Integer, nullable=False)
|
||||
due_date = db.Column(db.DateTime, nullable=True)
|
||||
created_at = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = db.Column(db.DateTime(timezone=True), onupdate=func.now())
|
||||
updated_at = db.Column(db.DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
loan = relationship(
|
||||
"Loan",
|
||||
primaryjoin="LoanCharge.loan_id == Loan.id",
|
||||
@@ -63,7 +63,9 @@ class LoanCharge(db.Model):
|
||||
percent = percent,
|
||||
description = description,
|
||||
due = due_days,
|
||||
due_date = now + timedelta(days=due_days)
|
||||
due_date = now + timedelta(days=due_days),
|
||||
created_at=datetime.now(timezone.utc),
|
||||
updated_at=datetime.now(timezone.utc)
|
||||
)
|
||||
|
||||
db.session.add(charge_obj)
|
||||
|
||||
@@ -19,7 +19,7 @@ class LoanRepaymentSchedule(db.Model):
|
||||
paid_at = db.Column(db.DateTime, nullable=True)
|
||||
|
||||
created_at = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = db.Column(db.DateTime(timezone=True), onupdate=func.now())
|
||||
updated_at = db.Column(db.DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
loan = relationship(
|
||||
"Loan",
|
||||
primaryjoin="LoanRepaymentSchedule.loan_id == Loan.id",
|
||||
@@ -45,7 +45,9 @@ class LoanRepaymentSchedule(db.Model):
|
||||
total_repayment_amount = round(loan.repayment_amount, 2),
|
||||
installment_amount=round(loan.installment_amount, 2),
|
||||
product_id = loan.product_id,
|
||||
transaction_id = transaction_id
|
||||
transaction_id = transaction_id,
|
||||
created_at=datetime.now(timezone.utc),
|
||||
updated_at=datetime.now(timezone.utc)
|
||||
)
|
||||
|
||||
db.session.add(schedule)
|
||||
|
||||
+10
-2
@@ -18,8 +18,12 @@ class Offer(db.Model):
|
||||
insurance_rate = db.Column(db.Float, default=1.0)
|
||||
vat_rate = db.Column(db.Float, default=7.5)
|
||||
list_order = db.Column(db.Integer, nullable=True)
|
||||
max_daily_loans = db.Column(db.Integer, nullable=True)
|
||||
max_active_loans = db.Column(db.Integer, nullable=True)
|
||||
max_life_loans = db.Column(db.Integer, nullable=True)
|
||||
created_at = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = db.Column(db.DateTime(timezone=True), onupdate=func.now())
|
||||
updated_at = db.Column(db.DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
|
||||
charges = relationship(
|
||||
"Charge",
|
||||
primaryjoin="Offer.id == Charge.offer_id",
|
||||
@@ -79,7 +83,11 @@ class Offer(db.Model):
|
||||
"interest_rate": self.interest_rate,
|
||||
"management_rate": self.management_rate,
|
||||
"insurance_rate": self.insurance_rate,
|
||||
"vat_rate": self.vat_rate
|
||||
"vat_rate": self.vat_rate,
|
||||
"maxDailyLoans": self.max_daily_loans,
|
||||
"maxActiveLoans": self.max_active_loans,
|
||||
"maxLifeLoans": self.max_life_loans
|
||||
|
||||
}
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
@@ -15,7 +15,7 @@ class RACCheck(db.Model):
|
||||
account_id = db.Column(db.String, nullable=False)
|
||||
rac_response = db.Column(db.JSON, nullable=False)
|
||||
created_at = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = db.Column(db.DateTime(timezone=True), onupdate=func.now())
|
||||
updated_at = db.Column(db.DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
@classmethod
|
||||
def add_rac_check(cls, customer_id, account_id, transaction_id, data = None):
|
||||
|
||||
@@ -25,7 +25,9 @@ class RACCheck(db.Model):
|
||||
customer_id = customer_id,
|
||||
account_id = account_id,
|
||||
transaction_id = transaction_id,
|
||||
rac_response = data
|
||||
rac_response = data,
|
||||
created_at=datetime.now(timezone.utc),
|
||||
updated_at=datetime.now(timezone.utc)
|
||||
)
|
||||
|
||||
try:
|
||||
|
||||
@@ -19,7 +19,7 @@ class Repayment(db.Model):
|
||||
customer_id = db.Column(db.String(50), nullable=False)
|
||||
product_id = db.Column(db.String(20), nullable=True)
|
||||
created_at = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = db.Column(db.DateTime(timezone=True), onupdate=func.now())
|
||||
updated_at = db.Column(db.DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
transaction_id = db.Column(db.String(50), nullable=True)
|
||||
|
||||
@classmethod
|
||||
@@ -42,7 +42,9 @@ class Repayment(db.Model):
|
||||
customer_id=customer_id,
|
||||
loan_id=loan_id,
|
||||
product_id=product_id,
|
||||
transaction_id = transaction_id
|
||||
transaction_id = transaction_id,
|
||||
created_at=datetime.now(timezone.utc),
|
||||
updated_at=datetime.now(timezone.utc)
|
||||
)
|
||||
|
||||
try:
|
||||
|
||||
@@ -18,7 +18,7 @@ class Transaction(db.Model):
|
||||
type = db.Column(db.String(50), nullable=False)
|
||||
channel = db.Column(db.String(50), nullable=False)
|
||||
created_at = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = db.Column(db.DateTime(timezone=True), onupdate=func.now())
|
||||
updated_at = db.Column(db.DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
def __repr__(self):
|
||||
return f'<Transaction {self.id}>'
|
||||
|
||||
@@ -38,7 +38,9 @@ class Transaction(db.Model):
|
||||
customer_id = customer_id,
|
||||
account_id = account_id,
|
||||
type = type,
|
||||
channel = channel
|
||||
channel = channel,
|
||||
created_at=datetime.now(timezone.utc),
|
||||
updated_at=datetime.now(timezone.utc)
|
||||
)
|
||||
|
||||
try:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from datetime import datetime, timezone
|
||||
from datetime import datetime, timezone, timedelta
|
||||
from app.api.enums.loan_status import LoanStatus
|
||||
from app.extensions import db
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql import func
|
||||
@@ -22,7 +23,7 @@ class TransactionOffer(db.Model):
|
||||
tenor = db.Column(db.Integer, nullable=True) # tenor in months, typically
|
||||
|
||||
created_at = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = db.Column(db.DateTime(timezone=True), onupdate=func.now())
|
||||
updated_at = db.Column(db.DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
customer = relationship(
|
||||
"Customer",
|
||||
primaryjoin="Customer.id == TransactionOffer.customer_id",
|
||||
@@ -31,12 +32,11 @@ class TransactionOffer(db.Model):
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
||||
def is_valid_transaction_offer(cls, transaction_offer, customer_id, product_id):
|
||||
transaction_offer = cls.query.filter_by(
|
||||
id = transaction_offer,
|
||||
customer_id = customer_id,
|
||||
product_id = product_id
|
||||
# product_id = product_id
|
||||
# transaction_id = transaction_id,
|
||||
).first()
|
||||
|
||||
@@ -59,7 +59,9 @@ class TransactionOffer(db.Model):
|
||||
max_amount=max_amount,
|
||||
eligible_amount=eligible_amount,
|
||||
product_id=product_id,
|
||||
tenor=tenor
|
||||
tenor=tenor,
|
||||
created_at=datetime.now(timezone.utc),
|
||||
updated_at=datetime.now(timezone.utc)
|
||||
)
|
||||
|
||||
db.session.add(transaction_offer)
|
||||
@@ -67,6 +69,43 @@ class TransactionOffer(db.Model):
|
||||
|
||||
return transaction_offer
|
||||
|
||||
@classmethod
|
||||
def get_lifetime_loan_count(cls, customer_id):
|
||||
"""
|
||||
Returns the total number of loans ever created for a customer.
|
||||
"""
|
||||
return cls.query.filter_by(customer_id=customer_id).count()
|
||||
|
||||
@classmethod
|
||||
def get_daily_loan_count(cls, customer_id, offer_id):
|
||||
"""
|
||||
Returns the count of loans created today for a customer.
|
||||
"""
|
||||
|
||||
start_of_day = datetime.now(timezone.utc).replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
end_of_day = start_of_day + timedelta(days=1)
|
||||
|
||||
return cls.query.filter_by(
|
||||
customer_id=customer_id,
|
||||
offer_id=offer_id
|
||||
).filter(
|
||||
cls.created_at >= start_of_day,
|
||||
cls.created_at < end_of_day
|
||||
).count()
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_latest_transaction_offer(cls, customer_id):
|
||||
"""
|
||||
Returns the most recent transaction offer for the given customer based on creation time.
|
||||
"""
|
||||
return cls.query.filter_by(customer_id=customer_id) \
|
||||
.order_by(cls.created_at.desc()) \
|
||||
.first()
|
||||
|
||||
|
||||
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
"""empty message
|
||||
|
||||
Revision ID: e8dd9b841ad7
|
||||
Revises: 2eee4157505f
|
||||
Create Date: 2025-05-19 11:46:19.204637
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'e8dd9b841ad7'
|
||||
down_revision = '2eee4157505f'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('offers', schema=None) as batch_op:
|
||||
batch_op.add_column(sa.Column('max_daily_loans', sa.Integer(), nullable=True))
|
||||
batch_op.add_column(sa.Column('max_active_loans', sa.Integer(), nullable=True))
|
||||
batch_op.add_column(sa.Column('max_life_loans', sa.Integer(), nullable=True))
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('offers', schema=None) as batch_op:
|
||||
batch_op.drop_column('max_life_loans')
|
||||
batch_op.drop_column('max_active_loans')
|
||||
batch_op.drop_column('max_daily_loans')
|
||||
|
||||
# ### end Alembic commands ###
|
||||
Reference in New Issue
Block a user