// File: crates/api_models/src/payments.rs
// Module: api_models
// Public functions: 70
// Public structs: 311

#[cfg(feature = "v1")]
use std::fmt;
use std::{
    collections::{HashMap, HashSet},
    num::NonZeroI64,
};
pub mod additional_info;
pub mod trait_impls;
use cards::CardNumber;
#[cfg(feature = "v2")]
use common_enums::enums::PaymentConnectorTransmission;
use common_enums::ProductType;
#[cfg(feature = "v1")]
use common_types::primitive_wrappers::{
    ExtendedAuthorizationAppliedBool, RequestExtendedAuthorizationBool,
};
use common_types::{payments as common_payments_types, primitive_wrappers};
use common_utils::{
    consts::default_payments_list_limit,
    crypto,
    errors::ValidationError,
    ext_traits::{ConfigExt, Encode, ValueExt},
    hashing::HashedString,
    id_type,
    new_type::MaskedBankAccount,
    pii::{self, Email},
    types::{AmountConvertor, MinorUnit, StringMajorUnit},
};
use error_stack::ResultExt;

#[cfg(feature = "v2")]
fn parse_comma_separated<'de, D, T>(v: D) -> Result<Option<Vec<T>>, D::Error>
where
    D: serde::Deserializer<'de>,
    T: std::str::FromStr,
    <T as std::str::FromStr>::Err: std::fmt::Debug + std::fmt::Display + std::error::Error,
{
    let opt_str: Option<String> = Option::deserialize(v)?;
    match opt_str {
        Some(s) if s.is_empty() => Ok(None),
        Some(s) => {
            // Estimate capacity based on comma count
            let capacity = s.matches(',').count() + 1;
            let mut result = Vec::with_capacity(capacity);

            for item in s.split(',') {
                let trimmed_item = item.trim();
                if !trimmed_item.is_empty() {
                    let parsed_item = trimmed_item.parse::<T>().map_err(|e| {
                        <D::Error as serde::de::Error>::custom(format!(
                            "Invalid value '{trimmed_item}': {e}"
                        ))
                    })?;
                    result.push(parsed_item);
                }
            }
            Ok(Some(result))
        }
        None => Ok(None),
    }
}
use masking::{PeekInterface, Secret, WithType};
use router_derive::Setter;
#[cfg(feature = "v1")]
use serde::{de, Deserializer};
use serde::{ser::Serializer, Deserialize, Serialize};
use strum::Display;
use time::{Date, PrimitiveDateTime};
use url::Url;
use utoipa::ToSchema;

#[cfg(feature = "v2")]
use crate::mandates;
#[cfg(feature = "v2")]
use crate::payment_methods;
use crate::{
    admin::{self, MerchantConnectorInfo},
    enums as api_enums,
    mandates::RecurringDetails,
};
#[cfg(feature = "v1")]
use crate::{disputes, ephemeral_key::EphemeralKeyCreateResponse, refunds, ValidateFieldAndGet};

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum PaymentOp {
    Create,
    Update,
    Confirm,
}

use crate::enums;
#[derive(serde::Deserialize)]
pub struct BankData {
    pub payment_method_type: api_enums::PaymentMethodType,
    pub code_information: Vec<BankCodeInformation>,
}

#[derive(serde::Deserialize)]
pub struct BankCodeInformation {
    pub bank_name: common_enums::BankNames,
    pub connector_codes: Vec<ConnectorCode>,
}

#[derive(serde::Deserialize)]
pub struct ConnectorCode {
    pub connector: api_enums::Connector,
    pub code: String,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema, PartialEq, Eq)]
pub struct BankCodeResponse {
    #[schema(value_type = Vec<BankNames>)]
    pub bank_name: Vec<common_enums::BankNames>,
    pub eligible_connectors: Vec<String>,
}

/// Passing this object creates a new customer or attaches an existing customer to the payment
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema, PartialEq)]
pub struct CustomerDetails {
    /// The identifier for the customer.
    #[schema(value_type = String, max_length = 64, min_length = 1, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
    pub id: id_type::CustomerId,

    /// The customer's name
    #[schema(max_length = 255, value_type = Option<String>, example = "John Doe")]
    pub name: Option<Secret<String>>,

    /// The customer's email address
    #[schema(max_length = 255, value_type = Option<String>, example = "johntest@test.com")]
    pub email: Option<Email>,

    /// The customer's phone number
    #[schema(value_type = Option<String>, max_length = 10, example = "9123456789")]
    pub phone: Option<Secret<String>>,

    /// The country code for the customer's phone number
    #[schema(max_length = 2, example = "+1")]
    pub phone_country_code: Option<String>,

    /// The tax registration identifier of the customer.
    #[schema(value_type=Option<String>,max_length = 255)]
    pub tax_registration_id: Option<Secret<String>>,
}

#[cfg(feature = "v1")]
/// Details of customer attached to this payment
#[derive(
    Debug, Default, serde::Serialize, serde::Deserialize, Clone, ToSchema, PartialEq, Setter,
)]
pub struct CustomerDetailsResponse {
    /// The identifier for the customer.
    #[schema(value_type = Option<String>, max_length = 64, min_length = 1, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
    pub id: Option<id_type::CustomerId>,

    /// The customer's name
    #[schema(max_length = 255, value_type = Option<String>, example = "John Doe")]
    pub name: Option<Secret<String>>,

    /// The customer's email address
    #[schema(max_length = 255, value_type = Option<String>, example = "johntest@test.com")]
    pub email: Option<Email>,

    /// The customer's phone number
    #[schema(value_type = Option<String>, max_length = 10, example = "9123456789")]
    pub phone: Option<Secret<String>>,

    /// The country code for the customer's phone number
    #[schema(max_length = 2, example = "+1")]
    pub phone_country_code: Option<String>,
}

#[cfg(feature = "v2")]
/// Details of customer attached to this payment
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, ToSchema, PartialEq, Setter)]
pub struct CustomerDetailsResponse {
    /// The customer's name
    #[schema(max_length = 255, value_type = Option<String>, example = "John Doe")]
    pub name: Option<Secret<String>>,

    /// The customer's email address
    #[schema(max_length = 255, value_type = Option<String>, example = "johntest@test.com")]
    pub email: Option<Email>,

    /// The customer's phone number
    #[schema(value_type = Option<String>, max_length = 10, example = "9123456789")]
    pub phone: Option<Secret<String>>,

    /// The country code for the customer's phone number
    #[schema(max_length = 2, example = "+1")]
    pub phone_country_code: Option<String>,
}

// Serialize is required because the api event requires Serialize to be implemented
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, ToSchema)]
#[serde(deny_unknown_fields)]
#[cfg(feature = "v2")]
pub struct PaymentsCreateIntentRequest {
    /// The amount details for the payment
    pub amount_details: AmountDetails,

    /// Unique identifier for the payment. This ensures idempotency for multiple payments
    /// that have been done by a single merchant.
    #[schema(
        value_type = Option<String>,
        min_length = 30,
        max_length = 30,
        example = "pay_mbabizu24mvu3mela5njyhpit4"
    )]
    pub merchant_reference_id: Option<id_type::PaymentReferenceId>,

    /// The routing algorithm id to be used for the payment
    #[schema(value_type = Option<String>)]
    pub routing_algorithm_id: Option<id_type::RoutingId>,

    #[schema(value_type = Option<CaptureMethod>, example = "automatic")]
    pub capture_method: Option<api_enums::CaptureMethod>,

    #[schema(value_type = Option<AuthenticationType>, example = "no_three_ds", default = "no_three_ds")]
    pub authentication_type: Option<api_enums::AuthenticationType>,

    /// The billing details of the payment. This address will be used for invoicing.
    pub billing: Option<Address>,

    /// The shipping address for the payment
    pub shipping: Option<Address>,

    /// The identifier for the customer
    #[schema(
        min_length = 32,
        max_length = 64,
        example = "12345_cus_01926c58bc6e77c09e809964e72af8c8",
        value_type = String
    )]
    pub customer_id: Option<id_type::GlobalCustomerId>,

    /// Set to `present` to indicate that the customer is in your checkout flow during this payment, and therefore is able to authenticate. This parameter should be `absent` when merchant's doing merchant initiated payments and customer is not present while doing the payment.
    #[schema(example = "present", value_type = Option<PresenceOfCustomerDuringPayment>)]
    pub customer_present: Option<common_enums::PresenceOfCustomerDuringPayment>,

    /// A description for the payment
    #[schema(example = "It's my first payment request", value_type = Option<String>)]
    pub description: Option<common_utils::types::Description>,

    /// The URL to which you want the user to be redirected after the completion of the payment operation
    #[schema(value_type = Option<String>, example = "https://hyperswitch.io")]
    pub return_url: Option<common_utils::types::Url>,

    #[schema(value_type = Option<FutureUsage>, example = "off_session")]
    pub setup_future_usage: Option<api_enums::FutureUsage>,

    /// Apply MIT exemption for a payment
    #[schema(value_type = Option<MitExemptionRequest>)]
    pub apply_mit_exemption: Option<common_enums::MitExemptionRequest>,

    /// For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters.
    #[schema(max_length = 22, example = "Hyperswitch Router", value_type = Option<String>)]
    pub statement_descriptor: Option<common_utils::types::StatementDescriptor>,

    /// Use this object to capture the details about the different products for which the payment is being made. The sum of amount across different products here should be equal to the overall payment amount
    #[schema(value_type = Option<Vec<OrderDetailsWithAmount>>, example = r#"[{
        "product_name": "Apple iPhone 16",
        "quantity": 1,
        "amount" : 69000
        "product_img_link" : "https://dummy-img-link.com"
    }]"#)]
    pub order_details: Option<Vec<OrderDetailsWithAmount>>,

    /// Use this parameter to restrict the Payment Method Types to show for a given PaymentIntent
    #[schema(value_type = Option<Vec<PaymentMethodType>>)]
    pub allowed_payment_method_types: Option<Vec<api_enums::PaymentMethodType>>,

    /// Metadata is useful for storing additional, unstructured information on an object.
    #[schema(value_type = Option<Object>, example = r#"{ "udf1": "some-value", "udf2": "some-value" }"#)]
    pub metadata: Option<pii::SecretSerdeValue>,

    /// Some connectors like Apple pay, Airwallex and Noon might require some additional information, find specific details in the child attributes below.
    pub connector_metadata: Option<ConnectorMetadata>,

    /// Additional data that might be required by hyperswitch based on the requested features by the merchants.
    pub feature_metadata: Option<FeatureMetadata>,

    /// Whether to generate the payment link for this payment or not (if applicable)
    #[schema(value_type = Option<EnablePaymentLinkRequest>)]
    pub payment_link_enabled: Option<common_enums::EnablePaymentLinkRequest>,

    /// Configure a custom payment link for the particular payment
    #[schema(value_type = Option<PaymentLinkConfigRequest>)]
    pub payment_link_config: Option<admin::PaymentLinkConfigRequest>,

    ///Request an incremental authorization, i.e., increase the authorized amount on a confirmed payment before you capture it.
    #[schema(value_type = Option<RequestIncrementalAuthorization>)]
    pub request_incremental_authorization: Option<common_enums::RequestIncrementalAuthorization>,

    ///Will be used to expire client secret after certain amount of time to be supplied in seconds, if not sent it will be taken from profile config
    ///(900) for 15 mins
    #[schema(example = 900)]
    pub session_expiry: Option<u32>,

    /// Additional data related to some frm(Fraud Risk Management) connectors
    #[schema(value_type = Option<Object>, example = r#"{ "coverage_request" : "fraud", "fulfillment_method" : "delivery" }"#)]
    pub frm_metadata: Option<pii::SecretSerdeValue>,

    /// Whether to perform external authentication (if applicable)
    #[schema(value_type = Option<External3dsAuthenticationRequest>)]
    pub request_external_three_ds_authentication:
        Option<common_enums::External3dsAuthenticationRequest>,

    /// Indicates if 3ds challenge is forced
    pub force_3ds_challenge: Option<bool>,

    /// Merchant connector details used to make payments.
    #[schema(value_type = Option<MerchantConnectorAuthDetails>)]
    pub merchant_connector_details: Option<common_types::domain::MerchantConnectorAuthDetails>,

    /// Allow partial authorization for this payment
    #[schema(value_type = Option<bool>, default = false)]
    pub enable_partial_authorization: Option<primitive_wrappers::EnablePartialAuthorizationBool>,
}
#[cfg(feature = "v2")]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, ToSchema)]
pub struct PaymentAttemptListRequest {
    #[schema(value_type = String)]
    pub payment_intent_id: id_type::GlobalPaymentId,
}

#[cfg(feature = "v2")]
#[derive(Debug, serde::Serialize, Clone, ToSchema)]
pub struct PaymentAttemptListResponse {
    pub payment_attempt_list: Vec<PaymentAttemptResponse>,
}
#[cfg(feature = "v2")]
impl PaymentsCreateIntentRequest {
    pub fn get_feature_metadata_as_value(
        &self,
    ) -> common_utils::errors::CustomResult<
        Option<pii::SecretSerdeValue>,
        common_utils::errors::ParsingError,
    > {
        Ok(self
            .feature_metadata
            .as_ref()
            .map(Encode::encode_to_value)
            .transpose()?
            .map(Secret::new))
    }

    pub fn get_connector_metadata_as_value(
        &self,
    ) -> common_utils::errors::CustomResult<
        Option<pii::SecretSerdeValue>,
        common_utils::errors::ParsingError,
    > {
        Ok(self
            .connector_metadata
            .as_ref()
            .map(Encode::encode_to_value)
            .transpose()?
            .map(Secret::new))
    }

    pub fn get_allowed_payment_method_types_as_value(
        &self,
    ) -> common_utils::errors::CustomResult<
        Option<pii::SecretSerdeValue>,
        common_utils::errors::ParsingError,
    > {
        Ok(self
            .allowed_payment_method_types
            .as_ref()
            .map(Encode::encode_to_value)
            .transpose()?
            .map(Secret::new))
    }

    pub fn get_order_details_as_value(
        &self,
    ) -> common_utils::errors::CustomResult<
        Option<Vec<pii::SecretSerdeValue>>,
        common_utils::errors::ParsingError,
    > {
        self.order_details
            .as_ref()
            .map(|od| {
                od.iter()
                    .map(|order| order.encode_to_value().map(Secret::new))
                    .collect::<Result<Vec<_>, _>>()
            })
            .transpose()
    }
}

// This struct is only used internally, not visible in API Reference
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[cfg(feature = "v2")]
pub struct PaymentsGetIntentRequest {
    pub id: id_type::GlobalPaymentId,
}

#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, ToSchema)]
#[serde(deny_unknown_fields)]
#[cfg(feature = "v2")]
pub struct PaymentsUpdateIntentRequest {
    pub amount_details: Option<AmountDetailsUpdate>,

    /// The routing algorithm id to be used for the payment
    #[schema(value_type = Option<String>)]
    pub routing_algorithm_id: Option<id_type::RoutingId>,

    #[schema(value_type = Option<CaptureMethod>, example = "automatic")]
    pub capture_method: Option<api_enums::CaptureMethod>,

    #[schema(value_type = Option<AuthenticationType>, example = "no_three_ds", default = "no_three_ds")]
    pub authentication_type: Option<api_enums::AuthenticationType>,

    /// The billing details of the payment. This address will be used for invoicing.
    pub billing: Option<Address>,

    /// The shipping address for the payment
    pub shipping: Option<Address>,

    /// Set to `present` to indicate that the customer is in your checkout flow during this payment, and therefore is able to authenticate. This parameter should be `absent` when merchant's doing merchant initiated payments and customer is not present while doing the payment.
    #[schema(example = "present", value_type = Option<PresenceOfCustomerDuringPayment>)]
    pub customer_present: Option<common_enums::PresenceOfCustomerDuringPayment>,

    /// A description for the payment
    #[schema(example = "It's my first payment request", value_type = Option<String>)]
    pub description: Option<common_utils::types::Description>,

    /// The URL to which you want the user to be redirected after the completion of the payment operation
    #[schema(value_type = Option<String>, example = "https://hyperswitch.io")]
    pub return_url: Option<common_utils::types::Url>,

    #[schema(value_type = Option<FutureUsage>, example = "off_session")]
    pub setup_future_usage: Option<api_enums::FutureUsage>,

    /// Apply MIT exemption for a payment
    #[schema(value_type = Option<MitExemptionRequest>)]
    pub apply_mit_exemption: Option<common_enums::MitExemptionRequest>,

    /// For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters.
    #[schema(max_length = 22, example = "Hyperswitch Router", value_type = Option<String>)]
    pub statement_descriptor: Option<common_utils::types::StatementDescriptor>,

    /// Use this object to capture the details about the different products for which the payment is being made. The sum of amount across different products here should be equal to the overall payment amount
    #[schema(value_type = Option<Vec<OrderDetailsWithAmount>>, example = r#"[{
        "product_name": "Apple iPhone 16",
        "quantity": 1,
        "amount" : 69000
        "product_img_link" : "https://dummy-img-link.com"
    }]"#)]
    pub order_details: Option<Vec<OrderDetailsWithAmount>>,

    /// Use this parameter to restrict the Payment Method Types to show for a given PaymentIntent
    #[schema(value_type = Option<Vec<PaymentMethodType>>)]
    pub allowed_payment_method_types: Option<Vec<api_enums::PaymentMethodType>>,

    /// Metadata is useful for storing additional, unstructured information on an object. This metadata will override the metadata that was passed in payments
    #[schema(value_type = Option<Object>, example = r#"{ "udf1": "some-value", "udf2": "some-value" }"#)]
    pub metadata: Option<pii::SecretSerdeValue>,

    /// Some connectors like Apple pay, Airwallex and Noon might require some additional information, find specific details in the child attributes below.
    #[schema(value_type = Option<ConnectorMetadata>)]
    pub connector_metadata: Option<pii::SecretSerdeValue>,

    /// Additional data that might be required by hyperswitch based on the requested features by the merchants.
    #[schema(value_type = Option<FeatureMetadata>)]
    pub feature_metadata: Option<FeatureMetadata>,

    /// Configure a custom payment link for the particular payment
    #[schema(value_type = Option<PaymentLinkConfigRequest>)]
    pub payment_link_config: Option<admin::PaymentLinkConfigRequest>,

    /// Request an incremental authorization, i.e., increase the authorized amount on a confirmed payment before you capture it.
    #[schema(value_type = Option<RequestIncrementalAuthorization>)]
    pub request_incremental_authorization: Option<common_enums::RequestIncrementalAuthorization>,

    /// Will be used to expire client secret after certain amount of time to be supplied in seconds, if not sent it will be taken from profile config
    ///(900) for 15 mins
    #[schema(value_type = Option<u32>, example = 900)]
    pub session_expiry: Option<u32>,

    /// Additional data related to some frm(Fraud Risk Management) connectors
    #[schema(value_type = Option<Object>, example = r#"{ "coverage_request" : "fraud", "fulfillment_method" : "delivery" }"#)]
    pub frm_metadata: Option<pii::SecretSerdeValue>,

    /// Whether to perform external authentication (if applicable)
    #[schema(value_type = Option<External3dsAuthenticationRequest>)]
    pub request_external_three_ds_authentication:
        Option<common_enums::External3dsAuthenticationRequest>,

    #[schema(value_type = Option<UpdateActiveAttempt>)]
    /// Whether to set / unset the active attempt id
    pub set_active_attempt_id: Option<api_enums::UpdateActiveAttempt>,

    /// Allow partial authorization for this payment
    #[schema(value_type = Option<bool>, default = false)]
    pub enable_partial_authorization: Option<primitive_wrappers::EnablePartialAuthorizationBool>,
}

#[cfg(feature = "v2")]
impl PaymentsUpdateIntentRequest {
    pub fn update_feature_metadata_and_active_attempt_with_api(
        feature_metadata: FeatureMetadata,
        set_active_attempt_id: api_enums::UpdateActiveAttempt,
    ) -> Self {
        Self {
            feature_metadata: Some(feature_metadata),
            set_active_attempt_id: Some(set_active_attempt_id),
            amount_details: None,
            routing_algorithm_id: None,
            capture_method: None,
            authentication_type: None,
            billing: None,
            shipping: None,
            customer_present: None,
            description: None,
            return_url: None,
            setup_future_usage: None,
            apply_mit_exemption: None,
            statement_descriptor: None,
            order_details: None,
            allowed_payment_method_types: None,
            metadata: None,
            connector_metadata: None,
            payment_link_config: None,
            request_incremental_authorization: None,
            session_expiry: None,
            frm_metadata: None,
            request_external_three_ds_authentication: None,
            enable_partial_authorization: None,
        }
    }
}

#[derive(Debug, serde::Serialize, Clone, ToSchema)]
#[serde(deny_unknown_fields)]
#[cfg(feature = "v2")]
pub struct PaymentsIntentResponse {
    /// Global Payment Id for the payment
    #[schema(value_type = String)]
    pub id: id_type::GlobalPaymentId,

    /// The status of the payment
    #[schema(value_type = IntentStatus, example = "succeeded")]
    pub status: common_enums::IntentStatus,

    /// The amount details for the payment
    pub amount_details: AmountDetailsResponse,

    /// It's a token used for client side verification.
    #[schema(value_type = String, example = "cs_0195b34da95d75239c6a4bf514458896")]
    pub client_secret: Option<Secret<String>>,

    /// The identifier for the profile. This is inferred from the `x-profile-id` header
    #[schema(value_type = String)]
    pub profile_id: id_type::ProfileId,

    /// Unique identifier for the payment. This ensures idempotency for multiple payments
    /// that have been done by a single merchant.
    #[schema(
        value_type = Option<String>,
        min_length = 30,
        max_length = 30,
        example = "pay_mbabizu24mvu3mela5njyhpit4"
    )]
    pub merchant_reference_id: Option<id_type::PaymentReferenceId>,

    /// The routing algorithm id to be used for the payment
    #[schema(value_type = Option<String>)]
    pub routing_algorithm_id: Option<id_type::RoutingId>,

    #[schema(value_type = CaptureMethod, example = "automatic")]
    pub capture_method: api_enums::CaptureMethod,

    /// The authentication type for the payment
    #[schema(value_type = Option<AuthenticationType>, example = "no_three_ds")]
    pub authentication_type: Option<api_enums::AuthenticationType>,

    /// The billing details of the payment. This address will be used for invoicing.
    #[schema(value_type = Option<Address>)]
    pub billing: Option<Address>,

    /// The shipping address for the payment
    #[schema(value_type = Option<Address>)]
    pub shipping: Option<Address>,

    /// The identifier for the customer
    #[schema(
        min_length = 32,
        max_length = 64,
        example = "12345_cus_01926c58bc6e77c09e809964e72af8c8",
        value_type = String
    )]
    pub customer_id: Option<id_type::GlobalCustomerId>,

    /// Set to `present` to indicate that the customer is in your checkout flow during this payment, and therefore is able to authenticate. This parameter should be `absent` when merchant's doing merchant initiated payments and customer is not present while doing the payment.
    #[schema(example = "present", value_type = PresenceOfCustomerDuringPayment)]
    pub customer_present: common_enums::PresenceOfCustomerDuringPayment,

    /// A description for the payment
    #[schema(example = "It's my first payment request", value_type = Option<String>)]
    pub description: Option<common_utils::types::Description>,

    /// The URL to which you want the user to be redirected after the completion of the payment operation
    #[schema(value_type = Option<String>, example = "https://hyperswitch.io")]
    pub return_url: Option<common_utils::types::Url>,

    #[schema(value_type = FutureUsage, example = "off_session")]
    pub setup_future_usage: api_enums::FutureUsage,

    /// Apply MIT exemption for a payment
    #[schema(value_type = MitExemptionRequest)]
    pub apply_mit_exemption: common_enums::MitExemptionRequest,

    /// For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters.
    #[schema(max_length = 22, example = "Hyperswitch Router", value_type = Option<String>)]
    pub statement_descriptor: Option<common_utils::types::StatementDescriptor>,

    /// Use this object to capture the details about the different products for which the payment is being made. The sum of amount across different products here should be equal to the overall payment amount
    #[schema(value_type = Option<Vec<OrderDetailsWithAmount>>, example = r#"[{
        "product_name": "Apple iPhone 16",
        "quantity": 1,
        "amount" : 69000
        "product_img_link" : "https://dummy-img-link.com"
    }]"#)]
    pub order_details: Option<Vec<OrderDetailsWithAmount>>,

    /// Use this parameter to restrict the Payment Method Types to show for a given PaymentIntent
    #[schema(value_type = Option<Vec<PaymentMethodType>>)]
    pub allowed_payment_method_types: Option<Vec<api_enums::PaymentMethodType>>,

    /// Metadata is useful for storing additional, unstructured information on an object.
    #[schema(value_type = Option<Object>, example = r#"{ "udf1": "some-value", "udf2": "some-value" }"#)]
    pub metadata: Option<pii::SecretSerdeValue>,

    /// Some connectors like Apple pay, Airwallex and Noon might require some additional information, find specific details in the child attributes below.
    #[schema(value_type = Option<ConnectorMetadata>)]
    pub connector_metadata: Option<pii::SecretSerdeValue>,

    /// Additional data that might be required by hyperswitch based on the requested features by the merchants.
    #[schema(value_type = Option<FeatureMetadata>)]
    pub feature_metadata: Option<FeatureMetadata>,

    /// Whether to generate the payment link for this payment or not (if applicable)
    #[schema(value_type = EnablePaymentLinkRequest)]
    pub payment_link_enabled: common_enums::EnablePaymentLinkRequest,

    /// Configure a custom payment link for the particular payment
    #[schema(value_type = Option<PaymentLinkConfigRequest>)]
    pub payment_link_config: Option<admin::PaymentLinkConfigRequest>,

    ///Request an incremental authorization, i.e., increase the authorized amount on a confirmed payment before you capture it.
    #[schema(value_type = RequestIncrementalAuthorization)]
    pub request_incremental_authorization: common_enums::RequestIncrementalAuthorization,

    /// Enable split payments, i.e., split the amount between multiple payment methods
    #[schema(value_type = SplitTxnsEnabled, default = "skip")]
    pub split_txns_enabled: common_enums::SplitTxnsEnabled,

    ///Will be used to expire client secret after certain amount of time to be supplied in seconds
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub expires_on: PrimitiveDateTime,

    /// Additional data related to some frm(Fraud Risk Management) connectors
    #[schema(value_type = Option<Object>, example = r#"{ "coverage_request" : "fraud", "fulfillment_method" : "delivery" }"#)]
    pub frm_metadata: Option<pii::SecretSerdeValue>,

    /// Whether to perform external authentication (if applicable)
    #[schema(value_type = External3dsAuthenticationRequest)]
    pub request_external_three_ds_authentication: common_enums::External3dsAuthenticationRequest,

    /// The type of the payment that differentiates between normal and various types of mandate payments
    #[schema(value_type = PaymentType)]
    pub payment_type: api_enums::PaymentType,

    /// Allow partial authorization for this payment
    #[schema(value_type = Option<bool>, default = false)]
    pub enable_partial_authorization: Option<primitive_wrappers::EnablePartialAuthorizationBool>,
}

#[cfg(feature = "v2")]
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct GiftCardBalanceCheckResponse {
    /// Global Payment Id for the payment
    #[schema(value_type = String)]
    pub payment_id: id_type::GlobalPaymentId,
    /// The balance of the gift card
    pub balance: MinorUnit,
    /// The currency of the Gift Card
    #[schema(value_type = Currency)]
    pub currency: common_enums::Currency,
    /// Whether the gift card balance is enough for the transaction (Used for split payments case)
    pub needs_additional_pm_data: bool,
    /// Transaction amount left after subtracting gift card balance (Used for split payments)
    pub remaining_amount: MinorUnit,
}

#[cfg(feature = "v2")]
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct AmountDetails {
    /// The payment amount. Amount for the payment in the lowest denomination of the currency, (i.e) in cents for USD denomination, in yen for JPY denomination etc. E.g., Pass 100 to charge $1.00 and 1 for 1¥ since ¥ is a zero-decimal currency. Read more about [the Decimal and Non-Decimal Currencies](https://github.com/juspay/hyperswitch/wiki/Decimal-and-Non%E2%80%90Decimal-Currencies)
    #[schema(value_type = u64, example = 6540)]
    #[serde(default, deserialize_with = "amount::deserialize")]
    order_amount: Amount,
    /// The currency of the order
    #[schema(example = "USD", value_type = Currency)]
    currency: common_enums::Currency,
    /// The shipping cost of the order. This has to be collected from the merchant
    shipping_cost: Option<MinorUnit>,
    /// Tax amount related to the order. This will be calculated by the external tax provider
    order_tax_amount: Option<MinorUnit>,
    /// The action to whether calculate tax by calling external tax provider or not
    #[serde(default)]
    #[schema(value_type = TaxCalculationOverride)]
    skip_external_tax_calculation: common_enums::TaxCalculationOverride,
    /// The action to whether calculate surcharge or not
    #[serde(default)]
    #[schema(value_type = SurchargeCalculationOverride)]
    skip_surcharge_calculation: common_enums::SurchargeCalculationOverride,
    /// The surcharge amount to be added to the order, collected from the merchant
    surcharge_amount: Option<MinorUnit>,
    /// tax on surcharge amount
    tax_on_surcharge: Option<MinorUnit>,
}

#[cfg(feature = "v2")]
impl AmountDetails {
    pub fn new_for_zero_auth_payment(currency: common_enums::Currency) -> Self {
        Self {
            order_amount: Amount::Zero,
            currency,
            shipping_cost: None,
            order_tax_amount: None,
            skip_external_tax_calculation: common_enums::TaxCalculationOverride::Skip,
            skip_surcharge_calculation: common_enums::SurchargeCalculationOverride::Skip,
            surcharge_amount: None,
            tax_on_surcharge: None,
        }
    }
}

#[cfg(feature = "v2")]
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct AmountDetailsUpdate {
    /// The payment amount. Amount for the payment in the lowest denomination of the currency, (i.e) in cents for USD denomination, in yen for JPY denomination etc. E.g., Pass 100 to charge $1.00 and 1 for 1¥ since ¥ is a zero-decimal currency. Read more about [the Decimal and Non-Decimal Currencies](https://github.com/juspay/hyperswitch/wiki/Decimal-and-Non%E2%80%90Decimal-Currencies)
    #[schema(value_type = Option<u64>, example = 6540)]
    #[serde(default, deserialize_with = "amount::deserialize_option")]
    order_amount: Option<Amount>,
    /// The currency of the order
    #[schema(example = "USD", value_type = Option<Currency>)]
    currency: Option<common_enums::Currency>,
    /// The shipping cost of the order. This has to be collected from the merchant
    shipping_cost: Option<MinorUnit>,
    /// Tax amount related to the order. This will be calculated by the external tax provider
    order_tax_amount: Option<MinorUnit>,
    /// The action to whether calculate tax by calling external tax provider or not
    #[schema(value_type = Option<TaxCalculationOverride>)]
    skip_external_tax_calculation: Option<common_enums::TaxCalculationOverride>,
    /// The action to whether calculate surcharge or not
    #[schema(value_type = Option<SurchargeCalculationOverride>)]
    skip_surcharge_calculation: Option<common_enums::SurchargeCalculationOverride>,
    /// The surcharge amount to be added to the order, collected from the merchant
    surcharge_amount: Option<MinorUnit>,
    /// tax on surcharge amount
    tax_on_surcharge: Option<MinorUnit>,
}

#[cfg(feature = "v2")]
pub struct AmountDetailsSetter {
    pub order_amount: Amount,
    pub currency: common_enums::Currency,
    pub shipping_cost: Option<MinorUnit>,
    pub order_tax_amount: Option<MinorUnit>,
    pub skip_external_tax_calculation: common_enums::TaxCalculationOverride,
    pub skip_surcharge_calculation: common_enums::SurchargeCalculationOverride,
    pub surcharge_amount: Option<MinorUnit>,
    pub tax_on_surcharge: Option<MinorUnit>,
}

#[cfg(feature = "v2")]
#[derive(Clone, Debug, PartialEq, serde::Serialize, ToSchema)]
pub struct AmountDetailsResponse {


// Implementation: impl Hipay
// File: crates/hyperswitch_connectors/src/connectors/hipay.rs
// Module: hyperswitch_connectors
// Methods: 1 total (1 public)

impl Hipay


// Implementation: impl api::ConnectorAccessToken for for Amazonpay
// File: crates/hyperswitch_connectors/src/connectors/amazonpay.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::ConnectorAccessToken for for Amazonpay


// Struct: CustomerPaymentMethod
// File: crates/api_models/src/payment_methods.rs
// Module: api_models
// Implementations: 0

pub struct CustomerPaymentMethod


// Implementation: impl std::fmt::Display for for InvalidCrmConfig
// File: crates/external_services/src/crm.rs
// Module: external_services
// Methods: 1 total (0 public)

impl std::fmt::Display for for InvalidCrmConfig


// Implementation: impl RefundInterface for for KafkaStore
// File: crates/router/src/db/kafka_store.rs
// Module: router
// Methods: 14 total (0 public)

impl RefundInterface for for KafkaStore


// Struct: GivexGiftCardAdditionalData
// File: crates/api_models/src/payments/additional_info.rs
// Module: api_models
// Implementations: 0

pub struct GivexGiftCardAdditionalData


// Struct: RsyncApplicationInformation
// File: crates/hyperswitch_connectors/src/connectors/bankofamerica/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct RsyncApplicationInformation


// Function: generate_payment_method_response
// File: crates/router/src/core/payment_methods/transformers.rs
// Module: router

pub fn generate_payment_method_response(
    payment_method: &domain::PaymentMethod,
    single_use_token: &Option<payment_method_data::SingleUsePaymentMethodToken>,
) -> errors::RouterResult<api::PaymentMethodResponse>


// Implementation: impl webhooks::IncomingWebhook for for Finix
// File: crates/hyperswitch_connectors/src/connectors/finix.rs
// Module: hyperswitch_connectors
// Methods: 3 total (0 public)

impl webhooks::IncomingWebhook for for Finix


// Function: accept_dispute
// File: crates/router/src/core/disputes.rs
// Module: router

pub fn accept_dispute(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id: Option<common_utils::id_type::ProfileId>,
    req: disputes::DisputeId,
) -> RouterResponse<dispute_models::DisputeResponse>


// File: crates/router/src/compatibility/stripe/customers/types.rs
// Module: router
// Public structs: 9

use std::{convert::From, default::Default};

#[cfg(feature = "v1")]
use api_models::payment_methods as api_types;
use api_models::payments;
#[cfg(feature = "v1")]
use common_utils::{crypto::Encryptable, date_time};
use common_utils::{
    id_type,
    pii::{self, Email},
    types::Description,
};
use serde::{Deserialize, Serialize};

#[cfg(feature = "v1")]
use crate::logger;
use crate::types::{api, api::enums as api_enums};

#[derive(Default, Serialize, PartialEq, Eq, Deserialize, Clone)]
pub struct Shipping {
    pub address: StripeAddressDetails,
    pub name: Option<masking::Secret<String>>,
    pub carrier: Option<String>,
    pub phone: Option<masking::Secret<String>>,
    pub tracking_number: Option<masking::Secret<String>>,
}

#[derive(Default, Serialize, PartialEq, Eq, Deserialize, Clone)]
pub struct StripeAddressDetails {
    pub city: Option<String>,
    pub country: Option<api_enums::CountryAlpha2>,
    pub line1: Option<masking::Secret<String>>,
    pub line2: Option<masking::Secret<String>>,
    pub postal_code: Option<masking::Secret<String>>,
    pub state: Option<masking::Secret<String>>,
}

#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct CreateCustomerRequest {
    pub email: Option<Email>,
    pub invoice_prefix: Option<String>,
    pub name: Option<masking::Secret<String>>,
    pub phone: Option<masking::Secret<String>>,
    pub address: Option<StripeAddressDetails>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub description: Option<Description>,
    pub shipping: Option<Shipping>,
    pub payment_method: Option<String>,              // not used
    pub balance: Option<i64>,                        // not used
    pub cash_balance: Option<pii::SecretSerdeValue>, // not used
    pub coupon: Option<String>,                      // not used
    pub invoice_settings: Option<pii::SecretSerdeValue>, // not used
    pub next_invoice_sequence: Option<String>,       // not used
    pub preferred_locales: Option<String>,           // not used
    pub promotion_code: Option<String>,              // not used
    pub source: Option<String>,                      // not used
    pub tax: Option<pii::SecretSerdeValue>,          // not used
    pub tax_exempt: Option<String>,                  // not used
    pub tax_id_data: Option<String>,                 // not used
    pub test_clock: Option<String>,                  // not used
}

#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct CustomerUpdateRequest {
    pub description: Option<Description>,
    pub email: Option<Email>,
    pub phone: Option<masking::Secret<String, masking::WithType>>,
    pub name: Option<masking::Secret<String>>,
    pub address: Option<StripeAddressDetails>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub shipping: Option<Shipping>,
    pub payment_method: Option<String>,              // not used
    pub balance: Option<i64>,                        // not used
    pub cash_balance: Option<pii::SecretSerdeValue>, // not used
    pub coupon: Option<String>,                      // not used
    pub default_source: Option<String>,              // not used
    pub invoice_settings: Option<pii::SecretSerdeValue>, // not used
    pub next_invoice_sequence: Option<String>,       // not used
    pub preferred_locales: Option<String>,           // not used
    pub promotion_code: Option<String>,              // not used
    pub source: Option<String>,                      // not used
    pub tax: Option<pii::SecretSerdeValue>,          // not used
    pub tax_exempt: Option<String>,                  // not used
}

#[derive(Serialize, PartialEq, Eq)]
pub struct CreateCustomerResponse {
    pub id: id_type::CustomerId,
    pub object: String,
    pub created: u64,
    pub description: Option<Description>,
    pub email: Option<Email>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub name: Option<masking::Secret<String>>,
    pub phone: Option<masking::Secret<String, masking::WithType>>,
}

pub type CustomerRetrieveResponse = CreateCustomerResponse;
pub type CustomerUpdateResponse = CreateCustomerResponse;

#[derive(Serialize, PartialEq, Eq)]
pub struct CustomerDeleteResponse {
    pub id: id_type::CustomerId,
    pub deleted: bool,
}

impl From<StripeAddressDetails> for payments::AddressDetails {
    fn from(address: StripeAddressDetails) -> Self {
        Self {
            city: address.city,
            country: address.country,
            line1: address.line1,
            line2: address.line2,
            zip: address.postal_code,
            state: address.state,
            first_name: None,
            line3: None,
            last_name: None,
            origin_zip: None,
        }
    }
}

#[cfg(feature = "v1")]
impl From<CreateCustomerRequest> for api::CustomerRequest {
    fn from(req: CreateCustomerRequest) -> Self {
        Self {
            customer_id: Some(common_utils::generate_customer_id_of_default_length()),
            name: req.name,
            phone: req.phone,
            email: req.email,
            description: req.description,
            metadata: req.metadata,
            address: req.address.map(|s| s.into()),
            ..Default::default()
        }
    }
}

#[cfg(feature = "v1")]
impl From<CustomerUpdateRequest> for api::CustomerUpdateRequest {
    fn from(req: CustomerUpdateRequest) -> Self {
        Self {
            name: req.name,
            phone: req.phone,
            email: req.email,
            description: req.description,
            metadata: req.metadata,
            address: req.address.map(|s| s.into()),
            ..Default::default()
        }
    }
}

#[cfg(feature = "v1")]
impl From<api::CustomerResponse> for CreateCustomerResponse {
    fn from(cust: api::CustomerResponse) -> Self {
        let cust = cust.into_inner();
        Self {
            id: cust.customer_id,
            object: "customer".to_owned(),
            created: u64::try_from(cust.created_at.assume_utc().unix_timestamp()).unwrap_or_else(
                |error| {
                    logger::error!(
                        %error,
                        "incorrect value for `customer.created_at` provided {}", cust.created_at
                    );
                    // Current timestamp converted to Unix timestamp should have a positive value
                    // for many years to come
                    u64::try_from(date_time::now().assume_utc().unix_timestamp())
                        .unwrap_or_default()
                },
            ),
            description: cust.description,
            email: cust.email.map(|inner| inner.into()),
            metadata: cust.metadata,
            name: cust.name.map(Encryptable::into_inner),
            phone: cust.phone.map(Encryptable::into_inner),
        }
    }
}

#[cfg(feature = "v1")]
impl From<api::CustomerDeleteResponse> for CustomerDeleteResponse {
    fn from(cust: api::CustomerDeleteResponse) -> Self {
        Self {
            id: cust.customer_id,
            deleted: cust.customer_deleted,
        }
    }
}

#[derive(Default, Serialize, PartialEq, Eq)]
pub struct CustomerPaymentMethodListResponse {
    pub object: &'static str,
    pub data: Vec<PaymentMethodData>,
}

#[derive(Default, Serialize, PartialEq, Eq)]
pub struct PaymentMethodData {
    pub id: Option<String>,
    pub object: &'static str,
    pub card: Option<CardDetails>,
    pub created: Option<time::PrimitiveDateTime>,
}

#[derive(Default, Serialize, PartialEq, Eq)]
pub struct CardDetails {
    pub country: Option<String>,
    pub last4: Option<String>,
    pub exp_month: Option<masking::Secret<String>>,
    pub exp_year: Option<masking::Secret<String>>,
    pub fingerprint: Option<masking::Secret<String>>,
}

#[cfg(feature = "v1")]
impl From<api::CustomerPaymentMethodsListResponse> for CustomerPaymentMethodListResponse {
    fn from(item: api::CustomerPaymentMethodsListResponse) -> Self {
        let customer_payment_methods = item.customer_payment_methods;
        let data = customer_payment_methods
            .into_iter()
            .map(From::from)
            .collect();
        Self {
            object: "list",
            data,
        }
    }
}

#[cfg(feature = "v1")]
impl From<api_types::CustomerPaymentMethod> for PaymentMethodData {
    fn from(item: api_types::CustomerPaymentMethod) -> Self {
        let card = item.card.map(From::from);
        Self {
            id: Some(item.payment_token),
            object: "payment_method",
            card,
            created: item.created,
        }
    }
}

#[cfg(feature = "v1")]
impl From<api_types::CardDetailFromLocker> for CardDetails {
    fn from(item: api_types::CardDetailFromLocker) -> Self {
        Self {
            country: item.issuer_country,
            last4: item.last4_digits,
            exp_month: item.expiry_month,
            exp_year: item.expiry_year,
            fingerprint: item.card_fingerprint,
        }
    }
}


// File: crates/currency_conversion/src/types.rs
// Module: currency_conversion
// Public functions: 5
// Public structs: 2

use std::collections::HashMap;

use common_enums::Currency;
use rust_decimal::Decimal;
use rusty_money::iso;

use crate::error::CurrencyConversionError;

/// Cached currency store of base currency
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct ExchangeRates {
    pub base_currency: Currency,
    pub conversion: HashMap<Currency, CurrencyFactors>,
}

/// Stores the multiplicative factor for  conversion between currency to base and vice versa
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct CurrencyFactors {
    /// The factor that will be multiplied to provide Currency output
    pub to_factor: Decimal,
    /// The factor that will be multiplied to provide for the base output
    pub from_factor: Decimal,
}

impl CurrencyFactors {
    pub fn new(to_factor: Decimal, from_factor: Decimal) -> Self {
        Self {
            to_factor,
            from_factor,
        }
    }
}

impl ExchangeRates {
    pub fn new(base_currency: Currency, conversion: HashMap<Currency, CurrencyFactors>) -> Self {
        Self {
            base_currency,
            conversion,
        }
    }

    /// The flow here is from_currency -> base_currency -> to_currency
    /// from to_currency -> base currency
    pub fn forward_conversion(
        &self,
        amt: Decimal,
        from_currency: Currency,
    ) -> Result<Decimal, CurrencyConversionError> {
        let from_factor = self
            .conversion
            .get(&from_currency)
            .ok_or_else(|| {
                CurrencyConversionError::ConversionNotSupported(from_currency.to_string())
            })?
            .from_factor;
        amt.checked_mul(from_factor)
            .ok_or(CurrencyConversionError::DecimalMultiplicationFailed)
    }

    /// from base_currency -> to_currency
    pub fn backward_conversion(
        &self,
        amt: Decimal,
        to_currency: Currency,
    ) -> Result<Decimal, CurrencyConversionError> {
        let to_factor = self
            .conversion
            .get(&to_currency)
            .ok_or_else(|| {
                CurrencyConversionError::ConversionNotSupported(to_currency.to_string())
            })?
            .to_factor;
        amt.checked_mul(to_factor)
            .ok_or(CurrencyConversionError::DecimalMultiplicationFailed)
    }
}

pub fn currency_match(currency: Currency) -> &'static iso::Currency {
    match currency {
        Currency::AED => iso::AED,
        Currency::AFN => iso::AFN,
        Currency::ALL => iso::ALL,
        Currency::AMD => iso::AMD,
        Currency::ANG => iso::ANG,
        Currency::AOA => iso::AOA,
        Currency::ARS => iso::ARS,
        Currency::AUD => iso::AUD,
        Currency::AWG => iso::AWG,
        Currency::AZN => iso::AZN,
        Currency::BAM => iso::BAM,
        Currency::BBD => iso::BBD,
        Currency::BDT => iso::BDT,
        Currency::BGN => iso::BGN,
        Currency::BHD => iso::BHD,
        Currency::BIF => iso::BIF,
        Currency::BMD => iso::BMD,
        Currency::BND => iso::BND,
        Currency::BOB => iso::BOB,
        Currency::BRL => iso::BRL,
        Currency::BSD => iso::BSD,
        Currency::BTN => iso::BTN,
        Currency::BWP => iso::BWP,
        Currency::BYN => iso::BYN,
        Currency::BZD => iso::BZD,
        Currency::CAD => iso::CAD,
        Currency::CDF => iso::CDF,
        Currency::CHF => iso::CHF,
        Currency::CLF => iso::CLF,
        Currency::CLP => iso::CLP,
        Currency::CNY => iso::CNY,
        Currency::COP => iso::COP,
        Currency::CRC => iso::CRC,
        Currency::CUC => iso::CUC,
        Currency::CUP => iso::CUP,
        Currency::CVE => iso::CVE,
        Currency::CZK => iso::CZK,
        Currency::DJF => iso::DJF,
        Currency::DKK => iso::DKK,
        Currency::DOP => iso::DOP,
        Currency::DZD => iso::DZD,
        Currency::EGP => iso::EGP,
        Currency::ERN => iso::ERN,
        Currency::ETB => iso::ETB,
        Currency::EUR => iso::EUR,
        Currency::FJD => iso::FJD,
        Currency::FKP => iso::FKP,
        Currency::GBP => iso::GBP,
        Currency::GEL => iso::GEL,
        Currency::GHS => iso::GHS,
        Currency::GIP => iso::GIP,
        Currency::GMD => iso::GMD,
        Currency::GNF => iso::GNF,
        Currency::GTQ => iso::GTQ,
        Currency::GYD => iso::GYD,
        Currency::HKD => iso::HKD,
        Currency::HNL => iso::HNL,
        Currency::HRK => iso::HRK,
        Currency::HTG => iso::HTG,
        Currency::HUF => iso::HUF,
        Currency::IDR => iso::IDR,
        Currency::ILS => iso::ILS,
        Currency::INR => iso::INR,
        Currency::IQD => iso::IQD,
        Currency::IRR => iso::IRR,
        Currency::ISK => iso::ISK,
        Currency::JMD => iso::JMD,
        Currency::JOD => iso::JOD,
        Currency::JPY => iso::JPY,
        Currency::KES => iso::KES,
        Currency::KGS => iso::KGS,
        Currency::KHR => iso::KHR,
        Currency::KMF => iso::KMF,
        Currency::KPW => iso::KPW,
        Currency::KRW => iso::KRW,
        Currency::KWD => iso::KWD,
        Currency::KYD => iso::KYD,
        Currency::KZT => iso::KZT,
        Currency::LAK => iso::LAK,
        Currency::LBP => iso::LBP,
        Currency::LKR => iso::LKR,
        Currency::LRD => iso::LRD,
        Currency::LSL => iso::LSL,
        Currency::LYD => iso::LYD,
        Currency::MAD => iso::MAD,
        Currency::MDL => iso::MDL,
        Currency::MGA => iso::MGA,
        Currency::MKD => iso::MKD,
        Currency::MMK => iso::MMK,
        Currency::MNT => iso::MNT,
        Currency::MOP => iso::MOP,
        Currency::MRU => iso::MRU,
        Currency::MUR => iso::MUR,
        Currency::MVR => iso::MVR,
        Currency::MWK => iso::MWK,
        Currency::MXN => iso::MXN,
        Currency::MYR => iso::MYR,
        Currency::MZN => iso::MZN,
        Currency::NAD => iso::NAD,
        Currency::NGN => iso::NGN,
        Currency::NIO => iso::NIO,
        Currency::NOK => iso::NOK,
        Currency::NPR => iso::NPR,
        Currency::NZD => iso::NZD,
        Currency::OMR => iso::OMR,
        Currency::PAB => iso::PAB,
        Currency::PEN => iso::PEN,
        Currency::PGK => iso::PGK,
        Currency::PHP => iso::PHP,
        Currency::PKR => iso::PKR,
        Currency::PLN => iso::PLN,
        Currency::PYG => iso::PYG,
        Currency::QAR => iso::QAR,
        Currency::RON => iso::RON,
        Currency::RSD => iso::RSD,
        Currency::RUB => iso::RUB,
        Currency::RWF => iso::RWF,
        Currency::SAR => iso::SAR,
        Currency::SBD => iso::SBD,
        Currency::SCR => iso::SCR,
        Currency::SDG => iso::SDG,
        Currency::SEK => iso::SEK,
        Currency::SGD => iso::SGD,
        Currency::SHP => iso::SHP,
        Currency::SLE => iso::SLE,
        Currency::SLL => iso::SLL,
        Currency::SOS => iso::SOS,
        Currency::SRD => iso::SRD,
        Currency::SSP => iso::SSP,
        Currency::STD => iso::STD,
        Currency::STN => iso::STN,
        Currency::SVC => iso::SVC,
        Currency::SYP => iso::SYP,
        Currency::SZL => iso::SZL,
        Currency::THB => iso::THB,
        Currency::TJS => iso::TJS,
        Currency::TND => iso::TND,
        Currency::TMT => iso::TMT,
        Currency::TOP => iso::TOP,
        Currency::TTD => iso::TTD,
        Currency::TRY => iso::TRY,
        Currency::TWD => iso::TWD,
        Currency::TZS => iso::TZS,
        Currency::UAH => iso::UAH,
        Currency::UGX => iso::UGX,
        Currency::USD => iso::USD,
        Currency::UYU => iso::UYU,
        Currency::UZS => iso::UZS,
        Currency::VES => iso::VES,
        Currency::VND => iso::VND,
        Currency::VUV => iso::VUV,
        Currency::WST => iso::WST,
        Currency::XAF => iso::XAF,
        Currency::XCD => iso::XCD,
        Currency::XOF => iso::XOF,
        Currency::XPF => iso::XPF,
        Currency::YER => iso::YER,
        Currency::ZAR => iso::ZAR,
        Currency::ZMW => iso::ZMW,
        Currency::ZWL => iso::ZWL,
    }
}


// File: crates/diesel_models/src/query/utils.rs
// Module: diesel_models

use diesel;

use crate::{schema, schema_v2};

/// This trait will return a single column as primary key even in case of composite primary key.
///
/// In case of composite key, it will return the column that is used as local unique.
pub(super) trait GetPrimaryKey: diesel::Table {
    type PK: diesel::ExpressionMethods;
    fn get_primary_key(&self) -> Self::PK;
}

/// This trait must be implemented for all composite keys.
pub(super) trait CompositeKey {
    type UK;
    /// It will return the local unique key of the composite key.
    ///
    /// If `(attempt_id, merchant_id)` is the composite key for `payment_attempt` table, then it will return `attempt_id`.
    fn get_local_unique_key(&self) -> Self::UK;
}

/// implementation of `CompositeKey` trait for all the composite keys must be done here.
mod composite_key {
    use super::{schema, schema_v2, CompositeKey};
    impl CompositeKey for <schema::payment_attempt::table as diesel::Table>::PrimaryKey {
        type UK = schema::payment_attempt::dsl::attempt_id;
        fn get_local_unique_key(&self) -> Self::UK {
            self.0
        }
    }
    impl CompositeKey for <schema::refund::table as diesel::Table>::PrimaryKey {
        type UK = schema::refund::dsl::refund_id;
        fn get_local_unique_key(&self) -> Self::UK {
            self.1
        }
    }
    impl CompositeKey for <schema::customers::table as diesel::Table>::PrimaryKey {
        type UK = schema::customers::dsl::customer_id;
        fn get_local_unique_key(&self) -> Self::UK {
            self.0
        }
    }
    impl CompositeKey for <schema::blocklist::table as diesel::Table>::PrimaryKey {
        type UK = schema::blocklist::dsl::fingerprint_id;
        fn get_local_unique_key(&self) -> Self::UK {
            self.1
        }
    }
    impl CompositeKey for <schema::incremental_authorization::table as diesel::Table>::PrimaryKey {
        type UK = schema::incremental_authorization::dsl::authorization_id;
        fn get_local_unique_key(&self) -> Self::UK {
            self.0
        }
    }
    impl CompositeKey for <schema::hyperswitch_ai_interaction::table as diesel::Table>::PrimaryKey {
        type UK = schema::hyperswitch_ai_interaction::dsl::id;
        fn get_local_unique_key(&self) -> Self::UK {
            self.0
        }
    }
    impl CompositeKey for <schema_v2::incremental_authorization::table as diesel::Table>::PrimaryKey {
        type UK = schema_v2::incremental_authorization::dsl::authorization_id;
        fn get_local_unique_key(&self) -> Self::UK {
            self.0
        }
    }
    impl CompositeKey for <schema_v2::blocklist::table as diesel::Table>::PrimaryKey {
        type UK = schema_v2::blocklist::dsl::fingerprint_id;
        fn get_local_unique_key(&self) -> Self::UK {
            self.1
        }
    }
}

/// This macro will implement the `GetPrimaryKey` trait for all the tables with single primary key.
macro_rules! impl_get_primary_key {
    ($($table:ty),*) => {
        $(
            impl GetPrimaryKey for $table
            {
                type PK = <$table as diesel::Table>::PrimaryKey;
                fn get_primary_key(&self) -> Self::PK {
                    <Self as diesel::Table>::primary_key(self)
                }
            }
        )*
    };
}
impl_get_primary_key!(
    // v1 tables
    schema::dashboard_metadata::table,
    schema::merchant_connector_account::table,
    schema::merchant_key_store::table,
    schema::payment_methods::table,
    schema::user_authentication_methods::table,
    schema::user_key_store::table,
    schema::users::table,
    schema::api_keys::table,
    schema::captures::table,
    schema::business_profile::table,
    schema::mandate::dsl::mandate,
    schema::dispute::table,
    schema::events::table,
    schema::merchant_account::table,
    schema::process_tracker::table,
    // v2 tables
    schema_v2::dashboard_metadata::table,
    schema_v2::merchant_connector_account::table,
    schema_v2::merchant_key_store::table,
    schema_v2::payment_methods::table,
    schema_v2::user_authentication_methods::table,
    schema_v2::user_key_store::table,
    schema_v2::users::table,
    schema_v2::api_keys::table,
    schema_v2::captures::table,
    schema_v2::business_profile::table,
    schema_v2::mandate::table,
    schema_v2::dispute::table,
    schema_v2::events::table,
    schema_v2::merchant_account::table,
    schema_v2::process_tracker::table,
    schema_v2::refund::table,
    schema_v2::customers::table,
    schema_v2::payment_attempt::table
);

/// This macro will implement the `GetPrimaryKey` trait for all the tables with composite key.
macro_rules! impl_get_primary_key_for_composite {
    ($($table:ty),*) => {
        $(
            impl GetPrimaryKey for $table
            {
                type PK = <<$table as diesel::Table>::PrimaryKey as CompositeKey>::UK;
                fn get_primary_key(&self) -> Self::PK {
                    <Self as diesel::Table>::primary_key(self).get_local_unique_key()
                }
            }
        )*
    };
}

impl_get_primary_key_for_composite!(
    schema::payment_attempt::table,
    schema::refund::table,
    schema::customers::table,
    schema::blocklist::table,
    schema::incremental_authorization::table,
    schema::hyperswitch_ai_interaction::table,
    schema_v2::incremental_authorization::table,
    schema_v2::blocklist::table
);


// Function: generate_permissions_inner
// File: crates/router_derive/src/macros/generate_permissions.rs
// Module: router_derive

pub fn generate_permissions_inner(input: TokenStream) -> TokenStream


// Implementation: impl Responder
// File: crates/router/src/analytics.rs
// Module: router
// Methods: 0 total (0 public)

impl Responder


// Struct: CeleroVoidResponse
// File: crates/hyperswitch_connectors/src/connectors/celero/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CeleroVoidResponse


// Struct: PaymentValue
// File: crates/hyperswitch_connectors/src/connectors/worldpay/requests.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PaymentValue


// Function: tokenize_card_using_pm_api
// File: crates/openapi/src/routes/payment_method.rs
// Module: openapi

pub fn tokenize_card_using_pm_api()


// Implementation: impl RefundSync for for Riskified
// File: crates/hyperswitch_connectors/src/connectors/riskified.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl RefundSync for for Riskified


// Implementation: impl api::RefundSync for for Rapyd
// File: crates/hyperswitch_connectors/src/connectors/rapyd.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::RefundSync for for Rapyd


// Struct: DrainerSettings
// File: crates/scheduler/src/settings.rs
// Module: scheduler
// Implementations: 2
// Traits: Default

pub struct DrainerSettings


// Implementation: impl api::Payment for for Paystack
// File: crates/hyperswitch_connectors/src/connectors/paystack.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::Payment for for Paystack


// Function: validate
// File: crates/router/src/configs/validations.rs
// Module: router

pub fn validate(&self) -> Result<(), ApplicationError>


// Implementation: impl api::Payment for for Sift
// File: crates/hyperswitch_connectors/src/connectors/sift.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::Payment for for Sift


// Implementation: impl Capturable for for PaymentsRejectData
// File: crates/router/src/types.rs
// Module: router
// Methods: 0 total (0 public)

impl Capturable for for PaymentsRejectData


// Implementation: impl super::auth_events::metrics::AuthEventMetricAnalytics for for SqlxClient
// File: crates/analytics/src/sqlx.rs
// Module: analytics
// Methods: 0 total (0 public)

impl super::auth_events::metrics::AuthEventMetricAnalytics for for SqlxClient


// Implementation: impl Deref for for EnablePartialAuthorizationBool
// File: crates/common_types/src/primitive_wrappers.rs
// Module: common_types
// Methods: 1 total (0 public)

impl Deref for for EnablePartialAuthorizationBool


// Function: get_payment_link_response_from_id
// File: crates/router/src/core/payments.rs
// Module: router

pub fn get_payment_link_response_from_id(
    state: &SessionState,
    payment_link_id: &str,
) -> CustomResult<api_models::payments::PaymentLinkResponse, errors::ApiErrorResponse>


// Struct: ChargebeeRouterData
// File: crates/hyperswitch_connectors/src/connectors/chargebee/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ChargebeeRouterData<T>


// File: crates/hyperswitch_connectors/src/connectors/nexinets.rs
// Module: hyperswitch_connectors
// Public functions: 1
// Public structs: 1

pub mod transformers;
use std::sync::LazyLock;

use api_models::webhooks::{IncomingWebhookEvent, ObjectReferenceId};
use common_enums::enums;
use common_utils::{
    errors::CustomResult,
    ext_traits::ByteSliceExt,
    request::{Method, Request, RequestBuilder, RequestContent},
};
use error_stack::{report, ResultExt};
use hyperswitch_domain_models::{
    errors::api_error_response::ApiErrorResponse,
    payment_method_data::PaymentMethodData,
    payments::payment_attempt::PaymentAttempt,
    router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData},
    router_flow_types::{
        access_token_auth::AccessTokenAuth,
        payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void},
        refunds::{Execute, RSync},
    },
    router_request_types::{
        AccessTokenRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData,
        PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData,
        RefundsData, SetupMandateRequestData,
    },
    router_response_types::{
        ConnectorInfo, PaymentMethodDetails, PaymentsResponseData, RefundsResponseData,
        SupportedPaymentMethods, SupportedPaymentMethodsExt,
    },
    types::{
        PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
        PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData,
    },
};
use hyperswitch_interfaces::{
    api::{
        self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorSpecifications,
        ConnectorTransactionId, ConnectorValidation,
    },
    configs::Connectors,
    errors,
    events::connector_api_logs::ConnectorEvent,
    types::{
        PaymentsAuthorizeType, PaymentsCaptureType, PaymentsSyncType, PaymentsVoidType,
        RefundExecuteType, RefundSyncType, Response,
    },
    webhooks::{IncomingWebhook, IncomingWebhookRequestDetails},
};
use masking::Mask;
#[cfg(feature = "v2")]
use masking::PeekInterface;
use transformers as nexinets;

use crate::{
    constants::headers,
    types::ResponseRouterData,
    utils::{
        is_mandate_supported, to_connector_meta, PaymentMethodDataType, PaymentsSyncRequestData,
    },
};

#[derive(Debug, Clone)]
pub struct Nexinets;

impl api::Payment for Nexinets {}
impl api::PaymentSession for Nexinets {}
impl api::ConnectorAccessToken for Nexinets {}
impl api::MandateSetup for Nexinets {}
impl api::PaymentAuthorize for Nexinets {}
impl api::PaymentSync for Nexinets {}
impl api::PaymentCapture for Nexinets {}
impl api::PaymentVoid for Nexinets {}
impl api::Refund for Nexinets {}
impl api::RefundExecute for Nexinets {}
impl api::RefundSync for Nexinets {}

impl Nexinets {
    pub fn connector_transaction_id(
        &self,
        connector_meta: Option<&serde_json::Value>,
    ) -> CustomResult<Option<String>, errors::ConnectorError> {
        let meta: nexinets::NexinetsPaymentsMetadata = to_connector_meta(connector_meta.cloned())?;
        Ok(meta.transaction_id)
    }
}

impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Nexinets
where
    Self: ConnectorIntegration<Flow, Request, Response>,
{
    fn build_headers(
        &self,
        req: &RouterData<Flow, Request, Response>,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        let mut header = vec![(
            headers::CONTENT_TYPE.to_string(),
            self.get_content_type().to_string().into(),
        )];
        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
        header.append(&mut api_key);
        Ok(header)
    }
}

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

    fn common_get_content_type(&self) -> &'static str {
        "application/json"
    }

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

    fn get_auth_header(
        &self,
        auth_type: &ConnectorAuthType,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        let auth = nexinets::NexinetsAuthType::try_from(auth_type)
            .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
        Ok(vec![(
            headers::AUTHORIZATION.to_string(),
            auth.api_key.into_masked(),
        )])
    }

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

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

        let errors = response.errors;
        let mut message = String::new();
        let mut static_message = String::new();
        for error in errors.iter() {
            let field = error.field.to_owned().unwrap_or_default();
            let mut msg = String::new();
            if !field.is_empty() {
                msg.push_str(format!("{} : {}", field, error.message).as_str());
            } else {
                error.message.clone_into(&mut msg)
            }
            if message.is_empty() {
                message.push_str(&msg);
                static_message.push_str(&msg);
            } else {
                message.push_str(format!(", {msg}").as_str());
            }
        }
        let connector_reason = format!("reason : {} , message : {}", response.message, message);

        Ok(ErrorResponse {
            status_code: response.status,
            code: response.code.to_string(),
            message: static_message,
            reason: Some(connector_reason),
            attempt_status: None,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    }
}

impl ConnectorValidation for Nexinets {
    fn validate_mandate_payment(
        &self,
        pm_type: Option<enums::PaymentMethodType>,
        pm_data: PaymentMethodData,
    ) -> CustomResult<(), errors::ConnectorError> {
        let mandate_supported_pmd = std::collections::HashSet::from([
            PaymentMethodDataType::Card,
            PaymentMethodDataType::PaypalRedirect,
            PaymentMethodDataType::ApplePay,
            PaymentMethodDataType::Eps,
            PaymentMethodDataType::Giropay,
            PaymentMethodDataType::Ideal,
        ]);
        is_mandate_supported(pm_data, pm_type, mandate_supported_pmd, self.id())
    }
}

impl ConnectorIntegration<Session, PaymentsSessionData, PaymentsResponseData> for Nexinets {}

impl ConnectorIntegration<AccessTokenAuth, AccessTokenRequestData, AccessToken> for Nexinets {}

impl ConnectorIntegration<SetupMandate, SetupMandateRequestData, PaymentsResponseData>
    for Nexinets
{
    fn build_request(
        &self,
        _req: &RouterData<SetupMandate, SetupMandateRequestData, PaymentsResponseData>,
        _connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Err(
            errors::ConnectorError::NotImplemented("Setup Mandate flow for Nexinets".to_string())
                .into(),
        )
    }
}

impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData> for Nexinets {
    fn get_headers(
        &self,
        req: &PaymentsAuthorizeRouterData,
        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: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let url = if matches!(
            req.request.capture_method,
            Some(enums::CaptureMethod::Automatic) | Some(enums::CaptureMethod::SequentialAutomatic)
        ) {
            format!("{}/orders/debit", self.base_url(connectors))
        } else {
            format!("{}/orders/preauth", self.base_url(connectors))
        };
        Ok(url)
    }

    fn get_request_body(
        &self,
        req: &PaymentsAuthorizeRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = nexinets::NexinetsPaymentsRequest::try_from(req)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&PaymentsAuthorizeType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(PaymentsAuthorizeType::get_headers(self, req, connectors)?)
                .set_body(PaymentsAuthorizeType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsAuthorizeRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsAuthorizeRouterData, errors::ConnectorError> {
        let response: nexinets::NexinetsPreAuthOrDebitResponse = res
            .response
            .parse_struct("Nexinets PaymentsAuthorizeResponse")
            .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<PSync, PaymentsSyncData, PaymentsResponseData> for Nexinets {
    fn get_headers(
        &self,
        req: &PaymentsSyncRouterData,
        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: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let meta: nexinets::NexinetsPaymentsMetadata =
            to_connector_meta(req.request.connector_meta.clone())?;
        let order_id = nexinets::get_order_id(&meta)?;
        let transaction_id = match meta.psync_flow {
            transformers::NexinetsTransactionType::Debit
            | transformers::NexinetsTransactionType::Capture => {
                req.request.get_connector_transaction_id()?
            }
            _ => nexinets::get_transaction_id(&meta)?,
        };
        Ok(format!(
            "{}/orders/{order_id}/transactions/{transaction_id}",
            self.base_url(connectors)
        ))
    }

    fn build_request(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Get)
                .url(&PaymentsSyncType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(PaymentsSyncType::get_headers(self, req, connectors)?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsSyncRouterData, errors::ConnectorError> {
        let response: nexinets::NexinetsPaymentResponse = res
            .response
            .parse_struct("nexinets NexinetsPaymentResponse")
            .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<Capture, PaymentsCaptureData, PaymentsResponseData> for Nexinets {
    fn get_headers(
        &self,
        req: &PaymentsCaptureRouterData,
        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: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let meta: nexinets::NexinetsPaymentsMetadata =
            to_connector_meta(req.request.connector_meta.clone())?;
        let order_id = nexinets::get_order_id(&meta)?;
        let transaction_id = nexinets::get_transaction_id(&meta)?;
        Ok(format!(
            "{}/orders/{order_id}/transactions/{transaction_id}/capture",
            self.base_url(connectors)
        ))
    }

    fn get_request_body(
        &self,
        req: &PaymentsCaptureRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = nexinets::NexinetsCaptureOrVoidRequest::try_from(req)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&PaymentsCaptureType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(PaymentsCaptureType::get_headers(self, req, connectors)?)
                .set_body(PaymentsCaptureType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsCaptureRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCaptureRouterData, errors::ConnectorError> {
        let response: nexinets::NexinetsPaymentResponse = res
            .response
            .parse_struct("NexinetsPaymentResponse")
            .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<Void, PaymentsCancelData, PaymentsResponseData> for Nexinets {
    fn get_headers(
        &self,
        req: &PaymentsCancelRouterData,
        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: &PaymentsCancelRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let meta: nexinets::NexinetsPaymentsMetadata =
            to_connector_meta(req.request.connector_meta.clone())?;
        let order_id = nexinets::get_order_id(&meta)?;
        let transaction_id = nexinets::get_transaction_id(&meta)?;
        Ok(format!(
            "{}/orders/{order_id}/transactions/{transaction_id}/cancel",
            self.base_url(connectors),
        ))
    }

    fn get_request_body(
        &self,
        req: &PaymentsCancelRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = nexinets::NexinetsCaptureOrVoidRequest::try_from(req)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &PaymentsCancelRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let request = RequestBuilder::new()
            .method(Method::Post)
            .url(&PaymentsVoidType::get_url(self, req, connectors)?)
            .headers(PaymentsVoidType::get_headers(self, req, connectors)?)
            .set_body(PaymentsVoidType::get_request_body(self, req, connectors)?)
            .build();

        Ok(Some(request))
    }

    fn handle_response(
        &self,
        data: &PaymentsCancelRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCancelRouterData, errors::ConnectorError> {
        let response: nexinets::NexinetsPaymentResponse = res
            .response
            .parse_struct("NexinetsPaymentResponse")
            .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<Execute, RefundsData, RefundsResponseData> for Nexinets {
    fn get_headers(
        &self,
        req: &RefundsRouterData<Execute>,
        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: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let meta: nexinets::NexinetsPaymentsMetadata =
            to_connector_meta(req.request.connector_metadata.clone())?;
        let order_id = nexinets::get_order_id(&meta)?;
        Ok(format!(
            "{}/orders/{order_id}/transactions/{}/refund",
            self.base_url(connectors),
            req.request.connector_transaction_id
        ))
    }

    fn get_request_body(
        &self,
        req: &RefundsRouterData<Execute>,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = nexinets::NexinetsRefundRequest::try_from(req)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let request = RequestBuilder::new()
            .method(Method::Post)
            .url(&RefundExecuteType::get_url(self, req, connectors)?)
            .attach_default_headers()
            .headers(RefundExecuteType::get_headers(self, req, connectors)?)
            .set_body(RefundExecuteType::get_request_body(self, req, connectors)?)
            .build();
        Ok(Some(request))
    }

    fn handle_response(
        &self,
        data: &RefundsRouterData<Execute>,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefundsRouterData<Execute>, errors::ConnectorError> {
        let response: nexinets::NexinetsRefundResponse = res
            .response
            .parse_struct("nexinets RefundResponse")
            .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<RSync, RefundsData, RefundsResponseData> for Nexinets {
    fn get_headers(
        &self,
        req: &RefundSyncRouterData,
        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: &RefundSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let transaction_id = req
            .request
            .connector_refund_id
            .clone()
            .ok_or(errors::ConnectorError::MissingConnectorRefundID)?;
        let meta: nexinets::NexinetsPaymentsMetadata =
            to_connector_meta(req.request.connector_metadata.clone())?;
        let order_id = nexinets::get_order_id(&meta)?;
        Ok(format!(
            "{}/orders/{order_id}/transactions/{transaction_id}",
            self.base_url(connectors)
        ))
    }

    fn build_request(
        &self,
        req: &RefundSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Get)
                .url(&RefundSyncType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(RefundSyncType::get_headers(self, req, connectors)?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &RefundSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefundSyncRouterData, errors::ConnectorError> {
        let response: nexinets::NexinetsRefundResponse = res
            .response
            .parse_struct("nexinets RefundSyncResponse")
            .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)
    }
}

#[async_trait::async_trait]
impl IncomingWebhook for Nexinets {
    fn get_webhook_object_reference_id(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<ObjectReferenceId, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }

    fn get_webhook_event_type(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<IncomingWebhookEvent, errors::ConnectorError> {
        Ok(IncomingWebhookEvent::EventNotSupported)
    }

    fn get_webhook_resource_object(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }
}

impl api::PaymentToken for Nexinets {}

impl ConnectorIntegration<PaymentMethodToken, PaymentMethodTokenizationData, PaymentsResponseData>
    for Nexinets
{
    // Not Implemented (R)
}

static NEXINETS_SUPPORTED_PAYMENT_METHODS: LazyLock<SupportedPaymentMethods> =
    LazyLock::new(|| {
        let supported_capture_methods = vec![
            enums::CaptureMethod::Automatic,
            enums::CaptureMethod::Manual,
            enums::CaptureMethod::SequentialAutomatic,
        ];

        let supported_card_network = vec![
            common_enums::CardNetwork::Visa,
            common_enums::CardNetwork::Mastercard,
            common_enums::CardNetwork::AmericanExpress,
            common_enums::CardNetwork::DinersClub,
            common_enums::CardNetwork::Discover,
            common_enums::CardNetwork::Interac,
            common_enums::CardNetwork::JCB,
            common_enums::CardNetwork::CartesBancaires,
            common_enums::CardNetwork::UnionPay,
        ];

        let mut nexinets_supported_payment_methods = SupportedPaymentMethods::new();

        nexinets_supported_payment_methods.add(
            enums::PaymentMethod::Card,
            enums::PaymentMethodType::Credit,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::Supported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: Some(
                    api_models::feature_matrix::PaymentMethodSpecificFeatures::Card({
                        api_models::feature_matrix::CardSpecificFeatures {
                            three_ds: common_enums::FeatureStatus::Supported,
                            no_three_ds: common_enums::FeatureStatus::Supported,
                            supported_card_networks: supported_card_network.clone(),
                        }
                    }),
                ),
            },
        );
        nexinets_supported_payment_methods.add(
            enums::PaymentMethod::Card,
            enums::PaymentMethodType::Debit,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::Supported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: Some(
                    api_models::feature_matrix::PaymentMethodSpecificFeatures::Card({
                        api_models::feature_matrix::CardSpecificFeatures {
                            three_ds: common_enums::FeatureStatus::Supported,
                            no_three_ds: common_enums::FeatureStatus::Supported,
                            supported_card_networks: supported_card_network.clone(),
                        }
                    }),
                ),
            },
        );

        nexinets_supported_payment_methods.add(
            enums::PaymentMethod::BankRedirect,
            enums::PaymentMethodType::Ideal,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );

        nexinets_supported_payment_methods.add(
            enums::PaymentMethod::BankRedirect,
            enums::PaymentMethodType::Giropay,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );
        nexinets_supported_payment_methods.add(
            enums::PaymentMethod::BankRedirect,
            enums::PaymentMethodType::Sofort,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );
        nexinets_supported_payment_methods.add(
            enums::PaymentMethod::BankRedirect,
            enums::PaymentMethodType::Eps,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );
        nexinets_supported_payment_methods.add(
            enums::PaymentMethod::Wallet,
            enums::PaymentMethodType::ApplePay,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );
        nexinets_supported_payment_methods.add(
            enums::PaymentMethod::Wallet,
            enums::PaymentMethodType::Paypal,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );

        nexinets_supported_payment_methods
    });

static NEXINETS_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
        display_name: "Nexinets",
        description: "Nexi and Nets join forces to create The European PayTech leader, a strategic combination to offer future-proof innovative payment solutions.",
        connector_type: enums::HyperswitchConnectorCategory::PaymentGateway,
        integration_status: enums::ConnectorIntegrationStatus::Sandbox,
    };

static NEXINETS_SUPPORTED_WEBHOOK_FLOWS: [enums::EventClass; 0] = [];

impl ConnectorSpecifications for Nexinets {
    fn get_connector_about(&self) -> Option<&'static ConnectorInfo> {
        Some(&NEXINETS_CONNECTOR_INFO)
    }

    fn get_supported_payment_methods(&self) -> Option<&'static SupportedPaymentMethods> {
        Some(&*NEXINETS_SUPPORTED_PAYMENT_METHODS)
    }

    fn get_supported_webhook_flows(&self) -> Option<&'static [enums::EventClass]> {
        Some(&NEXINETS_SUPPORTED_WEBHOOK_FLOWS)
    }
}

impl ConnectorTransactionId for Nexinets {
    #[cfg(feature = "v1")]
    fn connector_transaction_id(
        &self,
        payment_attempt: &PaymentAttempt,
    ) -> Result<Option<String>, ApiErrorResponse> {
        let metadata =
            Self::connector_transaction_id(self, payment_attempt.connector_metadata.as_ref());
        metadata.map_err(|_| ApiErrorResponse::ResourceIdNotFound)
    }

    #[cfg(feature = "v2")]
    fn connector_transaction_id(
        &self,
        payment_attempt: &PaymentAttempt,
    ) -> Result<Option<String>, ApiErrorResponse> {
        use hyperswitch_domain_models::errors::api_error_response::ApiErrorResponse;

        let metadata = Self::connector_transaction_id(
            self,
            payment_attempt
                .connector_metadata
                .as_ref()
                .map(|connector_metadata| connector_metadata.peek()),
        );
        metadata.map_err(|_| ApiErrorResponse::ResourceIdNotFound)
    }
}


// Struct: PreProcessing
// File: crates/hyperswitch_domain_models/src/router_flow_types/payments.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct PreProcessing


// File: crates/router/src/routes/process_tracker/revenue_recovery.rs
// Module: router
// Public functions: 2

use actix_web::{web, HttpRequest, HttpResponse};
use api_models::process_tracker::revenue_recovery as revenue_recovery_api;
use router_env::Flow;

use crate::{
    core::{api_locking, revenue_recovery},
    routes::AppState,
    services::{api, authentication as auth, authorization::permissions::Permission},
};

pub async fn revenue_recovery_pt_retrieve_api(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<common_utils::id_type::GlobalPaymentId>,
) -> HttpResponse {
    let flow = Flow::RevenueRecoveryRetrieve;
    let id = path.into_inner();
    let payload = revenue_recovery_api::RevenueRecoveryId {
        revenue_recovery_id: id,
    };

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, _: (), id, _| {
            revenue_recovery::retrieve_revenue_recovery_process_tracker(
                state,
                id.revenue_recovery_id,
            )
        },
        &auth::JWTAuth {
            permission: Permission::ProfileRevenueRecoveryRead,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

pub async fn revenue_recovery_resume_api(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<common_utils::id_type::GlobalPaymentId>,
    json_payload: web::Json<revenue_recovery_api::RevenueRecoveryRetriggerRequest>,
) -> HttpResponse {
    let flow = Flow::RevenueRecoveryResume;
    let id = path.into_inner();
    let payload = json_payload.into_inner();

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, _, payload, _| {
            revenue_recovery::resume_revenue_recovery_process_tracker(state, id.clone(), payload)
        },
        &auth::V2AdminApiAuth,
        api_locking::LockAction::NotApplicable,
    ))
    .await
}