From ad25be18564f9c21ce183fa9c978aeaf80ae8dcf Mon Sep 17 00:00:00 2001 From: Chinenye Nmoh Date: Wed, 18 Jun 2025 22:25:45 +0100 Subject: [PATCH] added salary table --- app/integrations/simbrella.py | 18 +++++++++-- app/models/__init__.py | 3 +- app/models/repayment.py | 8 +++++ app/models/repayments_data.py | 4 ++- app/models/salary.py | 61 +++++++++++++++++++++++++++++++++++ app/routes/autocall.py | 1 + app/services/repayment.py | 6 ++++ app/services/salary.py | 11 +++++++ openapi.yml | 33 +++++++++---------- 9 files changed, 124 insertions(+), 21 deletions(-) create mode 100644 app/models/salary.py create mode 100644 app/services/salary.py diff --git a/app/integrations/simbrella.py b/app/integrations/simbrella.py index b4cbd36..b85a8b9 100644 --- a/app/integrations/simbrella.py +++ b/app/integrations/simbrella.py @@ -10,6 +10,7 @@ from app.services.transactions import TransactionService from app.services.repayment import RepaymentService from app.extensions import db from app.services.repayments_data import RepaymentsData +from app.services.salary import SalaryService class SimbrellaClient: @@ -186,7 +187,18 @@ class SimbrellaClient: @staticmethod def collect_loan_user_salary_detect(data): #InitiatedBy = SALARY_DETECT - return SimbrellaClient._collect_loan(data) + logger.info(f"salary data: {data}") + try: + salary = SalaryService.add_salary_data(data) + if salary: + return ResponseHelper.success(salary.to_dict(), "Successful") + + except Exception as e: + logger.info(f"Failed to save salary: {e}") + return ResponseHelper.error(message="Failed to call salary endpoint", + status_code=400, + error=str(e) ) + @staticmethod def collect_loan_user_due_payment(data): @@ -218,6 +230,7 @@ class SimbrellaClient: return ResponseHelper.error("Loan not found") loan_data = loan.to_dict() + logger.info(f"loan dict : {loan_data}") if repayment_data['repayDate'] is not None: logger.info( @@ -242,7 +255,7 @@ class SimbrellaClient: "channel": "USSD", "collectionMethod": "1", "lienAmount": 0, - "countryId": "01", + "countryId": "NG", "comment": "COLLECT LOAN" } @@ -263,6 +276,7 @@ class SimbrellaClient: "repaymentAmount": collect_loan_data.get('collectAmount'), "responseCode": result.get('responseCode'), "responseDescr": result.get('responseMessage'), + "balance":result.get('lienAmount') } new_repayment_data = RepaymentsData.add_repayment_data(data_to_add) diff --git a/app/models/__init__.py b/app/models/__init__.py index 44f2561..47bc45c 100644 --- a/app/models/__init__.py +++ b/app/models/__init__.py @@ -5,5 +5,6 @@ from .loan_charge import LoanCharge from .customer import Customer from .account import Account from .repayments_data import RepaymentsData +from .salary import Salary -__all__ = ['Transaction', 'Repayment', 'Loan', 'LoanCharge', 'Customer', 'Account', 'RepaymentsData'] \ No newline at end of file +__all__ = ['Transaction', 'Repayment', 'Loan', 'LoanCharge', 'Customer', 'Account', 'RepaymentsData','Salary'] \ No newline at end of file diff --git a/app/models/repayment.py b/app/models/repayment.py index 3ea9db5..7fd9ea2 100644 --- a/app/models/repayment.py +++ b/app/models/repayment.py @@ -161,6 +161,14 @@ class Repayment(db.Model): return cls.query.filter( cls.repay_date.is_(None) ).order_by(cls.created_at.desc()).first() + @classmethod + def get_latest_repayment_with_loanId(cls, loan_id): + """ + Get the latest repayment with loan Id. + """ + return cls.query.filter( + cls.loan_id == loan_id + ).order_by(cls.created_at.desc()).first() @classmethod def get_latest_loan_with_repay_date(cls): diff --git a/app/models/repayments_data.py b/app/models/repayments_data.py index 890a08a..a790a78 100644 --- a/app/models/repayments_data.py +++ b/app/models/repayments_data.py @@ -15,6 +15,7 @@ class RepaymentsData(db.Model): customer_id = db.Column(db.String(50), nullable=True) repayment_amount = db.Column(db.Float, nullable=True) amount_collected = db.Column(db.Float, nullable=True) + balance = db.Column(db.Float, nullable=True, default=0.0) def to_dict(self): return { @@ -27,7 +28,8 @@ class RepaymentsData(db.Model): "accountId": self.customer_id, "fbnTransactionId": self.fbn_transaction_id, "repaymentAmount": self.repayment_amount, - "amountCollected": self.amount_collected + "amountCollected": self.amount_collected, + "balance": self.balance } diff --git a/app/models/salary.py b/app/models/salary.py new file mode 100644 index 0000000..c9e489a --- /dev/null +++ b/app/models/salary.py @@ -0,0 +1,61 @@ +from app.extensions import db +from datetime import datetime, timezone +from app.utils.logger import logger + +class Salary(db.Model): + __tablename__ = "salaries" + + id = db.Column( + db.Integer, + primary_key=True, + autoincrement=True, + ) + customer_id = db.Column(db.String(50), nullable=False) + account_id = db.Column(db.String(50), nullable=False) + amount = db.Column(db.Float, nullable=True, default=0.0) + status = db.Column(db.String(20), nullable=True) + created_at = db.Column(db.DateTime, default=datetime.now) + updated_at = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now) + salary_date = db.Column(db.DateTime, nullable=True) + + def __repr__(self): + return f'' + + def to_dict(self): + """ + Convert the Salary object to a dictionary format for JSON serialization. + """ + return { + 'id': self.id, + 'customerId': self.customer_id, + 'accountId' : self.account_id, + 'amount': self.amount, + 'status': self.status, + 'createdAt': self.created_at.isoformat() if self.created_at else None, + 'updatedAt': self.updated_at.isoformat() if self.updated_at else None, + 'salaryDate': self.salary_date.isoformat() if self.salary_date else None, + } + + @classmethod + def add_salary_data(cls, data): + """ + Add a new salary data entry. + """ + logger.info(f"receieved data:{data}") + try: + new_data = cls( + customer_id=data.get('customerId'), + + amount=data.get('amount', 0.0), + status=data.get('status'), + salary_date = datetime.strptime(data.get('salaryDate'), "%Y-%m-%d").date() if data.get('salaryDate') else None, + account_id=data.get('accountId') + ) + db.session.add(new_data) + db.session.commit() + logger.info("Salary data has been committed.") + return new_data + except Exception as e: + db.session.rollback() + logger.info(f"error : {str(e)}") + raise Exception(f"Error adding salary data: {str(e)}") \ No newline at end of file diff --git a/app/routes/autocall.py b/app/routes/autocall.py index 16ce7aa..525afee 100644 --- a/app/routes/autocall.py +++ b/app/routes/autocall.py @@ -72,6 +72,7 @@ def refresh_collection(): logger.info(f"Calling Collection ") #grab the last repayments with repay date is none repayment = RepaymentService.get_latest_repayment_without_repay_date() + #repayment = RepaymentService.get_latest_repayment_with_loanId(13735) if not repayment: logger.info(f"No repayment found without disbursement date") return 0 diff --git a/app/services/repayment.py b/app/services/repayment.py index f4baece..3784a98 100644 --- a/app/services/repayment.py +++ b/app/services/repayment.py @@ -43,6 +43,12 @@ class RepaymentService: Get the latest repayment without a repay date. """ return Repayment.get_latest_repayment_without_repay_date() + @classmethod + def get_latest_repayment_with_loanId(cls,loan_id): + """ + Get the latest repayment with loan id. + """ + return Repayment.get_latest_repayment_with_loanId(loan_id) @classmethod def get_latest_loan_with_repay_date(cls): diff --git a/app/services/salary.py b/app/services/salary.py new file mode 100644 index 0000000..dfb27d2 --- /dev/null +++ b/app/services/salary.py @@ -0,0 +1,11 @@ +from app.models import Salary + +class SalaryService: + + + @classmethod + def add_salary_data(cls,data): + """ + Add a new salary data entry. + """ + return Salary.add_salary_data(data) \ No newline at end of file diff --git a/openapi.yml b/openapi.yml index 2792646..90113b7 100644 --- a/openapi.yml +++ b/openapi.yml @@ -178,23 +178,22 @@ paths: content: application/json: schema: - type: array - items: - type: object - properties: - salaryDate: - type: string - format: date - example: "2022-01-01" - customerId: - type: string - example: "CN621868" - accountId: - type: string - example: "2017821799" - salaryAmount: - type: number - example: 200000 + type: object + properties: + customerId: + type: string + example: "CN621868" + accountId: + type: string + example: "OP621868" + status: + type: string + amount: + type: number + example: 200000 + salaryDate: + type: string + example: "2025-01-01" responses: 200: description: A successful response \ No newline at end of file -- 2.34.1