// TODO: uncomment fields as and when required
#[cfg(feature = "v2")]
#[derive(Clone, Debug, AsChangeset, router_derive::DebugAsDisplay, Serialize, Deserialize)]
#[diesel(table_name = payment_attempt)]
pub struct PaymentAttemptUpdateInternal {
    pub status: Option<storage_enums::AttemptStatus>,
    pub authentication_type: Option<storage_enums::AuthenticationType>,
    pub error_message: Option<String>,
    pub connector_payment_id: Option<ConnectorTransactionId>,
    pub connector_payment_data: Option<String>,
    pub payment_method_id: Option<id_type::GlobalPaymentMethodId>,
    // cancellation_reason: Option<String>,
    pub modified_at: PrimitiveDateTime,
    pub browser_info: Option<serde_json::Value>,
    // payment_token: Option<String>,
    pub error_code: Option<String>,
    pub connector_metadata: Option<pii::SecretSerdeValue>,
    // payment_method_data: Option<serde_json::Value>,
    // payment_experience: Option<storage_enums::PaymentExperience>,
    // preprocessing_step_id: Option<String>,
    pub error_reason: Option<String>,
    pub connector_response_reference_id: Option<String>,
    // multiple_capture_count: Option<i16>,
    // pub surcharge_amount: Option<MinorUnit>,
    // tax_on_surcharge: Option<MinorUnit>,
    pub amount_capturable: Option<MinorUnit>,
    pub amount_to_capture: Option<MinorUnit>,
    pub updated_by: String,
    pub merchant_connector_id: Option<id_type::MerchantConnectorAccountId>,
    pub connector: Option<String>,
    pub redirection_data: Option<RedirectForm>,
    // encoded_data: Option<String>,
    pub unified_code: Option<String>,
    pub unified_message: Option<String>,
    // external_three_ds_authentication_attempted: Option<bool>,
    // authentication_connector: Option<String>,
    // authentication_id: Option<String>,
    // fingerprint_id: Option<String>,
    // charge_id: Option<String>,
    // client_source: Option<String>,
    // client_version: Option<String>,
    // customer_acceptance: Option<pii::SecretSerdeValue>,
    // card_network: Option<String>,
    pub connector_token_details: Option<ConnectorTokenDetails>,
    pub feature_metadata: Option<PaymentAttemptFeatureMetadata>,
    pub network_decline_code: Option<String>,
    pub network_advice_code: Option<String>,
    pub network_error_message: Option<String>,
    pub connector_request_reference_id: Option<String>,
}

#[cfg(feature = "v2")]
impl PaymentAttemptUpdateInternal {
    pub fn apply_changeset(self, source: PaymentAttempt) -> PaymentAttempt {
        let Self {
            status,
            authentication_type,
            error_message,
            connector_payment_id,
            connector_payment_data,
            modified_at,
            browser_info,
            error_code,
            connector_metadata,
            error_reason,
            amount_capturable,
            amount_to_capture,
            updated_by,
            merchant_connector_id,
            connector,
            redirection_data,
            unified_code,
            unified_message,
            connector_token_details,
            feature_metadata,
            network_decline_code,
            network_advice_code,
            network_error_message,
            payment_method_id,
            connector_request_reference_id,
            connector_response_reference_id,
        } = self;

        PaymentAttempt {
            payment_id: source.payment_id,
            merchant_id: source.merchant_id,
            status: status.unwrap_or(source.status),
            connector: connector.or(source.connector),
            error_message: error_message.or(source.error_message),
            surcharge_amount: source.surcharge_amount,
            payment_method_id: payment_method_id.or(source.payment_method_id),
            authentication_type: authentication_type.unwrap_or(source.authentication_type),
            created_at: source.created_at,
            modified_at: common_utils::date_time::now(),
            last_synced: source.last_synced,
            cancellation_reason: source.cancellation_reason,
            amount_to_capture: amount_to_capture.or(source.amount_to_capture),
            browser_info: browser_info
                .and_then(|val| {
                    serde_json::from_value::<common_utils::types::BrowserInformation>(val).ok()
                })
                .or(source.browser_info),
            error_code: error_code.or(source.error_code),
            payment_token: source.payment_token,
            connector_metadata: connector_metadata.or(source.connector_metadata),
            payment_experience: source.payment_experience,
            payment_method_data: source.payment_method_data,
            preprocessing_step_id: source.preprocessing_step_id,
            error_reason: error_reason.or(source.error_reason),
            multiple_capture_count: source.multiple_capture_count,
            connector_response_reference_id: connector_response_reference_id
                .or(source.connector_response_reference_id),
            amount_capturable: amount_capturable.unwrap_or(source.amount_capturable),
            updated_by,
            merchant_connector_id: merchant_connector_id.or(source.merchant_connector_id),
            encoded_data: source.encoded_data,
            unified_code: unified_code.or(source.unified_code),
            unified_message: unified_message.or(source.unified_message),
            net_amount: source.net_amount,
            external_three_ds_authentication_attempted: source
                .external_three_ds_authentication_attempted,
            authentication_connector: source.authentication_connector,
            authentication_id: source.authentication_id,
            fingerprint_id: source.fingerprint_id,
            client_source: source.client_source,
            client_version: source.client_version,
            customer_acceptance: source.customer_acceptance,
            profile_id: source.profile_id,
            organization_id: source.organization_id,
            card_network: source.card_network,
            shipping_cost: source.shipping_cost,
            order_tax_amount: source.order_tax_amount,
            request_extended_authorization: source.request_extended_authorization,
            extended_authorization_applied: source.extended_authorization_applied,
            capture_before: source.capture_before,
            card_discovery: source.card_discovery,
            charges: source.charges,
            processor_merchant_id: source.processor_merchant_id,
            created_by: source.created_by,
            payment_method_type_v2: source.payment_method_type_v2,
            network_transaction_id: source.network_transaction_id,
            connector_payment_id: connector_payment_id.or(source.connector_payment_id),
            payment_method_subtype: source.payment_method_subtype,
            routing_result: source.routing_result,
            authentication_applied: source.authentication_applied,
            external_reference_id: source.external_reference_id,
            tax_on_surcharge: source.tax_on_surcharge,
            payment_method_billing_address: source.payment_method_billing_address,
            redirection_data: redirection_data.or(source.redirection_data),
            connector_payment_data: connector_payment_data.or(source.connector_payment_data),
            connector_token_details: connector_token_details.or(source.connector_token_details),
            id: source.id,
            feature_metadata: feature_metadata.or(source.feature_metadata),
            network_advice_code: network_advice_code.or(source.network_advice_code),
            network_decline_code: network_decline_code.or(source.network_decline_code),
            network_error_message: network_error_message.or(source.network_error_message),
            connector_request_reference_id: connector_request_reference_id
                .or(source.connector_request_reference_id),
        }
    }
}
#[cfg(feature = "v1")]
#[derive(Clone, Debug, AsChangeset, router_derive::DebugAsDisplay)]
#[diesel(table_name = payment_attempt)]
pub struct PaymentAttemptUpdateInternal {
    pub amount: Option<MinorUnit>,
    pub net_amount: Option<MinorUnit>,
    pub currency: Option<storage_enums::Currency>,
    pub status: Option<storage_enums::AttemptStatus>,
    pub connector_transaction_id: Option<ConnectorTransactionId>,
    pub amount_to_capture: Option<MinorUnit>,
    pub connector: Option<Option<String>>,
    pub authentication_type: Option<storage_enums::AuthenticationType>,
    pub payment_method: Option<storage_enums::PaymentMethod>,
    pub error_message: Option<Option<String>>,
    pub payment_method_id: Option<String>,
    pub cancellation_reason: Option<String>,
    pub modified_at: PrimitiveDateTime,
    pub mandate_id: Option<String>,
    pub browser_info: Option<serde_json::Value>,
    pub payment_token: Option<String>,
    pub error_code: Option<Option<String>>,
    pub connector_metadata: Option<serde_json::Value>,
    pub payment_method_data: Option<serde_json::Value>,
    pub payment_method_type: Option<storage_enums::PaymentMethodType>,
    pub payment_experience: Option<storage_enums::PaymentExperience>,
    pub business_sub_label: Option<String>,
    pub straight_through_algorithm: Option<serde_json::Value>,
    pub preprocessing_step_id: Option<String>,
    pub error_reason: Option<Option<String>>,
    pub capture_method: Option<storage_enums::CaptureMethod>,
    pub connector_response_reference_id: Option<String>,
    pub multiple_capture_count: Option<i16>,
    pub surcharge_amount: Option<MinorUnit>,
    pub tax_amount: Option<MinorUnit>,
    pub amount_capturable: Option<MinorUnit>,
    pub updated_by: String,
    pub merchant_connector_id: Option<Option<id_type::MerchantConnectorAccountId>>,
    pub authentication_data: Option<serde_json::Value>,
    pub encoded_data: Option<String>,
    pub unified_code: Option<Option<String>>,
    pub unified_message: Option<Option<String>>,
    pub external_three_ds_authentication_attempted: Option<bool>,
    pub authentication_connector: Option<String>,
    pub authentication_id: Option<id_type::AuthenticationId>,
    pub fingerprint_id: Option<String>,
    pub payment_method_billing_address_id: Option<String>,
    pub client_source: Option<String>,
    pub client_version: Option<String>,
    pub customer_acceptance: Option<pii::SecretSerdeValue>,
    pub card_network: Option<String>,
    pub capture_before: Option<PrimitiveDateTime>,
    pub extended_authorization_applied: Option<ExtendedAuthorizationAppliedBool>,
    pub shipping_cost: Option<MinorUnit>,
    pub order_tax_amount: Option<MinorUnit>,
    pub connector_mandate_detail: Option<ConnectorMandateReferenceId>,
    pub processor_transaction_data: Option<String>,
    pub card_discovery: Option<common_enums::CardDiscovery>,
    pub charges: Option<common_types::payments::ConnectorChargeResponseData>,
    pub issuer_error_code: Option<String>,
    pub issuer_error_message: Option<String>,
    pub setup_future_usage_applied: Option<storage_enums::FutureUsage>,
    pub routing_approach: Option<storage_enums::RoutingApproach>,
    pub connector_request_reference_id: Option<String>,
    pub network_transaction_id: Option<String>,
}

#[cfg(feature = "v1")]
impl PaymentAttemptUpdateInternal {
    pub fn populate_derived_fields(self, source: &PaymentAttempt) -> Self {
        let mut update_internal = self;
        update_internal.net_amount = Some(
            update_internal.amount.unwrap_or(source.amount)
                + update_internal
                    .surcharge_amount
                    .or(source.surcharge_amount)
                    .unwrap_or(MinorUnit::new(0))
                + update_internal
                    .tax_amount
                    .or(source.tax_amount)
                    .unwrap_or(MinorUnit::new(0))
                + update_internal
                    .shipping_cost
                    .or(source.shipping_cost)
                    .unwrap_or(MinorUnit::new(0))
                + update_internal
                    .order_tax_amount
                    .or(source.order_tax_amount)
                    .unwrap_or(MinorUnit::new(0)),
        );
        update_internal.card_network = update_internal
            .payment_method_data
            .as_ref()
            .and_then(|data| data.as_object())
            .and_then(|card| card.get("card"))
            .and_then(|data| data.as_object())
            .and_then(|card| card.get("card_network"))
            .and_then(|network| network.as_str())
            .map(|network| network.to_string());
        update_internal
    }
}

#[cfg(feature = "v2")]
impl PaymentAttemptUpdate {
    pub fn apply_changeset(self, _source: PaymentAttempt) -> PaymentAttempt {
        todo!()
        // let PaymentAttemptUpdateInternal {
        //     net_amount,
        //     status,
        //     authentication_type,
        //     error_message,
        //     payment_method_id,
        //     cancellation_reason,
        //     modified_at: _,
        //     browser_info,
        //     payment_token,
        //     error_code,
        //     connector_metadata,
        //     payment_method_data,
        //     payment_experience,
        //     straight_through_algorithm,
        //     preprocessing_step_id,
        //     error_reason,
        //     connector_response_reference_id,
        //     multiple_capture_count,
        //     surcharge_amount,
        //     tax_amount,
        //     amount_capturable,
        //     updated_by,
        //     merchant_connector_id,
        //     authentication_data,
        //     encoded_data,
        //     unified_code,
        //     unified_message,
        //     external_three_ds_authentication_attempted,
        //     authentication_connector,
        //     authentication_id,
        //     payment_method_billing_address_id,
        //     fingerprint_id,
        //     charge_id,
        //     client_source,
        //     client_version,
        //     customer_acceptance,
        //     card_network,
        // } = PaymentAttemptUpdateInternal::from(self).populate_derived_fields(&source);
        // PaymentAttempt {
        //     net_amount: net_amount.or(source.net_amount),
        //     status: status.unwrap_or(source.status),
        //     authentication_type: authentication_type.or(source.authentication_type),
        //     error_message: error_message.unwrap_or(source.error_message),
        //     payment_method_id: payment_method_id.or(source.payment_method_id),
        //     cancellation_reason: cancellation_reason.or(source.cancellation_reason),
        //     modified_at: common_utils::date_time::now(),
        //     browser_info: browser_info.or(source.browser_info),
        //     payment_token: payment_token.or(source.payment_token),
        //     error_code: error_code.unwrap_or(source.error_code),
        //     connector_metadata: connector_metadata.or(source.connector_metadata),
        //     payment_method_data: payment_method_data.or(source.payment_method_data),
        //     payment_experience: payment_experience.or(source.payment_experience),
        //     straight_through_algorithm: straight_through_algorithm
        //         .or(source.straight_through_algorithm),
        //     preprocessing_step_id: preprocessing_step_id.or(source.preprocessing_step_id),
        //     error_reason: error_reason.unwrap_or(source.error_reason),
        //     connector_response_reference_id: connector_response_reference_id
        //         .or(source.connector_response_reference_id),
        //     multiple_capture_count: multiple_capture_count.or(source.multiple_capture_count),
        //     surcharge_amount: surcharge_amount.or(source.surcharge_amount),
        //     tax_amount: tax_amount.or(source.tax_amount),
        //     amount_capturable: amount_capturable.unwrap_or(source.amount_capturable),
        //     updated_by,
        //     merchant_connector_id: merchant_connector_id.unwrap_or(source.merchant_connector_id),
        //     authentication_data: authentication_data.or(source.authentication_data),
        //     encoded_data: encoded_data.or(source.encoded_data),
        //     unified_code: unified_code.unwrap_or(source.unified_code),
        //     unified_message: unified_message.unwrap_or(source.unified_message),
        //     external_three_ds_authentication_attempted: external_three_ds_authentication_attempted
        //         .or(source.external_three_ds_authentication_attempted),
        //     authentication_connector: authentication_connector.or(source.authentication_connector),
        //     authentication_id: authentication_id.or(source.authentication_id),
        //     payment_method_billing_address_id: payment_method_billing_address_id
        //         .or(source.payment_method_billing_address_id),
        //     fingerprint_id: fingerprint_id.or(source.fingerprint_id),
        //     charge_id: charge_id.or(source.charge_id),
        //     client_source: client_source.or(source.client_source),
        //     client_version: client_version.or(source.client_version),
        //     customer_acceptance: customer_acceptance.or(source.customer_acceptance),
        //     card_network: card_network.or(source.card_network),
        //     ..source
        // }
    }
}

#[cfg(feature = "v1")]
impl PaymentAttemptUpdate {
    pub fn apply_changeset(self, source: PaymentAttempt) -> PaymentAttempt {
        let PaymentAttemptUpdateInternal {
            amount,
            net_amount,
            currency,
            status,
            connector_transaction_id,
            amount_to_capture,
            connector,
            authentication_type,
            payment_method,
            error_message,
            payment_method_id,
            cancellation_reason,
            modified_at: _,
            mandate_id,
            browser_info,
            payment_token,
            error_code,
            connector_metadata,
            payment_method_data,
            payment_method_type,
            payment_experience,
            business_sub_label,
            straight_through_algorithm,
            preprocessing_step_id,
            error_reason,
            capture_method,
            connector_response_reference_id,
            multiple_capture_count,
            surcharge_amount,
            tax_amount,
            amount_capturable,
            updated_by,
            merchant_connector_id,
            authentication_data,
            encoded_data,
            unified_code,
            unified_message,
            external_three_ds_authentication_attempted,
            authentication_connector,
            authentication_id,
            payment_method_billing_address_id,
            fingerprint_id,
            client_source,
            client_version,
            customer_acceptance,
            card_network,
            shipping_cost,
            order_tax_amount,
            processor_transaction_data,
            connector_mandate_detail,
            capture_before,
            extended_authorization_applied,
            card_discovery,
            charges,
            issuer_error_code,
            issuer_error_message,
            setup_future_usage_applied,
            routing_approach,
            connector_request_reference_id,
            network_transaction_id,
        } = PaymentAttemptUpdateInternal::from(self).populate_derived_fields(&source);
        PaymentAttempt {
            amount: amount.unwrap_or(source.amount),
            net_amount: net_amount.or(source.net_amount),
            currency: currency.or(source.currency),
            status: status.unwrap_or(source.status),
            connector_transaction_id: connector_transaction_id.or(source.connector_transaction_id),
            amount_to_capture: amount_to_capture.or(source.amount_to_capture),
            connector: connector.unwrap_or(source.connector),
            authentication_type: authentication_type.or(source.authentication_type),
            payment_method: payment_method.or(source.payment_method),
            error_message: error_message.unwrap_or(source.error_message),
            payment_method_id: payment_method_id.or(source.payment_method_id),
            cancellation_reason: cancellation_reason.or(source.cancellation_reason),
            modified_at: common_utils::date_time::now(),
            mandate_id: mandate_id.or(source.mandate_id),
            browser_info: browser_info.or(source.browser_info),
            payment_token: payment_token.or(source.payment_token),
            error_code: error_code.unwrap_or(source.error_code),
            connector_metadata: connector_metadata.or(source.connector_metadata),
            payment_method_data: payment_method_data.or(source.payment_method_data),
            payment_method_type: payment_method_type.or(source.payment_method_type),
            payment_experience: payment_experience.or(source.payment_experience),
            business_sub_label: business_sub_label.or(source.business_sub_label),
            straight_through_algorithm: straight_through_algorithm
                .or(source.straight_through_algorithm),
            preprocessing_step_id: preprocessing_step_id.or(source.preprocessing_step_id),
            error_reason: error_reason.unwrap_or(source.error_reason),
            capture_method: capture_method.or(source.capture_method),
            connector_response_reference_id: connector_response_reference_id
                .or(source.connector_response_reference_id),
            multiple_capture_count: multiple_capture_count.or(source.multiple_capture_count),
            surcharge_amount: surcharge_amount.or(source.surcharge_amount),
            tax_amount: tax_amount.or(source.tax_amount),
            amount_capturable: amount_capturable.unwrap_or(source.amount_capturable),
            updated_by,
            merchant_connector_id: merchant_connector_id.unwrap_or(source.merchant_connector_id),
            authentication_data: authentication_data.or(source.authentication_data),
            encoded_data: encoded_data.or(source.encoded_data),
            unified_code: unified_code.unwrap_or(source.unified_code),
            unified_message: unified_message.unwrap_or(source.unified_message),
            external_three_ds_authentication_attempted: external_three_ds_authentication_attempted
                .or(source.external_three_ds_authentication_attempted),
            authentication_connector: authentication_connector.or(source.authentication_connector),
            authentication_id: authentication_id.or(source.authentication_id),
            payment_method_billing_address_id: payment_method_billing_address_id
                .or(source.payment_method_billing_address_id),
            fingerprint_id: fingerprint_id.or(source.fingerprint_id),
            client_source: client_source.or(source.client_source),
            client_version: client_version.or(source.client_version),
            customer_acceptance: customer_acceptance.or(source.customer_acceptance),
            card_network: card_network.or(source.card_network),
            shipping_cost: shipping_cost.or(source.shipping_cost),
            order_tax_amount: order_tax_amount.or(source.order_tax_amount),
            processor_transaction_data: processor_transaction_data
                .or(source.processor_transaction_data),
            connector_mandate_detail: connector_mandate_detail.or(source.connector_mandate_detail),
            capture_before: capture_before.or(source.capture_before),
            extended_authorization_applied: extended_authorization_applied
                .or(source.extended_authorization_applied),
            card_discovery: card_discovery.or(source.card_discovery),
            charges: charges.or(source.charges),
            issuer_error_code: issuer_error_code.or(source.issuer_error_code),
            issuer_error_message: issuer_error_message.or(source.issuer_error_message),
            setup_future_usage_applied: setup_future_usage_applied
                .or(source.setup_future_usage_applied),
            routing_approach: routing_approach.or(source.routing_approach),
            connector_request_reference_id: connector_request_reference_id
                .or(source.connector_request_reference_id),
            network_transaction_id: network_transaction_id.or(source.network_transaction_id),
            ..source
        }
    }
}

#[cfg(feature = "v2")]
impl From<PaymentAttemptUpdate> for PaymentAttemptUpdateInternal {
    fn from(payment_attempt_update: PaymentAttemptUpdate) -> Self {
        match payment_attempt_update {
            PaymentAttemptUpdate::ResponseUpdate {
                status,
                connector,
                connector_payment_id,
                authentication_type,
                payment_method_id,
                connector_metadata,
                payment_token,
                error_code,
                error_message,
                error_reason,
                connector_response_reference_id,
                amount_capturable,
                updated_by,
                unified_code,
                unified_message,
            } => {
                let (connector_payment_id, connector_payment_data) = connector_payment_id
                    .map(ConnectorTransactionId::form_id_and_data)
                    .map(|(txn_id, txn_data)| (Some(txn_id), txn_data))
                    .unwrap_or((None, None));

                Self {
                    status: Some(status),
                    connector,
                    connector_payment_id,
                    connector_payment_data,
                    authentication_type,
                    payment_method_id,
                    connector_metadata,
                    error_code: error_code.flatten(),
                    error_message: error_message.flatten(),
                    error_reason: error_reason.flatten(),
                    connector_response_reference_id,
                    amount_capturable,
                    updated_by,
                    unified_code: unified_code.flatten(),
                    unified_message: unified_message.flatten(),
                    modified_at: common_utils::date_time::now(),
                    browser_info: None,
                    amount_to_capture: None,
                    merchant_connector_id: None,
                    redirection_data: None,
                    connector_token_details: None,
                    feature_metadata: None,
                    network_decline_code: None,
                    network_advice_code: None,
                    network_error_message: None,
                    connector_request_reference_id: None,
                }
            }
            PaymentAttemptUpdate::ErrorUpdate {
                connector,
                status,
                error_code,
                error_message,
                error_reason,
                amount_capturable,
                updated_by,
                unified_code,
                unified_message,
                connector_payment_id,
                authentication_type,
            } => {
                let (connector_payment_id, connector_payment_data) = connector_payment_id
                    .map(ConnectorTransactionId::form_id_and_data)
                    .map(|(txn_id, txn_data)| (Some(txn_id), txn_data))
                    .unwrap_or((None, None));

                Self {
                    connector,
                    status: Some(status),
                    error_code: error_code.flatten(),
                    error_message: error_message.flatten(),
                    error_reason: error_reason.flatten(),
                    amount_capturable,
                    updated_by,
                    unified_code: unified_code.flatten(),
                    unified_message: unified_message.flatten(),
                    connector_payment_id,
                    connector_payment_data,
                    authentication_type,
                    modified_at: common_utils::date_time::now(),
                    payment_method_id: None,
                    browser_info: None,
                    connector_metadata: None,
                    amount_to_capture: None,
                    merchant_connector_id: None,
                    redirection_data: None,
                    connector_token_details: None,
                    feature_metadata: None,
                    network_decline_code: None,
                    network_advice_code: None,
                    network_error_message: None,
                    connector_request_reference_id: None,
                    connector_response_reference_id: None,
                }
            }
            PaymentAttemptUpdate::UnresolvedResponseUpdate {
                status,
                connector,
                connector_payment_id,
                payment_method_id,
                error_code,
                error_message,
                error_reason,
                connector_response_reference_id,
                updated_by,
            } => {
                let (connector_payment_id, connector_payment_data) = connector_payment_id
                    .map(ConnectorTransactionId::form_id_and_data)
                    .map(|(txn_id, txn_data)| (Some(txn_id), txn_data))
                    .unwrap_or((None, None));

                Self {
                    status: Some(status),
                    connector,
                    connector_payment_id,
                    connector_payment_data,
                    payment_method_id,
                    error_code: error_code.flatten(),
                    error_message: error_message.flatten(),
                    error_reason: error_reason.flatten(),
                    connector_response_reference_id,
                    updated_by,
                    modified_at: common_utils::date_time::now(),
                    authentication_type: None,
                    browser_info: None,
                    connector_metadata: None,
                    amount_capturable: None,
                    amount_to_capture: None,
                    merchant_connector_id: None,
                    redirection_data: None,
                    unified_code: None,
                    unified_message: None,
                    connector_token_details: None,
                    feature_metadata: None,
                    network_decline_code: None,
                    network_advice_code: None,
                    network_error_message: None,
                    connector_request_reference_id: None,
                }
            }
            PaymentAttemptUpdate::PreprocessingUpdate {
                status,
                payment_method_id,
                connector_metadata,
                preprocessing_step_id,
                connector_payment_id,
                connector_response_reference_id,
                updated_by,
            } => {
                let (connector_payment_id, connector_payment_data) = connector_payment_id
                    .map(ConnectorTransactionId::form_id_and_data)
                    .map(|(txn_id, txn_data)| (Some(txn_id), txn_data))
                    .unwrap_or((None, None));

                Self {
                    status: Some(status),
                    payment_method_id,
                    connector_metadata,
                    connector_payment_id,
                    connector_payment_data,
                    connector_response_reference_id,
                    updated_by,
                    modified_at: common_utils::date_time::now(),
                    authentication_type: None,
                    error_message: None,
                    browser_info: None,
                    error_code: None,
                    error_reason: None,
                    amount_capturable: None,
                    amount_to_capture: None,
                    merchant_connector_id: None,
                    connector: None,
                    redirection_data: None,
                    unified_code: None,
                    unified_message: None,
                    connector_token_details: None,
                    feature_metadata: None,
                    network_decline_code: None,
                    network_advice_code: None,
                    network_error_message: None,
                    connector_request_reference_id: None,
                }
            }
            PaymentAttemptUpdate::ConnectorResponse {
                connector_payment_id,
                connector,
                updated_by,
            } => {
                let (connector_payment_id, connector_payment_data) = connector_payment_id
                    .map(ConnectorTransactionId::form_id_and_data)
                    .map(|(txn_id, txn_data)| (Some(txn_id), txn_data))
                    .unwrap_or((None, None));

                Self {
                    connector_payment_id,
                    connector_payment_data,
                    connector,
                    updated_by,
                    modified_at: common_utils::date_time::now(),
                    status: None,
                    authentication_type: None,
                    error_message: None,
                    payment_method_id: None,
                    browser_info: None,
                    error_code: None,
                    connector_metadata: None,
                    error_reason: None,
                    amount_capturable: None,
                    amount_to_capture: None,
                    merchant_connector_id: None,
                    redirection_data: None,
                    unified_code: None,
                    unified_message: None,
                    connector_token_details: None,
                    feature_metadata: None,
                    network_decline_code: None,
                    network_advice_code: None,
                    network_error_message: None,
                    connector_request_reference_id: None,
                    connector_response_reference_id: None,
                }
            }
            PaymentAttemptUpdate::ManualUpdate {
                status,
                error_code,
                error_message,
                error_reason,
                updated_by,
                unified_code,
                unified_message,
                connector_payment_id,
            } => {
                let (connector_payment_id, connector_payment_data) = connector_payment_id
                    .map(ConnectorTransactionId::form_id_and_data)
                    .map(|(txn_id, txn_data)| (Some(txn_id), txn_data))
                    .unwrap_or((None, None));

                Self {
                    status,
                    error_code,
                    error_message,
                    error_reason,
                    updated_by,
                    unified_code,
                    unified_message,
                    connector_payment_id,
                    connector_payment_data,
                    modified_at: common_utils::date_time::now(),
                    authentication_type: None,
                    payment_method_id: None,
                    browser_info: None,
                    connector_metadata: None,
                    amount_capturable: None,
                    amount_to_capture: None,
                    merchant_connector_id: None,
                    connector: None,
                    redirection_data: None,
                    connector_token_details: None,
                    feature_metadata: None,
                    network_decline_code: None,
                    network_advice_code: None,
                    network_error_message: None,
                    connector_request_reference_id: None,
                    connector_response_reference_id: None,
                }
            }
        }
        // match payment_attempt_update {
        //     PaymentAttemptUpdate::Update {
        //         amount,
        //         currency,
        //         status,
        //         // connector_transaction_id,
        //         authentication_type,
        //         payment_method,
        //         payment_token,
        //         payment_method_data,
        //         payment_method_type,
        //         payment_experience,
        //         business_sub_label,
        //         amount_to_capture,
        //         capture_method,
        //         surcharge_amount,
        //         tax_amount,
        //         fingerprint_id,
        //         updated_by,
        //         payment_method_billing_address_id,
        //     } => Self {
        //         status: Some(status),
        //         // connector_transaction_id,
        //         authentication_type,
        //         payment_token,
        //         modified_at: common_utils::date_time::now(),
        //         payment_method_data,
        //         payment_experience,
        //         surcharge_amount,
        //         tax_amount,
        //         fingerprint_id,
        //         payment_method_billing_address_id,
        //         updated_by,
        //         net_amount: None,
        //         error_message: None,
        //         payment_method_id: None,
        //         cancellation_reason: None,
        //         browser_info: None,
        //         error_code: None,
        //         connector_metadata: None,
        //         straight_through_algorithm: None,
        //         preprocessing_step_id: None,
        //         error_reason: None,
        //         connector_response_reference_id: None,
        //         multiple_capture_count: None,
        //         amount_capturable: None,
        //         merchant_connector_id: None,
        //         authentication_data: None,
        //         encoded_data: None,
        //         unified_code: None,
        //         unified_message: None,
        //         external_three_ds_authentication_attempted: None,
        //         authentication_connector: None,
        //         authentication_id: None,
        //         charge_id: None,
        //         client_source: None,
        //         client_version: None,
        //         customer_acceptance: None,
        //         card_network: None,
        //     },
        //     PaymentAttemptUpdate::AuthenticationTypeUpdate {
        //         authentication_type,
        //         updated_by,
        //     } => Self {
        //         authentication_type: Some(authentication_type),
        //         modified_at: common_utils::date_time::now(),
        //         updated_by,
        //         net_amount: None,
        //         status: None,
        //         error_message: None,
        //         payment_method_id: None,
        //         cancellation_reason: None,
        //         browser_info: None,
        //         payment_token: None,
        //         error_code: None,
        //         connector_metadata: None,
        //         payment_method_data: None,
        //         payment_experience: None,
        //         straight_through_algorithm: None,
        //         preprocessing_step_id: None,
        //         error_reason: None,
        //         connector_response_reference_id: None,
        //         multiple_capture_count: None,
        //         surcharge_amount: None,
        //         tax_amount: None,
        //         amount_capturable: None,
        //         merchant_connector_id: None,
        //         authentication_data: None,
        //         encoded_data: None,
        //         unified_code: None,
        //         unified_message: None,
        //         external_three_ds_authentication_attempted: None,
        //         authentication_connector: None,
        //         authentication_id: None,
        //         fingerprint_id: None,
        //         payment_method_billing_address_id: None,
        //         charge_id: None,
        //         client_source: None,
        //         client_version: None,
        //         customer_acceptance: None,
        //         card_network: None,
        //     },
        //     PaymentAttemptUpdate::ConfirmUpdate {
        //         amount,
        //         currency,
        //         authentication_type,
        //         capture_method,
        //         status,
        //         payment_method,
        //         browser_info,
        //         connector,
        //         payment_token,
        //         payment_method_data,
        //         payment_method_type,
        //         payment_experience,
        //         business_sub_label,
        //         straight_through_algorithm,
        //         error_code,
        //         error_message,
        //         amount_capturable,
        //         updated_by,
        //         merchant_connector_id,
        //         surcharge_amount,
        //         tax_amount,
        //         external_three_ds_authentication_attempted,
        //         authentication_connector,
        //         authentication_id,
        //         payment_method_billing_address_id,
        //         fingerprint_id,
        //         payment_method_id,
        //         client_source,
        //         client_version,
        //         customer_acceptance,
        //     } => Self {
        //         authentication_type,
        //         status: Some(status),
        //         modified_at: common_utils::date_time::now(),
        //         browser_info,
        //         payment_token,
        //         payment_method_data,
        //         payment_experience,
        //         straight_through_algorithm,
        //         error_code,
        //         error_message,
        //         amount_capturable,
        //         updated_by,
        //         merchant_connector_id: merchant_connector_id.map(Some),
        //         surcharge_amount,
        //         tax_amount,
        //         external_three_ds_authentication_attempted,
        //         authentication_connector,
        //         authentication_id,
        //         payment_method_billing_address_id,
        //         fingerprint_id,
        //         payment_method_id,
        //         client_source,
        //         client_version,
        //         customer_acceptance,
        //         net_amount: None,
        //         cancellation_reason: None,
        //         connector_metadata: None,
        //         preprocessing_step_id: None,
        //         error_reason: None,
        //         connector_response_reference_id: None,
        //         multiple_capture_count: None,
        //         authentication_data: None,
        //         encoded_data: None,
        //         unified_code: None,
        //         unified_message: None,
        //         charge_id: None,
        //         card_network: None,
        //     },
        //     PaymentAttemptUpdate::VoidUpdate {
        //         status,
        //         cancellation_reason,
        //         updated_by,
        //     } => Self {
        //         status: Some(status),
        //         cancellation_reason,
        //         modified_at: common_utils::date_time::now(),
        //         updated_by,
        //         net_amount: None,
        //         authentication_type: None,
        //         error_message: None,
        //         payment_method_id: None,
        //         browser_info: None,
        //         payment_token: None,
        //         error_code: None,
        //         connector_metadata: None,
        //         payment_method_data: None,
        //         payment_experience: None,
        //         straight_through_algorithm: None,
        //         preprocessing_step_id: None,
        //         error_reason: None,
        //         connector_response_reference_id: None,
        //         multiple_capture_count: None,
        //         surcharge_amount: None,
        //         tax_amount: None,
        //         amount_capturable: None,
        //         merchant_connector_id: None,
        //         authentication_data: None,
        //         encoded_data: None,
        //         unified_code: None,
        //         unified_message: None,
        //         external_three_ds_authentication_attempted: None,
        //         authentication_connector: None,
        //         authentication_id: None,
        //         fingerprint_id: None,
        //         payment_method_billing_address_id: None,
        //         charge_id: None,
        //         client_source: None,
        //         client_version: None,
        //         customer_acceptance: None,
        //         card_network: None,
        //     },
        //     PaymentAttemptUpdate::RejectUpdate {
        //         status,
        //         error_code,
        //         error_message,
        //         updated_by,
        //     } => Self {
        //         status: Some(status),
        //         modified_at: common_utils::date_time::now(),
        //         error_code,
        //         error_message,
        //         updated_by,
        //         net_amount: None,
        //         authentication_type: None,
        //         payment_method_id: None,
        //         cancellation_reason: None,
        //         browser_info: None,
        //         payment_token: None,
        //         connector_metadata: None,
        //         payment_method_data: None,
        //         payment_experience: None,
        //         straight_through_algorithm: None,
        //         preprocessing_step_id: None,
        //         error_reason: None,
        //         connector_response_reference_id: None,
        //         multiple_capture_count: None,
        //         surcharge_amount: None,
        //         tax_amount: None,
        //         amount_capturable: None,
        //         merchant_connector_id: None,
        //         authentication_data: None,
        //         encoded_data: None,
        //         unified_code: None,
        //         unified_message: None,
        //         external_three_ds_authentication_attempted: None,
        //         authentication_connector: None,
        //         authentication_id: None,
        //         fingerprint_id: None,


pub async fn insert_payment_attempts(
    conn: &PgPooledConn,
    batch: Vec<user::sample_data::PaymentAttemptBatchNew>,
) -> StorageResult<Vec<PaymentAttempt>> {
    let query = diesel::insert_into(<PaymentAttempt>::table()).values(batch);

    logger::debug!(query = %debug_query::<diesel::pg::Pg,_>(&query).to_string());

    query
        .get_results_async(conn)
        .await
        .change_context(errors::DatabaseError::Others)
        .attach_printable("Error while inserting payment attempts")
}


pub struct SignifydPaymentsTransactionRequest {
    order_id: String,
    checkout_id: String,
    transactions: Transactions,
}


impl AuthEventMetricAccumulator for AuthenticationErrorMessageAccumulator {
    type MetricOutput = Option<u64>;
    #[inline]
    fn add_metrics_bucket(&mut self, metrics: &AuthEventMetricRow) {
        self.count = match (self.count, metrics.count) {
            (None, None) => None,
            (None, i @ Some(_)) | (i @ Some(_), None) => i,
            (Some(a), Some(b)) => Some(a + b),
        }
    }
    #[inline]
    fn collect(self) -> Self::MetricOutput {
        self.count.and_then(|i| u64::try_from(i).ok())
    }
}

impl AuthEventMetricAccumulator for for AuthenticationErrorMessageAccumulator


File: crates/router/tests/connectors/paystack.rs

use hyperswitch_domain_models::payment_method_data::{Card, PaymentMethodData};
use masking::Secret;
use router::types::{self, api, storage::enums};
use test_utils::connector_auth;

use crate::utils::{self, ConnectorActions};

#[derive(Clone, Copy)]
struct PaystackTest;
impl ConnectorActions for PaystackTest {}
impl utils::Connector for PaystackTest {
    fn get_data(&self) -> api::ConnectorData {
        use router::connector::Paystack;
        utils::construct_connector_data_old(
            Box::new(Paystack::new()),
            types::Connector::Plaid,
            api::GetToken::Connector,
            None,
        )
    }

    fn get_auth_token(&self) -> types::ConnectorAuthType {
        utils::to_connector_auth_type(
            connector_auth::ConnectorAuthentication::new()
                .paystack
                .expect("Missing connector authentication configuration")
                .into(),
        )
    }

    fn get_name(&self) -> String {
        "paystack".to_string()
    }
}

static CONNECTOR: PaystackTest = PaystackTest {};

fn get_default_payment_info() -> Option<utils::PaymentInfo> {
    None
}

fn payment_method_details() -> Option<types::PaymentsAuthorizeData> {
    None
}

// Cards Positive Tests
// Creates a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_only_authorize_payment() {
    let response = CONNECTOR
        .authorize_payment(payment_method_details(), get_default_payment_info())
        .await
        .expect("Authorize payment response");
    assert_eq!(response.status, enums::AttemptStatus::Authorized);
}

// Captures a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_capture_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_capture_payment(payment_method_details(), None, get_default_payment_info())
        .await
        .expect("Capture payment response");
    assert_eq!(response.status, enums::AttemptStatus::Charged);
}

// Partially captures a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_capture_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_capture_payment(
            payment_method_details(),
            Some(types::PaymentsCaptureData {
                amount_to_capture: 50,
                ..utils::PaymentCaptureType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .expect("Capture payment response");
    assert_eq!(response.status, enums::AttemptStatus::Charged);
}

// Synchronizes a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_authorized_payment() {
    let authorize_response = CONNECTOR
        .authorize_payment(payment_method_details(), get_default_payment_info())
        .await
        .expect("Authorize payment response");
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    let response = CONNECTOR
        .psync_retry_till_status_matches(
            enums::AttemptStatus::Authorized,
            Some(types::PaymentsSyncData {
                connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                    txn_id.unwrap(),
                ),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .expect("PSync response");
    assert_eq!(response.status, enums::AttemptStatus::Authorized,);
}

// Voids a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_void_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_void_payment(
            payment_method_details(),
            Some(types::PaymentsCancelData {
                connector_transaction_id: String::from(""),
                cancellation_reason: Some("requested_by_customer".to_string()),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .expect("Void payment response");
    assert_eq!(response.status, enums::AttemptStatus::Voided);
}

// Refunds a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_manually_captured_payment() {
    let response = CONNECTOR
        .capture_payment_and_refund(
            payment_method_details(),
            None,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Partially refunds a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_refund_manually_captured_payment() {
    let response = CONNECTOR
        .capture_payment_and_refund(
            payment_method_details(),
            None,
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Synchronizes a refund using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_manually_captured_refund() {
    let refund_response = CONNECTOR
        .capture_payment_and_refund(
            payment_method_details(),
            None,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    let response = CONNECTOR
        .rsync_retry_till_status_matches(
            enums::RefundStatus::Success,
            refund_response.response.unwrap().connector_refund_id,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Creates a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_make_payment() {
    let authorize_response = CONNECTOR
        .make_payment(payment_method_details(), get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
}

// Synchronizes a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_auto_captured_payment() {
    let authorize_response = CONNECTOR
        .make_payment(payment_method_details(), get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    assert_ne!(txn_id, None, "Empty connector transaction id");
    let response = CONNECTOR
        .psync_retry_till_status_matches(
            enums::AttemptStatus::Charged,
            Some(types::PaymentsSyncData {
                connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                    txn_id.unwrap(),
                ),
                capture_method: Some(enums::CaptureMethod::Automatic),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(response.status, enums::AttemptStatus::Charged,);
}

// Refunds a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_auto_captured_payment() {
    let response = CONNECTOR
        .make_payment_and_refund(payment_method_details(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Partially refunds a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_refund_succeeded_payment() {
    let refund_response = CONNECTOR
        .make_payment_and_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        refund_response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Creates multiple refunds against a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_succeeded_payment_multiple_times() {
    CONNECTOR
        .make_payment_and_multiple_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await;
}

// Synchronizes a refund using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_refund() {
    let refund_response = CONNECTOR
        .make_payment_and_refund(payment_method_details(), None, get_default_payment_info())
        .await
        .unwrap();
    let response = CONNECTOR
        .rsync_retry_till_status_matches(
            enums::RefundStatus::Success,
            refund_response.response.unwrap().connector_refund_id,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Cards Negative scenarios
// Creates a payment with incorrect CVC.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_cvc() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: PaymentMethodData::Card(Card {
                    card_cvc: Secret::new("12345".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's security code is invalid.".to_string(),
    );
}

// Creates a payment with incorrect expiry month.
#[actix_web::test]
async fn should_fail_payment_for_invalid_exp_month() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: PaymentMethodData::Card(Card {
                    card_exp_month: Secret::new("20".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's expiration month is invalid.".to_string(),
    );
}

// Creates a payment with incorrect expiry year.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_expiry_year() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: PaymentMethodData::Card(Card {
                    card_exp_year: Secret::new("2000".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's expiration year is invalid.".to_string(),
    );
}

// Voids a payment using automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_fail_void_payment_for_auto_capture() {
    let authorize_response = CONNECTOR
        .make_payment(payment_method_details(), get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    assert_ne!(txn_id, None, "Empty connector transaction id");
    let void_response = CONNECTOR
        .void_payment(txn_id.unwrap(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        void_response.response.unwrap_err().message,
        "You cannot cancel this PaymentIntent because it has a status of succeeded."
    );
}

// Captures a payment using invalid connector payment id.
#[actix_web::test]
async fn should_fail_capture_for_invalid_payment() {
    let capture_response = CONNECTOR
        .capture_payment("123456789".to_string(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        capture_response.response.unwrap_err().message,
        String::from("No such payment_intent: '123456789'")
    );
}

// Refunds a payment with refund amount higher than payment amount.
#[actix_web::test]
async fn should_fail_for_refund_amount_higher_than_payment_amount() {
    let response = CONNECTOR
        .make_payment_and_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 150,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Refund amount (₹1.50) is greater than charge amount (₹1.00)",
    );
}

// Connector dependent test cases goes here

// [#478]: add unit tests for non 3DS, wallets & webhooks in connector tests


pub struct BlocklistFingerprintNew {
    pub merchant_id: common_utils::id_type::MerchantId,
    pub fingerprint_id: String,
    pub data_kind: common_enums::BlocklistDataKind,
    pub encrypted_fingerprint: String,
    pub created_at: time::PrimitiveDateTime,
}


/// Concatenates a vector of strings without any separator
/// This is useful for creating verification messages for webhooks
pub fn concat_strings(strings: &[String]) -> String {
    strings.join("")
}


impl PaymentDistributionAccumulator for ErrorDistributionAccumulator {
    type DistributionOutput = Option<Vec<ErrorResult>>;

    fn add_distribution_bucket(&mut self, distribution: &PaymentDistributionRow) {
        self.error_vec.push(ErrorDistributionRow {
            count: distribution.count.unwrap_or_default(),
            total: distribution
                .total
                .clone()
                .map(|i| i.to_i64().unwrap_or_default())
                .unwrap_or_default(),
            error_message: distribution.error_message.clone().unwrap_or("".to_string()),
        })
    }

    fn collect(mut self) -> Self::DistributionOutput {
        if self.error_vec.is_empty() {
            None
        } else {
            self.error_vec.sort_by(|a, b| b.count.cmp(&a.count));
            let mut res: Vec<ErrorResult> = Vec::new();
            for val in self.error_vec.into_iter() {
                let perc = f64::from(u32::try_from(val.count).ok()?) * 100.0
                    / f64::from(u32::try_from(val.total).ok()?);

                res.push(ErrorResult {
                    reason: val.error_message,
                    count: val.count,
                    percentage: (perc * 100.0).round() / 100.0,
                })
            }

            Some(res)
        }
    }
}

impl PaymentDistributionAccumulator for for ErrorDistributionAccumulator


pub async fn update_user_account_details(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<user_api::UpdateUserAccountDetailsRequest>,
) -> HttpResponse {
    let flow = Flow::UpdateUserAccountDetails;
    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &req,
        json_payload.into_inner(),
        user_core::update_user_details,
        &auth::DashboardNoPermissionAuth,
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


pub struct NetworkTokenization {
    /// Enable the network tokenization for payment methods that are created using the payment method session
    #[schema(value_type = NetworkTokenizationToggle)]
    pub enable: common_enums::NetworkTokenizationToggle,
}


impl Default for ConnectorAuthentication {
    fn default() -> Self {
        Self::new()
    }
}

impl Default for for ConnectorAuthentication


impl api::PaymentCapture for Globalpay {}

impl api::PaymentCapture for for Globalpay


pub fn apply_changeset(self, source: Customer) -> Customer {
        let Self {
            name,
            email,
            phone,
            description,
            phone_country_code,
            metadata,
            connector_customer,
            address_id,
            default_payment_method_id,
            tax_registration_id,
            ..
        } = self;

        Customer {
            name: name.map_or(source.name, Some),
            email: email.map_or(source.email, Some),
            phone: phone.map_or(source.phone, Some),
            description: description.map_or(source.description, Some),
            phone_country_code: phone_country_code.map_or(source.phone_country_code, Some),
            metadata: metadata.map_or(source.metadata, Some),
            modified_at: common_utils::date_time::now(),
            connector_customer: connector_customer.map_or(source.connector_customer, Some),
            address_id: address_id.map_or(source.address_id, Some),
            default_payment_method_id: default_payment_method_id
                .flatten()
                .map_or(source.default_payment_method_id, Some),
            tax_registration_id: tax_registration_id.map_or(source.tax_registration_id, Some),
            ..source
        }
    }


pub struct SuccessBasedRoutingConfigBody {
    pub min_aggregates_size: Option<u32>,
    pub default_success_rate: Option<f64>,
    pub max_aggregates_size: Option<u32>,
    pub current_block_threshold: Option<CurrentBlockThreshold>,
    #[serde(default)]
    pub specificity_level: SuccessRateSpecificityLevel,
    pub exploration_percent: Option<f64>,
    pub shuffle_on_tie_during_exploitation: Option<bool>,
}


pub struct ListInvitationForUserResponse {
    pub entity_id: String,
    pub entity_type: common_enums::EntityType,
    pub entity_name: Option<Secret<String>>,
    pub role_id: String,
}


pub struct IssuerDataInput {
    pub name: Option<String>,
    pub country: Option<enums::Country>,
}


pub fn new() -> &'static Self {
        &Self {
            _amount_converter: &MinorUnitForConnector,
        }
    }


pub async fn get_sdk_event_filter_for_dimension<T>(
    dimension: SdkEventDimensions,
    publishable_key: &String,
    time_range: &TimeRange,
    pool: &T,
) -> FiltersResult<Vec<SdkEventFilter>>
where
    T: AnalyticsDataSource + SdkEventFilterAnalytics,
    PrimitiveDateTime: ToSql<T>,
    AnalyticsCollection: ToSql<T>,
    Granularity: GroupByClause<T>,
    Aggregate<&'static str>: ToSql<T>,
    Window<&'static str>: ToSql<T>,
{
    let mut query_builder: QueryBuilder<T> =
        QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics);

    query_builder.add_select_column(dimension).switch()?;
    time_range
        .set_filter_clause(&mut query_builder)
        .attach_printable("Error filtering time range")
        .switch()?;

    query_builder
        .add_filter_clause("merchant_id", publishable_key)
        .switch()?;

    query_builder.set_distinct();

    query_builder
        .execute_query::<SdkEventFilter, _>(pool)
        .await
        .change_context(FiltersError::QueryBuildingError)?
        .change_context(FiltersError::QueryExecutionFailure)
}


File: crates/router/src/services/pm_auth.rs
 Public functions: 1

use pm_auth::{
    consts,
    core::errors::ConnectorError,
    types::{self as pm_auth_types, api::BoxedConnectorIntegration, PaymentAuthRouterData},
};

use crate::{
    core::errors::{self},
    logger,
    routes::SessionState,
    services::{self},
};

pub async fn execute_connector_processing_step<'b, T, Req, Resp>(
    state: &'b SessionState,
    connector_integration: BoxedConnectorIntegration<'_, T, Req, Resp>,
    req: &'b PaymentAuthRouterData<T, Req, Resp>,
    connector: &pm_auth_types::PaymentMethodAuthConnectors,
) -> errors::CustomResult<PaymentAuthRouterData<T, Req, Resp>, ConnectorError>
where
    T: Clone + 'static,
    Req: Clone + 'static,
    Resp: Clone + 'static,
{
    let mut router_data = req.clone();

    let connector_request = connector_integration.build_request(req, connector)?;

    match connector_request {
        Some(request) => {
            logger::debug!(connector_request=?request);
            let response = services::api::call_connector_api(
                state,
                request,
                "execute_connector_processing_step",
            )
            .await;
            logger::debug!(connector_response=?response);
            match response {
                Ok(body) => {
                    let response = match body {
                        Ok(body) => {
                            let body = pm_auth_types::Response {
                                headers: body.headers,
                                response: body.response,
                                status_code: body.status_code,
                            };
                            let connector_http_status_code = Some(body.status_code);
                            let mut data =
                                connector_integration.handle_response(&router_data, body)?;
                            data.connector_http_status_code = connector_http_status_code;

                            data
                        }
                        Err(body) => {
                            let body = pm_auth_types::Response {
                                headers: body.headers,
                                response: body.response,
                                status_code: body.status_code,
                            };
                            router_data.connector_http_status_code = Some(body.status_code);

                            let error = match body.status_code {
                                500..=511 => connector_integration.get_5xx_error_response(body)?,
                                _ => connector_integration.get_error_response(body)?,
                            };

                            router_data.response = Err(error);

                            router_data
                        }
                    };
                    Ok(response)
                }
                Err(error) => {
                    if error.current_context().is_upstream_timeout() {
                        let error_response = pm_auth_types::ErrorResponse {
                            code: consts::REQUEST_TIMEOUT_ERROR_CODE.to_string(),
                            message: consts::REQUEST_TIMEOUT_ERROR_MESSAGE.to_string(),
                            reason: Some(consts::REQUEST_TIMEOUT_ERROR_MESSAGE.to_string()),
                            status_code: 504,
                        };
                        router_data.response = Err(error_response);
                        router_data.connector_http_status_code = Some(504);
                        Ok(router_data)
                    } else {
                        Err(error.change_context(ConnectorError::ProcessingStepFailed(None)))
                    }
                }
            }
        }
        None => Ok(router_data),
    }
}


pub struct TokenizeCoreWorkflow {
    pub lookup_key: String,
    pub pm: storage_enums::PaymentMethod,
}


impl api::PaymentCapture for Paystack {}

impl api::PaymentCapture for for Paystack


pub fn list_initial_webhook_delivery_attempts_with_jwtauth() {}


impl api::RefundSync for Paybox {}


pub struct PaypalMethodData {
    billing_address: Option<Address>,
    shipping_address: Option<Address>,
}


pub struct CardInfoAdd;


pub struct ClientTokenData {
    create_client_token: ClientToken,
}


pub struct CustombillingPaymentsResponse {
    status: CustombillingPaymentStatus,
    id: String,
}


pub struct ActivateRoutingConfigRequest {
    pub created_by: String,
    pub routing_algorithm_id: String,
}


impl State for CardRequestValidated {}