From 30d3d813fc645f253557421815f9fe71b599be06 Mon Sep 17 00:00:00 2001 From: Sanchith Hegde <22217505+SanchithHegde@users.noreply.github.com> Date: Tue, 19 Nov 2024 20:33:30 +0530 Subject: [PATCH] refactor(payment_methods_v2): rename `payment_method` and `payment_method_type` fields and use concrete type for `payment_method_data` (#6555) --- api-reference-v2/openapi_spec.json | 557 ++++++++++-------- api-reference/openapi_spec.json | 243 ++++++-- crates/api_models/src/events.rs | 4 +- crates/api_models/src/events/payment.rs | 13 + crates/api_models/src/payment_methods.rs | 119 ++-- crates/api_models/src/payments.rs | 1 + crates/diesel_models/src/payment_method.rs | 78 ++- crates/diesel_models/src/schema_v2.rs | 7 +- .../src/payment_methods.rs | 55 +- .../src/type_encryption.rs | 322 +++++++++- crates/openapi/Cargo.toml | 2 +- crates/openapi/src/openapi.rs | 8 +- crates/openapi/src/openapi_v2.rs | 12 +- crates/router/src/core/customers.rs | 4 +- crates/router/src/core/locker_migration.rs | 14 +- crates/router/src/core/payment_methods.rs | 61 +- .../router/src/core/payment_methods/cards.rs | 66 ++- .../surcharge_decision_configs.rs | 5 +- .../src/core/payment_methods/transformers.rs | 10 +- crates/router/src/core/payments.rs | 4 +- crates/router/src/core/payments/helpers.rs | 24 +- .../payments/operations/payment_confirm.rs | 2 +- .../router/src/core/payments/tokenization.rs | 6 +- crates/router/src/core/pm_auth.rs | 6 +- crates/router/src/routes/payment_methods.rs | 2 +- crates/router/src/types/api/mandates.rs | 4 +- .../router/src/types/api/payment_methods.rs | 12 +- crates/router/src/types/domain/types.rs | 2 +- crates/router/src/types/transformers.rs | 4 +- .../down.sql | 9 +- .../up.sql | 9 +- 31 files changed, 1169 insertions(+), 496 deletions(-) diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index 5bf302134d27..c3bb68717681 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -3237,6 +3237,27 @@ ], "description": "Masked payout method details for bank payout method" }, + "BankCodeResponse": { + "type": "object", + "required": [ + "bank_name", + "eligible_connectors" + ], + "properties": { + "bank_name": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BankNames" + } + }, + "eligible_connectors": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "BankDebitAdditionalData": { "oneOf": [ { @@ -3507,6 +3528,20 @@ } ] }, + "BankDebitTypes": { + "type": "object", + "required": [ + "eligible_connectors" + ], + "properties": { + "eligible_connectors": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "BankHolderType": { "type": "string", "enum": [ @@ -4730,6 +4765,25 @@ } ] }, + "BankTransferTypes": { + "type": "object", + "required": [ + "eligible_connectors" + ], + "properties": { + "eligible_connectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The list of eligible connectors for a given payment experience", + "example": [ + "stripe", + "adyen" + ] + } + } + }, "BankType": { "type": "string", "enum": [ @@ -5284,7 +5338,8 @@ "card_number", "card_exp_month", "card_exp_year", - "card_holder_name" + "card_holder_name", + "card_issuing_country" ], "properties": { "card_number": { @@ -5314,9 +5369,7 @@ "nullable": true }, "card_issuing_country": { - "type": "string", - "description": "Card Issuing Country", - "nullable": true + "$ref": "#/components/schemas/CountryAlpha2" }, "card_network": { "allOf": [ @@ -5332,8 +5385,11 @@ "nullable": true }, "card_type": { - "type": "string", - "description": "Card Type", + "allOf": [ + { + "$ref": "#/components/schemas/CardType" + } + ], "nullable": true } }, @@ -5345,12 +5401,12 @@ "saved_to_locker" ], "properties": { - "scheme": { - "type": "string", - "nullable": true - }, "issuer_country": { - "type": "string", + "allOf": [ + { + "$ref": "#/components/schemas/CountryAlpha2" + } + ], "nullable": true }, "last4_digits": { @@ -5365,10 +5421,6 @@ "type": "string", "nullable": true }, - "card_token": { - "type": "string", - "nullable": true - }, "card_holder_name": { "type": "string", "nullable": true @@ -5409,21 +5461,9 @@ "CardDetailUpdate": { "type": "object", "required": [ - "card_exp_month", - "card_exp_year", "card_holder_name" ], "properties": { - "card_exp_month": { - "type": "string", - "description": "Card Expiry Month", - "example": "10" - }, - "card_exp_year": { - "type": "string", - "description": "Card Expiry Year", - "example": "25" - }, "card_holder_name": { "type": "string", "description": "Card Holder Name", @@ -5455,6 +5495,41 @@ "Maestro" ] }, + "CardNetworkTypes": { + "type": "object", + "required": [ + "eligible_connectors" + ], + "properties": { + "card_network": { + "allOf": [ + { + "$ref": "#/components/schemas/CardNetwork" + } + ], + "nullable": true + }, + "surcharge_details": { + "allOf": [ + { + "$ref": "#/components/schemas/SurchargeDetailsResponse" + } + ], + "nullable": true + }, + "eligible_connectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The list of eligible connectors for a given card network", + "example": [ + "stripe", + "adyen" + ] + } + } + }, "CardPayout": { "type": "object", "required": [ @@ -5648,6 +5723,13 @@ } ] }, + "CardType": { + "type": "string", + "enum": [ + "credit", + "debit" + ] + }, "CashappQr": { "type": "object" }, @@ -6741,20 +6823,19 @@ "CustomerPaymentMethod": { "type": "object", "required": [ - "payment_token", "payment_method_id", "customer_id", - "payment_method", + "payment_method_type", "recurring_enabled", - "installment_payment_enabled", "requires_cvv", - "default_payment_method_set" + "is_default" ], "properties": { "payment_token": { "type": "string", "description": "Token for payment method in temporary card locker which gets refreshed often", - "example": "7ebf443f-a050-4067-84e5-e6f6d4800aef" + "example": "7ebf443f-a050-4067-84e5-e6f6d4800aef", + "nullable": true }, "payment_method_id": { "type": "string", @@ -6768,10 +6849,10 @@ "maxLength": 64, "minLength": 1 }, - "payment_method": { + "payment_method_type": { "$ref": "#/components/schemas/PaymentMethod" }, - "payment_method_type": { + "payment_method_subtype": { "allOf": [ { "$ref": "#/components/schemas/PaymentMethodType" @@ -6779,54 +6860,27 @@ ], "nullable": true }, - "payment_method_issuer": { - "type": "string", - "description": "The name of the bank/ provider issuing the payment method to the end user", - "example": "Citibank", - "nullable": true - }, - "payment_method_issuer_code": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentMethodIssuerCode" - } - ], - "nullable": true - }, "recurring_enabled": { "type": "boolean", "description": "Indicates whether the payment method is eligible for recurring payments", "example": true }, - "installment_payment_enabled": { - "type": "boolean", - "description": "Indicates whether the payment method is eligible for installment payments", - "example": true - }, - "payment_experience": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PaymentExperience" - }, - "description": "Type of payment experience enabled with the connector", - "example": [ - "redirect_to_url" + "payment_method_data": { + "allOf": [ + { + "$ref": "#/components/schemas/PaymentMethodListData" + } ], "nullable": true }, - "card": { + "bank": { "allOf": [ { - "$ref": "#/components/schemas/CardDetailFromLocker" + "$ref": "#/components/schemas/MaskedBankDetails" } ], "nullable": true }, - "metadata": { - "type": "object", - "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.", - "nullable": true - }, "created": { "type": "string", "format": "date-time", @@ -6834,22 +6888,6 @@ "example": "2023-01-18T11:04:09.922Z", "nullable": true }, - "bank_transfer": { - "allOf": [ - { - "$ref": "#/components/schemas/Bank" - } - ], - "nullable": true - }, - "bank": { - "allOf": [ - { - "$ref": "#/components/schemas/MaskedBankDetails" - } - ], - "nullable": true - }, "surcharge_details": { "allOf": [ { @@ -6870,7 +6908,7 @@ "example": "2024-02-24T11:04:09.922Z", "nullable": true }, - "default_payment_method_set": { + "is_default": { "type": "boolean", "description": "Indicates if the payment method has been set to default or not", "example": true @@ -11941,6 +11979,33 @@ "collect_otp" ] }, + "PaymentExperienceTypes": { + "type": "object", + "required": [ + "eligible_connectors" + ], + "properties": { + "payment_experience_type": { + "allOf": [ + { + "$ref": "#/components/schemas/PaymentExperience" + } + ], + "nullable": true + }, + "eligible_connectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The list of eligible connectors for a given payment experience", + "example": [ + "stripe", + "adyen" + ] + } + } + }, "PaymentLinkConfig": { "type": "object", "required": [ @@ -12357,41 +12422,17 @@ "PaymentMethodCreate": { "type": "object", "required": [ - "payment_method" + "payment_method_type", + "payment_method_subtype", + "customer_id", + "payment_method_data" ], "properties": { - "payment_method": { - "$ref": "#/components/schemas/PaymentMethod" - }, "payment_method_type": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentMethodType" - } - ], - "nullable": true - }, - "payment_method_issuer": { - "type": "string", - "description": "The name of the bank/ provider issuing the payment method to the end user", - "example": "Citibank", - "nullable": true - }, - "payment_method_issuer_code": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentMethodIssuerCode" - } - ], - "nullable": true + "$ref": "#/components/schemas/PaymentMethod" }, - "card": { - "allOf": [ - { - "$ref": "#/components/schemas/CardDetail" - } - ], - "nullable": true + "payment_method_subtype": { + "$ref": "#/components/schemas/PaymentMethodType" }, "metadata": { "type": "object", @@ -12402,44 +12443,11 @@ "type": "string", "description": "The unique identifier of the customer.", "example": "cus_y3oqhf46pyzuxjbcn2giaqnb44", - "nullable": true, "maxLength": 64, "minLength": 1 }, - "card_network": { - "type": "string", - "description": "The card network", - "example": "Visa", - "nullable": true - }, - "bank_transfer": { - "allOf": [ - { - "$ref": "#/components/schemas/Bank" - } - ], - "nullable": true - }, - "wallet": { - "allOf": [ - { - "$ref": "#/components/schemas/Wallet" - } - ], - "nullable": true - }, - "client_secret": { - "type": "string", - "description": "For Client based calls, SDK will use the client_secret\nin order to call /payment_methods\nClient secret will be generated whenever a new\npayment method is created", - "nullable": true - }, "payment_method_data": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentMethodCreateData" - } - ], - "nullable": true + "$ref": "#/components/schemas/PaymentMethodCreateData" }, "billing": { "allOf": [ @@ -12910,19 +12918,13 @@ "PaymentMethodDeleteResponse": { "type": "object", "required": [ - "payment_method_id", - "deleted" + "payment_method_id" ], "properties": { "payment_method_id": { "type": "string", "description": "The unique identifier of the Payment method", "example": "card_rGK4Vi5iSW70MY7J2mIg" - }, - "deleted": { - "type": "boolean", - "description": "Whether payment method was deleted or not", - "example": true } } }, @@ -12941,27 +12943,31 @@ "jp_bacs" ] }, - "PaymentMethodList": { - "type": "object", - "required": [ - "payment_method" - ], - "properties": { - "payment_method": { - "$ref": "#/components/schemas/PaymentMethod" + "PaymentMethodListData": { + "oneOf": [ + { + "type": "object", + "required": [ + "card" + ], + "properties": { + "card": { + "$ref": "#/components/schemas/CardDetailFromLocker" + } + } }, - "payment_method_types": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PaymentMethodType" - }, - "description": "This is a sub-category of payment method.", - "example": [ - "credit" + { + "type": "object", + "required": [ + "bank" ], - "nullable": true + "properties": { + "bank": { + "$ref": "#/components/schemas/Bank" + } + } } - } + ] }, "PaymentMethodListResponse": { "type": "object", @@ -12986,19 +12992,9 @@ "payment_methods": { "type": "array", "items": { - "$ref": "#/components/schemas/PaymentMethodList" + "$ref": "#/components/schemas/ResponsePaymentMethodsEnabled" }, - "description": "Information about the payment method", - "example": [ - { - "payment_experience": null, - "payment_method": "wallet", - "payment_method_issuers": [ - "labore magna ipsum", - "aute" - ] - } - ] + "description": "Information about the payment method" }, "mandate_payment": { "$ref": "#/components/schemas/MandateType" @@ -13045,9 +13041,8 @@ "required": [ "merchant_id", "payment_method_id", - "payment_method", - "recurring_enabled", - "installment_payment_enabled" + "payment_method_type", + "recurring_enabled" ], "properties": { "merchant_id": { @@ -13068,10 +13063,10 @@ "description": "The unique identifier of the Payment method", "example": "card_rGK4Vi5iSW70MY7J2mIg" }, - "payment_method": { + "payment_method_type": { "$ref": "#/components/schemas/PaymentMethod" }, - "payment_method_type": { + "payment_method_subtype": { "allOf": [ { "$ref": "#/components/schemas/PaymentMethodType" @@ -13079,40 +13074,11 @@ ], "nullable": true }, - "card": { - "allOf": [ - { - "$ref": "#/components/schemas/CardDetailFromLocker" - } - ], - "nullable": true - }, "recurring_enabled": { "type": "boolean", "description": "Indicates whether the payment method is eligible for recurring payments", "example": true }, - "installment_payment_enabled": { - "type": "boolean", - "description": "Indicates whether the payment method is eligible for installment payments", - "example": true - }, - "payment_experience": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PaymentExperience" - }, - "description": "Type of payment experience enabled with the connector", - "example": [ - "redirect_to_url" - ], - "nullable": true - }, - "metadata": { - "type": "object", - "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.", - "nullable": true - }, "created": { "type": "string", "format": "date-time", @@ -13120,14 +13086,6 @@ "example": "2023-01-18T11:04:09.922Z", "nullable": true }, - "bank_transfer": { - "allOf": [ - { - "$ref": "#/components/schemas/Bank" - } - ], - "nullable": true - }, "last_used_at": { "type": "string", "format": "date-time", @@ -13138,9 +13096,32 @@ "type": "string", "description": "For Client based calls", "nullable": true + }, + "payment_method_data": { + "allOf": [ + { + "$ref": "#/components/schemas/PaymentMethodResponseData" + } + ], + "nullable": true } } }, + "PaymentMethodResponseData": { + "oneOf": [ + { + "type": "object", + "required": [ + "card" + ], + "properties": { + "card": { + "$ref": "#/components/schemas/CardDetailFromLocker" + } + } + } + ] + }, "PaymentMethodStatus": { "type": "string", "description": "Payment Method Status", @@ -13254,14 +13235,12 @@ }, "PaymentMethodUpdate": { "type": "object", + "required": [ + "payment_method_data" + ], "properties": { - "card": { - "allOf": [ - { - "$ref": "#/components/schemas/CardDetailUpdate" - } - ], - "nullable": true + "payment_method_data": { + "$ref": "#/components/schemas/PaymentMethodUpdateData" }, "client_secret": { "type": "string", @@ -13274,6 +13253,21 @@ }, "additionalProperties": false }, + "PaymentMethodUpdateData": { + "oneOf": [ + { + "type": "object", + "required": [ + "card" + ], + "properties": { + "card": { + "$ref": "#/components/schemas/CardDetailUpdate" + } + } + } + ] + }, "PaymentMethodsEnabled": { "type": "object", "description": "Details of all the payment methods enabled for the connector for the given merchant account", @@ -17830,6 +17824,97 @@ } } }, + "ResponsePaymentMethodTypes": { + "type": "object", + "required": [ + "payment_method_subtype" + ], + "properties": { + "payment_method_subtype": { + "$ref": "#/components/schemas/PaymentMethodType" + }, + "payment_experience": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PaymentExperienceTypes" + }, + "description": "The list of payment experiences enabled, if applicable for a payment method type", + "nullable": true + }, + "card_networks": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CardNetworkTypes" + }, + "description": "The list of card networks enabled, if applicable for a payment method type", + "nullable": true + }, + "bank_names": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BankCodeResponse" + }, + "description": "The list of banks enabled, if applicable for a payment method type", + "nullable": true + }, + "bank_debits": { + "allOf": [ + { + "$ref": "#/components/schemas/BankDebitTypes" + } + ], + "nullable": true + }, + "bank_transfers": { + "allOf": [ + { + "$ref": "#/components/schemas/BankTransferTypes" + } + ], + "nullable": true + }, + "required_fields": { + "type": "object", + "description": "Required fields for the payment_method_type.", + "additionalProperties": { + "$ref": "#/components/schemas/RequiredFieldInfo" + }, + "nullable": true + }, + "surcharge_details": { + "allOf": [ + { + "$ref": "#/components/schemas/SurchargeDetailsResponse" + } + ], + "nullable": true + }, + "pm_auth_connector": { + "type": "string", + "description": "auth service connector label for this payment method type, if exists", + "nullable": true + } + } + }, + "ResponsePaymentMethodsEnabled": { + "type": "object", + "required": [ + "payment_method", + "payment_method_types" + ], + "properties": { + "payment_method": { + "$ref": "#/components/schemas/PaymentMethod" + }, + "payment_method_types": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResponsePaymentMethodTypes" + }, + "description": "The list of payment method types enabled for a connector account" + } + } + }, "RetrieveApiKeyResponse": { "type": "object", "description": "The response body for retrieving an API Key.", diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index 0343e0ad7172..d15a861a8743 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -6144,6 +6144,27 @@ ], "description": "Masked payout method details for bank payout method" }, + "BankCodeResponse": { + "type": "object", + "required": [ + "bank_name", + "eligible_connectors" + ], + "properties": { + "bank_name": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BankNames" + } + }, + "eligible_connectors": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "BankDebitAdditionalData": { "oneOf": [ { @@ -6414,6 +6435,20 @@ } ] }, + "BankDebitTypes": { + "type": "object", + "required": [ + "eligible_connectors" + ], + "properties": { + "eligible_connectors": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "BankHolderType": { "type": "string", "enum": [ @@ -7637,6 +7672,25 @@ } ] }, + "BankTransferTypes": { + "type": "object", + "required": [ + "eligible_connectors" + ], + "properties": { + "eligible_connectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The list of eligible connectors for a given payment experience", + "example": [ + "stripe", + "adyen" + ] + } + } + }, "BankType": { "type": "string", "enum": [ @@ -8362,6 +8416,41 @@ "Maestro" ] }, + "CardNetworkTypes": { + "type": "object", + "required": [ + "eligible_connectors" + ], + "properties": { + "card_network": { + "allOf": [ + { + "$ref": "#/components/schemas/CardNetwork" + } + ], + "nullable": true + }, + "surcharge_details": { + "allOf": [ + { + "$ref": "#/components/schemas/SurchargeDetailsResponse" + } + ], + "nullable": true + }, + "eligible_connectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The list of eligible connectors for a given card network", + "example": [ + "stripe", + "adyen" + ] + } + } + }, "CardPayout": { "type": "object", "required": [ @@ -15067,6 +15156,33 @@ "collect_otp" ] }, + "PaymentExperienceTypes": { + "type": "object", + "required": [ + "eligible_connectors" + ], + "properties": { + "payment_experience_type": { + "allOf": [ + { + "$ref": "#/components/schemas/PaymentExperience" + } + ], + "nullable": true + }, + "eligible_connectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The list of eligible connectors for a given payment experience", + "example": [ + "stripe", + "adyen" + ] + } + } + }, "PaymentLinkConfig": { "type": "object", "required": [ @@ -16067,28 +16183,6 @@ "jp_bacs" ] }, - "PaymentMethodList": { - "type": "object", - "required": [ - "payment_method" - ], - "properties": { - "payment_method": { - "$ref": "#/components/schemas/PaymentMethod" - }, - "payment_method_types": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PaymentMethodType" - }, - "description": "This is a sub-category of payment method.", - "example": [ - "credit" - ], - "nullable": true - } - } - }, "PaymentMethodListResponse": { "type": "object", "required": [ @@ -16112,19 +16206,9 @@ "payment_methods": { "type": "array", "items": { - "$ref": "#/components/schemas/PaymentMethodList" + "$ref": "#/components/schemas/ResponsePaymentMethodsEnabled" }, - "description": "Information about the payment method", - "example": [ - { - "payment_experience": null, - "payment_method": "wallet", - "payment_method_issuers": [ - "labore magna ipsum", - "aute" - ] - } - ] + "description": "Information about the payment method" }, "mandate_payment": { "$ref": "#/components/schemas/MandateType" @@ -22388,6 +22472,97 @@ } } }, + "ResponsePaymentMethodTypes": { + "type": "object", + "required": [ + "payment_method_type" + ], + "properties": { + "payment_method_type": { + "$ref": "#/components/schemas/PaymentMethodType" + }, + "payment_experience": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PaymentExperienceTypes" + }, + "description": "The list of payment experiences enabled, if applicable for a payment method type", + "nullable": true + }, + "card_networks": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CardNetworkTypes" + }, + "description": "The list of card networks enabled, if applicable for a payment method type", + "nullable": true + }, + "bank_names": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BankCodeResponse" + }, + "description": "The list of banks enabled, if applicable for a payment method type", + "nullable": true + }, + "bank_debits": { + "allOf": [ + { + "$ref": "#/components/schemas/BankDebitTypes" + } + ], + "nullable": true + }, + "bank_transfers": { + "allOf": [ + { + "$ref": "#/components/schemas/BankTransferTypes" + } + ], + "nullable": true + }, + "required_fields": { + "type": "object", + "description": "Required fields for the payment_method_type.", + "additionalProperties": { + "$ref": "#/components/schemas/RequiredFieldInfo" + }, + "nullable": true + }, + "surcharge_details": { + "allOf": [ + { + "$ref": "#/components/schemas/SurchargeDetailsResponse" + } + ], + "nullable": true + }, + "pm_auth_connector": { + "type": "string", + "description": "auth service connector label for this payment method type, if exists", + "nullable": true + } + } + }, + "ResponsePaymentMethodsEnabled": { + "type": "object", + "required": [ + "payment_method", + "payment_method_types" + ], + "properties": { + "payment_method": { + "$ref": "#/components/schemas/PaymentMethod" + }, + "payment_method_types": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResponsePaymentMethodTypes" + }, + "description": "The list of payment method types enabled for a connector account" + } + } + }, "RetrieveApiKeyResponse": { "type": "object", "description": "The response body for retrieving an API Key.", diff --git a/crates/api_models/src/events.rs b/crates/api_models/src/events.rs index 77d8cb117ef4..dad624ef87c4 100644 --- a/crates/api_models/src/events.rs +++ b/crates/api_models/src/events.rs @@ -178,8 +178,8 @@ impl ApiEventMetric for PaymentMethodIntentConfirmInternal { fn get_api_event_type(&self) -> Option { Some(ApiEventsType::PaymentMethod { payment_method_id: self.id.clone(), - payment_method: Some(self.payment_method), - payment_method_type: Some(self.payment_method_type), + payment_method: Some(self.payment_method_type), + payment_method_type: Some(self.payment_method_subtype), }) } } diff --git a/crates/api_models/src/events/payment.rs b/crates/api_models/src/events/payment.rs index a3e36a232dc0..b1f15188dcb1 100644 --- a/crates/api_models/src/events/payment.rs +++ b/crates/api_models/src/events/payment.rs @@ -196,6 +196,10 @@ impl ApiEventMetric for PaymentsResponse { } impl ApiEventMetric for PaymentMethodResponse { + #[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "payment_methods_v2") + ))] fn get_api_event_type(&self) -> Option { Some(ApiEventsType::PaymentMethod { payment_method_id: self.payment_method_id.clone(), @@ -203,6 +207,15 @@ impl ApiEventMetric for PaymentMethodResponse { payment_method_type: self.payment_method_type, }) } + + #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] + fn get_api_event_type(&self) -> Option { + Some(ApiEventsType::PaymentMethod { + payment_method_id: self.payment_method_id.clone(), + payment_method: self.payment_method_type, + payment_method_type: self.payment_method_subtype, + }) + } } impl ApiEventMetric for PaymentMethodUpdate {} diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index 0602f69d1584..5baf138b090b 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -110,11 +110,11 @@ pub struct PaymentMethodCreate { pub struct PaymentMethodCreate { /// The type of payment method use for the payment. #[schema(value_type = PaymentMethod,example = "card")] - pub payment_method: api_enums::PaymentMethod, + pub payment_method_type: api_enums::PaymentMethod, /// This is a sub-category of payment method. #[schema(value_type = PaymentMethodType,example = "credit")] - pub payment_method_type: api_enums::PaymentMethodType, + pub payment_method_subtype: api_enums::PaymentMethodType, /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object. #[schema(value_type = Option,example = json!({ "city": "NY", "unit": "245" }))] @@ -165,20 +165,20 @@ pub struct PaymentMethodIntentConfirm { /// The type of payment method use for the payment. #[schema(value_type = PaymentMethod,example = "card")] - pub payment_method: api_enums::PaymentMethod, + pub payment_method_type: api_enums::PaymentMethod, /// This is a sub-category of payment method. #[schema(value_type = PaymentMethodType,example = "credit")] - pub payment_method_type: api_enums::PaymentMethodType, + pub payment_method_subtype: api_enums::PaymentMethodType, } #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] impl PaymentMethodIntentConfirm { pub fn validate_payment_method_data_against_payment_method( - payment_method: api_enums::PaymentMethod, + payment_method_type: api_enums::PaymentMethod, payment_method_data: PaymentMethodCreateData, ) -> bool { - match payment_method { + match payment_method_type { api_enums::PaymentMethod::Card => { matches!(payment_method_data, PaymentMethodCreateData::Card(_)) } @@ -195,11 +195,11 @@ pub struct PaymentMethodIntentConfirmInternal { pub id: String, /// The type of payment method use for the payment. #[schema(value_type = PaymentMethod,example = "card")] - pub payment_method: api_enums::PaymentMethod, + pub payment_method_type: api_enums::PaymentMethod, /// This is a sub-category of payment method. #[schema(value_type = PaymentMethodType,example = "credit")] - pub payment_method_type: api_enums::PaymentMethodType, + pub payment_method_subtype: api_enums::PaymentMethodType, /// For SDK based calls, client_secret would be required pub client_secret: String, @@ -217,8 +217,8 @@ impl From for PaymentMethodIntentConfirm { fn from(item: PaymentMethodIntentConfirmInternal) -> Self { Self { client_secret: item.client_secret, - payment_method: item.payment_method, payment_method_type: item.payment_method_type, + payment_method_subtype: item.payment_method_subtype, customer_id: item.customer_id, payment_method_data: item.payment_method_data.clone(), } @@ -339,10 +339,10 @@ impl PaymentMethodCreate { #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] impl PaymentMethodCreate { pub fn validate_payment_method_data_against_payment_method( - payment_method: api_enums::PaymentMethod, + payment_method_type: api_enums::PaymentMethod, payment_method_data: PaymentMethodCreateData, ) -> bool { - match payment_method { + match payment_method_type { api_enums::PaymentMethod::Card => { matches!(payment_method_data, PaymentMethodCreateData::Card(_)) } @@ -489,6 +489,7 @@ pub struct CardDetail { pub nick_name: Option>, /// Card Issuing Country + #[schema(value_type = CountryAlpha2)] pub card_issuing_country: Option, /// Card's Network @@ -709,7 +710,7 @@ pub struct PaymentMethodResponse { #[derive(Debug, serde::Deserialize, serde::Serialize, ToSchema, Clone)] pub struct PaymentMethodResponse { /// Unique identifier for a merchant - #[schema(example = "merchant_1671528864")] + #[schema(example = "merchant_1671528864", value_type = String)] pub merchant_id: id_type::MerchantId, /// The unique identifier of the customer. @@ -722,11 +723,11 @@ pub struct PaymentMethodResponse { /// The type of payment method use for the payment. #[schema(value_type = PaymentMethod, example = "card")] - pub payment_method: Option, + pub payment_method_type: Option, /// This is a sub-category of payment method. #[schema(value_type = Option, example = "credit")] - pub payment_method_type: Option, + pub payment_method_subtype: Option, /// Indicates whether the payment method is eligible for recurring payments #[schema(example = true)] @@ -852,6 +853,7 @@ pub struct CardDetailFromLocker { #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] #[derive(Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)] pub struct CardDetailFromLocker { + #[schema(value_type = Option)] pub issuer_country: Option, pub last4_digits: Option, #[serde(skip)] @@ -1099,10 +1101,14 @@ pub struct BankDebitTypes { pub eligible_connectors: Vec, } +#[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "payment_methods_v2") +))] #[derive(Debug, Clone, serde::Serialize, ToSchema, PartialEq)] pub struct ResponsePaymentMethodTypes { /// The payment method type enabled - #[schema(example = "klarna")] + #[schema(example = "klarna", value_type = PaymentMethodType)] pub payment_method_type: api_enums::PaymentMethodType, /// The list of payment experiences enabled, if applicable for a payment method type @@ -1116,6 +1122,39 @@ pub struct ResponsePaymentMethodTypes { /// The Bank debit payment method information, if applicable for a payment method type. pub bank_debits: Option, + + /// The Bank transfer payment method information, if applicable for a payment method type. + pub bank_transfers: Option, + + /// Required fields for the payment_method_type. + pub required_fields: Option>, + + /// surcharge details for this payment method type if exists + pub surcharge_details: Option, + + /// auth service connector label for this payment method type, if exists + pub pm_auth_connector: Option, +} + +#[cfg(all(feature = "v2", feature = "payment_methods_v2"))] +#[derive(Debug, Clone, serde::Serialize, ToSchema, PartialEq)] +pub struct ResponsePaymentMethodTypes { + /// The payment method type enabled + #[schema(example = "klarna", value_type = PaymentMethodType)] + pub payment_method_subtype: api_enums::PaymentMethodType, + + /// The list of payment experiences enabled, if applicable for a payment method type + pub payment_experience: Option>, + + /// The list of card networks enabled, if applicable for a payment method type + pub card_networks: Option>, + + /// The list of banks enabled, if applicable for a payment method type + pub bank_names: Option>, + + /// The Bank debit payment method information, if applicable for a payment method type. + pub bank_debits: Option, + /// The Bank transfer payment method information, if applicable for a payment method type. pub bank_transfers: Option, @@ -1541,18 +1580,6 @@ pub struct PaymentMethodListResponse { pub currency: Option, /// Information about the payment method - #[schema(value_type = Vec,example = json!( - [ - { - "payment_method": "wallet", - "payment_experience": null, - "payment_method_issuers": [ - "labore magna ipsum", - "aute" - ] - } - ] - ))] pub payment_methods: Vec, /// Value indicating if the current payment is a mandate payment #[schema(value_type = MandateType)] @@ -1582,35 +1609,6 @@ pub struct PaymentMethodListResponse { pub is_tax_calculation_enabled: bool, } -#[derive(Eq, PartialEq, Hash, Debug, serde::Deserialize, ToSchema)] -pub struct PaymentMethodList { - /// The type of payment method use for the payment. - #[schema(value_type = PaymentMethod,example = "card")] - pub payment_method: api_enums::PaymentMethod, - - /// This is a sub-category of payment method. - #[schema(value_type = Option>,example = json!(["credit"]))] - pub payment_method_types: Option>, -} - -/// Currently if the payment method is Wallet or Paylater the relevant fields are `payment_method` -/// and `payment_method_issuers`. Otherwise only consider -/// `payment_method`,`payment_method_issuers`,`payment_method_types`,`payment_schemes` fields. -impl serde::Serialize for PaymentMethodList { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - use serde::ser::SerializeStruct; - let mut state = serializer.serialize_struct("PaymentMethodList", 4)?; - state.serialize_field("payment_method", &self.payment_method)?; - - state.serialize_field("payment_method_types", &self.payment_method_types)?; - - state.end() - } -} - #[cfg(all( any(feature = "v2", feature = "v1"), not(feature = "payment_methods_v2") @@ -1686,11 +1684,11 @@ pub struct CustomerPaymentMethod { /// The type of payment method use for the payment. #[schema(value_type = PaymentMethod,example = "card")] - pub payment_method: api_enums::PaymentMethod, + pub payment_method_type: api_enums::PaymentMethod, /// This is a sub-category of payment method. #[schema(value_type = Option,example = "credit_card")] - pub payment_method_type: Option, + pub payment_method_subtype: Option, /// Indicates whether the payment method is eligible for recurring payments #[schema(example = true)] @@ -1734,6 +1732,7 @@ pub struct CustomerPaymentMethod { pub enum PaymentMethodListData { Card(CardDetailFromLocker), #[cfg(feature = "payouts")] + #[schema(value_type = Bank)] Bank(payouts::Bank), } @@ -2145,8 +2144,8 @@ impl From for PaymentMethodMigrationResponse match response { Ok(res) => Self { payment_method_id: Some(res.payment_method_id), - payment_method: res.payment_method, - payment_method_type: res.payment_method_type, + payment_method: res.payment_method_type, + payment_method_type: res.payment_method_subtype, customer_id: Some(res.customer_id), migration_status: MigrationStatus::Success, migration_error: None, diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 2f7f796aef1d..98bc7b754a46 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -63,6 +63,7 @@ pub struct ConnectorCode { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema, PartialEq, Eq)] pub struct BankCodeResponse { + #[schema(value_type = Vec)] pub bank_name: Vec, pub eligible_connectors: Vec, } diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index 9ca88267ae65..d607cd04bff3 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -74,8 +74,6 @@ pub struct PaymentMethod { pub merchant_id: common_utils::id_type::MerchantId, pub created_at: PrimitiveDateTime, pub last_modified: PrimitiveDateTime, - pub payment_method: Option, - pub payment_method_type: Option, pub payment_method_data: Option, pub locker_id: Option, pub last_used_at: PrimitiveDateTime, @@ -87,6 +85,8 @@ pub struct PaymentMethod { pub payment_method_billing_address: Option, pub updated_by: Option, pub locker_fingerprint_id: Option, + pub payment_method_type_v2: Option, + pub payment_method_subtype: Option, pub id: common_utils::id_type::GlobalPaymentMethodId, pub version: common_enums::ApiVersion, pub network_token_requestor_reference_id: Option, @@ -160,8 +160,6 @@ pub struct PaymentMethodNew { pub struct PaymentMethodNew { pub customer_id: common_utils::id_type::CustomerId, pub merchant_id: common_utils::id_type::MerchantId, - pub payment_method: Option, - pub payment_method_type: Option, pub created_at: PrimitiveDateTime, pub last_modified: PrimitiveDateTime, pub payment_method_data: Option, @@ -175,6 +173,8 @@ pub struct PaymentMethodNew { pub payment_method_billing_address: Option, pub updated_by: Option, pub locker_fingerprint_id: Option, + pub payment_method_type_v2: Option, + pub payment_method_subtype: Option, pub id: common_utils::id_type::GlobalPaymentMethodId, pub version: common_enums::ApiVersion, pub network_token_requestor_reference_id: Option, @@ -274,8 +274,8 @@ pub enum PaymentMethodUpdate { payment_method_data: Option, status: Option, locker_id: Option, - payment_method: Option, - payment_method_type: Option, + payment_method_type_v2: Option, + payment_method_subtype: Option, network_token_requestor_reference_id: Option, network_token_locker_id: Option, network_token_payment_method_data: Option, @@ -305,10 +305,10 @@ pub struct PaymentMethodUpdateInternal { network_transaction_id: Option, status: Option, locker_id: Option, - payment_method: Option, + payment_method_type_v2: Option, connector_mandate_details: Option, updated_by: Option, - payment_method_type: Option, + payment_method_subtype: Option, last_modified: PrimitiveDateTime, network_token_requestor_reference_id: Option, network_token_locker_id: Option, @@ -324,10 +324,10 @@ impl PaymentMethodUpdateInternal { network_transaction_id, status, locker_id, - payment_method, + payment_method_type_v2, connector_mandate_details, updated_by, - payment_method_type, + payment_method_subtype, last_modified, network_token_requestor_reference_id, network_token_locker_id, @@ -339,8 +339,6 @@ impl PaymentMethodUpdateInternal { merchant_id: source.merchant_id, created_at: source.created_at, last_modified, - payment_method: payment_method.or(source.payment_method), - payment_method_type: payment_method_type.or(source.payment_method_type), payment_method_data: payment_method_data.or(source.payment_method_data), locker_id: locker_id.or(source.locker_id), last_used_at: last_used_at.unwrap_or(source.last_used_at), @@ -353,6 +351,8 @@ impl PaymentMethodUpdateInternal { payment_method_billing_address: source.payment_method_billing_address, updated_by: updated_by.or(source.updated_by), locker_fingerprint_id: source.locker_fingerprint_id, + payment_method_type_v2: payment_method_type_v2.or(source.payment_method_type_v2), + payment_method_subtype: payment_method_subtype.or(source.payment_method_subtype), id: source.id, version: source.version, network_token_requestor_reference_id: network_token_requestor_reference_id @@ -636,10 +636,10 @@ impl From for PaymentMethodUpdateInternal { network_transaction_id: None, status: None, locker_id: None, - payment_method: None, + payment_method_type_v2: None, connector_mandate_details: None, updated_by: None, - payment_method_type: None, + payment_method_subtype: None, last_modified: common_utils::date_time::now(), network_token_locker_id: None, network_token_requestor_reference_id: None, @@ -651,10 +651,10 @@ impl From for PaymentMethodUpdateInternal { network_transaction_id: None, status: None, locker_id: None, - payment_method: None, + payment_method_type_v2: None, connector_mandate_details: None, updated_by: None, - payment_method_type: None, + payment_method_subtype: None, last_modified: common_utils::date_time::now(), network_token_locker_id: None, network_token_requestor_reference_id: None, @@ -669,10 +669,10 @@ impl From for PaymentMethodUpdateInternal { network_transaction_id: None, status: None, locker_id: None, - payment_method: None, + payment_method_type_v2: None, connector_mandate_details: None, updated_by: None, - payment_method_type: None, + payment_method_subtype: None, last_modified: common_utils::date_time::now(), network_token_locker_id: None, network_token_requestor_reference_id: None, @@ -687,10 +687,10 @@ impl From for PaymentMethodUpdateInternal { network_transaction_id, status, locker_id: None, - payment_method: None, + payment_method_type_v2: None, connector_mandate_details: None, updated_by: None, - payment_method_type: None, + payment_method_subtype: None, last_modified: common_utils::date_time::now(), network_token_locker_id: None, network_token_requestor_reference_id: None, @@ -702,10 +702,10 @@ impl From for PaymentMethodUpdateInternal { network_transaction_id: None, status, locker_id: None, - payment_method: None, + payment_method_type_v2: None, connector_mandate_details: None, updated_by: None, - payment_method_type: None, + payment_method_subtype: None, last_modified: common_utils::date_time::now(), network_token_locker_id: None, network_token_requestor_reference_id: None, @@ -715,8 +715,8 @@ impl From for PaymentMethodUpdateInternal { payment_method_data, status, locker_id, - payment_method, - payment_method_type, + payment_method_type_v2, + payment_method_subtype, network_token_requestor_reference_id, network_token_locker_id, network_token_payment_method_data, @@ -726,10 +726,10 @@ impl From for PaymentMethodUpdateInternal { network_transaction_id: None, status, locker_id, - payment_method, + payment_method_type_v2, connector_mandate_details: None, updated_by: None, - payment_method_type, + payment_method_subtype, last_modified: common_utils::date_time::now(), network_token_requestor_reference_id, network_token_locker_id, @@ -742,11 +742,11 @@ impl From for PaymentMethodUpdateInternal { last_used_at: None, status: None, locker_id: None, - payment_method: None, + payment_method_type_v2: None, connector_mandate_details, network_transaction_id: None, updated_by: None, - payment_method_type: None, + payment_method_subtype: None, last_modified: common_utils::date_time::now(), network_token_locker_id: None, network_token_requestor_reference_id: None, @@ -816,8 +816,6 @@ impl From<&PaymentMethodNew> for PaymentMethod { locker_id: payment_method_new.locker_id.clone(), created_at: payment_method_new.created_at, last_modified: payment_method_new.last_modified, - payment_method: payment_method_new.payment_method, - payment_method_type: payment_method_new.payment_method_type, payment_method_data: payment_method_new.payment_method_data.clone(), last_used_at: payment_method_new.last_used_at, connector_mandate_details: payment_method_new.connector_mandate_details.clone(), @@ -829,8 +827,10 @@ impl From<&PaymentMethodNew> for PaymentMethod { payment_method_billing_address: payment_method_new .payment_method_billing_address .clone(), - id: payment_method_new.id.clone(), locker_fingerprint_id: payment_method_new.locker_fingerprint_id.clone(), + payment_method_type_v2: payment_method_new.payment_method_type_v2, + payment_method_subtype: payment_method_new.payment_method_subtype, + id: payment_method_new.id.clone(), version: payment_method_new.version, network_token_requestor_reference_id: payment_method_new .network_token_requestor_reference_id @@ -843,6 +843,10 @@ impl From<&PaymentMethodNew> for PaymentMethod { } } +#[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "payment_methods_v2") +))] #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct PaymentsMandateReferenceRecord { pub connector_mandate_id: String, @@ -854,6 +858,18 @@ pub struct PaymentsMandateReferenceRecord { pub connector_mandate_request_reference_id: Option, } +#[cfg(all(feature = "v2", feature = "payment_methods_v2"))] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct PaymentsMandateReferenceRecord { + pub connector_mandate_id: String, + pub payment_method_subtype: Option, + pub original_payment_authorized_amount: Option, + pub original_payment_authorized_currency: Option, + pub mandate_metadata: Option, + pub connector_mandate_status: Option, + pub connector_mandate_request_reference_id: Option, +} + #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, diesel::AsExpression)] #[diesel(sql_type = diesel::sql_types::Jsonb)] pub struct PaymentsMandateReference( diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs index e3097f80db91..aa7f3f7232c6 100644 --- a/crates/diesel_models/src/schema_v2.rs +++ b/crates/diesel_models/src/schema_v2.rs @@ -938,9 +938,6 @@ diesel::table! { merchant_id -> Varchar, created_at -> Timestamp, last_modified -> Timestamp, - payment_method -> Nullable, - #[max_length = 64] - payment_method_type -> Nullable, payment_method_data -> Nullable, #[max_length = 64] locker_id -> Nullable, @@ -959,6 +956,10 @@ diesel::table! { #[max_length = 64] locker_fingerprint_id -> Nullable, #[max_length = 64] + payment_method_type_v2 -> Nullable, + #[max_length = 64] + payment_method_subtype -> Nullable, + #[max_length = 64] id -> Varchar, version -> ApiVersion, #[max_length = 128] diff --git a/crates/hyperswitch_domain_models/src/payment_methods.rs b/crates/hyperswitch_domain_models/src/payment_methods.rs index 4ff246d3760b..083d6e475019 100644 --- a/crates/hyperswitch_domain_models/src/payment_methods.rs +++ b/crates/hyperswitch_domain_models/src/payment_methods.rs @@ -1,10 +1,9 @@ +#[cfg(all(feature = "v2", feature = "payment_methods_v2"))] +use common_utils::crypto::Encryptable; use common_utils::{ crypto::OptionalEncryptableValue, - // date_time, - // encryption::Encryption, errors::{CustomResult, ValidationError}, - pii, - type_name, + pii, type_name, types::keymanager, }; use diesel_models::enums as storage_enums; @@ -12,6 +11,8 @@ use error_stack::ResultExt; use masking::{PeekInterface, Secret}; use time::PrimitiveDateTime; +#[cfg(all(feature = "v2", feature = "payment_methods_v2"))] +use crate::type_encryption::EncryptedJsonType; use crate::type_encryption::{crypto_operation, AsyncLift, CryptoOperation}; #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] @@ -77,9 +78,11 @@ pub struct PaymentMethod { pub merchant_id: common_utils::id_type::MerchantId, pub created_at: PrimitiveDateTime, pub last_modified: PrimitiveDateTime, - pub payment_method: Option, - pub payment_method_type: Option, - pub payment_method_data: OptionalEncryptableValue, + pub payment_method_type: Option, + pub payment_method_subtype: Option, + pub payment_method_data: Option< + Encryptable>>, + >, pub locker_id: Option, pub last_used_at: PrimitiveDateTime, pub connector_mandate_details: Option, @@ -110,6 +113,32 @@ impl PaymentMethod { pub fn get_id(&self) -> &common_utils::id_type::GlobalPaymentMethodId { &self.id } + + #[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "payment_methods_v2") + ))] + pub fn get_payment_method_type(&self) -> Option { + self.payment_method + } + + #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] + pub fn get_payment_method_type(&self) -> Option { + self.payment_method_type + } + + #[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "payment_methods_v2") + ))] + pub fn get_payment_method_subtype(&self) -> Option { + self.payment_method_type + } + + #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] + pub fn get_payment_method_subtype(&self) -> Option { + self.payment_method_subtype + } } #[cfg(all( @@ -311,8 +340,8 @@ impl super::behaviour::Conversion for PaymentMethod { id: self.id, created_at: self.created_at, last_modified: self.last_modified, - payment_method: self.payment_method, - payment_method_type: self.payment_method_type, + payment_method_type_v2: self.payment_method_type, + payment_method_subtype: self.payment_method_subtype, payment_method_data: self.payment_method_data.map(|val| val.into()), locker_id: self.locker_id.map(|id| id.get_string_repr().clone()), last_used_at: self.last_used_at, @@ -351,8 +380,8 @@ impl super::behaviour::Conversion for PaymentMethod { id: item.id, created_at: item.created_at, last_modified: item.last_modified, - payment_method: item.payment_method, - payment_method_type: item.payment_method_type, + payment_method_type: item.payment_method_type_v2, + payment_method_subtype: item.payment_method_subtype, payment_method_data: item .payment_method_data .async_lift(|inner| async { @@ -422,8 +451,8 @@ impl super::behaviour::Conversion for PaymentMethod { id: self.id, created_at: self.created_at, last_modified: self.last_modified, - payment_method: self.payment_method, - payment_method_type: self.payment_method_type, + payment_method_type_v2: self.payment_method_type, + payment_method_subtype: self.payment_method_subtype, payment_method_data: self.payment_method_data.map(|val| val.into()), locker_id: self.locker_id.map(|id| id.get_string_repr().clone()), last_used_at: self.last_used_at, diff --git a/crates/hyperswitch_domain_models/src/type_encryption.rs b/crates/hyperswitch_domain_models/src/type_encryption.rs index 983528dee981..641e295155fc 100644 --- a/crates/hyperswitch_domain_models/src/type_encryption.rs +++ b/crates/hyperswitch_domain_models/src/type_encryption.rs @@ -18,6 +18,7 @@ mod encrypt { crypto, encryption::Encryption, errors::{self, CustomResult}, + ext_traits::ByteSliceExt, keymanager::call_encryption_service, transformers::{ForeignFrom, ForeignTryFrom}, types::keymanager::{ @@ -32,7 +33,7 @@ mod encrypt { use router_env::{instrument, logger, tracing}; use rustc_hash::FxHashMap; - use super::metrics; + use super::{metrics, EncryptedJsonType}; #[async_trait] pub trait TypeEncryption< @@ -115,8 +116,8 @@ mod encrypt { S: masking::Strategy + Send + Sync, > TypeEncryption for crypto::Encryptable> { + // Do not remove the `skip_all` as the key would be logged otherwise #[instrument(skip_all)] - #[allow(unused_variables)] async fn encrypt_via_api( state: &KeyManagerState, masked_data: Secret, @@ -150,8 +151,8 @@ mod encrypt { } } + // Do not remove the `skip_all` as the key would be logged otherwise #[instrument(skip_all)] - #[allow(unused_variables)] async fn decrypt_via_api( state: &KeyManagerState, encrypted_data: Encryption, @@ -194,6 +195,8 @@ mod encrypt { } } + // Do not remove the `skip_all` as the key would be logged otherwise + #[instrument(skip_all)] async fn encrypt( masked_data: Secret, key: &[u8], @@ -204,6 +207,8 @@ mod encrypt { Ok(Self::new(masked_data, encrypted_data.into())) } + // Do not remove the `skip_all` as the key would be logged otherwise + #[instrument(skip_all)] async fn decrypt( encrypted_data: Encryption, key: &[u8], @@ -220,7 +225,8 @@ mod encrypt { Ok(Self::new(value.into(), encrypted)) } - #[allow(unused_variables)] + // Do not remove the `skip_all` as the key would be logged otherwise + #[instrument(skip_all)] async fn batch_encrypt_via_api( state: &KeyManagerState, masked_data: FxHashMap>, @@ -254,7 +260,8 @@ mod encrypt { } } - #[allow(unused_variables)] + // Do not remove the `skip_all` as the key would be logged otherwise + #[instrument(skip_all)] async fn batch_decrypt_via_api( state: &KeyManagerState, encrypted_data: FxHashMap, @@ -296,6 +303,8 @@ mod encrypt { } } + // Do not remove the `skip_all` as the key would be logged otherwise + #[instrument(skip_all)] async fn batch_encrypt( masked_data: FxHashMap>, key: &[u8], @@ -316,6 +325,8 @@ mod encrypt { .collect() } + // Do not remove the `skip_all` as the key would be logged otherwise + #[instrument(skip_all)] async fn batch_decrypt( encrypted_data: FxHashMap, key: &[u8], @@ -342,8 +353,8 @@ mod encrypt { > TypeEncryption for crypto::Encryptable> { + // Do not remove the `skip_all` as the key would be logged otherwise #[instrument(skip_all)] - #[allow(unused_variables)] async fn encrypt_via_api( state: &KeyManagerState, masked_data: Secret, @@ -377,8 +388,8 @@ mod encrypt { } } + // Do not remove the `skip_all` as the key would be logged otherwise #[instrument(skip_all)] - #[allow(unused_variables)] async fn decrypt_via_api( state: &KeyManagerState, encrypted_data: Encryption, @@ -420,6 +431,7 @@ mod encrypt { } } + // Do not remove the `skip_all` as the key would be logged otherwise #[instrument(skip_all)] async fn encrypt( masked_data: Secret, @@ -433,6 +445,7 @@ mod encrypt { Ok(Self::new(masked_data, encrypted_data.into())) } + // Do not remove the `skip_all` as the key would be logged otherwise #[instrument(skip_all)] async fn decrypt( encrypted_data: Encryption, @@ -448,7 +461,8 @@ mod encrypt { Ok(Self::new(value.into(), encrypted)) } - #[allow(unused_variables)] + // Do not remove the `skip_all` as the key would be logged otherwise + #[instrument(skip_all)] async fn batch_encrypt_via_api( state: &KeyManagerState, masked_data: FxHashMap>, @@ -482,7 +496,8 @@ mod encrypt { } } - #[allow(unused_variables)] + // Do not remove the `skip_all` as the key would be logged otherwise + #[instrument(skip_all)] async fn batch_decrypt_via_api( state: &KeyManagerState, encrypted_data: FxHashMap, @@ -524,6 +539,8 @@ mod encrypt { } } + // Do not remove the `skip_all` as the key would be logged otherwise + #[instrument(skip_all)] async fn batch_encrypt( masked_data: FxHashMap>, key: &[u8], @@ -543,6 +560,8 @@ mod encrypt { .collect() } + // Do not remove the `skip_all` as the key would be logged otherwise + #[instrument(skip_all)] async fn batch_decrypt( encrypted_data: FxHashMap, key: &[u8], @@ -562,14 +581,251 @@ mod encrypt { } } + impl EncryptedJsonType + where + T: std::fmt::Debug + Clone + serde::Serialize + serde::de::DeserializeOwned, + { + fn serialize_json_bytes(&self) -> CustomResult>, errors::CryptoError> { + common_utils::ext_traits::Encode::encode_to_vec(self.inner()) + .change_context(errors::CryptoError::EncodingFailed) + .attach_printable("Failed to JSON serialize data before encryption") + .map(Secret::new) + } + + fn deserialize_json_bytes( + bytes: Secret>, + ) -> CustomResult, errors::ParsingError> + where + S: masking::Strategy, + { + bytes + .peek() + .as_slice() + .parse_struct::(std::any::type_name::()) + .map(|result| Secret::new(Self::from(result))) + .attach_printable("Failed to JSON deserialize data after decryption") + } + } + + #[async_trait] + impl< + T: std::fmt::Debug + Clone + serde::Serialize + serde::de::DeserializeOwned + Send, + V: crypto::DecodeMessage + crypto::EncodeMessage + Send + 'static, + S: masking::Strategy> + Send + Sync, + > TypeEncryption, V, S> + for crypto::Encryptable, S>> + { + // Do not remove the `skip_all` as the key would be logged otherwise + #[instrument(skip_all)] + async fn encrypt_via_api( + state: &KeyManagerState, + masked_data: Secret, S>, + identifier: Identifier, + key: &[u8], + crypt_algo: V, + ) -> CustomResult { + let data_bytes = EncryptedJsonType::serialize_json_bytes(masked_data.peek())?; + let result: crypto::Encryptable>> = + TypeEncryption::encrypt_via_api(state, data_bytes, identifier, key, crypt_algo) + .await?; + Ok(Self::new(masked_data, result.into_encrypted())) + } + + // Do not remove the `skip_all` as the key would be logged otherwise + #[instrument(skip_all)] + async fn decrypt_via_api( + state: &KeyManagerState, + encrypted_data: Encryption, + identifier: Identifier, + key: &[u8], + crypt_algo: V, + ) -> CustomResult { + let result: crypto::Encryptable>> = + TypeEncryption::decrypt_via_api(state, encrypted_data, identifier, key, crypt_algo) + .await?; + result + .deserialize_inner_value(EncryptedJsonType::deserialize_json_bytes) + .change_context(errors::CryptoError::DecodingFailed) + } + + // Do not remove the `skip_all` as the key would be logged otherwise + #[instrument(skip_all)] + async fn encrypt( + masked_data: Secret, S>, + key: &[u8], + crypt_algo: V, + ) -> CustomResult { + let data_bytes = EncryptedJsonType::serialize_json_bytes(masked_data.peek())?; + let result: crypto::Encryptable>> = + TypeEncryption::encrypt(data_bytes, key, crypt_algo).await?; + Ok(Self::new(masked_data, result.into_encrypted())) + } + + // Do not remove the `skip_all` as the key would be logged otherwise + #[instrument(skip_all)] + async fn decrypt( + encrypted_data: Encryption, + key: &[u8], + crypt_algo: V, + ) -> CustomResult { + let result: crypto::Encryptable>> = + TypeEncryption::decrypt(encrypted_data, key, crypt_algo).await?; + result + .deserialize_inner_value(EncryptedJsonType::deserialize_json_bytes) + .change_context(errors::CryptoError::DecodingFailed) + } + + // Do not remove the `skip_all` as the key would be logged otherwise + #[instrument(skip_all)] + async fn batch_encrypt_via_api( + state: &KeyManagerState, + masked_data: FxHashMap, S>>, + identifier: Identifier, + key: &[u8], + crypt_algo: V, + ) -> CustomResult, errors::CryptoError> { + let hashmap_capacity = masked_data.len(); + let data_bytes = masked_data.iter().try_fold( + FxHashMap::with_capacity_and_hasher(hashmap_capacity, Default::default()), + |mut map, (key, value)| { + let value_bytes = EncryptedJsonType::serialize_json_bytes(value.peek())?; + map.insert(key.to_owned(), value_bytes); + Ok::<_, error_stack::Report>(map) + }, + )?; + + let result: FxHashMap>>> = + TypeEncryption::batch_encrypt_via_api( + state, data_bytes, identifier, key, crypt_algo, + ) + .await?; + let result_hashmap = result.into_iter().try_fold( + FxHashMap::with_capacity_and_hasher(hashmap_capacity, Default::default()), + |mut map, (key, value)| { + let original_value = masked_data + .get(&key) + .ok_or(errors::CryptoError::EncodingFailed) + .attach_printable_lazy(|| { + format!("Failed to find {key} in input hashmap") + })?; + map.insert( + key, + Self::new(original_value.clone(), value.into_encrypted()), + ); + Ok::<_, error_stack::Report>(map) + }, + )?; + + Ok(result_hashmap) + } + + // Do not remove the `skip_all` as the key would be logged otherwise + #[instrument(skip_all)] + async fn batch_decrypt_via_api( + state: &KeyManagerState, + encrypted_data: FxHashMap, + identifier: Identifier, + key: &[u8], + crypt_algo: V, + ) -> CustomResult, errors::CryptoError> { + let result: FxHashMap>>> = + TypeEncryption::batch_decrypt_via_api( + state, + encrypted_data, + identifier, + key, + crypt_algo, + ) + .await?; + + let hashmap_capacity = result.len(); + let result_hashmap = result.into_iter().try_fold( + FxHashMap::with_capacity_and_hasher(hashmap_capacity, Default::default()), + |mut map, (key, value)| { + let deserialized_value = value + .deserialize_inner_value(EncryptedJsonType::deserialize_json_bytes) + .change_context(errors::CryptoError::DecodingFailed)?; + map.insert(key, deserialized_value); + Ok::<_, error_stack::Report>(map) + }, + )?; + + Ok(result_hashmap) + } + + // Do not remove the `skip_all` as the key would be logged otherwise + #[instrument(skip_all)] + async fn batch_encrypt( + masked_data: FxHashMap, S>>, + key: &[u8], + crypt_algo: V, + ) -> CustomResult, errors::CryptoError> { + let hashmap_capacity = masked_data.len(); + let data_bytes = masked_data.iter().try_fold( + FxHashMap::with_capacity_and_hasher(hashmap_capacity, Default::default()), + |mut map, (key, value)| { + let value_bytes = EncryptedJsonType::serialize_json_bytes(value.peek())?; + map.insert(key.to_owned(), value_bytes); + Ok::<_, error_stack::Report>(map) + }, + )?; + + let result: FxHashMap>>> = + TypeEncryption::batch_encrypt(data_bytes, key, crypt_algo).await?; + let result_hashmap = result.into_iter().try_fold( + FxHashMap::with_capacity_and_hasher(hashmap_capacity, Default::default()), + |mut map, (key, value)| { + let original_value = masked_data + .get(&key) + .ok_or(errors::CryptoError::EncodingFailed) + .attach_printable_lazy(|| { + format!("Failed to find {key} in input hashmap") + })?; + map.insert( + key, + Self::new(original_value.clone(), value.into_encrypted()), + ); + Ok::<_, error_stack::Report>(map) + }, + )?; + + Ok(result_hashmap) + } + + // Do not remove the `skip_all` as the key would be logged otherwise + #[instrument(skip_all)] + async fn batch_decrypt( + encrypted_data: FxHashMap, + key: &[u8], + crypt_algo: V, + ) -> CustomResult, errors::CryptoError> { + let result: FxHashMap>>> = + TypeEncryption::batch_decrypt(encrypted_data, key, crypt_algo).await?; + + let hashmap_capacity = result.len(); + let result_hashmap = result.into_iter().try_fold( + FxHashMap::with_capacity_and_hasher(hashmap_capacity, Default::default()), + |mut map, (key, value)| { + let deserialized_value = value + .deserialize_inner_value(EncryptedJsonType::deserialize_json_bytes) + .change_context(errors::CryptoError::DecodingFailed)?; + map.insert(key, deserialized_value); + Ok::<_, error_stack::Report>(map) + }, + )?; + + Ok(result_hashmap) + } + } + #[async_trait] impl< V: crypto::DecodeMessage + crypto::EncodeMessage + Send + 'static, S: masking::Strategy> + Send + Sync, > TypeEncryption, V, S> for crypto::Encryptable, S>> { + // Do not remove the `skip_all` as the key would be logged otherwise #[instrument(skip_all)] - #[allow(unused_variables)] async fn encrypt_via_api( state: &KeyManagerState, masked_data: Secret, S>, @@ -603,8 +859,8 @@ mod encrypt { } } + // Do not remove the `skip_all` as the key would be logged otherwise #[instrument(skip_all)] - #[allow(unused_variables)] async fn decrypt_via_api( state: &KeyManagerState, encrypted_data: Encryption, @@ -646,6 +902,7 @@ mod encrypt { } } + // Do not remove the `skip_all` as the key would be logged otherwise #[instrument(skip_all)] async fn encrypt( masked_data: Secret, S>, @@ -657,6 +914,7 @@ mod encrypt { Ok(Self::new(masked_data, encrypted_data.into())) } + // Do not remove the `skip_all` as the key would be logged otherwise #[instrument(skip_all)] async fn decrypt( encrypted_data: Encryption, @@ -669,7 +927,8 @@ mod encrypt { Ok(Self::new(data.into(), encrypted)) } - #[allow(unused_variables)] + // Do not remove the `skip_all` as the key would be logged otherwise + #[instrument(skip_all)] async fn batch_encrypt_via_api( state: &KeyManagerState, masked_data: FxHashMap, S>>, @@ -703,7 +962,8 @@ mod encrypt { } } - #[allow(unused_variables)] + // Do not remove the `skip_all` as the key would be logged otherwise + #[instrument(skip_all)] async fn batch_decrypt_via_api( state: &KeyManagerState, encrypted_data: FxHashMap, @@ -745,6 +1005,8 @@ mod encrypt { } } + // Do not remove the `skip_all` as the key would be logged otherwise + #[instrument(skip_all)] async fn batch_encrypt( masked_data: FxHashMap, S>>, key: &[u8], @@ -762,6 +1024,8 @@ mod encrypt { .collect() } + // Do not remove the `skip_all` as the key would be logged otherwise + #[instrument(skip_all)] async fn batch_decrypt( encrypted_data: FxHashMap, key: &[u8], @@ -785,6 +1049,37 @@ mod encrypt { } } } + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct EncryptedJsonType(T); + +impl EncryptedJsonType { + pub fn inner(&self) -> &T { + &self.0 + } + + pub fn into_inner(self) -> T { + self.0 + } +} + +impl From for EncryptedJsonType { + fn from(value: T) -> Self { + Self(value) + } +} + +impl std::ops::Deref for EncryptedJsonType { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.inner() + } +} + +/// Type alias for `Option>>>` +pub type OptionalEncryptableJsonType = Option>>>; + pub trait Lift { type SelfWrapper; type OtherWrapper; @@ -983,6 +1278,7 @@ pub enum CryptoOutput> { BatchOperation(FxHashMap>>), } +// Do not remove the `skip_all` as the key would be logged otherwise #[instrument(skip_all, fields(table = table_name))] pub async fn crypto_operation>( state: &KeyManagerState, diff --git a/crates/openapi/Cargo.toml b/crates/openapi/Cargo.toml index 26707479b0d6..930f9739e6e2 100644 --- a/crates/openapi/Cargo.toml +++ b/crates/openapi/Cargo.toml @@ -16,7 +16,7 @@ common_utils = { version = "0.1.0", path = "../common_utils", features = ["logs" router_env = { version = "0.1.0", path = "../router_env" } [features] -v2 = ["api_models/v2", "api_models/customer_v2", "common_utils/v2"] +v2 = ["api_models/v2", "api_models/customer_v2", "common_utils/v2", "api_models/payment_methods_v2", "common_utils/payment_methods_v2"] v1 = ["api_models/v1", "common_utils/v1"] [lints] diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs index dc9274b71ee2..6356b5f15bee 100644 --- a/crates/openapi/src/openapi.rs +++ b/crates/openapi/src/openapi.rs @@ -231,9 +231,14 @@ Never share your secret api keys. Keep them guarded and secure. api_models::customers::CustomerDeleteResponse, api_models::payment_methods::PaymentMethodCreate, api_models::payment_methods::PaymentMethodResponse, - api_models::payment_methods::PaymentMethodList, api_models::payment_methods::CustomerPaymentMethod, api_models::payment_methods::PaymentMethodListResponse, + api_models::payment_methods::ResponsePaymentMethodsEnabled, + api_models::payment_methods::ResponsePaymentMethodTypes, + api_models::payment_methods::PaymentExperienceTypes, + api_models::payment_methods::CardNetworkTypes, + api_models::payment_methods::BankDebitTypes, + api_models::payment_methods::BankTransferTypes, api_models::payment_methods::CustomerPaymentMethodsListResponse, api_models::payment_methods::PaymentMethodDeleteResponse, api_models::payment_methods::PaymentMethodUpdate, @@ -507,6 +512,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::MobilePaymentData, api_models::payments::MobilePaymentResponse, api_models::payments::Address, + api_models::payments::BankCodeResponse, api_models::payouts::CardPayout, api_models::payouts::Wallet, api_models::payouts::Paypal, diff --git a/crates/openapi/src/openapi_v2.rs b/crates/openapi/src/openapi_v2.rs index 7417466bfd25..17c004169336 100644 --- a/crates/openapi/src/openapi_v2.rs +++ b/crates/openapi/src/openapi_v2.rs @@ -171,18 +171,27 @@ Never share your secret api keys. Keep them guarded and secure. api_models::customers::CustomerDeleteResponse, api_models::payment_methods::PaymentMethodCreate, api_models::payment_methods::PaymentMethodResponse, - api_models::payment_methods::PaymentMethodList, + api_models::payment_methods::PaymentMethodResponseData, api_models::payment_methods::CustomerPaymentMethod, api_models::payment_methods::PaymentMethodListResponse, + api_models::payment_methods::ResponsePaymentMethodsEnabled, + api_models::payment_methods::ResponsePaymentMethodTypes, + api_models::payment_methods::PaymentExperienceTypes, + api_models::payment_methods::CardNetworkTypes, + api_models::payment_methods::BankDebitTypes, + api_models::payment_methods::BankTransferTypes, api_models::payment_methods::CustomerPaymentMethodsListResponse, api_models::payment_methods::PaymentMethodDeleteResponse, api_models::payment_methods::PaymentMethodUpdate, + api_models::payment_methods::PaymentMethodUpdateData, api_models::payment_methods::CustomerDefaultPaymentMethodResponse, api_models::payment_methods::CardDetailFromLocker, api_models::payment_methods::PaymentMethodCreateData, api_models::payment_methods::CardDetail, api_models::payment_methods::CardDetailUpdate, api_models::payment_methods::RequestPaymentMethodTypes, + api_models::payment_methods::CardType, + api_models::payment_methods::PaymentMethodListData, api_models::poll::PollResponse, api_models::poll::PollStatus, api_models::customers::CustomerResponse, @@ -426,6 +435,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::PaymentsConfirmIntentRequest, api_models::payments::PaymentsConfirmIntentResponse, api_models::payments::AmountDetailsResponse, + api_models::payments::BankCodeResponse, api_models::payment_methods::RequiredFieldInfo, api_models::payment_methods::DefaultPaymentMethod, api_models::payment_methods::MaskedBankDetails, diff --git a/crates/router/src/core/customers.rs b/crates/router/src/core/customers.rs index 6d47ac174f3d..266873b1a111 100644 --- a/crates/router/src/core/customers.rs +++ b/crates/router/src/core/customers.rs @@ -621,7 +621,7 @@ impl CustomerDeleteBridge for customers::GlobalId { // check this in review Ok(customer_payment_methods) => { for pm in customer_payment_methods.into_iter() { - if pm.payment_method == Some(enums::PaymentMethod::Card) { + if pm.payment_method_type_v2 == Some(enums::PaymentMethod::Card) { cards::delete_card_by_locker_id(state, &self.id, merchant_account.get_id()) .await .switch()?; @@ -796,7 +796,7 @@ impl CustomerDeleteBridge for customers::CustomerId { // check this in review Ok(customer_payment_methods) => { for pm in customer_payment_methods.into_iter() { - if pm.payment_method == Some(enums::PaymentMethod::Card) { + if pm.get_payment_method_type() == Some(enums::PaymentMethod::Card) { cards::delete_card_from_locker( state, &self.customer_id, diff --git a/crates/router/src/core/locker_migration.rs b/crates/router/src/core/locker_migration.rs index 8fd4b10ed3fc..dbadadb3a6fc 100644 --- a/crates/router/src/core/locker_migration.rs +++ b/crates/router/src/core/locker_migration.rs @@ -138,10 +138,12 @@ pub async fn call_to_locker( ) -> CustomResult { let mut cards_moved = 0; - for pm in payment_methods - .into_iter() - .filter(|pm| matches!(pm.payment_method, Some(storage_enums::PaymentMethod::Card))) - { + for pm in payment_methods.into_iter().filter(|pm| { + matches!( + pm.get_payment_method_type(), + Some(storage_enums::PaymentMethod::Card) + ) + }) { let card = cards::get_card_from_locker( state, customer_id, @@ -171,8 +173,8 @@ pub async fn call_to_locker( }; let pm_create = api::PaymentMethodCreate { - payment_method: pm.payment_method, - payment_method_type: pm.payment_method_type, + payment_method: pm.get_payment_method_type(), + payment_method_type: pm.get_payment_method_subtype(), payment_method_issuer: pm.payment_method_issuer, payment_method_issuer_code: pm.payment_method_issuer_code, card: Some(card_details.clone()), diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs index 932a4a26ee09..8b8b3f33ed80 100644 --- a/crates/router/src/core/payment_methods.rs +++ b/crates/router/src/core/payment_methods.rs @@ -673,14 +673,14 @@ pub async fn retrieve_payment_method_with_token( #[instrument(skip_all)] pub(crate) async fn get_payment_method_create_request( payment_method_data: Option<&domain::PaymentMethodData>, - payment_method: Option, - payment_method_type: Option, + payment_method_type: Option, + payment_method_subtype: Option, customer_id: &Option, billing_name: Option>, ) -> RouterResult { match payment_method_data { - Some(pm_data) => match payment_method { - Some(payment_method) => match pm_data { + Some(pm_data) => match payment_method_type { + Some(payment_method_type) => match pm_data { domain::PaymentMethodData::Card(card) => { let card_detail = payment_methods::CardDetail { card_number: card.card_number.clone(), @@ -706,9 +706,9 @@ pub(crate) async fn get_payment_method_create_request( .flatten(), }; let payment_method_request = payment_methods::PaymentMethodCreate { - payment_method, - payment_method_type: payment_method_type - .get_required_value("Payment_method_type") + payment_method_type, + payment_method_subtype: payment_method_subtype + .get_required_value("payment_method_subtype") .change_context(errors::ApiErrorResponse::MissingRequiredField { field_name: "payment_method_data", })?, @@ -900,8 +900,8 @@ pub async fn create_payment_method( state, key_store, Some(resp.vault_id.get_string_repr().clone()), - Some(req.payment_method), Some(req.payment_method_type), + Some(req.payment_method_subtype), ) .await .attach_printable("Unable to create Payment method data")?; @@ -1072,8 +1072,8 @@ pub async fn payment_method_intent_confirm( state, key_store, Some(resp.vault_id.get_string_repr().clone()), - Some(req.payment_method), Some(req.payment_method_type), + Some(req.payment_method_subtype), ) .await .attach_printable("Unable to create Payment method data")?; @@ -1132,7 +1132,9 @@ pub async fn create_payment_method_in_db( locker_id: Option, merchant_id: &id_type::MerchantId, customer_acceptance: Option, - payment_method_data: crypto::OptionalEncryptableValue, + payment_method_data: domain::types::OptionalEncryptableJsonType< + api::payment_methods::PaymentMethodsData, + >, key_store: &domain::MerchantKeyStore, connector_mandate_details: Option, status: Option, @@ -1154,8 +1156,8 @@ pub async fn create_payment_method_in_db( merchant_id: merchant_id.to_owned(), id: payment_method_id, locker_id, - payment_method: Some(req.payment_method), payment_method_type: Some(req.payment_method_type), + payment_method_subtype: Some(req.payment_method_subtype), payment_method_data, connector_mandate_details, customer_acceptance, @@ -1208,8 +1210,8 @@ pub async fn create_payment_method_for_intent( merchant_id: merchant_id.to_owned(), id: payment_method_id, locker_id: None, - payment_method: None, payment_method_type: None, + payment_method_subtype: None, payment_method_data: None, connector_mandate_details: None, customer_acceptance: None, @@ -1242,8 +1244,8 @@ pub async fn create_pm_additional_data_update( state: &SessionState, key_store: &domain::MerchantKeyStore, vault_id: Option, - payment_method: Option, - payment_method_type: Option, + payment_method_type: Option, + payment_method_subtype: Option, ) -> RouterResult { let card = match pmd { pm_types::PaymentMethodVaultingData::Card(card) => { @@ -1260,8 +1262,8 @@ pub async fn create_pm_additional_data_update( let pm_update = storage::PaymentMethodUpdate::AdditionalDataUpdate { status: Some(enums::PaymentMethodStatus::Active), locker_id: vault_id, - payment_method, - payment_method_type, + payment_method_type_v2: payment_method_type, + payment_method_subtype, payment_method_data: Some(pmd.into()), network_token_requestor_reference_id: None, network_token_locker_id: None, @@ -1508,7 +1510,9 @@ pub async fn list_customer_payment_method( let mut filtered_saved_payment_methods_ctx = Vec::new(); for pm in saved_payment_methods.into_iter() { - let payment_method = pm.payment_method.get_required_value("payment_method")?; + let payment_method = pm + .get_payment_method_type() + .get_required_value("payment_method")?; let parent_payment_method_token = is_payment_associated.then(|| generate_id(consts::ID_LENGTH, "token")); @@ -1601,9 +1605,11 @@ async fn generate_saved_pm_response( customer: &domain::Customer, payment_info: Option<&pm_types::SavedPMLPaymentsInfo>, ) -> Result> { - let payment_method = pm.payment_method.get_required_value("payment_method")?; + let payment_method_type = pm + .get_payment_method_type() + .get_required_value("payment_method_type")?; - let bank_details = if payment_method == enums::PaymentMethod::BankDebit { + let bank_details = if payment_method_type == enums::PaymentMethod::BankDebit { cards::get_masked_bank_details(&pm) .await .unwrap_or_else(|err| { @@ -1670,8 +1676,8 @@ async fn generate_saved_pm_response( payment_token: parent_payment_method_token.clone(), payment_method_id: pm.get_id().get_string_repr().to_owned(), customer_id: pm.customer_id.to_owned(), - payment_method, - payment_method_type: pm.payment_method_type, + payment_method_type, + payment_method_subtype: pm.get_payment_method_subtype(), payment_method_data: pmd, recurring_enabled: mca_enabled, created: Some(pm.created_at), @@ -1723,8 +1729,7 @@ pub async fn retrieve_payment_method( let pmd = payment_method .payment_method_data .clone() - .map(|x| x.into_inner().expose()) - .and_then(|v| serde_json::from_value::(v).ok()) + .map(|x| x.into_inner().expose().into_inner()) .and_then(|pmd| match pmd { api::PaymentMethodsData::Card(card) => { Some(api::PaymentMethodResponseData::Card(card.into())) @@ -1736,8 +1741,8 @@ pub async fn retrieve_payment_method( merchant_id: payment_method.merchant_id.to_owned(), customer_id: payment_method.customer_id.to_owned(), payment_method_id: payment_method.id.get_string_repr().to_string(), - payment_method: payment_method.payment_method, - payment_method_type: payment_method.payment_method_type, + payment_method_type: payment_method.get_payment_method_type(), + payment_method_subtype: payment_method.get_payment_method_subtype(), created: Some(payment_method.created_at), recurring_enabled: false, last_used_at: Some(payment_method.last_used_at), @@ -1813,8 +1818,8 @@ pub async fn update_payment_method( &state, &key_store, Some(vaulting_response.vault_id.get_string_repr().clone()), - payment_method.payment_method, - payment_method.payment_method_type, + payment_method.get_payment_method_type(), + payment_method.get_payment_method_subtype(), ) .await .attach_printable("Unable to create Payment method data")?; @@ -1956,7 +1961,7 @@ impl pm_types::SavedPMLPaymentsInfo { .get_order_fulfillment_time() .unwrap_or(common_utils::consts::DEFAULT_INTENT_FULFILLMENT_TIME); - pm_routes::ParentPaymentMethodToken::create_key_for_token((token, pma.payment_method)) + pm_routes::ParentPaymentMethodToken::create_key_for_token((token, pma.payment_method_type)) .insert(intent_fulfillment_time, hyperswitch_token_data, state) .await?; diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index fcf0c6ca4d1d..49a75735ea47 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -1915,8 +1915,8 @@ pub async fn update_customer_payment_method( // Construct new payment method object from request let new_pm = api::PaymentMethodCreate { - payment_method: pm.payment_method, - payment_method_type: pm.payment_method_type, + payment_method: pm.get_payment_method_type(), + payment_method_type: pm.get_payment_method_subtype(), payment_method_issuer: pm.payment_method_issuer.clone(), payment_method_issuer_code: pm.payment_method_issuer_code, #[cfg(feature = "payouts")] @@ -2017,10 +2017,10 @@ pub async fn update_customer_payment_method( // Return existing payment method data as response without any changes api::PaymentMethodResponse { merchant_id: pm.merchant_id.to_owned(), - customer_id: Some(pm.customer_id), - payment_method_id: pm.payment_method_id, - payment_method: pm.payment_method, - payment_method_type: pm.payment_method_type, + customer_id: Some(pm.customer_id.clone()), + payment_method_id: pm.payment_method_id.clone(), + payment_method: pm.get_payment_method_type(), + payment_method_type: pm.get_payment_method_subtype(), #[cfg(feature = "payouts")] bank_transfer: None, card: Some(existing_card_data), @@ -3264,14 +3264,14 @@ pub async fn list_payment_methods( let customer_wallet_pm = customer_payment_methods .iter() .filter(|cust_pm| { - cust_pm.payment_method == Some(enums::PaymentMethod::Wallet) + cust_pm.get_payment_method_type() == Some(enums::PaymentMethod::Wallet) }) .collect::>(); response.retain(|mca| { !(mca.payment_method == enums::PaymentMethod::Wallet && customer_wallet_pm.iter().any(|cust_pm| { - cust_pm.payment_method_type == Some(mca.payment_method_type) + cust_pm.get_payment_method_subtype() == Some(mca.payment_method_type) })) }); @@ -4665,7 +4665,9 @@ pub async fn list_customer_payment_method( for pm in resp.into_iter() { let parent_payment_method_token = generate_id(consts::ID_LENGTH, "token"); - let payment_method = pm.payment_method.get_required_value("payment_method")?; + let payment_method = pm + .get_payment_method_type() + .get_required_value("payment_method")?; let pm_list_context = get_pm_list_context( state, @@ -4735,9 +4737,9 @@ pub async fn list_customer_payment_method( let pma = api::CustomerPaymentMethod { payment_token: parent_payment_method_token.to_owned(), payment_method_id: pm.payment_method_id.clone(), - customer_id: pm.customer_id, + customer_id: pm.customer_id.clone(), payment_method, - payment_method_type: pm.payment_method_type, + payment_method_type: pm.get_payment_method_subtype(), payment_method_issuer: pm.payment_method_issuer, card: pm_list_context.card_details, metadata: pm.metadata, @@ -5194,6 +5196,10 @@ pub async fn get_lookup_key_from_locker( pub async fn get_masked_bank_details( pm: &domain::PaymentMethod, ) -> errors::RouterResult> { + #[cfg(all( + any(feature = "v2", feature = "v1"), + not(feature = "payment_methods_v2") + ))] let payment_method_data = pm .payment_method_data .clone() @@ -5208,6 +5214,12 @@ pub async fn get_masked_bank_details( ) .transpose()?; + #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] + let payment_method_data = pm + .payment_method_data + .clone() + .map(|x| x.into_inner().expose().into_inner()); + match payment_method_data { Some(pmd) => match pmd { PaymentMethodsData::Card(_) => Ok(None), @@ -5223,6 +5235,10 @@ pub async fn get_masked_bank_details( pub async fn get_bank_account_connector_details( pm: &domain::PaymentMethod, ) -> errors::RouterResult> { + #[cfg(all( + any(feature = "v2", feature = "v1"), + not(feature = "payment_methods_v2") + ))] let payment_method_data = pm .payment_method_data .clone() @@ -5237,6 +5253,12 @@ pub async fn get_bank_account_connector_details( ) .transpose()?; + #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] + let payment_method_data = pm + .payment_method_data + .clone() + .map(|x| x.into_inner().expose().into_inner()); + match payment_method_data { Some(pmd) => match pmd { PaymentMethodsData::Card(_) => Err(errors::ApiErrorResponse::UnprocessableEntity { @@ -5250,12 +5272,12 @@ pub async fn get_bank_account_connector_details( .ok_or(errors::ApiErrorResponse::InternalServerError)?; let pm_type = pm - .payment_method_type + .get_payment_method_subtype() .get_required_value("payment_method_type") .attach_printable("PaymentMethodType not found")?; let pm = pm - .payment_method + .get_payment_method_type() .get_required_value("payment_method") .attach_printable("PaymentMethod not found")?; @@ -5318,7 +5340,7 @@ pub async fn set_default_payment_method( .await .to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?; let pm = payment_method - .payment_method + .get_payment_method_type() .get_required_value("payment_method")?; utils::when( @@ -5363,7 +5385,7 @@ pub async fn set_default_payment_method( let resp = CustomerDefaultPaymentMethodResponse { default_payment_method_id: updated_customer_details.default_payment_method_id, customer_id, - payment_method_type: payment_method.payment_method_type, + payment_method_type: payment_method.get_payment_method_subtype(), payment_method: pm, }; @@ -5562,7 +5584,7 @@ pub async fn retrieve_payment_method( .await .to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?; - let card = if pm.payment_method == Some(enums::PaymentMethod::Card) { + let card = if pm.get_payment_method_type() == Some(enums::PaymentMethod::Card) { let card_detail = if state.conf.locker.locker_enabled { let card = get_card_from_locker( &state, @@ -5585,11 +5607,11 @@ pub async fn retrieve_payment_method( }; Ok(services::ApplicationResponse::Json( api::PaymentMethodResponse { - merchant_id: pm.merchant_id, - customer_id: Some(pm.customer_id), - payment_method_id: pm.payment_method_id, - payment_method: pm.payment_method, - payment_method_type: pm.payment_method_type, + merchant_id: pm.merchant_id.clone(), + customer_id: Some(pm.customer_id.clone()), + payment_method_id: pm.payment_method_id.clone(), + payment_method: pm.get_payment_method_type(), + payment_method_type: pm.get_payment_method_subtype(), #[cfg(feature = "payouts")] bank_transfer: None, card, @@ -5636,7 +5658,7 @@ pub async fn delete_payment_method( .to_not_found_response(errors::ApiErrorResponse::InternalServerError) .attach_printable("Customer not found for the payment method")?; - if key.payment_method == Some(enums::PaymentMethod::Card) { + if key.get_payment_method_type() == Some(enums::PaymentMethod::Card) { let response = delete_card_from_locker( &state, &key.customer_id, diff --git a/crates/router/src/core/payment_methods/surcharge_decision_configs.rs b/crates/router/src/core/payment_methods/surcharge_decision_configs.rs index ca1cdf06768d..ff52799ed631 100644 --- a/crates/router/src/core/payment_methods/surcharge_decision_configs.rs +++ b/crates/router/src/core/payment_methods/surcharge_decision_configs.rs @@ -412,9 +412,10 @@ pub async fn perform_surcharge_decision_management_for_saved_cards( .get_required_value("payment_token") .change_context(ConfigError::InputConstructionError)?; - backend_input.payment_method.payment_method = Some(customer_payment_method.payment_method); + backend_input.payment_method.payment_method = + Some(customer_payment_method.payment_method_type); backend_input.payment_method.payment_method_type = - customer_payment_method.payment_method_type; + customer_payment_method.payment_method_subtype; let card_network = match customer_payment_method.payment_method_data.as_ref() { Some(api_models::payment_methods::PaymentMethodListData::Card(card)) => { diff --git a/crates/router/src/core/payment_methods/transformers.rs b/crates/router/src/core/payment_methods/transformers.rs index 51a109e8a909..c0f54a30f3f2 100644 --- a/crates/router/src/core/payment_methods/transformers.rs +++ b/crates/router/src/core/payment_methods/transformers.rs @@ -552,11 +552,7 @@ pub fn generate_payment_method_response( let pmd = pm .payment_method_data .clone() - .map(|data| data.into_inner().expose()) - .map(|decrypted_value| decrypted_value.parse_value("PaymentMethodsData")) - .transpose() - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("unable to parse PaymentMethodsData")? + .map(|data| data.into_inner().expose().into_inner()) .and_then(|data| match data { api::PaymentMethodsData::Card(card) => { Some(api::PaymentMethodResponseData::Card(card.into())) @@ -568,8 +564,8 @@ pub fn generate_payment_method_response( merchant_id: pm.merchant_id.to_owned(), customer_id: pm.customer_id.to_owned(), payment_method_id: pm.id.get_string_repr().to_owned(), - payment_method: pm.payment_method, - payment_method_type: pm.payment_method_type, + payment_method_type: pm.get_payment_method_type(), + payment_method_subtype: pm.get_payment_method_subtype(), created: Some(pm.created_at), recurring_enabled: false, last_used_at: Some(pm.last_used_at), diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index dd481467f16f..5ac8f454c21f 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -5683,7 +5683,7 @@ pub fn is_network_transaction_id_flow( .connector_list; is_connector_agnostic_mit_enabled == Some(true) - && payment_method_info.payment_method == Some(storage_enums::PaymentMethod::Card) + && payment_method_info.get_payment_method_type() == Some(storage_enums::PaymentMethod::Card) && ntid_supported_connectors.contains(&connector) && payment_method_info.network_transaction_id.is_some() } @@ -5702,7 +5702,7 @@ pub fn is_network_token_with_network_transaction_id_flow( match ( is_connector_agnostic_mit_enabled, is_network_tokenization_enabled, - payment_method_info.payment_method, + payment_method_info.get_payment_method_type(), payment_method_info.network_transaction_id.clone(), payment_method_info.network_token_locker_id.is_some(), payment_method_info diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index f00f03d929fa..5dc5ca35469b 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -554,8 +554,8 @@ pub async fn get_token_pm_type_mandate_details( ( None, - payment_method_info.payment_method, - payment_method_info.payment_method_type, + payment_method_info.get_payment_method_type(), + payment_method_info.get_payment_method_subtype(), None, None, None, @@ -608,7 +608,7 @@ pub async fn get_token_pm_type_mandate_details( Ok(customer_payment_methods) => Ok(customer_payment_methods .iter() .find(|payment_method| { - payment_method.payment_method_type + payment_method.get_payment_method_subtype() == request.payment_method_type }) .cloned()), @@ -808,13 +808,13 @@ pub async fn get_token_for_recurring_mandate( .to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?; let token = Uuid::new_v4().to_string(); - let payment_method_type = payment_method.payment_method_type; + let payment_method_type = payment_method.get_payment_method_subtype(); let mandate_connector_details = payments::MandateConnectorDetails { connector: mandate.connector, merchant_connector_id: mandate.merchant_connector_id, }; - if let Some(enums::PaymentMethod::Card) = payment_method.payment_method { + if let Some(enums::PaymentMethod::Card) = payment_method.get_payment_method_type() { if state.conf.locker.locker_enabled { let _ = cards::get_lookup_key_from_locker( state, @@ -828,7 +828,7 @@ pub async fn get_token_for_recurring_mandate( if let Some(payment_method_from_request) = req.payment_method { let pm: storage_enums::PaymentMethod = payment_method_from_request; if payment_method - .payment_method + .get_payment_method_type() .is_some_and(|payment_method| payment_method != pm) { Err(report!(errors::ApiErrorResponse::PreconditionFailed { @@ -842,14 +842,14 @@ pub async fn get_token_for_recurring_mandate( Ok(MandateGenericData { token: Some(token), - payment_method: payment_method.payment_method, + payment_method: payment_method.get_payment_method_type(), recurring_mandate_payment_data: Some(RecurringMandatePaymentData { payment_method_type, original_payment_authorized_amount, original_payment_authorized_currency, mandate_metadata: None, }), - payment_method_type: payment_method.payment_method_type, + payment_method_type: payment_method.get_payment_method_subtype(), mandate_connector: Some(mandate_connector_details), mandate_data: None, payment_method_info: Some(payment_method), @@ -857,14 +857,14 @@ pub async fn get_token_for_recurring_mandate( } else { Ok(MandateGenericData { token: None, - payment_method: payment_method.payment_method, + payment_method: payment_method.get_payment_method_type(), recurring_mandate_payment_data: Some(RecurringMandatePaymentData { payment_method_type, original_payment_authorized_amount, original_payment_authorized_currency, mandate_metadata: None, }), - payment_method_type: payment_method.payment_method_type, + payment_method_type: payment_method.get_payment_method_subtype(), mandate_connector: Some(mandate_connector_details), mandate_data: None, payment_method_info: Some(payment_method), @@ -2340,7 +2340,9 @@ pub async fn make_pm_data<'a, F: Clone, R, D>( if payment_data.token_data.is_none() { if let Some(payment_method_info) = &payment_data.payment_method_info { - if payment_method_info.payment_method == Some(storage_enums::PaymentMethod::Card) { + if payment_method_info.get_payment_method_type() + == Some(storage_enums::PaymentMethod::Card) + { payment_data.token_data = Some(storage::PaymentTokenData::PermanentCard(CardTokenData { payment_method_id: Some(payment_method_info.get_id().clone()), diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index 9bbe7cca3912..8c82c38be714 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -653,7 +653,7 @@ impl GetTracker, api::PaymentsRequest> for Pa .or(payment_attempt.payment_method_type) .or(payment_method_info .as_ref() - .and_then(|pm_info| pm_info.payment_method_type)); + .and_then(|pm_info| pm_info.get_payment_method_subtype())); // The operation merges mandate data from both request and payment_attempt let setup_mandate = mandate_data.map(|mut sm| { diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index 6f01af96bb8e..4bae04e14264 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -610,7 +610,8 @@ where Ok(customer_payment_methods) => Ok(customer_payment_methods .iter() .find(|payment_method| { - payment_method.payment_method_type == payment_method_type + payment_method.get_payment_method_subtype() + == payment_method_type }) .cloned()), Err(error) => { @@ -1143,6 +1144,7 @@ pub fn update_router_data_with_payment_method_token_result( } } +#[cfg(feature = "v1")] pub fn add_connector_mandate_details_in_payment_method( payment_method_type: Option, authorized_amount: Option, @@ -1174,7 +1176,9 @@ pub fn add_connector_mandate_details_in_payment_method( None } } + #[allow(clippy::too_many_arguments)] +#[cfg(feature = "v1")] pub fn update_connector_mandate_details( mandate_details: Option, payment_method_type: Option, diff --git a/crates/router/src/core/pm_auth.rs b/crates/router/src/core/pm_auth.rs index b8672ee79b42..afba73e839c7 100644 --- a/crates/router/src/core/pm_auth.rs +++ b/crates/router/src/core/pm_auth.rs @@ -375,7 +375,7 @@ async fn store_bank_details_in_payment_methods( > = HashMap::new(); let key_manager_state = (&state).into(); for pm in payment_methods { - if pm.payment_method == Some(enums::PaymentMethod::BankDebit) + if pm.get_payment_method_type() == Some(enums::PaymentMethod::BankDebit) && pm.payment_method_data.is_some() { let bank_details_pm_data = pm @@ -561,8 +561,8 @@ async fn store_bank_details_in_payment_methods( customer_id: customer_id.clone(), merchant_id: merchant_account.get_id().clone(), id: pm_id, - payment_method: Some(enums::PaymentMethod::BankDebit), - payment_method_type: Some(creds.payment_method_type), + payment_method_type: Some(enums::PaymentMethod::BankDebit), + payment_method_subtype: Some(creds.payment_method_type), status: enums::PaymentMethodStatus::Active, metadata: None, payment_method_data: Some(encrypted_data.into()), diff --git a/crates/router/src/routes/payment_methods.rs b/crates/router/src/routes/payment_methods.rs index 764e75df02a0..7296a510248a 100644 --- a/crates/router/src/routes/payment_methods.rs +++ b/crates/router/src/routes/payment_methods.rs @@ -148,8 +148,8 @@ pub async fn confirm_payment_method_intent_api( let inner_payload = payment_methods::PaymentMethodIntentConfirmInternal { id: pm_id.clone(), - payment_method: payload.payment_method, payment_method_type: payload.payment_method_type, + payment_method_subtype: payload.payment_method_subtype, client_secret: payload.client_secret.clone(), customer_id: payload.customer_id.to_owned(), payment_method_data: payload.payment_method_data.clone(), diff --git a/crates/router/src/types/api/mandates.rs b/crates/router/src/types/api/mandates.rs index b3bcfa2a8872..949eac397450 100644 --- a/crates/router/src/types/api/mandates.rs +++ b/crates/router/src/types/api/mandates.rs @@ -56,7 +56,7 @@ impl MandateResponseExt for MandateResponse { .to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?; let pm = payment_method - .payment_method + .get_payment_method_type() .get_required_value("payment_method") .change_context(errors::ApiErrorResponse::PaymentMethodNotFound) .attach_printable("payment_method not found")?; @@ -91,7 +91,7 @@ impl MandateResponseExt for MandateResponse { None }; let payment_method_type = payment_method - .payment_method_type + .get_payment_method_subtype() .map(|pmt| pmt.to_string()); Ok(Self { mandate_id: mandate.mandate_id, diff --git a/crates/router/src/types/api/payment_methods.rs b/crates/router/src/types/api/payment_methods.rs index d66bf079d42a..8b1175d5cc63 100644 --- a/crates/router/src/types/api/payment_methods.rs +++ b/crates/router/src/types/api/payment_methods.rs @@ -6,7 +6,7 @@ pub use api_models::payment_methods::{ PaymentMethodCollectLinkRenderRequest, PaymentMethodCollectLinkRequest, PaymentMethodCreate, PaymentMethodCreateData, PaymentMethodDeleteResponse, PaymentMethodId, PaymentMethodIntentConfirm, PaymentMethodIntentConfirmInternal, PaymentMethodIntentCreate, - PaymentMethodList, PaymentMethodListData, PaymentMethodListRequest, PaymentMethodListResponse, + PaymentMethodListData, PaymentMethodListRequest, PaymentMethodListResponse, PaymentMethodMigrate, PaymentMethodResponse, PaymentMethodResponseData, PaymentMethodUpdate, PaymentMethodUpdateData, PaymentMethodsData, TokenizePayloadEncrypted, TokenizePayloadRequest, TokenizedCardValue1, TokenizedCardValue2, TokenizedWalletValue1, TokenizedWalletValue2, @@ -20,7 +20,7 @@ pub use api_models::payment_methods::{ CustomerPaymentMethodsListResponse, DefaultPaymentMethod, DeleteTokenizeByTokenRequest, GetTokenizePayloadRequest, GetTokenizePayloadResponse, ListCountriesCurrenciesRequest, PaymentMethodCollectLinkRenderRequest, PaymentMethodCollectLinkRequest, PaymentMethodCreate, - PaymentMethodCreateData, PaymentMethodDeleteResponse, PaymentMethodId, PaymentMethodList, + PaymentMethodCreateData, PaymentMethodDeleteResponse, PaymentMethodId, PaymentMethodListRequest, PaymentMethodListResponse, PaymentMethodMigrate, PaymentMethodResponse, PaymentMethodUpdate, PaymentMethodsData, TokenizePayloadEncrypted, TokenizePayloadRequest, TokenizedCardValue1, TokenizedCardValue2, TokenizedWalletValue1, @@ -65,8 +65,8 @@ impl PaymentMethodCreateExt for PaymentMethodCreate { fn validate(&self) -> RouterResult<()> { utils::when( !validate_payment_method_type_against_payment_method( - self.payment_method, self.payment_method_type, + self.payment_method_subtype, ), || { Err(report!(errors::ApiErrorResponse::InvalidRequestData { @@ -78,7 +78,7 @@ impl PaymentMethodCreateExt for PaymentMethodCreate { utils::when( !Self::validate_payment_method_data_against_payment_method( - self.payment_method, + self.payment_method_type, self.payment_method_data.clone(), ), || { @@ -97,8 +97,8 @@ impl PaymentMethodCreateExt for PaymentMethodIntentConfirm { fn validate(&self) -> RouterResult<()> { utils::when( !validate_payment_method_type_against_payment_method( - self.payment_method, self.payment_method_type, + self.payment_method_subtype, ), || { Err(report!(errors::ApiErrorResponse::InvalidRequestData { @@ -110,7 +110,7 @@ impl PaymentMethodCreateExt for PaymentMethodIntentConfirm { utils::when( !Self::validate_payment_method_data_against_payment_method( - self.payment_method, + self.payment_method_type, self.payment_method_data.clone(), ), || { diff --git a/crates/router/src/types/domain/types.rs b/crates/router/src/types/domain/types.rs index 082e8df4bfc9..d4cd9ef62d7d 100644 --- a/crates/router/src/types/domain/types.rs +++ b/crates/router/src/types/domain/types.rs @@ -1,6 +1,6 @@ use common_utils::types::keymanager::KeyManagerState; pub use hyperswitch_domain_models::type_encryption::{ - crypto_operation, AsyncLift, CryptoOperation, Lift, + crypto_operation, AsyncLift, CryptoOperation, Lift, OptionalEncryptableJsonType, }; impl From<&crate::SessionState> for KeyManagerState { diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index af1dc188015d..31ec1ff8c327 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -101,8 +101,8 @@ impl merchant_id: item.merchant_id.to_owned(), customer_id: Some(item.customer_id.to_owned()), payment_method_id: item.get_id().clone(), - payment_method: item.payment_method, - payment_method_type: item.payment_method_type, + payment_method: item.get_payment_method_type(), + payment_method_type: item.get_payment_method_subtype(), card: card_details, recurring_enabled: false, installment_payment_enabled: false, diff --git a/v2_migrations/2024-08-23-112510_payment_methods_v2_db_changes/down.sql b/v2_migrations/2024-08-23-112510_payment_methods_v2_db_changes/down.sql index ce485048f4ef..30c499e6c42d 100644 --- a/v2_migrations/2024-08-23-112510_payment_methods_v2_db_changes/down.sql +++ b/v2_migrations/2024-08-23-112510_payment_methods_v2_db_changes/down.sql @@ -10,7 +10,9 @@ ALTER TABLE payment_methods ADD COLUMN IF NOT EXISTS direct_debit_token VARCHAR(128), ADD COLUMN IF NOT EXISTS swift_code VARCHAR(32), ADD COLUMN IF NOT EXISTS payment_method_issuer VARCHAR(128), - ADD COLUMN IF NOT EXISTS metadata JSON; + ADD COLUMN IF NOT EXISTS metadata JSON, + ADD COLUMN IF NOT EXISTS payment_method VARCHAR, + ADD COLUMN IF NOT EXISTS payment_method_type VARCHAR(64); CREATE TYPE "PaymentMethodIssuerCode" AS ENUM ( 'jp_hdfc', @@ -27,7 +29,10 @@ CREATE TYPE "PaymentMethodIssuerCode" AS ENUM ( ALTER TABLE payment_methods ADD COLUMN IF NOT EXISTS payment_method_issuer_code "PaymentMethodIssuerCode"; -ALTER TABLE payment_methods DROP COLUMN IF EXISTS locker_fingerprint_id; +ALTER TABLE payment_methods + DROP COLUMN IF EXISTS locker_fingerprint_id, + DROP COLUMN IF EXISTS payment_method_type_v2, + DROP COLUMN IF EXISTS payment_method_subtype; ALTER TABLE payment_methods ADD COLUMN IF NOT EXISTS payment_method_id VARCHAR(64); UPDATE payment_methods SET payment_method_id = id; diff --git a/v2_migrations/2024-08-23-112510_payment_methods_v2_db_changes/up.sql b/v2_migrations/2024-08-23-112510_payment_methods_v2_db_changes/up.sql index 23a274b68444..fb319d9f05df 100644 --- a/v2_migrations/2024-08-23-112510_payment_methods_v2_db_changes/up.sql +++ b/v2_migrations/2024-08-23-112510_payment_methods_v2_db_changes/up.sql @@ -12,11 +12,16 @@ ALTER TABLE payment_methods DROP COLUMN IF EXISTS swift_code, DROP COLUMN IF EXISTS payment_method_issuer, DROP COLUMN IF EXISTS payment_method_issuer_code, - DROP COLUMN IF EXISTS metadata; + DROP COLUMN IF EXISTS metadata, + DROP COLUMN IF EXISTS payment_method, + DROP COLUMN IF EXISTS payment_method_type; DROP TYPE IF EXISTS "PaymentMethodIssuerCode"; -ALTER TABLE payment_methods ADD COLUMN IF NOT EXISTS locker_fingerprint_id VARCHAR(64); +ALTER TABLE payment_methods + ADD COLUMN IF NOT EXISTS locker_fingerprint_id VARCHAR(64), + ADD COLUMN IF NOT EXISTS payment_method_type_v2 VARCHAR(64), + ADD COLUMN IF NOT EXISTS payment_method_subtype VARCHAR(64); ALTER TABLE payment_methods DROP COLUMN IF EXISTS id; ALTER TABLE payment_methods ADD COLUMN IF NOT EXISTS id VARCHAR(64);