From 95cc89ee64b7bb53bf8c228334a498d09e9b62eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Szyma=C5=84ski?= Date: Wed, 8 May 2024 11:47:15 +0200 Subject: [PATCH] Fix transactionUpdate/transactionCreate with empty metadata (#15890) --- .../transaction/transaction_create.py | 4 +- .../mutations/test_transaction_create.py | 118 ++++++++++++++++++ .../mutations/test_transaction_update.py | 52 ++++++++ 3 files changed, 173 insertions(+), 1 deletion(-) diff --git a/saleor/graphql/payment/mutations/transaction/transaction_create.py b/saleor/graphql/payment/mutations/transaction/transaction_create.py index cf67b3cfdc4..2a10318b192 100644 --- a/saleor/graphql/payment/mutations/transaction/transaction_create.py +++ b/saleor/graphql/payment/mutations/transaction/transaction_create.py @@ -136,8 +136,10 @@ def validate_external_url(cls, external_url: Optional[str], error_code: str): @classmethod def validate_metadata_keys( # type: ignore[override] - cls, metadata_list: list[dict], field_name, error_code + cls, metadata_list: Optional[list[dict]], field_name, error_code ): + if not metadata_list: + return if metadata_contains_empty_key(metadata_list): raise ValidationError( { diff --git a/saleor/graphql/payment/tests/mutations/test_transaction_create.py b/saleor/graphql/payment/tests/mutations/test_transaction_create.py index 7aaa7e90806..186f34daa44 100644 --- a/saleor/graphql/payment/tests/mutations/test_transaction_create.py +++ b/saleor/graphql/payment/tests/mutations/test_transaction_create.py @@ -195,6 +195,63 @@ def test_transaction_create_for_order_by_app( assert transaction.external_url == external_url +def test_transaction_create_for_order_by_app_metadata_null_value( + order_with_lines, permission_manage_payments, app_api_client +): + # given + name = "Credit Card" + psp_reference = "PSP reference - 123" + available_actions = [ + TransactionActionEnum.CHARGE.name, + TransactionActionEnum.CHARGE.name, + ] + authorized_value = Decimal("10") + external_url = f"http://{TEST_SERVER_DOMAIN}/external-url" + + variables = { + "id": graphene.Node.to_global_id("Order", order_with_lines.pk), + "transaction": { + "name": name, + "pspReference": psp_reference, + "availableActions": available_actions, + "amountAuthorized": { + "amount": authorized_value, + "currency": "USD", + }, + "metadata": None, + "privateMetadata": None, + "externalUrl": external_url, + }, + } + + # when + response = app_api_client.post_graphql( + MUTATION_TRANSACTION_CREATE, variables, permissions=[permission_manage_payments] + ) + + # then + available_actions = list(set(available_actions)) + + transaction = order_with_lines.payment_transactions.first() + content = get_graphql_content(response) + data = content["data"]["transactionCreate"]["transaction"] + assert data["actions"] == available_actions + assert data["pspReference"] == psp_reference + assert data["authorizedAmount"]["amount"] == authorized_value + assert data["externalUrl"] == external_url + assert data["createdBy"]["id"] == to_global_id_or_none(app_api_client.app) + + assert available_actions == list(map(str.upper, transaction.available_actions)) + assert psp_reference == transaction.psp_reference + assert authorized_value == transaction.authorized_value + assert transaction.metadata == {} + assert transaction.private_metadata == {} + assert transaction.app_identifier == app_api_client.app.identifier + assert transaction.app == app_api_client.app + assert transaction.user is None + assert transaction.external_url == external_url + + def test_transaction_create_for_order_updates_order_total_authorized_by_app( order_with_lines, permission_manage_payments, app_api_client ): @@ -351,6 +408,67 @@ def test_transaction_create_for_checkout_by_app( assert transaction.user is None +def test_transaction_create_for_checkout_by_app_metadata_null_value( + checkout_with_items, permission_manage_payments, app_api_client +): + # given + name = "Credit Card" + psp_reference = "PSP reference - 123" + available_actions = [ + TransactionActionEnum.CHARGE.name, + TransactionActionEnum.CHARGE.name, + ] + authorized_value = Decimal("10") + external_url = f"http://{TEST_SERVER_DOMAIN}/external-url" + + variables = { + "id": graphene.Node.to_global_id("Checkout", checkout_with_items.pk), + "transaction": { + "name": name, + "pspReference": psp_reference, + "availableActions": available_actions, + "amountAuthorized": { + "amount": authorized_value, + "currency": "USD", + }, + "metadata": None, + "privateMetadata": None, + "externalUrl": external_url, + }, + } + + # when + response = app_api_client.post_graphql( + MUTATION_TRANSACTION_CREATE, variables, permissions=[permission_manage_payments] + ) + + # then + checkout_with_items.refresh_from_db() + assert checkout_with_items.charge_status == CheckoutChargeStatus.NONE + assert checkout_with_items.authorize_status == CheckoutAuthorizeStatus.PARTIAL + + available_actions = list(set(available_actions)) + + transaction = checkout_with_items.payment_transactions.first() + content = get_graphql_content(response) + data = content["data"]["transactionCreate"]["transaction"] + assert data["actions"] == available_actions + assert data["pspReference"] == psp_reference + assert data["authorizedAmount"]["amount"] == authorized_value + assert data["externalUrl"] == external_url + assert data["createdBy"]["id"] == to_global_id_or_none(app_api_client.app) + + assert available_actions == list(map(str.upper, transaction.available_actions)) + assert psp_reference == transaction.psp_reference + assert authorized_value == transaction.authorized_value + assert transaction.metadata == {} + assert transaction.private_metadata == {} + assert transaction.external_url == external_url + assert transaction.app_identifier == app_api_client.app.identifier + assert transaction.app == app_api_client.app + assert transaction.user is None + + @pytest.mark.parametrize( ("amount_field_name", "amount_db_field"), [ diff --git a/saleor/graphql/payment/tests/mutations/test_transaction_update.py b/saleor/graphql/payment/tests/mutations/test_transaction_update.py index 0fa383e9451..c0d79c74f88 100644 --- a/saleor/graphql/payment/tests/mutations/test_transaction_update.py +++ b/saleor/graphql/payment/tests/mutations/test_transaction_update.py @@ -241,6 +241,31 @@ def test_transaction_update_metadata_by_app( assert transaction_item_created_by_app.metadata == {meta_key: meta_value} +def test_transaction_update_metadata_by_app_null_value( + transaction_item_created_by_app, permission_manage_payments, app_api_client +): + # given + transaction = transaction_item_created_by_app + + variables = { + "id": graphene.Node.to_global_id("TransactionItem", transaction.token), + "transaction": { + "metadata": None, + }, + } + + # when + response = app_api_client.post_graphql( + MUTATION_TRANSACTION_UPDATE, variables, permissions=[permission_manage_payments] + ) + + # then + transaction.refresh_from_db() + content = get_graphql_content(response) + data = content["data"]["transactionUpdate"]["transaction"] + assert len(data["metadata"]) == 0 + + def test_transaction_update_metadata_incorrect_key_by_app( transaction_item_created_by_app, permission_manage_payments, app_api_client ): @@ -300,6 +325,33 @@ def test_transaction_update_private_metadata_by_app( assert transaction_item_created_by_app.private_metadata == {meta_key: meta_value} +def test_transaction_update_private_metadata_by_app_null_value( + transaction_item_created_by_app, permission_manage_payments, app_api_client +): + # given + transaction = transaction_item_created_by_app + transaction.private_metadata = {"key": "value"} + transaction.save(update_fields=["private_metadata"]) + + variables = { + "id": graphene.Node.to_global_id("TransactionItem", transaction.token), + "transaction": { + "privateMetadata": None, + }, + } + + # when + response = app_api_client.post_graphql( + MUTATION_TRANSACTION_UPDATE, variables, permissions=[permission_manage_payments] + ) + + # then + transaction.refresh_from_db() + content = get_graphql_content(response) + data = content["data"]["transactionUpdate"]["transaction"] + assert len(data["privateMetadata"]) == 1 + + def test_transaction_update_private_metadata_incorrect_key_by_app( transaction_item_created_by_app, permission_manage_payments, app_api_client ):