File: crates/hyperswitch_domain_models/src/lib.rs
 Public functions: 1

pub mod address;
pub mod api;
pub mod authentication;
pub mod behaviour;
pub mod bulk_tokenization;
pub mod business_profile;
pub mod callback_mapper;
pub mod card_testing_guard_data;
pub mod cards_info;
pub mod chat;
pub mod connector_endpoints;
pub mod consts;
pub mod customer;
pub mod disputes;
pub mod errors;
pub mod ext_traits;
pub mod gsm;
pub mod mandates;
pub mod merchant_account;
pub mod merchant_connector_account;
pub mod merchant_context;
pub mod merchant_key_store;
pub mod network_tokenization;
pub mod payment_address;
pub mod payment_method_data;
pub mod payment_methods;
pub mod payments;
#[cfg(feature = "payouts")]
pub mod payouts;
pub mod refunds;
pub mod relay;
#[cfg(all(feature = "v2", feature = "revenue_recovery"))]
pub mod revenue_recovery;
pub mod router_data;
pub mod router_data_v2;
pub mod router_flow_types;
pub mod router_request_types;
pub mod router_response_types;
pub mod routing;
#[cfg(feature = "tokenization_v2")]
pub mod tokenization;
pub mod transformers;
pub mod type_encryption;
pub mod types;
pub mod vault;

#[cfg(not(feature = "payouts"))]
pub trait PayoutAttemptInterface {}

#[cfg(not(feature = "payouts"))]
pub trait PayoutsInterface {}

use api_models::payments::{
    ApplePayRecurringDetails as ApiApplePayRecurringDetails,
    ApplePayRegularBillingDetails as ApiApplePayRegularBillingDetails,
    FeatureMetadata as ApiFeatureMetadata, OrderDetailsWithAmount as ApiOrderDetailsWithAmount,
    RecurringPaymentIntervalUnit as ApiRecurringPaymentIntervalUnit,
    RedirectResponse as ApiRedirectResponse,
};
#[cfg(feature = "v2")]
use api_models::payments::{
    BillingConnectorAdditionalCardInfo as ApiBillingConnectorAdditionalCardInfo,
    BillingConnectorPaymentDetails as ApiBillingConnectorPaymentDetails,
    BillingConnectorPaymentMethodDetails as ApiBillingConnectorPaymentMethodDetails,
    PaymentRevenueRecoveryMetadata as ApiRevenueRecoveryMetadata,
};
use diesel_models::types::{
    ApplePayRecurringDetails, ApplePayRegularBillingDetails, FeatureMetadata,
    OrderDetailsWithAmount, RecurringPaymentIntervalUnit, RedirectResponse,
};
#[cfg(feature = "v2")]
use diesel_models::types::{
    BillingConnectorAdditionalCardInfo, BillingConnectorPaymentDetails,
    BillingConnectorPaymentMethodDetails, PaymentRevenueRecoveryMetadata,
};

#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
pub enum RemoteStorageObject<T: ForeignIDRef> {
    ForeignID(String),
    Object(T),
}

impl<T: ForeignIDRef> From<T> for RemoteStorageObject<T> {
    fn from(value: T) -> Self {
        Self::Object(value)
    }
}

pub trait ForeignIDRef {
    fn foreign_id(&self) -> String;
}

impl<T: ForeignIDRef> RemoteStorageObject<T> {
    pub fn get_id(&self) -> String {
        match self {
            Self::ForeignID(id) => id.clone(),
            Self::Object(i) => i.foreign_id(),
        }
    }
}

use std::fmt::Debug;

pub trait ApiModelToDieselModelConvertor<F> {
    /// Convert from a foreign type to the current type
    fn convert_from(from: F) -> Self;
    fn convert_back(self) -> F;
}

#[cfg(feature = "v1")]
impl ApiModelToDieselModelConvertor<ApiFeatureMetadata> for FeatureMetadata {
    fn convert_from(from: ApiFeatureMetadata) -> Self {
        let ApiFeatureMetadata {
            redirect_response,
            search_tags,
            apple_pay_recurring_details,
        } = from;

        Self {
            redirect_response: redirect_response.map(RedirectResponse::convert_from),
            search_tags,
            apple_pay_recurring_details: apple_pay_recurring_details
                .map(ApplePayRecurringDetails::convert_from),
            gateway_system: None,
        }
    }

    fn convert_back(self) -> ApiFeatureMetadata {
        let Self {
            redirect_response,
            search_tags,
            apple_pay_recurring_details,
            ..
        } = self;

        ApiFeatureMetadata {
            redirect_response: redirect_response
                .map(|redirect_response| redirect_response.convert_back()),
            search_tags,
            apple_pay_recurring_details: apple_pay_recurring_details
                .map(|value| value.convert_back()),
        }
    }
}

#[cfg(feature = "v2")]
impl ApiModelToDieselModelConvertor<ApiFeatureMetadata> for FeatureMetadata {
    fn convert_from(from: ApiFeatureMetadata) -> Self {
        let ApiFeatureMetadata {
            redirect_response,
            search_tags,
            apple_pay_recurring_details,
            revenue_recovery: payment_revenue_recovery_metadata,
        } = from;

        Self {
            redirect_response: redirect_response.map(RedirectResponse::convert_from),
            search_tags,
            apple_pay_recurring_details: apple_pay_recurring_details
                .map(ApplePayRecurringDetails::convert_from),
            payment_revenue_recovery_metadata: payment_revenue_recovery_metadata
                .map(PaymentRevenueRecoveryMetadata::convert_from),
        }
    }

    fn convert_back(self) -> ApiFeatureMetadata {
        let Self {
            redirect_response,
            search_tags,
            apple_pay_recurring_details,
            payment_revenue_recovery_metadata,
        } = self;

        ApiFeatureMetadata {
            redirect_response: redirect_response
                .map(|redirect_response| redirect_response.convert_back()),
            search_tags,
            apple_pay_recurring_details: apple_pay_recurring_details
                .map(|value| value.convert_back()),
            revenue_recovery: payment_revenue_recovery_metadata.map(|value| value.convert_back()),
        }
    }
}

impl ApiModelToDieselModelConvertor<ApiRedirectResponse> for RedirectResponse {
    fn convert_from(from: ApiRedirectResponse) -> Self {
        let ApiRedirectResponse {
            param,
            json_payload,
        } = from;
        Self {
            param,
            json_payload,
        }
    }

    fn convert_back(self) -> ApiRedirectResponse {
        let Self {
            param,
            json_payload,
        } = self;
        ApiRedirectResponse {
            param,
            json_payload,
        }
    }
}

impl ApiModelToDieselModelConvertor<ApiRecurringPaymentIntervalUnit>
    for RecurringPaymentIntervalUnit
{
    fn convert_from(from: ApiRecurringPaymentIntervalUnit) -> Self {
        match from {
            ApiRecurringPaymentIntervalUnit::Year => Self::Year,
            ApiRecurringPaymentIntervalUnit::Month => Self::Month,
            ApiRecurringPaymentIntervalUnit::Day => Self::Day,
            ApiRecurringPaymentIntervalUnit::Hour => Self::Hour,
            ApiRecurringPaymentIntervalUnit::Minute => Self::Minute,
        }
    }
    fn convert_back(self) -> ApiRecurringPaymentIntervalUnit {
        match self {
            Self::Year => ApiRecurringPaymentIntervalUnit::Year,
            Self::Month => ApiRecurringPaymentIntervalUnit::Month,
            Self::Day => ApiRecurringPaymentIntervalUnit::Day,
            Self::Hour => ApiRecurringPaymentIntervalUnit::Hour,
            Self::Minute => ApiRecurringPaymentIntervalUnit::Minute,
        }
    }
}

impl ApiModelToDieselModelConvertor<ApiApplePayRegularBillingDetails>
    for ApplePayRegularBillingDetails
{
    fn convert_from(from: ApiApplePayRegularBillingDetails) -> Self {
        Self {
            label: from.label,
            recurring_payment_start_date: from.recurring_payment_start_date,
            recurring_payment_end_date: from.recurring_payment_end_date,
            recurring_payment_interval_unit: from
                .recurring_payment_interval_unit
                .map(RecurringPaymentIntervalUnit::convert_from),
            recurring_payment_interval_count: from.recurring_payment_interval_count,
        }
    }

    fn convert_back(self) -> ApiApplePayRegularBillingDetails {
        ApiApplePayRegularBillingDetails {
            label: self.label,
            recurring_payment_start_date: self.recurring_payment_start_date,
            recurring_payment_end_date: self.recurring_payment_end_date,
            recurring_payment_interval_unit: self
                .recurring_payment_interval_unit
                .map(|value| value.convert_back()),
            recurring_payment_interval_count: self.recurring_payment_interval_count,
        }
    }
}

impl ApiModelToDieselModelConvertor<ApiApplePayRecurringDetails> for ApplePayRecurringDetails {
    fn convert_from(from: ApiApplePayRecurringDetails) -> Self {
        Self {
            payment_description: from.payment_description,
            regular_billing: ApplePayRegularBillingDetails::convert_from(from.regular_billing),
            billing_agreement: from.billing_agreement,
            management_url: from.management_url,
        }
    }

    fn convert_back(self) -> ApiApplePayRecurringDetails {
        ApiApplePayRecurringDetails {
            payment_description: self.payment_description,
            regular_billing: self.regular_billing.convert_back(),
            billing_agreement: self.billing_agreement,
            management_url: self.management_url,
        }
    }
}

#[cfg(feature = "v2")]
impl ApiModelToDieselModelConvertor<ApiBillingConnectorAdditionalCardInfo>
    for BillingConnectorAdditionalCardInfo
{
    fn convert_from(from: ApiBillingConnectorAdditionalCardInfo) -> Self {
        Self {
            card_issuer: from.card_issuer,
            card_network: from.card_network,
        }
    }

    fn convert_back(self) -> ApiBillingConnectorAdditionalCardInfo {
        ApiBillingConnectorAdditionalCardInfo {
            card_issuer: self.card_issuer,
            card_network: self.card_network,
        }
    }
}

#[cfg(feature = "v2")]
impl ApiModelToDieselModelConvertor<ApiBillingConnectorPaymentMethodDetails>
    for BillingConnectorPaymentMethodDetails
{
    fn convert_from(from: ApiBillingConnectorPaymentMethodDetails) -> Self {
        match from {
            ApiBillingConnectorPaymentMethodDetails::Card(data) => {
                Self::Card(BillingConnectorAdditionalCardInfo::convert_from(data))
            }
        }
    }

    fn convert_back(self) -> ApiBillingConnectorPaymentMethodDetails {
        match self {
            Self::Card(data) => ApiBillingConnectorPaymentMethodDetails::Card(data.convert_back()),
        }
    }
}

#[cfg(feature = "v2")]
impl ApiModelToDieselModelConvertor<ApiRevenueRecoveryMetadata> for PaymentRevenueRecoveryMetadata {
    fn convert_from(from: ApiRevenueRecoveryMetadata) -> Self {
        Self {
            total_retry_count: from.total_retry_count,
            payment_connector_transmission: from.payment_connector_transmission.unwrap_or_default(),
            billing_connector_id: from.billing_connector_id,
            active_attempt_payment_connector_id: from.active_attempt_payment_connector_id,
            billing_connector_payment_details: BillingConnectorPaymentDetails::convert_from(
                from.billing_connector_payment_details,
            ),
            payment_method_type: from.payment_method_type,
            payment_method_subtype: from.payment_method_subtype,
            connector: from.connector,
            invoice_next_billing_time: from.invoice_next_billing_time,
            billing_connector_payment_method_details: from
                .billing_connector_payment_method_details
                .map(BillingConnectorPaymentMethodDetails::convert_from),
            first_payment_attempt_network_advice_code: from
                .first_payment_attempt_network_advice_code,
            first_payment_attempt_network_decline_code: from
                .first_payment_attempt_network_decline_code,
            first_payment_attempt_pg_error_code: from.first_payment_attempt_pg_error_code,
            invoice_billing_started_at_time: from.invoice_billing_started_at_time,
        }
    }

    fn convert_back(self) -> ApiRevenueRecoveryMetadata {
        ApiRevenueRecoveryMetadata {
            total_retry_count: self.total_retry_count,
            payment_connector_transmission: Some(self.payment_connector_transmission),
            billing_connector_id: self.billing_connector_id,
            active_attempt_payment_connector_id: self.active_attempt_payment_connector_id,
            billing_connector_payment_details: self
                .billing_connector_payment_details
                .convert_back(),
            payment_method_type: self.payment_method_type,
            payment_method_subtype: self.payment_method_subtype,
            connector: self.connector,
            invoice_next_billing_time: self.invoice_next_billing_time,
            billing_connector_payment_method_details: self
                .billing_connector_payment_method_details
                .map(|data| data.convert_back()),
            first_payment_attempt_network_advice_code: self
                .first_payment_attempt_network_advice_code,
            first_payment_attempt_network_decline_code: self
                .first_payment_attempt_network_decline_code,
            first_payment_attempt_pg_error_code: self.first_payment_attempt_pg_error_code,
            invoice_billing_started_at_time: self.invoice_billing_started_at_time,
        }
    }
}

#[cfg(feature = "v2")]
impl ApiModelToDieselModelConvertor<ApiBillingConnectorPaymentDetails>
    for BillingConnectorPaymentDetails
{
    fn convert_from(from: ApiBillingConnectorPaymentDetails) -> Self {
        Self {
            payment_processor_token: from.payment_processor_token,
            connector_customer_id: from.connector_customer_id,
        }
    }

    fn convert_back(self) -> ApiBillingConnectorPaymentDetails {
        ApiBillingConnectorPaymentDetails {
            payment_processor_token: self.payment_processor_token,
            connector_customer_id: self.connector_customer_id,
        }
    }
}

impl ApiModelToDieselModelConvertor<ApiOrderDetailsWithAmount> for OrderDetailsWithAmount {
    fn convert_from(from: ApiOrderDetailsWithAmount) -> Self {
        let ApiOrderDetailsWithAmount {
            product_name,
            quantity,
            amount,
            requires_shipping,
            product_img_link,
            product_id,
            category,
            sub_category,
            brand,
            product_type,
            product_tax_code,
            tax_rate,
            total_tax_amount,
            description,
            sku,
            upc,
            commodity_code,
            unit_of_measure,
            total_amount,
            unit_discount_amount,
        } = from;
        Self {
            product_name,
            quantity,
            amount,
            requires_shipping,
            product_img_link,
            product_id,
            category,
            sub_category,
            brand,
            product_type,
            product_tax_code,
            tax_rate,
            total_tax_amount,
            description,
            sku,
            upc,
            commodity_code,
            unit_of_measure,
            total_amount,
            unit_discount_amount,
        }
    }

    fn convert_back(self) -> ApiOrderDetailsWithAmount {
        let Self {
            product_name,
            quantity,
            amount,
            requires_shipping,
            product_img_link,
            product_id,
            category,
            sub_category,
            brand,
            product_type,
            product_tax_code,
            tax_rate,
            total_tax_amount,
            description,
            sku,
            upc,
            commodity_code,
            unit_of_measure,
            total_amount,
            unit_discount_amount,
        } = self;
        ApiOrderDetailsWithAmount {
            product_name,
            quantity,
            amount,
            requires_shipping,
            product_img_link,
            product_id,
            category,
            sub_category,
            brand,
            product_type,
            product_tax_code,
            tax_rate,
            total_tax_amount,
            description,
            sku,
            upc,
            commodity_code,
            unit_of_measure,
            total_amount,
            unit_discount_amount,
        }
    }
}

#[cfg(feature = "v2")]
impl ApiModelToDieselModelConvertor<api_models::admin::PaymentLinkConfigRequest>
    for diesel_models::payment_intent::PaymentLinkConfigRequestForPayments
{
    fn convert_from(item: api_models::admin::PaymentLinkConfigRequest) -> Self {
        Self {
            theme: item.theme,
            logo: item.logo,
            seller_name: item.seller_name,
            sdk_layout: item.sdk_layout,
            display_sdk_only: item.display_sdk_only,
            enabled_saved_payment_method: item.enabled_saved_payment_method,
            hide_card_nickname_field: item.hide_card_nickname_field,
            show_card_form_by_default: item.show_card_form_by_default,
            details_layout: item.details_layout,
            transaction_details: item.transaction_details.map(|transaction_details| {
                transaction_details
                    .into_iter()
                    .map(|transaction_detail| {
                        diesel_models::PaymentLinkTransactionDetails::convert_from(
                            transaction_detail,
                        )
                    })
                    .collect()
            }),
            background_image: item.background_image.map(|background_image| {
                diesel_models::business_profile::PaymentLinkBackgroundImageConfig::convert_from(
                    background_image,
                )
            }),
            payment_button_text: item.payment_button_text,
            custom_message_for_card_terms: item.custom_message_for_card_terms,
            payment_button_colour: item.payment_button_colour,
            skip_status_screen: item.skip_status_screen,
            background_colour: item.background_colour,
            payment_button_text_colour: item.payment_button_text_colour,
            sdk_ui_rules: item.sdk_ui_rules,
            payment_link_ui_rules: item.payment_link_ui_rules,
            enable_button_only_on_form_ready: item.enable_button_only_on_form_ready,
            payment_form_header_text: item.payment_form_header_text,
            payment_form_label_type: item.payment_form_label_type,
            show_card_terms: item.show_card_terms,
            is_setup_mandate_flow: item.is_setup_mandate_flow,
            color_icon_card_cvc_error: item.color_icon_card_cvc_error,
        }
    }
    fn convert_back(self) -> api_models::admin::PaymentLinkConfigRequest {
        let Self {
            theme,
            logo,
            seller_name,
            sdk_layout,
            display_sdk_only,
            enabled_saved_payment_method,
            hide_card_nickname_field,
            show_card_form_by_default,
            transaction_details,
            background_image,
            details_layout,
            payment_button_text,
            custom_message_for_card_terms,
            payment_button_colour,
            skip_status_screen,
            background_colour,
            payment_button_text_colour,
            sdk_ui_rules,
            payment_link_ui_rules,
            enable_button_only_on_form_ready,
            payment_form_header_text,
            payment_form_label_type,
            show_card_terms,
            is_setup_mandate_flow,
            color_icon_card_cvc_error,
        } = self;
        api_models::admin::PaymentLinkConfigRequest {
            theme,
            logo,
            seller_name,
            sdk_layout,
            display_sdk_only,
            enabled_saved_payment_method,
            hide_card_nickname_field,
            show_card_form_by_default,
            details_layout,
            transaction_details: transaction_details.map(|transaction_details| {
                transaction_details
                    .into_iter()
                    .map(|transaction_detail| transaction_detail.convert_back())
                    .collect()
            }),
            background_image: background_image
                .map(|background_image| background_image.convert_back()),
            payment_button_text,
            custom_message_for_card_terms,
            payment_button_colour,
            skip_status_screen,
            background_colour,
            payment_button_text_colour,
            sdk_ui_rules,
            payment_link_ui_rules,
            enable_button_only_on_form_ready,
            payment_form_header_text,
            payment_form_label_type,
            show_card_terms,
            is_setup_mandate_flow,
            color_icon_card_cvc_error,
        }
    }
}

#[cfg(feature = "v2")]
impl ApiModelToDieselModelConvertor<api_models::admin::PaymentLinkTransactionDetails>
    for diesel_models::PaymentLinkTransactionDetails
{
    fn convert_from(from: api_models::admin::PaymentLinkTransactionDetails) -> Self {
        Self {
            key: from.key,
            value: from.value,
            ui_configuration: from
                .ui_configuration
                .map(diesel_models::TransactionDetailsUiConfiguration::convert_from),
        }
    }
    fn convert_back(self) -> api_models::admin::PaymentLinkTransactionDetails {
        let Self {
            key,
            value,
            ui_configuration,
        } = self;
        api_models::admin::PaymentLinkTransactionDetails {
            key,
            value,
            ui_configuration: ui_configuration
                .map(|ui_configuration| ui_configuration.convert_back()),
        }
    }
}

#[cfg(feature = "v2")]
impl ApiModelToDieselModelConvertor<api_models::admin::PaymentLinkBackgroundImageConfig>
    for diesel_models::business_profile::PaymentLinkBackgroundImageConfig
{
    fn convert_from(from: api_models::admin::PaymentLinkBackgroundImageConfig) -> Self {
        Self {
            url: from.url,
            position: from.position,
            size: from.size,
        }
    }
    fn convert_back(self) -> api_models::admin::PaymentLinkBackgroundImageConfig {
        let Self {
            url,
            position,
            size,
        } = self;
        api_models::admin::PaymentLinkBackgroundImageConfig {
            url,
            position,
            size,
        }
    }
}

#[cfg(feature = "v2")]
impl ApiModelToDieselModelConvertor<api_models::admin::TransactionDetailsUiConfiguration>
    for diesel_models::TransactionDetailsUiConfiguration
{
    fn convert_from(from: api_models::admin::TransactionDetailsUiConfiguration) -> Self {
        Self {
            position: from.position,
            is_key_bold: from.is_key_bold,
            is_value_bold: from.is_value_bold,
        }
    }
    fn convert_back(self) -> api_models::admin::TransactionDetailsUiConfiguration {
        let Self {
            position,
            is_key_bold,
            is_value_bold,
        } = self;
        api_models::admin::TransactionDetailsUiConfiguration {
            position,
            is_key_bold,
            is_value_bold,
        }
    }
}

#[cfg(feature = "v2")]
impl From<api_models::payments::AmountDetails> for payments::AmountDetails {
    fn from(amount_details: api_models::payments::AmountDetails) -> Self {
        Self {
            order_amount: amount_details.order_amount().into(),
            currency: amount_details.currency(),
            shipping_cost: amount_details.shipping_cost(),
            tax_details: amount_details.order_tax_amount().map(|order_tax_amount| {
                diesel_models::TaxDetails {
                    default: Some(diesel_models::DefaultTax { order_tax_amount }),
                    payment_method_type: None,
                }
            }),
            skip_external_tax_calculation: amount_details.skip_external_tax_calculation(),
            skip_surcharge_calculation: amount_details.skip_surcharge_calculation(),
            surcharge_amount: amount_details.surcharge_amount(),
            tax_on_surcharge: amount_details.tax_on_surcharge(),
            // We will not receive this in the request. This will be populated after calling the connector / processor
            amount_captured: None,
        }
    }
}

#[cfg(feature = "v2")]
impl From<payments::AmountDetails> for api_models::payments::AmountDetailsSetter {
    fn from(amount_details: payments::AmountDetails) -> Self {
        Self {
            order_amount: amount_details.order_amount.into(),
            currency: amount_details.currency,
            shipping_cost: amount_details.shipping_cost,
            order_tax_amount: amount_details
                .tax_details
                .and_then(|tax_detail| tax_detail.get_default_tax_amount()),
            skip_external_tax_calculation: amount_details.skip_external_tax_calculation,
            skip_surcharge_calculation: amount_details.skip_surcharge_calculation,
            surcharge_amount: amount_details.surcharge_amount,
            tax_on_surcharge: amount_details.tax_on_surcharge,
        }
    }
}
#[cfg(feature = "v2")]
impl From<&api_models::payments::PaymentAttemptAmountDetails>
    for payments::payment_attempt::AttemptAmountDetailsSetter
{
    fn from(amount: &api_models::payments::PaymentAttemptAmountDetails) -> Self {
        Self {
            net_amount: amount.net_amount,
            amount_to_capture: amount.amount_to_capture,
            surcharge_amount: amount.surcharge_amount,
            tax_on_surcharge: amount.tax_on_surcharge,
            amount_capturable: amount.amount_capturable,
            shipping_cost: amount.shipping_cost,
            order_tax_amount: amount.order_tax_amount,
        }
    }
}
#[cfg(feature = "v2")]
impl From<&payments::payment_attempt::AttemptAmountDetailsSetter>
    for api_models::payments::PaymentAttemptAmountDetails
{
    fn from(amount: &payments::payment_attempt::AttemptAmountDetailsSetter) -> Self {
        Self {
            net_amount: amount.net_amount,
            amount_to_capture: amount.amount_to_capture,
            surcharge_amount: amount.surcharge_amount,
            tax_on_surcharge: amount.tax_on_surcharge,
            amount_capturable: amount.amount_capturable,
            shipping_cost: amount.shipping_cost,
            order_tax_amount: amount.order_tax_amount,
        }
    }
}
#[cfg(feature = "v2")]
impl From<&api_models::payments::RecordAttemptErrorDetails>
    for payments::payment_attempt::ErrorDetails
{
    fn from(error: &api_models::payments::RecordAttemptErrorDetails) -> Self {
        Self {
            code: error.code.clone(),
            message: error.message.clone(),
            reason: Some(error.message.clone()),
            unified_code: None,
            unified_message: None,
            network_advice_code: error.network_advice_code.clone(),
            network_decline_code: error.network_decline_code.clone(),
            network_error_message: error.network_error_message.clone(),
        }
    }
}


pub struct NoonPaymentsCancelRequest {
    api_operation: NoonApiOperations,
    order: NoonActionOrder,
}


File: crates/external_services/src/grpc_client/unified_connector_service.rs
 Public functions: 7
 Public structs: 4

use std::collections::{HashMap, HashSet};

use common_enums::connector_enums::Connector;
use common_utils::{consts as common_utils_consts, errors::CustomResult, types::Url};
use error_stack::ResultExt;
use masking::{PeekInterface, Secret};
use router_env::logger;
use tokio::time::{timeout, Duration};
use tonic::{
    metadata::{MetadataMap, MetadataValue},
    transport::Uri,
};
use unified_connector_service_client::payments::{
    self as payments_grpc, payment_service_client::PaymentServiceClient,
    PaymentServiceAuthorizeResponse, PaymentServiceTransformRequest,
    PaymentServiceTransformResponse,
};

use crate::{
    consts,
    grpc_client::{GrpcClientSettings, GrpcHeaders},
    utils::deserialize_hashset,
};

/// Unified Connector Service error variants
#[derive(Debug, Clone, thiserror::Error)]
pub enum UnifiedConnectorServiceError {
    /// Error occurred while communicating with the gRPC server.
    #[error("Error from gRPC Server : {0}")]
    ConnectionError(String),

    /// Failed to encode the request to the unified connector service.
    #[error("Failed to encode unified connector service request")]
    RequestEncodingFailed,

    /// Request encoding failed due to a specific reason.
    #[error("Request encoding failed : {0}")]
    RequestEncodingFailedWithReason(String),

    /// Failed to deserialize the response from the connector.
    #[error("Failed to deserialize connector response")]
    ResponseDeserializationFailed,

    /// The connector name provided is invalid or unrecognized.
    #[error("An invalid connector name was provided")]
    InvalidConnectorName,

    /// Connector name is missing
    #[error("Connector name is missing")]
    MissingConnectorName,

    /// A required field was missing in the request.
    #[error("Missing required field: {field_name}")]
    MissingRequiredField {
        /// Missing Field
        field_name: &'static str,
    },

    /// Multiple required fields were missing in the request.
    #[error("Missing required fields: {field_names:?}")]
    MissingRequiredFields {
        /// Missing Fields
        field_names: Vec<&'static str>,
    },

    /// The requested step or feature is not yet implemented.
    #[error("This step has not been implemented for: {0}")]
    NotImplemented(String),

    /// Parsing of some value or input failed.
    #[error("Parsing failed")]
    ParsingFailed,

    /// Data format provided is invalid
    #[error("Invalid Data format")]
    InvalidDataFormat {
        /// Field Name for which data is invalid
        field_name: &'static str,
    },

    /// Failed to obtain authentication type
    #[error("Failed to obtain authentication type")]
    FailedToObtainAuthType,

    /// Failed to inject metadata into request headers
    #[error("Failed to inject metadata into request headers: {0}")]
    HeaderInjectionFailed(String),

    /// Failed to perform Payment Authorize from gRPC Server
    #[error("Failed to perform Payment Authorize from gRPC Server")]
    PaymentAuthorizeFailure,

    /// Failed to perform Payment Get from gRPC Server
    #[error("Failed to perform Payment Get from gRPC Server")]
    PaymentGetFailure,

    /// Failed to perform Payment Setup Mandate from gRPC Server
    #[error("Failed to perform Setup Mandate from gRPC Server")]
    PaymentRegisterFailure,

    /// Failed to perform Payment Repeat Payment from gRPC Server
    #[error("Failed to perform Repeat Payment from gRPC Server")]
    PaymentRepeatEverythingFailure,

    /// Failed to transform incoming webhook from gRPC Server
    #[error("Failed to transform incoming webhook from gRPC Server")]
    WebhookTransformFailure,
}

/// Result type for Dynamic Routing
pub type UnifiedConnectorServiceResult<T> = CustomResult<T, UnifiedConnectorServiceError>;
/// Contains the  Unified Connector Service client
#[derive(Debug, Clone)]
pub struct UnifiedConnectorServiceClient {
    /// The Unified Connector Service Client
    pub client: PaymentServiceClient<tonic::transport::Channel>,
}

/// Contains the Unified Connector Service Client config
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct UnifiedConnectorServiceClientConfig {
    /// Base URL of the gRPC Server
    pub base_url: Url,

    /// Contains the connection timeout duration in seconds
    pub connection_timeout: u64,

    /// Set of external services/connectors available for the unified connector service
    #[serde(default, deserialize_with = "deserialize_hashset")]
    pub ucs_only_connectors: HashSet<Connector>,

    /// Set of connectors for which psync is disabled in unified connector service
    #[serde(default, deserialize_with = "deserialize_hashset")]
    pub ucs_psync_disabled_connectors: HashSet<Connector>,
}

/// Contains the Connector Auth Type and related authentication data.
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct ConnectorAuthMetadata {
    /// Name of the connector (e.g., "stripe", "paypal").
    pub connector_name: String,

    /// Type of authentication used (e.g., "HeaderKey", "BodyKey", "SignatureKey").
    pub auth_type: String,

    /// Optional API key used for authentication.
    pub api_key: Option<Secret<String>>,

    /// Optional additional key used by some authentication types.
    pub key1: Option<Secret<String>>,

    /// Optional API secret used for signature or secure authentication.
    pub api_secret: Option<Secret<String>>,

    /// Optional auth_key_map used for authentication.
    pub auth_key_map:
        Option<HashMap<common_enums::enums::Currency, common_utils::pii::SecretSerdeValue>>,

    /// Id of the merchant.
    pub merchant_id: Secret<String>,
}

/// External Vault Proxy Related Metadata
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
#[serde(untagged)]
pub enum ExternalVaultProxyMetadata {
    /// VGS proxy data variant
    VgsMetadata(VgsMetadata),
}

/// VGS proxy data
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct VgsMetadata {
    /// External vault url
    pub proxy_url: Url,
    /// CA certificates to verify the vault server
    pub certificate: Secret<String>,
}

impl UnifiedConnectorServiceClient {
    /// Builds the connection to the gRPC service
    pub async fn build_connections(config: &GrpcClientSettings) -> Option<Self> {
        match &config.unified_connector_service {
            Some(unified_connector_service_client_config) => {
                let uri: Uri = match unified_connector_service_client_config
                    .base_url
                    .get_string_repr()
                    .parse()
                {
                    Ok(parsed_uri) => parsed_uri,
                    Err(err) => {
                        logger::error!(error = ?err, "Failed to parse URI for Unified Connector Service");
                        return None;
                    }
                };

                let connect_result = timeout(
                    Duration::from_secs(unified_connector_service_client_config.connection_timeout),
                    PaymentServiceClient::connect(uri),
                )
                .await;

                match connect_result {
                    Ok(Ok(client)) => {
                        logger::info!("Successfully connected to Unified Connector Service");
                        Some(Self { client })
                    }
                    Ok(Err(err)) => {
                        logger::error!(error = ?err, "Failed to connect to Unified Connector Service");
                        None
                    }
                    Err(err) => {
                        logger::error!(error = ?err, "Connection to Unified Connector Service timed out");
                        None
                    }
                }
            }
            None => {
                router_env::logger::error!(?config.unified_connector_service, "Unified Connector Service config is missing");
                None
            }
        }
    }

    /// Performs Payment Authorize
    pub async fn payment_authorize(
        &self,
        payment_authorize_request: payments_grpc::PaymentServiceAuthorizeRequest,
        connector_auth_metadata: ConnectorAuthMetadata,
        external_vault_proxy_metadata: Option<String>,
        grpc_headers: GrpcHeaders,
    ) -> UnifiedConnectorServiceResult<tonic::Response<PaymentServiceAuthorizeResponse>> {
        let mut request = tonic::Request::new(payment_authorize_request);

        let connector_name = connector_auth_metadata.connector_name.clone();
        let metadata = build_unified_connector_service_grpc_headers(
            connector_auth_metadata,
            external_vault_proxy_metadata,
            grpc_headers,
        )?;

        *request.metadata_mut() = metadata;

        self.client
            .clone()
            .authorize(request)
            .await
            .change_context(UnifiedConnectorServiceError::PaymentAuthorizeFailure)
            .inspect_err(|error| {
                logger::error!(
                    grpc_error=?error,
                    method="payment_authorize",
                    connector_name=?connector_name,
                    "UCS payment authorize gRPC call failed"
                )
            })
    }

    /// Performs Payment Sync/Get
    pub async fn payment_get(
        &self,
        payment_get_request: payments_grpc::PaymentServiceGetRequest,
        connector_auth_metadata: ConnectorAuthMetadata,
        grpc_headers: GrpcHeaders,
    ) -> UnifiedConnectorServiceResult<tonic::Response<payments_grpc::PaymentServiceGetResponse>>
    {
        let mut request = tonic::Request::new(payment_get_request);

        let connector_name = connector_auth_metadata.connector_name.clone();
        let metadata = build_unified_connector_service_grpc_headers(
            connector_auth_metadata,
            None,
            grpc_headers,
        )?;
        *request.metadata_mut() = metadata;

        self.client
            .clone()
            .get(request)
            .await
            .change_context(UnifiedConnectorServiceError::PaymentGetFailure)
            .inspect_err(|error| {
                logger::error!(
                    grpc_error=?error,
                    method="payment_get",
                    connector_name=?connector_name,
                    "UCS payment get/sync gRPC call failed"
                )
            })
    }

    /// Performs Payment Setup Mandate
    pub async fn payment_setup_mandate(
        &self,
        payment_register_request: payments_grpc::PaymentServiceRegisterRequest,
        connector_auth_metadata: ConnectorAuthMetadata,
        grpc_headers: GrpcHeaders,
    ) -> UnifiedConnectorServiceResult<tonic::Response<payments_grpc::PaymentServiceRegisterResponse>>
    {
        let mut request = tonic::Request::new(payment_register_request);

        let connector_name = connector_auth_metadata.connector_name.clone();
        let metadata = build_unified_connector_service_grpc_headers(
            connector_auth_metadata,
            None,
            grpc_headers,
        )?;
        *request.metadata_mut() = metadata;

        self.client
            .clone()
            .register(request)
            .await
            .change_context(UnifiedConnectorServiceError::PaymentRegisterFailure)
            .inspect_err(|error| {
                logger::error!(
                    grpc_error=?error,
                    method="payment_setup_mandate",
                    connector_name=?connector_name,
                    "UCS payment setup mandate gRPC call failed"
                )
            })
    }

    /// Performs Payment repeat (MIT - Merchant Initiated Transaction).
    pub async fn payment_repeat(
        &self,
        payment_repeat_request: payments_grpc::PaymentServiceRepeatEverythingRequest,
        connector_auth_metadata: ConnectorAuthMetadata,
        grpc_headers: GrpcHeaders,
    ) -> UnifiedConnectorServiceResult<
        tonic::Response<payments_grpc::PaymentServiceRepeatEverythingResponse>,
    > {
        let mut request = tonic::Request::new(payment_repeat_request);

        let connector_name = connector_auth_metadata.connector_name.clone();
        let metadata = build_unified_connector_service_grpc_headers(
            connector_auth_metadata,
            None,
            grpc_headers,
        )?;
        *request.metadata_mut() = metadata;

        self.client
            .clone()
            .repeat_everything(request)
            .await
            .change_context(UnifiedConnectorServiceError::PaymentRepeatEverythingFailure)
            .inspect_err(|error| {
                logger::error!(
                    grpc_error=?error,
                    method="payment_repeat",
                    connector_name=?connector_name,
                    "UCS payment repeat gRPC call failed"
                )
            })
    }

    /// Transforms incoming webhook through UCS
    pub async fn transform_incoming_webhook(
        &self,
        webhook_transform_request: PaymentServiceTransformRequest,
        connector_auth_metadata: ConnectorAuthMetadata,
        grpc_headers: GrpcHeaders,
    ) -> UnifiedConnectorServiceResult<tonic::Response<PaymentServiceTransformResponse>> {
        let mut request = tonic::Request::new(webhook_transform_request);

        let connector_name = connector_auth_metadata.connector_name.clone();
        let metadata = build_unified_connector_service_grpc_headers(
            connector_auth_metadata,
            None,
            grpc_headers,
        )?;
        *request.metadata_mut() = metadata;

        self.client
            .clone()
            .transform(request)
            .await
            .change_context(UnifiedConnectorServiceError::WebhookTransformFailure)
            .inspect_err(|error| {
                logger::error!(
                    grpc_error=?error,
                    method="transform_incoming_webhook",
                    connector_name=?connector_name,
                    "UCS webhook transform gRPC call failed"
                )
            })
    }
}

/// Build the gRPC Headers for Unified Connector Service Request
pub fn build_unified_connector_service_grpc_headers(
    meta: ConnectorAuthMetadata,
    external_vault_proxy_metadata: Option<String>,
    grpc_headers: GrpcHeaders,
) -> Result<MetadataMap, UnifiedConnectorServiceError> {
    let mut metadata = MetadataMap::new();
    let parse =
        |key: &str, value: &str| -> Result<MetadataValue<_>, UnifiedConnectorServiceError> {
            value.parse::<MetadataValue<_>>().map_err(|error| {
                logger::error!(?error);
                UnifiedConnectorServiceError::HeaderInjectionFailed(key.to_string())
            })
        };

    metadata.append(
        consts::UCS_HEADER_CONNECTOR,
        parse("connector", &meta.connector_name)?,
    );
    metadata.append(
        consts::UCS_HEADER_AUTH_TYPE,
        parse("auth_type", &meta.auth_type)?,
    );

    if let Some(api_key) = meta.api_key {
        metadata.append(
            consts::UCS_HEADER_API_KEY,
            parse("api_key", api_key.peek())?,
        );
    }
    if let Some(key1) = meta.key1 {
        metadata.append(consts::UCS_HEADER_KEY1, parse("key1", key1.peek())?);
    }
    if let Some(api_secret) = meta.api_secret {
        metadata.append(
            consts::UCS_HEADER_API_SECRET,
            parse("api_secret", api_secret.peek())?,
        );
    }
    if let Some(auth_key_map) = meta.auth_key_map {
        let auth_key_map_str = serde_json::to_string(&auth_key_map).map_err(|error| {
            logger::error!(?error);
            UnifiedConnectorServiceError::ParsingFailed
        })?;
        metadata.append(
            consts::UCS_HEADER_AUTH_KEY_MAP,
            parse("auth_key_map", &auth_key_map_str)?,
        );
    }

    metadata.append(
        common_utils_consts::X_MERCHANT_ID,
        parse(common_utils_consts::X_MERCHANT_ID, meta.merchant_id.peek())?,
    );

    if let Some(external_vault_proxy_metadata) = external_vault_proxy_metadata {
        metadata.append(
            consts::UCS_HEADER_EXTERNAL_VAULT_METADATA,
            parse("external_vault_metadata", &external_vault_proxy_metadata)?,
        );
    };

    if let Err(err) = grpc_headers
        .tenant_id
        .parse()
        .map(|tenant_id| metadata.append(common_utils_consts::TENANT_HEADER, tenant_id))
    {
        logger::error!(
            header_parse_error=?err,
            tenant_id=?grpc_headers.tenant_id,
            "Failed to parse tenant_id header for UCS gRPC request: {}",
            common_utils_consts::TENANT_HEADER
        );
    }

    Ok(metadata)
}


pub struct DeviceRenderOptions {
    pub sdk_interface: String,
    pub sdk_ui_type: Vec<String>,
}


pub struct CybersourcePaymentsCaptureRequest {
    processing_information: ProcessingInformation,
    order_information: OrderInformationWithBill,
    client_reference_information: ClientReferenceInformation,
    #[serde(skip_serializing_if = "Option::is_none")]
    merchant_defined_information: Option<Vec<MerchantDefinedInformation>>,
}


pub async fn insert(self, conn: &PgPooledConn) -> StorageResult<Event> {
        generics::generic_insert(conn, self).await
    }


File: crates/hyperswitch_connectors/src/connectors/celero/transformers.rs
 Public functions: 4
 Public structs: 19

use common_enums::{enums, Currency};
use common_utils::{id_type::CustomerId, pii::Email, types::MinorUnit};
use hyperswitch_domain_models::{
    address::Address as DomainAddress,
    payment_method_data::PaymentMethodData,
    router_data::{
        AdditionalPaymentMethodConnectorResponse, ConnectorAuthType, ConnectorResponseData,
        RouterData,
    },
    router_flow_types::{
        payments::Capture,
        refunds::{Execute, RSync},
    },
    router_request_types::{PaymentsCaptureData, ResponseId},
    router_response_types::{MandateReference, PaymentsResponseData, RefundsResponseData},
    types::{
        PaymentsAuthorizeRouterData, PaymentsCaptureRouterData, PaymentsSyncRouterData,
        RefundSyncRouterData, RefundsRouterData,
    },
};
use hyperswitch_interfaces::{
    consts,
    errors::{self},
};
use masking::{PeekInterface, Secret};
use serde::{Deserialize, Serialize};

use crate::{
    types::{RefundsResponseRouterData, ResponseRouterData},
    utils::{
        get_unimplemented_payment_method_error_message, AddressDetailsData,
        PaymentsAuthorizeRequestData, RefundsRequestData, RouterData as _,
    },
};

//TODO: Fill the struct with respective fields
pub struct CeleroRouterData<T> {
    pub amount: MinorUnit, // CeleroCommerce expects integer cents
    pub router_data: T,
}

impl<T> TryFrom<(MinorUnit, T)> for CeleroRouterData<T> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from((amount, item): (MinorUnit, T)) -> Result<Self, Self::Error> {
        Ok(Self {
            amount,
            router_data: item,
        })
    }
}
// CeleroCommerce Search Request for sync operations - POST /api/transaction/search
#[derive(Debug, Serialize, PartialEq)]
pub struct CeleroSearchRequest {
    transaction_id: String,
}

impl TryFrom<&PaymentsSyncRouterData> for CeleroSearchRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &PaymentsSyncRouterData) -> Result<Self, Self::Error> {
        let transaction_id = match &item.request.connector_transaction_id {
            ResponseId::ConnectorTransactionId(id) => id.clone(),
            _ => {
                return Err(errors::ConnectorError::MissingConnectorTransactionID.into());
            }
        };
        Ok(Self { transaction_id })
    }
}

impl TryFrom<&RefundSyncRouterData> for CeleroSearchRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &RefundSyncRouterData) -> Result<Self, Self::Error> {
        Ok(Self {
            transaction_id: item.request.get_connector_refund_id()?,
        })
    }
}

// CeleroCommerce Payment Request according to API specs
#[derive(Debug, Serialize, PartialEq)]
pub struct CeleroPaymentsRequest {
    idempotency_key: String,
    #[serde(rename = "type")]
    transaction_type: TransactionType,
    amount: MinorUnit, // CeleroCommerce expects integer cents
    currency: Currency,
    payment_method: CeleroPaymentMethod,
    #[serde(skip_serializing_if = "Option::is_none")]
    billing_address: Option<CeleroAddress>,
    #[serde(skip_serializing_if = "Option::is_none")]
    shipping_address: Option<CeleroAddress>,
    #[serde(skip_serializing_if = "Option::is_none")]
    create_vault_record: Option<bool>,
    // CIT/MIT fields
    #[serde(skip_serializing_if = "Option::is_none")]
    card_on_file_indicator: Option<CardOnFileIndicator>,
    #[serde(skip_serializing_if = "Option::is_none")]
    initiated_by: Option<InitiatedBy>,
    #[serde(skip_serializing_if = "Option::is_none")]
    initial_transaction_id: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    stored_credential_indicator: Option<StoredCredentialIndicator>,
    #[serde(skip_serializing_if = "Option::is_none")]
    billing_method: Option<BillingMethod>,
}

#[derive(Debug, Serialize, PartialEq)]
pub struct CeleroAddress {
    first_name: Option<Secret<String>>,
    last_name: Option<Secret<String>>,
    address_line_1: Option<Secret<String>>,
    address_line_2: Option<Secret<String>>,
    city: Option<String>,
    state: Option<Secret<String>>,
    postal_code: Option<Secret<String>>,
    country: Option<common_enums::CountryAlpha2>,
    phone: Option<Secret<String>>,
    email: Option<Email>,
}

impl TryFrom<&DomainAddress> for CeleroAddress {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(address: &DomainAddress) -> Result<Self, Self::Error> {
        let address_details = address.address.as_ref();
        match address_details {
            Some(address_details) => Ok(Self {
                first_name: address_details.get_optional_first_name(),
                last_name: address_details.get_optional_last_name(),
                address_line_1: address_details.get_optional_line1(),
                address_line_2: address_details.get_optional_line2(),
                city: address_details.get_optional_city(),
                state: address_details.get_optional_state(),
                postal_code: address_details.get_optional_zip(),
                country: address_details.get_optional_country(),
                phone: address
                    .phone
                    .as_ref()
                    .and_then(|phone| phone.number.clone()),
                email: address.email.clone(),
            }),
            None => Err(errors::ConnectorError::MissingRequiredField {
                field_name: "address_details",
            }
            .into()),
        }
    }
}

#[derive(Debug, Serialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum CeleroPaymentMethod {
    Card(CeleroCard),
    Customer(CeleroCustomer),
}

#[derive(Debug, Serialize, PartialEq)]
pub struct CeleroCustomer {
    id: Option<CustomerId>,
    payment_method_id: Option<String>,
}
#[derive(Debug, Serialize, PartialEq, Clone, Copy)]
#[serde(rename_all = "lowercase")]
pub enum CeleroEntryType {
    Keyed,
}

#[derive(Debug, Serialize, PartialEq)]
pub struct CeleroCard {
    entry_type: CeleroEntryType,
    number: cards::CardNumber,
    expiration_date: Secret<String>,
    cvc: Secret<String>,
}

impl TryFrom<&PaymentMethodData> for CeleroPaymentMethod {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &PaymentMethodData) -> Result<Self, Self::Error> {
        match item {
            PaymentMethodData::Card(req_card) => {
                let card = CeleroCard {
                    entry_type: CeleroEntryType::Keyed,
                    number: req_card.card_number.clone(),
                    expiration_date: Secret::new(format!(
                        "{}/{}",
                        req_card.card_exp_month.peek(),
                        req_card.card_exp_year.peek()
                    )),
                    cvc: req_card.card_cvc.clone(),
                };
                Ok(Self::Card(card))
            }
            PaymentMethodData::CardDetailsForNetworkTransactionId(_)
            | PaymentMethodData::CardRedirect(_)
            | PaymentMethodData::Wallet(_)
            | PaymentMethodData::PayLater(_)
            | PaymentMethodData::BankRedirect(_)
            | PaymentMethodData::BankDebit(_)
            | PaymentMethodData::BankTransfer(_)
            | PaymentMethodData::Crypto(_)
            | PaymentMethodData::MandatePayment
            | PaymentMethodData::Reward
            | PaymentMethodData::RealTimePayment(_)
            | PaymentMethodData::Upi(_)
            | PaymentMethodData::Voucher(_)
            | PaymentMethodData::GiftCard(_)
            | PaymentMethodData::CardToken(_)
            | PaymentMethodData::OpenBanking(_)
            | PaymentMethodData::NetworkToken(_)
            | PaymentMethodData::MobilePayment(_) => Err(errors::ConnectorError::NotImplemented(
                "Selected payment method through celero".to_string(),
            )
            .into()),
        }
    }
}

// Implementation for handling 3DS specifically
impl TryFrom<(&PaymentMethodData, bool)> for CeleroPaymentMethod {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from((item, is_three_ds): (&PaymentMethodData, bool)) -> Result<Self, Self::Error> {
        // If 3DS is requested, return an error
        if is_three_ds {
            return Err(errors::ConnectorError::NotSupported {
                message: "Cards 3DS".to_string(),
                connector: "celero",
            }
            .into());
        }

        // Otherwise, delegate to the standard implementation
        Self::try_from(item)
    }
}

impl TryFrom<&CeleroRouterData<&PaymentsAuthorizeRouterData>> for CeleroPaymentsRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: &CeleroRouterData<&PaymentsAuthorizeRouterData>,
    ) -> Result<Self, Self::Error> {
        let is_auto_capture = item.router_data.request.is_auto_capture()?;
        let transaction_type = if is_auto_capture {
            TransactionType::Sale
        } else {
            TransactionType::Authorize
        };

        let billing_address: Option<CeleroAddress> = item
            .router_data
            .get_optional_billing()
            .and_then(|address| address.try_into().ok());

        let shipping_address: Option<CeleroAddress> = item
            .router_data
            .get_optional_shipping()
            .and_then(|address| address.try_into().ok());

        // Determine CIT/MIT fields based on mandate data
        let (mandate_fields, payment_method) = determine_cit_mit_fields(item.router_data)?;

        let request = Self {
            idempotency_key: item.router_data.connector_request_reference_id.clone(),
            transaction_type,
            amount: item.amount,
            currency: item.router_data.request.currency,
            payment_method,
            billing_address,
            shipping_address,
            create_vault_record: Some(false),
            card_on_file_indicator: mandate_fields.card_on_file_indicator,
            initiated_by: mandate_fields.initiated_by,
            initial_transaction_id: mandate_fields.initial_transaction_id,
            stored_credential_indicator: mandate_fields.stored_credential_indicator,
            billing_method: mandate_fields.billing_method,
        };

        Ok(request)
    }
}

// Define a struct to hold CIT/MIT fields to avoid complex tuple return type
#[derive(Debug, Default)]
pub struct CeleroMandateFields {
    pub card_on_file_indicator: Option<CardOnFileIndicator>,
    pub initiated_by: Option<InitiatedBy>,
    pub initial_transaction_id: Option<String>,
    pub stored_credential_indicator: Option<StoredCredentialIndicator>,
    pub billing_method: Option<BillingMethod>,
}

// Helper function to determine CIT/MIT fields based on mandate data
fn determine_cit_mit_fields(
    router_data: &PaymentsAuthorizeRouterData,
) -> Result<(CeleroMandateFields, CeleroPaymentMethod), error_stack::Report<errors::ConnectorError>>
{
    // Default null values
    let mut mandate_fields = CeleroMandateFields::default();

    // First check if there's a mandate_id in the request
    match router_data
        .request
        .mandate_id
        .clone()
        .and_then(|mandate_ids| mandate_ids.mandate_reference_id)
    {
        // If there's a connector mandate ID, this is a MIT (Merchant Initiated Transaction)
        Some(api_models::payments::MandateReferenceId::ConnectorMandateId(
            connector_mandate_id,
        )) => {
            mandate_fields.card_on_file_indicator = Some(CardOnFileIndicator::RecurringPayment);
            mandate_fields.initiated_by = Some(InitiatedBy::Merchant); // This is a MIT
            mandate_fields.stored_credential_indicator = Some(StoredCredentialIndicator::Used);
            mandate_fields.billing_method = Some(BillingMethod::Recurring);
            mandate_fields.initial_transaction_id =
                connector_mandate_id.get_connector_mandate_request_reference_id();
            Ok((
                mandate_fields,
                CeleroPaymentMethod::Customer(CeleroCustomer {
                    id: Some(router_data.get_customer_id()?),
                    payment_method_id: connector_mandate_id.get_payment_method_id(),
                }),
            ))
        }
        // For other mandate types that might not be supported
        Some(api_models::payments::MandateReferenceId::NetworkMandateId(_))
        | Some(api_models::payments::MandateReferenceId::NetworkTokenWithNTI(_)) => {
            // These might need different handling or return an error
            Err(errors::ConnectorError::NotImplemented(
                get_unimplemented_payment_method_error_message("Celero"),
            )
            .into())
        }
        // If no mandate ID is present, check if it's a mandate payment
        None => {
            if router_data.request.is_mandate_payment() {
                // This is a customer-initiated transaction for a recurring payment
                mandate_fields.initiated_by = Some(InitiatedBy::Customer);
                mandate_fields.card_on_file_indicator = Some(CardOnFileIndicator::RecurringPayment);
                mandate_fields.billing_method = Some(BillingMethod::Recurring);
                mandate_fields.stored_credential_indicator = Some(StoredCredentialIndicator::Used);
            }
            let is_three_ds = router_data.is_three_ds();
            Ok((
                mandate_fields,
                CeleroPaymentMethod::try_from((
                    &router_data.request.payment_method_data,
                    is_three_ds,
                ))?,
            ))
        }
    }
}

// Auth Struct for CeleroCommerce API key authentication
pub struct CeleroAuthType {
    pub(super) api_key: Secret<String>,
}

impl TryFrom<&ConnectorAuthType> for CeleroAuthType {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
        match auth_type {
            ConnectorAuthType::HeaderKey { api_key } => Ok(Self {
                api_key: api_key.clone(),
            }),
            _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
        }
    }
}
// CeleroCommerce API Response Structures
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum CeleroResponseStatus {
    #[serde(alias = "success", alias = "Success", alias = "SUCCESS")]
    Success,
    #[serde(alias = "error", alias = "Error", alias = "ERROR")]
    Error,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum CeleroTransactionStatus {
    Approved,
    Declined,
    Error,
    Pending,
    PendingSettlement,
    Settled,
    Voided,
    Reversed,
}

impl From<CeleroTransactionStatus> for common_enums::AttemptStatus {
    fn from(item: CeleroTransactionStatus) -> Self {
        match item {
            CeleroTransactionStatus::Approved => Self::Authorized,
            CeleroTransactionStatus::Settled => Self::Charged,
            CeleroTransactionStatus::Declined | CeleroTransactionStatus::Error => Self::Failure,
            CeleroTransactionStatus::Pending | CeleroTransactionStatus::PendingSettlement => {
                Self::Pending
            }
            CeleroTransactionStatus::Voided | CeleroTransactionStatus::Reversed => Self::Voided,
        }
    }
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CeleroCardResponse {
    pub status: CeleroTransactionStatus,
    pub auth_code: Option<String>,
    pub processor_response_code: Option<String>,
    pub avs_response_code: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum CeleroPaymentMethodResponse {
    Card(CeleroCardResponse),
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum TransactionType {
    Sale,
    Authorize,
}

// CIT/MIT related enums
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum CardOnFileIndicator {
    #[serde(rename = "C")]
    GeneralPurposeStorage,
    #[serde(rename = "R")]
    RecurringPayment,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum InitiatedBy {
    Customer,
    Merchant,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum StoredCredentialIndicator {
    Used,
    Stored,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum BillingMethod {
    Straight,
    #[serde(rename = "initial_recurring")]
    InitialRecurring,
    Recurring,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde_with::skip_serializing_none]
pub struct CeleroTransactionResponseData {
    pub id: String,
    #[serde(rename = "type")]
    pub transaction_type: TransactionType,
    pub amount: i64,
    pub currency: String,
    pub response: CeleroPaymentMethodResponse,
    pub billing_address: Option<CeleroAddressResponse>,
    pub shipping_address: Option<CeleroAddressResponse>,
    // Additional fields from the sample response
    pub status: Option<String>,
    pub response_code: Option<i32>,
    pub customer_id: Option<String>,
    pub payment_method_id: Option<String>,
}

impl CeleroTransactionResponseData {
    pub fn get_mandate_reference(&self) -> Box<Option<MandateReference>> {
        if self.payment_method_id.is_some() {
            Box::new(Some(MandateReference {
                connector_mandate_id: None,
                payment_method_id: self.payment_method_id.clone(),
                mandate_metadata: None,
                connector_mandate_request_reference_id: Some(self.id.clone()),
            }))
        } else {
            Box::new(None)
        }
    }
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct CeleroAddressResponse {
    first_name: Option<Secret<String>>,
    last_name: Option<Secret<String>>,
    address_line_1: Option<Secret<String>>,
    address_line_2: Option<Secret<String>>,
    city: Option<String>,
    state: Option<Secret<String>>,
    postal_code: Option<Secret<String>>,
    country: Option<common_enums::CountryAlpha2>,
    phone: Option<Secret<String>>,
    email: Option<Secret<String>>,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct CeleroPaymentsResponse {
    pub status: CeleroResponseStatus,
    pub msg: String,
    pub data: Option<CeleroTransactionResponseData>,
}

impl<F, T> TryFrom<ResponseRouterData<F, CeleroPaymentsResponse, T, PaymentsResponseData>>
    for RouterData<F, T, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<F, CeleroPaymentsResponse, T, PaymentsResponseData>,
    ) -> Result<Self, Self::Error> {
        match item.response.status {
            CeleroResponseStatus::Success => {
                if let Some(data) = item.response.data {
                    let CeleroPaymentMethodResponse::Card(response) = &data.response;
                    // Check if transaction itself failed despite successful API call
                    match response.status {
                        CeleroTransactionStatus::Declined | CeleroTransactionStatus::Error => {
                            // Transaction failed - create error response with transaction details
                            let error_details = CeleroErrorDetails::from_transaction_response(
                                response,
                                item.response.msg,
                            );

                            Ok(Self {
                                status: common_enums::AttemptStatus::Failure,
                                response: Err(
                                    hyperswitch_domain_models::router_data::ErrorResponse {
                                        code: error_details
                                            .error_code
                                            .unwrap_or_else(|| "TRANSACTION_FAILED".to_string()),
                                        message: error_details.error_message,
                                        reason: error_details.decline_reason,
                                        status_code: item.http_code,
                                        attempt_status: None,
                                        connector_transaction_id: Some(data.id),
                                        network_decline_code: None,
                                        network_advice_code: None,
                                        network_error_message: None,
                                        connector_metadata: None,
                                    },
                                ),
                                ..item.data
                            })
                        }
                        _ => {
                            let connector_response_data =
                                convert_to_additional_payment_method_connector_response(
                                    response.avs_response_code.clone(),
                                )
                                .map(ConnectorResponseData::with_additional_payment_method_data);
                            let final_status: enums::AttemptStatus = response.status.into();
                            Ok(Self {
                                status: final_status,
                                response: Ok(PaymentsResponseData::TransactionResponse {
                                    resource_id: ResponseId::ConnectorTransactionId(
                                        data.id.clone(),
                                    ),
                                    redirection_data: Box::new(None),
                                    mandate_reference: data.get_mandate_reference(),
                                    connector_metadata: None,
                                    network_txn_id: None,
                                    connector_response_reference_id: response.auth_code.clone(),
                                    incremental_authorization_allowed: None,
                                    charges: None,
                                }),
                                connector_response: connector_response_data,
                                ..item.data
                            })
                        }
                    }
                } else {
                    // No transaction data in successful response
                    // We don't have a transaction ID in this case
                    Ok(Self {
                        status: common_enums::AttemptStatus::Failure,
                        response: Err(hyperswitch_domain_models::router_data::ErrorResponse {
                            code: "MISSING_DATA".to_string(),
                            message: "No transaction data in response".to_string(),
                            reason: Some(item.response.msg),
                            status_code: item.http_code,
                            attempt_status: None,
                            connector_transaction_id: None,
                            network_decline_code: None,
                            network_advice_code: None,
                            network_error_message: None,
                            connector_metadata: None,
                        }),
                        ..item.data
                    })
                }
            }
            CeleroResponseStatus::Error => {
                // Top-level API error
                let error_details =
                    CeleroErrorDetails::from_top_level_error(item.response.msg.clone());

                // Extract transaction ID from the top-level data if available
                let connector_transaction_id =
                    item.response.data.as_ref().map(|data| data.id.clone());

                Ok(Self {
                    status: common_enums::AttemptStatus::Failure,
                    response: Err(hyperswitch_domain_models::router_data::ErrorResponse {
                        code: error_details
                            .error_code
                            .unwrap_or_else(|| "API_ERROR".to_string()),
                        message: error_details.error_message,
                        reason: error_details.decline_reason,
                        status_code: item.http_code,
                        attempt_status: None,
                        connector_transaction_id,
                        network_decline_code: None,
                        network_advice_code: None,
                        network_error_message: None,
                        connector_metadata: None,
                    }),
                    ..item.data
                })
            }
        }
    }
}

// CAPTURE:
// Type definition for CaptureRequest
#[derive(Default, Debug, Serialize)]
pub struct CeleroCaptureRequest {
    pub amount: MinorUnit,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub order_id: Option<String>,
}

impl TryFrom<&CeleroRouterData<&PaymentsCaptureRouterData>> for CeleroCaptureRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &CeleroRouterData<&PaymentsCaptureRouterData>) -> Result<Self, Self::Error> {
        Ok(Self {
            amount: item.amount,
            order_id: Some(item.router_data.payment_id.clone()),
        })
    }
}

// CeleroCommerce Capture Response
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CeleroCaptureResponse {
    pub status: CeleroResponseStatus,
    pub msg: Option<String>,
    pub data: Option<serde_json::Value>, // Usually null for capture responses
}

impl
    TryFrom<
        ResponseRouterData<
            Capture,
            CeleroCaptureResponse,
            PaymentsCaptureData,
            PaymentsResponseData,
        >,
    > for RouterData<Capture, PaymentsCaptureData, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            Capture,
            CeleroCaptureResponse,
            PaymentsCaptureData,
            PaymentsResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        match item.response.status {
            CeleroResponseStatus::Success => Ok(Self {
                status: common_enums::AttemptStatus::Charged,
                response: Ok(PaymentsResponseData::TransactionResponse {
                    resource_id: ResponseId::ConnectorTransactionId(
                        item.data.request.connector_transaction_id.clone(),
                    ),
                    redirection_data: Box::new(None),
                    mandate_reference: Box::new(None),
                    connector_metadata: None,
                    network_txn_id: None,
                    connector_response_reference_id: None,
                    incremental_authorization_allowed: None,
                    charges: None,
                }),
                ..item.data
            }),
            CeleroResponseStatus::Error => Ok(Self {
                status: common_enums::AttemptStatus::Failure,
                response: Err(hyperswitch_domain_models::router_data::ErrorResponse {
                    code: "CAPTURE_FAILED".to_string(),
                    message: item
                        .response
                        .msg
                        .clone()
                        .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
                    reason: None,
                    status_code: item.http_code,
                    attempt_status: None,
                    connector_transaction_id: Some(
                        item.data.request.connector_transaction_id.clone(),
                    ),
                    network_decline_code: None,
                    network_advice_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                }),
                ..item.data
            }),
        }
    }
}

// CeleroCommerce Void Response - matches API spec format
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CeleroVoidResponse {
    pub status: CeleroResponseStatus,
    pub msg: String,
    pub data: Option<serde_json::Value>, // Usually null for void responses
}

impl
    TryFrom<
        ResponseRouterData<
            hyperswitch_domain_models::router_flow_types::payments::Void,
            CeleroVoidResponse,
            hyperswitch_domain_models::router_request_types::PaymentsCancelData,
            PaymentsResponseData,
        >,
    >
    for RouterData<
        hyperswitch_domain_models::router_flow_types::payments::Void,
        hyperswitch_domain_models::router_request_types::PaymentsCancelData,
        PaymentsResponseData,
    >
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            hyperswitch_domain_models::router_flow_types::payments::Void,
            CeleroVoidResponse,
            hyperswitch_domain_models::router_request_types::PaymentsCancelData,
            PaymentsResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        match item.response.status {
            CeleroResponseStatus::Success => Ok(Self {
                status: common_enums::AttemptStatus::Voided,
                response: Ok(PaymentsResponseData::TransactionResponse {
                    resource_id: ResponseId::ConnectorTransactionId(
                        item.data.request.connector_transaction_id.clone(),
                    ),
                    redirection_data: Box::new(None),
                    mandate_reference: Box::new(None),
                    connector_metadata: None,
                    network_txn_id: None,
                    connector_response_reference_id: None,
                    incremental_authorization_allowed: None,
                    charges: None,
                }),
                ..item.data
            }),
            CeleroResponseStatus::Error => Ok(Self {
                status: common_enums::AttemptStatus::Failure,
                response: Err(hyperswitch_domain_models::router_data::ErrorResponse {
                    code: "VOID_FAILED".to_string(),
                    message: item.response.msg.clone(),
                    reason: Some(item.response.msg),
                    status_code: item.http_code,
                    attempt_status: None,
                    connector_transaction_id: Some(
                        item.data.request.connector_transaction_id.clone(),
                    ),
                    network_decline_code: None,
                    network_advice_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                }),
                ..item.data
            }),
        }
    }
}
#[derive(Default, Debug, Serialize)]
pub struct CeleroRefundRequest {
    pub amount: MinorUnit,
    pub surcharge: MinorUnit, // Required field as per API specification
}

impl<F> TryFrom<&CeleroRouterData<&RefundsRouterData<F>>> for CeleroRefundRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &CeleroRouterData<&RefundsRouterData<F>>) -> Result<Self, Self::Error> {
        Ok(Self {
            amount: item.amount,
            surcharge: MinorUnit::zero(), // Default to 0 as per API specification
        })
    }
}

// CeleroCommerce Refund Response - matches API spec format
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CeleroRefundResponse {
    pub status: CeleroResponseStatus,
    pub msg: String,
    pub data: Option<serde_json::Value>, // Usually null for refund responses
}

impl TryFrom<RefundsResponseRouterData<Execute, CeleroRefundResponse>>
    for RefundsRouterData<Execute>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<Execute, CeleroRefundResponse>,
    ) -> Result<Self, Self::Error> {
        match item.response.status {
            CeleroResponseStatus::Success => Ok(Self {
                response: Ok(RefundsResponseData {
                    connector_refund_id: item.data.request.refund_id.clone(),
                    refund_status: enums::RefundStatus::Success,
                }),
                ..item.data
            }),
            CeleroResponseStatus::Error => Ok(Self {
                response: Err(hyperswitch_domain_models::router_data::ErrorResponse {
                    code: "REFUND_FAILED".to_string(),
                    message: item.response.msg.clone(),
                    reason: Some(item.response.msg),
                    status_code: item.http_code,
                    attempt_status: None,
                    connector_transaction_id: Some(
                        item.data.request.connector_transaction_id.clone(),
                    ),
                    network_decline_code: None,
                    network_advice_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                }),
                ..item.data
            }),
        }
    }
}

impl TryFrom<RefundsResponseRouterData<RSync, CeleroRefundResponse>> for RefundsRouterData<RSync> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<RSync, CeleroRefundResponse>,
    ) -> Result<Self, Self::Error> {
        match item.response.status {
            CeleroResponseStatus::Success => Ok(Self {
                response: Ok(RefundsResponseData {
                    connector_refund_id: item.data.request.refund_id.clone(),
                    refund_status: enums::RefundStatus::Success,
                }),
                ..item.data
            }),
            CeleroResponseStatus::Error => Ok(Self {
                response: Err(hyperswitch_domain_models::router_data::ErrorResponse {
                    code: "REFUND_SYNC_FAILED".to_string(),
                    message: item.response.msg.clone(),
                    reason: Some(item.response.msg),
                    status_code: item.http_code,
                    attempt_status: None,
                    connector_transaction_id: Some(
                        item.data.request.connector_transaction_id.clone(),
                    ),
                    network_decline_code: None,
                    network_advice_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                }),
                ..item.data
            }),
        }
    }
}

// CeleroCommerce Error Response Structures

// Main error response structure - matches API spec format
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CeleroErrorResponse {
    pub status: CeleroResponseStatus,
    pub msg: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub data: Option<serde_json::Value>,
}

// Error details that can be extracted from various response fields
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CeleroErrorDetails {
    pub error_code: Option<String>,
    pub error_message: String,
    pub processor_response_code: Option<String>,
    pub decline_reason: Option<String>,
}

impl From<CeleroErrorResponse> for CeleroErrorDetails {
    fn from(error_response: CeleroErrorResponse) -> Self {
        Self {
            error_code: Some("API_ERROR".to_string()),
            error_message: error_response.msg,
            processor_response_code: None,
            decline_reason: None,
        }
    }
}

// Function to extract error details from transaction response data
impl CeleroErrorDetails {
    pub fn from_transaction_response(response: &CeleroCardResponse, msg: String) -> Self {
        // Map specific error codes based on common response patterns
        let decline_reason = Self::map_processor_error(&response.processor_response_code, &msg);

        Self {
            error_code: None,
            error_message: msg,
            processor_response_code: response.processor_response_code.clone(),
            decline_reason,
        }
    }

    pub fn from_top_level_error(msg: String) -> Self {
        // Map specific error codes from top-level API errors

        Self {
            error_code: None,
            error_message: msg,
            processor_response_code: None,
            decline_reason: None,
        }
    }

    /// Map processor response codes and messages to specific Hyperswitch error codes
    fn map_processor_error(processor_code: &Option<String>, message: &str) -> Option<String> {
        let message_lower = message.to_lowercase();
        // Check processor response codes if available
        if let Some(code) = processor_code {
            match code.as_str() {
                "05" => Some("TRANSACTION_DECLINED".to_string()),
                "14" => Some("INVALID_CARD_DATA".to_string()),
                "51" => Some("INSUFFICIENT_FUNDS".to_string()),
                "54" => Some("EXPIRED_CARD".to_string()),
                "55" => Some("INCORRECT_CVC".to_string()),
                "61" => Some("Exceeds withdrawal amount limit".to_string()),
                "62" => Some("TRANSACTION_DECLINED".to_string()),
                "65" => Some("Exceeds withdrawal frequency limit".to_string()),
                "78" => Some("INVALID_CARD_DATA".to_string()),
                "91" => Some("PROCESSING_ERROR".to_string()),
                "96" => Some("PROCESSING_ERROR".to_string()),
                _ => {
                    router_env::logger::info!(
                        "Celero response error code ({:?}) is not mapped to any error state ",
                        code
                    );
                    Some("Transaction failed".to_string())
                }
            }
        } else {
            Some(message_lower)
        }
    }
}

pub fn get_avs_definition(code: &str) -> Option<&'static str> {
    match code {
        "0" => Some("AVS Not Available"),
        "A" => Some("Address match only"),
        "B" => Some("Address matches, ZIP not verified"),
        "C" => Some("Incompatible format"),
        "D" => Some("Exact match"),
        "F" => Some("Exact match, UK-issued cards"),
        "G" => Some("Non-U.S. Issuer does not participate"),
        "I" => Some("Not verified"),
        "M" => Some("Exact match"),
        "N" => Some("No address or ZIP match"),
        "P" => Some("Postal Code match"),
        "R" => Some("Issuer system unavailable"),
        "S" => Some("Service not supported"),
        "U" => Some("Address unavailable"),
        "W" => Some("9-character numeric ZIP match only"),
        "X" => Some("Exact match, 9-character numeric ZIP"),
        "Y" => Some("Exact match, 5-character numeric ZIP"),
        "Z" => Some("5-character ZIP match only"),
        "L" => Some("Partial match, Name and billing postal code match"),
        "1" => Some("Cardholder name and ZIP match"),
        "2" => Some("Cardholder name, address and ZIP match"),
        "3" => Some("Cardholder name and address match"),
        "4" => Some("Cardholder name matches"),
        "5" => Some("Cardholder name incorrect, ZIP matches"),
        "6" => Some("Cardholder name incorrect, address and zip match"),
        "7" => Some("Cardholder name incorrect, address matches"),
        "8" => Some("Cardholder name, address, and ZIP do not match"),
        _ => {
            router_env::logger::info!(
                "Celero avs response code ({:?}) is not mapped to any definition.",
                code
            );

            None
        } // No definition found for the given code
    }
}
fn convert_to_additional_payment_method_connector_response(
    response_code: Option<String>,
) -> Option<AdditionalPaymentMethodConnectorResponse> {
    match response_code {
        None => None,
        Some(code) => {
            let description = get_avs_definition(&code);
            let payment_checks = serde_json::json!({
                "avs_result_code": code,
                "description": description
            });
            Some(AdditionalPaymentMethodConnectorResponse::Card {
                authentication_data: None,
                payment_checks: Some(payment_checks),
                card_network: None,
                domestic_network: None,
            })
        }
    }
}


pub struct PaymentMethodTokenizationData {
    pub payment_method_data: PaymentMethodData,
    pub browser_info: Option<BrowserInformation>,
    pub currency: storage_enums::Currency,
    pub amount: Option<i64>,
    pub split_payments: Option<common_types::payments::SplitPaymentsRequest>,
    pub customer_acceptance: Option<common_payments_types::CustomerAcceptance>,
    pub setup_future_usage: Option<storage_enums::FutureUsage>,
    pub setup_mandate_details: Option<mandates::MandateData>,
    pub mandate_id: Option<api_models::payments::MandateIds>,
}


impl ConnectorCommon for Payload {
    fn id(&self) -> &'static str {
        "payload"
    }

    fn get_currency_unit(&self) -> api::CurrencyUnit {
        api::CurrencyUnit::Minor
    }

    fn common_get_content_type(&self) -> &'static str {
        "application/x-www-form-urlencoded"
    }

    fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str {
        connectors.payload.base_url.as_ref()
    }

    fn get_auth_header(
        &self,
        auth_type: &ConnectorAuthType,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        let auth = payload::PayloadAuthType::try_from(auth_type)
            .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
        // The API key is the same for all currencies, so we can take any.
        let api_key = auth
            .auths
            .values()
            .next()
            .ok_or(errors::ConnectorError::FailedToObtainAuthType)?
            .api_key
            .clone();

        let encoded_api_key = BASE64_ENGINE.encode(format!("{}:", api_key.expose()));
        Ok(vec![(
            headers::AUTHORIZATION.to_string(),
            format!("Basic {encoded_api_key}").into_masked(),
        )])
    }

    fn build_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        let response: responses::PayloadErrorResponse = res
            .response
            .parse_struct("PayloadErrorResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response.error_type,
            message: response.error_description,
            reason: response
                .details
                .as_ref()
                .map(|details_value| details_value.to_string()),
            attempt_status: None,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    }
}


OpenAPI Block Path: components.schemas.ApplepayPaymentMethod
{
  "type": "object",
  "required": [
    "display_name",
    "network",
    "type"
  ],
  "properties": {
    "display_name": {
      "type": "string",
      "description": "The name to be displayed on Apple Pay button"
    },
    "network": {
      "type": "string",
      "description": "The network of the Apple pay payment method"
    },
    "type": {
      "type": "string",
      "description": "The type of the payment method"
    }
  }
}


OpenAPI Block Path: components.schemas.IncrementalAuthorizationResponse
{
  "type": "object",
  "required": [
    "authorization_id",
    "amount",
    "status",
    "previously_authorized_amount"
  ],
  "properties": {
    "authorization_id": {
      "type": "string",
      "description": "The unique identifier of authorization"
    },
    "amount": {
      "type": "integer",
      "format": "int64",
      "description": "Amount the authorization has been made for",
      "example": 6540
    },
    "status": {
      "$ref": "#/components/schemas/AuthorizationStatus"
    },
    "error_code": {
      "type": "string",
      "description": "Error code sent by the connector for authorization",
      "nullable": true
    },
    "error_message": {
      "type": "string",
      "description": "Error message sent by the connector for authorization",
      "nullable": true
    },
    "previously_authorized_amount": {
      "$ref": "#/components/schemas/MinorUnit"
    }
  }
}