Bug: Add zero auth mandates support for nexixpay



Zero auth mandates support for nexixpay.
diff --git a/crates/hyperswitch_connectors/src/connectors/adyen.rs b/crates/hyperswitch_connectors/src/connectors/adyen.rs
index 8e0694336b5..b047d99a9d0 100644
--- a/crates/hyperswitch_connectors/src/connectors/adyen.rs
+++ b/crates/hyperswitch_connectors/src/connectors/adyen.rs
@@ -72,10 +72,7 @@ use hyperswitch_interfaces::{
 use masking::{ExposeInterface, Mask, Maskable, Secret};
 use ring::hmac;
 use router_env::{instrument, tracing};
-use transformers::{
-    self as adyen, convert_payment_authorize_router_response,
-    convert_setup_mandate_router_data_to_authorize_router_data,
-};
+use transformers as adyen;
 
 #[cfg(feature = "payouts")]
 use crate::utils::PayoutsData as UtilsPayoutData;
@@ -86,7 +83,11 @@ use crate::{
         AcceptDisputeRouterData, DefendDisputeRouterData, ResponseRouterData,
         SubmitEvidenceRouterData,
     },
-    utils::{self as connector_utils, is_mandate_supported, ForeignTryFrom, PaymentMethodDataType},
+    utils::{
+        self as connector_utils, convert_payment_authorize_router_response,
+        convert_setup_mandate_router_data_to_authorize_router_data, is_mandate_supported,
+        ForeignTryFrom, PaymentMethodDataType,
+    },
 };
 const ADYEN_API_VERSION: &str = "v68";
 
diff --git a/crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs b/crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs
index 793a33e1fc1..2e87967b0f9 100644
--- a/crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs
+++ b/crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs
@@ -1,5 +1,3 @@
-use std::marker::PhantomData;
-
 #[cfg(feature = "payouts")]
 use api_models::payouts::{self, PayoutMethodData};
 use api_models::{
@@ -27,16 +25,14 @@ use hyperswitch_domain_models::{
     router_data::{
         ConnectorAuthType, ErrorResponse, PaymentMethodBalance, PaymentMethodToken, RouterData,
     },
-    router_request_types::{
-        PaymentsAuthorizeData, PaymentsPreProcessingData, ResponseId, SubmitEvidenceRequestData,
-    },
+    router_request_types::{PaymentsPreProcessingData, ResponseId, SubmitEvidenceRequestData},
     router_response_types::{
         AcceptDisputeResponse, DefendDisputeResponse, MandateReference, PaymentsResponseData,
         RedirectForm, RefundsResponseData, SubmitEvidenceResponse,
     },
     types::{
         PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
-        PaymentsPreProcessingRouterData, RefundsRouterData, SetupMandateRouterData,
+        PaymentsPreProcessingRouterData, RefundsRouterData,
     },
 };
 #[cfg(feature = "payouts")]
@@ -5545,106 +5541,3 @@ impl
         })
     }
 }
-
-pub(crate) fn convert_setup_mandate_router_data_to_authorize_router_data(
-    data: &SetupMandateRouterData,
-) -> PaymentsAuthorizeData {
-    PaymentsAuthorizeData {
-        currency: data.request.currency,
-        payment_method_data: data.request.payment_method_data.clone(),
-        confirm: data.request.confirm,
-        statement_descriptor_suffix: data.request.statement_descriptor_suffix.clone(),
-        mandate_id: data.request.mandate_id.clone(),
-        setup_future_usage: data.request.setup_future_usage,
-        off_session: data.request.off_session,
-        setup_mandate_details: data.request.setup_mandate_details.clone(),
-        router_return_url: data.request.router_return_url.clone(),
-        email: data.request.email.clone(),
-        customer_name: data.request.customer_name.clone(),
-        amount: 0,
-        order_tax_amount: Some(MinorUnit::zero()),
-        minor_amount: MinorUnit::new(0),
-        statement_descriptor: None,
-        capture_method: None,
-        webhook_url: None,
-        complete_authorize_url: None,
-        browser_info: data.request.browser_info.clone(),
-        order_details: None,
-        order_category: None,
-        session_token: None,
-        enrolled_for_3ds: true,
-        related_transaction_id: None,
-        payment_experience: None,
-        payment_method_type: None,
-        customer_id: None,
-        surcharge_details: None,
-        request_incremental_authorization: data.request.request_incremental_authorization,
-        metadata: None,
-        authentication_data: None,
-        customer_acceptance: data.request.customer_acceptance.clone(),
-        split_payments: None, // TODO: allow charges on mandates?
-        merchant_order_reference_id: None,
-        integrity_object: None,
-        additional_payment_method_data: None,
-        shipping_cost: data.request.shipping_cost,
-        merchant_account_id: None,
-        merchant_config_currency: None,
-    }
-}
-
-pub(crate) fn convert_payment_authorize_router_response<F1, F2, T1, T2>(
-    item: (&RouterData<F1, T1, PaymentsResponseData>, T2),
-) -> RouterData<F2, T2, PaymentsResponseData> {
-    let data = item.0;
-    let request = item.1;
-    RouterData {
-        flow: PhantomData,
-        request,
-        merchant_id: data.merchant_id.clone(),
-        connector: data.connector.clone(),
-        attempt_id: data.attempt_id.clone(),
-        tenant_id: data.tenant_id.clone(),
-        status: data.status,
-        payment_method: data.payment_method,
-        connector_auth_type: data.connector_auth_type.clone(),
-        description: data.description.clone(),
-        address: data.address.clone(),
-        auth_type: data.auth_type,
-        connector_meta_data: data.connector_meta_data.clone(),
-        connector_wallets_details: data.connector_wallets_details.clone(),
-        amount_captured: data.amount_captured,
-        minor_amount_captured: data.minor_amount_captured,
-        access_token: data.access_token.clone(),
-        response: data.response.clone(),
-        payment_id: data.payment_id.clone(),
-        session_token: data.session_token.clone(),
-        reference_id: data.reference_id.clone(),
-        customer_id: data.customer_id.clone(),
-        payment_method_token: None,
-        preprocessing_id: None,
-        connector_customer: data.connector_customer.clone(),
-        recurring_mandate_payment_data: data.recurring_mandate_payment_data.clone(),
-        connector_request_reference_id: data.connector_request_reference_id.clone(),
-        #[cfg(feature = "payouts")]
-        payout_method_data: data.payout_method_data.clone(),
-        #[cfg(feature = "payouts")]
-        quote_id: data.quote_id.clone(),
-        test_mode: data.test_mode,
-        payment_method_status: None,
-        payment_method_balance: data.payment_method_balance.clone(),
-        connector_api_version: data.connector_api_version.clone(),
-        connector_http_status_code: data.connector_http_status_code,
-        external_latency: data.external_latency,
-        apple_pay_flow: data.apple_pay_flow.clone(),
-        frm_metadata: data.frm_metadata.clone(),
-        dispute_id: data.dispute_id.clone(),
-        refund_id: data.refund_id.clone(),
-        connector_response: data.connector_response.clone(),
-        integrity_check: Ok(()),
-        additional_merchant_data: data.additional_merchant_data.clone(),
-        header_payload: data.header_payload.clone(),
-        connector_mandate_request_reference_id: data.connector_mandate_request_reference_id.clone(),
-        authentication_id: data.authentication_id.clone(),
-        psd2_sca_exemption_type: data.psd2_sca_exemption_type,
-    }
-}
diff --git a/crates/hyperswitch_connectors/src/connectors/nexixpay.rs b/crates/hyperswitch_connectors/src/connectors/nexixpay.rs
index 264bca6b5a9..bed54d66e4d 100644
--- a/crates/hyperswitch_connectors/src/connectors/nexixpay.rs
+++ b/crates/hyperswitch_connectors/src/connectors/nexixpay.rs
@@ -32,7 +32,7 @@ use hyperswitch_domain_models::{
     types::{
         PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
         PaymentsCompleteAuthorizeRouterData, PaymentsPreProcessingRouterData,
-        PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData,
+        PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData, SetupMandateRouterData,
     },
 };
 use hyperswitch_interfaces::{
@@ -228,6 +228,91 @@ impl ConnectorIntegration<AccessTokenAuth, AccessTokenRequestData, AccessToken>
 impl ConnectorIntegration<SetupMandate, SetupMandateRequestData, PaymentsResponseData>
     for Nexixpay
 {
+    fn get_headers(
+        &self,
+        req: &SetupMandateRouterData,
+        connectors: &Connectors,
+    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
+        self.build_headers(req, connectors)
+    }
+
+    fn get_content_type(&self) -> &'static str {
+        self.common_get_content_type()
+    }
+
+    fn get_url(
+        &self,
+        _req: &SetupMandateRouterData,
+        connectors: &Connectors,
+    ) -> CustomResult<String, errors::ConnectorError> {
+        Ok(format!("{}/orders/3steps/init", self.base_url(connectors)))
+    }
+
+    fn get_request_body(
+        &self,
+        req: &SetupMandateRouterData,
+        _connectors: &Connectors,
+    ) -> CustomResult<RequestContent, errors::ConnectorError> {
+        let authorize_req = utils::convert_payment_authorize_router_response((
+            req,
+            utils::convert_setup_mandate_router_data_to_authorize_router_data(req),
+        ));
+
+        let amount = utils::convert_amount(
+            self.amount_converter,
+            authorize_req.request.minor_amount,
+            authorize_req.request.currency,
+        )?;
+
+        let connector_router_data = nexixpay::NexixpayRouterData::from((amount, &authorize_req));
+        let connector_req = nexixpay::NexixpayPaymentsRequest::try_from(&connector_router_data)?;
+        Ok(RequestContent::Json(Box::new(connector_req)))
+    }
+
+    fn build_request(
+        &self,
+        req: &SetupMandateRouterData,
+        connectors: &Connectors,
+    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
+        Ok(Some(
+            RequestBuilder::new()
+                .method(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: &SetupMandateRouterData,
+        event_builder: Option<&mut ConnectorEvent>,
+        res: Response,
+    ) -> CustomResult<SetupMandateRouterData, errors::ConnectorError> {
+        let response: nexixpay::PaymentsResponse = res
+            .response
+            .parse_struct("PaymentsResponse")
+            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
+        event_builder.map(|i| i.set_response_body(&response));
+        router_env::logger::info!(connector_response=?response);
+        RouterData::try_from(ResponseRouterData {
+            response,
+            data: data.clone(),
+            http_code: res.status_code,
+        })
+    }
+
+    fn get_error_response(
+        &self,
+        res: Response,
+        event_builder: Option<&mut ConnectorEvent>,
+    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
+        self.build_error_response(res, event_builder)
+    }
 }
 
 impl ConnectorIntegration<PreProcessing, PaymentsPreProcessingData, PaymentsResponseData>
diff --git a/crates/hyperswitch_connectors/src/connectors/nexixpay/transformers.rs b/crates/hyperswitch_connectors/src/connectors/nexixpay/transformers.rs
index 27eebf78dfb..06925eea6cf 100644
--- a/crates/hyperswitch_connectors/src/connectors/nexixpay/transformers.rs
+++ b/crates/hyperswitch_connectors/src/connectors/nexixpay/transformers.rs
@@ -9,10 +9,13 @@ use error_stack::ResultExt;
 use hyperswitch_domain_models::{
     payment_method_data::PaymentMethodData,
     router_data::{ConnectorAuthType, RouterData},
-    router_flow_types::refunds::{Execute, RSync},
+    router_flow_types::{
+        refunds::{Execute, RSync},
+        SetupMandate,
+    },
     router_request_types::{
         CompleteAuthorizeData, PaymentsAuthorizeData, PaymentsCancelData, PaymentsCaptureData,
-        PaymentsPreProcessingData, PaymentsSyncData, ResponseId,
+        PaymentsPreProcessingData, PaymentsSyncData, ResponseId, SetupMandateRequestData,
     },
     router_response_types::{
         MandateReference, PaymentsResponseData, RedirectForm, RefundsResponseData,
@@ -31,7 +34,8 @@ use crate::{
     utils::{
         get_unimplemented_payment_method_error_message, to_connector_meta,
         to_connector_meta_from_secret, CardData, PaymentsAuthorizeRequestData,
-        PaymentsCompleteAuthorizeRequestData, PaymentsPreProcessingRequestData, RouterData as _,
+        PaymentsCompleteAuthorizeRequestData, PaymentsPreProcessingRequestData,
+        PaymentsSetupMandateRequestData, RouterData as _,
     },
 };
 
@@ -1290,3 +1294,74 @@ impl<F>
         })
     }
 }
+
+impl
+    TryFrom<
+        ResponseRouterData<
+            SetupMandate,
+            PaymentsResponse,
+            SetupMandateRequestData,
+            PaymentsResponseData,
+        >,
+    > for RouterData<SetupMandate, SetupMandateRequestData, PaymentsResponseData>
+{
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(
+        item: ResponseRouterData<
+            SetupMandate,
+            PaymentsResponse,
+            SetupMandateRequestData,
+            PaymentsResponseData,
+        >,
+    ) -> Result<Self, Self::Error> {
+        let complete_authorize_url = item.data.request.get_complete_authorize_url()?;
+        let operation_id: String = item.response.operation.operation_id.clone();
+        let redirection_form = nexixpay_threeds_link(NexixpayRedirectionRequest {
+            three_d_s_auth_url: item
+                .response
+                .three_d_s_auth_url
+                .clone()
+                .expose()
+                .to_string(),
+            three_ds_request: item.response.three_d_s_auth_request.clone(),
+            return_url: complete_authorize_url.clone(),
+            transaction_id: operation_id.clone(),
+        })?;
+        let is_auto_capture = item.data.request.is_auto_capture()?;
+        let connector_metadata = Some(serde_json::json!(NexixpayConnectorMetaData {
+            three_d_s_auth_result: None,
+            three_d_s_auth_response: None,
+            authorization_operation_id: Some(operation_id.clone()),
+            cancel_operation_id: None,
+            capture_operation_id: {
+                if is_auto_capture {
+                    Some(operation_id)
+                } else {
+                    None
+                }
+            },
+            psync_flow: NexixpayPaymentIntent::Authorize
+        }));
+        Ok(Self {
+            status: AttemptStatus::from(item.response.operation.operation_result.clone()),
+            response: Ok(PaymentsResponseData::TransactionResponse {
+                resource_id: ResponseId::ConnectorTransactionId(
+                    item.response.operation.order_id.clone(),
+                ),
+                redirection_data: Box::new(Some(redirection_form.clone())),
+                mandate_reference: Box::new(Some(MandateReference {
+                    connector_mandate_id: item.data.connector_mandate_request_reference_id.clone(),
+                    payment_method_id: None,
+                    mandate_metadata: None,
+                    connector_mandate_request_reference_id: None,
+                })),
+                connector_metadata,
+                network_txn_id: None,
+                connector_response_reference_id: Some(item.response.operation.order_id.clone()),
+                incremental_authorization_allowed: None,
+                charges: None,
+            }),
+            ..item.data
+        })
+    }
+}
diff --git a/crates/hyperswitch_connectors/src/utils.rs b/crates/hyperswitch_connectors/src/utils.rs
index a34699498b5..b1bd7a04d5f 100644
--- a/crates/hyperswitch_connectors/src/utils.rs
+++ b/crates/hyperswitch_connectors/src/utils.rs
@@ -1,5 +1,6 @@
 use std::{
     collections::{HashMap, HashSet},
+    marker::PhantomData,
     str::FromStr,
 };
 
@@ -44,6 +45,7 @@ use hyperswitch_domain_models::{
     payment_method_data::{self, Card, CardDetailsForNetworkTransactionId, PaymentMethodData},
     router_data::{
         ApplePayPredecryptData, ErrorResponse, PaymentMethodToken, RecurringMandatePaymentData,
+        RouterData as ConnectorRouterData,
     },
     router_request_types::{
         AuthenticationData, BrowserInformation, CompleteAuthorizeData, ConnectorCustomerData,
@@ -52,8 +54,8 @@ use hyperswitch_domain_models::{
         PaymentsPreProcessingData, PaymentsSyncData, RefundsData, ResponseId,
         SetupMandateRequestData,
     },
-    router_response_types::CaptureSyncResponse,
-    types::OrderDetailsWithAmount,
+    router_response_types::{CaptureSyncResponse, PaymentsResponseData},
+    types::{OrderDetailsWithAmount, SetupMandateRouterData},
 };
 use hyperswitch_interfaces::{api, consts, errors, types::Response};
 use image::{DynamicImage, ImageBuffer, ImageFormat, Luma, Rgba};
@@ -2014,6 +2016,8 @@ pub trait PaymentsSetupMandateRequestData {
     fn get_return_url(&self) -> Result<String, Error>;
     fn get_webhook_url(&self) -> Result<String, Error>;
     fn get_optional_language_from_browser_info(&self) -> Option<String>;
+    fn get_complete_authorize_url(&self) -> Result<String, Error>;
+    fn is_auto_capture(&self) -> Result<bool, Error>;
 }
 
 impl PaymentsSetupMandateRequestData for SetupMandateRequestData {
@@ -2048,6 +2052,20 @@ impl PaymentsSetupMandateRequestData for SetupMandateRequestData {
             .clone()
             .and_then(|browser_info| browser_info.language)
     }
+    fn get_complete_authorize_url(&self) -> Result<String, Error> {
+        self.complete_authorize_url
+            .clone()
+            .ok_or_else(missing_field_err("complete_authorize_url"))
+    }
+    fn is_auto_capture(&self) -> Result<bool, Error> {
+        match self.capture_method {
+            Some(enums::CaptureMethod::Automatic)
+            | Some(enums::CaptureMethod::SequentialAutomatic)
+            | None => Ok(true),
+            Some(enums::CaptureMethod::Manual) => Ok(false),
+            Some(_) => Err(errors::ConnectorError::CaptureMethodNotSupported.into()),
+        }
+    }
 }
 
 pub trait PaymentMethodTokenizationRequestData {
@@ -5855,3 +5873,106 @@ where
     let output = <&str>::deserialize(v)?;
     output.to_uppercase().parse::<T>().map_err(D::Error::custom)
 }
+
+pub(crate) fn convert_setup_mandate_router_data_to_authorize_router_data(
+    data: &SetupMandateRouterData,
+) -> PaymentsAuthorizeData {
+    PaymentsAuthorizeData {
+        currency: data.request.currency,
+        payment_method_data: data.request.payment_method_data.clone(),
+        confirm: data.request.confirm,
+        statement_descriptor_suffix: data.request.statement_descriptor_suffix.clone(),
+        mandate_id: data.request.mandate_id.clone(),
+        setup_future_usage: data.request.setup_future_usage,
+        off_session: data.request.off_session,
+        setup_mandate_details: data.request.setup_mandate_details.clone(),
+        router_return_url: data.request.router_return_url.clone(),
+        email: data.request.email.clone(),
+        customer_name: data.request.customer_name.clone(),
+        amount: 0,
+        order_tax_amount: Some(MinorUnit::zero()),
+        minor_amount: MinorUnit::new(0),
+        statement_descriptor: None,
+        capture_method: None,
+        webhook_url: None,
+        complete_authorize_url: None,
+        browser_info: data.request.browser_info.clone(),
+        order_details: None,
+        order_category: None,
+        session_token: None,
+        enrolled_for_3ds: true,
+        related_transaction_id: None,
+        payment_experience: None,
+        payment_method_type: None,
+        customer_id: None,
+        surcharge_details: None,
+        request_incremental_authorization: data.request.request_incremental_authorization,
+        metadata: None,
+        authentication_data: None,
+        customer_acceptance: data.request.customer_acceptance.clone(),
+        split_payments: None, // TODO: allow charges on mandates?
+        merchant_order_reference_id: None,
+        integrity_object: None,
+        additional_payment_method_data: None,
+        shipping_cost: data.request.shipping_cost,
+        merchant_account_id: None,
+        merchant_config_currency: None,
+    }
+}
+
+pub(crate) fn convert_payment_authorize_router_response<F1, F2, T1, T2>(
+    item: (&ConnectorRouterData<F1, T1, PaymentsResponseData>, T2),
+) -> ConnectorRouterData<F2, T2, PaymentsResponseData> {
+    let data = item.0;
+    let request = item.1;
+    ConnectorRouterData {
+        flow: PhantomData,
+        request,
+        merchant_id: data.merchant_id.clone(),
+        connector: data.connector.clone(),
+        attempt_id: data.attempt_id.clone(),
+        tenant_id: data.tenant_id.clone(),
+        status: data.status,
+        payment_method: data.payment_method,
+        connector_auth_type: data.connector_auth_type.clone(),
+        description: data.description.clone(),
+        address: data.address.clone(),
+        auth_type: data.auth_type,
+        connector_meta_data: data.connector_meta_data.clone(),
+        connector_wallets_details: data.connector_wallets_details.clone(),
+        amount_captured: data.amount_captured,
+        minor_amount_captured: data.minor_amount_captured,
+        access_token: data.access_token.clone(),
+        response: data.response.clone(),
+        payment_id: data.payment_id.clone(),
+        session_token: data.session_token.clone(),
+        reference_id: data.reference_id.clone(),
+        customer_id: data.customer_id.clone(),
+        payment_method_token: None,
+        preprocessing_id: None,
+        connector_customer: data.connector_customer.clone(),
+        recurring_mandate_payment_data: data.recurring_mandate_payment_data.clone(),
+        connector_request_reference_id: data.connector_request_reference_id.clone(),
+        #[cfg(feature = "payouts")]
+        payout_method_data: data.payout_method_data.clone(),
+        #[cfg(feature = "payouts")]
+        quote_id: data.quote_id.clone(),
+        test_mode: data.test_mode,
+        payment_method_status: None,
+        payment_method_balance: data.payment_method_balance.clone(),
+        connector_api_version: data.connector_api_version.clone(),
+        connector_http_status_code: data.connector_http_status_code,
+        external_latency: data.external_latency,
+        apple_pay_flow: data.apple_pay_flow.clone(),
+        frm_metadata: data.frm_metadata.clone(),
+        dispute_id: data.dispute_id.clone(),
+        refund_id: data.refund_id.clone(),
+        connector_response: data.connector_response.clone(),
+        integrity_check: Ok(()),
+        additional_merchant_data: data.additional_merchant_data.clone(),
+        header_payload: data.header_payload.clone(),
+        connector_mandate_request_reference_id: data.connector_mandate_request_reference_id.clone(),
+        authentication_id: data.authentication_id.clone(),
+        psd2_sca_exemption_type: data.psd2_sca_exemption_type,
+    }
+}
diff --git a/crates/hyperswitch_domain_models/src/router_request_types.rs b/crates/hyperswitch_domain_models/src/router_request_types.rs
index ff5534dcebc..4671c4552f0 100644
--- a/crates/hyperswitch_domain_models/src/router_request_types.rs
+++ b/crates/hyperswitch_domain_models/src/router_request_types.rs
@@ -918,6 +918,8 @@ pub struct SetupMandateRequestData {
     pub payment_method_type: Option<storage_enums::PaymentMethodType>,
     pub request_incremental_authorization: bool,
     pub metadata: Option<pii::SecretSerdeValue>,
+    pub complete_authorize_url: Option<String>,
+    pub capture_method: Option<storage_enums::CaptureMethod>,
 
     // MinorUnit for amount framework
     pub minor_amount: Option<MinorUnit>,
diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs
index 804516b86a4..f50e28e940a 100644
--- a/crates/router/src/core/payments/transformers.rs
+++ b/crates/router/src/core/payments/transformers.rs
@@ -958,6 +958,8 @@ pub async fn construct_payment_router_data_for_setup_mandate<'a>(
         metadata: payment_data.payment_intent.metadata,
         minor_amount: Some(payment_data.payment_attempt.amount_details.get_net_amount()),
         shipping_cost: payment_data.payment_intent.amount_details.shipping_cost,
+        capture_method: Some(payment_data.payment_intent.capture_method),
+        complete_authorize_url,
     };
     let connector_mandate_request_reference_id = payment_data
         .payment_attempt
@@ -4001,6 +4003,12 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::SetupMandateRequ
             &attempt.merchant_id,
             merchant_connector_account_id_or_connector_name,
         ));
+        let complete_authorize_url = Some(helpers::create_complete_authorize_url(
+            router_base_url,
+            attempt,
+            connector_name,
+            payment_data.creds_identifier.as_deref(),
+        ));
 
         Ok(Self {
             currency: payment_data.currency,
@@ -4032,6 +4040,8 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::SetupMandateRequ
             metadata: payment_data.payment_intent.metadata.clone().map(Into::into),
             shipping_cost: payment_data.payment_intent.shipping_cost,
             webhook_url,
+            complete_authorize_url,
+            capture_method: payment_data.payment_attempt.capture_method,
         })
     }
 }

## 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 -->
Add zero auth mandate flow for nexixpay connector. It uses 3ds payments flow to create  mandates. 

### 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).
-->
We have to add support for zero amount CIT payments for nexixpay so that  merchants can do MIT payments with required value.


## 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)?
-->
Cypress test:
<img width="1728" alt="image" src="https://github.com/user-attachments/assets/63853683-40cd-409c-a3e7-00c1b0ffc0e0" />

Below curls should be used for testing zero auth mandates:
1. Payments CIT
```
curl --location 'localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_PczXRK73enU0k1JDyjEZ8u76iSUxrocg963jiEzfbY7z1ncgosfLvQFlRoHOcux4' \
--data-raw '{
    "amount": 0,
    "currency": "EUR",
    "confirm": false,
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    "authentication_type": "three_ds",
    "return_url": "https://abc.com",
    "email": "something@gmail.com",
    "name": "Joseph Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "Its my first payment request",
    "setup_future_usage": "off_session"
}'
```

2. Confirm CIT
```
curl --location 'http://localhost:8080/payments/pay_I46gW94NSY7cGwi0BTjl/confirm' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_PczXRK73enU0k1JDyjEZ8u76iSUxrocg963jiEzfbY7z1ncgosfLvQFlRoHOcux4' \
--data-raw '{
    "confirm": true,
    "customer_id": "customer123",
    "payment_type": "setup_mandate",
    "customer_acceptance": {
        "acceptance_type": "online",
        "accepted_at": "1963-05-03T04:07:52.723Z",
        "online": {
            "ip_address": "127.0.0.1",
            "user_agent": "amet irure esse"
        }
    },
    "payment_method": "card",
    "payment_method_type": "credit",
    "email": "test@novalnet.de",
    "payment_method_data": {
        "card": {
            "card_number": "4349940199004549",
            "card_exp_month": "12",
            "card_exp_year": "30",
            "card_holder_name": "joseph Doe",
            "card_cvc": "396"
        },
        "billing": {
            "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "IT",
            "first_name": "joseph",
            "last_name": "Doe"
        },
            "email": "test@novalnet.de",
            "phone": {
                "number": "8056594427",
                "country_code": "+91"
            }
        }
    }
}'
```

3. MIT payment
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_PczXRK73enU0k1JDyjEZ8u76iSUxrocg963jiEzfbY7z1ncgosfLvQFlRoHOcux4' \
--data '{
    "amount": 3545,
    "currency": "EUR",
    "confirm": true,
    "customer_id": "customer123",
    "recurring_details": {
        "type": "payment_method_id",
        "data": "pm_unSAF4FSldeu1wAeLvpe"
    },
    "off_session": true
}'
```

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