Skip to content

Commit

Permalink
24685 - Add in check for create_cfs_accounts job to see if it's withi…
Browse files Browse the repository at this point in the history
…n business hours (#1845)
  • Loading branch information
seeker25 authored Dec 2, 2024
1 parent 06e7888 commit 81f6f88
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 114 deletions.
27 changes: 26 additions & 1 deletion jobs/payment-jobs/tasks/cfs_create_account_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@
# limitations under the License.
"""Task to create CFS account offline."""
import re
from datetime import datetime, timezone
from datetime import datetime, time, timezone
from typing import Dict

import pytz
from flask import current_app
from pay_api.models import CfsAccount as CfsAccountModel
from pay_api.models import PaymentAccount as PaymentAccountModel
Expand All @@ -34,6 +35,26 @@
class CreateAccountTask: # pylint: disable=too-few-public-methods
"""Create CFS Account."""

@staticmethod
def is_within_cfs_business_hours() -> bool:
"""Check if the current time is within business hours."""
# https://bcgov.sharepoint.com/sites/FIN-OCG-CAS-CFS/SitePages/Calendar.aspx
vancouver_tz = pytz.timezone("America/Vancouver")
now_vancouver = datetime.now(vancouver_tz)
day_of_week = now_vancouver.weekday()
weekday_hours = (time(6, 0), time(21, 0)) # Monday-Friday: 6am - 9pm
saturday_hours = (time(6, 0), time(19, 0)) # Saturday: 6am - 7pm
sunday_hours = (time(9, 0), time(21, 0)) # Sunday: 9am - 9pm
current_time = now_vancouver.time()
# Check business hours based on the day
if day_of_week in range(0, 5):
return weekday_hours[0] <= current_time <= weekday_hours[1]
if day_of_week == 5:
return saturday_hours[0] <= current_time <= saturday_hours[1]
if day_of_week == 6:
return sunday_hours[0] <= current_time <= sunday_hours[1]
return False

@classmethod
def create_accounts(cls): # pylint: disable=too-many-locals
"""Find all pending accounts to be created in CFS.
Expand All @@ -43,6 +64,10 @@ def create_accounts(cls): # pylint: disable=too-many-locals
2. Create CFS accounts.
3. Publish a message to the queue if successful.
"""
if not CreateAccountTask.is_within_cfs_business_hours():
current_app.logger.info("Outside business hours. Skipping account creation.")
return

# Pass payment method if offline account creation has be restricted based on payment method.
pending_accounts = CfsAccountModel.find_all_pending_accounts()
current_app.logger.info(f"Found {len(pending_accounts)} CFS Accounts to be created.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from tasks.cfs_create_account_task import CreateAccountTask

from .factory import factory_create_pad_account
from .utils import valid_time_for_job


def test_activate_pad_accounts(session):
Expand All @@ -39,7 +40,8 @@ def test_activate_pad_accounts_with_time_check(session):
"""Test Activate account."""
# Create a pending account first, then call the job
account = factory_create_pad_account(auth_account_id="1")
CreateAccountTask.create_accounts()
with freeze_time(valid_time_for_job):
CreateAccountTask.create_accounts()
account: PaymentAccount = PaymentAccount.find_by_id(account.id)
cfs_account = CfsAccount.find_effective_by_payment_method(account.id, PaymentMethod.PAD.value)
assert cfs_account.status == CfsAccountStatus.PENDING_PAD_ACTIVATION.value, "Created account has pending pad status"
Expand All @@ -66,7 +68,9 @@ def test_activate_bcol_change_to_pad(session):
"""Test Activate account."""
# Create a pending account first, then call the job
account = factory_create_pad_account(auth_account_id="1", payment_method=PaymentMethod.DRAWDOWN.value)
CreateAccountTask.create_accounts()

with freeze_time(valid_time_for_job):
CreateAccountTask.create_accounts()
account = PaymentAccount.find_by_id(account.id)
cfs_account = CfsAccount.find_effective_by_payment_method(account.id, PaymentMethod.PAD.value)
assert cfs_account.status == CfsAccountStatus.PENDING_PAD_ACTIVATION.value, "Created account has pending pad status"
Expand Down
233 changes: 129 additions & 104 deletions jobs/payment-jobs/tests/jobs/test_cfs_create_account_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@
Test-Suite to ensure that the CreateAccountTask is working as expected.
"""
from datetime import datetime
from unittest.mock import patch

import pytz
import requests
from freezegun import freeze_time
from pay_api.models import CfsAccount, PaymentAccount
from pay_api.services.online_banking_service import OnlineBankingService
from pay_api.services.pad_service import PadService
Expand All @@ -29,157 +32,179 @@
from utils import mailer

from .factory import factory_create_eft_account, factory_create_online_banking_account, factory_create_pad_account
from .utils import invalid_time_for_job, valid_time_for_job


def test_create_account_setup(session):
"""Test create account."""
CreateAccountTask.create_accounts()
assert True
with freeze_time(valid_time_for_job):
CreateAccountTask.create_accounts()
assert True


def test_create_pad_account(session):
"""Test create account."""
# Create a pending account first, then call the job
account = factory_create_pad_account(auth_account_id="1")
CreateAccountTask.create_accounts()
account = PaymentAccount.find_by_id(account.id)
cfs_account = CfsAccount.find_effective_by_payment_method(account.id, PaymentMethod.PAD.value)
assert cfs_account.status == CfsAccountStatus.PENDING_PAD_ACTIVATION.value
assert cfs_account.bank_account_number
assert cfs_account.cfs_party
assert cfs_account.cfs_site
assert cfs_account.cfs_account
assert cfs_account.payment_instrument_number
with freeze_time(valid_time_for_job):
account = factory_create_pad_account(auth_account_id="1")
CreateAccountTask.create_accounts()
account = PaymentAccount.find_by_id(account.id)
cfs_account = CfsAccount.find_effective_by_payment_method(account.id, PaymentMethod.PAD.value)
assert cfs_account.status == CfsAccountStatus.PENDING_PAD_ACTIVATION.value
assert cfs_account.bank_account_number
assert cfs_account.cfs_party
assert cfs_account.cfs_site
assert cfs_account.cfs_account
assert cfs_account.payment_instrument_number


def test_create_eft_account(session):
"""Test create account."""
# Create a pending account first, then call the job
account = factory_create_eft_account(auth_account_id="1")
CreateAccountTask.create_accounts()
account = PaymentAccount.find_by_id(account.id)
cfs_account = CfsAccount.find_effective_by_payment_method(account.id, PaymentMethod.EFT.value)
assert cfs_account.status == CfsAccountStatus.ACTIVE.value
assert cfs_account.payment_instrument_number is None
with freeze_time(valid_time_for_job):
account = factory_create_eft_account(auth_account_id="1")
CreateAccountTask.create_accounts()
account = PaymentAccount.find_by_id(account.id)
cfs_account = CfsAccount.find_effective_by_payment_method(account.id, PaymentMethod.EFT.value)
assert cfs_account.status == CfsAccountStatus.ACTIVE.value
assert cfs_account.payment_instrument_number is None


def test_create_pad_account_user_error(session):
"""Test create account."""
# Create a pending account first, then call the job
account = factory_create_pad_account(auth_account_id="1")
cfs_account = CfsAccount.find_effective_by_payment_method(account.id, PaymentMethod.PAD.value)
assert cfs_account.status == CfsAccountStatus.PENDING.value
mock_response = requests.models.Response()
mock_response.headers["CAS-Returned-Messages"] = "[Errors = [34] Bank Account Number is Invalid]"
mock_response.status_code = 404
with freeze_time(valid_time_for_job):
account = factory_create_pad_account(auth_account_id="1")
cfs_account = CfsAccount.find_effective_by_payment_method(account.id, PaymentMethod.PAD.value)
assert cfs_account.status == CfsAccountStatus.PENDING.value
mock_response = requests.models.Response()
mock_response.headers["CAS-Returned-Messages"] = "[Errors = [34] Bank Account Number is Invalid]"
mock_response.status_code = 404

side_effect = HTTPError(response=mock_response)
with patch.object(mailer, "publish_mailer_events") as mock_mailer:
with patch("pay_api.services.CFSService.create_cfs_account", side_effect=side_effect):
CreateAccountTask.create_accounts()
mock_mailer.assert_called
side_effect = HTTPError(response=mock_response)
with patch.object(mailer, "publish_mailer_events") as mock_mailer:
with patch("pay_api.services.CFSService.create_cfs_account", side_effect=side_effect):
CreateAccountTask.create_accounts()
mock_mailer.assert_called

account = PaymentAccount.find_by_id(account.id)
cfs_account = CfsAccount.find_by_id(cfs_account.id)
assert cfs_account.status == CfsAccountStatus.INACTIVE.value
account = PaymentAccount.find_by_id(account.id)
cfs_account = CfsAccount.find_by_id(cfs_account.id)
assert cfs_account.status == CfsAccountStatus.INACTIVE.value


def test_create_pad_account_system_error(session):
"""Test create account."""
# Create a pending account first, then call the job
account = factory_create_pad_account(auth_account_id="1")
cfs_account = CfsAccount.find_effective_by_payment_method(account.id, PaymentMethod.PAD.value)
assert cfs_account.status == CfsAccountStatus.PENDING.value
mock_response = requests.models.Response()
mock_response.headers["CAS-Returned-Messages"] = "[CFS Down]"
mock_response.status_code = 404
with freeze_time(valid_time_for_job):
account = factory_create_pad_account(auth_account_id="1")
cfs_account = CfsAccount.find_effective_by_payment_method(account.id, PaymentMethod.PAD.value)
assert cfs_account.status == CfsAccountStatus.PENDING.value
mock_response = requests.models.Response()
mock_response.headers["CAS-Returned-Messages"] = "[CFS Down]"
mock_response.status_code = 404

side_effect = HTTPError(response=mock_response)
with patch.object(mailer, "publish_mailer_events") as mock_mailer:
with patch("pay_api.services.CFSService.create_cfs_account", side_effect=side_effect):
CreateAccountTask.create_accounts()
mock_mailer.assert_not_called()
side_effect = HTTPError(response=mock_response)
with patch.object(mailer, "publish_mailer_events") as mock_mailer:
with patch("pay_api.services.CFSService.create_cfs_account", side_effect=side_effect):
CreateAccountTask.create_accounts()
mock_mailer.assert_not_called()

account = PaymentAccount.find_by_id(account.id)
cfs_account = CfsAccount.find_by_id(cfs_account.id)
assert cfs_account.status == CfsAccountStatus.PENDING.value
account = PaymentAccount.find_by_id(account.id)
cfs_account = CfsAccount.find_by_id(cfs_account.id)
assert cfs_account.status == CfsAccountStatus.PENDING.value


def test_create_pad_account_no_confirmation_period(session):
"""Test create account.Arbitrary scenario when there is no confirmation period."""
# Create a pending account first, then call the job
account = factory_create_pad_account(auth_account_id="1", confirmation_period=0)
CreateAccountTask.create_accounts()
account = PaymentAccount.find_by_id(account.id)
cfs_account = CfsAccount.find_effective_by_payment_method(account.id, PaymentMethod.PAD.value)
assert cfs_account.status == CfsAccountStatus.ACTIVE.value
assert cfs_account.bank_account_number
assert cfs_account.cfs_party
assert cfs_account.cfs_site
assert cfs_account.cfs_account
assert cfs_account.payment_instrument_number
with freeze_time(valid_time_for_job):
account = factory_create_pad_account(auth_account_id="1", confirmation_period=0)
CreateAccountTask.create_accounts()
account = PaymentAccount.find_by_id(account.id)
cfs_account = CfsAccount.find_effective_by_payment_method(account.id, PaymentMethod.PAD.value)
assert cfs_account.status == CfsAccountStatus.ACTIVE.value
assert cfs_account.bank_account_number
assert cfs_account.cfs_party
assert cfs_account.cfs_site
assert cfs_account.cfs_account
assert cfs_account.payment_instrument_number


def test_create_online_banking_account(session):
"""Test create account."""
# Create a pending account first, then call the job
account = factory_create_online_banking_account(auth_account_id="2")
CreateAccountTask.create_accounts()
account = PaymentAccount.find_by_id(account.id)
cfs_account = CfsAccount.find_effective_by_payment_method(account.id, PaymentMethod.ONLINE_BANKING.value)
assert cfs_account.status == CfsAccountStatus.ACTIVE.value
assert not cfs_account.bank_account_number
assert cfs_account.cfs_party
assert cfs_account.cfs_site
assert cfs_account.cfs_account
assert cfs_account.payment_instrument_number is None
with freeze_time(valid_time_for_job):
account = factory_create_online_banking_account(auth_account_id="2")
CreateAccountTask.create_accounts()
account = PaymentAccount.find_by_id(account.id)
cfs_account = CfsAccount.find_effective_by_payment_method(account.id, PaymentMethod.ONLINE_BANKING.value)
assert cfs_account.status == CfsAccountStatus.ACTIVE.value
assert not cfs_account.bank_account_number
assert cfs_account.cfs_party
assert cfs_account.cfs_site
assert cfs_account.cfs_account
assert cfs_account.payment_instrument_number is None


def test_update_online_banking_account(session):
"""Test update account."""
# Create a pending account first, then call the job
account = factory_create_online_banking_account(auth_account_id="2")
CreateAccountTask.create_accounts()
account = PaymentAccount.find_by_id(account.id)
cfs_account = CfsAccount.find_effective_by_payment_method(account.id, PaymentMethod.ONLINE_BANKING.value)
with freeze_time(valid_time_for_job):
account = factory_create_online_banking_account(auth_account_id="2")
CreateAccountTask.create_accounts()
account = PaymentAccount.find_by_id(account.id)
cfs_account = CfsAccount.find_effective_by_payment_method(account.id, PaymentMethod.ONLINE_BANKING.value)

# Update account, which shouldn't change any details
OnlineBankingService().update_account(name="Test", cfs_account=cfs_account, payment_info=None)
updated_cfs_account = CfsAccount.find_effective_by_payment_method(account.id, PaymentMethod.ONLINE_BANKING.value)
# Update account, which shouldn't change any details
OnlineBankingService().update_account(name="Test", cfs_account=cfs_account, payment_info=None)
updated_cfs_account = CfsAccount.find_effective_by_payment_method(
account.id, PaymentMethod.ONLINE_BANKING.value
)

assert updated_cfs_account.status == CfsAccountStatus.ACTIVE.value
assert cfs_account.id == updated_cfs_account.id
assert updated_cfs_account.status == CfsAccountStatus.ACTIVE.value
assert cfs_account.id == updated_cfs_account.id


def test_update_pad_account(session):
"""Test update account."""
# Create a pending account first, then call the job
account = factory_create_pad_account(auth_account_id="2")
CreateAccountTask.create_accounts()

account = PaymentAccount.find_by_id(account.id)
cfs_account = CfsAccount.find_effective_by_payment_method(account.id, PaymentMethod.PAD.value)

assert cfs_account.payment_instrument_number

# Now update the account.
new_payment_details = {
"bankInstitutionNumber": "111",
"bankTransitNumber": "222",
"bankAccountNumber": "3333333333",
}
PadService().update_account(name="Test", cfs_account=cfs_account, payment_info=new_payment_details)
cfs_account = CfsAccount.find_by_id(cfs_account.id)

# Run the job again
CreateAccountTask.create_accounts()

updated_cfs_account = CfsAccount.find_effective_by_payment_method(account.id, PaymentMethod.PAD.value)
assert updated_cfs_account.id != cfs_account.id
assert updated_cfs_account.bank_account_number == new_payment_details.get("bankAccountNumber")
assert updated_cfs_account.bank_branch_number == new_payment_details.get("bankTransitNumber")
assert updated_cfs_account.bank_number == new_payment_details.get("bankInstitutionNumber")

assert cfs_account.status == CfsAccountStatus.INACTIVE.value
assert updated_cfs_account.status == CfsAccountStatus.ACTIVE.value
assert updated_cfs_account.payment_instrument_number
with freeze_time(valid_time_for_job):
account = factory_create_pad_account(auth_account_id="2")
CreateAccountTask.create_accounts()

account = PaymentAccount.find_by_id(account.id)
cfs_account = CfsAccount.find_effective_by_payment_method(account.id, PaymentMethod.PAD.value)

assert cfs_account.payment_instrument_number

# Now update the account.
new_payment_details = {
"bankInstitutionNumber": "111",
"bankTransitNumber": "222",
"bankAccountNumber": "3333333333",
}
PadService().update_account(name="Test", cfs_account=cfs_account, payment_info=new_payment_details)
cfs_account = CfsAccount.find_by_id(cfs_account.id)

# Run the job again
CreateAccountTask.create_accounts()

updated_cfs_account = CfsAccount.find_effective_by_payment_method(account.id, PaymentMethod.PAD.value)
assert updated_cfs_account.id != cfs_account.id
assert updated_cfs_account.bank_account_number == new_payment_details.get("bankAccountNumber")
assert updated_cfs_account.bank_branch_number == new_payment_details.get("bankTransitNumber")
assert updated_cfs_account.bank_number == new_payment_details.get("bankInstitutionNumber")

assert cfs_account.status == CfsAccountStatus.INACTIVE.value
assert updated_cfs_account.status == CfsAccountStatus.ACTIVE.value
assert updated_cfs_account.payment_instrument_number


def test_invalid_time_for_job(session):
"""Try creating EFT account outside of CFS hopurs."""
with freeze_time(invalid_time_for_job):
account = factory_create_eft_account(auth_account_id="1")
CreateAccountTask.create_accounts()
account = PaymentAccount.find_by_id(account.id)
cfs_account = CfsAccount.find_effective_by_payment_method(account.id, PaymentMethod.EFT.value)
assert cfs_account.status == CfsAccountStatus.PENDING.value
Loading

0 comments on commit 81f6f88

Please sign in to comment.