Bug: add payment_method_type duplication check for samsung pay



As we do not have a unique identifier to store when we save a wallet, we are unable to prevent payment method duplication. As a result, when a customer uses a saved wallet, we end up saving it again. During the next payment, the customer will see two buttons for the same wallet in the customer PML.

To address this issue, we check if the wallet is already saved. If the particular wallet is already saved, we simply update the 'last used' status for the same wallet, rather than creating a new entry. This payment method duplication check is already implemented for Apple Pay and Google Pay, similar check needs to be added for samsung pay as well
diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs
index 54514f6e05a..c286ae04d5f 100644
--- a/crates/common_enums/src/enums.rs
+++ b/crates/common_enums/src/enums.rs
@@ -1651,6 +1651,12 @@ pub enum PaymentMethodType {
     DirectCarrierBilling,
 }
 
+impl PaymentMethodType {
+    pub fn should_check_for_customer_saved_payment_method_type(self) -> bool {
+        matches!(self, Self::ApplePay | Self::GooglePay | Self::SamsungPay)
+    }
+}
+
 impl masking::SerializableSecret for PaymentMethodType {}
 
 /// Indicates the type of payment method. Eg: 'card', 'wallet', etc.
diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs
index 1803e12f0b2..8020c3d4d5f 100644
--- a/crates/router/src/core/payments/helpers.rs
+++ b/crates/router/src/core/payments/helpers.rs
@@ -591,10 +591,13 @@ pub async fn get_token_pm_type_mandate_details(
                             mandate_generic_data.mandate_connector,
                             mandate_generic_data.payment_method_info,
                         )
-                    } else if request.payment_method_type
-                        == Some(api_models::enums::PaymentMethodType::ApplePay)
-                        || request.payment_method_type
-                            == Some(api_models::enums::PaymentMethodType::GooglePay)
+                    } else if request
+                        .payment_method_type
+                        .map(|payment_method_type_value| {
+                            payment_method_type_value
+                                .should_check_for_customer_saved_payment_method_type()
+                        })
+                        .unwrap_or(false)
                     {
                         let payment_request_customer_id = request.get_customer_id();
                         if let Some(customer_id) =
diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs
index d46977d8c99..b4e4db3d161 100644
--- a/crates/router/src/core/payments/tokenization.rs
+++ b/crates/router/src/core/payments/tokenization.rs
@@ -655,9 +655,11 @@ where
                     },
                     None => {
                         let customer_saved_pm_option = if payment_method_type
-                            == Some(api_models::enums::PaymentMethodType::ApplePay)
-                            || payment_method_type
-                                == Some(api_models::enums::PaymentMethodType::GooglePay)
+                            .map(|payment_method_type_value| {
+                                payment_method_type_value
+                                    .should_check_for_customer_saved_payment_method_type()
+                            })
+                            .unwrap_or(false)
                         {
                             match state
                                 .store

## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [x] Bugfix
- [ ] New feature
- [ ] Enhancement
- [ ] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
<!-- Describe your changes in detail -->
As we do not have a unique identifier to store when we save a wallet, we are unable to prevent payment method duplication. As a result, when a customer uses a saved wallet, we end up saving it again. During the next payment, the customer will see two buttons for the same wallet in the customer PML.

To address this issue, we check if the wallet is already saved. If the particular wallet is already saved, we simply update the 'last used' status for the same wallet, rather than creating a new entry. This payment method duplication check is already implemented for Apple Pay and Google Pay, and in this PR, I have extended it to include Samsung Pay as well.

### Additional Changes

- [ ] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables

<!--
Provide links to the files with corresponding changes.

Following are the paths where you can find config files:
1. `config`
2. `crates/router/src/configs`
3. `loadtest/config`
-->


## Motivation and Context
<!--
Why is this change required? What problem does it solve?
If it fixes an open issue, please link to the issue here.

If you don't have an issue, we'd recommend starting with one first so the PR
can focus on the implementation (unless it is an obvious bug or documentation fix
that will have little conversation).
-->


## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
-> Create a merchant connector account with google pay or samsung pay enabled
-> Enable the below config
```
curl --location 'localhost:8080/configs/' \
--header 'api-key: api-key' \
--header 'Content-Type: application/json' \
--data '{
    "key": "skip_saving_wallet_at_connector_merchant_1740130285",
    "value": "[\"samsung_pay\",\"google_pay\"]"
}'
```
```
{
    "key": "skip_saving_wallet_at_connector_merchant_1740130285",
    "value": "[\"samsung_pay\",\"google_pay\"]"
}
```
-> Make a samsung pay payment with `"setup_future_usage": "off_session"`
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: api-key' \
--data-raw '{
    "amount": 2300,
    "currency": "USD",
    "confirm": true,
    "business_country": "US",
    "business_label": "default",
    "amount_to_capture": 2300,
    "customer_id": "cu_1740120198",
    "setup_future_usage": "off_session",
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    "return_url": "https://google.com",
    "email": "samsungpay@gmail.com",
    "name": "Joseph Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "Its my first payment request",
    "statement_descriptor_name": "Juspay",
    "statement_descriptor_suffix": "Router",
    "payment_method": "wallet",
    "payment_method_type": "samsung_pay",
    "customer_acceptance": {
        "acceptance_type": "offline",
        "accepted_at": "1963-05-03T04:07:52.723Z",
        "online": {
            "ip_address": "in sit",
            "user_agent": "amet irure esse"
        }
    },
    "billing": {
        "address": {
            "line1": "1467",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "joseph",
            "last_name": "Doe"
        }
    },
    "payment_method_data": {
        "wallet": {
            "samsung_pay": {
                "payment_credential": {
                    "3_d_s": {
                        "type": "S",
                        "version": "100",
                        "data": "samsung pay token"
                    },
                    "payment_card_brand": "VI",
                    "payment_currency_type": "USD",
                    "payment_last4_fpan": "1661",
                    "method": "3DS",
                    "recurring_payment": false
                }
            }
        }
    }
}
'
```
```
{
    "payment_id": "pay_2p8lTfi6OM7SZrj6PBnR",
    "merchant_id": "merchant_1740130285",
    "status": "succeeded",
    "amount": 2300,
    "net_amount": 2300,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": 2300,
    "connector": "cybersource",
    "client_secret": "pay_2p8lTfi6OM7SZrj6PBnR_secret_gMXnHSdwMhvGnpslHATf",
    "created": "2025-02-21T09:33:01.655Z",
    "currency": "USD",
    "customer_id": "cu_1740120198",
    "customer": {
        "id": "cu_1740120198",
        "name": "Joseph Doe",
        "email": "samsungpay@gmail.com",
        "phone": "999999999",
        "phone_country_code": "+65"
    },
    "description": "Its my first payment request",
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": "on_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "wallet",
    "payment_method_data": {
        "wallet": {
            "samsung_pay": {
                "last4": "1661",
                "card_network": "Visa",
                "type": null
            }
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": null,
    "billing": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": null,
            "line3": null,
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": null,
        "email": null
    },
    "order_details": null,
    "email": "samsungpay@gmail.com",
    "name": "Joseph Doe",
    "phone": "999999999",
    "return_url": "https://google.com/",
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": "Juspay",
    "statement_descriptor_suffix": "Router",
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": "samsung_pay",
    "connector_label": "cybersource_US_default_default",
    "business_country": "US",
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "cu_1740120198",
        "created_at": 1740130381,
        "expires": 1740133981,
        "secret": "epk_6ce927c963fa4105a8ab9228f97416b7"
    },
    "manual_retry_allowed": false,
    "connector_transaction_id": "7401303829696483104805",
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": "pay_2p8lTfi6OM7SZrj6PBnR_1",
    "payment_link": null,
    "profile_id": "pro_Gi6ZTv5ZEsUTOmapC9Rq",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_1qwQigfi1hdSHlCKLEOw",
    "incremental_authorization_allowed": false,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-02-21T09:48:01.655Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2025-02-21T09:33:04.066Z",
    "split_payments": null,
    "frm_metadata": null,
    "extended_authorization_applied": null,
    "capture_before": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": null,
    "card_discovery": null
}
```
-> List customer payment methods for the above customer. We can see that there is only one payment method that is saved
```
curl --location 'http://localhost:8080/customers/cu_1740120198/payment_methods' \
--header 'Accept: application/json' \
--header 'api-key: api-key'
```
```
{
    "customer_payment_methods": [
        {
            "payment_token": "token_NHsoBD91m4hXF1jHayz0",
            "payment_method_id": "pm_BuHQFVj1XP70L0hlwzrT",
            "customer_id": "cu_1740120198",
            "payment_method": "wallet",
            "payment_method_type": "samsung_pay",
            "payment_method_issuer": null,
            "payment_method_issuer_code": null,
            "recurring_enabled": false,
            "installment_payment_enabled": false,
            "payment_experience": [
                "redirect_to_url"
            ],
            "card": null,
            "metadata": null,
            "created": "2025-02-21T09:33:04.086Z",
            "bank": null,
            "surcharge_details": null,
            "requires_cvv": true,
            "last_used_at": "2025-02-21T09:33:04.086Z",
            "default_payment_method_set": true,
            "billing": {
                "address": {
                    "city": "San Fransico",
                    "country": "US",
                    "line1": "1467",
                    "line2": null,
                    "line3": null,
                    "zip": "94122",
                    "state": "California",
                    "first_name": "joseph",
                    "last_name": "Doe"
                },
                "phone": null,
                "email": null
            }
        }
    ],
    "is_guest_customer": null
}
```
-> Make a google pay payment for the same customer and make customer pml. The response will contain the google pay at the top indicating it is the recently used payment method type.
```
curl --location 'http://localhost:8080/customers/cu_1740120198/payment_methods' \
--header 'Accept: application/json' \
--header 'api-key: api-key'
```
```
{
    "customer_payment_methods": [
        {
            "payment_token": "token_CLtCX0lG2248Tg9x8TCs",
            "payment_method_id": "pm_YQISjUrUW9YHJT0Szb7P",
            "customer_id": "cu_1740120198",
            "payment_method": "wallet",
            "payment_method_type": "google_pay",
            "payment_method_issuer": null,
            "payment_method_issuer_code": null,
            "recurring_enabled": false,
            "installment_payment_enabled": false,
            "payment_experience": [
                "redirect_to_url"
            ],
            "card": null,
            "metadata": null,
            "created": "2025-02-21T09:38:01.648Z",
            "bank": null,
            "surcharge_details": null,
            "requires_cvv": true,
            "last_used_at": "2025-02-21T09:38:01.648Z",
            "default_payment_method_set": false,
            "billing": {
                "address": {
                    "city": "San Fransico",
                    "country": "US",
                    "line1": "1467",
                    "line2": null,
                    "line3": null,
                    "zip": "94122",
                    "state": "California",
                    "first_name": "joseph",
                    "last_name": "Doe"
                },
                "phone": null,
                "email": null
            }
        },
        {
            "payment_token": "token_1w5WhYajhQbs8ghjTCXP",
            "payment_method_id": "pm_BuHQFVj1XP70L0hlwzrT",
            "customer_id": "cu_1740120198",
            "payment_method": "wallet",
            "payment_method_type": "samsung_pay",
            "payment_method_issuer": null,
            "payment_method_issuer_code": null,
            "recurring_enabled": false,
            "installment_payment_enabled": false,
            "payment_experience": [
                "redirect_to_url"
            ],
            "card": null,
            "metadata": null,
            "created": "2025-02-21T09:33:04.086Z",
            "bank": null,
            "surcharge_details": null,
            "requires_cvv": true,
            "last_used_at": "2025-02-21T09:33:04.086Z",
            "default_payment_method_set": true,
            "billing": {
                "address": {
                    "city": "San Fransico",
                    "country": "US",
                    "line1": "1467",
                    "line2": null,
                    "line3": null,
                    "zip": "94122",
                    "state": "California",
                    "first_name": "joseph",
                    "last_name": "Doe"
                },
                "phone": null,
                "email": null
            }
        }
    ],
    "is_guest_customer": null
}
```
-> Now make one more samsung pay payment for the same customer
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: api-key' \
--data-raw '{
    "amount": 2300,
    "currency": "USD",
    "confirm": true,
    "business_country": "US",
    "business_label": "default",
    "amount_to_capture": 2300,
    "customer_id": "cu_1740120198",
    "setup_future_usage": "off_session",
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    "return_url": "https://google.com",
    "email": "samsungpay@gmail.com",
    "name": "Joseph Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "Its my first payment request",
    "statement_descriptor_name": "Juspay",
    "statement_descriptor_suffix": "Router",
    "payment_method": "wallet",
    "payment_method_type": "samsung_pay",
    "customer_acceptance": {
        "acceptance_type": "offline",
        "accepted_at": "1963-05-03T04:07:52.723Z",
        "online": {
            "ip_address": "in sit",
            "user_agent": "amet irure esse"
        }
    },
    "billing": {
        "address": {
            "line1": "1467",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "joseph",
            "last_name": "Doe"
        }
    },
    "payment_method_data": {
        "wallet": {
            "samsung_pay": {
                "payment_credential": {
                    "3_d_s": {
                        "type": "S",
                        "version": "100",
                        "data": "samsung pay token"
                    },
                    "payment_card_brand": "VI",
                    "payment_currency_type": "USD",
                    "payment_last4_fpan": "1661",
                    "method": "3DS",
                    "recurring_payment": false
                }
            }
        }
    }
}
'
```
```
{
    "payment_id": "pay_4ixWGjRYTrngGcTYhhYO",
    "merchant_id": "merchant_1740130285",
    "status": "succeeded",
    "amount": 2300,
    "net_amount": 2300,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": 2300,
    "connector": "cybersource",
    "client_secret": "pay_4ixWGjRYTrngGcTYhhYO_secret_PbeOhfHgCOZNYYYTmzcB",
    "created": "2025-02-21T09:40:10.925Z",
    "currency": "USD",
    "customer_id": "cu_1740120198",
    "customer": {
        "id": "cu_1740120198",
        "name": "Joseph Doe",
        "email": "samsungpay@gmail.com",
        "phone": "999999999",
        "phone_country_code": "+65"
    },
    "description": "Its my first payment request",
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": "on_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "wallet",
    "payment_method_data": {
        "wallet": {
            "samsung_pay": {
                "last4": "1661",
                "card_network": "Visa",
                "type": null
            }
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": null,
    "billing": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": null,
            "line3": null,
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": null,
        "email": null
    },
    "order_details": null,
    "email": "samsungpay@gmail.com",
    "name": "Joseph Doe",
    "phone": "999999999",
    "return_url": "https://google.com/",
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": "Juspay",
    "statement_descriptor_suffix": "Router",
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": "samsung_pay",
    "connector_label": "cybersource_US_default_default",
    "business_country": "US",
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "cu_1740120198",
        "created_at": 1740130810,
        "expires": 1740134410,
        "secret": "epk_86d9427e2e0641ae9d888d0aee1892e9"
    },
    "manual_retry_allowed": false,
    "connector_transaction_id": "7401308119186931304807",
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": "pay_4ixWGjRYTrngGcTYhhYO_1",
    "payment_link": null,
    "profile_id": "pro_Gi6ZTv5ZEsUTOmapC9Rq",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_1qwQigfi1hdSHlCKLEOw",
    "incremental_authorization_allowed": false,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-02-21T09:55:10.925Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2025-02-21T09:40:13.489Z",
    "split_payments": null,
    "frm_metadata": null,
    "extended_authorization_applied": null,
    "capture_before": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": null,
    "card_discovery": null
}
```
-> Make customer pml. The response should contain samsung pay at the top indicating it is the recently used payment method type and also there should only be one samsung pay button
```
curl --location 'http://localhost:8080/customers/cu_1740120198/payment_methods' \
--header 'Accept: application/json' \
--header 'api-key: api-key'
```
```
{
    "customer_payment_methods": [
        {
            "payment_token": "token_6QkmZgFGtk17Spmc0Krc",
            "payment_method_id": "pm_BuHQFVj1XP70L0hlwzrT",
            "customer_id": "cu_1740120198",
            "payment_method": "wallet",
            "payment_method_type": "samsung_pay",
            "payment_method_issuer": null,
            "payment_method_issuer_code": null,
            "recurring_enabled": false,
            "installment_payment_enabled": false,
            "payment_experience": [
                "redirect_to_url"
            ],
            "card": null,
            "metadata": null,
            "created": "2025-02-21T09:33:04.086Z",
            "bank": null,
            "surcharge_details": null,
            "requires_cvv": true,
            "last_used_at": "2025-02-21T09:40:13.492Z",
            "default_payment_method_set": true,
            "billing": {
                "address": {
                    "city": "San Fransico",
                    "country": "US",
                    "line1": "1467",
                    "line2": null,
                    "line3": null,
                    "zip": "94122",
                    "state": "California",
                    "first_name": "joseph",
                    "last_name": "Doe"
                },
                "phone": null,
                "email": null
            }
        },
        {
            "payment_token": "token_uUhRNFlDlK8pkDXapajC",
            "payment_method_id": "pm_YQISjUrUW9YHJT0Szb7P",
            "customer_id": "cu_1740120198",
            "payment_method": "wallet",
            "payment_method_type": "google_pay",
            "payment_method_issuer": null,
            "payment_method_issuer_code": null,
            "recurring_enabled": false,
            "installment_payment_enabled": false,
            "payment_experience": [
                "redirect_to_url"
            ],
            "card": null,
            "metadata": null,
            "created": "2025-02-21T09:38:01.648Z",
            "bank": null,
            "surcharge_details": null,
            "requires_cvv": true,
            "last_used_at": "2025-02-21T09:38:01.648Z",
            "default_payment_method_set": false,
            "billing": {
                "address": {
                    "city": "San Fransico",
                    "country": "US",
                    "line1": "1467",
                    "line2": null,
                    "line3": null,
                    "zip": "94122",
                    "state": "California",
                    "first_name": "joseph",
                    "last_name": "Doe"
                },
                "phone": null,
                "email": null
            }
        }
    ],
    "is_guest_customer": null
}
```

## Checklist
<!-- Put an `x` in the boxes that apply -->

- [x] I formatted the code `cargo +nightly fmt --all`
- [x] I addressed lints thrown by `cargo clippy`
- [x] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible
