6 Commits

Author SHA1 Message Date
Chinenye Nmoh 04861d2c52 added repayment data 2025-07-07 20:25:03 +01:00
Chinenye Nmoh 2d6ff1adc2 updated loan and repayment endpoint 2025-07-05 20:49:57 +01:00
ameye 6bed4d2dfa Merge branch 'task_3' of DigiFi/FirstCore into master 2025-05-28 12:40:51 +00:00
Chinenye Nmoh bbb919d933 completed the task 2025-05-28 13:14:09 +01:00
CHIEFSOFT\ameye 2c46a4390c Sample env 2025-05-26 06:54:20 -04:00
ameye fac6a80284 Merge branch 'testing' of DigiFi/FirstCore into master 2025-05-19 15:04:49 +00:00
19 changed files with 579 additions and 60 deletions
+25 -17
View File
@@ -1,26 +1,34 @@
VALID_APP_ID=********** SIMBRELLA_BASE_URL=***************
VALID_API_KEY=*************
BASIC_AUTH_USERNAME=******
BASIC_AUTH_PASSWORD=******
# Environment Variables
BASIC_AUTH_USERNAME=user
BASIC_AUTH_PASSWORD=password
SWAGGER_URL="/documentation" SWAGGER_URL="/documentation"
API_URL="/swagger.json" API_URL="/swagger.json"
JWT_SECRET_KEY=******
JWT_ACCESS_TOKEN_EXPIRES=******
JWT_REFRESH_TOKEN_EXPIRES=******
DATABASE_USER=*****
DATABASE_PASSWORD=*****
DATABASE_HOST=******
DATABASE_PORT=******
DATABASE_NAME=*****
# Flask Configuration # Flask Configuration
FLASK_APP=wsgi.py FLASK_APP=wsgi.py
FLASK_ENV=development FLASK_ENV=development
APP_PORT=4500 APP_PORT=4700
#Database Configuration
#DATABASE_USER=firstadvance
#DATABASE_PASSWORD=FirstAdvance!
#DATABASE_HOST=10.20.30.60
#DATABASE_PORT=5432
#DATABASE_NAME=firstadvancedev
DATABASE_USER=firstadvance
DATABASE_PASSWORD=FirstAdvance!
DATABASE_HOST=dev-data.simbrellang.net
DATABASE_PORT=10532
DATABASE_NAME=firstadvancedev
#Events if Needed
KAFKA_TIMEOUT=45000.0
KAFKA_BROKER="10.20.30.50:9092"
SIMBRELLA_BASE_URL=***************
+6 -3
View File
@@ -18,7 +18,10 @@ ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0 ENV FLASK_RUN_HOST=0.0.0.0
#COPY scripts/enterypointone.sh scripts/enterypointone.sh #COPY scripts/enterypointone.sh scripts/enterypointone.sh
#RUN chmod +x scripts/entry.sh
#ENTRYPOINT ["scripts/entry.sh"]
RUN chmod +x scripts/enterypointone.sh # Run the application
CMD [ "sh", "-c", \
ENTRYPOINT ["scripts/enterypointone.sh"] "echo 'Starting Gunicorn server...' && \
exec gunicorn -w 4 -b 0.0.0.0:5000 wsgi:wsgi_app"]
+19 -1
View File
@@ -11,6 +11,7 @@ from app.api.services.auth_service import AuthService
from app.api.services.dashboard_service import DashboardService from app.api.services.dashboard_service import DashboardService
from app.api.services.offer_service import OfferService from app.api.services.offer_service import OfferService
from app.api.services.charge_service import ChargeService from app.api.services.charge_service import ChargeService
from app.api.services.repayment_data_service import RepaymentDataService
from functools import wraps from functools import wraps
from app.utils.logger import logger from app.utils.logger import logger
from app.api.middlewares import enforce_json, require_auth from app.api.middlewares import enforce_json, require_auth
@@ -123,7 +124,8 @@ def get_loans():
'page': request.args.get('page', 1), 'page': request.args.get('page', 1),
'limit': request.args.get('limit', 20) 'limit': request.args.get('limit', 20)
} }
# logger.info(f"Get loans request received with filters: {filters}") #logger.info(f"Get loans request received with filters: {filters}")
response = LoanService.process_request(filters) response = LoanService.process_request(filters)
return response return response
@@ -179,6 +181,22 @@ def get_all_repayments():
# logger.info(f"Get repayments request received with filters: {filters}") # logger.info(f"Get repayments request received with filters: {filters}")
response = RepaymentService.get_all_repayments(filters) response = RepaymentService.get_all_repayments(filters)
return response return response
@api.route('/repayment-data', methods=['GET'])
# @token_required
def get_all_repayments_data():
# Extract query parameters for filtering
filters = {
'customer_id': request.args.get('customer_id'),
'account_id': request.args.get('account_id'),
'added_date': request.args.get('added_date'),
'transaction_id': request.args.get('transaction_id'),
'fbn_transaction_id': request.args.get('fbn_transaction_id'),
'page': request.args.get('page', 1),
'limit': request.args.get('limit', 20)
}
# logger.info(f"Get repayments request received with filters: {filters}")
response = RepaymentDataService.get_all_repayments_data(filters)
return response
@api.route('/loan-charges', methods=['GET']) @api.route('/loan-charges', methods=['GET'])
# @token_required # @token_required
+1
View File
@@ -9,3 +9,4 @@ from app.api.services.repayment_service import RepaymentService
from app.api.services.loan_charge_service import LoanChargeService from app.api.services.loan_charge_service import LoanChargeService
from app.api.services.loan_repayment_schedule_service import LoanRepaymentScheduleService from app.api.services.loan_repayment_schedule_service import LoanRepaymentScheduleService
from app.api.services.transaction_offers_service import TransactionOfferService from app.api.services.transaction_offers_service import TransactionOfferService
from app.api.services.repayment_data_service import RepaymentDataService
+30 -34
View File
@@ -4,34 +4,30 @@ from app.api.services.base_service import BaseService
from app.models.transaction import Transaction from app.models.transaction import Transaction
from app.models.loan import Loan from app.models.loan import Loan
from sqlalchemy import func, desc from sqlalchemy import func, desc
from datetime import datetime, timedelta from datetime import datetime, timedelta, timezone
from app.extensions import db from app.extensions import db
from app.api.enums.transaction_type import TransactionType
class DashboardService(BaseService): class DashboardService(BaseService):
@staticmethod @staticmethod
def get_dashboard_data(): def get_dashboard_data():
"""
Get dashboard summary data.
Returns:
dict: A standardized response with dashboard data.
"""
try: try:
# Get current date and start of the week
now = datetime.now() now = datetime.now()
start_of_week = now - timedelta(days=now.weekday()) start_of_week = now - timedelta(days=now.weekday())
start_of_week = start_of_week.replace(hour=0, minute=0, second=0, microsecond=0) start_of_week = start_of_week.replace(hour=0, minute=0, second=0, microsecond=0)
# Get loans data for the current week # Calculate 24 hours ago
last_24_hours = datetime.now(timezone.utc) - timedelta(hours=24)
# Loans this week
loans_this_week = db.session.query( loans_this_week = db.session.query(
func.sum(Loan.initial_loan_amount) func.sum(Loan.initial_loan_amount)
).filter( ).filter(
Loan.created_at >= start_of_week Loan.created_at >= start_of_week
).scalar() or 0 ).scalar() or 0
# Get payments data for the current week # Payments this week
# Assuming payments are transactions with type 'PAYMENT'
payments_this_week = db.session.query( payments_this_week = db.session.query(
func.count(Transaction.id) func.count(Transaction.id)
).filter( ).filter(
@@ -39,51 +35,53 @@ class DashboardService(BaseService):
Transaction.type == 'PAYMENT' Transaction.type == 'PAYMENT'
).scalar() or 0 ).scalar() or 0
# Get request summary counts
# These are placeholders - needed to adjust based on your actual data model # Request summary for the last 24 hours
eligibility_check_count = db.session.query( eligibility_check_count = db.session.query(
func.count(Transaction.id) func.count(Transaction.id)
).filter( ).filter(
Transaction.type == 'ELIGIBILITY_CHECK' Transaction.type == TransactionType.ELIGIBILITY_CHECK.value,
Transaction.created_at >= last_24_hours
).scalar() or 0 ).scalar() or 0
select_offer_count = db.session.query( select_offer_count = db.session.query(
func.count(Transaction.id) func.count(Transaction.id)
).filter( ).filter(
Transaction.type == 'SELECT_OFFER' Transaction.type == TransactionType.SELECT_OFFER.value,
Transaction.created_at >= last_24_hours
).scalar() or 0 ).scalar() or 0
provide_loan_count = db.session.query( provide_loan_count = db.session.query(
func.count(Transaction.id) func.count(Transaction.id)
).filter( ).filter(
Transaction.type == 'PROVIDE_LOAN' Transaction.type == TransactionType.PROVIDE_LOAN.value,
Transaction.created_at >= last_24_hours
).scalar() or 0 ).scalar() or 0
repayment_count = db.session.query( repayment_count = db.session.query(
func.count(Transaction.id) func.count(Transaction.id)
).filter( ).filter(
Transaction.type == 'REPAYMENT' Transaction.type == TransactionType.REPAYMENT.value,
Transaction.created_at >= last_24_hours
).scalar() or 0 ).scalar() or 0
# Get recent transactions # Recent transactions (not limited to 24 hrs, just latest 15)
recent_transactions = Transaction.query.order_by( recent_transactions = Transaction.query.order_by(
Transaction.id.desc() Transaction.id.desc()
).limit(15).all() ).limit(15).all()
# Format recent transactions recent_transactions_data = [{
recent_transactions_data = [] 'id': t.id,
for transaction in recent_transactions: 'transaction_id': t.transaction_id,
recent_transactions_data.append({ 'account_id': t.account_id,
'id': transaction.id, 'type': t.type,
'transaction_id': transaction.transaction_id, 'channel': t.channel,
'account_id': transaction.account_id, 'created_at': t.created_at.isoformat() if t.created_at else None,
'type': transaction.type, 'updated_at': t.updated_at.isoformat() if t.updated_at else None
'channel': transaction.channel, } for t in recent_transactions]
'created_at': transaction.created_at.isoformat() if transaction.created_at else None,
'updated_at': transaction.updated_at.isoformat() if transaction.updated_at else None
})
# Prepare response data # Final response
dashboard_data = { dashboard_data = {
"loans": { "loans": {
"value": float(loans_this_week), "value": float(loans_this_week),
@@ -110,6 +108,4 @@ class DashboardService(BaseService):
except Exception as e: except Exception as e:
logger.error(f"An error occurred while getting dashboard data: {str(e)}", exc_info=True) logger.error(f"An error occurred while getting dashboard data: {str(e)}", exc_info=True)
return jsonify({ return jsonify({"message": "Internal Server Error"}), 500
"message": "Internal Server Error"
}), 500
+10 -2
View File
@@ -81,7 +81,7 @@ class LoanService:
limit=limit limit=limit
) )
logger.info(f"Result from loans model cme back") logger.info(f"Result from loans model cme back ")
# Convert loans to dictionary format # Convert loans to dictionary format
loans_data = [] loans_data = []
@@ -98,6 +98,8 @@ class LoanService:
'current_loan_amount': loan.current_loan_amount, 'current_loan_amount': loan.current_loan_amount,
'status': loan.status, 'status': loan.status,
'tenor': loan.tenor, 'tenor': loan.tenor,
'balance': loan.balance,
'reference': loan.reference,
'product_id': loan.product_id, 'product_id': loan.product_id,
'default_penalty_fee': loan.default_penalty_fee, 'default_penalty_fee': loan.default_penalty_fee,
'continuous_fee': loan.continuous_fee, 'continuous_fee': loan.continuous_fee,
@@ -106,7 +108,13 @@ class LoanService:
'installment_amount': loan.installment_amount, 'installment_amount': loan.installment_amount,
'due_date': loan.due_date.isoformat() if loan.due_date else None, 'due_date': loan.due_date.isoformat() if loan.due_date else None,
'created_at': loan.created_at.isoformat() if loan.created_at else None, 'created_at': loan.created_at.isoformat() if loan.created_at else None,
'updated_at': loan.updated_at.isoformat() if loan.updated_at else None 'updated_at': loan.updated_at.isoformat() if loan.updated_at else None,
'disburseResult': loan.disburse_result,
'disburseDescription': loan.disburse_description,
'verifyResult': loan.verify_result,
'verifyDescription': loan.verify_description,
'disburseDate': loan.disburse_date.isoformat() if loan.disburse_date else None,
'disburseVerify': loan.disburse_verify.isoformat() if loan.disburse_verify else None,
}) })
# Calculate total pages # Calculate total pages
@@ -0,0 +1,82 @@
import logging
from datetime import datetime
from app.models.repayment_data import RepaymentsData
from dateutil.parser import parse as parse_date
logger = logging.getLogger(__name__)
class RepaymentDataService:
"""
Service class for handling repayment-data operations.
"""
@staticmethod
def get_all_repayments_data(filters=None):
try:
if filters is None:
filters = {}
customer_id = filters.get('customer_id')
account_id = filters.get('account_id')
added_date = filters.get('added_date')
transaction_id = filters.get('transaction_id')
fbn_transaction_id = filters.get('fbn_transaction_id')
page = int(filters.get('page', 1))
limit = int(filters.get('limit', 20))
if page < 1:
page = 1
if limit < 1 or limit > 100:
limit = 20
if added_date and isinstance(added_date, str):
try:
added_date = parse_date(added_date)
except Exception as parse_err:
logger.error(f"Invalid date format for 'added_date': {added_date}")
return {"message": "Invalid date format for 'added_date'"}, 400
repayments_data, total_count = RepaymentsData.get_all_repayment_data(
customer_id=customer_id,
account_id=account_id,
added_date=added_date,
transaction_id=transaction_id,
fbn_transaction_id=fbn_transaction_id,
page=page,
limit=limit
)
repayments_list = []
for repayment in repayments_data:
repayments_list.append({
'customer_id': repayment.customer_id,
'account_id': repayment.account_id,
'transaction_id': repayment.transaction_id,
'fbn_transaction_id': repayment.fbn_transaction_id,
'added_date': repayment.added_date.isoformat() if repayment.added_date else None,
'response_code': repayment.response_code,
'response_descr': repayment.response_descr,
'repayment_amount': repayment.repayment_amount,
'amount_collected': repayment.amount_collected,
'balance': repayment.balance
})
total_pages = (total_count + limit - 1) // limit
return {
'repayment_data': repayments_list,
'count': len(repayments_list),
'pagination': {
'total_count': total_count,
'total_pages': total_pages,
'current_page': page,
'limit': limit,
'has_next': page < total_pages,
'has_prev': page > 1
}
}
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return {"message": "Internal Server Error"}, 500
+9 -1
View File
@@ -69,7 +69,15 @@ class RepaymentService:
'product_id': repayment.product_id, 'product_id': repayment.product_id,
'transaction_id': repayment.transaction_id, 'transaction_id': repayment.transaction_id,
'created_at': repayment.created_at.isoformat() if repayment.created_at else None, 'created_at': repayment.created_at.isoformat() if repayment.created_at else None,
'updated_at': repayment.updated_at.isoformat() if repayment.updated_at else None 'updated_at': repayment.updated_at.isoformat() if repayment.updated_at else None,
'repay_date': repayment.repay_date.isoformat() if repayment.repay_date else None,
'initiated_by': repayment.initiated_by,
'salary_amount': repayment.salary_amount,
'verify_date': repayment.verify_date.isoformat() if repayment.verify_date else None,
'repay_result': repayment.repay_result,
'repay_description': repayment.repay_description,
'verify_result': repayment.verify_result,
'verify_description': repayment.verify_description
}) })
# Calculate total pages # Calculate total pages
+1
View File
@@ -72,6 +72,7 @@ class TransactionService:
'transaction_id': transaction.transaction_id, 'transaction_id': transaction.transaction_id,
'account_id': transaction.account_id, 'account_id': transaction.account_id,
'type': transaction.type, 'type': transaction.type,
'customer_id': transaction.customer_id,
'channel': transaction.channel, 'channel': transaction.channel,
'created_at': transaction.created_at.isoformat(), 'created_at': transaction.created_at.isoformat(),
'updated_at': transaction.updated_at.isoformat() 'updated_at': transaction.updated_at.isoformat()
+17 -1
View File
@@ -36,6 +36,14 @@ class Loan(db.Model):
created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc)) created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc))
updated_at = db.Column(db.DateTime, default=datetime.now(timezone.utc), onupdate=datetime.now(timezone.utc)) updated_at = db.Column(db.DateTime, default=datetime.now(timezone.utc), onupdate=datetime.now(timezone.utc))
eligible_amount = db.Column(db.Float, nullable=True, default=0.0) 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)
disburse_result = db.Column(db.String(10), nullable=True)
disburse_description = db.Column(db.String(100), nullable=True)
verify_result = db.Column(db.String(10), nullable=True)
verify_description = db.Column(db.String(100), nullable=True)
reference = db.Column(db.String(50), nullable=True)
balance = db.Column(db.Float, nullable=True, default=0.0)
customer = relationship( customer = relationship(
"Customer", "Customer",
@@ -147,7 +155,15 @@ class Loan(db.Model):
'installment_amount': self.installment_amount, 'installment_amount': self.installment_amount,
'due_date': self.due_date.isoformat() if self.due_date else None, 'due_date': self.due_date.isoformat() if self.due_date else None,
'created_at': self.created_at.isoformat() if self.created_at else None, 'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None 'updated_at': self.updated_at.isoformat() if self.updated_at else None,
'disburseResult': self.disburse_result,
'disburseDescription': self.disburse_description,
'verifyResult': self.verify_result,
'verifyDescription': self.verify_description,
'disburseDate': self.disburse_date.isoformat() if self.disburse_date else None,
'disburseVerify': self.disburse_verify.isoformat() if self.disburse_verify else None,
'reference': self.reference,
'balance': self.balance,
} }
def __repr__(self): def __repr__(self):
+18 -1
View File
@@ -12,6 +12,14 @@ class Repayment(db.Model):
created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc)) created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc))
updated_at = db.Column(db.DateTime, default=datetime.now(timezone.utc), onupdate=datetime.now(timezone.utc)) updated_at = db.Column(db.DateTime, default=datetime.now(timezone.utc), onupdate=datetime.now(timezone.utc))
transaction_id = db.Column(db.String(50)) transaction_id = db.Column(db.String(50))
repay_date = db.Column(db.DateTime, nullable=True)
initiated_by = db.Column(db.String(50), nullable=True)
salary_amount = db.Column(db.Float, nullable=True, default=0.0)
verify_date = db.Column(db.DateTime, nullable=True)
repay_result = db.Column(db.String(10), nullable=True)
repay_description = db.Column(db.String(100), nullable=True)
verify_result = db.Column(db.String(10), nullable=True)
verify_description = db.Column(db.String(100), nullable=True)
@classmethod @classmethod
def get_all_repayments(cls, loan_id=None, customer_id=None, product_id=None, def get_all_repayments(cls, loan_id=None, customer_id=None, product_id=None,
@@ -71,7 +79,16 @@ class Repayment(db.Model):
'product_id': self.product_id, 'product_id': self.product_id,
'transaction_id': self.transaction_id, 'transaction_id': self.transaction_id,
'created_at': self.created_at.isoformat() if self.created_at else None, 'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None 'updated_at': self.updated_at.isoformat() if self.updated_at else None,
'repay_date': self.repay_date.isoformat() if self.repay_date else None,
'initiated_by': self.initiated_by,
'salary_amount': self.salary_amount,
'verify_date': self.verify_date.isoformat() if self.verify_date else None,
'repay_result': self.repay_result,
'repay_description': self.repay_description,
'verify_result': self.verify_result,
'verify_description': self.verify_description
} }
def __repr__(self): def __repr__(self):
+80
View File
@@ -0,0 +1,80 @@
from datetime import datetime, timezone
from app.extensions import db
from app.utils.logger import logger
class RepaymentsData(db.Model):
__tablename__ = 'repayments_data'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
transaction_id = db.Column(db.String(50), nullable=False)
added_date = db.Column(db.DateTime(timezone=True), default=datetime.now(timezone.utc), nullable=False)
response_code = db.Column(db.String(10), nullable=True)
response_descr = db.Column(db.String(255), nullable=True)
fbn_transaction_id = db.Column(db.String(255),nullable=True)
account_id = db.Column(db.String(50), nullable=True)
customer_id = db.Column(db.String(50), nullable=True)
repayment_amount = db.Column(db.Float, nullable=True)
amount_collected = db.Column(db.Float, nullable=True)
balance = db.Column(db.Float, nullable=True, default=0.0)
def to_dict(self):
return {
"id": self.id,
"transaction_id": self.transaction_id,
"added_date": self.added_date.isoformat() if self.added_date else None,
"response_code": self.response_code,
"response_descr": self.response_descr,
"customerId": self.customer_id,
"accountId": self.account_id,
"fbnTransactionId": self.fbn_transaction_id,
"repaymentAmount": self.repayment_amount,
"amountCollected": self.amount_collected,
"balance": self.balance
}
def __repr__(self):
return f"<RepaymentsData id={self.id}, transaction_id={self.transaction_id}>"
@classmethod
def get_all_repayment_data(cls, customer_id=None, account_id=None, transaction_id=None, fbn_transaction_id=None,
added_date=None, page=1, limit=20):
"""
Get all repayment data with optional filtering
Args:
customer_id (str, optional): Filter by customer ID
account_id (str, optional): Filter by account ID
added_date (datetime, optional): Filter by added date
transaction_id (str, optional): Filter by transaction ID
fbn_transaction_id (str, optional): Filter by FBN transaction ID
page (int, optional): Page number for pagination
limit (int, optional): Number of items per page
Returns:
tuple: (list of Repayment objects, total count)
"""
query = cls.query
if customer_id:
query = query.filter(cls.customer_id == customer_id)
if account_id:
query = query.filter(cls.account_id == account_id)
if transaction_id:
query = query.filter(cls.transaction_id == transaction_id)
if fbn_transaction_id:
query = query.filter(cls.fbn_transaction_id == fbn_transaction_id)
if added_date:
query = query.filter(cls.added_date >= added_date)
# Get total count before pagination
total_count = query.count()
#order
query = query.order_by(cls.added_date.desc())
# Apply pagination
offset = (page - 1) * limit
query = query.limit(limit).offset(offset)
return query.all(), total_count
+14
View File
@@ -80,6 +80,14 @@
"url": "https://www.simbrellang.net" "url": "https://www.simbrellang.net"
} }
}, },
{
"name": "Repayment Data",
"description": "Get all repayment data with optional filtering.",
"externalDocs": {
"description": "Find out more",
"url": "https://www.simbrellang.net"
}
},
{ {
"name": "Offers", "name": "Offers",
"description": "Get all offers with optional filtering.", "description": "Get all offers with optional filtering.",
@@ -119,6 +127,9 @@
"/loan-charges": { "/loan-charges": {
"$ref": "../swagger/paths/LoanCharges.json" "$ref": "../swagger/paths/LoanCharges.json"
}, },
"/repayment-data": {
"$ref": "../swagger/paths/RepaymentData.json"
},
"/repayment-schedules": { "/repayment-schedules": {
"$ref": "../swagger/paths/RepaymentSchedules.json" "$ref": "../swagger/paths/RepaymentSchedules.json"
}, },
@@ -158,6 +169,9 @@
"RepaymentsResponse": { "RepaymentsResponse": {
"$ref": "../swagger/schemas/RepaymentsResponse.json" "$ref": "../swagger/schemas/RepaymentsResponse.json"
}, },
"RepaymentDataResponse": {
"$ref": "../swagger/schemas/RepaymentDataResponse.json"
},
"LoanChargesResponse": { "LoanChargesResponse": {
"$ref": "../swagger/schemas/LoanChargesResponse.json" "$ref": "../swagger/schemas/LoanChargesResponse.json"
}, },
+104
View File
@@ -0,0 +1,104 @@
{
"get": {
"tags": ["RepaymentData"],
"summary": "Get all repayment data with optional filtering",
"description": "Retrieve repayment data records with optional filtering by transaction ID, customer ID, account ID, FBN transaction ID, and added date. Supports pagination.",
"operationId": "getRepaymentData",
"parameters": [
{
"name": "transaction_id",
"in": "query",
"description": "Filter by transaction ID",
"required": false,
"schema": {
"type": "string"
},
"example": "TRX123456789"
},
{
"name": "customer_id",
"in": "query",
"description": "Filter by customer ID",
"required": false,
"schema": {
"type": "string"
},
"example": "CID0000025585"
},
{
"name": "account_id",
"in": "query",
"description": "Filter by account ID",
"required": false,
"schema": {
"type": "string"
},
"example": "ACCT000000123"
},
{
"name": "fbn_transaction_id",
"in": "query",
"description": "Filter by FBN transaction ID",
"required": false,
"schema": {
"type": "string"
},
"example": "FBNTRX7890"
},
{
"name": "added_date",
"in": "query",
"description": "Filter by added date (ISO format)",
"required": false,
"schema": {
"type": "string",
"format": "date-time"
},
"example": "2024-01-01T00:00:00Z"
},
{
"name": "page",
"in": "query",
"description": "Page number for pagination",
"required": false,
"schema": {
"type": "integer",
"default": 1,
"minimum": 1
},
"example": 1
},
{
"name": "limit",
"in": "query",
"description": "Number of items per page (max 100)",
"required": false,
"schema": {
"type": "integer",
"default": 20,
"minimum": 1,
"maximum": 100
},
"example": 20
}
],
"responses": {
"200": {
"description": "Successful operation",
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/RepaymentDataResponse.json"
}
}
}
},
"400": {
"description": "Invalid request"
},
"500": {
"description": "Internal server error"
}
}
}
}
+11
View File
@@ -76,6 +76,17 @@
"example": 10500.0, "example": 10500.0,
"nullable": true "nullable": true
}, },
"balance": {
"type": "number",
"format": "float",
"example": 5000.0,
"nullable": true
},
"reference": {
"type": "string",
"example": "REF12345",
"nullable": true
},
"installment_amount": { "installment_amount": {
"type": "number", "type": "number",
"format": "float", "format": "float",
@@ -0,0 +1,106 @@
{
"type": "object",
"properties": {
"repayment_data": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"example": 1
},
"transaction_id": {
"type": "string",
"example": "TRX123456",
"nullable": false
},
"added_date": {
"type": "string",
"format": "date-time",
"example": "2025-04-10T16:45:47.879Z"
},
"response_code": {
"type": "string",
"example": "00",
"nullable": true
},
"response_descr": {
"type": "string",
"example": "Repayment successful",
"nullable": true
},
"fbn_transaction_id": {
"type": "string",
"example": "FBN123456",
"nullable": true
},
"customer_id": {
"type": "string",
"example": "CID0000025585",
"nullable": true
},
"account_id": {
"type": "string",
"example": "ACCT000000123",
"nullable": true
},
"repayment_amount": {
"type": "number",
"format": "float",
"example": 15000.0,
"nullable": true
},
"amount_collected": {
"type": "number",
"format": "float",
"example": 14500.0,
"nullable": true
},
"balance": {
"type": "number",
"format": "float",
"example": 500.0,
"nullable": true
}
}
}
},
"count": {
"type": "integer",
"example": 1
},
"pagination": {
"type": "object",
"properties": {
"total_count": {
"type": "integer",
"example": 100
},
"total_pages": {
"type": "integer",
"example": 5
},
"current_page": {
"type": "integer",
"example": 1
},
"limit": {
"type": "integer",
"example": 20
},
"has_next": {
"type": "boolean",
"example": true
},
"has_prev": {
"type": "boolean",
"example": false
}
}
}
},
"xml": {
"name": "RepaymentDataResponse"
}
}
@@ -23,6 +23,50 @@
"example": "TRX123456", "example": "TRX123456",
"nullable": true "nullable": true
}, },
"initiated_by": {
"type": "string",
"example": "system",
"nullable": true
},
"salary_amount": {
"type": "number",
"format": "float",
"example": 1000.0,
"nullable": true
},
"repay_date": {
"type": "string",
"format": "date-time",
"example": "2025-04-10T16:45:47.879552Z",
"nullable": true
},
"verify_date": {
"type": "string",
"format": "date-time",
"example": "2025-04-10T16:45:47.879552Z",
"nullable": true
},
"repay_result": {
"type": "string",
"example": "success",
"nullable": true
},
"repay_description": {
"type": "string",
"example": "Repayment processed successfully",
"nullable": true
},
"verify_result": {
"type": "string",
"example": "verified",
"nullable": true
},
"verify_description": {
"type": "string",
"example": "Verification completed successfully",
"nullable": true
},
"created_at": { "created_at": {
"type": "string", "type": "string",
"format": "date-time", "format": "date-time",
+2
View File
@@ -11,6 +11,8 @@ alembic
Flask-Marshmallow==0.15.0 Flask-Marshmallow==0.15.0
marshmallow==3.19.0 marshmallow==3.19.0
python-dateutil==2.9.0
# CORS # CORS
Flask-Cors==3.0.10 Flask-Cors==3.0.10