diff --git a/app/api/services/base_service.py b/app/api/services/base_service.py index 02e73c2..453f629 100644 --- a/app/api/services/base_service.py +++ b/app/api/services/base_service.py @@ -1,4 +1,4 @@ -from app.models import Transaction +from app.models import Customer, Account, Transaction from app.api.enums import transaction_type from flask import jsonify from marshmallow import ValidationError @@ -10,19 +10,48 @@ class BaseService: TRANSACTION_TYPE = None @classmethod - def log_transaction(cls, data, schema): - logger.info(f"Processing {cls.TRANSACTION_TYPE} request") + def validate_data(cls, data, schema): + """ + Validate input data based on the provided schema. + """ + logger.info(f"Processing {cls.TRANSACTION_TYPE} request") + return schema.load(data) - validated_data = schema.load(data) + @classmethod + def get_or_create_customer(cls, validated_data): + + """ + Check if a customer exists; if not, create one. + """ - 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"), + customer = Customer.query.filter_by(id=validated_data.get("customerId")).first() + if not customer: + customer = Customer.create_customer( + id=validated_data.get("customerId"), msisdn=validated_data.get("msisdn"), - country_code=validated_data.get("countryCode") + country_code=validated_data.get("countryCode"), + account_id=validated_data.get("accountId"), ) + return customer - return transaction \ No newline at end of file + @classmethod + def validate_account_ownership(cls, account_id, customer_id): + """ + Check if the provided account belongs to the customer. + """ + is_valid = Account.is_valid_account(account_id, customer_id) + + if not is_valid: + raise ValueError("Account does not belong to customer") + + @classmethod + def create_transaction(cls, validated_data): + """ + Create a new transaction. + """ + return Transaction.create_transaction( + id=validated_data.get("transactionId"), + account_id=validated_data.get("accountId"), + type=BaseService.TRANSACTION_TYPE, + channel=validated_data.get("channel"), + ) diff --git a/app/api/services/customer_consent.py b/app/api/services/customer_consent.py index cd76120..5db10e4 100644 --- a/app/api/services/customer_consent.py +++ b/app/api/services/customer_consent.py @@ -1,10 +1,11 @@ from flask import request, jsonify +from app.api.services.base_service import BaseService from marshmallow import ValidationError from app.utils.logger import logger from app.api.schemas.customer_consent import CustomerConsentSchema -class CustomerConsentService: +class CustomerConsentService(BaseService): @staticmethod def process_request(data): """ @@ -21,7 +22,7 @@ class CustomerConsentService: # Validate input data using the CustomerConsent schema schema = CustomerConsentSchema() - validated_data = schema.load(data) # Raises ValidationError if invalid + validated_data = schema.load(data) # Simulated processing logic response_data = { diff --git a/app/api/services/eligibility_check.py b/app/api/services/eligibility_check.py index a4bffcb..146218f 100644 --- a/app/api/services/eligibility_check.py +++ b/app/api/services/eligibility_check.py @@ -3,7 +3,6 @@ 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): @@ -21,14 +20,29 @@ class EligibilityCheckService(BaseService): dict: A standardized response. """ try: - transaction = EligibilityCheckService.log_transaction(data, EligibilityCheckSchema()) - if not transaction: - logger.error(f"Customer creation failed") + validated_data = EligibilityCheckService.validate_data(data, EligibilityCheckSchema()) + account_id = validated_data.get('accountId') + customer_id = validated_data.get('customerId') + + customer = EligibilityCheckService.get_or_create_customer(validated_data = validated_data) + + logger.error(account_id) + logger.error(customer_id) + + if (EligibilityCheckService.validate_account_ownership(account_id = account_id, customer_id = customer_id)): + transaction = EligibilityCheckService.create_transaction(validated_data = validated_data) + + if not transaction: + logger.error(f"Transaction creation failed") + return jsonify({ + "message": "Transaction creation failed." + }), 400 + else: return jsonify({ - "message": "Customer creation failed." . customer - }), 400 - + "message": "Invalid account" + }), 400 + offers = [ { @@ -61,7 +75,9 @@ class EligibilityCheckService(BaseService): return response_data except (ValidationError, ValueError) as err: - logger.error(f"Validation Error: {err.messages}") + + logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") + return jsonify({ "message": "Validation exception" }) , 422 diff --git a/app/models/account.py b/app/models/account.py index c4254b9..95ddbc4 100644 --- a/app/models/account.py +++ b/app/models/account.py @@ -27,10 +27,10 @@ class Account(db.Model): def is_valid_account(cls, account_id, customer_id): account = cls.query.filter_by(id=account_id, customer_id=customer_id).first() if not account: - return False, "Account not found or doesn't belong to customer" + return False if account.lien_amount > 0: - return False, "Account has an existing lien" - return True, "Account is valid" + return False + return True def __repr__(self): return f'' diff --git a/app/models/customer.py b/app/models/customer.py index b6eb1de..a41efe3 100644 --- a/app/models/customer.py +++ b/app/models/customer.py @@ -20,8 +20,8 @@ class Customer(db.Model): @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" + if cls.query.filter_by(id=id).first(): + raise ValueError("Customer already exists") # Create the customer customer = cls(id=id, msisdn=msisdn, country_code=country_code) diff --git a/app/models/transaction.py b/app/models/transaction.py index 5343e80..62831ae 100644 --- a/app/models/transaction.py +++ b/app/models/transaction.py @@ -1,12 +1,12 @@ from datetime import datetime, timezone from app.extensions import db -from app.models import Customer +from sqlalchemy.exc import IntegrityError class Transaction(db.Model): __tablename__ = 'transactions' id = db.Column(db.String(50), primary_key=True) - customer_id = db.Column(db.String(50), nullable=False) + account_id = db.Column(db.String(50), nullable=False) type = db.Column(db.String(50), nullable=False) channel = db.Column(db.String(50), nullable=False) created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc)) @@ -16,27 +16,24 @@ class Transaction(db.Model): return f'' @classmethod - def create_transaction(cls, id, account_id, customer_id, type, channel, msisdn, country_code,): + def create_transaction(cls, id, account_id, type, channel): if cls.query.filter_by(id=id).first(): - raise ValueError("Transaction with this id already exists") + raise ValueError("Duplicate Transaction") transaction = cls( id=id, - customer_id=customer_id, + account_id=account_id, type=type, channel=channel - ) - customer = Customer.create_customer( - id=customer_id, - msisdn= msisdn, - country_code= country_code, - account_id= account_id, - ) + try: + db.session.add(transaction) + db.session.commit() + except IntegrityError as err: + db.session.rollback() + raise ValueError(f"Database integrity error: {err}") - db.session.add(transaction) - db.session.commit() return transaction @classmethod