Skip to content

Commit

Permalink
add amount exceed business exception and unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
Jxio committed Jul 26, 2024
1 parent 05118ac commit 1ec969c
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 26 deletions.
5 changes: 0 additions & 5 deletions pay-api/src/pay_api/models/eft_credit.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,3 @@ class EFTCredit(BaseModel): # pylint:disable=too-many-instance-attributes
def find_by_payment_account_id(cls, payment_account_id: int):
"""Find EFT Credit by payment account id."""
return cls.query.filter_by(payment_account_id=payment_account_id).all()

@classmethod
def find_by_short_name_id(cls, short_name_id: int):
"""Find EFT Credit by short name id."""
return cls.query.filter_by(short_name_id=short_name_id).all()
26 changes: 14 additions & 12 deletions pay-api/src/pay_api/services/eft_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from flask import current_app
from jinja2 import Environment, FileSystemLoader

from pay_api.exceptions import BusinessException
from pay_api.models import CfsAccount as CfsAccountModel
from pay_api.models import EFTCredit as EFTCreditModel
from pay_api.models import EFTRefund as EFTRefundModel
Expand All @@ -29,9 +30,11 @@
from pay_api.models import PaymentAccount as PaymentAccountModel
from pay_api.models import Receipt as ReceiptModel
from pay_api.models.eft_refund_email_list import EFTRefundEmailList
from pay_api.services.eft_short_names import EFTShortnames
from pay_api.services.email_service import send_email
from pay_api.utils.enums import (
CfsAccountStatus, EFTCreditInvoiceStatus, InvoiceReferenceStatus, PaymentMethod, PaymentStatus, PaymentSystem)
from pay_api.utils.errors import Error
from pay_api.utils.user_context import user_context
from pay_api.utils.util import get_str_by_path

Expand Down Expand Up @@ -123,7 +126,7 @@ def create_shortname_refund(cls, request: Dict[str, str], **kwargs) -> Dict[str,
current_app.logger.debug(f'Starting shortname refund : {shortname_id}')

refund = cls._create_refund_model(request, shortname_id, amount, comment)
cls._refund_eft_credits(shortname_id, amount)
cls._refund_eft_credits(int(shortname_id), amount)

recipients = EFTRefundEmailList.find_all_emails()
subject = f'Pending Refund Request for Short Name {shortname}'
Expand All @@ -133,10 +136,15 @@ def create_shortname_refund(cls, request: Dict[str, str], **kwargs) -> Dict[str,
refund.save()

@classmethod
def _refund_eft_credits(cls, shortname_id: str, amount: str):
def _refund_eft_credits(cls, shortname_id: int, amount: str):
"""Refund the amount to eft_credits table based on short_name_id."""
refund_amount = Decimal(amount)
eft_credits = EFTCreditModel.find_by_short_name_id(int(shortname_id))
eft_credits: List[EFTCreditModel] = EFTShortnames.get_eft_credits(shortname_id)
eft_credit_balance = EFTShortnames.get_eft_credit_balance(shortname_id)

if refund_amount > eft_credit_balance:
current_app.logger.error(f'Shortname {shortname_id} Refund amount exceed eft_credits remaining amount.')
raise BusinessException(Error.INVALID_TRANSACTION)

for credit in eft_credits:
if refund_amount <= 0:
Expand All @@ -145,18 +153,12 @@ def _refund_eft_credits(cls, shortname_id: str, amount: str):
if credit_amount <= 0:
continue

if refund_amount <= credit_amount:
credit.remaining_amount -= refund_amount
refund_amount = Decimal(0)
else:
refund_amount -= credit_amount
credit.remaining_amount = Decimal(0)
deduction = min(refund_amount, credit_amount)
credit.remaining_amount -= deduction
refund_amount -= deduction

credit.save()

if refund_amount > 0:
current_app.logger.error(f'Shortname {shortname_id} Refund amount exceed eft_credits remaining amount.')

@classmethod
def _create_refund_model(cls, request: Dict[str, str],
shortname_id: str, amount: str, comment: str) -> EFTRefundModel:
Expand Down
40 changes: 31 additions & 9 deletions pay-api/tests/unit/services/test_eft_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@

from unittest.mock import MagicMock, patch
import pytest
from pay_api.models import EFTCredit as EFTCreditModel
from pay_api.exceptions import BusinessException
from pay_api.services.eft_service import EftService
from pay_api.utils.enums import InvoiceStatus, PaymentMethod
from pay_api.utils.errors import Error
from tests.utilities.base_test import factory_invoice, factory_payment_account


Expand Down Expand Up @@ -66,22 +66,44 @@ def test_refund_eft_credits(session):
credit2 = MagicMock(remaining_amount=4)
credit3 = MagicMock(remaining_amount=3)

with patch.object(EFTCreditModel, 'find_by_short_name_id', return_value=[credit1, credit2, credit3]):
EftService._refund_eft_credits(1, 8)
with patch('pay_api.services.eft_service.EFTShortnames.get_eft_credits',
return_value=[credit1, credit2, credit3]), \
patch('pay_api.services.eft_service.EFTShortnames.get_eft_credit_balance', return_value=9):
EftService._refund_eft_credits(1, '8')
assert credit1.remaining_amount == 0
assert credit2.remaining_amount == 0
assert credit3.remaining_amount == 1

credit1.remaining_amount = 5
credit2.remaining_amount = 5

EftService._refund_eft_credits(1, 7)
assert credit1.remaining_amount == 0
assert credit2.remaining_amount == 3
with patch('pay_api.services.eft_service.EFTShortnames.get_eft_credit_balance', return_value=10):
EftService._refund_eft_credits(1, '7')
assert credit1.remaining_amount == 0
assert credit2.remaining_amount == 3

credit1.remaining_amount = 5
credit2.remaining_amount = 2

EftService._refund_eft_credits(1, 1)
assert credit1.remaining_amount == 4
assert credit2.remaining_amount == 2
with patch('pay_api.services.eft_service.EFTShortnames.get_eft_credit_balance', return_value=7):
EftService._refund_eft_credits(1, '1')
assert credit1.remaining_amount == 4
assert credit2.remaining_amount == 2


def test_refund_eft_credits_exceed_balance(session):
"""Test refund amount exceeds eft_credit_balance."""
credit1 = MagicMock(remaining_amount=2)
credit2 = MagicMock(remaining_amount=4)
credit3 = MagicMock(remaining_amount=3)

with patch('pay_api.services.eft_service.EFTShortnames.get_eft_credits',
return_value=[credit1, credit2, credit3]), \
patch('pay_api.services.eft_service.EFTShortnames.get_eft_credit_balance', return_value=8), \
patch('flask.current_app.logger.error') as mock_error_logger:

with pytest.raises(BusinessException) as excinfo:
EftService._refund_eft_credits(1, '20')

assert excinfo.value.code == Error.INVALID_TRANSACTION.name
mock_error_logger.assert_called_with('Shortname 1 Refund amount exceed eft_credits remaining amount.')

0 comments on commit 1ec969c

Please sign in to comment.