// File: crates/diesel_models/src/payout_attempt.rs

use common_utils::{
    payout_method_utils, pii,
    types::{UnifiedCode, UnifiedMessage},
};
use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
use serde::{self, Deserialize, Serialize};
use time::PrimitiveDateTime;

use crate::{enums as storage_enums, schema::payout_attempt};

#[derive(
    Clone, Debug, Eq, PartialEq, Identifiable, Queryable, Selectable, Serialize, Deserialize,
)]
#[diesel(table_name = payout_attempt, primary_key(payout_attempt_id), check_for_backend(diesel::pg::Pg))]
pub struct PayoutAttempt {
    pub payout_attempt_id: String,
    pub payout_id: common_utils::id_type::PayoutId,
    pub customer_id: Option<common_utils::id_type::CustomerId>,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub address_id: Option<String>,
    pub connector: Option<String>,
    pub connector_payout_id: Option<String>,
    pub payout_token: Option<String>,
    pub status: storage_enums::PayoutStatus,
    pub is_eligible: Option<bool>,
    pub error_message: Option<String>,
    pub error_code: Option<String>,
    pub business_country: Option<storage_enums::CountryAlpha2>,
    pub business_label: Option<String>,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub created_at: PrimitiveDateTime,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub last_modified_at: PrimitiveDateTime,
    pub profile_id: common_utils::id_type::ProfileId,
    pub merchant_connector_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
    pub routing_info: Option<serde_json::Value>,
    pub unified_code: Option<UnifiedCode>,
    pub unified_message: Option<UnifiedMessage>,
    pub additional_payout_method_data: Option<payout_method_utils::AdditionalPayoutMethodData>,
    pub merchant_order_reference_id: Option<String>,
    pub payout_connector_metadata: Option<pii::SecretSerdeValue>,
}

#[derive(
    Clone,
    Debug,
    Eq,
    PartialEq,
    Insertable,
    serde::Serialize,
    serde::Deserialize,
    router_derive::DebugAsDisplay,
    router_derive::Setter,
)]
#[diesel(table_name = payout_attempt)]
pub struct PayoutAttemptNew {
    pub payout_attempt_id: String,
    pub payout_id: common_utils::id_type::PayoutId,
    pub customer_id: Option<common_utils::id_type::CustomerId>,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub address_id: Option<String>,
    pub connector: Option<String>,
    pub connector_payout_id: Option<String>,
    pub payout_token: Option<String>,
    pub status: storage_enums::PayoutStatus,
    pub is_eligible: Option<bool>,
    pub error_message: Option<String>,
    pub error_code: Option<String>,
    pub business_country: Option<storage_enums::CountryAlpha2>,
    pub business_label: Option<String>,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub created_at: PrimitiveDateTime,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub last_modified_at: PrimitiveDateTime,
    pub profile_id: common_utils::id_type::ProfileId,
    pub merchant_connector_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
    pub routing_info: Option<serde_json::Value>,
    pub unified_code: Option<UnifiedCode>,
    pub unified_message: Option<UnifiedMessage>,
    pub additional_payout_method_data: Option<payout_method_utils::AdditionalPayoutMethodData>,
    pub merchant_order_reference_id: Option<String>,
    pub payout_connector_metadata: Option<pii::SecretSerdeValue>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum PayoutAttemptUpdate {
    StatusUpdate {
        connector_payout_id: Option<String>,
        status: storage_enums::PayoutStatus,
        error_message: Option<String>,
        error_code: Option<String>,
        is_eligible: Option<bool>,
        unified_code: Option<UnifiedCode>,
        unified_message: Option<UnifiedMessage>,
        payout_connector_metadata: Option<pii::SecretSerdeValue>,
    },
    PayoutTokenUpdate {
        payout_token: String,
    },
    BusinessUpdate {
        business_country: Option<storage_enums::CountryAlpha2>,
        business_label: Option<String>,
        address_id: Option<String>,
        customer_id: Option<common_utils::id_type::CustomerId>,
    },
    UpdateRouting {
        connector: String,
        routing_info: Option<serde_json::Value>,
        merchant_connector_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
    },
    AdditionalPayoutMethodDataUpdate {
        additional_payout_method_data: Option<payout_method_utils::AdditionalPayoutMethodData>,
    },
}

#[derive(Clone, Debug, AsChangeset, router_derive::DebugAsDisplay)]
#[diesel(table_name = payout_attempt)]
pub struct PayoutAttemptUpdateInternal {
    pub payout_token: Option<String>,
    pub connector_payout_id: Option<String>,
    pub status: Option<storage_enums::PayoutStatus>,
    pub error_message: Option<String>,
    pub error_code: Option<String>,
    pub is_eligible: Option<bool>,
    pub business_country: Option<storage_enums::CountryAlpha2>,
    pub business_label: Option<String>,
    pub connector: Option<String>,
    pub routing_info: Option<serde_json::Value>,
    pub last_modified_at: PrimitiveDateTime,
    pub address_id: Option<String>,
    pub customer_id: Option<common_utils::id_type::CustomerId>,
    pub merchant_connector_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
    pub unified_code: Option<UnifiedCode>,
    pub unified_message: Option<UnifiedMessage>,
    pub additional_payout_method_data: Option<payout_method_utils::AdditionalPayoutMethodData>,
    pub merchant_order_reference_id: Option<String>,
    pub payout_connector_metadata: Option<pii::SecretSerdeValue>,
}

impl Default for PayoutAttemptUpdateInternal {
    fn default() -> Self {
        Self {
            payout_token: None,
            connector_payout_id: None,
            status: None,
            error_message: None,
            error_code: None,
            is_eligible: None,
            business_country: None,
            business_label: None,
            connector: None,
            routing_info: None,
            merchant_connector_id: None,
            last_modified_at: common_utils::date_time::now(),
            address_id: None,
            customer_id: None,
            unified_code: None,
            unified_message: None,
            additional_payout_method_data: None,
            merchant_order_reference_id: None,
            payout_connector_metadata: None,
        }
    }
}

impl From<PayoutAttemptUpdate> for PayoutAttemptUpdateInternal {
    fn from(payout_update: PayoutAttemptUpdate) -> Self {
        match payout_update {
            PayoutAttemptUpdate::PayoutTokenUpdate { payout_token } => Self {
                payout_token: Some(payout_token),
                ..Default::default()
            },
            PayoutAttemptUpdate::StatusUpdate {
                connector_payout_id,
                status,
                error_message,
                error_code,
                is_eligible,
                unified_code,
                unified_message,
                payout_connector_metadata,
            } => Self {
                connector_payout_id,
                status: Some(status),
                error_message,
                error_code,
                is_eligible,
                unified_code,
                unified_message,
                payout_connector_metadata,
                ..Default::default()
            },
            PayoutAttemptUpdate::BusinessUpdate {
                business_country,
                business_label,
                address_id,
                customer_id,
            } => Self {
                business_country,
                business_label,
                address_id,
                customer_id,
                ..Default::default()
            },
            PayoutAttemptUpdate::UpdateRouting {
                connector,
                routing_info,
                merchant_connector_id,
            } => Self {
                connector: Some(connector),
                routing_info,
                merchant_connector_id,
                ..Default::default()
            },
            PayoutAttemptUpdate::AdditionalPayoutMethodDataUpdate {
                additional_payout_method_data,
            } => Self {
                additional_payout_method_data,
                ..Default::default()
            },
        }
    }
}

impl PayoutAttemptUpdate {
    pub fn apply_changeset(self, source: PayoutAttempt) -> PayoutAttempt {
        let PayoutAttemptUpdateInternal {
            payout_token,
            connector_payout_id,
            status,
            error_message,
            error_code,
            is_eligible,
            business_country,
            business_label,
            connector,
            routing_info,
            last_modified_at,
            address_id,
            customer_id,
            merchant_connector_id,
            unified_code,
            unified_message,
            additional_payout_method_data,
            merchant_order_reference_id,
            payout_connector_metadata,
        } = self.into();
        PayoutAttempt {
            payout_token: payout_token.or(source.payout_token),
            connector_payout_id: connector_payout_id.or(source.connector_payout_id),
            status: status.unwrap_or(source.status),
            error_message: error_message.or(source.error_message),
            error_code: error_code.or(source.error_code),
            is_eligible: is_eligible.or(source.is_eligible),
            business_country: business_country.or(source.business_country),
            business_label: business_label.or(source.business_label),
            connector: connector.or(source.connector),
            routing_info: routing_info.or(source.routing_info),
            last_modified_at,
            address_id: address_id.or(source.address_id),
            customer_id: customer_id.or(source.customer_id),
            merchant_connector_id: merchant_connector_id.or(source.merchant_connector_id),
            unified_code: unified_code.or(source.unified_code),
            unified_message: unified_message.or(source.unified_message),
            additional_payout_method_data: additional_payout_method_data
                .or(source.additional_payout_method_data),
            merchant_order_reference_id: merchant_order_reference_id
                .or(source.merchant_order_reference_id),
            payout_connector_metadata: payout_connector_metadata
                .or(source.payout_connector_metadata),
            ..source
        }
    }
}


// File: crates/diesel_models/src/authentication.rs

use std::str::FromStr;

use common_utils::{
    encryption::Encryption,
    errors::{CustomResult, ValidationError},
    pii,
};
use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
use error_stack::ResultExt;
use serde::{self, Deserialize, Serialize};

use crate::schema::authentication;

#[derive(
    Clone, Debug, Eq, PartialEq, Identifiable, Queryable, Selectable, Serialize, Deserialize,
)]
#[diesel(table_name = authentication,  primary_key(authentication_id), check_for_backend(diesel::pg::Pg))]
pub struct Authentication {
    pub authentication_id: common_utils::id_type::AuthenticationId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub authentication_connector: Option<String>,
    pub connector_authentication_id: Option<String>,
    pub authentication_data: Option<serde_json::Value>,
    pub payment_method_id: String,
    pub authentication_type: Option<common_enums::DecoupledAuthenticationType>,
    pub authentication_status: common_enums::AuthenticationStatus,
    pub authentication_lifecycle_status: common_enums::AuthenticationLifecycleStatus,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub created_at: time::PrimitiveDateTime,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub modified_at: time::PrimitiveDateTime,
    pub error_message: Option<String>,
    pub error_code: Option<String>,
    pub connector_metadata: Option<serde_json::Value>,
    pub maximum_supported_version: Option<common_utils::types::SemanticVersion>,
    pub threeds_server_transaction_id: Option<String>,
    pub cavv: Option<String>,
    pub authentication_flow_type: Option<String>,
    pub message_version: Option<common_utils::types::SemanticVersion>,
    pub eci: Option<String>,
    pub trans_status: Option<common_enums::TransactionStatus>,
    pub acquirer_bin: Option<String>,
    pub acquirer_merchant_id: Option<String>,
    pub three_ds_method_data: Option<String>,
    pub three_ds_method_url: Option<String>,
    pub acs_url: Option<String>,
    pub challenge_request: Option<String>,
    pub acs_reference_number: Option<String>,
    pub acs_trans_id: Option<String>,
    pub acs_signed_content: Option<String>,
    pub profile_id: common_utils::id_type::ProfileId,
    pub payment_id: Option<common_utils::id_type::PaymentId>,
    pub merchant_connector_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
    pub ds_trans_id: Option<String>,
    pub directory_server_id: Option<String>,
    pub acquirer_country_code: Option<String>,
    pub service_details: Option<serde_json::Value>,
    pub organization_id: common_utils::id_type::OrganizationId,
    pub authentication_client_secret: Option<String>,
    pub force_3ds_challenge: Option<bool>,
    pub psd2_sca_exemption_type: Option<common_enums::ScaExemptionType>,
    pub return_url: Option<String>,
    pub amount: Option<common_utils::types::MinorUnit>,
    pub currency: Option<common_enums::Currency>,
    pub billing_address: Option<Encryption>,
    pub shipping_address: Option<Encryption>,
    pub browser_info: Option<serde_json::Value>,
    pub email: Option<Encryption>,
    pub profile_acquirer_id: Option<common_utils::id_type::ProfileAcquirerId>,
    pub challenge_code: Option<String>,
    pub challenge_cancel: Option<String>,
    pub challenge_code_reason: Option<String>,
    pub message_extension: Option<pii::SecretSerdeValue>,
    pub challenge_request_key: Option<String>,
    pub customer_details: Option<Encryption>,
}

impl Authentication {
    pub fn is_separate_authn_required(&self) -> bool {
        self.maximum_supported_version
            .as_ref()
            .is_some_and(|version| version.get_major() == 2)
    }

    // get authentication_connector from authentication record and check if it is jwt flow
    pub fn is_jwt_flow(&self) -> CustomResult<bool, ValidationError> {
        Ok(self
            .authentication_connector
            .clone()
            .map(|connector| {
                common_enums::AuthenticationConnectors::from_str(&connector)
                    .change_context(ValidationError::InvalidValue {
                        message: "failed to parse authentication_connector".to_string(),
                    })
                    .map(|connector_enum| connector_enum.is_jwt_flow())
            })
            .transpose()?
            .unwrap_or(false))
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Insertable)]
#[diesel(table_name = authentication)]
pub struct AuthenticationNew {
    pub authentication_id: common_utils::id_type::AuthenticationId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub authentication_connector: Option<String>,
    pub connector_authentication_id: Option<String>,
    // pub authentication_data: Option<serde_json::Value>,
    pub payment_method_id: String,
    pub authentication_type: Option<common_enums::DecoupledAuthenticationType>,
    pub authentication_status: common_enums::AuthenticationStatus,
    pub authentication_lifecycle_status: common_enums::AuthenticationLifecycleStatus,
    pub error_message: Option<String>,
    pub error_code: Option<String>,
    pub connector_metadata: Option<serde_json::Value>,
    pub maximum_supported_version: Option<common_utils::types::SemanticVersion>,
    pub threeds_server_transaction_id: Option<String>,
    pub cavv: Option<String>,
    pub authentication_flow_type: Option<String>,
    pub message_version: Option<common_utils::types::SemanticVersion>,
    pub eci: Option<String>,
    pub trans_status: Option<common_enums::TransactionStatus>,
    pub acquirer_bin: Option<String>,
    pub acquirer_merchant_id: Option<String>,
    pub three_ds_method_data: Option<String>,
    pub three_ds_method_url: Option<String>,
    pub acs_url: Option<String>,
    pub challenge_request: Option<String>,
    pub acs_reference_number: Option<String>,
    pub acs_trans_id: Option<String>,
    pub acs_signed_content: Option<String>,
    pub profile_id: common_utils::id_type::ProfileId,
    pub payment_id: Option<common_utils::id_type::PaymentId>,
    pub merchant_connector_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
    pub ds_trans_id: Option<String>,
    pub directory_server_id: Option<String>,
    pub acquirer_country_code: Option<String>,
    pub service_details: Option<serde_json::Value>,
    pub organization_id: common_utils::id_type::OrganizationId,
    pub authentication_client_secret: Option<String>,
    pub force_3ds_challenge: Option<bool>,
    pub psd2_sca_exemption_type: Option<common_enums::ScaExemptionType>,
    pub return_url: Option<String>,
    pub amount: Option<common_utils::types::MinorUnit>,
    pub currency: Option<common_enums::Currency>,
    pub billing_address: Option<Encryption>,
    pub shipping_address: Option<Encryption>,
    pub browser_info: Option<serde_json::Value>,
    pub email: Option<Encryption>,
    pub profile_acquirer_id: Option<common_utils::id_type::ProfileAcquirerId>,
    pub challenge_code: Option<String>,
    pub challenge_cancel: Option<String>,
    pub challenge_code_reason: Option<String>,
    pub message_extension: Option<pii::SecretSerdeValue>,
    pub challenge_request_key: Option<String>,
    pub customer_details: Option<Encryption>,
}

#[derive(Debug)]
pub enum AuthenticationUpdate {
    PreAuthenticationVersionCallUpdate {
        maximum_supported_3ds_version: common_utils::types::SemanticVersion,
        message_version: common_utils::types::SemanticVersion,
    },
    PreAuthenticationThreeDsMethodCall {
        threeds_server_transaction_id: String,
        three_ds_method_data: Option<String>,
        three_ds_method_url: Option<String>,
        acquirer_bin: Option<String>,
        acquirer_merchant_id: Option<String>,
        connector_metadata: Option<serde_json::Value>,
    },
    PreAuthenticationUpdate {
        threeds_server_transaction_id: String,
        maximum_supported_3ds_version: common_utils::types::SemanticVersion,
        connector_authentication_id: String,
        three_ds_method_data: Option<String>,
        three_ds_method_url: Option<String>,
        message_version: common_utils::types::SemanticVersion,
        connector_metadata: Option<serde_json::Value>,
        authentication_status: common_enums::AuthenticationStatus,
        acquirer_bin: Option<String>,
        acquirer_merchant_id: Option<String>,
        directory_server_id: Option<String>,
        acquirer_country_code: Option<String>,
        billing_address: Option<Encryption>,
        shipping_address: Option<Encryption>,
        browser_info: Box<Option<serde_json::Value>>,
        email: Option<Encryption>,
    },
    AuthenticationUpdate {
        trans_status: common_enums::TransactionStatus,
        authentication_type: common_enums::DecoupledAuthenticationType,
        acs_url: Option<String>,
        challenge_request: Option<String>,
        acs_reference_number: Option<String>,
        acs_trans_id: Option<String>,
        acs_signed_content: Option<String>,
        connector_metadata: Option<serde_json::Value>,
        authentication_status: common_enums::AuthenticationStatus,
        ds_trans_id: Option<String>,
        eci: Option<String>,
        challenge_code: Option<String>,
        challenge_cancel: Option<String>,
        challenge_code_reason: Option<String>,
        message_extension: Option<pii::SecretSerdeValue>,
        challenge_request_key: Option<String>,
    },
    PostAuthenticationUpdate {
        trans_status: common_enums::TransactionStatus,
        eci: Option<String>,
        authentication_status: common_enums::AuthenticationStatus,
        challenge_cancel: Option<String>,
        challenge_code_reason: Option<String>,
    },
    ErrorUpdate {
        error_message: Option<String>,
        error_code: Option<String>,
        authentication_status: common_enums::AuthenticationStatus,
        connector_authentication_id: Option<String>,
    },
    PostAuthorizationUpdate {
        authentication_lifecycle_status: common_enums::AuthenticationLifecycleStatus,
    },
    AuthenticationStatusUpdate {
        trans_status: common_enums::TransactionStatus,
        authentication_status: common_enums::AuthenticationStatus,
    },
}

#[derive(Clone, Debug, Eq, PartialEq, AsChangeset, Serialize, Deserialize)]
#[diesel(table_name = authentication)]
pub struct AuthenticationUpdateInternal {
    pub connector_authentication_id: Option<String>,
    // pub authentication_data: Option<serde_json::Value>,
    pub payment_method_id: Option<String>,
    pub authentication_type: Option<common_enums::DecoupledAuthenticationType>,
    pub authentication_status: Option<common_enums::AuthenticationStatus>,
    pub authentication_lifecycle_status: Option<common_enums::AuthenticationLifecycleStatus>,
    pub modified_at: time::PrimitiveDateTime,
    pub error_message: Option<String>,
    pub error_code: Option<String>,
    pub connector_metadata: Option<serde_json::Value>,
    pub maximum_supported_version: Option<common_utils::types::SemanticVersion>,
    pub threeds_server_transaction_id: Option<String>,
    pub authentication_flow_type: Option<String>,
    pub message_version: Option<common_utils::types::SemanticVersion>,
    pub eci: Option<String>,
    pub trans_status: Option<common_enums::TransactionStatus>,
    pub acquirer_bin: Option<String>,
    pub acquirer_merchant_id: Option<String>,
    pub three_ds_method_data: Option<String>,
    pub three_ds_method_url: Option<String>,
    pub acs_url: Option<String>,
    pub challenge_request: Option<String>,
    pub acs_reference_number: Option<String>,
    pub acs_trans_id: Option<String>,
    pub acs_signed_content: Option<String>,
    pub ds_trans_id: Option<String>,
    pub directory_server_id: Option<String>,
    pub acquirer_country_code: Option<String>,
    pub service_details: Option<serde_json::Value>,
    pub force_3ds_challenge: Option<bool>,
    pub psd2_sca_exemption_type: Option<common_enums::ScaExemptionType>,
    pub billing_address: Option<Encryption>,
    pub shipping_address: Option<Encryption>,
    pub browser_info: Option<serde_json::Value>,
    pub email: Option<Encryption>,
    pub profile_acquirer_id: Option<common_utils::id_type::ProfileAcquirerId>,
    pub challenge_code: Option<String>,
    pub challenge_cancel: Option<String>,
    pub challenge_code_reason: Option<String>,
    pub message_extension: Option<pii::SecretSerdeValue>,
    pub challenge_request_key: Option<String>,
    pub customer_details: Option<Encryption>,
}

impl Default for AuthenticationUpdateInternal {
    fn default() -> Self {
        Self {
            connector_authentication_id: Default::default(),
            payment_method_id: Default::default(),
            authentication_type: Default::default(),
            authentication_status: Default::default(),
            authentication_lifecycle_status: Default::default(),
            modified_at: common_utils::date_time::now(),
            error_message: Default::default(),
            error_code: Default::default(),
            connector_metadata: Default::default(),
            maximum_supported_version: Default::default(),
            threeds_server_transaction_id: Default::default(),
            authentication_flow_type: Default::default(),
            message_version: Default::default(),
            eci: Default::default(),
            trans_status: Default::default(),
            acquirer_bin: Default::default(),
            acquirer_merchant_id: Default::default(),
            three_ds_method_data: Default::default(),
            three_ds_method_url: Default::default(),
            acs_url: Default::default(),
            challenge_request: Default::default(),
            acs_reference_number: Default::default(),
            acs_trans_id: Default::default(),
            acs_signed_content: Default::default(),
            ds_trans_id: Default::default(),
            directory_server_id: Default::default(),
            acquirer_country_code: Default::default(),
            service_details: Default::default(),
            force_3ds_challenge: Default::default(),
            psd2_sca_exemption_type: Default::default(),
            billing_address: Default::default(),
            shipping_address: Default::default(),
            browser_info: Default::default(),
            email: Default::default(),
            profile_acquirer_id: Default::default(),
            challenge_code: Default::default(),
            challenge_cancel: Default::default(),
            challenge_code_reason: Default::default(),
            message_extension: Default::default(),
            challenge_request_key: Default::default(),
            customer_details: Default::default(),
        }
    }
}

impl AuthenticationUpdateInternal {
    pub fn apply_changeset(self, source: Authentication) -> Authentication {
        let Self {
            connector_authentication_id,
            payment_method_id,
            authentication_type,
            authentication_status,
            authentication_lifecycle_status,
            modified_at: _,
            error_code,
            error_message,
            connector_metadata,
            maximum_supported_version,
            threeds_server_transaction_id,
            authentication_flow_type,
            message_version,
            eci,
            trans_status,
            acquirer_bin,
            acquirer_merchant_id,
            three_ds_method_data,
            three_ds_method_url,
            acs_url,
            challenge_request,
            acs_reference_number,
            acs_trans_id,
            acs_signed_content,
            ds_trans_id,
            directory_server_id,
            acquirer_country_code,
            service_details,
            force_3ds_challenge,
            psd2_sca_exemption_type,
            billing_address,
            shipping_address,
            browser_info,
            email,
            profile_acquirer_id,
            challenge_code,
            challenge_cancel,
            challenge_code_reason,
            message_extension,
            challenge_request_key,
            customer_details,
        } = self;
        Authentication {
            connector_authentication_id: connector_authentication_id
                .or(source.connector_authentication_id),
            payment_method_id: payment_method_id.unwrap_or(source.payment_method_id),
            authentication_type: authentication_type.or(source.authentication_type),
            authentication_status: authentication_status.unwrap_or(source.authentication_status),
            authentication_lifecycle_status: authentication_lifecycle_status
                .unwrap_or(source.authentication_lifecycle_status),
            modified_at: common_utils::date_time::now(),
            error_code: error_code.or(source.error_code),
            error_message: error_message.or(source.error_message),
            connector_metadata: connector_metadata.or(source.connector_metadata),
            maximum_supported_version: maximum_supported_version
                .or(source.maximum_supported_version),
            threeds_server_transaction_id: threeds_server_transaction_id
                .or(source.threeds_server_transaction_id),
            authentication_flow_type: authentication_flow_type.or(source.authentication_flow_type),
            message_version: message_version.or(source.message_version),
            eci: eci.or(source.eci),
            trans_status: trans_status.or(source.trans_status),
            acquirer_bin: acquirer_bin.or(source.acquirer_bin),
            acquirer_merchant_id: acquirer_merchant_id.or(source.acquirer_merchant_id),
            three_ds_method_data: three_ds_method_data.or(source.three_ds_method_data),
            three_ds_method_url: three_ds_method_url.or(source.three_ds_method_url),
            acs_url: acs_url.or(source.acs_url),
            challenge_request: challenge_request.or(source.challenge_request),
            acs_reference_number: acs_reference_number.or(source.acs_reference_number),
            acs_trans_id: acs_trans_id.or(source.acs_trans_id),
            acs_signed_content: acs_signed_content.or(source.acs_signed_content),
            ds_trans_id: ds_trans_id.or(source.ds_trans_id),
            directory_server_id: directory_server_id.or(source.directory_server_id),
            acquirer_country_code: acquirer_country_code.or(source.acquirer_country_code),
            service_details: service_details.or(source.service_details),
            force_3ds_challenge: force_3ds_challenge.or(source.force_3ds_challenge),
            psd2_sca_exemption_type: psd2_sca_exemption_type.or(source.psd2_sca_exemption_type),
            billing_address: billing_address.or(source.billing_address),
            shipping_address: shipping_address.or(source.shipping_address),
            browser_info: browser_info.or(source.browser_info),
            email: email.or(source.email),
            profile_acquirer_id: profile_acquirer_id.or(source.profile_acquirer_id),
            challenge_code: challenge_code.or(source.challenge_code),
            challenge_cancel: challenge_cancel.or(source.challenge_cancel),
            challenge_code_reason: challenge_code_reason.or(source.challenge_code_reason),
            message_extension: message_extension.or(source.message_extension),
            challenge_request_key: challenge_request_key.or(source.challenge_request_key),
            customer_details: customer_details.or(source.customer_details),
            ..source
        }
    }
}

impl From<AuthenticationUpdate> for AuthenticationUpdateInternal {
    fn from(auth_update: AuthenticationUpdate) -> Self {
        match auth_update {
            AuthenticationUpdate::ErrorUpdate {
                error_message,
                error_code,
                authentication_status,
                connector_authentication_id,
            } => Self {
                error_code,
                error_message,
                authentication_status: Some(authentication_status),
                connector_authentication_id,
                authentication_type: None,
                authentication_lifecycle_status: None,
                modified_at: common_utils::date_time::now(),
                payment_method_id: None,
                connector_metadata: None,
                ..Default::default()
            },
            AuthenticationUpdate::PostAuthorizationUpdate {
                authentication_lifecycle_status,
            } => Self {
                connector_authentication_id: None,

                payment_method_id: None,
                authentication_type: None,
                authentication_status: None,
                authentication_lifecycle_status: Some(authentication_lifecycle_status),
                modified_at: common_utils::date_time::now(),
                error_message: None,
                error_code: None,
                connector_metadata: None,
                ..Default::default()
            },
            AuthenticationUpdate::PreAuthenticationUpdate {
                threeds_server_transaction_id,
                maximum_supported_3ds_version,
                connector_authentication_id,
                three_ds_method_data,
                three_ds_method_url,
                message_version,
                connector_metadata,
                authentication_status,
                acquirer_bin,
                acquirer_merchant_id,
                directory_server_id,
                acquirer_country_code,
                billing_address,
                shipping_address,
                browser_info,
                email,
            } => Self {
                threeds_server_transaction_id: Some(threeds_server_transaction_id),
                maximum_supported_version: Some(maximum_supported_3ds_version),
                connector_authentication_id: Some(connector_authentication_id),
                three_ds_method_data,
                three_ds_method_url,
                message_version: Some(message_version),
                connector_metadata,
                authentication_status: Some(authentication_status),
                acquirer_bin,
                acquirer_merchant_id,
                directory_server_id,
                acquirer_country_code,
                billing_address,
                shipping_address,
                browser_info: *browser_info,
                email,
                ..Default::default()
            },
            AuthenticationUpdate::AuthenticationUpdate {
                trans_status,
                authentication_type,
                acs_url,
                challenge_request,
                acs_reference_number,
                acs_trans_id,
                acs_signed_content,
                connector_metadata,
                authentication_status,
                ds_trans_id,
                eci,
                challenge_code,
                challenge_cancel,
                challenge_code_reason,
                message_extension,
                challenge_request_key,
            } => Self {
                trans_status: Some(trans_status),
                authentication_type: Some(authentication_type),
                acs_url,
                challenge_request,
                acs_reference_number,
                acs_trans_id,
                acs_signed_content,
                connector_metadata,
                authentication_status: Some(authentication_status),
                ds_trans_id,
                eci,
                challenge_code,
                challenge_cancel,
                challenge_code_reason,
                message_extension,
                challenge_request_key,
                ..Default::default()
            },
            AuthenticationUpdate::PostAuthenticationUpdate {
                trans_status,
                eci,
                authentication_status,
                challenge_cancel,
                challenge_code_reason,
            } => Self {
                trans_status: Some(trans_status),
                eci,
                authentication_status: Some(authentication_status),
                challenge_cancel,
                challenge_code_reason,
                ..Default::default()
            },
            AuthenticationUpdate::PreAuthenticationVersionCallUpdate {
                maximum_supported_3ds_version,
                message_version,
            } => Self {
                maximum_supported_version: Some(maximum_supported_3ds_version),
                message_version: Some(message_version),
                ..Default::default()
            },
            AuthenticationUpdate::PreAuthenticationThreeDsMethodCall {
                threeds_server_transaction_id,
                three_ds_method_data,
                three_ds_method_url,
                acquirer_bin,
                acquirer_merchant_id,
                connector_metadata,
            } => Self {
                threeds_server_transaction_id: Some(threeds_server_transaction_id),
                three_ds_method_data,
                three_ds_method_url,
                acquirer_bin,
                acquirer_merchant_id,
                connector_metadata,
                ..Default::default()
            },
            AuthenticationUpdate::AuthenticationStatusUpdate {
                trans_status,
                authentication_status,
            } => Self {
                trans_status: Some(trans_status),
                authentication_status: Some(authentication_status),
                ..Default::default()
            },
        }
    }
}


// File: crates/diesel_models/src/merchant_key_store.rs

use common_utils::{custom_serde, encryption::Encryption};
use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
use time::PrimitiveDateTime;

use crate::schema::merchant_key_store;

#[derive(
    Clone,
    Debug,
    serde::Serialize,
    serde::Deserialize,
    Identifiable,
    Queryable,
    Selectable,
    router_derive::DebugAsDisplay,
)]
#[diesel(table_name = merchant_key_store, primary_key(merchant_id), check_for_backend(diesel::pg::Pg))]
pub struct MerchantKeyStore {
    pub merchant_id: common_utils::id_type::MerchantId,
    pub key: Encryption,
    #[serde(with = "custom_serde::iso8601")]
    pub created_at: PrimitiveDateTime,
}

#[derive(
    Clone, Debug, serde::Serialize, serde::Deserialize, Insertable, router_derive::DebugAsDisplay,
)]
#[diesel(table_name = merchant_key_store)]
pub struct MerchantKeyStoreNew {
    pub merchant_id: common_utils::id_type::MerchantId,
    pub key: Encryption,
    pub created_at: PrimitiveDateTime,
}

#[derive(
    Clone, Debug, serde::Serialize, serde::Deserialize, AsChangeset, router_derive::DebugAsDisplay,
)]
#[diesel(table_name = merchant_key_store)]
pub struct MerchantKeyStoreUpdateInternal {
    pub merchant_id: common_utils::id_type::MerchantId,
    pub key: Encryption,
}


// File: crates/diesel_models/src/user_key_store.rs

use common_utils::encryption::Encryption;
use diesel::{Identifiable, Insertable, Queryable, Selectable};
use time::PrimitiveDateTime;

use crate::schema::user_key_store;

#[derive(
    Clone, Debug, serde::Serialize, serde::Deserialize, Identifiable, Queryable, Selectable,
)]
#[diesel(table_name = user_key_store, primary_key(user_id), check_for_backend(diesel::pg::Pg))]
pub struct UserKeyStore {
    pub user_id: String,
    pub key: Encryption,
    pub created_at: PrimitiveDateTime,
}

#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, Insertable)]
#[diesel(table_name = user_key_store)]
pub struct UserKeyStoreNew {
    pub user_id: String,
    pub key: Encryption,
    pub created_at: PrimitiveDateTime,
}


// File: crates/diesel_models/src/ephemeral_key.rs

#[cfg(feature = "v2")]
use masking::{PeekInterface, Secret};

#[cfg(feature = "v2")]
pub struct ClientSecretTypeNew {
    pub id: common_utils::id_type::ClientSecretId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub secret: Secret<String>,
    pub resource_id: common_utils::types::authentication::ResourceId,
}

#[cfg(feature = "v2")]
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct ClientSecretType {
    pub id: common_utils::id_type::ClientSecretId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub resource_id: common_utils::types::authentication::ResourceId,
    pub created_at: time::PrimitiveDateTime,
    pub expires: time::PrimitiveDateTime,
    pub secret: Secret<String>,
}

#[cfg(feature = "v2")]
impl ClientSecretType {
    pub fn generate_secret_key(&self) -> String {
        format!("cs_{}", self.secret.peek())
    }
}

pub struct EphemeralKeyNew {
    pub id: String,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub customer_id: common_utils::id_type::CustomerId,
    pub secret: String,
}

#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct EphemeralKey {
    pub id: String,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub customer_id: common_utils::id_type::CustomerId,
    pub created_at: i64,
    pub expires: i64,
    pub secret: String,
}

impl common_utils::events::ApiEventMetric for EphemeralKey {
    fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
        Some(common_utils::events::ApiEventsType::Miscellaneous)
    }
}


// File: crates/diesel_models/src/reverse_lookup.rs

use diesel::{Identifiable, Insertable, Queryable, Selectable};

use crate::schema::reverse_lookup;

/// This reverse lookup table basically looks up id's and get result_id that you want. This is
/// useful for KV where you can't lookup without key
#[derive(
    Clone,
    Debug,
    serde::Serialize,
    serde::Deserialize,
    Identifiable,
    Queryable,
    Selectable,
    Eq,
    PartialEq,
)]
#[diesel(table_name = reverse_lookup, primary_key(lookup_id), check_for_backend(diesel::pg::Pg))]
pub struct ReverseLookup {
    /// Primary key. The key id.
    pub lookup_id: String,
    /// the `field` in KV database. Which is used to differentiate between two same keys
    pub sk_id: String,
    /// the value id. i.e the id you want to access KV table.
    pub pk_id: String,
    /// the source of insertion for reference
    pub source: String,
    pub updated_by: String,
}

#[derive(
    Clone,
    Debug,
    Insertable,
    router_derive::DebugAsDisplay,
    Eq,
    PartialEq,
    serde::Serialize,
    serde::Deserialize,
)]
#[diesel(table_name = reverse_lookup)]
pub struct ReverseLookupNew {
    pub lookup_id: String,
    pub pk_id: String,
    pub sk_id: String,
    pub source: String,
    pub updated_by: String,
}

impl From<ReverseLookupNew> for ReverseLookup {
    fn from(new: ReverseLookupNew) -> Self {
        Self {
            lookup_id: new.lookup_id,
            sk_id: new.sk_id,
            pk_id: new.pk_id,
            source: new.source,
            updated_by: new.updated_by,
        }
    }
}


// File: crates/diesel_models/src/relay.rs

use common_utils::pii;
use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
use time::PrimitiveDateTime;

use crate::{enums as storage_enums, schema::relay};

#[derive(
    Clone,
    Debug,
    Eq,
    Identifiable,
    Queryable,
    Selectable,
    PartialEq,
    serde::Serialize,
    serde::Deserialize,
)]
#[diesel(table_name = relay)]
pub struct Relay {
    pub id: common_utils::id_type::RelayId,
    pub connector_resource_id: String,
    pub connector_id: common_utils::id_type::MerchantConnectorAccountId,
    pub profile_id: common_utils::id_type::ProfileId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub relay_type: storage_enums::RelayType,
    pub request_data: Option<pii::SecretSerdeValue>,
    pub status: storage_enums::RelayStatus,
    pub connector_reference_id: Option<String>,
    pub error_code: Option<String>,
    pub error_message: Option<String>,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub created_at: PrimitiveDateTime,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub modified_at: PrimitiveDateTime,
    pub response_data: Option<pii::SecretSerdeValue>,
}

#[derive(
    Clone,
    Debug,
    Eq,
    PartialEq,
    Insertable,
    router_derive::DebugAsDisplay,
    serde::Serialize,
    serde::Deserialize,
    router_derive::Setter,
)]
#[diesel(table_name = relay)]
pub struct RelayNew {
    pub id: common_utils::id_type::RelayId,
    pub connector_resource_id: String,
    pub connector_id: common_utils::id_type::MerchantConnectorAccountId,
    pub profile_id: common_utils::id_type::ProfileId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub relay_type: storage_enums::RelayType,
    pub request_data: Option<pii::SecretSerdeValue>,
    pub status: storage_enums::RelayStatus,
    pub connector_reference_id: Option<String>,
    pub error_code: Option<String>,
    pub error_message: Option<String>,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub created_at: PrimitiveDateTime,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub modified_at: PrimitiveDateTime,
    pub response_data: Option<pii::SecretSerdeValue>,
}

#[derive(Clone, Debug, AsChangeset, router_derive::DebugAsDisplay)]
#[diesel(table_name = relay)]
pub struct RelayUpdateInternal {
    pub connector_reference_id: Option<String>,
    pub status: Option<storage_enums::RelayStatus>,
    pub error_code: Option<String>,
    pub error_message: Option<String>,
    pub modified_at: PrimitiveDateTime,
}


// File: crates/diesel_models/src/mandate.rs

use common_enums::MerchantStorageScheme;
use common_utils::pii;
use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
use masking::Secret;
use time::PrimitiveDateTime;

use crate::{enums as storage_enums, schema::mandate};

#[derive(
    Clone, Debug, Identifiable, Queryable, Selectable, serde::Serialize, serde::Deserialize,
)]
#[diesel(table_name = mandate, primary_key(mandate_id), check_for_backend(diesel::pg::Pg))]
pub struct Mandate {
    pub mandate_id: String,
    pub customer_id: common_utils::id_type::CustomerId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub payment_method_id: String,
    pub mandate_status: storage_enums::MandateStatus,
    pub mandate_type: storage_enums::MandateType,
    pub customer_accepted_at: Option<PrimitiveDateTime>,
    pub customer_ip_address: Option<Secret<String, pii::IpAddress>>,
    pub customer_user_agent: Option<String>,
    pub network_transaction_id: Option<String>,
    pub previous_attempt_id: Option<String>,
    pub created_at: PrimitiveDateTime,
    pub mandate_amount: Option<i64>,
    pub mandate_currency: Option<storage_enums::Currency>,
    pub amount_captured: Option<i64>,
    pub connector: String,
    pub connector_mandate_id: Option<String>,
    pub start_date: Option<PrimitiveDateTime>,
    pub end_date: Option<PrimitiveDateTime>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub connector_mandate_ids: Option<pii::SecretSerdeValue>,
    pub original_payment_id: Option<common_utils::id_type::PaymentId>,
    pub merchant_connector_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
    pub updated_by: Option<String>,
    // This is the extended version of customer user agent that can store string upto 2048 characters unlike customer user agent that can store 255 characters at max
    pub customer_user_agent_extended: Option<String>,
}

#[derive(
    router_derive::Setter,
    Clone,
    Debug,
    Default,
    Insertable,
    router_derive::DebugAsDisplay,
    serde::Serialize,
    serde::Deserialize,
)]
#[diesel(table_name = mandate)]
pub struct MandateNew {
    pub mandate_id: String,
    pub customer_id: common_utils::id_type::CustomerId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub payment_method_id: String,
    pub mandate_status: storage_enums::MandateStatus,
    pub mandate_type: storage_enums::MandateType,
    pub customer_accepted_at: Option<PrimitiveDateTime>,
    pub customer_ip_address: Option<Secret<String, pii::IpAddress>>,
    pub customer_user_agent: Option<String>,
    pub network_transaction_id: Option<String>,
    pub previous_attempt_id: Option<String>,
    pub created_at: Option<PrimitiveDateTime>,
    pub mandate_amount: Option<i64>,
    pub mandate_currency: Option<storage_enums::Currency>,
    pub amount_captured: Option<i64>,
    pub connector: String,
    pub connector_mandate_id: Option<String>,
    pub start_date: Option<PrimitiveDateTime>,
    pub end_date: Option<PrimitiveDateTime>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub connector_mandate_ids: Option<pii::SecretSerdeValue>,
    pub original_payment_id: Option<common_utils::id_type::PaymentId>,
    pub merchant_connector_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
    pub updated_by: Option<String>,
    pub customer_user_agent_extended: Option<String>,
}

impl Mandate {
    /// Returns customer_user_agent_extended with customer_user_agent as fallback
    pub fn get_user_agent_extended(&self) -> Option<String> {
        self.customer_user_agent_extended
            .clone()
            .or_else(|| self.customer_user_agent.clone())
    }
}

impl MandateNew {
    pub fn update_storage_scheme(&mut self, storage_scheme: MerchantStorageScheme) {
        self.updated_by = Some(storage_scheme.to_string());
    }

    /// Returns customer_user_agent_extended with customer_user_agent as fallback
    pub fn get_customer_user_agent_extended(&self) -> Option<String> {
        self.customer_user_agent_extended
            .clone()
            .or_else(|| self.customer_user_agent.clone())
    }
}

#[derive(Debug)]
pub enum MandateUpdate {
    StatusUpdate {
        mandate_status: storage_enums::MandateStatus,
    },
    CaptureAmountUpdate {
        amount_captured: Option<i64>,
    },
    ConnectorReferenceUpdate {
        connector_mandate_ids: Option<pii::SecretSerdeValue>,
    },
    ConnectorMandateIdUpdate {
        connector_mandate_id: Option<String>,
        connector_mandate_ids: Option<pii::SecretSerdeValue>,
        payment_method_id: String,
        original_payment_id: Option<common_utils::id_type::PaymentId>,
    },
}

impl MandateUpdate {
    pub fn convert_to_mandate_update(
        self,
        storage_scheme: MerchantStorageScheme,
    ) -> MandateUpdateInternal {
        let mut updated_object = MandateUpdateInternal::from(self);
        updated_object.updated_by = Some(storage_scheme.to_string());
        updated_object
    }
}

#[derive(Clone, Eq, PartialEq, Copy, Debug, Default, serde::Serialize, serde::Deserialize)]
pub struct SingleUseMandate {
    pub amount: i64,
    pub currency: storage_enums::Currency,
}

#[derive(
    Clone,
    Debug,
    Default,
    AsChangeset,
    router_derive::DebugAsDisplay,
    serde::Serialize,
    serde::Deserialize,
)]
#[diesel(table_name = mandate)]
pub struct MandateUpdateInternal {
    mandate_status: Option<storage_enums::MandateStatus>,
    amount_captured: Option<i64>,
    connector_mandate_ids: Option<pii::SecretSerdeValue>,
    connector_mandate_id: Option<String>,
    payment_method_id: Option<String>,
    original_payment_id: Option<common_utils::id_type::PaymentId>,
    updated_by: Option<String>,
}

impl From<MandateUpdate> for MandateUpdateInternal {
    fn from(mandate_update: MandateUpdate) -> Self {
        match mandate_update {
            MandateUpdate::StatusUpdate { mandate_status } => Self {
                mandate_status: Some(mandate_status),
                connector_mandate_ids: None,
                amount_captured: None,
                connector_mandate_id: None,
                payment_method_id: None,
                original_payment_id: None,
                updated_by: None,
            },
            MandateUpdate::CaptureAmountUpdate { amount_captured } => Self {
                mandate_status: None,
                amount_captured,
                connector_mandate_ids: None,
                connector_mandate_id: None,
                payment_method_id: None,
                original_payment_id: None,
                updated_by: None,
            },
            MandateUpdate::ConnectorReferenceUpdate {
                connector_mandate_ids,
            } => Self {
                connector_mandate_ids,
                ..Default::default()
            },
            MandateUpdate::ConnectorMandateIdUpdate {
                connector_mandate_id,
                connector_mandate_ids,
                payment_method_id,
                original_payment_id,
            } => Self {
                connector_mandate_id,
                connector_mandate_ids,
                payment_method_id: Some(payment_method_id),
                original_payment_id,
                ..Default::default()
            },
        }
    }
}

impl MandateUpdateInternal {
    pub fn apply_changeset(self, source: Mandate) -> Mandate {
        let Self {
            mandate_status,
            amount_captured,
            connector_mandate_ids,
            connector_mandate_id,
            payment_method_id,
            original_payment_id,
            updated_by,
        } = self;

        Mandate {
            mandate_status: mandate_status.unwrap_or(source.mandate_status),
            amount_captured: amount_captured.map_or(source.amount_captured, Some),
            connector_mandate_ids: connector_mandate_ids.map_or(source.connector_mandate_ids, Some),
            connector_mandate_id: connector_mandate_id.map_or(source.connector_mandate_id, Some),
            payment_method_id: payment_method_id.unwrap_or(source.payment_method_id),
            original_payment_id: original_payment_id.map_or(source.original_payment_id, Some),
            updated_by: updated_by.map_or(source.updated_by, Some),
            ..source
        }
    }
}

impl From<&MandateNew> for Mandate {
    fn from(mandate_new: &MandateNew) -> Self {
        Self {
            mandate_id: mandate_new.mandate_id.clone(),
            customer_id: mandate_new.customer_id.clone(),
            merchant_id: mandate_new.merchant_id.clone(),
            payment_method_id: mandate_new.payment_method_id.clone(),
            mandate_status: mandate_new.mandate_status,
            mandate_type: mandate_new.mandate_type,
            customer_accepted_at: mandate_new.customer_accepted_at,
            customer_ip_address: mandate_new.customer_ip_address.clone(),
            customer_user_agent: None,
            network_transaction_id: mandate_new.network_transaction_id.clone(),
            previous_attempt_id: mandate_new.previous_attempt_id.clone(),
            created_at: mandate_new
                .created_at
                .unwrap_or_else(common_utils::date_time::now),
            mandate_amount: mandate_new.mandate_amount,
            mandate_currency: mandate_new.mandate_currency,
            amount_captured: mandate_new.amount_captured,
            connector: mandate_new.connector.clone(),
            connector_mandate_id: mandate_new.connector_mandate_id.clone(),
            start_date: mandate_new.start_date,
            end_date: mandate_new.end_date,
            metadata: mandate_new.metadata.clone(),
            connector_mandate_ids: mandate_new.connector_mandate_ids.clone(),
            original_payment_id: mandate_new.original_payment_id.clone(),
            merchant_connector_id: mandate_new.merchant_connector_id.clone(),
            updated_by: mandate_new.updated_by.clone(),
            // Using customer_user_agent as a fallback
            customer_user_agent_extended: mandate_new.get_customer_user_agent_extended(),
        }
    }
}