Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

24664 - Adding sbc-finance to PAD locking email #1905

Merged
merged 29 commits into from
Feb 19, 2025
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 155 additions & 6 deletions jobs/payment-jobs/poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion jobs/payment-jobs/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ readme = "README.md"

[tool.poetry.dependencies]
python = "^3.12"
pay-api = {git = "https://github.com/seeker25/sbc-pay.git", branch = "25571", subdirectory = "pay-api"}
pay-api = {git = "https://github.com/rodrigo-barraza/sbc-pay.git", branch = "feature/24664", subdirectory = "pay-api"}
flask = "^3.0.2"
flask-sqlalchemy = "^3.1.1"
sqlalchemy = "^2.0.28"
Expand Down
14 changes: 10 additions & 4 deletions jobs/payment-jobs/tasks/eft_statement_due_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@
from pay_api.services import NonSufficientFundsService
from pay_api.services.statement import Statement
from pay_api.services.statement_settings import StatementSettings as StatementSettingsService
from pay_api.utils.enums import InvoiceStatus, PaymentMethod, StatementFrequency
from pay_api.utils.auth_event import AuthEvent
from pay_api.utils.enums import InvoiceStatus, PaymentMethod, QueueSources, StatementFrequency, SuspensionReasonCodes
from pay_api.utils.util import current_local_time
from sentry_sdk import capture_message
from sqlalchemy import select

from utils.auth_event import AuthEvent
from utils.enums import StatementNotificationAction
from utils.mailer import StatementNotificationInfo, publish_payment_notification

Expand Down Expand Up @@ -160,8 +160,14 @@ def _update_invoice_overdue_status(cls):

# Only publish lock event if it is not already locked
if payment_account.has_overdue_invoices is None:
additional_emails = current_app.config.get("EFT_OVERDUE_NOTIFY_EMAILS")
AuthEvent.publish_lock_account_event(payment_account, additional_emails)
lock_account_event_params = {
"pay_account": payment_account,
"additional_emails": current_app.config.get("EFT_OVERDUE_NOTIFY_EMAILS"),
"payment_method": PaymentMethod.EFT.value,
"source": QueueSources.PAY_JOBS.value,
"suspension_reason_code": SuspensionReasonCodes.OVERDUE_EFT.value,
}
AuthEvent.publish_lock_account_event(lock_account_event_params)

# Even if the account is locked, there is a new overdue statement that needs NSF invoices added and
# set the most recent date for has_overdue_invoices
Expand Down
3 changes: 1 addition & 2 deletions jobs/payment-jobs/tasks/eft_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from pay_api.services.cfs_service import CFSService
from pay_api.services.eft_service import EftService
from pay_api.services.invoice import Invoice as InvoiceService
from pay_api.utils.auth_event import AuthEvent
from pay_api.utils.enums import (
CfsAccountStatus,
EFTCreditInvoiceStatus,
Expand All @@ -44,8 +45,6 @@
from sqlalchemy import func
from sqlalchemy.orm import lazyload, registry

from utils.auth_event import AuthEvent


class EFTTask: # pylint:disable=too-few-public-methods
"""Task to link electronic funds transfers."""
Expand Down
35 changes: 28 additions & 7 deletions jobs/payment-jobs/tests/jobs/test_eft_statement_due_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ def test_send_unpaid_statement_notification(setup, session, test_name, action_on
summary = StatementService.get_summary(account.auth_account_id, statements[0][0].id)
total_amount_owing = summary["total_due"]

with patch("utils.auth_event.AuthEvent.publish_lock_account_event") as mock_auth_event:
with patch("pay_api.utils.auth_event.AuthEvent.publish_lock_account_event") as mock_auth_event:
with patch("tasks.eft_statement_due_task.publish_payment_notification") as mock_mailer:
with freeze_time(action_on):
# Statement due task looks at the month before.
Expand Down Expand Up @@ -228,11 +228,17 @@ def test_account_lock(setup, session):
assert invoices2 is not None
assert invoices2[0].invoice_id == invoice2.id

with patch("utils.auth_event.AuthEvent.publish_lock_account_event") as mock_auth_event:
with patch("pay_api.utils.auth_event.AuthEvent.publish_lock_account_event") as mock_auth_event:
with patch("tasks.eft_statement_due_task.publish_payment_notification"):
EFTStatementDueTask.process_unpaid_statements()
mock_auth_event.assert_called_once()
expected_calls = [call(account1, "")]
expected_calls = [call({
'pay_account': account1,
'additional_emails': '',
'payment_method': PaymentMethod.EFT.value,
'source': 'PAY-JOBS',
'suspension_reason_code': 'OVERDUE_EFT'
})]
mock_auth_event.assert_has_calls(expected_calls, any_order=True)
assert account1.has_overdue_invoices
assert statements[0][0].overdue_notification_date
Expand All @@ -258,7 +264,7 @@ def test_account_lock(setup, session):
assert invoices3 is not None
assert invoices3[0].invoice_id == invoice3.id

with patch("utils.auth_event.AuthEvent.publish_lock_account_event") as mock_auth_event:
with patch("pay_api.utils.auth_event.AuthEvent.publish_lock_account_event") as mock_auth_event:
with patch("tasks.eft_statement_due_task.publish_payment_notification"):
EFTStatementDueTask.process_unpaid_statements()
# Already locked we should not be publishing another event
Expand Down Expand Up @@ -315,11 +321,26 @@ def test_multi_account_lock(setup, session):
assert invoices2 is not None
assert invoices2[0].invoice_id == invoice2.id

with patch("utils.auth_event.AuthEvent.publish_lock_account_event") as mock_auth_event:
with patch("pay_api.utils.auth_event.AuthEvent.publish_lock_account_event") as mock_auth_event:
with patch("tasks.eft_statement_due_task.publish_payment_notification"):
EFTStatementDueTask.process_unpaid_statements()
mock_auth_event.call_count == 2
expected_calls = [call(account1, ""), call(account2, "")]
expected_calls = [
call({
'pay_account': account1,
'additional_emails': '',
'payment_method': PaymentMethod.EFT.value,
'source': 'PAY-JOBS',
'suspension_reason_code': 'OVERDUE_EFT'
}),
call({
'pay_account': account2,
'additional_emails': '',
'payment_method': PaymentMethod.EFT.value,
'source': 'PAY-JOBS',
'suspension_reason_code': 'OVERDUE_EFT'
})
]
mock_auth_event.assert_has_calls(expected_calls, any_order=True)
assert statements1[0][1].overdue_notification_date
assert NonSufficientFundsModel.find_by_invoice_id(invoice1.id)
Expand Down Expand Up @@ -364,7 +385,7 @@ def test_statement_due_overrides(setup, session, test_name, date_override, actio
summary = StatementService.get_summary(account.auth_account_id, statements[0][0].id)
total_amount_owing = summary["total_due"]

with patch("utils.auth_event.AuthEvent.publish_lock_account_event") as mock_auth_event:
with patch("pay_api.utils.auth_event.AuthEvent.publish_lock_account_event") as mock_auth_event:
with patch("tasks.eft_statement_due_task.publish_payment_notification") as mock_mailer:
# Statement due task looks at the month before.
if test_name == "overdue":
Expand Down
2 changes: 1 addition & 1 deletion jobs/payment-jobs/tests/jobs/test_eft_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ def test_unlock_overdue_accounts(session):
factory_invoice_reference(invoice_id=invoice_2.id)
factory_create_eft_credit_invoice_link(invoice_id=invoice_2.id, eft_credit_id=eft_credit.id, amount=10)

with patch("utils.auth_event.AuthEvent.publish_unlock_account_event") as mock_unlock:
with patch("pay_api.utils.auth_event.AuthEvent.publish_unlock_account_event") as mock_unlock:
EFTTask.link_electronic_funds_transfers_cfs()
assert payment_account.has_overdue_invoices is None
mock_unlock.assert_called_once()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,56 @@
"""Common code that sends AUTH events."""

from flask import current_app
from sbc_common_components.utils.enums import QueueMessageTypes
from sentry_sdk import capture_message

from pay_api.models import PaymentAccount as PaymentAccountModel
from pay_api.services import gcp_queue_publisher
from pay_api.services.gcp_queue_publisher import QueueMessage
from pay_api.utils.enums import PaymentMethod, QueueSources, SuspensionReasonCodes
from sbc_common_components.utils.enums import QueueMessageTypes
from sentry_sdk import capture_message
from pay_api.utils.enums import QueueSources


class AuthEvent:
"""Publishes to the auth-queue as an auth event though PUBSUB, this message gets sent to account-mailer after."""

@staticmethod
def publish_lock_account_event(pay_account: PaymentAccountModel, additional_emails=""):
def publish_lock_account_event(params: dict):
"""Publish NSF lock account event to the auth queue."""
pay_account = params.get("pay_account")
additional_emails = params.get("additional_emails", "")
payment_method = params.get("payment_method", None)
source = params.get("source", None)
suspension_reason_code = params.get("suspension_reason_code", None)
outstanding_amount = params.get("outstanding_amount", None)
original_amount = params.get("original_amount", None)
amount = params.get("amount", None)
try:
payload = AuthEvent._create_event_payload(pay_account, additional_emails)
lock_payload = {
"accountId": pay_account.auth_account_id,
"paymentMethod": payment_method,
"suspensionReasonCode": suspension_reason_code,
"additionalEmails": additional_emails,
"outstandingAmount": outstanding_amount,
"originalAmount": original_amount,
"amount": amount,
}
gcp_queue_publisher.publish_to_queue(
QueueMessage(
source=QueueSources.PAY_JOBS.value,
source=source,
message_type=QueueMessageTypes.NSF_LOCK_ACCOUNT.value,
payload=payload,
payload=lock_payload,
topic=current_app.config.get("AUTH_EVENT_TOPIC"),
)
)
except Exception: # NOQA pylint: disable=broad-except
current_app.logger.error("Error publishing lock event:", exc_info=True)
current_app.logger.warning(
f"Notification to Queue failed for the Account {
pay_account.auth_account_id} - {pay_account.name}"
pay_account.auth_account_id} - {pay_account.name}"
)
capture_message(
f"Notification to Queue failed for the Account {
pay_account.auth_account_id}, {payload}.",
pay_account.auth_account_id}, {lock_payload}.",
level="error",
)

Expand All @@ -57,19 +74,10 @@ def publish_unlock_account_event(payment_account: PaymentAccountModel):
current_app.logger.error("Error publishing NSF unlock event:", exc_info=True)
current_app.logger.warning(
f"Notification to Queue failed for the Account {
payment_account.auth_account_id} - {payment_account.name}"
payment_account.auth_account_id} - {payment_account.name}"
)
capture_message(
f"Notification to Queue failed for the Account {
payment_account.auth_account_id}, {unlock_payload}.",
payment_account.auth_account_id}, {unlock_payload}.",
level="error",
)

@staticmethod
def _create_event_payload(pay_account, additional_emails=""):
return {
"accountId": pay_account.auth_account_id,
"paymentMethod": PaymentMethod.EFT.value,
"suspensionReasonCode": SuspensionReasonCodes.OVERDUE_EFT.value,
"additionalEmails": additional_emails,
}
1 change: 1 addition & 0 deletions pay-queue/devops/vaults.gcp.env
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ PAY_CONNECTOR_AUTH="op://relationship/$APP_ENV/pay-api/PAY_CONNECTOR_AUTH"
EFT_TDI17_LOCATION_ID="op://relationship/$APP_ENV/pay-queue/EFT_TDI17_LOCATION_ID"
EFT_WIRE_PATTERNS="op://relationship/$APP_ENV/pay-queue/EFT_WIRE_PATTERNS"
EFT_PATTERNS="op://relationship/$APP_ENV/pay-queue/EFT_PATTERNS"
PAD_OVERDUE_NOTIFY_EMAILS="op://relationship/$APP_ENV/pay-queue/PAD_OVERDUE_NOTIFY_EMAILS"
Loading
Loading