Bug: feat(connector): add support for affirm and afterpay/clearpay through stripe



### Feature Description

Add support for creating payments through affirm and afterpay/clearpay through stripe. The api contract changes will be as follows
- afterpay/clearpay
```json
{
  "payment_method": "pay_later",
  "payment_method_data": {
    "issuer_name": "afterpay_clearpay",
    "afterpay_clearpay_redirect": {
      "billing_email_address": "abc@gmail.com"
    }
  }
}
```
- affirm
```json
{
  "payment_method": "pay_later",
  "payment_method_data": {
    "issuer_name": "affirm",
    "affirm_redirect": {
      "billing_email_address": "abc@gmail.com"
    }
  }
}
```

### Possible Implementation

Modify the payments request of stripe to include affirm and afterpay

### Have you spent some time to check if this feature request has been raised before?

- [X] I checked and didn't find similar issue

### Have you read the Contributing Guidelines?

- [X] I have read the [Contributing Guidelines](https://github.com/juspay/hyperswitch/blob/main/contrib/CONTRIBUTING.md)

### Are you willing to submit a PR?

Yes I am willing to submit a PR!

- [X] Support for affirm #355 
- [ ] Support for afterpay_clearpay
diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs
index ddbf7325fd6..fc761d2851d 100644
--- a/crates/api_models/src/payments.rs
+++ b/crates/api_models/src/payments.rs
@@ -321,14 +321,20 @@ pub struct CCard {
 
 #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
 #[serde(rename_all = "snake_case")]
-pub enum KlarnaRedirectIssuer {
-    Stripe,
+pub enum KlarnaIssuer {
+    Klarna,
 }
 
 #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
 #[serde(rename_all = "snake_case")]
-pub enum KlarnaSdkIssuer {
-    Klarna,
+pub enum AffirmIssuer {
+    Affirm,
+}
+
+#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
+#[serde(rename_all = "snake_case")]
+pub enum AfterpayClearpayIssuer {
+    AfterpayClearpay,
 }
 
 #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
@@ -337,7 +343,7 @@ pub enum PayLaterData {
     /// For KlarnaRedirect as PayLater Option
     KlarnaRedirect {
         /// The issuer name of the redirect
-        issuer_name: KlarnaRedirectIssuer,
+        issuer_name: KlarnaIssuer,
         /// The billing email
         billing_email: String,
         // The billing country code
@@ -345,15 +351,26 @@ pub enum PayLaterData {
     },
     /// For Klarna Sdk as PayLater Option
     KlarnaSdk {
-        /// The issuer name of the redirect
-        issuer_name: KlarnaSdkIssuer,
+        /// The issuer name of the sdk
+        issuer_name: KlarnaIssuer,
         /// The token for the sdk workflow
         token: String,
     },
-    /// For Affirm redirect flow
+    /// For Affirm redirect as PayLater Option
     AffirmRedirect {
-        /// The billing email address
+        /// The issuer name of affirm redirect issuer
+        issuer_name: AffirmIssuer,
+        /// The billing email
+        billing_email: String,
+    },
+    /// For AfterpayClearpay redirect as PayLater Option
+    AfterpayClearpayRedirect {
+        /// The issuer name of afterpayclearpay redirect issuer
+        issuer_name: AfterpayClearpayIssuer,
+        /// The billing email
         billing_email: String,
+        /// The billing name
+        billing_name: String,
     },
 }
 
diff --git a/crates/router/src/connector/stripe.rs b/crates/router/src/connector/stripe.rs
index b98fd22d8c4..d6841c257cf 100644
--- a/crates/router/src/connector/stripe.rs
+++ b/crates/router/src/connector/stripe.rs
@@ -344,7 +344,8 @@ impl
         &self,
         req: &types::PaymentsAuthorizeRouterData,
     ) -> CustomResult<Option<String>, errors::ConnectorError> {
-        let stripe_req = utils::Encode::<stripe::PaymentIntentRequest>::convert_and_url_encode(req)
+        let req = stripe::PaymentIntentRequest::try_from(req)?;
+        let stripe_req = utils::Encode::<stripe::PaymentIntentRequest>::encode(&req)
             .change_context(errors::ConnectorError::RequestEncodingFailed)?;
         Ok(Some(stripe_req))
     }
diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs
index 2d7ef4a24c6..2f18b3fd29a 100644
--- a/crates/router/src/connector/stripe/transformers.rs
+++ b/crates/router/src/connector/stripe/transformers.rs
@@ -1,6 +1,9 @@
 use std::str::FromStr;
 
+use api_models::{self, payments};
+use common_utils::fp_utils;
 use error_stack::{IntoReport, ResultExt};
+use masking::ExposeInterface;
 use serde::{Deserialize, Serialize};
 use strum::EnumString;
 use url::Url;
@@ -81,7 +84,7 @@ pub struct PaymentIntentRequest {
     pub mandate: Option<String>,
     pub description: Option<String>,
     #[serde(flatten)]
-    pub shipping: Address,
+    pub shipping: StripeShippingAddress,
     #[serde(flatten)]
     pub payment_data: Option<StripePaymentMethodData>,
     pub capture_method: StripeCaptureMethod,
@@ -129,6 +132,8 @@ pub struct StripePayLaterData {
     pub billing_email: String,
     #[serde(rename = "payment_method_data[billing_details][address][country]")]
     pub billing_country: Option<String>,
+    #[serde(rename = "payment_method_data[billing_details][name]")]
+    pub billing_name: Option<String>,
 }
 
 #[derive(Debug, Eq, PartialEq, Serialize)]
@@ -137,6 +142,7 @@ pub enum StripePaymentMethodData {
     Card(StripeCardData),
     Klarna(StripePayLaterData),
     Affirm(StripePayLaterData),
+    AfterpayClearpay(StripePayLaterData),
     Bank,
     Wallet,
     Paypal,
@@ -148,10 +154,46 @@ pub enum StripePaymentMethodType {
     Card,
     Klarna,
     Affirm,
+    AfterpayClearpay,
+}
+
+fn validate_shipping_address_against_payment_method(
+    shipping_address: &StripeShippingAddress,
+    payment_method: &payments::PaymentMethod,
+) -> Result<(), errors::ConnectorError> {
+    if let payments::PaymentMethod::PayLater(payments::PayLaterData::AfterpayClearpayRedirect {
+        ..
+    }) = payment_method
+    {
+        fp_utils::when(shipping_address.name.is_none(), || {
+            Err(errors::ConnectorError::MissingRequiredField {
+                field_name: "shipping.first_name".to_string(),
+            })
+        })?;
+
+        fp_utils::when(shipping_address.line1.is_none(), || {
+            Err(errors::ConnectorError::MissingRequiredField {
+                field_name: "shipping.line1".to_string(),
+            })
+        })?;
+
+        fp_utils::when(shipping_address.country.is_none(), || {
+            Err(errors::ConnectorError::MissingRequiredField {
+                field_name: "shipping.country".to_string(),
+            })
+        })?;
+
+        fp_utils::when(shipping_address.zip.is_none(), || {
+            Err(errors::ConnectorError::MissingRequiredField {
+                field_name: "shipping.zip".to_string(),
+            })
+        })?;
+    }
+    Ok(())
 }
 
 impl TryFrom<&types::PaymentsAuthorizeRouterData> for PaymentIntentRequest {
-    type Error = error_stack::Report<errors::ConnectorError>;
+    type Error = errors::ConnectorError;
     fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result<Self, Self::Error> {
         let metadata_order_id = item.payment_id.to_string();
         let metadata_txn_id = format!("{}_{}_{}", item.merchant_id, item.payment_id, "1");
@@ -166,71 +208,32 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PaymentIntentRequest {
                 .clone()
                 .and_then(|mandate_ids| mandate_ids.connector_mandate_id)
             {
-                None => (
-                    Some(match item.request.payment_method_data {
-                        api::PaymentMethod::Card(ref ccard) => StripePaymentMethodData::Card({
-                            let payment_method_auth_type = match item.auth_type {
-                                enums::AuthenticationType::ThreeDs => Auth3ds::Any,
-                                enums::AuthenticationType::NoThreeDs => Auth3ds::Automatic,
-                            };
-                            StripeCardData {
-                                payment_method_types: StripePaymentMethodType::Card,
-                                payment_method_data_type: StripePaymentMethodType::Card,
-                                payment_method_data_card_number: ccard.card_number.clone(),
-                                payment_method_data_card_exp_month: ccard.card_exp_month.clone(),
-                                payment_method_data_card_exp_year: ccard.card_exp_year.clone(),
-                                payment_method_data_card_cvc: ccard.card_cvc.clone(),
-                                payment_method_auth_type,
-                            }
-                        }),
-                        api::PaymentMethod::BankTransfer => StripePaymentMethodData::Bank,
-                        api::PaymentMethod::PayLater(ref pay_later_data) => match pay_later_data {
-                            api_models::payments::PayLaterData::KlarnaRedirect {
-                                billing_email,
-                                billing_country,
-                                ..
-                            } => StripePaymentMethodData::Klarna(StripePayLaterData {
-                                payment_method_types: StripePaymentMethodType::Klarna,
-                                payment_method_data_type: StripePaymentMethodType::Klarna,
-                                billing_email: billing_email.to_string(),
-                                billing_country: Some(billing_country.to_string()),
-                            }),
-                            api_models::payments::PayLaterData::AffirmRedirect {
-                                billing_email,
-                            } => StripePaymentMethodData::Affirm(StripePayLaterData {
-                                payment_method_types: StripePaymentMethodType::Affirm,
-                                payment_method_data_type: StripePaymentMethodType::Affirm,
-                                billing_email: billing_email.to_string(),
-                                billing_country: None,
-                            }),
-                            _ => Err(error_stack::report!(
-                                errors::ConnectorError::NotImplemented(String::from("Stripe does not support payment through provided payment method"))
-                            ))?,
-                        },
-                        api::PaymentMethod::Wallet(_) => StripePaymentMethodData::Wallet,
-                        api::PaymentMethod::Paypal => StripePaymentMethodData::Paypal,
-                    }),
-                    None,
-                ),
+                None => {
+                    let payment_method: StripePaymentMethodData =
+                        (item.request.payment_method_data.clone(), item.auth_type).try_into()?;
+                    (Some(payment_method), None)
+                }
                 Some(mandate_id) => (None, Some(mandate_id)),
             }
         };
 
         let shipping_address = match item.address.shipping.clone() {
-            Some(mut shipping) => Address {
+            Some(mut shipping) => StripeShippingAddress {
                 city: shipping.address.as_mut().and_then(|a| a.city.take()),
                 country: shipping.address.as_mut().and_then(|a| a.country.take()),
                 line1: shipping.address.as_mut().and_then(|a| a.line1.take()),
                 line2: shipping.address.as_mut().and_then(|a| a.line2.take()),
-                postal_code: shipping.address.as_mut().and_then(|a| a.zip.take()),
+                zip: shipping.address.as_mut().and_then(|a| a.zip.take()),
                 state: shipping.address.as_mut().and_then(|a| a.state.take()),
-                name: shipping.address.as_mut().map(|a| {
-                    format!(
-                        "{} {}",
-                        a.first_name.clone().expose_option().unwrap_or_default(),
-                        a.last_name.clone().expose_option().unwrap_or_default()
-                    )
-                    .into()
+                name: shipping.address.as_mut().and_then(|a| {
+                    a.first_name.as_ref().map(|first_name| {
+                        format!(
+                            "{} {}",
+                            first_name.clone().expose(),
+                            a.last_name.clone().expose_option().unwrap_or_default()
+                        )
+                        .into()
+                    })
                 }),
                 phone: shipping.phone.map(|p| {
                     format!(
@@ -241,9 +244,14 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PaymentIntentRequest {
                     .into()
                 }),
             },
-            None => Address::default(),
+            None => StripeShippingAddress::default(),
         };
 
+        validate_shipping_address_against_payment_method(
+            &shipping_address,
+            &item.request.payment_method_data,
+        )?;
+
         let off_session = item
             .request
             .off_session
@@ -402,6 +410,7 @@ impl<F, T>
                     } => mandate_options.map(|mandate_options| mandate_options.reference),
                     StripePaymentMethodOptions::Klarna {} => None,
                     StripePaymentMethodOptions::Affirm {} => None,
+                    StripePaymentMethodOptions::AfterpayClearpay {} => None,
                 });
 
         Ok(Self {
@@ -457,6 +466,7 @@ impl<F, T>
                     } => mandate_options.map(|mandate_option| mandate_option.reference),
                     StripePaymentMethodOptions::Klarna {} => None,
                     StripePaymentMethodOptions::Affirm {} => None,
+                    StripePaymentMethodOptions::AfterpayClearpay {} => None,
                 });
 
         Ok(Self {
@@ -620,7 +630,7 @@ pub struct ErrorResponse {
 }
 
 #[derive(Debug, Default, Eq, PartialEq, Serialize)]
-pub struct Address {
+pub struct StripeShippingAddress {
     #[serde(rename = "shipping[address][city]")]
     pub city: Option<String>,
     #[serde(rename = "shipping[address][country]")]
@@ -630,7 +640,7 @@ pub struct Address {
     #[serde(rename = "shipping[address][line2]")]
     pub line2: Option<Secret<String>>,
     #[serde(rename = "shipping[address][postal_code]")]
-    pub postal_code: Option<Secret<String>>,
+    pub zip: Option<Secret<String>>,
     #[serde(rename = "shipping[address][state]")]
     pub state: Option<Secret<String>>,
     #[serde(rename = "shipping[name]")]
@@ -690,6 +700,7 @@ pub enum StripePaymentMethodOptions {
     },
     Klarna {},
     Affirm {},
+    AfterpayClearpay {},
 }
 // #[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
 // pub struct Card
@@ -782,7 +793,7 @@ pub struct StripeWebhookObjectId {
 }
 
 impl TryFrom<(api::PaymentMethod, enums::AuthenticationType)> for StripePaymentMethodData {
-    type Error = error_stack::Report<errors::ConnectorError>;
+    type Error = errors::ConnectorError;
     fn try_from(
         (pm_data, auth_type): (api::PaymentMethod, enums::AuthenticationType),
     ) -> Result<Self, Self::Error> {
@@ -813,12 +824,31 @@ impl TryFrom<(api::PaymentMethod, enums::AuthenticationType)> for StripePaymentM
                     payment_method_data_type: StripePaymentMethodType::Klarna,
                     billing_email,
                     billing_country: Some(billing_country),
+                    billing_name: None,
+                })),
+                api_models::payments::PayLaterData::AffirmRedirect { billing_email, .. } => {
+                    Ok(Self::Affirm(StripePayLaterData {
+                        payment_method_types: StripePaymentMethodType::Affirm,
+                        payment_method_data_type: StripePaymentMethodType::Affirm,
+                        billing_email,
+                        billing_country: None,
+                        billing_name: None,
+                    }))
+                }
+                api_models::payments::PayLaterData::AfterpayClearpayRedirect {
+                    billing_email,
+                    billing_name,
+                    ..
+                } => Ok(Self::AfterpayClearpay(StripePayLaterData {
+                    payment_method_types: StripePaymentMethodType::AfterpayClearpay,
+                    payment_method_data_type: StripePaymentMethodType::AfterpayClearpay,
+                    billing_email,
+                    billing_country: None,
+                    billing_name: Some(billing_name),
                 })),
-                _ => Err(error_stack::report!(
-                    errors::ConnectorError::NotImplemented(String::from(
-                        "Stripe does not support payment through provided payment method"
-                    ))
-                )),
+                _ => Err(errors::ConnectorError::NotImplemented(String::from(
+                    "Stripe does not support payment through provided payment method",
+                ))),
             },
             api::PaymentMethod::Wallet(_) => Ok(Self::Wallet),
             api::PaymentMethod::Paypal => Ok(Self::Paypal),
diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs
index b2c7dffd3c3..450572adaa8 100644
--- a/crates/router/src/core/payments/operations/payment_create.rs
+++ b/crates/router/src/core/payments/operations/payment_create.rs
@@ -2,7 +2,7 @@ use std::marker::PhantomData;
 
 use async_trait::async_trait;
 use common_utils::ext_traits::{AsyncExt, Encode};
-use error_stack::ResultExt;
+use error_stack::{self, ResultExt};
 use router_derive::PaymentOperation;
 use router_env::{instrument, tracing};
 use uuid::Uuid;
diff --git a/crates/router/src/openapi.rs b/crates/router/src/openapi.rs
index 3c8a7d857b3..cd3329c526b 100644
--- a/crates/router/src/openapi.rs
+++ b/crates/router/src/openapi.rs
@@ -25,7 +25,7 @@ Use the following base URLs when making requests to the APIs:
 
 | Environment   |  Base URL                                            |
 |---------------|------------------------------------------------------|
-| Sandbox       | <https://sandbox.hyperswitch.io>                   |
+| Sandbox       | <https://sandbox.hyperswitch.io>                     |
 | Production    | <https://router.juspay.io>                           |
 
 ## Authentication
@@ -80,8 +80,9 @@ Never share your secret api keys. Keep them guarded and secure.
         api_models::payments::NextActionType,
         api_models::payments::Metadata,
         api_models::payments::WalletData,
-        api_models::payments::KlarnaRedirectIssuer,
-        api_models::payments::KlarnaSdkIssuer,
+        api_models::payments::KlarnaIssuer,
+        api_models::payments::AffirmIssuer,
+        api_models::payments::AfterpayClearpayIssuer,
         api_models::payments::NextAction,
         api_models::payments::PayLaterData,
         api_models::payments::MandateData,
diff --git a/openapi/generated.json b/openapi/generated.json
index 4dce27f50d3..5c30411af97 100644
--- a/openapi/generated.json
+++ b/openapi/generated.json
@@ -203,6 +203,14 @@
           }
         }
       },
+      "AffirmIssuer": {
+        "type": "string",
+        "enum": ["affirm"]
+      },
+      "AfterpayClearpayIssuer": {
+        "type": "string",
+        "enum": ["afterpay_clearpay"]
+      },
       "AuthenticationType": {
         "type": "string",
         "enum": ["three_ds", "no_three_ds"]
@@ -778,11 +786,7 @@
           "requires_capture"
         ]
       },
-      "KlarnaRedirectIssuer": {
-        "type": "string",
-        "enum": ["stripe"]
-      },
-      "KlarnaSdkIssuer": {
+      "KlarnaIssuer": {
         "type": "string",
         "enum": ["klarna"]
       },
@@ -1071,7 +1075,7 @@
                 "required": ["issuer_name", "billing_email", "billing_country"],
                 "properties": {
                   "issuer_name": {
-                    "$ref": "#/components/schemas/KlarnaRedirectIssuer"
+                    "$ref": "#/components/schemas/KlarnaIssuer"
                   },
                   "billing_email": {
                     "type": "string",
@@ -1094,7 +1098,7 @@
                 "required": ["issuer_name", "token"],
                 "properties": {
                   "issuer_name": {
-                    "$ref": "#/components/schemas/KlarnaSdkIssuer"
+                    "$ref": "#/components/schemas/KlarnaIssuer"
                   },
                   "token": {
                     "type": "string",
@@ -1110,12 +1114,39 @@
             "properties": {
               "affirm_redirect": {
                 "type": "object",
-                "description": "For Affirm redirect flow",
-                "required": ["billing_email"],
+                "description": "For Affirm redirect as PayLater Option",
+                "required": ["issuer_name", "billing_email"],
                 "properties": {
+                  "issuer_name": {
+                    "$ref": "#/components/schemas/AffirmIssuer"
+                  },
                   "billing_email": {
                     "type": "string",
-                    "description": "The billing email address"
+                    "description": "The billing email"
+                  }
+                }
+              }
+            }
+          },
+          {
+            "type": "object",
+            "required": ["afterpay_clearpay_redirect"],
+            "properties": {
+              "afterpay_clearpay_redirect": {
+                "type": "object",
+                "description": "For AfterpayClearpay redirect as PayLater Option",
+                "required": ["issuer_name", "billing_email", "billing_name"],
+                "properties": {
+                  "issuer_name": {
+                    "$ref": "#/components/schemas/AfterpayClearpayIssuer"
+                  },
+                  "billing_email": {
+                    "type": "string",
+                    "description": "The billing email"
+                  },
+                  "billing_name": {
+                    "type": "string",
+                    "description": "The billing name"
                   }
                 }
               }
@@ -2036,6 +2067,9 @@
           "error_message": {
             "type": "string"
           },
+          "error_code": {
+            "type": "string"
+          },
           "created_at": {
             "type": "string",
             "format": "date-time"

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

- [x] New feature

## Description
<!-- Describe your changes in detail -->
This PR will support creating pay_later payments using `afterpay_clearpay` as the issuer through stripe. This is a redirection flow.

## 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).
-->
#347 


## 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 payment with `payment_method_data` as `pay_later` and body as 
```json
{
  "payment_method_data": {
    "pay_later": {
      "afterpay_clearpay_redirect": {
        "issuer_name": "afterpay_clearpay",
        "billing_email": "example@juspay.in",
        "billing_name": "Juspay"
      }
    }
  }
}
```
![Screenshot 2023-01-20 at 11 23 29 PM](https://user-images.githubusercontent.com/48803246/213772167-0614cec9-a566-4275-9220-c55ae414e92f.png)
- Complete the redirection
![Screenshot 2023-01-20 at 11 23 42 PM](https://user-images.githubusercontent.com/48803246/213772205-d512148a-c259-494d-bdba-514c8b2dcb99.png)
- Redirection status is succeeced
![Screenshot 2023-01-20 at 11 23 57 PM](https://user-images.githubusercontent.com/48803246/213772256-a4faa66a-655f-4f2c-9d97-b4835bc770a0.png)


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