Skip to content

Commit

Permalink
Merge branch 'main' into feature/17534
Browse files Browse the repository at this point in the history
  • Loading branch information
rodrigo-barraza committed Dec 11, 2023
2 parents 456eb65 + dafa812 commit 31aa3da
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 30 deletions.
2 changes: 0 additions & 2 deletions jobs/payment-jobs/tasks/distribution_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,7 @@ def update_invoice_to_refunded_or_paid(cls, invoice: InvoiceModel):
refund.gl_posted = datetime.now()
refund.save()
invoice.invoice_status_code = InvoiceStatus.REFUNDED.value
invoice.refund_date = datetime.now()
else:
invoice.invoice_status_code = InvoiceStatus.PAID.value
invoice.payment_date = datetime.now()
invoice.save()
current_app.logger.info(f'Updated invoice : {invoice.id}')
2 changes: 0 additions & 2 deletions jobs/payment-jobs/tests/jobs/test_distribution_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ def test_update_failed_distributions_refunds(session, monkeypatch):

DistributionTask.update_failed_distributions()
assert invoice.invoice_status_code == InvoiceStatus.REFUNDED.value
assert invoice.refund_date is not None


def test_update_failed_distribution_payments(session, monkeypatch):
Expand Down Expand Up @@ -112,7 +111,6 @@ def test_non_direct_pay_invoices(session, monkeypatch):
factory_refund_invoice(invoice.id)
DistributionTask.update_failed_distributions()
assert invoice.invoice_status_code == InvoiceStatus.REFUNDED.value
assert invoice.refund_date is not None


def test_no_response_pay_bc(session, monkeypatch):
Expand Down
4 changes: 2 additions & 2 deletions pay-api/src/pay_api/services/ejv_pay_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def process_cfs_refund(self, invoice: InvoiceModel,
Return the status after checking invoice status.
1. If invoice status is APPROVED:
1.1 return REFUND_REQUESTED if there is an ACTIVE invoice_reference
1.2 else return REFUNDED (as no refund process is needed for this as JV hasn't started yet)
1.2 else return CANCELLED (as no refund process is needed for this as JV hasn't started yet)
2. If invoice status is PAID
2.1 Return REFUND_REQUESTED
"""
Expand All @@ -82,5 +82,5 @@ def process_cfs_refund(self, invoice: InvoiceModel,
if invoice.invoice_status_code == InvoiceStatus.APPROVED.value:
if InvoiceReference.find_active_reference_by_invoice_id(invoice.id):
return InvoiceStatus.REFUND_REQUESTED.value
return InvoiceStatus.REFUNDED.value
return InvoiceStatus.CANCELLED.value
return InvoiceStatus.REFUND_REQUESTED.value
25 changes: 24 additions & 1 deletion pay-api/src/pay_api/services/payment_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from pay_api.services.cfs_service import CFSService
from pay_api.services.distribution_code import DistributionCode
from pay_api.services.queue_publisher import publish_response
from pay_api.services.statement_settings import StatementSettings
from pay_api.utils.enums import (
CfsAccountStatus, InvoiceStatus, MessageType, PaymentMethod, PaymentSystem, StatementFrequency)
from pay_api.utils.errors import Error
Expand Down Expand Up @@ -352,6 +353,20 @@ def create(cls, account_request: Dict[str, Any] = None, is_sandbox: bool = False
current_app.logger.debug('>create payment account')
return payment_account

@classmethod
def _check_and_update_statement_settings(cls, payment_account: PaymentAccountModel):
"""Check and update statement settings based on payment method."""
# On create of a payment account _persist_default_statement_frequency() is used, so we
# will only check if an update is needed if statement settings already exists - i.e an update
if payment_account and payment_account.payment_method == PaymentMethod.EFT.value:
# EFT payment method should automatically set statement frequency to MONTHLY
auth_account_id = str(payment_account.auth_account_id)
statements_settings: StatementSettingsModel = StatementSettingsModel\
.find_active_settings(auth_account_id, datetime.today())

if statements_settings is not None and statements_settings.frequency != StatementFrequency.MONTHLY.value:
StatementSettings.update_statement_settings(auth_account_id, StatementFrequency.MONTHLY.value)

@classmethod
def _save_account(cls, account_request: Dict[str, any], payment_account: PaymentAccountModel,
is_sandbox: bool = False):
Expand Down Expand Up @@ -390,6 +405,7 @@ def _save_account(cls, account_request: Dict[str, any], payment_account: Payment
if payment_method:
pay_system = PaymentSystemFactory.create_from_payment_method(payment_method=payment_method)
cls._handle_payment_details(account_request, is_sandbox, pay_system, payment_account, payment_info)
cls._check_and_update_statement_settings(payment_account)
payment_account.save()

@classmethod
Expand Down Expand Up @@ -534,8 +550,15 @@ def _get_payment_based_on_pad_activation(account: PaymentAccountModel) -> Tuple[

@staticmethod
def _persist_default_statement_frequency(payment_account_id):
payment_account: PaymentAccountModel = PaymentAccountModel.find_by_id(payment_account_id)
frequency = StatementFrequency.default_frequency().value

# EFT Payment method default to MONTHLY frequency
if payment_account.payment_method == PaymentMethod.EFT.value:
frequency = StatementFrequency.MONTHLY.value

statement_settings_model = StatementSettingsModel(
frequency=StatementFrequency.default_frequency().value,
frequency=frequency,
payment_account_id=payment_account_id
)
statement_settings_model.save()
Expand Down
2 changes: 1 addition & 1 deletion pay-api/src/pay_api/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@
Development release segment: .devN
"""

__version__ = '1.20.3' # pylint: disable=invalid-name
__version__ = '1.20.4' # pylint: disable=invalid-name
41 changes: 40 additions & 1 deletion pay-api/tests/unit/services/test_payment_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@
from pay_api.models import EFTCredit as EFTCreditModel
from pay_api.models import EFTShortnames as EFTShortnameModel
from pay_api.models import Invoice as InvoiceModel
from pay_api.models import StatementSettings as StatementSettingsModel
from pay_api.services.payment_account import PaymentAccount as PaymentAccountService
from pay_api.utils.enums import CfsAccountStatus, InvoiceStatus, PaymentMethod
from pay_api.utils.enums import CfsAccountStatus, InvoiceStatus, PaymentMethod, StatementFrequency
from pay_api.utils.errors import Error
from pay_api.utils.util import get_outstanding_txns_from_date
from tests.utilities.base_test import (
Expand Down Expand Up @@ -336,3 +337,41 @@ def test_payment_request_eft_with_credit(session, client, jwt, app):
assert invoice.invoice_status_code == InvoiceStatus.PAID.value
assert eft_credit_1.remaining_amount == 0
assert eft_credit_2.remaining_amount == 10


def test_eft_payment_method_settings(session, client, jwt, app):
"""Assert EFT payment method statement settings are applied."""
# Validate on account create with EFT payment method that statement settings are automatically set to MONTHLY
payment_account: PaymentAccountService = PaymentAccountService.create(
get_premium_account_payload(payment_method=PaymentMethod.EFT.value))

assert payment_account is not None
assert payment_account.payment_method == PaymentMethod.EFT.value

statement_settings: StatementSettingsModel = StatementSettingsModel\
.find_active_settings(str(payment_account.auth_account_id), datetime.today())

assert statement_settings is not None
assert statement_settings.frequency == StatementFrequency.MONTHLY.value

# Validate on account update to EFT payment method that statement settings are automatically set to MONTHLY
payment_account_2: PaymentAccountService = PaymentAccountService.create(
get_premium_account_payload(account_id=payment_account.id + 1,
payment_method=PaymentMethod.ONLINE_BANKING.value))

assert payment_account_2 is not None
assert payment_account_2.payment_method == PaymentMethod.ONLINE_BANKING.value

payment_account_2 = PaymentAccountService\
.update(payment_account_2.auth_account_id,
get_eft_enable_account_payload(payment_method=PaymentMethod.EFT.value,
account_id=payment_account_2.auth_account_id))

assert payment_account_2 is not None
assert payment_account_2.payment_method == PaymentMethod.EFT.value

statement_settings: StatementSettingsModel = StatementSettingsModel \
.find_latest_settings(str(payment_account_2.auth_account_id))

assert statement_settings is not None
assert statement_settings.frequency == StatementFrequency.MONTHLY.value
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,8 @@ async def _process_jv_details_feedback(ejv_file, has_errors, line, receipt_numbe
.find_by_id(debit_distribution.disbursement_distribution_code_id)
credit_distribution.stop_ejv = True
else:
await _update_invoice_disbursement_status(invoice)
effective_date = datetime.strptime(line[22:30], '%Y%m%d')
await _update_invoice_disbursement_status(invoice, effective_date)

elif line[104:105] == 'D' and ejv_file.file_type == EjvFileType.PAYMENT.value:
# This is for gov account payment JV.
Expand All @@ -223,9 +224,10 @@ async def _process_jv_details_feedback(ejv_file, has_errors, line, receipt_numbe
dist_code.stop_ejv = True
elif invoice_link.disbursement_status_code == DisbursementStatus.COMPLETED.value:
# Set the invoice status as REFUNDED if it's a JV reversal, else mark as PAID
effective_date = datetime.strptime(line[22:30], '%Y%m%d')
is_reversal = invoice.invoice_status_code in (
InvoiceStatus.REFUNDED.value, InvoiceStatus.REFUND_REQUESTED.value)
_set_invoice_jv_reversal(invoice, is_reversal)
_set_invoice_jv_reversal(invoice, effective_date, is_reversal)

# Mark the invoice reference as COMPLETED, create a receipt
if inv_ref:
Expand All @@ -242,14 +244,14 @@ async def _process_jv_details_feedback(ejv_file, has_errors, line, receipt_numbe
return has_errors


def _set_invoice_jv_reversal(invoice: InvoiceModel, is_reversal: bool):
def _set_invoice_jv_reversal(invoice: InvoiceModel, effective_date: datetime, is_reversal: bool):
# Set the invoice status as REFUNDED if it's a JV reversal, else mark as PAID
if is_reversal:
invoice.invoice_status_code = InvoiceStatus.REFUNDED.value
invoice.refund_date = datetime.now()
invoice.refund_date = effective_date
else:
invoice.invoice_status_code = InvoiceStatus.PAID.value
invoice.payment_date = datetime.now()
invoice.payment_date = effective_date
invoice.paid = invoice.total


Expand All @@ -262,9 +264,9 @@ def _fix_invoice_line(line):
return line


async def _update_invoice_disbursement_status(invoice):
async def _update_invoice_disbursement_status(invoice, effective_date: datetime):
"""Update status to reversed if its a refund, else to completed."""
invoice.disbursement_date = datetime.now()
invoice.disbursement_date = effective_date
if invoice.invoice_status_code in (InvoiceStatus.REFUNDED.value, InvoiceStatus.REFUND_REQUESTED.value):
invoice.disbursement_status_code = DisbursementStatus.REVERSED.value
else:
Expand Down Expand Up @@ -413,7 +415,8 @@ async def _process_ap_header_non_gov_disbursement(line, ejv_file: EjvFileModel)
capture_message(f'AP - NON-GOV - Disbursement failed for {invoice_id}, reason : {ap_header_error_message}',
level='error')
else:
await _update_invoice_disbursement_status(invoice)
# TODO - Fix this on BC Assessment launch, so the effective date reads from the feedback.
await _update_invoice_disbursement_status(invoice, effective_date=datetime.now())
if invoice.invoice_status_code != InvoiceStatus.PAID.value:
refund = RefundModel.find_by_invoice_id(invoice.id)
refund.gl_posted = datetime.now()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ async def _process_paid_invoices(inv_references, row):
logger.debug('PAID Invoice. Invoice Reference ID : %s, invoice ID : %s', inv_ref.id, inv_ref.invoice_id)

inv.invoice_status_code = InvoiceStatus.PAID.value
inv.payment_date = datetime.now()
inv.payment_date = receipt_date
inv.paid = inv.total
# Create Receipt records
receipt: ReceiptModel = ReceiptModel()
Expand Down
Loading

0 comments on commit 31aa3da

Please sign in to comment.