Compare commits

...

19 Commits

Author SHA1 Message Date
Fluxtra 6d743ea09b Update offer_analysis.py 2025-05-10 15:42:09 +01:00
Fluxtra 4718c9c50b Update loan.py 2025-05-10 15:34:43 +01:00
Fluxtra feb97c3fa8 Update loan.py 2025-05-10 15:32:11 +01:00
Fluxtra 4bcaa3d13d Update loan.py 2025-05-10 15:30:15 +01:00
Fluxtra d6faa14b54 Merge branch 'define_offers' of https://gitlab.chiefsoft.net/DigiFi/digifi-BankToProductCore into define_offers 2025-05-10 14:57:48 +01:00
Fluxtra 332c344efa [fix]: Indentation 2025-05-10 14:47:52 +01:00
CHIEFSOFT\ameye e377858c47 removed comments 2025-05-10 09:43:21 -04:00
ameye ed64d2c97c Merge branch 'define_offers' of DigiFi/digifi-BankToProductCore into master 2025-05-10 13:34:36 +00:00
Fluxtra bbdb7214d1 [add]: define offers update 2025-05-10 14:24:05 +01:00
ameye e9c50f75b1 disburse migration 2025-05-10 08:55:38 -04:00
CHIEFSOFT\ameye c330c3f0e7 disburse_date 2025-05-10 08:54:08 -04:00
CHIEFSOFT\ameye 976fb14614 This ensures the progragation of original transaction id 2025-05-10 07:53:35 -04:00
CHIEFSOFT\ameye 334cb0f2d6 Staered 2025-05-10 06:58:17 -04:00
CHIEFSOFT\ameye 40158b1c54 Analysis steps 2025-05-10 06:20:03 -04:00
ameye b7ae0e6baa New original transaction on offer 2025-05-10 05:55:53 -04:00
CHIEFSOFT\ameye 89b621b9a8 Original Transaction id on offers 2025-05-10 05:53:32 -04:00
CHIEFSOFT\ameye cc3cd5b72b Customer id fix 2025-05-10 05:33:04 -04:00
CHIEFSOFT\ameye f573d5e643 transaction_id 2025-05-10 05:17:28 -04:00
CHIEFSOFT\ameye 09b57d81a2 Moved offer decide 2025-05-10 05:14:53 -04:00
7 changed files with 206 additions and 42 deletions
+46 -30
View File
@@ -8,6 +8,8 @@ from app.api.enums import TransactionType
from app.api.integrations import SimbrellaIntegration
from app.extensions import db
from app.models import Offer, RACCheck
from app.api.services.offer_analysis import OfferAnalysis
import random
@@ -78,39 +80,53 @@ class EligibilityCheckService(BaseService):
return jsonify({
"message": "Failed to save RACCheck."
}), 400
offers = Offer.get_all_offers()
eligible_offers = []
for offer in offers:
# Determine an approved amount
random_float = random.random() # temporary to play data
approved_amount = min(offer.max_amount, offer.max_amount * random_float) #temporary for now
approved_amount = round(approved_amount, 2)
transaction_offer = TransactionOffer.create_transaction_offer(
customer_id = customer.id,
transaction_id = transaction.transaction_id,
offer_id = offer.id,
min_amount = offer.min_amount,
max_amount = offer.max_amount,
eligible_amount = approved_amount,
product_id = offer.product_id,
tenor = offer.tenor
# -----------------TIME FOR ANALYSIS TO REGISTER OFFER ----------------------
# eligible_offers = []
try:
eligible_offers = OfferAnalysis.decide_offer(
transaction_id=transactionId,
rac_check=rac_check,
validated_data=validated_data,
customer=customer
)
except ValueError as ve:
logger.error(str(ve))
return jsonify({
"message": str(ve)
}), 400
# -----------------------------------------------------------------------
# s = Offer.get_all_offers()
# Visible offer ID: offer_id + padded(transaction_offer.id)
padded_id = str(transaction_offer.id).zfill(6)
public_offer_id = f"{offer.id}{padded_id}"
# eligible_offers = []
eligible_offers.append({
"offerId": public_offer_id,
"product_id": offer.product_id,
"min_amount": offer.min_amount,
"max_amount": approved_amount,
"tenor": offer.tenor
})
# for offer in offers:
# # Determine an approved amount
# random_float = random.random() # temporary to play data
# approved_amount = min(offer.max_amount, offer.max_amount * random_float) #temporary for now
# approved_amount = round(approved_amount, 2)
#
# transaction_offer = TransactionOffer.create_transaction_offer(
# customer_id = customer.id,
# transaction_id = transaction.transaction_id,
# offer_id = offer.id,
# min_amount = offer.min_amount,
# max_amount = offer.max_amount,
# eligible_amount = approved_amount,
# product_id = offer.product_id,
# tenor = offer.tenor
# )
#
# # Visible offer ID: offer_id + padded(transaction_offer.id)
# padded_id = str(transaction_offer.id).zfill(6)
# public_offer_id = f"{offer.id}{padded_id}"
#
# eligible_offers.append({
# "offerId": public_offer_id,
# "product_id": offer.product_id,
# "min_amount": offer.min_amount,
# "max_amount": approved_amount,
# "tenor": offer.tenor
# })
# Simulate processing
response_data = {
+64 -4
View File
@@ -1,6 +1,6 @@
from app.models import Offer, TransactionOffer
from app.models.loan import Loan
import random
import logging
logger = logging.getLogger(__name__)
@@ -30,8 +30,68 @@ class OfferAnalysis:
if not offer:
raise ValueError("Invalid Offer.")
original_transaction = transaction_id
# we can now find the origin transactions
customer_loan = Loan.get_customer_current_active_loan(customer_id)
return transaction_offer, offer, eligible_amount, original_transaction
@staticmethod
def decide_offer(transaction_id, rac_check, validated_data, customer):
# if we have active offers - we have to feed off it
# we can now find the origin transactions
# Find the last loan - it will have original_transaction
# last_customer_loan = Loan.get_customer_last_loan(customer.id)
# logger.info(f"{last_customer_loan}")
new_eligible_amount = 0
# if last_customer_loan:
# original_transaction = last_customer_loan.original_transaction or last_customer_loan.transaction_id
# real_eligible_amount = last_customer_loan.eligible_amount
# active_loans = Loan.get_active_loans_by_original_transaction(original_transaction)
# sum_active_loans = sum(loan.current_loan_amount for loan in active_loans)
# new_eligible_amount = max(real_eligible_amount - sum_active_loans, 0)
# logger.info(f"Real eligible: {real_eligible_amount}, Sum of active: {sum_active_loans}, New eligible: {new_eligible_amount}")
# Construct eligible_offers
offers = Offer.get_all_offers()
eligible_offers = []
for offer in offers:
# Get approved amount
random_float = random.random() # temporary to play data
approved_amount = new_eligible_amount if new_eligible_amount > 0 else min(offer.max_amount, offer.max_amount * random_float)
approved_amount = round(approved_amount, 2)
transaction_offer = TransactionOffer.create_transaction_offer(
customer_id=customer.id,
transaction_id=transaction_id,
original_transaction=transaction_id,
offer_id=offer.id,
min_amount=offer.min_amount,
max_amount=offer.max_amount,
eligible_amount=approved_amount,
product_id=offer.product_id,
tenor=offer.tenor
)
# Visible offer ID: offer_id + padded(transaction_offer.id)
padded_id = str(transaction_offer.id).zfill(6)
public_offer_id = f"{offer.id}{padded_id}"
eligible_offers.append({
"offerId": public_offer_id,
"product_id": offer.product_id,
"min_amount": offer.min_amount,
"max_amount": approved_amount,
"tenor": offer.tenor
})
return eligible_offers
+2 -4
View File
@@ -107,7 +107,6 @@ class ProvideLoanService(BaseService):
vat = charges["vat"]
# Save the loan details
loan = Loan.create_loan(
customer_id = customer_id,
@@ -116,7 +115,7 @@ class ProvideLoanService(BaseService):
product_id = offer.product_id,
collection_type = collection_type,
transaction_id = validated_data.get('transactionId'),
original_transaction = validated_data.get('transactionId'),
original_transaction = transaction_offer.original_transaction,
initial_loan_amount = validated_data.get('requestedAmount'),
upfront_fee = upfront_fee,
repayment_amount = repayment_amount,
@@ -124,7 +123,6 @@ class ProvideLoanService(BaseService):
eligible_amount=eligible_amount,
status = LoanStatus.ACTIVE,
tenor = offer.tenor,
)
if not loan:
@@ -146,7 +144,7 @@ class ProvideLoanService(BaseService):
# charges = Charge.get_offer_charges(offer.id)
logger.info(f"{charges}")
# logger.info(f"{charges}")
loan_id = loan.id
+25 -3
View File
@@ -6,6 +6,8 @@ from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import relationship
from dateutil.relativedelta import relativedelta
from datetime import timedelta
import logging
logger = logging.getLogger(__name__)
class Loan(db.Model):
@@ -36,6 +38,8 @@ class Loan(db.Model):
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))
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)
customer = relationship(
"Customer",
@@ -134,12 +138,16 @@ class Loan(db.Model):
return loan
@classmethod
def get_customer_current_active_loan(cls, customer_id):
def get_customer_last_loan(cls, customer_id):
"""
Get customer's active loans.
"""
logger.info(f"Find last loan for [customer_id] ==>>>> {customer_id}")
loan = cls.query.filter_by( customer_id = customer_id).first()
logger.info(f" Active Loan ==>>>> RESULT************************ AMEYE")
if not loan:
return None
loan = {
"eligible_amount": 0,
"loan_amount": 0,
@@ -147,11 +155,25 @@ class Loan(db.Model):
"transaction_id": "",
"resultDescription": "No Active Loan"
}
logger.info(f" Active Loan ==>>>> {loan}")
logger.info(f" Active Loan ==>>>> RESULT*********************")
logger.info(f" Active Loan ==>>>> {loan}")
return loan
@classmethod
def get_active_loans_by_original_transaction(cls, original_transaction_id):
"""
Get all active loans with the same original_transaction ID.
"""
active_loans = cls.query.filter_by(
original_transaction=original_transaction_id,
# status='active'
).all()
return active_loans
@classmethod
def update_status(cls, loan_id, status):
"""
+3 -1
View File
@@ -8,6 +8,7 @@ class TransactionOffer(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
customer_id = db.Column(db.String(50), nullable=False)
transaction_id = db.Column(db.String(50), nullable=False)
original_transaction = db.Column(db.String(50), nullable=True)
offer_id = db.Column(db.String(20), nullable=False)
product_id = db.Column(db.String(20), nullable=True)
min_amount = db.Column(db.Float, nullable=False)
@@ -39,13 +40,14 @@ class TransactionOffer(db.Model):
return transaction_offer
@classmethod
def create_transaction_offer(cls, customer_id, transaction_id, offer_id, min_amount, max_amount, eligible_amount=None, product_id=None, tenor=None):
def create_transaction_offer(cls, customer_id, transaction_id, original_transaction, offer_id, min_amount, max_amount, eligible_amount=None, product_id=None, tenor=None):
"""
Class method to create and save a TransactionOffer.
"""
transaction_offer = cls(
customer_id=customer_id,
transaction_id=transaction_id,
original_transaction=original_transaction,
offer_id=offer_id,
min_amount=min_amount,
max_amount=max_amount,
@@ -0,0 +1,32 @@
"""Migration on Sat May 10 09:54:34 UTC 2025
Revision ID: 173ea45db189
Revises: 3105abd795d4
Create Date: 2025-05-10 09:54:39.380499
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '173ea45db189'
down_revision = '3105abd795d4'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('transaction_offers', schema=None) as batch_op:
batch_op.add_column(sa.Column('original_transaction', sa.String(length=50), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('transaction_offers', schema=None) as batch_op:
batch_op.drop_column('original_transaction')
# ### end Alembic commands ###
@@ -0,0 +1,34 @@
"""Migration on Sat May 10 12:54:52 UTC 2025
Revision ID: 565bc3d0ba6e
Revises: 173ea45db189
Create Date: 2025-05-10 12:54:56.683215
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '565bc3d0ba6e'
down_revision = '173ea45db189'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('loans', schema=None) as batch_op:
batch_op.add_column(sa.Column('disburse_date', sa.DateTime(), nullable=True))
batch_op.add_column(sa.Column('disburse_verify', sa.DateTime(), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('loans', schema=None) as batch_op:
batch_op.drop_column('disburse_verify')
batch_op.drop_column('disburse_date')
# ### end Alembic commands ###