diff --git a/Dockerfile b/Dockerfile index 0bc8e59..8bd47b3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ WORKDIR /app COPY . /app # Install dependencies -RUN pip install --no-cache-dir -r requirements.txt +RUN pip install --no-cache-dir -r requirements.txt --verbose # Expose port 5000 for the Flask app EXPOSE 5000 diff --git a/app/__init__.py b/app/__init__.py index 732af48..d2fab1c 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -7,10 +7,7 @@ from app.api.routes import api from app.errors import register_error_handlers from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate - - -db = SQLAlchemy() -migrate = Migrate() +from app.extensions import db, migrate def create_app(): """ Factory function to create a Flask app instance """ diff --git a/app/api/enums/__init__.py b/app/api/enums/__init__.py new file mode 100644 index 0000000..cf543fd --- /dev/null +++ b/app/api/enums/__init__.py @@ -0,0 +1 @@ +from .transaction_type import transaction_type \ No newline at end of file diff --git a/app/api/enums/transaction_type.py b/app/api/enums/transaction_type.py new file mode 100644 index 0000000..2f5ac09 --- /dev/null +++ b/app/api/enums/transaction_type.py @@ -0,0 +1,6 @@ +from enum import Enum + +class transaction_type(str, Enum): + ELIGIBILITY_CHECK = "eligibility_check" + PAYMENT = "payment" + REPAYMENT = "repayment" diff --git a/app/api/services/base_service.py b/app/api/services/base_service.py new file mode 100644 index 0000000..02e73c2 --- /dev/null +++ b/app/api/services/base_service.py @@ -0,0 +1,28 @@ +from app.models import Transaction +from app.api.enums import transaction_type +from flask import jsonify +from marshmallow import ValidationError +import logging + +logger = logging.getLogger(__name__) + +class BaseService: + TRANSACTION_TYPE = None + + @classmethod + def log_transaction(cls, data, schema): + logger.info(f"Processing {cls.TRANSACTION_TYPE} request") + + validated_data = schema.load(data) + + transaction = Transaction.create_transaction( + id=validated_data.get("transactionId"), + account_id=validated_data.get("accountId"), + customer_id=validated_data.get("customerId"), + type=cls.TRANSACTION_TYPE, + channel=validated_data.get("channel"), + msisdn=validated_data.get("msisdn"), + country_code=validated_data.get("countryCode") + ) + + return transaction \ No newline at end of file diff --git a/app/api/services/eligibility_check.py b/app/api/services/eligibility_check.py index 2d7cd63..5343a3a 100644 --- a/app/api/services/eligibility_check.py +++ b/app/api/services/eligibility_check.py @@ -1,9 +1,14 @@ from flask import session, jsonify from app.utils.logger import logger +from app.api.services.base_service import BaseService from app.api.schemas.eligibility_check import EligibilityCheckSchema from marshmallow import ValidationError +from app.models import Transaction +from app.api.enums import transaction_type + +class EligibilityCheckService(BaseService): + TRANSACTION_TYPE = transaction_type.ELIGIBILITY_CHECK -class EligibilityCheckService: @staticmethod def process_request(data): """ @@ -16,11 +21,14 @@ class EligibilityCheckService: dict: A standardized response. """ try: - logger.info("Processing EligibilityCheck request") + transaction = EligibilityCheckService.log_transaction(data, EligibilityCheckSchema()) + + if not transaction: + logger.error(f"Customer creation failed") + return jsonify({ + "message": "Customer creation failed." . customer + }), 400 - # Validate input data using Schema - schema = EligibilityCheckSchema() - validated_data = schema.load(data) # Raises an error if invalid offers = [ { @@ -51,13 +59,6 @@ class EligibilityCheckService: "accountId": "ACN8263457" } - - # Return a success response - # return ResponseHelper.success( - # data=response_data, - # message="Eligibility check completed successfully" - # ) - return response_data except ValidationError as err: logger.error(f"Validation Error: {err.messages}") diff --git a/app/extensions.py b/app/extensions.py new file mode 100644 index 0000000..de1947d --- /dev/null +++ b/app/extensions.py @@ -0,0 +1,5 @@ +from flask_sqlalchemy import SQLAlchemy +from flask_migrate import Migrate + +db = SQLAlchemy() +migrate = Migrate() \ No newline at end of file diff --git a/app/models/account.py b/app/models/account.py index 3a66113..c4254b9 100644 --- a/app/models/account.py +++ b/app/models/account.py @@ -1,5 +1,5 @@ from datetime import datetime, timezone -from app import db +from app.extensions import db class Account(db.Model): __tablename__ = 'accounts' @@ -12,14 +12,16 @@ class Account(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)) - # Database relationship - # customer = db.relationship( - # 'Customer', - # primaryjoin='Account.customer_id == Customer.id', - # backref='accounts', - # foreign_keys=[customer_id], - # viewonly=True - # ) + @classmethod + def create_account(cls, id, customer_id, account_type, status='active'): + account = cls( + id=id, + customer_id=customer_id, + account_type=account_type + ) + db.session.add(account) + db.session.commit() + return account @classmethod def is_valid_account(cls, account_id, customer_id): diff --git a/app/models/customer.py b/app/models/customer.py index aa31073..b6eb1de 100644 --- a/app/models/customer.py +++ b/app/models/customer.py @@ -1,5 +1,6 @@ from datetime import datetime, timezone -from app import db +from app.extensions import db +from app.models.account import Account class Customer(db.Model): __tablename__ = 'customers' @@ -17,6 +18,24 @@ class Customer(db.Model): return False, "Customer not found" return True, "Customer is eligible" + @classmethod + def create_customer(cls, id, msisdn, country_code, account_id, account_type='savings'): + if cls.query.filter_by(msisdn=msisdn).first(): + return False, "Customer with this MSISDN already exists" + + # Create the customer + customer = cls(id=id, msisdn=msisdn, country_code=country_code) + db.session.add(customer) + + # Create an associated account + account = Account.create_account( + id=account_id, + customer_id=id, + account_type=account_type + ) + + db.session.commit() + return customer + def __repr__(self): return f'' - diff --git a/app/models/loan.py b/app/models/loan.py index 5b9557b..6fa73a1 100644 --- a/app/models/loan.py +++ b/app/models/loan.py @@ -1,5 +1,5 @@ from datetime import datetime, timezone -from app import db +from app.extensions import db class Loan(db.Model): diff --git a/app/models/offer.py b/app/models/offer.py index 47fe6b3..ce62fa2 100644 --- a/app/models/offer.py +++ b/app/models/offer.py @@ -1,5 +1,5 @@ from datetime import datetime, timezone -from app import db +from app.extensions import db class Offer(db.Model): __tablename__ = 'offers' diff --git a/app/models/transaction.py b/app/models/transaction.py index 85317bd..010b31e 100644 --- a/app/models/transaction.py +++ b/app/models/transaction.py @@ -1,16 +1,41 @@ from datetime import datetime, timezone -from app import db +from app.extensions import db +from app.models import Customer class Transaction(db.Model): __tablename__ = 'transactions' id = db.Column(db.String(50), primary_key=True) - account_id = db.Column(db.String(50), nullable=False) + customer_id = db.Column(db.String(50), nullable=False) type = db.Column(db.String(50), nullable=False) - amount = db.Column(db.Float, nullable=False) - status = db.Column(db.String(20), default='pending') + channel = db.Column(db.String(50), nullable=False) 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)) def __repr__(self): - return f'' \ No newline at end of file + return f'' + + @classmethod + def create_transaction(cls, id, account_id, customer_id, type, channel, msisdn, country_code,): + transaction = cls( + id=id, + customer_id=customer_id, + type=type, + channel=channel + + ) + + customer = Customer.create_customer( + id=customer_id, + msisdn= msisdn, + country_code= country_code, + account_id= account_id, + ) + + db.session.add(transaction) + db.session.commit() + return transaction + + @classmethod + def get_transaction_by_id(cls, transaction_id): + return cls.query.get(transaction_id) \ No newline at end of file