diff --git a/pay-api/src/pay_api/models/eft_refund.py b/pay-api/src/pay_api/models/eft_refund.py index eaafbede4..c21eb7e76 100644 --- a/pay-api/src/pay_api/models/eft_refund.py +++ b/pay-api/src/pay_api/models/eft_refund.py @@ -62,7 +62,6 @@ class EFTRefund(Audit): cas_supplier_site = db.Column(db.String(), nullable=True) comment = db.Column(db.String(), nullable=False) decline_reason = db.Column(db.String(), nullable=True) - created_by = db.Column("created_by", db.String(100), nullable=True) created_on = db.Column("created_on", db.DateTime, nullable=False, default=lambda: datetime.now(tz=timezone.utc)) disbursement_date = db.Column( "disbursement_date", db.DateTime, nullable=False, default=lambda: datetime.now(tz=timezone.utc) diff --git a/pay-api/src/pay_api/models/eft_short_names.py b/pay-api/src/pay_api/models/eft_short_names.py index f72f415f8..242985765 100644 --- a/pay-api/src/pay_api/models/eft_short_names.py +++ b/pay-api/src/pay_api/models/eft_short_names.py @@ -125,6 +125,9 @@ class EFTShortnameSummarySchema: id: int short_name: str short_name_type: str + cas_supplier_number: str + cas_supplier_site: str + email: str last_payment_received_date: datetime credits_remaining: Decimal linked_accounts_count: int @@ -140,6 +143,9 @@ def from_row(cls, row: EFTShortnames): id=row.id, short_name=row.short_name, short_name_type=row.type, + cas_supplier_number=getattr(row, "cas_supplier_number", None), + cas_supplier_site=getattr(row, "cas_supplier_site", None), + email=getattr(row, "email", None), last_payment_received_date=getattr(row, "last_payment_received_date", None), credits_remaining=getattr(row, "credits_remaining", None), linked_accounts_count=getattr(row, "linked_accounts_count", None), diff --git a/pay-api/src/pay_api/services/eft_refund.py b/pay-api/src/pay_api/services/eft_refund.py index 7aba50066..751b7ec97 100644 --- a/pay-api/src/pay_api/services/eft_refund.py +++ b/pay-api/src/pay_api/services/eft_refund.py @@ -195,7 +195,8 @@ def refund_eft_credits(shortname_id: int, amount: Decimal): raise BusinessException(Error.INVALID_REFUND) @staticmethod - def update_shortname_refund(refund_id: int, data: EFTShortNameRefundPatchRequest) -> EFTRefundModel: + @user_context + def update_shortname_refund(refund_id: int, data: EFTShortNameRefundPatchRequest, **kwargs) -> EFTRefundModel: """Update the refund status.""" refund = EFTRefundModel.find_by_id(refund_id) if refund.status != EFTShortnameRefundStatus.PENDING_APPROVAL.value: @@ -225,6 +226,9 @@ def update_shortname_refund(refund_id: int, data: EFTShortNameRefundPatchRequest expense_authority_recipients = get_emails_with_keycloak_role(Role.EFT_REFUND_APPROVER.value) send_email(expense_authority_recipients, subject, body) case EFTShortnameRefundStatus.APPROVED.value: + if kwargs["user"].user_name == refund.created_by: + raise BusinessException(Error.EFT_REFUND_SAME_USER_APPROVAL_FORBIDDEN) + history = EFTHistoryModel.find_by_eft_refund_id(refund.id)[0] history.transaction_type = EFTHistoricalTypes.SN_REFUND_APPROVED.value history.save() diff --git a/pay-api/src/pay_api/services/eft_short_name_summaries.py b/pay-api/src/pay_api/services/eft_short_name_summaries.py index 69817ab18..7d5cf004a 100644 --- a/pay-api/src/pay_api/services/eft_short_name_summaries.py +++ b/pay-api/src/pay_api/services/eft_short_name_summaries.py @@ -137,6 +137,9 @@ def get_search_query(cls, search_criteria: EFTShortnamesSearch): EFTShortnameModel.id, EFTShortnameModel.short_name, EFTShortnameModel.type, + EFTShortnameModel.cas_supplier_number, + EFTShortnameModel.cas_supplier_site, + EFTShortnameModel.email, func.coalesce(linked_account_subquery.c.count, 0).label("linked_accounts_count"), func.coalesce(credit_remaining_subquery.c.total, 0).label("credits_remaining"), last_payment_subquery.c.deposit_date.label("last_payment_received_date"), diff --git a/pay-api/src/pay_api/utils/errors.py b/pay-api/src/pay_api/utils/errors.py index c0f53d5ee..775605005 100644 --- a/pay-api/src/pay_api/utils/errors.py +++ b/pay-api/src/pay_api/utils/errors.py @@ -135,6 +135,7 @@ class Error(Enum): HTTPStatus.BAD_REQUEST, ) EFT_INVOICES_OVERDUE = "EFT_INVOICES_OVERDUE", HTTPStatus.BAD_REQUEST + EFT_REFUND_SAME_USER_APPROVAL_FORBIDDEN = "EFT_REFUND_SAME_USER_APPROVAL_FORBIDDEN", HTTPStatus.FORBIDDEN FAS_INVALID_PAYMENT_METHOD = "FAS_INVALID_PAYMENT_METHOD", HTTPStatus.BAD_REQUEST FAS_INVALID_ROUTING_SLIP_NUMBER = ( diff --git a/pay-api/src/pay_api/version.py b/pay-api/src/pay_api/version.py index 8d5a9929a..98239652f 100644 --- a/pay-api/src/pay_api/version.py +++ b/pay-api/src/pay_api/version.py @@ -22,4 +22,4 @@ Development release segment: .devN """ -__version__ = "1.22.9" # pylint: disable=invalid-name +__version__ = "1.22.10" # pylint: disable=invalid-name diff --git a/pay-api/tests/unit/api/test_eft_short_names.py b/pay-api/tests/unit/api/test_eft_short_names.py index 406a6f236..cdbc2c65e 100755 --- a/pay-api/tests/unit/api/test_eft_short_names.py +++ b/pay-api/tests/unit/api/test_eft_short_names.py @@ -1117,6 +1117,15 @@ def test_get_shortname_refund(session, client, jwt, query_string_factory, test_n @pytest.mark.parametrize( "test_name, payload, role", [ + ( + "forbidden_approved_refund", + EFTShortNameRefundPatchRequest( + comment="Test comment", + decline_reason="Test reason", + status=EFTShortnameRefundStatus.APPROVED.value, + ).to_dict(), + Role.EFT_REFUND_APPROVER.value, + ), ( "valid_approved_refund", EFTShortNameRefundPatchRequest( @@ -1172,10 +1181,15 @@ def test_patch_shortname_refund( remaining_amount=90, ).save() eft_history = factory_eft_history(short_name.id, refund.id, 10, 10) + user_name = "TEST_USER" if test_name == "bad_transition": refund.status = EFTShortnameRefundStatus.APPROVED.value refund.save() - token = jwt.create_jwt(get_claims(roles=[role]), token_header) + elif test_name == "valid_approved_refund": + refund.created_by = "OTHER_USER" + refund.save() + + token = jwt.create_jwt(get_claims(roles=[role], username=user_name), token_header) headers = {"Authorization": f"Bearer {token}", "content-type": "application/json"} rv = client.patch( f"/api/v1/eft-shortnames/shortname-refund/{refund.id}", @@ -1183,6 +1197,8 @@ def test_patch_shortname_refund( json=payload, ) match test_name: + case "forbidden_approved_refund": + assert rv.status_code == 403 case "unauthorized": assert rv.status_code == 401 case "bad_transition" | "invalid_patch_refund": diff --git a/pay-api/tests/utilities/base_test.py b/pay-api/tests/utilities/base_test.py index 5757f2573..0c8cf64dc 100644 --- a/pay-api/tests/utilities/base_test.py +++ b/pay-api/tests/utilities/base_test.py @@ -971,9 +971,11 @@ def factory_eft_refund( comment="test comment", status="PENDING", decline_reason=None, + created_by="TEST_USER", ): """Return an EFT Refund.""" return EFTRefund( + created_by=created_by, decline_reason=decline_reason, short_name_id=short_name_id, refund_amount=refund_amount,