Bug: [FEATURE] [AUTHORIZEDOTNET] Implement zero mandates



### Feature Description

Zero dollar mandates need to be implemented for connector Authorizedotnet.

### Possible Implementation

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 0eb4297a414..a9e000b82b9 100644
--- a/crates/router/src/connector/authorizedotnet.rs
+++ b/crates/router/src/connector/authorizedotnet.rs
@@ -121,20 +121,84 @@ impl
         types::PaymentsResponseData,
     > for Authorizedotnet
 {
-    // Issue: #173
-    fn build_request(
+    fn get_headers(
         &self,
-        _req: &types::RouterData<
-            api::SetupMandate,
-            types::SetupMandateRequestData,
-            types::PaymentsResponseData,
-        >,
+        req: &types::SetupMandateRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Vec<(String, request::Maskable<String>)>, errors::ConnectorError> {
+        // This connector does not require an auth header, the authentication details are sent in the request body
+        self.build_headers(req, connectors)
+    }
+    fn get_content_type(&self) -> &'static str {
+        self.common_get_content_type()
+    }
+    fn get_url(
+        &self,
+        _req: &types::SetupMandateRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<String, errors::ConnectorError> {
+        Ok(self.base_url(connectors).to_string())
+    }
+    fn get_request_body(
+        &self,
+        req: &types::SetupMandateRouterData,
         _connectors: &settings::Connectors,
-    ) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
-        Err(errors::ConnectorError::NotImplemented(
-            "Setup Mandate flow for Authorizedotnet".to_string(),
-        )
-        .into())
+    ) -> CustomResult<RequestContent, errors::ConnectorError> {
+        let connector_req = authorizedotnet::CreateCustomerProfileRequest::try_from(req)?;
+        Ok(RequestContent::Json(Box::new(connector_req)))
+    }
+
+    fn build_request(
+        &self,
+        req: &types::SetupMandateRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Option<common_utils::request::Request>, errors::ConnectorError> {
+        Ok(Some(
+            services::RequestBuilder::new()
+                .method(services::Method::Post)
+                .url(&types::SetupMandateType::get_url(self, req, connectors)?)
+                .attach_default_headers()
+                .headers(types::SetupMandateType::get_headers(self, req, connectors)?)
+                .set_body(types::SetupMandateType::get_request_body(
+                    self, req, connectors,
+                )?)
+                .build(),
+        ))
+    }
+
+    fn handle_response(
+        &self,
+        data: &types::SetupMandateRouterData,
+        event_builder: Option<&mut ConnectorEvent>,
+        res: types::Response,
+    ) -> CustomResult<types::SetupMandateRouterData, errors::ConnectorError> {
+        use bytes::Buf;
+
+        // Handle the case where response bytes contains U+FEFF (BOM) character sent by connector
+        let encoding = encoding_rs::UTF_8;
+        let intermediate_response = encoding.decode_with_bom_removal(res.response.chunk());
+        let intermediate_response =
+            bytes::Bytes::copy_from_slice(intermediate_response.0.as_bytes());
+        let response: authorizedotnet::AuthorizedotnetSetupMandateResponse = intermediate_response
+            .parse_struct("AuthorizedotnetPaymentsResponse")
+            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
+
+        event_builder.map(|i| i.set_response_body(&response));
+        router_env::logger::info!(connector_response=?response);
+
+        types::RouterData::try_from(types::ResponseRouterData {
+            response,
+            data: data.clone(),
+            http_code: res.status_code,
+        })
+    }
+
+    fn get_error_response(
+        &self,
+        res: types::Response,
+        event_builder: Option<&mut ConnectorEvent>,
+    ) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
+        get_error_response(res, event_builder)
     }
 }
 
diff --git a/crates/router/src/connector/authorizedotnet/transformers.rs b/crates/router/src/connector/authorizedotnet/transformers.rs
index ddcfdfacad2..8069b925d44 100644
--- a/crates/router/src/connector/authorizedotnet/transformers.rs
+++ b/crates/router/src/connector/authorizedotnet/transformers.rs
@@ -1,6 +1,7 @@
 use common_utils::{
     errors::CustomResult,
     ext_traits::{Encode, ValueExt},
+    pii,
 };
 use error_stack::ResultExt;
 use masking::{ExposeInterface, PeekInterface, Secret, StrongSecret};
@@ -8,7 +9,8 @@ use serde::{Deserialize, Serialize};
 
 use crate::{
     connector::utils::{
-        self, CardData, PaymentsSyncRequestData, RefundsRequestData, RouterData, WalletData,
+        self, missing_field_err, CardData, PaymentsSyncRequestData, RefundsRequestData, RouterData,
+        WalletData,
     },
     core::errors,
     services,
@@ -126,112 +128,18 @@ pub enum WalletMethod {
     Applepay,
 }
 
-fn get_pm_and_subsequent_auth_detail(
-    item: &AuthorizedotnetRouterData<&types::PaymentsAuthorizeRouterData>,
-) -> Result<
-    (
-        PaymentDetails,
-        Option<ProcessingOptions>,
-        Option<SubsequentAuthInformation>,
-    ),
-    error_stack::Report<errors::ConnectorError>,
-> {
-    match item
-        .router_data
-        .request
-        .mandate_id
-        .to_owned()
-        .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 subseuent_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,
-                    });
-                    Ok((payment_details, processing_options, subseuent_auth_info))
-                }
-                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"),
-                    ))?
-                }
-            }
-        }
-        Some(api_models::payments::MandateReferenceId::ConnectorMandateId(_)) | None => {
-            match item.router_data.request.payment_method_data {
-                domain::PaymentMethodData::Card(ref ccard) => {
-                    Ok((
-                        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,
-                    ))
-                }
-                domain::PaymentMethodData::Wallet(ref wallet_data) => Ok((
-                    get_wallet_data(
-                        wallet_data,
-                        &item.router_data.request.complete_authorize_url,
-                    )?,
-                    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"),
-                    ))?
-                }
-            }
-        }
-    }
-}
-
 #[derive(Debug, Serialize)]
 #[serde(rename_all = "camelCase")]
 struct TransactionRequest {
     transaction_type: TransactionType,
     amount: f64,
     currency_code: String,
-    payment: PaymentDetails,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    profile: Option<CustomerProfileDetails>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    payment: Option<PaymentDetails>,
     order: Order,
+    #[serde(skip_serializing_if = "Option::is_none")]
     bill_to: Option<BillTo>,
     processing_options: Option<ProcessingOptions>,
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -239,6 +147,19 @@ struct TransactionRequest {
     authorization_indicator_type: Option<AuthorizationIndicator>,
 }
 
+#[derive(Serialize, Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+struct CustomerProfileDetails {
+    customer_profile_id: Secret<String>,
+    payment_profile: PaymentProfileDetails,
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+struct PaymentProfileDetails {
+    payment_profile_id: Secret<String>,
+}
+
 #[derive(Debug, Serialize)]
 #[serde(rename_all = "camelCase")]
 pub struct ProcessingOptions {
@@ -312,6 +233,192 @@ pub struct AuthorizedotnetPaymentCancelOrCaptureRequest {
     transaction_request: TransactionVoidOrCaptureRequest,
 }
 
+#[derive(Debug, Serialize)]
+#[serde(rename_all = "camelCase")]
+// The connector enforces field ordering, it expects fields to be in the same order as in their API documentation
+pub struct CreateCustomerProfileRequest {
+    create_customer_profile_request: AuthorizedotnetZeroMandateRequest,
+}
+
+#[derive(Debug, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct AuthorizedotnetZeroMandateRequest {
+    merchant_authentication: AuthorizedotnetAuthType,
+    profile: Profile,
+    validation_mode: ValidationMode,
+}
+
+#[derive(Debug, Serialize)]
+#[serde(rename_all = "camelCase")]
+struct Profile {
+    merchant_customer_id: String,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    description: Option<String>,
+    email: Option<pii::Email>,
+    payment_profiles: PaymentProfiles,
+}
+
+#[derive(Debug, Serialize)]
+#[serde(rename_all = "camelCase")]
+struct PaymentProfiles {
+    customer_type: CustomerType,
+    payment: PaymentDetails,
+}
+
+#[derive(Debug, Serialize)]
+#[serde(rename_all = "lowercase")]
+pub enum CustomerType {
+    Individual,
+    Business,
+}
+
+#[derive(Debug, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub enum ValidationMode {
+    // testMode performs a Luhn mod-10 check on the card number, without further validation at connector.
+    TestMode,
+    // liveMode submits a zero-dollar or one-cent transaction (depending on card type and processor support) to confirm that the card number belongs to an active credit or debit account.
+    LiveMode,
+}
+
+impl TryFrom<&types::SetupMandateRouterData> for CreateCustomerProfileRequest {
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(item: &types::SetupMandateRouterData) -> Result<Self, Self::Error> {
+        match item.request.payment_method_data.clone() {
+            domain::PaymentMethodData::Card(ccard) => {
+                let merchant_authentication =
+                    AuthorizedotnetAuthType::try_from(&item.connector_auth_type)?;
+                let validation_mode = match item.test_mode {
+                    Some(true) | None => ValidationMode::TestMode,
+                    Some(false) => ValidationMode::LiveMode,
+                };
+                Ok(Self {
+                    create_customer_profile_request: AuthorizedotnetZeroMandateRequest {
+                        merchant_authentication,
+                        profile: Profile {
+                            merchant_customer_id: item
+                                .customer_id
+                                .clone()
+                                .ok_or_else(missing_field_err("customer_id"))?,
+                            description: item.description.clone(),
+                            email: item.request.email.clone(),
+                            payment_profiles: PaymentProfiles {
+                                customer_type: CustomerType::Individual,
+                                payment: PaymentDetails::CreditCard(CreditCardDetails {
+                                    card_number: (*ccard.card_number).clone(),
+                                    expiration_date: ccard.get_expiry_date_as_yyyymm("-"),
+                                    card_code: Some(ccard.card_cvc.clone()),
+                                }),
+                            },
+                        },
+                        validation_mode,
+                    },
+                })
+            }
+            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"),
+                ))?
+            }
+        }
+    }
+}
+
+#[derive(Debug, Clone, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct AuthorizedotnetSetupMandateResponse {
+    customer_profile_id: Option<String>,
+    customer_payment_profile_id_list: Vec<String>,
+    validation_direct_response_list: Option<Vec<Secret<String>>>,
+    pub messages: ResponseMessages,
+}
+
+// zero dollar response
+impl<F, T>
+    TryFrom<
+        types::ResponseRouterData<
+            F,
+            AuthorizedotnetSetupMandateResponse,
+            T,
+            types::PaymentsResponseData,
+        >,
+    > for types::RouterData<F, T, types::PaymentsResponseData>
+{
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(
+        item: types::ResponseRouterData<
+            F,
+            AuthorizedotnetSetupMandateResponse,
+            T,
+            types::PaymentsResponseData,
+        >,
+    ) -> Result<Self, Self::Error> {
+        match item.response.messages.result_code {
+            ResultCode::Ok => Ok(Self {
+                status: enums::AttemptStatus::Charged,
+                response: Ok(types::PaymentsResponseData::TransactionResponse {
+                    resource_id: types::ResponseId::NoResponseId,
+                    redirection_data: None,
+                    mandate_reference: item.response.customer_profile_id.map(|mandate_id| {
+                        types::MandateReference {
+                            connector_mandate_id: Some(mandate_id),
+                            payment_method_id: item
+                                .response
+                                .customer_payment_profile_id_list
+                                .first()
+                                .cloned(),
+                        }
+                    }),
+                    connector_metadata: None,
+                    network_txn_id: None,
+                    connector_response_reference_id: None,
+                    incremental_authorization_allowed: None,
+                }),
+                ..item.data
+            }),
+            ResultCode::Error => {
+                let error_code = match item.response.messages.message.first() {
+                    Some(first_error_message) => first_error_message.code.clone(),
+                    None => crate::consts::NO_ERROR_CODE.to_string(),
+                };
+                let error_reason = item
+                    .response
+                    .messages
+                    .message
+                    .iter()
+                    .map(|error: &ResponseMessage| error.text.clone())
+                    .collect::<Vec<String>>()
+                    .join(" ");
+                let response = Err(types::ErrorResponse {
+                    code: error_code,
+                    message: item.response.messages.result_code.to_string(),
+                    reason: Some(error_reason),
+                    status_code: item.http_code,
+                    attempt_status: None,
+                    connector_transaction_id: None,
+                });
+                Ok(Self {
+                    response,
+                    status: enums::AttemptStatus::Failure,
+                    ..item.data
+                })
+            }
+        }
+    }
+}
+
 #[derive(Debug, Serialize)]
 #[serde(rename_all = "camelCase")]
 // The connector enforces field ordering, it expects fields to be in the same order as in their API documentation
@@ -353,31 +460,153 @@ impl TryFrom<&AuthorizedotnetRouterData<&types::PaymentsAuthorizeRouterData>>
     fn try_from(
         item: &AuthorizedotnetRouterData<&types::PaymentsAuthorizeRouterData>,
     ) -> Result<Self, Self::Error> {
-        let (payment_details, processing_options, subsequent_auth_information) =
-            get_pm_and_subsequent_auth_detail(item)?;
+        let (payment_details, processing_options, subsequent_auth_information, profile) = match item
+            .router_data
+            .request
+            .mandate_id
+            .to_owned()
+            .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,
+                        )
+                    }
+                    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",
+                            ),
+                        ))?
+                    }
+                }
+            }
+            Some(api_models::payments::MandateReferenceId::ConnectorMandateId(
+                connector_mandate_id,
+            )) => (
+                None,
+                Some(ProcessingOptions {
+                    is_subsequent_auth: true,
+                }),
+                None,
+                Some(CustomerProfileDetails {
+                    customer_profile_id: Secret::from(
+                        connector_mandate_id
+                            .connector_mandate_id
+                            .ok_or(errors::ConnectorError::MissingConnectorMandateID)?,
+                    ),
+                    payment_profile: PaymentProfileDetails {
+                        payment_profile_id: Secret::from(
+                            connector_mandate_id
+                                .payment_method_id
+                                .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()?,
             }),
             None => None,
         };
-        let 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,
-            });
+        let bill_to = match profile {
+            Some(_) => None,
+            None => 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,
+                }),
+        };
         let transaction_request = TransactionRequest {
             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,
             order: Order {
                 description: item.router_data.connector_request_reference_id.clone(),
@@ -506,7 +735,7 @@ pub struct ResponseMessage {
     pub text: String,
 }
 
-#[derive(Debug, Default, Clone, Deserialize, PartialEq, Serialize)]
+#[derive(Debug, Default, Clone, Deserialize, PartialEq, Serialize, strum::Display)]
 enum ResultCode {
     #[default]
     Ok,

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

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

## Description
<!-- Describe your changes in detail -->
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/4702

## 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)?
-->
_Note: `test_mode` should be set to `true` while testing._
- Create Zero Amount 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": 0,
    "currency": "USD",
    "confirm": true,
    "customer_id": "tester123",
    "email": "johndoe@gmail.com",
    "setup_future_usage": "off_session",
    "payment_type": "setup_mandate",
    "off_session": true,
    "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": 1000,
                "currency": "USD",
                "start_date": "2023-04-21T00:00:00Z",
                "end_date": "2023-05-21T00:00:00Z",
                "metadata": {
                    "frequency": "13"
                }
            }
        }
    }
}'
```
Response:
```
{
    "payment_id": "pay_BUTzOloWgy5ZjPUjOhDR",
    "merchant_id": "merchant_1709720492",
    "status": "succeeded",
    "amount": 0,
    "net_amount": 0,
    "amount_capturable": 0,
    "amount_received": null,
    "connector": "authorizedotnet",
    "client_secret": "pay_BUTzOloWgy5ZjPUjOhDR_secret_aQaDNrV3HKhGHZnLcWet",
    "created": "2024-05-21T13:43:09.180Z",
    "currency": "USD",
    "customer_id": "tester123",
    "customer": {
        "id": "tester123",
        "name": null,
        "email": "johndoe@gmail.com",
        "phone": null,
        "phone_country_code": null
    },
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": "man_SJ0R3Dx1krNV2OYYXqK8",
    "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": 1000,
                "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": "johndoe@gmail.com",
    "name": null,
    "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": "tester123",
        "created_at": 1716298989,
        "expires": 1716302589,
        "secret": "epk_1cdb048e685f43f9ad8b1f1c20b5142b"
    },
    "manual_retry_allowed": false,
    "connector_transaction_id": null,
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_4aXJeUeyy9BzdhcV9Xue",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_3mX9fbzXfxIkG0uwmy2D",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-05-21T13:58:09.180Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": "pm_eAcvFw4WhUlfAGyeya52",
    "payment_method_status": null,
    "updated": "2024-05-21T13:43:09.865Z",
    "frm_metadata": null
}
```

- Create Payment Using Mandate:

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

Response:
```
{
    "payment_id": "pay_BYA7GLOyizx2lXr7HY8l",
    "merchant_id": "merchant_1709720492",
    "status": "succeeded",
    "amount": 400,
    "net_amount": 400,
    "amount_capturable": 0,
    "amount_received": 400,
    "connector": "authorizedotnet",
    "client_secret": "pay_BYA7GLOyizx2lXr7HY8l_secret_eyykmbXcMfPnc4m9Vbid",
    "created": "2024-05-21T13:47:00.958Z",
    "currency": "USD",
    "customer_id": "tester123",
    "customer": {
        "id": "tester123",
        "name": null,
        "email": "johndoe@gmail.com",
        "phone": null,
        "phone_country_code": null
    },
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": "man_SJ0R3Dx1krNV2OYYXqK8",
    "mandate_data": null,
    "setup_future_usage": null,
    "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": "3906c467-f517-40a1-bb0f-a10c4e6f9878",
    "shipping": null,
    "billing": null,
    "order_details": null,
    "email": "johndoe@gmail.com",
    "name": null,
    "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": "tester123",
        "created_at": 1716299220,
        "expires": 1716302820,
        "secret": "epk_866be4c4a3de481b808853b80a5c5198"
    },
    "manual_retry_allowed": false,
    "connector_transaction_id": "80018772612",
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": "80018772612",
    "payment_link": null,
    "profile_id": "pro_4aXJeUeyy9BzdhcV9Xue",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_3mX9fbzXfxIkG0uwmy2D",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-05-21T14:02:00.957Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": "pm_eAcvFw4WhUlfAGyeya52",
    "payment_method_status": "active",
    "updated": "2024-05-21T13:47:03.437Z",
    "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
