Skip to content

Commit

Permalink
Merge pull request #2 from PSNAppz/develop
Browse files Browse the repository at this point in the history
Mt940 Generator
  • Loading branch information
venky-ganapathy authored Aug 8, 2024
2 parents b0d9cf8 + ec51c5d commit 1fc0d37
Show file tree
Hide file tree
Showing 29 changed files with 686 additions and 235 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,4 @@ cython_debug/
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
.idea/
13 changes: 0 additions & 13 deletions .idea/inspectionProfiles/Project_Default.xml

This file was deleted.

6 changes: 0 additions & 6 deletions .idea/inspectionProfiles/profiles_settings.xml

This file was deleted.

2 changes: 2 additions & 0 deletions openg2p-g2p-bridge-example-bank-api/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
EXAMPLE_BANK_HOST=0.0.0.0
EXAMPLE_BANK_PORT=8003
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,20 @@
from openg2p_g2p_bridge_example_bank_api.config import Settings

_config = Settings.get_config()

from openg2p_fastapi_common.app import Initializer as BaseInitializer
from openg2p_g2p_bridge_example_bank_models.models import (
Account,
FundBlock,
InitiatePaymentRequest,
)
from sqlalchemy import create_engine

from openg2p_g2p_bridge_example_bank_api.controllers import (
AccountStatementController,
BlockFundsController,
FundAvailabilityController,
PaymentController,
)
from openg2p_g2p_bridge_example_bank_models.models import Account, FundBlock, InitiatePaymentRequest

_logger = logging.getLogger(_config.logging_default_logger_name)

Expand All @@ -26,6 +30,7 @@ def initialize(self, **kwargs):
BlockFundsController().post_init()
FundAvailabilityController().post_init()
PaymentController().post_init()
AccountStatementController().post_init()

def migrate_database(self, args):
super().migrate_database(args)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from celery import Celery

celery_app = Celery(
"example_bank",
broker="redis://localhost:6379/0",
backend="redis://localhost:6379/0",
)

celery_app.conf.timezone = "UTC"
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
from openg2p_g2p_bridge_example_bank_api.controllers.block_funds import BlockFundsController
from openg2p_g2p_bridge_example_bank_api.controllers.check_available_funds import FundAvailabilityController
from openg2p_g2p_bridge_example_bank_api.controllers.initiate_payment import PaymentController
from .account_statement import AccountStatementController
from .block_funds import (
BlockFundsController,
)
from .check_available_funds import (
FundAvailabilityController,
)
from .initiate_payment import (
PaymentController,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import logging

from openg2p_fastapi_common.context import dbengine
from openg2p_fastapi_common.controller import BaseController
from openg2p_g2p_bridge_example_bank_models.models import Account, AccountStatement
from openg2p_g2p_bridge_example_bank_models.schemas import (
AccountStatementRequest,
AccountStatementResponse,
)
from sqlalchemy.ext.asyncio import async_sessionmaker
from sqlalchemy.future import select

from ..celery_app import celery_app
from ..config import Settings

_config = Settings.get_config()
_logger = logging.getLogger(_config.logging_default_logger_name)


class AccountStatementController(BaseController):
def __init__(self, **kwargs):
super().__init__(**kwargs)

self.router.tags += ["Account Statement"]

self.router.add_api_route(
"/generate_account_statement",
self.generate_account_statement,
response_model=AccountStatementResponse,
methods=["POST"],
)

async def generate_account_statement(
self, account_statement_request: AccountStatementRequest
) -> AccountStatementResponse:
_logger.info("Generating account statement")
session_maker = async_sessionmaker(dbengine.get(), expire_on_commit=False)
async with session_maker() as session:
stmt = select(Account).where(
Account.account_number
== account_statement_request.program_account_number
)
result = await session.execute(stmt)
account = result.scalars().first()

if not account:
_logger.error("Account not found")
return AccountStatementResponse(
status="failed",
error_message="Account not found",
)

account_statement = AccountStatement(
account_number=account_statement_request.program_account_number,
active=True,
)
session.add(account_statement)
await session.commit()

# Create a new task to generate the account statement
_logger.info("Account statement generation task created")
celery_app.send_task(
"account_statement_generator",
args=(account_statement.id,),
)

return AccountStatementResponse(
status="success", account_statement_id=str(account_statement.id)
)
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import logging
import uuid

from openg2p_fastapi_common.context import dbengine
from openg2p_fastapi_common.controller import BaseController
from openg2p_g2p_bridge_example_bank_models.models import Account, FundBlock
from openg2p_g2p_bridge_example_bank_models.schemas import (
BlockFundsRequest,
BlockFundsResponse,
)
from sqlalchemy import update
from sqlalchemy.ext.asyncio import async_sessionmaker
from sqlalchemy.future import select

from openg2p_g2p_bridge_example_bank_models.models import Account, FundBlock
from openg2p_g2p_bridge_example_bank_models.schemas import BlockFundsRequest, BlockFundsResponse
from ..config import Settings

_config = Settings.get_config()
_logger = logging.getLogger(_config.logging_default_logger_name)


class BlockFundsController(BaseController):
Expand All @@ -24,22 +32,25 @@ def __init__(self, **kwargs):
)

async def block_funds(self, request: BlockFundsRequest) -> BlockFundsResponse:
_logger.info("Blocking funds")
session_maker = async_sessionmaker(dbengine.get(), expire_on_commit=False)
async with session_maker() as session:
stmt = select(Account).where(
(Account.account_number == request.account_no)
(Account.account_number == request.account_number)
& (Account.account_currency == request.currency)
)
result = await session.execute(stmt)
account = result.scalars().first()

if not account:
_logger.error("Account not found")
return BlockFundsResponse(
status="failed",
block_reference_no="",
error_message="Account not found",
)
if account.available_balance < request.amount:
_logger.error("Insufficient funds")
return BlockFundsResponse(
status="failed",
block_reference_no="",
Expand All @@ -48,7 +59,7 @@ async def block_funds(self, request: BlockFundsRequest) -> BlockFundsResponse:

await session.execute(
update(Account)
.where(Account.account_number == request.account_no)
.where(Account.account_number == request.account_number)
.values(
available_balance=account.book_balance
- (account.blocked_amount + request.amount),
Expand All @@ -59,14 +70,15 @@ async def block_funds(self, request: BlockFundsRequest) -> BlockFundsResponse:
block_reference_no = str(uuid.uuid4())
fund_block = FundBlock(
block_reference_no=block_reference_no,
account_no=request.account_no,
account_number=request.account_number,
amount=request.amount,
currency=request.currency,
active=True,
)
session.add(fund_block)

await session.commit()
_logger.info("Funds blocked successfully")
return BlockFundsResponse(
status="success",
block_reference_no=block_reference_no,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
import logging

from openg2p_fastapi_common.context import dbengine
from openg2p_fastapi_common.controller import BaseController
from openg2p_g2p_bridge_example_bank_models.models import Account
from openg2p_g2p_bridge_example_bank_models.schemas import (
CheckFundRequest,
CheckFundResponse,
)
from sqlalchemy.ext.asyncio import async_sessionmaker
from sqlalchemy.future import select

from openg2p_g2p_bridge_example_bank_models.models import Account
from openg2p_g2p_bridge_example_bank_models.schemas import CheckFundRequest, CheckFundResponse
from ..config import Settings

_config = Settings.get_config()
_logger = logging.getLogger(_config.logging_default_logger_name)


class FundAvailabilityController(BaseController):
Expand All @@ -23,6 +32,7 @@ def __init__(self, **kwargs):
async def check_available_funds(
self, request: CheckFundRequest
) -> CheckFundResponse:
_logger.info("Checking available funds")
session_maker = async_sessionmaker(dbengine.get(), expire_on_commit=False)
async with session_maker() as session:
stmt = select(Account).where(
Expand All @@ -32,6 +42,7 @@ async def check_available_funds(
account = result.scalars().first()

if not account:
_logger.error("Account not found")
return CheckFundResponse(
status="failed",
account_number=request.account_number,
Expand All @@ -40,13 +51,15 @@ async def check_available_funds(
)

if account.available_balance >= request.total_funds_needed:
_logger.info("Sufficient funds")
return CheckFundResponse(
status="success",
account_number=account.account_number,
has_sufficient_funds=True,
error_message="",
)
else:
_logger.error("Insufficient funds")
return CheckFundResponse(
status="failed",
account_number=account.account_number,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
import logging
import uuid
from typing import List

from openg2p_fastapi_common.context import dbengine
from openg2p_fastapi_common.controller import BaseController
from openg2p_g2p_bridge_example_bank_models.models import (
FundBlock,
InitiatePaymentBatchRequest,
InitiatePaymentRequest,
)
from openg2p_g2p_bridge_example_bank_models.schemas import (
InitiatePaymentPayload,
InitiatePaymentResponse,
)
from sqlalchemy.ext.asyncio import async_sessionmaker
from sqlalchemy.future import select

from openg2p_g2p_bridge_example_bank_models.models import FundBlock, InitiatePaymentRequest
from openg2p_g2p_bridge_example_bank_models.schemas import InitiatePaymentPayload, InitiatorPaymentResponse
from ..config import Settings

_config = Settings.get_config()
_logger = logging.getLogger(_config.logging_default_logger_name)


class PaymentController(BaseController):
Expand All @@ -18,15 +31,23 @@ def __init__(self, **kwargs):
self.router.add_api_route(
"/initiate_payment",
self.initiate_payment,
response_model=InitiatorPaymentResponse,
response_model=InitiatePaymentResponse,
methods=["POST"],
)

async def initiate_payment(
self, initiate_payment_payloads: List[InitiatePaymentPayload]
) -> InitiatorPaymentResponse:
) -> InitiatePaymentResponse:
_logger.info("Initiating payment")
session_maker = async_sessionmaker(dbengine.get(), expire_on_commit=False)
async with session_maker() as session:
batch_id = str(uuid.uuid4())
initiate_payment_batch_request = InitiatePaymentBatchRequest(
batch_id=batch_id,
active=True,
)
session.add(initiate_payment_batch_request)
initiate_payment_requests = []
for initiate_payment_payload in initiate_payment_payloads:
fund_block_stmt = select(FundBlock).where(
FundBlock.block_reference_no
Expand All @@ -41,12 +62,16 @@ async def initiate_payment(
or fund_block.currency
!= initiate_payment_payload.remitting_account_currency
):
return InitiatorPaymentResponse(
_logger.error(
"Invalid funds block reference or mismatch in details"
)
return InitiatePaymentResponse(
status="failed",
error_message="Invalid funds block reference or mismatch in details",
)

payment = InitiatePaymentRequest(
initiate_payment_request = InitiatePaymentRequest(
batch_id=batch_id,
payment_reference_number=initiate_payment_payload.payment_reference_number,
remitting_account=initiate_payment_payload.remitting_account,
remitting_account_currency=initiate_payment_payload.remitting_account_currency,
Expand All @@ -71,8 +96,9 @@ async def initiate_payment(
narrative_6=initiate_payment_payload.narrative_6,
active=True,
)
session.add(payment)
initiate_payment_requests.append(initiate_payment_request)

session.add_all(initiate_payment_requests)
await session.commit()

return InitiatorPaymentResponse(status="success", error_message="")
_logger.info("Payment initiated successfully")
return InitiatePaymentResponse(status="success", error_message="")
4 changes: 4 additions & 0 deletions openg2p-g2p-bridge-example-bank-celery/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
EXAMPLE_BANK_HOST=0.0.0.0
EXAMPLE_BANK_PORT=8003
EXAMPLE_BANK_PROCESS_PAYMENT_FREQUENCY=3600
EXAMPLE_BANK_PAYMENT_INITIATE_ATTEMPTS=3
3 changes: 2 additions & 1 deletion openg2p-g2p-bridge-example-bank-celery/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,5 @@ docs/_build/

# Ignore secret files and env
.secrets.*
../.env
.env
/db
Binary file not shown.
Loading

0 comments on commit 1fc0d37

Please sign in to comment.