566 lines
19 KiB
Python
566 lines
19 KiB
Python
# from flask import Flask
|
|
import os
|
|
import psycopg2
|
|
from dotenv import load_dotenv
|
|
from flask_swagger_ui import get_swaggerui_blueprint
|
|
import datetime
|
|
import jwt
|
|
import random
|
|
import json
|
|
import names
|
|
from flask import (
|
|
Flask,
|
|
jsonify,
|
|
send_from_directory,
|
|
request,
|
|
)
|
|
from flask_cors import CORS, cross_origin
|
|
|
|
from functools import wraps
|
|
import json
|
|
import psycopg2.extras
|
|
import pandas as pd
|
|
|
|
from flask_sqlalchemy import SQLAlchemy
|
|
|
|
from sqlalchemy import create_engine
|
|
# import socket
|
|
#import SQLAlchemy
|
|
#from werkzeug.utils import secure_filename
|
|
|
|
load_dotenv()
|
|
|
|
app = Flask(__name__)
|
|
cors = CORS(app) # allow CORS for all domains on all routes.
|
|
|
|
SWAGGER_URL = '/api/docs' # URL for exposing Swagger UI (without trailing '/')
|
|
#API_URL = 'http://petstore.swagger.io/v2/swagger.json' # Our API url (can of course be a local resource)
|
|
API_URL = 'http://localhost:6335/docs/digifi_swagger.json'
|
|
# Call factory function to create our blueprint
|
|
swaggerui_blueprint = get_swaggerui_blueprint(
|
|
SWAGGER_URL, # Swagger UI static files will be mapped to '{SWAGGER_URL}/dist/'m
|
|
API_URL,
|
|
config={ # Swagger UI config overrides
|
|
'app_name': "digiFi-Core"
|
|
},
|
|
# oauth_config={ # OAuth config. See https://github.com/swagger-api/swagger-ui#oauth2-configuration .
|
|
# 'clientId': "your-client-id",
|
|
# 'clientSecret': "your-client-secret-if-required",
|
|
# 'realm': "your-realms",
|
|
# 'appName': "your-app-name",
|
|
# 'scopeSeparator': " ",
|
|
# 'additionalQueryStringParams': {'test': "hello"}
|
|
# }
|
|
)
|
|
|
|
app.register_blueprint(swaggerui_blueprint)
|
|
|
|
dataUrl = os.getenv("DATABASE_URL")
|
|
connection = psycopg2.connect(dataUrl)
|
|
|
|
@app.route('/')
|
|
def hello():
|
|
return "Hello World!"
|
|
|
|
@app.route('/salary/login', methods=["POST"])
|
|
def salary_login():
|
|
try:
|
|
data = request.json
|
|
if not data:
|
|
return {
|
|
"message": "Please provide user details",
|
|
"data": None,
|
|
"error": "Bad request"
|
|
}, 400
|
|
# validate input
|
|
username = data["username"]
|
|
password = data["password"]
|
|
if username == 'digifiuser' and password == 'digifipass' :
|
|
return {
|
|
"message": "Successfully Login",
|
|
"data": [
|
|
{"uid":"425611f2-c692-4404-b93d-76ca7a5ce70","icon": "icon_user", "name": "Simulator User" , "status": '1', "id": 1}
|
|
] }, 201
|
|
else:
|
|
return {
|
|
"message": "Error fetching auth token!, invalid email or password",
|
|
"data": None,
|
|
"error": "Unauthorized"
|
|
}, 404
|
|
|
|
except Exception as e:
|
|
return {
|
|
"message": "Something went wrong!",
|
|
"error": str(e),
|
|
"data": None
|
|
}, 500
|
|
|
|
@app.route('/salary/verifypin', methods=["POST"])
|
|
def salary_verifypin():
|
|
try:
|
|
data = request.json
|
|
if not data:
|
|
return {
|
|
"message": "Please provide pin",
|
|
"data": None,
|
|
"error": "Bad request"
|
|
}, 400
|
|
# validate input
|
|
bvn = data["bvn"]
|
|
pin = data["pin"]
|
|
SELECT_ACC = "SELECT id, uid,pin,bvn FROM demo_bank_accounts WHERE bvn='" + bvn + "' AND pin = '" + pin + "' "
|
|
with connection:
|
|
with connection.cursor(cursor_factory=psycopg2.extras.DictCursor) as cursor:
|
|
cursor.execute(SELECT_ACC)
|
|
account = cursor.fetchall()
|
|
|
|
account_found = count = len( account )
|
|
|
|
if account_found == 1 :
|
|
return {
|
|
"status": "1",
|
|
"data": account
|
|
}, 201
|
|
else:
|
|
return {
|
|
"status": "-1",
|
|
"data": None,
|
|
"message" : "Invalid Pin",
|
|
"error": "1"
|
|
}, 404
|
|
|
|
except Exception as e:
|
|
return {
|
|
"status": "0",
|
|
"error": str(e),
|
|
"message" : "Something went wrong",
|
|
"data": None
|
|
}, 500
|
|
|
|
|
|
|
|
@app.route('/salary/demousers')
|
|
def salary_demousers():
|
|
dList = []
|
|
|
|
|
|
SELECT_DEMO_ENTRY = f"SELECT id,uid, bvn AS CustomerID, mobile AS AccountID, name,offers,salary_account,current_loans,mobile,bvn, email, pin, added::text, balance, updated::text AS updated FROM demo_bank_accounts ORDER BY id ASC"
|
|
# print(SELECT_DEMO_ENTRY)
|
|
with connection:
|
|
with connection.cursor(cursor_factory=psycopg2.extras.DictCursor) as cursor:
|
|
cursor.execute(SELECT_DEMO_ENTRY)
|
|
select_demoS = cursor.fetchall()
|
|
|
|
demo_data = json.dumps( [dict(ix) for ix in select_demoS] )
|
|
result_demo_data = {
|
|
"last_update": datetime.datetime.utcnow(),
|
|
"offers":products(),
|
|
"list" : json.loads( demo_data)
|
|
}
|
|
return {
|
|
"demo_data": result_demo_data,
|
|
}, 200
|
|
|
|
|
|
# VARCHAR(125),
|
|
# offers INT DEFAULT 0,
|
|
# INT DEFAULT 0,
|
|
# current_loans INT DEFAULT 0,
|
|
# VARCHAR(25),
|
|
# VARCHAR(12),
|
|
# VARCHAR(125),
|
|
# VARCHAR(6),
|
|
|
|
# SQL_INSERT = "INSERT INTO demo_bank_accounts (name, salary_account, mobile, bvn, email, pin) VALUES(%s,%s,%s,%s,%s,%s)"
|
|
|
|
# for i in range(900):
|
|
# new_data = (
|
|
# names.get_full_name() ,
|
|
# random.randint(0, 1),
|
|
# '801-000-'+str( random.randint(1000, 9999) ) ,
|
|
# '8315000'+str( random.randint(1000, 9999) ),
|
|
# 'demo+'+ names.get_first_name() +'@chiefsoft.net',
|
|
# random.randint(1100, 9999)
|
|
# )
|
|
#
|
|
# print(new_data)
|
|
# with connection:
|
|
# with connection.cursor(cursor_factory=psycopg2.extras.DictCursor) as cursor:
|
|
# cursor.execute(SQL_INSERT, new_data)
|
|
#
|
|
# print(names.get_full_name())
|
|
|
|
# return jsonify(demo_data=demo_data)
|
|
# print(demo_data)
|
|
|
|
# sample_range = random.randint(2, 5)
|
|
# for x in range(sample_range):
|
|
# calDate = datetime.datetime.utcnow() + datetime.timedelta(minutes=180 * random.randint(1, 20))
|
|
# new_l = {
|
|
# "uid":"425611f2-c692-4404-b93d-76ca7a5ce7"+str(x),
|
|
# "name": names.get_full_name() ,
|
|
# "added": calDate,
|
|
# "offers":random.randint(1, 4),
|
|
# "mobile": '801-000-'+str( random.randint(1000, 9999) ) ,
|
|
# "bvn": '8315000'+str( random.randint(1000, 9999) ),
|
|
# "email": 'demo+'+ names.get_first_name() +'@chiefsoft.net' ,
|
|
# "current_loans" : [],
|
|
# "pin": random.randint(1100, 9999) ,
|
|
# "salary_account": random.randint(0, 1)
|
|
# }
|
|
# dList.append(new_l)
|
|
|
|
|
|
|
|
@app.route('/salary/products')
|
|
def salary_products():
|
|
product_data = {
|
|
"products": products() ,
|
|
"extra" : []
|
|
}
|
|
return {
|
|
"product_data": product_data,
|
|
}, 200
|
|
|
|
@app.route('/salary/loanoffers')
|
|
def salary_loanoffers2():
|
|
offers_data = {
|
|
"offers": offers() ,
|
|
"extra" : []
|
|
}
|
|
return {
|
|
"product_data": offers_data,
|
|
}, 200
|
|
|
|
@app.route('/salary/loanselect', methods=["POST"])
|
|
def salary_loanselect2():
|
|
try:
|
|
data = request.json
|
|
if not data:
|
|
return {
|
|
"message": "Please provide bvn and loan",
|
|
"data": None,
|
|
"error": "Bad request"
|
|
}, 400
|
|
# validate input
|
|
loan = data["loan"]
|
|
bvn = data["bvn"]
|
|
print ("here - 001 ")
|
|
if loan != '' and bvn != '' :
|
|
print ("here - 002 ")
|
|
loan_result = load_offer(loan,bvn)
|
|
INSERT_LOAN ="INSERT INTO loan_select (loan, bvn) VALUES(%s, %s)"
|
|
new_data = (loan,bvn)
|
|
with connection:
|
|
with connection.cursor(cursor_factory=psycopg2.extras.DictCursor) as cursor:
|
|
cursor.execute(INSERT_LOAN, new_data)
|
|
print ("here - 003 ")
|
|
return {
|
|
"message": "REQUEST_AMOUNT",
|
|
"loan": loan,
|
|
"active_loan_count": 0,
|
|
"active_loan": []
|
|
}, 201
|
|
else:
|
|
return {
|
|
"message": "Error fetching loan!, invalid bvn or loan",
|
|
"data": None,
|
|
"error": "Unauthorized"
|
|
}, 404
|
|
|
|
except Exception as e:
|
|
return {
|
|
"message": "Something went wrong!",
|
|
"error": str(e),
|
|
"data": None
|
|
}, 500
|
|
|
|
|
|
@app.route('/salary/loanapply', methods=["POST"])
|
|
def salary_loanapply2():
|
|
try:
|
|
data = request.json
|
|
if not data:
|
|
return {
|
|
"message": "Please provide bvn and loan and amount",
|
|
"data": None,
|
|
"error": "Bad request"
|
|
}, 400
|
|
# validate input
|
|
loan = data["loan"]
|
|
bvn = data["bvn"]
|
|
amount = data["amount"]
|
|
if loan != '' and bvn != '' and amount > 0 :
|
|
loan_read = load_offer(loan,bvn)
|
|
UPDATE_LOAN ="UPDATE loan_apply SET status=3 WHERE bvn = '" + bvn + "' AND status = 1 "
|
|
INSERT_LOAN ="INSERT INTO loan_apply (loan, bvn, amount) VALUES(%s, %s, %s)"
|
|
SELECT_LOAN ="SELECT uid FROM loan_apply WHERE loan = '" + loan + "' AND bvn = '" + bvn + "' AND status = 1 ORDER BY id DESC LIMIT 1"
|
|
new_data = (loan,bvn, amount)
|
|
with connection:
|
|
with connection.cursor(cursor_factory=psycopg2.extras.DictCursor) as cursor:
|
|
cursor.execute(INSERT_LOAN, new_data)
|
|
|
|
with connection:
|
|
with connection.cursor(cursor_factory=psycopg2.extras.DictCursor) as cursor:
|
|
cursor.execute(SELECT_LOAN)
|
|
loan_record = cursor.fetchall()
|
|
|
|
loan_found = count = len( loan_record )
|
|
|
|
return {
|
|
"message": "REQUEST_PIN",
|
|
"bvn" : bvn,
|
|
"loan_application_id": loan_record[0],
|
|
"active_loan_count": 0,
|
|
"active_loan": []
|
|
}, 201
|
|
else:
|
|
return {
|
|
"message": "Error fetching loan!, invalid bvn or loan or amount",
|
|
"data": None,
|
|
"error": "Unauthorized"
|
|
}, 404
|
|
|
|
except Exception as e:
|
|
return {
|
|
"message": "Something went wrong!",
|
|
"error": str(e),
|
|
"data": None
|
|
}, 500
|
|
|
|
|
|
@app.route('/salary/verifloan', methods=["POST"])
|
|
def salary_verifloan2():
|
|
try:
|
|
data = request.json
|
|
if not data:
|
|
return {
|
|
"message": "Please provide pin, bvn and loan_application_id",
|
|
"data": None,
|
|
"error": "Bad request"
|
|
}, 400
|
|
# validate input
|
|
bvn = data["bvn"]
|
|
pin = data["pin"]
|
|
loan_application_id = data["loan_application_id"]
|
|
|
|
# loan_read = load_offer(loan,bvn)
|
|
|
|
SELECT_ACC = "SELECT id, uid,pin,bvn FROM demo_bank_accounts WHERE bvn='" + bvn + "' AND pin = '" + pin + "' "
|
|
print(SELECT_ACC)
|
|
with connection:
|
|
with connection.cursor(cursor_factory=psycopg2.extras.DictCursor) as cursor:
|
|
cursor.execute(SELECT_ACC)
|
|
account = cursor.fetchall()
|
|
|
|
account_found = count = len( account )
|
|
print("10000-a")
|
|
if account_found == 1 :
|
|
UPDATE_APPLICATION = "UPDATE loan_apply SET verified = now(), due_date = now() + '30 days' , status=5 WHERE uid::text = '" + loan_application_id + "' AND status = 1"
|
|
print(UPDATE_APPLICATION)
|
|
with connection.cursor(cursor_factory=psycopg2.extras.DictCursor) as cursor:
|
|
cursor.execute(UPDATE_APPLICATION)
|
|
|
|
# loan_schedule = loan_create(bvn,loan_application_id)
|
|
return {
|
|
"qr": UPDATE_APPLICATION,
|
|
"status": "1",
|
|
"message" : "Loan Verified",
|
|
"data": account
|
|
}, 201
|
|
else:
|
|
return {
|
|
"status": "-1",
|
|
"data": None,
|
|
"message" : "Invalid Loan or PIN",
|
|
"error": "1"
|
|
}, 404
|
|
|
|
# let us verify the loan too with the UID
|
|
|
|
|
|
except Exception as e:
|
|
return {
|
|
"status": "0",
|
|
"error": str(e),
|
|
"message" : "Something went wrong",
|
|
"data": None
|
|
}, 500
|
|
|
|
def loan_create(bvn,loan_application_uid):
|
|
SELECT_LOAN = "SELECT uid,loan,bvn,amount,added,verified,status,due_date FROM loan_apply WHERE uid::text = '" + loan_application_uid + "' AND bvn ='" + bvn + "' "
|
|
with connection:
|
|
with connection.cursor(cursor_factory=psycopg2.extras.DictCursor) as cursor:
|
|
cursor.execute(SELECT_LOAN)
|
|
select_demoS = cursor.fetchall()
|
|
|
|
loan_data = json.dumps( [dict(ix) for ix in select_demoS] )
|
|
loan_result = json.loads( loan_data )
|
|
|
|
return loan_result
|
|
|
|
def products():
|
|
product_data = [
|
|
{"cid": "1", "description": "Product Loan 01" , "active" : 0 },
|
|
{"cid": "2", "description": "Product Loan 02" , "active" : 0 },
|
|
{"cid": "3", "description": "First Advance" , "active" : 1 },
|
|
]
|
|
return product_data
|
|
|
|
def load_offer(loan,bvn):
|
|
OFFER_QUERY = "SELECT uid AS cid,loan,amount,description,days_duration,active FROM loan_offers WHERE loan='" + loan +"' LIMIT 1"
|
|
with connection:
|
|
with connection.cursor(cursor_factory=psycopg2.extras.DictCursor) as cursor:
|
|
cursor.execute(OFFER_QUERY)
|
|
select_demoS = cursor.fetchall()
|
|
|
|
loan_data = json.dumps( [dict(ix) for ix in select_demoS] )
|
|
loan_result = json.loads( loan_data )
|
|
return json.loads( loan_data )
|
|
|
|
def offers():
|
|
OFFER_QUERY = "SELECT uid AS cid,loan,amount,description,days_duration,active FROM loan_offers ORDER BY amount ASC"
|
|
with connection:
|
|
with connection.cursor(cursor_factory=psycopg2.extras.DictCursor) as cursor:
|
|
cursor.execute(OFFER_QUERY)
|
|
select_demoS = cursor.fetchall()
|
|
|
|
demo_data = json.dumps( [dict(ix) for ix in select_demoS] )
|
|
return json.loads( demo_data)
|
|
#
|
|
# offers_data = [
|
|
# {"cid": "425611f2-c692-4404-b93d-76ca7a5ce00", "description": "100,000 Naira for 30 Days" , "active" : 1 },
|
|
# {"cid": "425611f2-c692-4404-b93d-76ca7a5ce01", "description": "300,000 Naira for 60 Days" , "active" : 1 },
|
|
# {"cid": "425611f2-c692-4404-b93d-76ca7a5ce02", "description": "900,000 Naira for 90 Days" , "active" : 1 },
|
|
# ]
|
|
# return offers_data
|
|
|
|
|
|
def offers_detail(offer_id):
|
|
offer_detail = [
|
|
{"cid": "425611f2-c692-4404-b93d-76ca7a5ce00", "description": "100,000 Naira for 30 Days" , "active" : 1 },
|
|
{"cid": "425611f2-c692-4404-b93d-76ca7a5ce01", "description": "300,000 Naira for 60 Days" , "active" : 1 },
|
|
{"cid": "425611f2-c692-4404-b93d-76ca7a5ce02", "description": "900,000 Naira for 90 Days" , "active" : 1 },
|
|
]
|
|
return offer_detail
|
|
|
|
|
|
@app.route('/office/auth')
|
|
def office_login():
|
|
result_data = {
|
|
"data": [],
|
|
"extra" : []
|
|
}
|
|
return {
|
|
"result_data": result_data,
|
|
}, 200
|
|
|
|
@app.route('/office/loan/select')
|
|
def loan_select():
|
|
result_data = {
|
|
"data": office_loan_data_select('SELECT'),
|
|
"extra" : []
|
|
}
|
|
return {
|
|
"result_data": result_data,
|
|
}, 200
|
|
|
|
@app.route('/office/loan/apply')
|
|
def loan_apply():
|
|
result_data = {
|
|
"data": office_loan_data('APPLY'),
|
|
"extra" : []
|
|
}
|
|
return {
|
|
"result_data": result_data,
|
|
}, 200
|
|
|
|
@app.route('/office/loan/approved')
|
|
def loan_approved():
|
|
result_data = {
|
|
"data": office_loan_data('APPROVED'),
|
|
"extra" : []
|
|
}
|
|
return {
|
|
"result_data": result_data,
|
|
}, 200
|
|
|
|
def office_loan_data_select(loanLevel):
|
|
|
|
SELECT_Q = f'''SELECT ls.id,ls.added::text, dm.name,dm.mobile, ls.bvn , ls.loan,lo.description FROM loan_select ls LEFT JOIN loan_offers lo ON lo.loan=ls.loan
|
|
LEFT JOIN demo_bank_accounts dm ON dm.bvn = ls.bvn ORDER BY ls.id DESC LIMIT 300 '''
|
|
|
|
with connection:
|
|
with connection.cursor(cursor_factory=psycopg2.extras.DictCursor) as cursor:
|
|
cursor.execute(SELECT_Q)
|
|
select_demoS = cursor.fetchall()
|
|
|
|
demo_data = json.dumps( [dict(ix) for ix in select_demoS] )
|
|
return json.loads( demo_data)
|
|
|
|
def office_loan_data(loanLevel):
|
|
# public | loan_apply | table | salaryloan
|
|
# public | loan_select | table | salaryloan
|
|
|
|
SELECT_Q = f'''SELECT ls.id,ls.added::text, dm.name,dm.mobile, ls.bvn , ls.loan,lo.description FROM loan_select ls LEFT JOIN loan_offers lo ON lo.loan=ls.loan
|
|
LEFT JOIN demo_bank_accounts dm ON dm.bvn = ls.bvn ORDER BY ls.id DESC LIMIT 300 '''
|
|
|
|
if loanLevel == "APPLY":
|
|
SELECT_Q = f'''SELECT ls.id,ls.added::text, dm.name,dm.mobile, ls.bvn , ls.loan,lo.description,ls.amount,ls.verified::text FROM loan_apply ls LEFT JOIN loan_offers lo ON lo.loan=ls.loan
|
|
LEFT JOIN demo_bank_accounts dm ON dm.bvn = ls.bvn ORDER BY ls.id DESC LIMIT 300'''
|
|
|
|
with connection:
|
|
with connection.cursor(cursor_factory=psycopg2.extras.DictCursor) as cursor:
|
|
cursor.execute(SELECT_Q)
|
|
select_demoS = cursor.fetchall()
|
|
|
|
demo_data = json.dumps( [dict(ix) for ix in select_demoS] )
|
|
return json.loads( demo_data)
|
|
|
|
@app.route('/office/offers')
|
|
def offer_offers():
|
|
OFFER_QUERY = "SELECT uid AS cid,loan,amount,description,days_duration,active,score,lorder FROM loan_offers "
|
|
with connection:
|
|
with connection.cursor(cursor_factory=psycopg2.extras.DictCursor) as cursor:
|
|
cursor.execute(OFFER_QUERY)
|
|
select_demoS = cursor.fetchall()
|
|
|
|
loan_data = json.dumps( [dict(ix) for ix in select_demoS] )
|
|
loan_result = json.loads( loan_data)
|
|
return loan_result
|
|
|
|
@app.route('/loan/info')
|
|
def pending_loans():
|
|
offer_detail = [
|
|
{"loan_id": "425611f2-c692-4404-b93d-76ca7a5ce00", "description": "Total amount to replay N50,000" , "active" : 1 },
|
|
{"loan_id": "425611f2-c692-4404-b93d-76ca7a5ce01", "description": "Total amount to replay N150,000" , "active" : 1 },
|
|
{"loan_id": "425611f2-c692-4404-b93d-76ca7a5ce02", "description": "Total amount to replay N300,000" , "active" : 1 },
|
|
]
|
|
return offer_detail
|
|
|
|
@app.route('/loan/repay', methods=["POST"])
|
|
def repay_loans():
|
|
# try:
|
|
# data = request.json
|
|
# if not data:
|
|
# return {
|
|
# "message": "Please provide pin,loan_id,accountID",
|
|
# "data": None,
|
|
# "error": "Bad request"
|
|
# }, 400
|
|
# validate input
|
|
# bvn = data["bvn"]
|
|
# accountid = data["accountid"]
|
|
# loan_id = data["bvn"]
|
|
|
|
offer_detail = [
|
|
{"cid": "425611f2-c692-4404-b93d-76ca7a5ce00", "description": "Total amount to replay N50,000" , "active" : 1 },
|
|
{"cid": "425611f2-c692-4404-b93d-76ca7a5ce01", "description": "Total amount to replay N150,000" , "active" : 1 },
|
|
{"cid": "425611f2-c692-4404-b93d-76ca7a5ce02", "description": "Total amount to replay N300,000" , "active" : 1 },
|
|
]
|
|
return offer_detail
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
app.run(host='0.0.0.0', port=8000) |