Bug: [CYPRESS]: Use the SDK to process a payment.



---

### **Title**: Verify Make and View a Test Payment

---

### **Description**:

This task involves testing the "Make a test payment" feature from the homepage. The user will go through the checkout process, entering payment details and viewing the payment summary upon successful payment.

---

### **Test Case**: Make and View a Test Payment

- **Pre-requisites**: None
- **Steps**:
  1. Go to the homepage.
  2. Click on **"Try it out"** in the **"Make a test payment - Try our unified checkout"** message box.
  3. Verify the user is redirected to the **test checkout page**.
  4. Select the currency from the dropdown (e.g., **"EUR"**).
  5. Enter the amount (**77**) in the text box.
  6. Click on **"Show preview"**.
  7. Verify that the **SDK preview** is rendered with the following elements:
     - **"Card number"** text box
     - **"Expiry"** text box
     - **"CVC"** text box
     - **"Save card details"** checkbox
     - **"Pay"** button with the currency and amount
  8. Enter the test card details into the SDK:
     - **Card Number**: 4242 4242 4242 4242
     - **Expiry**: 01/27
     - **CVC**: 492
  9. Verify that the card details are displayed correctly in the respective text boxes.
  10. Click on the **"Pay"** button.
  11. Verify that the **"Payment Successful"** message is displayed.
  12. Click on **"Go to payment"**.
  13. Verify that the user is redirected to the **payment details page**.
  
- **Test Data**:
  - **Currency**: EUR
  - **Amount**: 77
  - **Card Number**: 4242 4242 4242 4242
  - **Expiry**: 01/27
  - **CVC**: 492

- **Expected Results**:
  - The user is redirected to the **test checkout page** after clicking "Try it out."
  - The selected currency (**"EUR"**) should be reflected in the dropdown.
  - The amount (**77**) should be entered and displayed correctly in the text box.
  - After clicking **"Show preview,"** the SDK preview should be rendered with all necessary elements (card number, expiry, CVC, etc.).
  - Test card details should be entered correctly, and the payment form should reflect the correct input.
  - Upon clicking **"Pay,"** a **"Payment Successful"** message should be displayed.
  - The user should be redirected to the **payment details page** upon clicking **"Go to payment."**

---

### **Acceptance Criteria**:
1. The test checkout page is accessible from the homepage.
2. The currency and amount are correctly entered and reflected in the form.
3. The SDK preview renders with the appropriate fields.
4. Payment details are correctly submitted, and the payment is processed successfully.
5. The user can view the payment details page after successful payment.

---

This structured format ensures that all steps, test data, and expected outcomes are clearly defined for testing the payment process.
diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs
index 2d4a539c1e9..453d1521226 100644
--- a/crates/api_models/src/payments.rs
+++ b/crates/api_models/src/payments.rs
@@ -9,6 +9,7 @@ use common_utils::{
 use masking::{PeekInterface, Secret};
 use router_derive::Setter;
 use time::PrimitiveDateTime;
+use url::Url;
 use utoipa::ToSchema;
 
 use crate::{
@@ -177,7 +178,7 @@ pub struct PaymentsRequest {
 
     /// The URL to redirect after the completion of the operation
     #[schema(value_type = Option<String>, example = "https://hyperswitch.io")]
-    pub return_url: Option<url::Url>,
+    pub return_url: Option<Url>,
     /// Indicates that you intend to make future payments with this Payment’s payment method. Providing this parameter will attach the payment method to the Customer, if present, after the Payment is confirmed and any required actions from the user are complete.
     #[schema(value_type = Option<FutureUsage>, example = "off_session")]
     pub setup_future_usage: Option<api_enums::FutureUsage>,
@@ -920,6 +921,8 @@ pub enum WalletData {
     SamsungPay(Box<SamsungPayWalletData>),
     /// The wallet data for WeChat Pay Redirection
     WeChatPayRedirect(Box<WeChatPayRedirection>),
+    /// The wallet data for WeChat Pay
+    WeChatPay(Box<WeChatPay>),
 }
 
 #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
@@ -959,6 +962,9 @@ pub struct ApplePayThirdPartySdkData {}
 #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
 pub struct WeChatPayRedirection {}
 
+#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
+pub struct WeChatPay {}
+
 #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
 pub struct PaypalRedirection {}
 
@@ -1229,8 +1235,13 @@ pub enum NextActionData {
     DisplayBankTransferInformation {
         bank_transfer_steps_and_charges_details: BankTransferNextStepsData,
     },
-    /// contains third party sdk session token response
+    /// Contains third party sdk session token response
     ThirdPartySdkSessionToken { session_token: Option<SessionToken> },
+    /// Contains url for Qr code image, this qr code has to be shown in sdk
+    QrCodeInformation {
+        #[schema(value_type = String)]
+        image_data_url: Url,
+    },
 }
 
 #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, ToSchema)]
@@ -1242,6 +1253,11 @@ pub struct BankTransferNextStepsData {
     pub receiver: ReceiverDetails,
 }
 
+#[derive(Clone, Debug, serde::Deserialize)]
+pub struct QrCodeNextStepsInstruction {
+    pub image_data_url: Url,
+}
+
 #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, ToSchema)]
 #[serde(rename_all = "snake_case")]
 pub enum BankTransferInstructions {
diff --git a/crates/router/src/compatibility/stripe/payment_intents/types.rs b/crates/router/src/compatibility/stripe/payment_intents/types.rs
index 52e9219103e..d592904434c 100644
--- a/crates/router/src/compatibility/stripe/payment_intents/types.rs
+++ b/crates/router/src/compatibility/stripe/payment_intents/types.rs
@@ -687,6 +687,9 @@ pub enum StripeNextAction {
     ThirdPartySdkSessionToken {
         session_token: Option<payments::SessionToken>,
     },
+    QrCodeInformation {
+        image_data_url: url::Url,
+    },
 }
 
 pub(crate) fn into_stripe_next_action(
@@ -710,5 +713,8 @@ pub(crate) fn into_stripe_next_action(
         payments::NextActionData::ThirdPartySdkSessionToken { session_token } => {
             StripeNextAction::ThirdPartySdkSessionToken { session_token }
         }
+        payments::NextActionData::QrCodeInformation { image_data_url } => {
+            StripeNextAction::QrCodeInformation { image_data_url }
+        }
     })
 }
diff --git a/crates/router/src/compatibility/stripe/setup_intents/types.rs b/crates/router/src/compatibility/stripe/setup_intents/types.rs
index 0a013300aef..d4b6aac306b 100644
--- a/crates/router/src/compatibility/stripe/setup_intents/types.rs
+++ b/crates/router/src/compatibility/stripe/setup_intents/types.rs
@@ -345,6 +345,9 @@ pub enum StripeNextAction {
     ThirdPartySdkSessionToken {
         session_token: Option<payments::SessionToken>,
     },
+    QrCodeInformation {
+        image_data_url: url::Url,
+    },
 }
 
 pub(crate) fn into_stripe_next_action(
@@ -368,6 +371,9 @@ pub(crate) fn into_stripe_next_action(
         payments::NextActionData::ThirdPartySdkSessionToken { session_token } => {
             StripeNextAction::ThirdPartySdkSessionToken { session_token }
         }
+        payments::NextActionData::QrCodeInformation { image_data_url } => {
+            StripeNextAction::QrCodeInformation { image_data_url }
+        }
     })
 }
 
diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs
index 7a9c9ef4e27..acce44f4de4 100644
--- a/crates/router/src/connector/stripe/transformers.rs
+++ b/crates/router/src/connector/stripe/transformers.rs
@@ -1060,8 +1060,7 @@ fn create_stripe_payment_method(
                 StripePaymentMethodType::ApplePay,
                 StripeBillingAddress::default(),
             )),
-
-            payments::WalletData::WeChatPayRedirect(_) => Ok((
+            payments::WalletData::WeChatPay(_) => Ok((
                 StripePaymentMethodData::Wallet(StripeWallet::WechatpayPayment(WechatpayPayment {
                     client: WechatClient::Web,
                     payment_method_types: StripePaymentMethodType::Wechatpay,
@@ -1515,6 +1514,12 @@ pub struct SepaAndBacsBankTransferInstructions {
     pub receiver: SepaAndBacsReceiver,
 }
 
+#[serde_with::skip_serializing_none]
+#[derive(Clone, Debug, Serialize)]
+pub struct WechatPayNextInstructions {
+    pub image_data_url: Url,
+}
+
 #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
 pub struct SepaAndBacsReceiver {
     pub amount_received: i64,
@@ -1699,26 +1704,47 @@ pub fn get_connector_metadata(
     amount: i64,
 ) -> CustomResult<Option<serde_json::Value>, errors::ConnectorError> {
     let next_action_response = next_action
-            .and_then(|next_action_response| match next_action_response {
-                    StripeNextActionResponse::DisplayBankTransferInstructions(response) => {
-                        Some(SepaAndBacsBankTransferInstructions {
-                            sepa_bank_instructions: response.financial_addresses[0].iban.to_owned(),
-                            bacs_bank_instructions: response.financial_addresses[0]
-                                .sort_code
-                                .to_owned(),
-                            receiver: SepaAndBacsReceiver {
-                                amount_received: amount - response.amount_remaining,
-                                amount_remaining: response.amount_remaining,
-                            },
-                        })
-                    }
-                    _ => None,
-                }).map(|response| {
-                     common_utils::ext_traits::Encode::<SepaAndBacsBankTransferInstructions>::encode_to_value(
-                &response,
-            )
-            .change_context(errors::ConnectorError::ResponseHandlingFailed)
-                }).transpose()?;
+        .and_then(|next_action_response| match next_action_response {
+            StripeNextActionResponse::DisplayBankTransferInstructions(response) => {
+                let bank_instructions = response.financial_addresses.get(0);
+                let (sepa_bank_instructions, bacs_bank_instructions) =
+                    bank_instructions.map_or((None, None), |financial_address| {
+                        (
+                            financial_address.iban.to_owned(),
+                            financial_address.sort_code.to_owned(),
+                        )
+                    });
+
+                let bank_transfer_instructions = SepaAndBacsBankTransferInstructions {
+                    sepa_bank_instructions,
+                    bacs_bank_instructions,
+                    receiver: SepaAndBacsReceiver {
+                        amount_received: amount - response.amount_remaining,
+                        amount_remaining: response.amount_remaining,
+                    },
+                };
+
+                Some(common_utils::ext_traits::Encode::<
+                    SepaAndBacsBankTransferInstructions,
+                >::encode_to_value(
+                    &bank_transfer_instructions
+                ))
+            }
+            StripeNextActionResponse::WechatPayDisplayQrCode(response) => {
+                let wechat_pay_instructions = WechatPayNextInstructions {
+                    image_data_url: response.image_data_url.to_owned(),
+                };
+
+                Some(
+                    common_utils::ext_traits::Encode::<WechatPayNextInstructions>::encode_to_value(
+                        &wechat_pay_instructions,
+                    ),
+                )
+            }
+            _ => None,
+        })
+        .transpose()
+        .change_context(errors::ConnectorError::ResponseHandlingFailed)?;
     Ok(next_action_response)
 }
 
@@ -1848,7 +1874,7 @@ impl StripeNextActionResponse {
             Self::RedirectToUrl(redirect_to_url) | Self::AlipayHandleRedirect(redirect_to_url) => {
                 Some(redirect_to_url.url.to_owned())
             }
-            Self::WechatPayDisplayQrCode(redirect_to_url) => Some(redirect_to_url.data.to_owned()),
+            Self::WechatPayDisplayQrCode(_) => None,
             Self::VerifyWithMicrodeposits(verify_with_microdeposits) => {
                 Some(verify_with_microdeposits.hosted_verification_url.to_owned())
             }
@@ -1885,7 +1911,11 @@ pub struct StripeRedirectToUrlResponse {
 
 #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
 pub struct StripeRedirectToQr {
+    // This data contains url, it should be converted to QR code.
+    // Note: The url in this data is not redirection url
     data: Url,
+    // This is the image source, this image_data_url can directly be used by sdk to show the QR code
+    image_data_url: Url,
 }
 
 #[derive(Clone, Debug, Eq, PartialEq, Deserialize)]
diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs
index c5a25b993e5..384a2230389 100644
--- a/crates/router/src/core/payments.rs
+++ b/crates/router/src/core/payments.rs
@@ -431,7 +431,8 @@ impl PaymentRedirectFlow for PaymentRedirectCompleteAuthorize {
                     .and_then(|next_action_data| match next_action_data {
                         api_models::payments::NextActionData::RedirectToUrl { redirect_to_url } => Some(redirect_to_url),
                         api_models::payments::NextActionData::DisplayBankTransferInformation { .. } => None,
-                        api_models::payments::NextActionData::ThirdPartySdkSessionToken { .. } => None
+                        api_models::payments::NextActionData::ThirdPartySdkSessionToken { .. } => None,
+                        api_models::payments::NextActionData::QrCodeInformation{..} => None
                     })
                     .ok_or(errors::ApiErrorResponse::InternalServerError)
                     .into_report()
diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs
index 64cb0bc5e21..f807fc6c820 100644
--- a/crates/router/src/core/payments/transformers.rs
+++ b/crates/router/src/core/payments/transformers.rs
@@ -322,6 +322,9 @@ where
                 let bank_transfer_next_steps =
                     bank_transfer_next_steps_check(payment_attempt.clone())?;
 
+                let next_action_containing_qr_code =
+                    qr_code_next_steps_check(payment_attempt.clone())?;
+
                 if payment_intent.status == enums::IntentStatus::RequiresCustomerAction
                     || bank_transfer_next_steps.is_some()
                 {
@@ -331,6 +334,11 @@ where
                                 bank_transfer_steps_and_charges_details: bank_transfer,
                             }
                         })
+                        .or(next_action_containing_qr_code.map(|qr_code_data| {
+                            api_models::payments::NextActionData::QrCodeInformation {
+                                image_data_url: qr_code_data.image_data_url,
+                            }
+                        }))
                         .or(Some(api_models::payments::NextActionData::RedirectToUrl {
                             redirect_to_url: helpers::create_startpay_url(
                                 server,
@@ -554,6 +562,18 @@ where
     }
 }
 
+pub fn qr_code_next_steps_check(
+    payment_attempt: storage::PaymentAttempt,
+) -> RouterResult<Option<api_models::payments::QrCodeNextStepsInstruction>> {
+    let qr_code_steps: Option<Result<api_models::payments::QrCodeNextStepsInstruction, _>> =
+        payment_attempt
+            .connector_metadata
+            .map(|metadata| metadata.parse_value("QrCodeNextStepsInstruction"));
+
+    let qr_code_instructions = qr_code_steps.transpose().ok().flatten();
+    Ok(qr_code_instructions)
+}
+
 impl ForeignFrom<(storage::PaymentIntent, storage::PaymentAttempt)> for api::PaymentsResponse {
     fn foreign_from(item: (storage::PaymentIntent, storage::PaymentAttempt)) -> Self {
         let pi = item.0;
diff --git a/crates/router/src/openapi.rs b/crates/router/src/openapi.rs
index a53c57bc05e..9d1473be928 100644
--- a/crates/router/src/openapi.rs
+++ b/crates/router/src/openapi.rs
@@ -233,6 +233,7 @@ Never share your secret api keys. Keep them guarded and secure.
         api_models::payments::SdkNextAction,
         api_models::payments::NextActionCall,
         api_models::payments::SamsungPayWalletData,
+        api_models::payments::WeChatPay,
         api_models::payments::GpayTokenizationData,
         api_models::payments::GooglePayPaymentMethodInfo,
         api_models::payments::ApplePayWalletData,
diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json
index 53bc3c7c29a..650f6a4f5d9 100644
--- a/openapi/openapi_spec.json
+++ b/openapi/openapi_spec.json
@@ -5530,7 +5530,7 @@
           },
           {
             "type": "object",
-            "description": "contains third party sdk session token response",
+            "description": "Contains third party sdk session token response",
             "required": [
               "type"
             ],
@@ -5550,6 +5550,25 @@
                 ]
               }
             }
+          },
+          {
+            "type": "object",
+            "description": "Contains url for Qr code image, this qr code has to be shown in sdk",
+            "required": [
+              "image_data_url",
+              "type"
+            ],
+            "properties": {
+              "image_data_url": {
+                "type": "string"
+              },
+              "type": {
+                "type": "string",
+                "enum": [
+                  "qr_code_information"
+                ]
+              }
+            }
           }
         ],
         "discriminator": {
@@ -8548,9 +8567,23 @@
                 "$ref": "#/components/schemas/WeChatPayRedirection"
               }
             }
+          },
+          {
+            "type": "object",
+            "required": [
+              "we_chat_pay"
+            ],
+            "properties": {
+              "we_chat_pay": {
+                "$ref": "#/components/schemas/WeChatPay"
+              }
+            }
           }
         ]
       },
+      "WeChatPay": {
+        "type": "object"
+      },
       "WeChatPayRedirection": {
         "type": "object"
       },

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

- [x] New feature

## Description
<!-- Describe your changes in detail -->
Add support for WeChat Pay, we chat pay in stripe doesn't follow redirection.Qr code url is given in the next action, this qr code has to be shown in sdk.

API contract for WeChat Pay:
```
    "payment_method": "wallet",
    "payment_method_type": "we_chat_pay",
    "payment_method_data": {
        "wallet": {
            "we_chat_pay": {}
        }
    },
```

### Additional Changes

- [x] This PR modifies the API contract

<!--
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 its an obvious bug or documentation fix
that will have little conversation).
-->
Add support for WeChat Pay payment method

## 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)?
-->
Manual

Qr code url in next action
<img width="1264" alt="Screen Shot 2023-06-27 at 6 16 14 PM" src="https://github.com/juspay/hyperswitch/assets/59434228/eef065bd-f0ef-47b4-899d-89c42545a52c">

Qr code
<img width="1545" alt="Screen Shot 2023-06-27 at 6 15 53 PM" src="https://github.com/juspay/hyperswitch/assets/59434228/9c084396-8220-430e-a2e8-b2844c09416d">



## 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 submitted code
