From 92eadbfa165949969d34bfb683c681f4b0abfa3c Mon Sep 17 00:00:00 2001 From: VivianDee <115420678+VivianDee@users.noreply.github.com> Date: Tue, 29 Apr 2025 08:26:41 +0100 Subject: [PATCH] [update]: Eligibility check --- app/api/services/eligibility_check.py | 34 +++++++++++++- app/models/__init__.py | 3 +- app/models/customer.py | 7 +++ app/models/transaction_offers.py | 66 +++++++++++++++++++++++++++ migrations/versions/86e701febdda_.py | 41 +++++++++++++++++ 5 files changed, 148 insertions(+), 3 deletions(-) create mode 100644 app/models/transaction_offers.py create mode 100644 migrations/versions/86e701febdda_.py diff --git a/app/api/services/eligibility_check.py b/app/api/services/eligibility_check.py index 6cdf075..52b0f13 100644 --- a/app/api/services/eligibility_check.py +++ b/app/api/services/eligibility_check.py @@ -1,4 +1,5 @@ from flask import session, jsonify +from app.models.transaction_offers import TransactionOffer from app.utils.logger import logger from app.api.services.base_service import BaseService from app.api.schemas.eligibility_check import EligibilityCheckSchema @@ -61,7 +62,36 @@ class EligibilityCheckService(BaseService): if response.status_code != 200: return jsonify({"message": "RACCheck failed"}), 400 - offers = [offer.to_dict() for offer in Offer.get_all_offers()] + offers = Offer.get_all_offers() + + eligible_offers = [] + + for offer in offers: + # Determine an approved amount + approved_amount = min(offer.max_amount, 5000) + + transaction_offer = TransactionOffer.create_transaction_offer( + customer_id = customer.id, + transaction_id = 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 = { @@ -69,7 +99,7 @@ class EligibilityCheckService(BaseService): "transactionId": transactionId, "countryCode": "NG", "msisdn": msisdn, - "eligibleOffers": offers, + "eligibleOffers": eligible_offers, "resultDescription": "Successful", "resultCode": "00", "accountId": account_id diff --git a/app/models/__init__.py b/app/models/__init__.py index 9fa2f1e..de05d55 100644 --- a/app/models/__init__.py +++ b/app/models/__init__.py @@ -8,6 +8,7 @@ from .offer import Offer from .charge import Charge from .rac_checks import RACCheck from .loan_repayment_schedule import LoanRepaymentSchedule +from .transaction_offers import TransactionOffer -__all__ = ['Customer', 'Account', 'Loan', 'Transaction', 'Repayment', 'LoanCharge', 'Offer', 'Charge', 'RACCheck', 'LoanRepaymentSchedule'] \ No newline at end of file +__all__ = ['Customer', 'Account', 'Loan', 'Transaction', 'Repayment', 'LoanCharge', 'Offer', 'Charge', 'RACCheck', 'LoanRepaymentSchedule', 'TransactionOffer'] \ No newline at end of file diff --git a/app/models/customer.py b/app/models/customer.py index c601efe..4b6382a 100644 --- a/app/models/customer.py +++ b/app/models/customer.py @@ -27,6 +27,13 @@ class Customer(db.Model): back_populates="customer", ) + transaction_offers = relationship( + "TransactionOffer", + primaryjoin="Customer.id == TransactionOffer.customer_id", + foreign_keys="TransactionOffer.customer_id", + back_populates="customer", + ) + @classmethod def is_valid_customer(cls, customer_id): customer = cls.query.filter_by(id=customer_id).first() diff --git a/app/models/transaction_offers.py b/app/models/transaction_offers.py new file mode 100644 index 0000000..df9b0b9 --- /dev/null +++ b/app/models/transaction_offers.py @@ -0,0 +1,66 @@ +from datetime import datetime, timezone +from app.extensions import db +from sqlalchemy.orm import relationship + +class TransactionOffer(db.Model): + __tablename__ = 'transaction_offers' + + 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) + 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) + max_amount = db.Column(db.Float, nullable=False) + eligible_amount = db.Column(db.Float, nullable=True) + tenor = db.Column(db.Integer, nullable=True) # tenor in months, typically + + 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)) + + customer = relationship( + "Customer", + primaryjoin="Customer.id == TransactionOffer.customer_id", + foreign_keys=[customer_id], + back_populates="transaction_offers", + ) + + + @classmethod + 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, + offer_id=offer_id, + min_amount=min_amount, + max_amount=max_amount, + eligible_amount=eligible_amount, + product_id=product_id, + tenor=tenor + ) + + db.session.add(transaction_offer) + db.session.flush() + + return transaction_offer + + def to_dict(self): + return { + 'id': self.id, + 'customerId': self.customer_id, + 'transactionId': self.transaction_id, + 'offerId': self.offer_id, + 'productId': self.product_id, + 'minAmount': self.min_amount, + 'maxAmount': self.max_amount, + 'eligibleAmount': self.eligible_amount, + 'tenor': self.tenor, + 'createdAt': self.created_at.isoformat() if self.created_at else None, + 'updatedAt': self.updated_at.isoformat() if self.updated_at else None, + } + + def __repr__(self): + return f'' diff --git a/migrations/versions/86e701febdda_.py b/migrations/versions/86e701febdda_.py new file mode 100644 index 0000000..5f54178 --- /dev/null +++ b/migrations/versions/86e701febdda_.py @@ -0,0 +1,41 @@ +"""empty message + +Revision ID: 86e701febdda +Revises: eb99c7fb9e09 +Create Date: 2025-04-29 07:59:33.305967 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '86e701febdda' +down_revision = 'eb99c7fb9e09' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('transaction_offers', + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('customer_id', sa.String(length=50), nullable=False), + sa.Column('transaction_id', sa.String(length=50), nullable=False), + sa.Column('offer_id', sa.String(length=20), nullable=False), + sa.Column('product_id', sa.String(length=20), nullable=True), + sa.Column('min_amount', sa.Float(), nullable=False), + sa.Column('max_amount', sa.Float(), nullable=False), + sa.Column('eligible_amount', sa.Float(), nullable=True), + sa.Column('tenor', sa.Integer(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('transaction_offers') + # ### end Alembic commands ### -- 2.34.1