Bug: [FEATURE] [AUTHORIZEDOTNET] Implement non-zero mandates



### Feature Description

Non-zero dollar mandates need to be implemented for connector Authorizedotnet.

### Possible Implementation

Non-zero dollar mandates need to be implemented for connector Authorizedotnet.

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

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

### Have you read the Contributing Guidelines?

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

### Are you willing to submit a PR?

Yes, I am willing to submit a PR!
diff --git a/crates/router/src/connector/authorizedotnet.rs b/crates/router/src/connector/authorizedotnet.rs
index a9e000b82b9..8d0c1db37a2 100644
--- a/crates/router/src/connector/authorizedotnet.rs
+++ b/crates/router/src/connector/authorizedotnet.rs
@@ -79,6 +79,16 @@ impl ConnectorValidation for Authorizedotnet {
             ),
         }
     }
+
+    fn validate_mandate_payment(
+        &self,
+        pm_type: Option<types::storage::enums::PaymentMethodType>,
+        pm_data: types::domain::payments::PaymentMethodData,
+    ) -> CustomResult<(), errors::ConnectorError> {
+        let mandate_supported_pmd =
+            std::collections::HashSet::from([crate::connector::utils::PaymentMethodDataType::Card]);
+        connector_utils::is_mandate_supported(pm_data, pm_type, mandate_supported_pmd, self.id())
+    }
 }
 
 impl api::Payment for Authorizedotnet {}
diff --git a/crates/router/src/connector/authorizedotnet/transformers.rs b/crates/router/src/connector/authorizedotnet/transformers.rs
index 3e4d0a382e6..de68438edc4 100644
--- a/crates/router/src/connector/authorizedotnet/transformers.rs
+++ b/crates/router/src/connector/authorizedotnet/transformers.rs
@@ -133,20 +133,36 @@ pub enum WalletMethod {
 struct TransactionRequest {
     transaction_type: TransactionType,
     amount: f64,
-    currency_code: String,
-    #[serde(skip_serializing_if = "Option::is_none")]
-    profile: Option<CustomerProfileDetails>,
+    currency_code: common_enums::Currency,
     #[serde(skip_serializing_if = "Option::is_none")]
     payment: Option<PaymentDetails>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    profile: Option<ProfileDetails>,
     order: Order,
     #[serde(skip_serializing_if = "Option::is_none")]
+    customer: Option<CustomerDetails>,
+    #[serde(skip_serializing_if = "Option::is_none")]
     bill_to: Option<BillTo>,
+    #[serde(skip_serializing_if = "Option::is_none")]
     processing_options: Option<ProcessingOptions>,
     #[serde(skip_serializing_if = "Option::is_none")]
     subsequent_auth_information: Option<SubsequentAuthInformation>,
     authorization_indicator_type: Option<AuthorizationIndicator>,
 }
 
+#[derive(Serialize, Deserialize, Debug)]
+#[serde(untagged)]
+enum ProfileDetails {
+    CreateProfileDetails(CreateProfileDetails),
+    CustomerProfileDetails(CustomerProfileDetails),
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+pub struct CreateProfileDetails {
+    create_profile: bool,
+}
+
 #[derive(Serialize, Deserialize, Debug)]
 #[serde(rename_all = "camelCase")]
 struct CustomerProfileDetails {
@@ -160,6 +176,12 @@ struct PaymentProfileDetails {
     payment_profile_id: Secret<String>,
 }
 
+#[derive(Debug, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct CustomerDetails {
+    id: String,
+}
+
 #[derive(Debug, Serialize)]
 #[serde(rename_all = "camelCase")]
 pub struct ProcessingOptions {
@@ -461,37 +483,37 @@ impl TryFrom<&AuthorizedotnetRouterData<&types::PaymentsAuthorizeRouterData>>
     fn try_from(
         item: &AuthorizedotnetRouterData<&types::PaymentsAuthorizeRouterData>,
     ) -> Result<Self, Self::Error> {
-        let (payment_details, processing_options, subsequent_auth_information, profile) = match item
+        let merchant_authentication =
+            AuthorizedotnetAuthType::try_from(&item.router_data.connector_auth_type)?;
+
+        let ref_id = if item.router_data.connector_request_reference_id.len() <= 20 {
+            Some(item.router_data.connector_request_reference_id.clone())
+        } else {
+            None
+        };
+
+        let transaction_request = match item
             .router_data
             .request
             .mandate_id
-            .to_owned()
+            .clone()
             .and_then(|mandate_ids| mandate_ids.mandate_reference_id)
         {
             Some(api_models::payments::MandateReferenceId::NetworkMandateId(network_trans_id)) => {
-                let processing_options = Some(ProcessingOptions {
-                    is_subsequent_auth: true,
-                });
-                let subsequent_auth_info = Some(SubsequentAuthInformation {
-                    original_network_trans_id: Secret::new(network_trans_id),
-                    reason: Reason::Resubmission,
-                });
-                match item.router_data.request.payment_method_data {
-                    domain::PaymentMethodData::Card(ref ccard) => {
-                        let payment_details = PaymentDetails::CreditCard(CreditCardDetails {
-                            card_number: (*ccard.card_number).clone(),
-                            expiration_date: ccard.get_expiry_date_as_yyyymm("-"),
-                            card_code: None,
-                        });
-                        (
-                            Some(payment_details),
-                            processing_options,
-                            subsequent_auth_info,
-                            None,
-                        )
+                TransactionRequest::try_from((item, network_trans_id))?
+            }
+            Some(api_models::payments::MandateReferenceId::ConnectorMandateId(
+                connector_mandate_id,
+            )) => TransactionRequest::try_from((item, connector_mandate_id))?,
+            None => {
+                match &item.router_data.request.payment_method_data {
+                    domain::PaymentMethodData::Card(ccard) => {
+                        TransactionRequest::try_from((item, ccard))
+                    }
+                    domain::PaymentMethodData::Wallet(wallet_data) => {
+                        TransactionRequest::try_from((item, wallet_data))
                     }
                     domain::PaymentMethodData::CardRedirect(_)
-                    | domain::PaymentMethodData::Wallet(_)
                     | domain::PaymentMethodData::PayLater(_)
                     | domain::PaymentMethodData::BankRedirect(_)
                     | domain::PaymentMethodData::BankDebit(_)
@@ -510,16 +532,116 @@ impl TryFrom<&AuthorizedotnetRouterData<&types::PaymentsAuthorizeRouterData>>
                         ))?
                     }
                 }
-            }
-            Some(api_models::payments::MandateReferenceId::ConnectorMandateId(
-                connector_mandate_id,
-            )) => (
-                None,
-                Some(ProcessingOptions {
-                    is_subsequent_auth: true,
+            }?,
+        };
+        Ok(Self {
+            create_transaction_request: AuthorizedotnetPaymentsRequest {
+                merchant_authentication,
+                ref_id,
+                transaction_request,
+            },
+        })
+    }
+}
+
+impl
+    TryFrom<(
+        &AuthorizedotnetRouterData<&types::PaymentsAuthorizeRouterData>,
+        String,
+    )> for TransactionRequest
+{
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(
+        (item, network_trans_id): (
+            &AuthorizedotnetRouterData<&types::PaymentsAuthorizeRouterData>,
+            String,
+        ),
+    ) -> Result<Self, Self::Error> {
+        Ok(Self {
+            transaction_type: TransactionType::try_from(item.router_data.request.capture_method)?,
+            amount: item.amount,
+            currency_code: item.router_data.request.currency,
+            payment: Some(match item.router_data.request.payment_method_data {
+                domain::PaymentMethodData::Card(ref ccard) => {
+                    PaymentDetails::CreditCard(CreditCardDetails {
+                        card_number: (*ccard.card_number).clone(),
+                        expiration_date: ccard.get_expiry_date_as_yyyymm("-"),
+                        card_code: None,
+                    })
+                }
+                domain::PaymentMethodData::CardRedirect(_)
+                | domain::PaymentMethodData::Wallet(_)
+                | domain::PaymentMethodData::PayLater(_)
+                | domain::PaymentMethodData::BankRedirect(_)
+                | domain::PaymentMethodData::BankDebit(_)
+                | domain::PaymentMethodData::BankTransfer(_)
+                | domain::PaymentMethodData::Crypto(_)
+                | domain::PaymentMethodData::MandatePayment
+                | domain::PaymentMethodData::Reward
+                | domain::PaymentMethodData::Upi(_)
+                | domain::PaymentMethodData::Voucher(_)
+                | domain::PaymentMethodData::GiftCard(_)
+                | domain::PaymentMethodData::CardToken(_) => {
+                    Err(errors::ConnectorError::NotImplemented(
+                        utils::get_unimplemented_payment_method_error_message("authorizedotnet"),
+                    ))?
+                }
+            }),
+            profile: None,
+            order: Order {
+                description: item.router_data.connector_request_reference_id.clone(),
+            },
+            customer: None,
+            bill_to: item
+                .router_data
+                .get_optional_billing()
+                .and_then(|billing_address| billing_address.address.as_ref())
+                .map(|address| BillTo {
+                    first_name: address.first_name.clone(),
+                    last_name: address.last_name.clone(),
+                    address: address.line1.clone(),
+                    city: address.city.clone(),
+                    state: address.state.clone(),
+                    zip: address.zip.clone(),
+                    country: address.country,
+                }),
+            processing_options: Some(ProcessingOptions {
+                is_subsequent_auth: true,
+            }),
+            subsequent_auth_information: Some(SubsequentAuthInformation {
+                original_network_trans_id: Secret::new(network_trans_id),
+                reason: Reason::Resubmission,
+            }),
+            authorization_indicator_type: match item.router_data.request.capture_method {
+                Some(capture_method) => Some(AuthorizationIndicator {
+                    authorization_indicator: capture_method.try_into()?,
                 }),
-                None,
-                Some(CustomerProfileDetails {
+                None => None,
+            },
+        })
+    }
+}
+
+impl
+    TryFrom<(
+        &AuthorizedotnetRouterData<&types::PaymentsAuthorizeRouterData>,
+        api_models::payments::ConnectorMandateReferenceId,
+    )> for TransactionRequest
+{
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(
+        (item, connector_mandate_id): (
+            &AuthorizedotnetRouterData<&types::PaymentsAuthorizeRouterData>,
+            api_models::payments::ConnectorMandateReferenceId,
+        ),
+    ) -> Result<Self, Self::Error> {
+        Ok(Self {
+            transaction_type: TransactionType::try_from(item.router_data.request.capture_method)?,
+            amount: item.amount,
+            currency_code: item.router_data.request.currency,
+            payment: None,
+            profile: Some(ProfileDetails::CustomerProfileDetails(
+                CustomerProfileDetails {
                     customer_profile_id: Secret::from(
                         connector_mandate_id
                             .connector_mandate_id
@@ -532,64 +654,86 @@ impl TryFrom<&AuthorizedotnetRouterData<&types::PaymentsAuthorizeRouterData>>
                                 .ok_or(errors::ConnectorError::MissingConnectorMandateID)?,
                         ),
                     },
-                }),
-            ),
-            None => {
-                match item.router_data.request.payment_method_data {
-                    domain::PaymentMethodData::Card(ref ccard) => {
-                        (
-                            Some(PaymentDetails::CreditCard(CreditCardDetails {
-                                card_number: (*ccard.card_number).clone(),
-                                // expiration_date: format!("{expiry_year}-{expiry_month}").into(),
-                                expiration_date: ccard.get_expiry_date_as_yyyymm("-"),
-                                card_code: Some(ccard.card_cvc.clone()),
-                            })),
-                            Some(ProcessingOptions {
-                                is_subsequent_auth: true,
-                            }),
-                            None,
-                            None,
-                        )
-                    }
-                    domain::PaymentMethodData::Wallet(ref wallet_data) => (
-                        Some(get_wallet_data(
-                            wallet_data,
-                            &item.router_data.request.complete_authorize_url,
-                        )?),
-                        None,
-                        None,
-                        None,
-                    ),
-                    domain::PaymentMethodData::CardRedirect(_)
-                    | domain::PaymentMethodData::PayLater(_)
-                    | domain::PaymentMethodData::BankRedirect(_)
-                    | domain::PaymentMethodData::BankDebit(_)
-                    | domain::PaymentMethodData::BankTransfer(_)
-                    | domain::PaymentMethodData::Crypto(_)
-                    | domain::PaymentMethodData::MandatePayment
-                    | domain::PaymentMethodData::Reward
-                    | domain::PaymentMethodData::Upi(_)
-                    | domain::PaymentMethodData::Voucher(_)
-                    | domain::PaymentMethodData::GiftCard(_)
-                    | domain::PaymentMethodData::CardToken(_) => {
-                        Err(errors::ConnectorError::NotImplemented(
-                            utils::get_unimplemented_payment_method_error_message(
-                                "authorizedotnet",
-                            ),
-                        ))?
-                    }
-                }
-            }
-        };
-        let authorization_indicator_type = match item.router_data.request.capture_method {
-            Some(capture_method) => Some(AuthorizationIndicator {
-                authorization_indicator: capture_method.try_into()?,
+                },
+            )),
+            order: Order {
+                description: item.router_data.connector_request_reference_id.clone(),
+            },
+            customer: None,
+            bill_to: None,
+            processing_options: Some(ProcessingOptions {
+                is_subsequent_auth: true,
             }),
-            None => None,
+            subsequent_auth_information: None,
+            authorization_indicator_type: match item.router_data.request.capture_method {
+                Some(capture_method) => Some(AuthorizationIndicator {
+                    authorization_indicator: capture_method.try_into()?,
+                }),
+                None => None,
+            },
+        })
+    }
+}
+
+impl
+    TryFrom<(
+        &AuthorizedotnetRouterData<&types::PaymentsAuthorizeRouterData>,
+        &domain::Card,
+    )> for TransactionRequest
+{
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(
+        (item, ccard): (
+            &AuthorizedotnetRouterData<&types::PaymentsAuthorizeRouterData>,
+            &domain::Card,
+        ),
+    ) -> Result<Self, Self::Error> {
+        let (profile, customer) = if item
+            .router_data
+            .request
+            .setup_future_usage
+            .map_or(false, |future_usage| {
+                matches!(future_usage, common_enums::FutureUsage::OffSession)
+            })
+            && (item.router_data.request.customer_acceptance.is_some()
+                || item
+                    .router_data
+                    .request
+                    .setup_mandate_details
+                    .clone()
+                    .map_or(false, |mandate_details| {
+                        mandate_details.customer_acceptance.is_some()
+                    })) {
+            (
+                Some(ProfileDetails::CreateProfileDetails(CreateProfileDetails {
+                    create_profile: true,
+                })),
+                Some(CustomerDetails {
+                    id: item
+                        .router_data
+                        .customer_id
+                        .clone()
+                        .ok_or_else(missing_field_err("customer_id"))?,
+                }),
+            )
+        } else {
+            (None, None)
         };
-        let bill_to = match profile {
-            Some(_) => None,
-            None => item
+        Ok(Self {
+            transaction_type: TransactionType::try_from(item.router_data.request.capture_method)?,
+            amount: item.amount,
+            currency_code: item.router_data.request.currency,
+            payment: Some(PaymentDetails::CreditCard(CreditCardDetails {
+                card_number: (*ccard.card_number).clone(),
+                expiration_date: ccard.get_expiry_date_as_yyyymm("-"),
+                card_code: Some(ccard.card_cvc.clone()),
+            })),
+            profile,
+            order: Order {
+                description: item.router_data.connector_request_reference_id.clone(),
+            },
+            customer,
+            bill_to: item
                 .router_data
                 .get_optional_billing()
                 .and_then(|billing_address| billing_address.address.as_ref())
@@ -602,34 +746,64 @@ impl TryFrom<&AuthorizedotnetRouterData<&types::PaymentsAuthorizeRouterData>>
                     zip: address.zip.clone(),
                     country: address.country,
                 }),
-        };
-        let transaction_request = TransactionRequest {
+            processing_options: None,
+            subsequent_auth_information: None,
+            authorization_indicator_type: match item.router_data.request.capture_method {
+                Some(capture_method) => Some(AuthorizationIndicator {
+                    authorization_indicator: capture_method.try_into()?,
+                }),
+                None => None,
+            },
+        })
+    }
+}
+
+impl
+    TryFrom<(
+        &AuthorizedotnetRouterData<&types::PaymentsAuthorizeRouterData>,
+        &domain::WalletData,
+    )> for TransactionRequest
+{
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(
+        (item, wallet_data): (
+            &AuthorizedotnetRouterData<&types::PaymentsAuthorizeRouterData>,
+            &domain::WalletData,
+        ),
+    ) -> Result<Self, Self::Error> {
+        Ok(Self {
             transaction_type: TransactionType::try_from(item.router_data.request.capture_method)?,
             amount: item.amount,
-            currency_code: item.router_data.request.currency.to_string(),
-            profile,
-            payment: payment_details,
+            currency_code: item.router_data.request.currency,
+            payment: Some(get_wallet_data(
+                wallet_data,
+                &item.router_data.request.complete_authorize_url,
+            )?),
+            profile: None,
             order: Order {
                 description: item.router_data.connector_request_reference_id.clone(),
             },
-            bill_to,
-            processing_options,
-            subsequent_auth_information,
-            authorization_indicator_type,
-        };
-
-        let merchant_authentication =
-            AuthorizedotnetAuthType::try_from(&item.router_data.connector_auth_type)?;
-        let ref_id = if item.router_data.connector_request_reference_id.len() <= 20 {
-            Some(item.router_data.connector_request_reference_id.clone())
-        } else {
-            None
-        };
-        Ok(Self {
-            create_transaction_request: AuthorizedotnetPaymentsRequest {
-                merchant_authentication,
-                ref_id,
-                transaction_request,
+            customer: None,
+            bill_to: item
+                .router_data
+                .get_optional_billing()
+                .and_then(|billing_address| billing_address.address.as_ref())
+                .map(|address| BillTo {
+                    first_name: address.first_name.clone(),
+                    last_name: address.last_name.clone(),
+                    address: address.line1.clone(),
+                    city: address.city.clone(),
+                    state: address.state.clone(),
+                    zip: address.zip.clone(),
+                    country: address.country,
+                }),
+            processing_options: None,
+            subsequent_auth_information: None,
+            authorization_indicator_type: match item.router_data.request.capture_method {
+                Some(capture_method) => Some(AuthorizationIndicator {
+                    authorization_indicator: capture_method.try_into()?,
+                }),
+                None => None,
             },
         })
     }
@@ -804,6 +978,15 @@ pub struct SecureAcceptance {
 #[serde(rename_all = "camelCase")]
 pub struct AuthorizedotnetPaymentsResponse {
     pub transaction_response: Option<TransactionResponse>,
+    pub profile_response: Option<AuthorizedotnetNonZeroMandateResponse>,
+    pub messages: ResponseMessages,
+}
+
+#[derive(Debug, Clone, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct AuthorizedotnetNonZeroMandateResponse {
+    customer_profile_id: Option<String>,
+    customer_payment_profile_id_list: Option<Vec<String>>,
     pub messages: ResponseMessages,
 }
 
@@ -913,7 +1096,16 @@ impl<F, T>
                                 transaction_response.transaction_id.clone(),
                             ),
                             redirection_data,
-                            mandate_reference: None,
+                            mandate_reference: item.response.profile_response.map(
+                                |profile_response| types::MandateReference {
+                                    connector_mandate_id: profile_response.customer_profile_id,
+                                    payment_method_id: profile_response
+                                        .customer_payment_profile_id_list
+                                        .and_then(|customer_payment_profile_id_list| {
+                                            customer_payment_profile_id_list.first().cloned()
+                                        }),
+                                },
+                            ),
                             connector_metadata: metadata,
                             network_txn_id: transaction_response
                                 .network_trans_id

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

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

## Description
<!-- Describe your changes in detail -->
Non-zero dollar mandates are implemented for connector Authorizedotnet.

### 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).
-->
https://github.com/juspay/hyperswitch/issues/4703

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

- Payment Intent Create (Non-Zero Mandate):

Request:
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: API_KEY_HERE' \
--data-raw '{
    "amount": 370,
    "currency": "USD",
    "confirm": false,
    "customer_id": "cust6",
    "email": "something2@gmail.com",
    "name": "Joseph Doe",
    "description": "Its my first payment request",
    "setup_future_usage":"off_session"
}'
```

Response:
```
 {
    "payment_id": "pay_lx2DcRsYllb2QenBQfze",
    "merchant_id": "merchant_1716370796",
    "status": "requires_payment_method",
    "amount": 370,
    "net_amount": 370,
    "amount_capturable": 0,
    "amount_received": null,
    "connector": null,
    "client_secret": "pay_lx2DcRsYllb2QenBQfze_secret_X1riA15AgjzqEahbR8mv",
    "created": "2024-05-27T11:07:15.600Z",
    "currency": "USD",
    "customer_id": "cust6",
    "customer": {
        "id": "cust6",
        "name": "Joseph Doe",
        "email": "something2@gmail.com",
        "phone": null,
        "phone_country_code": null
    },
    "description": "Its my first payment request",
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": "off_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": null,
    "payment_method": null,
    "payment_method_data": null,
    "payment_token": null,
    "shipping": null,
    "billing": null,
    "order_details": null,
    "email": "something2@gmail.com",
    "name": "Joseph Doe",
    "phone": null,
    "return_url": null,
    "authentication_type": null,
    "statement_descriptor_name": null,
    "statement_descriptor_suffix": null,
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": null,
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "cust6",
        "created_at": 1716808035,
        "expires": 1716811635,
        "secret": "epk_339c8ebb1d9f430796cf8273ef72f78f"
    },
    "manual_retry_allowed": null,
    "connector_transaction_id": null,
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_ZjmEyV32O7pOQkBlB510",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": null,
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-05-27T11:22:15.600Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2024-05-27T11:07:15.690Z",
    "charges": null,
    "frm_metadata": null
}
```

- Payment Confirm:

Request:
```
curl --location 'http://localhost:8080/payments/pay_lx2DcRsYllb2QenBQfze/confirm' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: API_KEY_HERE' \
--data '{
    "payment_method": "card",
    "payment_method_type": "credit",
    "payment_method_data": {
        "card": {
            "card_number": "4111111111111111",
            "card_exp_month": "07",
            "card_exp_year": "26",
            "card_holder_name": "Joseph Does",
            "card_cvc": "123"
        }
    },
    "mandate_data": {
        "customer_acceptance": {
            "acceptance_type": "offline",
            "accepted_at": "1963-05-03T04:07:52.723Z",
            "online": {
                "ip_address": "125.0.0.1",
                "user_agent": "amet irure esse"
            }
        },
        "mandate_type": {
            "multi_use": {
                "amount": 68607706,
                "currency": "USD",
                "start_date": "2023-04-21T00:00:00Z",
                "end_date": "2023-05-21T00:00:00Z",
                "metadata": {
                    "frequency": "13"
                }
            }
        }
    }
}'
```

Response:
```
{
    "payment_id": "pay_lx2DcRsYllb2QenBQfze",
    "merchant_id": "merchant_1716370796",
    "status": "succeeded",
    "amount": 370,
    "net_amount": 370,
    "amount_capturable": 0,
    "amount_received": 370,
    "connector": "authorizedotnet",
    "client_secret": "pay_lx2DcRsYllb2QenBQfze_secret_X1riA15AgjzqEahbR8mv",
    "created": "2024-05-27T11:07:15.600Z",
    "currency": "USD",
    "customer_id": "cust6",
    "customer": {
        "id": "cust6",
        "name": "Joseph Doe",
        "email": "something2@gmail.com",
        "phone": null,
        "phone_country_code": null
    },
    "description": "Its my first payment request",
    "refunds": null,
    "disputes": null,
    "mandate_id": "man_wxTMvSxaQPFC5uvg7Qmm",
    "mandate_data": {
        "update_mandate_id": null,
        "customer_acceptance": {
            "acceptance_type": "offline",
            "accepted_at": "1963-05-03T04:07:52.723Z",
            "online": {
                "ip_address": "125.0.0.1",
                "user_agent": "amet irure esse"
            }
        },
        "mandate_type": {
            "multi_use": {
                "amount": 68607706,
                "currency": "USD",
                "start_date": "2023-04-21T00:00:00.000Z",
                "end_date": "2023-05-21T00:00:00.000Z",
                "metadata": {
                    "frequency": "13"
                }
            }
        }
    },
    "setup_future_usage": "off_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": null,
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "1111",
            "card_type": null,
            "card_network": null,
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "411111",
            "card_extended_bin": null,
            "card_exp_month": "07",
            "card_exp_year": "26",
            "card_holder_name": "Joseph Does",
            "payment_checks": null,
            "authentication_data": null
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": null,
    "billing": null,
    "order_details": null,
    "email": "something2@gmail.com",
    "name": "Joseph Doe",
    "phone": null,
    "return_url": null,
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": null,
    "statement_descriptor_suffix": null,
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": "credit",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": null,
    "manual_retry_allowed": false,
    "connector_transaction_id": "80019080368",
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": "80019080368",
    "payment_link": null,
    "profile_id": "pro_ZjmEyV32O7pOQkBlB510",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_6wtrG4tIah8tNezhNkT9",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-05-27T11:22:15.600Z",
    "fingerprint": null,
    "browser_info": {
        "language": null,
        "time_zone": null,
        "ip_address": "::1",
        "user_agent": null,
        "color_depth": null,
        "java_enabled": null,
        "screen_width": null,
        "accept_header": null,
        "screen_height": null,
        "java_script_enabled": null
    },
    "payment_method_id": "pm_ZN7bB0d33KWNWIUgVWod",
    "payment_method_status": null,
    "updated": "2024-05-27T11:07:32.165Z",
    "charges": null,
    "frm_metadata": null
}
```

- Payment Create (Using Mandate ID):

Request:
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: API_KEY_HERE' \
--data '{
    "amount": 141,
    "currency": "USD",
    "confirm": true,
    "customer_id": "cust6",
    "capture_method": "automatic",
    "mandate_id": "man_wxTMvSxaQPFC5uvg7Qmm",
    "off_session": true
}'
```

Response:
```
{
    "payment_id": "pay_8aI2C6oCZosMy1CQf2X9",
    "merchant_id": "merchant_1716370796",
    "status": "succeeded",
    "amount": 141,
    "net_amount": 141,
    "amount_capturable": 0,
    "amount_received": 141,
    "connector": "authorizedotnet",
    "client_secret": "pay_8aI2C6oCZosMy1CQf2X9_secret_gnro3S1Hlru3sUsAcdik",
    "created": "2024-05-27T11:07:53.638Z",
    "currency": "USD",
    "customer_id": "cust6",
    "customer": {
        "id": "cust6",
        "name": "Joseph Doe",
        "email": "something2@gmail.com",
        "phone": null,
        "phone_country_code": null
    },
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": "man_wxTMvSxaQPFC5uvg7Qmm",
    "mandate_data": null,
    "setup_future_usage": null,
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "1111",
            "card_type": null,
            "card_network": null,
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "411111",
            "card_extended_bin": null,
            "card_exp_month": "07",
            "card_exp_year": "26",
            "card_holder_name": "Joseph Does",
            "payment_checks": null,
            "authentication_data": null
        },
        "billing": null
    },
    "payment_token": "fa0a6a44-2e80-4953-971d-c70702e889d7",
    "shipping": null,
    "billing": null,
    "order_details": null,
    "email": "something2@gmail.com",
    "name": "Joseph Doe",
    "phone": null,
    "return_url": null,
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": null,
    "statement_descriptor_suffix": null,
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": "credit",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "cust6",
        "created_at": 1716808073,
        "expires": 1716811673,
        "secret": "epk_95141b60e629482ea657f64053afa3d2"
    },
    "manual_retry_allowed": false,
    "connector_transaction_id": "80019080384",
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": "80019080384",
    "payment_link": null,
    "profile_id": "pro_ZjmEyV32O7pOQkBlB510",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_6wtrG4tIah8tNezhNkT9",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-05-27T11:22:53.638Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": "pm_ZN7bB0d33KWNWIUgVWod",
    "payment_method_status": "active",
    "updated": "2024-05-27T11:07:54.663Z",
    "charges": null,
    "frm_metadata": 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