Compare commits

..

3 Commits

Author SHA1 Message Date
VivianDee dc21f41894 [add]: transaction offer fix 2025-05-10 10:04:06 +01:00
VivianDee 17db2cf8f9 Merge branch 'master' of https://gitlab.chiefsoft.net/DigiFi/digifi-BankToProductCore 2025-05-10 08:53:09 +01:00
VivianDee f07866a884 [add]: transaction fix 2025-05-10 08:50:10 +01:00
8 changed files with 47 additions and 207 deletions
+30 -46
View File
@@ -8,8 +8,6 @@ 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
@@ -80,53 +78,39 @@ class EligibilityCheckService(BaseService):
return jsonify({
"message": "Failed to save RACCheck."
}), 400
# -----------------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
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
)
except ValueError as ve:
logger.error(str(ve))
return jsonify({
"message": str(ve)
}), 400
# -----------------------------------------------------------------------
# s = Offer.get_all_offers()
# eligible_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}"
# 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
# })
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 = {
+4 -64
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,68 +30,8 @@ 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
+5 -2
View File
@@ -80,6 +80,7 @@ class ProvideLoanService(BaseService):
# "message": "Invalid Offer."
# }), 400
# Log Transaction
transaction = ProvideLoanService.log_transaction(validated_data=validated_data)
@@ -107,6 +108,7 @@ class ProvideLoanService(BaseService):
vat = charges["vat"]
# Save the loan details
loan = Loan.create_loan(
customer_id = customer_id,
@@ -115,7 +117,7 @@ class ProvideLoanService(BaseService):
product_id = offer.product_id,
collection_type = collection_type,
transaction_id = validated_data.get('transactionId'),
original_transaction = transaction_offer.original_transaction,
original_transaction = validated_data.get('transactionId'),
initial_loan_amount = validated_data.get('requestedAmount'),
upfront_fee = upfront_fee,
repayment_amount = repayment_amount,
@@ -123,6 +125,7 @@ class ProvideLoanService(BaseService):
eligible_amount=eligible_amount,
status = LoanStatus.ACTIVE,
tenor = offer.tenor,
)
if not loan:
@@ -144,7 +147,7 @@ class ProvideLoanService(BaseService):
# charges = Charge.get_offer_charges(offer.id)
# logger.info(f"{charges}")
logger.info(f"{charges}")
loan_id = loan.id
+1 -1
View File
@@ -35,10 +35,10 @@ class SelectOfferService(BaseService):
transaction_offer_id = validated_data.get("offerId")
transaction_id = validated_data.get("transactionId")
request_id = validated_data.get("requestId")
offer_id = int(transaction_offer_id[5:]) # The last part is int
#"offerId": "SAL30001129",
if SelectOfferService.validate_account_ownership(
account_id=account_id, customer_id=customer_id
+3 -23
View File
@@ -38,8 +38,6 @@ 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",
@@ -138,16 +136,12 @@ class Loan(db.Model):
return loan
@classmethod
def get_customer_last_loan(cls, customer_id):
def get_customer_current_active_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,
@@ -155,25 +149,11 @@ class Loan(db.Model):
"transaction_id": "",
"resultDescription": "No Active Loan"
}
logger.info(f" Active Loan ==>>>> RESULT*********************")
logger.info(f" Active Loan ==>>>> {loan}")
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):
"""
+4 -5
View File
@@ -8,7 +8,6 @@ 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)
@@ -27,27 +26,27 @@ class TransactionOffer(db.Model):
)
@classmethod
def is_valid_transaction_offer(cls, offer_id, customer_id, product_id):
def is_valid_transaction_offer(cls, transaction_offer_id, customer_id, product_id):
transaction_offer = cls.query.filter_by(
id = str(offer_id),
id = transaction_offer_id,
customer_id = customer_id,
# product_id = product_id
# transaction_id = transaction_id,
).first()
if not transaction_offer:
return False
return transaction_offer
@classmethod
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):
def create_transaction_offer(cls, customer_id, transaction_id, 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,
@@ -1,32 +0,0 @@
"""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 ###
@@ -1,34 +0,0 @@
"""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 ###