// File: crates/router/src/events/audit_events.rs
// Module: router
// Public functions: 1
// Public structs: 1

use api_models::payments::Amount;
use common_utils::types::MinorUnit;
use diesel_models::fraud_check::FraudCheck;
use events::{Event, EventInfo};
use serde::Serialize;
use time::PrimitiveDateTime;
#[derive(Debug, Clone, Serialize)]
#[serde(tag = "event_type")]
pub enum AuditEventType {
    Error {
        error_message: String,
    },
    PaymentCreated,
    ConnectorDecided,
    ConnectorCalled,
    RefundCreated,
    RefundSuccess,
    RefundFail,
    PaymentConfirm {
        client_src: Option<String>,
        client_ver: Option<String>,
        frm_message: Box<Option<FraudCheck>>,
    },
    PaymentCancelled {
        cancellation_reason: Option<String>,
    },
    PaymentCapture {
        capture_amount: Option<MinorUnit>,
        multiple_capture_count: Option<i16>,
    },
    PaymentUpdate {
        amount: Amount,
    },
    PaymentApprove,
    PaymentCreate,
    PaymentStatus,
    PaymentCompleteAuthorize,
    PaymentReject {
        error_code: Option<String>,
        error_message: Option<String>,
    },
}

#[derive(Debug, Clone, Serialize)]
pub struct AuditEvent {
    #[serde(flatten)]
    event_type: AuditEventType,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    created_at: PrimitiveDateTime,
}

impl AuditEvent {
    pub fn new(event_type: AuditEventType) -> Self {
        Self {
            event_type,
            created_at: common_utils::date_time::now(),
        }
    }
}

impl Event for AuditEvent {
    type EventType = super::EventType;

    fn timestamp(&self) -> PrimitiveDateTime {
        self.created_at
    }

    fn identifier(&self) -> String {
        let event_type = match &self.event_type {
            AuditEventType::Error { .. } => "error",
            AuditEventType::PaymentCreated => "payment_created",
            AuditEventType::PaymentConfirm { .. } => "payment_confirm",
            AuditEventType::ConnectorDecided => "connector_decided",
            AuditEventType::ConnectorCalled => "connector_called",
            AuditEventType::PaymentCapture { .. } => "payment_capture",
            AuditEventType::RefundCreated => "refund_created",
            AuditEventType::RefundSuccess => "refund_success",
            AuditEventType::RefundFail => "refund_fail",
            AuditEventType::PaymentCancelled { .. } => "payment_cancelled",
            AuditEventType::PaymentUpdate { .. } => "payment_update",
            AuditEventType::PaymentApprove => "payment_approve",
            AuditEventType::PaymentCreate => "payment_create",
            AuditEventType::PaymentStatus => "payment_status",
            AuditEventType::PaymentCompleteAuthorize => "payment_complete_authorize",
            AuditEventType::PaymentReject { .. } => "payment_rejected",
        };
        format!(
            "{event_type}-{}",
            self.timestamp().assume_utc().unix_timestamp_nanos()
        )
    }

    fn class(&self) -> Self::EventType {
        super::EventType::AuditEvent
    }
}

impl EventInfo for AuditEvent {
    type Data = Self;

    fn data(&self) -> error_stack::Result<Self::Data, events::EventsError> {
        Ok(self.clone())
    }

    fn key(&self) -> String {
        "event".to_string()
    }
}


// Function: error_type
// File: crates/api_models/src/errors/types.rs
// Module: api_models

pub fn error_type(&self) -> &'static str


// Implementation: impl api::PaymentSession for for Mifinity
// File: crates/hyperswitch_connectors/src/connectors/mifinity.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentSession for for Mifinity


// Function: update_payment_method_and_last_used
// File: crates/router/src/core/payment_methods/cards.rs
// Module: router

pub fn update_payment_method_and_last_used(
    state: &routes::SessionState,
    key_store: &domain::MerchantKeyStore,
    db: &dyn db::StorageInterface,
    pm: domain::PaymentMethod,
    payment_method_update: Option<Encryption>,
    storage_scheme: MerchantStorageScheme,
    card_scheme: Option<String>,
) -> errors::CustomResult<(), errors::VaultError>


// Function: insert
// File: crates/diesel_models/src/query/payment_attempt.rs
// Module: diesel_models

pub fn insert(self, conn: &PgPooledConn) -> StorageResult<PaymentAttempt>


// Implementation: impl PaymentAuthorize for for DummyConnector
// File: crates/hyperswitch_connectors/src/connectors/dummyconnector.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl PaymentAuthorize for for DummyConnector


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

impl Responder


// Struct: OpayoPaymentsResponse
// File: crates/hyperswitch_connectors/src/connectors/opayo/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct OpayoPaymentsResponse


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

pub fn list_payments(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    constraints: api::PaymentListConstraints,
) -> RouterResponse<payments_api::PaymentListResponse>


// Struct: RawPaymentCounterparty
// File: crates/hyperswitch_connectors/src/connectors/adyenplatform/transformers/payouts.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct RawPaymentCounterparty<'a, F>


// Function: update_by_address_id
// File: crates/diesel_models/src/query/address.rs
// Module: diesel_models

pub fn update_by_address_id(
        conn: &PgPooledConn,
        address_id: String,
        address: AddressUpdateInternal,
    ) -> StorageResult<Self>


// Struct: SantanderBoletoPaymentRequest
// File: crates/hyperswitch_connectors/src/connectors/santander/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct SantanderBoletoPaymentRequest


// Struct: TokenizedWalletInsensitiveValues
// File: crates/router/src/core/payment_methods/vault.rs
// Module: router
// Implementations: 0

pub struct TokenizedWalletInsensitiveValues


// Struct: HyperswitchVaultCreateRequest
// File: crates/hyperswitch_connectors/src/connectors/hyperswitch_vault/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct HyperswitchVaultCreateRequest


// Struct: PazePaymentProcessingDetails
// File: crates/router/src/core/payments.rs
// Module: router
// Implementations: 0

pub struct PazePaymentProcessingDetails


// Struct: PaymentAuthenticateCompleteAuthorize
// File: crates/router/src/core/payments.rs
// Module: router
// Implementations: 1
// Traits: PaymentRedirectFlow

pub struct PaymentAuthenticateCompleteAuthorize


// Function: new_single
// File: crates/hyperswitch_connectors/src/connectors/netcetera/netcetera_types.rs
// Module: hyperswitch_connectors

pub fn new_single(value: T) -> Self


// Implementation: impl MasterKeyInterface for for MockDb
// File: crates/router/src/db.rs
// Module: router
// Methods: 1 total (0 public)

impl MasterKeyInterface for for MockDb


// Struct: CustomerMetaData
// File: crates/hyperswitch_connectors/src/connectors/gocardless/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CustomerMetaData


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

pub fn perform_session_flow_routing<'a>(
    state: &'a SessionState,
    key_store: &'a domain::MerchantKeyStore,
    session_input: SessionFlowRoutingInput<'_>,
    business_profile: &domain::Profile,
    transaction_type: &api_enums::TransactionType,
) -> RoutingResult<FxHashMap<api_enums::PaymentMethodType, Vec<routing_types::SessionRoutingChoice>>>


// Implementation: impl Parse for for OperationsEnumMeta
// File: crates/router_derive/src/macros/operation.rs
// Module: router_derive
// Methods: 1 total (0 public)

impl Parse for for OperationsEnumMeta


// Function: check_service_type
// File: crates/router/src/services/authentication.rs
// Module: router

pub fn check_service_type(
        &self,
        required_service_type: &ExternalServiceType,
    ) -> RouterResult<()>


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

impl webhooks::IncomingWebhook for for Sift


// Struct: BillingConnectorPaymentsSyncFlowRouterData
// File: crates/router/src/core/webhooks/recovery_incoming.rs
// Module: router
// Implementations: 1

pub struct BillingConnectorPaymentsSyncFlowRouterData


// Function: get_sync_process_schedule_time
// File: crates/router/src/workflows/process_dispute.rs
// Module: router

pub fn get_sync_process_schedule_time(
    db: &dyn StorageInterface,
    connector: &str,
    merchant_id: &common_utils::id_type::MerchantId,
    retry_count: i32,
) -> Result<Option<time::PrimitiveDateTime>, errors::ProcessTrackerError>


// Function: create_authorization_header
// File: crates/hyperswitch_connectors/src/connectors/amazonpay.rs
// Module: hyperswitch_connectors

pub fn create_authorization_header(
        &self,
        auth: amazonpay::AmazonpayAuthType,
        canonical_uri: &str,
        http_method: &Method,
        hashed_payload: &str,
        header: &[(String, Maskable<String>)


// Struct: RedirectPaymentFlowResponse
// File: crates/router/src/types.rs
// Module: router
// Implementations: 0

pub struct RedirectPaymentFlowResponse<D>


// Struct: ApplePayMethodData
// File: crates/hyperswitch_connectors/src/connectors/mollie/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ApplePayMethodData


// Struct: FrictionlessFlowCount
// File: crates/api_models/src/analytics/auth_events.rs
// Module: api_models
// Implementations: 0

pub struct FrictionlessFlowCount


// Function: validate
// File: crates/drainer/src/settings.rs
// Module: drainer

pub fn validate(&self) -> Result<(), errors::DrainerError>


// Function: get_payout_status
// File: crates/hyperswitch_connectors/src/connectors/paypal/transformers.rs
// Module: hyperswitch_connectors

pub fn get_payout_status(status: PaypalFulfillStatus) -> storage_enums::PayoutStatus


// Trait: PaymentMethodsController
// File: crates/payment_methods/src/controller.rs
// Module: payment_methods

pub trait PaymentMethodsController


// Implementation: impl api::PaymentToken for for Multisafepay
// File: crates/hyperswitch_connectors/src/connectors/multisafepay.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentToken for for Multisafepay


// Function: to_str
// File: crates/common_utils/src/types/authentication.rs
// Module: common_utils

// Documentation: Get string representation of enclosed ID type

pub fn to_str(&self) -> &str


// Function: relay_flow_decider
// File: crates/router/src/core/relay.rs
// Module: router

pub fn relay_flow_decider(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id_optional: Option<id_type::ProfileId>,
    request: relay_api_models::RelayRequest,
) -> RouterResponse<relay_api_models::RelayResponse>


// Function: get_three_ds_keys
// File: crates/euclid_wasm/src/lib.rs
// Module: euclid_wasm

pub fn get_three_ds_keys() -> JsResult


// Struct: PaypalAuthUpdateRequest
// File: crates/hyperswitch_connectors/src/connectors/paypal/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PaypalAuthUpdateRequest


// Struct: BillingConnectorInvoiceSyncResponseData
// File: crates/router/src/core/webhooks/recovery_incoming.rs
// Module: router
// Implementations: 1

pub struct BillingConnectorInvoiceSyncResponseData


// Implementation: impl ConnectorCommon for for Netcetera
// File: crates/hyperswitch_connectors/src/connectors/netcetera.rs
// Module: hyperswitch_connectors
// Methods: 6 total (0 public)

impl ConnectorCommon for for Netcetera


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

pub mod transformers;

use std::sync::LazyLock;

use api_models::{enums, payments::PaymentIdType};
use common_utils::{
    crypto,
    errors::CustomResult,
    ext_traits::{ByteSliceExt, BytesExt},
    request::{Method, Request, RequestBuilder, RequestContent},
    types::{AmountConvertor, FloatMajorUnit, FloatMajorUnitForConnector},
};
use error_stack::ResultExt;
use hyperswitch_domain_models::{
    router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData},
    router_flow_types::{
        access_token_auth::AccessTokenAuth,
        payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void},
        refunds::{Execute, RSync},
    },
    router_request_types::{
        AccessTokenRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData,
        PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData,
        RefundsData, SetupMandateRequestData,
    },
    router_response_types::{
        ConnectorInfo, PaymentMethodDetails, PaymentsResponseData, RefundsResponseData,
        SupportedPaymentMethods, SupportedPaymentMethodsExt,
    },
    types::{
        PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsSyncRouterData,
        RefundSyncRouterData, RefundsRouterData,
    },
};
use hyperswitch_interfaces::{
    api::{
        self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorSpecifications,
        ConnectorValidation,
    },
    configs::Connectors,
    errors,
    events::connector_api_logs::ConnectorEvent,
    types::{self, Response},
    webhooks,
};
use masking::{ExposeInterface, Mask};
use transformers as checkbook;

use crate::{constants::headers, types::ResponseRouterData};

#[derive(Clone)]
pub struct Checkbook {
    amount_converter: &'static (dyn AmountConvertor<Output = FloatMajorUnit> + Sync),
}

impl Checkbook {
    pub fn new() -> &'static Self {
        &Self {
            amount_converter: &FloatMajorUnitForConnector,
        }
    }
}

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

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

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

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

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

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

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

    fn get_auth_header(
        &self,
        auth_type: &ConnectorAuthType,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        let auth = checkbook::CheckbookAuthType::try_from(auth_type)
            .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
        let auth_key = format!(
            "{}:{}",
            auth.publishable_key.expose(),
            auth.secret_key.expose()
        );
        Ok(vec![(
            headers::AUTHORIZATION.to_string(),
            auth_key.into_masked(),
        )])
    }

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

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

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response.code,
            message: response.message,
            reason: response.reason,
            attempt_status: None,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    }
}

impl ConnectorValidation for Checkbook {}

impl ConnectorIntegration<Session, PaymentsSessionData, PaymentsResponseData> for Checkbook {
    //TODO: implement sessions flow
}

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

impl ConnectorIntegration<SetupMandate, SetupMandateRequestData, PaymentsResponseData>
    for Checkbook
{
}

impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData> for Checkbook {
    fn get_headers(
        &self,
        req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!("{}/v3/invoice", self.base_url(connectors)))
    }

    fn get_request_body(
        &self,
        req: &PaymentsAuthorizeRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = self
            .amount_converter
            .convert(req.request.minor_amount, req.request.currency)
            .change_context(errors::ConnectorError::RequestEncodingFailed)?;
        let connector_req = checkbook::CheckbookPaymentsRequest::try_from((amount, req))?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

    fn handle_response(
        &self,
        data: &PaymentsAuthorizeRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsAuthorizeRouterData, errors::ConnectorError> {
        let response: checkbook::CheckbookPaymentsResponse = res
            .response
            .parse_struct("Checkbook PaymentsAuthorizeResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Checkbook {
    fn get_headers(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let connector_txn_id = req
            .request
            .connector_transaction_id
            .get_connector_transaction_id()
            .change_context(errors::ConnectorError::MissingConnectorTransactionID)?;
        Ok(format!(
            "{}/v3/invoice/{}",
            self.base_url(connectors),
            connector_txn_id
        ))
    }

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

    fn handle_response(
        &self,
        data: &PaymentsSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsSyncRouterData, errors::ConnectorError> {
        let response: checkbook::CheckbookPaymentsResponse = res
            .response
            .parse_struct("checkbook PaymentsSyncResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<Capture, PaymentsCaptureData, PaymentsResponseData> for Checkbook {}

impl ConnectorIntegration<Void, PaymentsCancelData, PaymentsResponseData> for Checkbook {
    fn get_headers(
        &self,
        req: &PaymentsCancelRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_url(
        &self,
        req: &PaymentsCancelRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!(
            "{}v3/invoice/{}",
            self.base_url(connectors),
            req.request.connector_transaction_id
        ))
    }

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

    fn handle_response(
        &self,
        data: &PaymentsCancelRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCancelRouterData, errors::ConnectorError> {
        let response: checkbook::CheckbookPaymentsResponse = res
            .response
            .parse_struct("Checkbook PaymentsCancelResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Checkbook {
    fn get_headers(
        &self,
        req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &RefundsRouterData<Execute>,
        _connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Err(errors::ConnectorError::NotSupported {
            message: "Refunds are not supported".to_string(),
            connector: "checkbook",
        }
        .into())
    }

    fn get_request_body(
        &self,
        _req: &RefundsRouterData<Execute>,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        Err(errors::ConnectorError::NotSupported {
            message: "Refunds are not supported".to_string(),
            connector: "checkbook",
        }
        .into())
    }

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

    fn handle_response(
        &self,
        _data: &RefundsRouterData<Execute>,
        _event_builder: Option<&mut ConnectorEvent>,
        _res: Response,
    ) -> CustomResult<RefundsRouterData<Execute>, errors::ConnectorError> {
        Err(errors::ConnectorError::NotImplemented("Refunds are not supported".to_string()).into())
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Checkbook {
    fn get_headers(
        &self,
        req: &RefundSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &RefundSyncRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
    }

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

    fn handle_response(
        &self,
        _data: &RefundSyncRouterData,
        _event_builder: Option<&mut ConnectorEvent>,
        _res: Response,
    ) -> CustomResult<RefundSyncRouterData, errors::ConnectorError> {
        Err(errors::ConnectorError::NotImplemented("Refunds are not supported".to_string()).into())
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

#[async_trait::async_trait]
impl webhooks::IncomingWebhook for Checkbook {
    fn get_webhook_object_reference_id(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
        let details: checkbook::CheckbookPaymentsResponse = request
            .body
            .parse_struct("CheckbookWebhookResponse")
            .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
        Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
            PaymentIdType::ConnectorTransactionId(details.id),
        ))
    }

    fn get_webhook_event_type(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::IncomingWebhookEvent, errors::ConnectorError> {
        let details: checkbook::CheckbookPaymentsResponse = request
            .body
            .parse_struct("CheckbookWebhookResponse")
            .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
        Ok(api_models::webhooks::IncomingWebhookEvent::from(
            details.status,
        ))
    }

    fn get_webhook_resource_object(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
        let details: checkbook::CheckbookPaymentsResponse = request
            .body
            .parse_struct("CheckbookWebhookResponse")
            .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
        Ok(Box::new(details))
    }

    fn get_webhook_source_verification_algorithm(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn crypto::VerifySignature + Send>, errors::ConnectorError> {
        Ok(Box::new(crypto::HmacSha256))
    }

    fn get_webhook_source_verification_signature(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
        _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        let header_value = request
            .headers
            .get("signature")
            .ok_or(errors::ConnectorError::WebhookSignatureNotFound)
            .attach_printable("Failed to get signature for checkbook")?
            .to_str()
            .map_err(|_| errors::ConnectorError::WebhookSignatureNotFound)
            .attach_printable("Failed to get signature for checkbook")?;
        let signature = header_value
            .split(',')
            .find_map(|s| s.strip_prefix("signature="))
            .ok_or(errors::ConnectorError::WebhookSignatureNotFound)?;
        hex::decode(signature)
            .change_context(errors::ConnectorError::WebhookSignatureNotFound)
            .attach_printable("Failed to decrypt checkbook webhook payload for verification")
    }

    fn get_webhook_source_verification_message(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
        _merchant_id: &common_utils::id_type::MerchantId,
        _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        let header_value = request
            .headers
            .get("signature")
            .ok_or(errors::ConnectorError::WebhookSignatureNotFound)?
            .to_str()
            .map_err(|_| errors::ConnectorError::WebhookSignatureNotFound)?;
        let nonce = header_value
            .split(',')
            .find_map(|s| s.strip_prefix("nonce="))
            .ok_or(errors::ConnectorError::WebhookSignatureNotFound)?;
        let message = format!("{}{}", String::from_utf8_lossy(request.body), nonce);
        Ok(message.into_bytes())
    }
}

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

        let mut checkbook_supported_payment_methods = SupportedPaymentMethods::new();

        checkbook_supported_payment_methods.add(
            enums::PaymentMethod::BankTransfer,
            enums::PaymentMethodType::Ach,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::NotSupported,
                supported_capture_methods,
                specific_features: None,
            },
        );
        checkbook_supported_payment_methods
    });

static CHECKBOOK_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
    display_name: "Checkbook",
    description:
        "Checkbook is a payment platform that allows users to send and receive digital checks.",
    connector_type: enums::HyperswitchConnectorCategory::PaymentGateway,
    integration_status: common_enums::ConnectorIntegrationStatus::Beta,
};

static CHECKBOOK_SUPPORTED_WEBHOOK_FLOWS: [enums::EventClass; 1] = [enums::EventClass::Payments];

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

    fn get_supported_payment_methods(&self) -> Option<&'static SupportedPaymentMethods> {
        Some(&*CHECKBOOK_SUPPORTED_PAYMENT_METHODS)
    }
    fn get_supported_webhook_flows(&self) -> Option<&'static [enums::EventClass]> {
        Some(&CHECKBOOK_SUPPORTED_WEBHOOK_FLOWS)
    }
}


// Function: get_merchant_reference_id
// File: crates/api_models/src/customers.rs
// Module: api_models

pub fn get_merchant_reference_id(&self) -> Option<id_type::CustomerId>


// Implementation: impl api::Payouts for for Nuvei
// File: crates/hyperswitch_connectors/src/connectors/nuvei.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::Payouts for for Nuvei


// Struct: NoonPaymentsActionRequest
// File: crates/hyperswitch_connectors/src/connectors/noon/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct NoonPaymentsActionRequest


// Struct: Payer
// File: crates/hyperswitch_connectors/src/connectors/santander/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct Payer


// Function: refund_manual_update
// File: crates/router/src/core/refunds.rs
// Module: router

pub fn refund_manual_update(
    state: SessionState,
    req: api_models::refunds::RefundManualUpdateRequest,
) -> RouterResponse<serde_json::Value>


// File: crates/hyperswitch_connectors/src/connectors/nomupay/transformers.rs
// Module: hyperswitch_connectors
// Public structs: 22

#[cfg(feature = "payouts")]
use common_enums::enums::PayoutEntityType;
use common_enums::{enums, Currency, PayoutStatus};
use common_utils::{pii::Email, types::FloatMajorUnit};
use hyperswitch_domain_models::router_data::ConnectorAuthType;
#[cfg(feature = "payouts")]
use hyperswitch_domain_models::{
    router_response_types::PayoutsResponseData, types::PayoutsRouterData,
};
use hyperswitch_interfaces::errors;
use masking::Secret;
use serde::{Deserialize, Serialize};

#[cfg(feature = "payouts")]
use crate::utils::PayoutFulfillRequestData;
#[cfg(feature = "payouts")]
use crate::{types::PayoutsResponseRouterData, utils::RouterData as UtilsRouterData};

pub const PURPOSE_OF_PAYMENT_IS_OTHER: &str = "OTHER";

pub struct NomupayRouterData<T> {
    pub amount: FloatMajorUnit, // The type of amount that a connector accepts, for example, String, i64, f64, etc.
    pub router_data: T,
}

impl<T> From<(FloatMajorUnit, T)> for NomupayRouterData<T> {
    fn from((amount, item): (FloatMajorUnit, T)) -> Self {
        //Todo :  use utils to convert the amount to the type of amount that a connector accepts
        Self {
            amount,
            router_data: item,
        }
    }
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Address {
    pub country: enums::CountryAlpha2,
    pub state_province: Secret<String>,
    pub street: Secret<String>,
    pub city: String,
    pub postal_code: Secret<String>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "UPPERCASE")]
pub enum ProfileType {
    #[default]
    Individual,
    Businness,
}

#[cfg(feature = "payouts")]
impl From<PayoutEntityType> for ProfileType {
    fn from(entity: PayoutEntityType) -> Self {
        match entity {
            PayoutEntityType::Personal
            | PayoutEntityType::NaturalPerson
            | PayoutEntityType::Individual => Self::Individual,
            _ => Self::Businness,
        }
    }
}

#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
pub enum NomupayGender {
    Male,
    Female,
    #[default]
    Other,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Profile {
    pub profile_type: ProfileType,
    pub first_name: Secret<String>,
    pub last_name: Secret<String>,
    pub date_of_birth: Secret<String>,
    pub gender: NomupayGender,
    pub email_address: Email,
    pub phone_number_country_code: Option<String>,
    pub phone_number: Option<Secret<String>>,
    pub address: Address,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct OnboardSubAccountRequest {
    pub account_id: Secret<String>,
    pub client_sub_account_id: Secret<String>,
    pub profile: Profile,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct BankAccount {
    pub bank_id: Option<Secret<String>>,
    pub account_id: Secret<String>,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct VirtualAccountsType {
    pub country_code: String,
    pub currency_code: String,
    pub bank_id: Secret<String>,
    pub bank_account_id: Secret<String>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum TransferMethodType {
    #[default]
    BankAccount,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct OnboardTransferMethodRequest {
    pub country_code: enums::CountryAlpha2,
    pub currency_code: Currency,
    #[serde(rename = "type")]
    pub transfer_method_type: TransferMethodType,
    pub display_name: Secret<String>,
    pub bank_account: BankAccount,
    pub profile: Profile,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct NomupayPaymentRequest {
    pub source_id: Secret<String>,
    pub destination_id: Secret<String>,
    pub payment_reference: String,
    pub amount: FloatMajorUnit,
    pub currency_code: Currency,
    pub purpose: String,
    pub description: Option<String>,
    pub internal_memo: Option<String>,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct QuoteRequest {
    pub source_id: Secret<String>,
    pub source_currency_code: Currency,
    pub destination_currency_code: Currency,
    pub amount: FloatMajorUnit,
    pub include_fee: String,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct CommitRequest {
    pub source_id: Secret<String>,
    pub id: String,
    pub destination_id: Secret<String>,
    pub payment_reference: String,
    pub amount: FloatMajorUnit,
    pub currency_code: Currency,
    pub purpose: String,
    pub description: String,
    pub internal_memo: String,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct OnboardSubAccountResponse {
    pub account_id: Secret<String>,
    pub id: String,
    pub client_sub_account_id: Secret<String>,
    pub profile: Profile,
    pub virtual_accounts: Vec<VirtualAccountsType>,
    pub status: String,
    pub created_on: String,
    pub last_updated: String,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct OnboardTransferMethodResponse {
    pub parent_id: Secret<String>,
    pub account_id: Secret<String>,
    pub sub_account_id: Secret<String>,
    pub id: String,
    pub status: String,
    pub created_on: String,
    pub last_updated: String,
    pub country_code: String,
    pub currency_code: Currency,
    pub display_name: String,
    #[serde(rename = "type")]
    pub transfer_method_type: String,
    pub profile: Profile,
    pub bank_account: BankAccount,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct NomupayPaymentResponse {
    pub id: String,
    pub status: NomupayPaymentStatus,
    pub created_on: String,
    pub last_updated: String,
    pub source_id: Secret<String>,
    pub destination_id: Secret<String>,
    pub payment_reference: String,
    pub amount: FloatMajorUnit,
    pub currency_code: String,
    pub purpose: String,
    pub description: String,
    pub internal_memo: String,
    pub release_on: String,
    pub expire_on: String,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct FeesType {
    #[serde(rename = "type")]
    pub fees_type: String,
    pub fees: FloatMajorUnit,
    pub currency_code: Currency,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct PayoutQuoteResponse {
    pub source_id: Secret<String>,
    pub destination_currency_code: Currency,
    pub amount: FloatMajorUnit,
    pub source_currency_code: Currency,
    pub include_fee: bool,
    pub fees: Vec<FeesType>,
    pub payment_reference: String,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct CommitResponse {
    pub id: String,
    pub status: String,
    pub created_on: String,
    pub last_updated: String,
    pub source_id: Secret<String>,
    pub destination_id: Secret<String>,
    pub payment_reference: String,
    pub amount: FloatMajorUnit,
    pub currency_code: Currency,
    pub purpose: String,
    pub description: String,
    pub internal_memo: String,
    pub release_on: String,
    pub expire_on: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct NomupayMetadata {
    pub private_key: Secret<String>,
}

#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ValidationError {
    pub field: String,
    pub message: String,
}

#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DetailsType {
    pub loc: Vec<String>,
    #[serde(rename = "type")]
    pub error_type: String,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct NomupayInnerError {
    pub error_code: String,
    pub error_description: Option<String>,
    pub validation_errors: Option<Vec<ValidationError>>,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct NomupayErrorResponse {
    pub status: Option<String>,
    pub code: Option<u64>,
    pub error: Option<NomupayInnerError>,
    pub status_code: Option<u16>,
    pub detail: Option<Vec<DetailsType>>,
}

pub struct NomupayAuthType {
    pub(super) kid: Secret<String>,
    #[cfg(feature = "payouts")]
    pub(super) eid: Secret<String>,
}

impl TryFrom<&ConnectorAuthType> for NomupayAuthType {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
        match auth_type {
            #[cfg(feature = "payouts")]
            ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self {
                kid: api_key.to_owned(),
                eid: key1.to_owned(),
            }),
            _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
        }
    }
}

#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "UPPERCASE")]
pub enum NomupayPaymentStatus {
    Pending,
    Processed,
    Failed,
    #[default]
    Processing,
    Scheduled,
    PendingAccountActivation,
    PendingTransferMethodCreation,
    PendingAccountKyc,
}

impl From<NomupayPaymentStatus> for PayoutStatus {
    fn from(item: NomupayPaymentStatus) -> Self {
        match item {
            NomupayPaymentStatus::Processed => Self::Success,
            NomupayPaymentStatus::Failed => Self::Failed,
            NomupayPaymentStatus::Processing
            | NomupayPaymentStatus::Pending
            | NomupayPaymentStatus::Scheduled
            | NomupayPaymentStatus::PendingAccountActivation
            | NomupayPaymentStatus::PendingTransferMethodCreation
            | NomupayPaymentStatus::PendingAccountKyc => Self::Pending,
        }
    }
}

#[cfg(feature = "payouts")]
fn get_profile<F>(
    item: &PayoutsRouterData<F>,
    entity_type: PayoutEntityType,
) -> Result<Profile, error_stack::Report<errors::ConnectorError>> {
    let my_address = Address {
        country: item.get_billing_country()?,
        state_province: item.get_billing_state()?,
        street: item.get_billing_line1()?,
        city: item.get_billing_city()?,
        postal_code: item.get_billing_zip()?,
    };

    Ok(Profile {
        profile_type: ProfileType::from(entity_type),
        first_name: item.get_billing_first_name()?,
        last_name: item.get_billing_last_name()?,
        date_of_birth: Secret::new("1991-01-01".to_string()), // Query raised with Nomupay regarding why this field is required
        gender: NomupayGender::Other, // Query raised with Nomupay regarding why this field is required
        email_address: item.get_billing_email()?,
        phone_number_country_code: item
            .get_billing_phone()
            .map(|phone| phone.country_code.clone())?,
        phone_number: Some(item.get_billing_phone_number()?),
        address: my_address,
    })
}

// PoRecipient Request
#[cfg(feature = "payouts")]
impl<F> TryFrom<&PayoutsRouterData<F>> for OnboardSubAccountRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &PayoutsRouterData<F>) -> Result<Self, Self::Error> {
        let request = item.request.to_owned();
        let payout_type = request.payout_type;

        let profile = get_profile(item, request.entity_type)?;

        let nomupay_auth_type = NomupayAuthType::try_from(&item.connector_auth_type)?;

        match payout_type {
            Some(common_enums::PayoutType::Bank) => Ok(Self {
                account_id: nomupay_auth_type.eid,
                client_sub_account_id: Secret::new(item.connector_request_reference_id.clone()),
                profile,
            }),
            _ => Err(errors::ConnectorError::NotImplemented(
                "This payment method is not implemented for Nomupay".to_string(),
            )
            .into()),
        }
    }
}

// PoRecipient Response
#[cfg(feature = "payouts")]
impl<F> TryFrom<PayoutsResponseRouterData<F, OnboardSubAccountResponse>> for PayoutsRouterData<F> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: PayoutsResponseRouterData<F, OnboardSubAccountResponse>,
    ) -> Result<Self, Self::Error> {
        let response: OnboardSubAccountResponse = item.response;

        Ok(Self {
            response: Ok(PayoutsResponseData {
                status: Some(PayoutStatus::RequiresVendorAccountCreation),
                connector_payout_id: Some(response.id.to_string()),
                payout_eligible: None,
                should_add_next_step_to_process_tracker: false,
                error_code: None,
                error_message: None,
            }),
            ..item.data
        })
    }
}

// PoRecipientAccount Request
#[cfg(feature = "payouts")]
impl<F> TryFrom<&PayoutsRouterData<F>> for OnboardTransferMethodRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &PayoutsRouterData<F>) -> Result<Self, Self::Error> {
        let payout_method_data = item.get_payout_method_data()?;
        match payout_method_data {
            api_models::payouts::PayoutMethodData::Bank(bank) => match bank {
                api_models::payouts::Bank::Sepa(bank_details) => {
                    let bank_account = BankAccount {
                        bank_id: bank_details.bic,
                        account_id: bank_details.iban,
                    };

                    let country_iso2_code = item
                        .get_billing_country()
                        .unwrap_or(enums::CountryAlpha2::CA);

                    let profile = get_profile(item, item.request.entity_type)?;

                    Ok(Self {
                        country_code: country_iso2_code,
                        currency_code: item.request.destination_currency,
                        transfer_method_type: TransferMethodType::BankAccount,
                        display_name: item.get_billing_full_name()?,
                        bank_account,
                        profile,
                    })
                }
                other_bank => Err(errors::ConnectorError::NotSupported {
                    message: format!("{other_bank:?} is not supported"),
                    connector: "nomupay",
                }
                .into()),
            },
            _ => Err(errors::ConnectorError::NotImplemented(
                "This payment method is not implemented for Nomupay".to_string(),
            )
            .into()),
        }
    }
}

// PoRecipientAccount response
#[cfg(feature = "payouts")]
impl<F> TryFrom<PayoutsResponseRouterData<F, OnboardTransferMethodResponse>>
    for PayoutsRouterData<F>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: PayoutsResponseRouterData<F, OnboardTransferMethodResponse>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(PayoutsResponseData {
                status: Some(PayoutStatus::RequiresCreation),
                connector_payout_id: Some(item.response.id),
                payout_eligible: None,
                should_add_next_step_to_process_tracker: false,
                error_code: None,
                error_message: None,
            }),
            ..item.data
        })
    }
}

// PoFulfill Request
#[cfg(feature = "payouts")]
impl<F> TryFrom<(&PayoutsRouterData<F>, FloatMajorUnit)> for NomupayPaymentRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        (item, amount): (&PayoutsRouterData<F>, FloatMajorUnit),
    ) -> Result<Self, Self::Error> {
        let nomupay_auth_type = NomupayAuthType::try_from(&item.connector_auth_type)?;
        let destination = item.request.clone().get_connector_transfer_method_id()?;

        Ok(Self {
            source_id: nomupay_auth_type.eid,
            destination_id: Secret::new(destination),
            payment_reference: item.connector_request_reference_id.clone(),
            amount,
            currency_code: item.request.destination_currency,
            purpose: PURPOSE_OF_PAYMENT_IS_OTHER.to_string(),
            description: item.description.clone(),
            internal_memo: item.description.clone(),
        })
    }
}

// PoFulfill response
#[cfg(feature = "payouts")]
impl<F> TryFrom<PayoutsResponseRouterData<F, NomupayPaymentResponse>> for PayoutsRouterData<F> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: PayoutsResponseRouterData<F, NomupayPaymentResponse>,
    ) -> Result<Self, Self::Error> {
        let response: NomupayPaymentResponse = item.response;

        Ok(Self {
            response: Ok(PayoutsResponseData {
                status: Some(PayoutStatus::from(response.status)),
                connector_payout_id: Some(response.id),
                payout_eligible: None,
                should_add_next_step_to_process_tracker: false,
                error_code: None,
                error_message: None,
            }),
            ..item.data
        })
    }
}


// Module Structure
// File: crates/common_enums/src/connector_enums.rs
// Module: common_enums

// Public exports:
pub use super::enums::{PaymentMethod, PayoutType};
pub use crate::PaymentMethodType;


// Function: get_profile_api_events
// File: crates/router/src/analytics.rs
// Module: router

pub fn get_profile_api_events(
        state: web::Data<AppState>,
        req: actix_web::HttpRequest,
        json_payload: web::Query<api_models::analytics::api_event::ApiLogsRequest>,
    ) -> impl Responder


// Implementation: impl api::PaymentAuthorize for for Prophetpay
// File: crates/hyperswitch_connectors/src/connectors/prophetpay.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentAuthorize for for Prophetpay


// Function: apply_changeset
// File: crates/diesel_models/src/merchant_account.rs
// Module: diesel_models

pub fn apply_changeset(self, source: MerchantAccount) -> MerchantAccount


// Function: is_db_unique_violation
// File: crates/storage_impl/src/errors.rs
// Module: storage_impl

pub fn is_db_unique_violation(&self) -> bool


// Function: decide_retry_failure_action
// File: crates/router/src/core/revenue_recovery/types.rs
// Module: router

pub fn decide_retry_failure_action(
        state: &SessionState,
        merchant_id: &id_type::MerchantId,
        pt: storage::ProcessTracker,
        revenue_recovery_payment_data: &storage::revenue_recovery::RevenueRecoveryPaymentData,
        payment_attempt: &PaymentAttempt,
        payment_intent: &PaymentIntent,
    ) -> RecoveryResult<Self>


// Function: get_card_vault_data
// File: crates/hyperswitch_domain_models/src/payments.rs
// Module: hyperswitch_domain_models

pub fn get_card_vault_data(&self) -> Option<payment_method_data::Card>


// Function: find_by_merchant_id
// File: crates/diesel_models/src/query/merchant_account.rs
// Module: diesel_models

pub fn find_by_merchant_id(
        conn: &PgPooledConn,
        identifier: &common_utils::id_type::MerchantId,
    ) -> StorageResult<Self>


// Struct: ItaubankDebtor
// File: crates/hyperswitch_connectors/src/connectors/itaubank/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ItaubankDebtor


// File: crates/common_enums/src/lib.rs
// Module: common_enums

pub mod connector_enums;
pub mod enums;
pub mod transformers;

pub use enums::*;
pub use transformers::*;


// Implementation: impl PaymentMethodsStorageInterface for for MockDb
// File: crates/payment_methods/src/state.rs
// Module: payment_methods
// Methods: 0 total (0 public)

impl PaymentMethodsStorageInterface for for MockDb


// Struct: SankeyRow
// File: crates/analytics/src/payment_intents/sankey.rs
// Module: analytics
// Implementations: 0

pub struct SankeyRow


// Struct: ArchipelWalletAuthorizationRequest
// File: crates/hyperswitch_connectors/src/connectors/archipel/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ArchipelWalletAuthorizationRequest


// Function: check_email_token_in_blacklist
// File: crates/router/src/services/authentication/blacklist.rs
// Module: router

pub fn check_email_token_in_blacklist(state: &SessionState, token: &str) -> UserResult<()>


// Implementation: impl GlobalTokenId
// File: crates/common_utils/src/id_type/global_id/token.rs
// Module: common_utils
// Methods: 3 total (3 public)

impl GlobalTokenId


// Implementation: impl api::ConnectorMandateRevoke for for Noon
// File: crates/hyperswitch_connectors/src/connectors/noon.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::ConnectorMandateRevoke for for Noon


// File: crates/hyperswitch_connectors/src/connectors/chargebee/transformers.rs
// Module: hyperswitch_connectors
// Public functions: 3
// Public structs: 44

#[cfg(all(feature = "revenue_recovery", feature = "v2"))]
use std::str::FromStr;

use common_enums::enums;
use common_utils::{
    errors::CustomResult,
    ext_traits::ByteSliceExt,
    id_type::{CustomerId, SubscriptionId},
    pii::{self, Email},
    types::MinorUnit,
};
use error_stack::ResultExt;
#[cfg(all(feature = "revenue_recovery", feature = "v2"))]
use hyperswitch_domain_models::revenue_recovery;
use hyperswitch_domain_models::{
    payment_method_data::PaymentMethodData,
    router_data::{ConnectorAuthType, RouterData},
    router_flow_types::{
        refunds::{Execute, RSync},
        subscriptions::SubscriptionCreate,
        CreateConnectorCustomer, InvoiceRecordBack,
    },
    router_request_types::{
        revenue_recovery::InvoiceRecordBackRequest,
        subscriptions::{SubscriptionAutoCollection, SubscriptionCreateRequest},
        ConnectorCustomerData, ResponseId,
    },
    router_response_types::{
        revenue_recovery::InvoiceRecordBackResponse,
        subscriptions::{
            self, GetSubscriptionEstimateResponse, GetSubscriptionPlanPricesResponse,
            GetSubscriptionPlansResponse, SubscriptionCreateResponse, SubscriptionLineItem,
            SubscriptionStatus,
        },
        ConnectorCustomerResponseData, PaymentsResponseData, RefundsResponseData,
    },
    types::{
        GetSubscriptionEstimateRouterData, InvoiceRecordBackRouterData,
        PaymentsAuthorizeRouterData, RefundsRouterData,
    },
};
use hyperswitch_interfaces::errors;
use masking::{ExposeInterface, Secret};
use serde::{Deserialize, Serialize};
use time::PrimitiveDateTime;

use crate::{
    types::{RefundsResponseRouterData, ResponseRouterData},
    utils::{self, PaymentsAuthorizeRequestData, RouterData as OtherRouterData},
};

// SubscriptionCreate structures
#[derive(Debug, Serialize)]
pub struct ChargebeeSubscriptionCreateRequest {
    #[serde(rename = "id")]
    pub subscription_id: SubscriptionId,
    #[serde(rename = "subscription_items[item_price_id][0]")]
    pub item_price_id: String,
    #[serde(rename = "subscription_items[quantity][0]")]
    pub quantity: Option<u32>,
    #[serde(rename = "billing_address[line1]")]
    pub billing_address_line1: Option<Secret<String>>,
    #[serde(rename = "billing_address[city]")]
    pub billing_address_city: Option<String>,
    #[serde(rename = "billing_address[state]")]
    pub billing_address_state: Option<Secret<String>>,
    #[serde(rename = "billing_address[zip]")]
    pub billing_address_zip: Option<Secret<String>>,
    #[serde(rename = "billing_address[country]")]
    pub billing_address_country: Option<common_enums::CountryAlpha2>,
    pub auto_collection: ChargebeeAutoCollection,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
#[serde(rename_all = "snake_case")]
pub enum ChargebeeAutoCollection {
    On,
    Off,
}

impl From<SubscriptionAutoCollection> for ChargebeeAutoCollection {
    fn from(auto_collection: SubscriptionAutoCollection) -> Self {
        match auto_collection {
            SubscriptionAutoCollection::On => Self::On,
            SubscriptionAutoCollection::Off => Self::Off,
        }
    }
}

impl TryFrom<&ChargebeeRouterData<&hyperswitch_domain_models::types::SubscriptionCreateRouterData>>
    for ChargebeeSubscriptionCreateRequest
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: &ChargebeeRouterData<&hyperswitch_domain_models::types::SubscriptionCreateRouterData>,
    ) -> Result<Self, Self::Error> {
        let req = &item.router_data.request;

        let first_item =
            req.subscription_items
                .first()
                .ok_or(errors::ConnectorError::MissingRequiredField {
                    field_name: "subscription_items",
                })?;

        Ok(Self {
            subscription_id: req.subscription_id.clone(),
            item_price_id: first_item.item_price_id.clone(),
            quantity: first_item.quantity,
            billing_address_line1: item.router_data.get_optional_billing_line1(),
            billing_address_city: item.router_data.get_optional_billing_city(),
            billing_address_state: item.router_data.get_optional_billing_state(),
            billing_address_zip: item.router_data.get_optional_billing_zip(),
            billing_address_country: item.router_data.get_optional_billing_country(),
            auto_collection: req.auto_collection.clone().into(),
        })
    }
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ChargebeeSubscriptionCreateResponse {
    pub subscription: ChargebeeSubscriptionDetails,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ChargebeeSubscriptionDetails {
    pub id: SubscriptionId,
    pub status: ChargebeeSubscriptionStatus,
    pub customer_id: CustomerId,
    pub currency_code: enums::Currency,
    pub total_dues: Option<MinorUnit>,
    #[serde(default, with = "common_utils::custom_serde::timestamp::option")]
    pub next_billing_at: Option<PrimitiveDateTime>,
    #[serde(default, with = "common_utils::custom_serde::timestamp::option")]
    pub created_at: Option<PrimitiveDateTime>,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
#[serde(rename_all = "snake_case")]
pub enum ChargebeeSubscriptionStatus {
    Future,
    #[serde(rename = "in_trial")]
    InTrial,
    Active,
    #[serde(rename = "non_renewing")]
    NonRenewing,
    Paused,
    Cancelled,
    Transferred,
}

impl From<ChargebeeSubscriptionStatus> for SubscriptionStatus {
    fn from(status: ChargebeeSubscriptionStatus) -> Self {
        match status {
            ChargebeeSubscriptionStatus::Future => Self::Pending,
            ChargebeeSubscriptionStatus::InTrial => Self::Trial,
            ChargebeeSubscriptionStatus::Active => Self::Active,
            ChargebeeSubscriptionStatus::NonRenewing => Self::Onetime,
            ChargebeeSubscriptionStatus::Paused => Self::Paused,
            ChargebeeSubscriptionStatus::Cancelled => Self::Cancelled,
            ChargebeeSubscriptionStatus::Transferred => Self::Cancelled,
        }
    }
}

impl
    TryFrom<
        ResponseRouterData<
            SubscriptionCreate,
            ChargebeeSubscriptionCreateResponse,
            SubscriptionCreateRequest,
            SubscriptionCreateResponse,
        >,
    > for hyperswitch_domain_models::types::SubscriptionCreateRouterData
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            SubscriptionCreate,
            ChargebeeSubscriptionCreateResponse,
            SubscriptionCreateRequest,
            SubscriptionCreateResponse,
        >,
    ) -> Result<Self, Self::Error> {
        let subscription = &item.response.subscription;
        Ok(Self {
            response: Ok(SubscriptionCreateResponse {
                subscription_id: subscription.id.clone(),
                status: subscription.status.clone().into(),
                customer_id: subscription.customer_id.clone(),
                currency_code: subscription.currency_code,
                total_amount: subscription.total_dues.unwrap_or(MinorUnit::new(0)),
                next_billing_at: subscription.next_billing_at,
                created_at: subscription.created_at,
            }),
            ..item.data
        })
    }
}

//TODO: Fill the struct with respective fields
pub struct ChargebeeRouterData<T> {
    pub amount: MinorUnit, // The type of amount that a connector accepts, for example, String, i64, f64, etc.
    pub router_data: T,
}

impl<T> From<(MinorUnit, T)> for ChargebeeRouterData<T> {
    fn from((amount, item): (MinorUnit, T)) -> Self {
        Self {
            amount,
            router_data: item,
        }
    }
}

//TODO: Fill the struct with respective fields
#[derive(Default, Debug, Serialize, PartialEq)]
pub struct ChargebeePaymentsRequest {
    amount: MinorUnit,
    card: ChargebeeCard,
}

#[derive(Default, Debug, Serialize, Eq, PartialEq)]
pub struct ChargebeeCard {
    number: cards::CardNumber,
    expiry_month: Secret<String>,
    expiry_year: Secret<String>,
    cvc: Secret<String>,
    complete: bool,
}

impl TryFrom<&ChargebeeRouterData<&PaymentsAuthorizeRouterData>> for ChargebeePaymentsRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: &ChargebeeRouterData<&PaymentsAuthorizeRouterData>,
    ) -> Result<Self, Self::Error> {
        match item.router_data.request.payment_method_data.clone() {
            PaymentMethodData::Card(req_card) => {
                let card = ChargebeeCard {
                    number: req_card.card_number,
                    expiry_month: req_card.card_exp_month,
                    expiry_year: req_card.card_exp_year,
                    cvc: req_card.card_cvc,
                    complete: item.router_data.request.is_auto_capture()?,
                };
                Ok(Self {
                    amount: item.amount,
                    card,
                })
            }
            _ => Err(errors::ConnectorError::NotImplemented("Payment method".to_string()).into()),
        }
    }
}

// Auth Struct
pub struct ChargebeeAuthType {
    pub(super) full_access_key_v1: Secret<String>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ChargebeeMetadata {
    pub(super) site: Secret<String>,
}

impl TryFrom<&Option<pii::SecretSerdeValue>> for ChargebeeMetadata {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(meta_data: &Option<pii::SecretSerdeValue>) -> Result<Self, Self::Error> {
        let metadata: Self = utils::to_connector_meta_from_secret::<Self>(meta_data.clone())
            .change_context(errors::ConnectorError::InvalidConnectorConfig {
                config: "metadata",
            })?;
        Ok(metadata)
    }
}

impl TryFrom<&ConnectorAuthType> for ChargebeeAuthType {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
        match auth_type {
            ConnectorAuthType::HeaderKey { api_key } => Ok(Self {
                full_access_key_v1: api_key.clone(),
            }),
            _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
        }
    }
}
// PaymentsResponse
//TODO: Append the remaining status flags
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum ChargebeePaymentStatus {
    Succeeded,
    Failed,
    #[default]
    Processing,
}

impl From<ChargebeePaymentStatus> for common_enums::AttemptStatus {
    fn from(item: ChargebeePaymentStatus) -> Self {
        match item {
            ChargebeePaymentStatus::Succeeded => Self::Charged,
            ChargebeePaymentStatus::Failed => Self::Failure,
            ChargebeePaymentStatus::Processing => Self::Authorizing,
        }
    }
}

//TODO: Fill the struct with respective fields
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ChargebeePaymentsResponse {
    status: ChargebeePaymentStatus,
    id: String,
}

impl<F, T> TryFrom<ResponseRouterData<F, ChargebeePaymentsResponse, T, PaymentsResponseData>>
    for RouterData<F, T, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<F, ChargebeePaymentsResponse, T, PaymentsResponseData>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            status: common_enums::AttemptStatus::from(item.response.status),
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(item.response.id),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: None,
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}

//TODO: Fill the struct with respective fields
// REFUND :
// Type definition for RefundRequest
#[derive(Default, Debug, Serialize)]
pub struct ChargebeeRefundRequest {
    pub amount: MinorUnit,
}

impl<F> TryFrom<&ChargebeeRouterData<&RefundsRouterData<F>>> for ChargebeeRefundRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &ChargebeeRouterData<&RefundsRouterData<F>>) -> Result<Self, Self::Error> {
        Ok(Self {
            amount: item.amount.to_owned(),
        })
    }
}

// Type definition for Refund Response

#[allow(dead_code)]
#[derive(Debug, Serialize, Default, Deserialize, Clone)]
pub enum RefundStatus {
    Succeeded,
    Failed,
    #[default]
    Processing,
}

impl From<RefundStatus> for enums::RefundStatus {
    fn from(item: RefundStatus) -> Self {
        match item {
            RefundStatus::Succeeded => Self::Success,
            RefundStatus::Failed => Self::Failure,
            RefundStatus::Processing => Self::Pending,
            //TODO: Review mapping
        }
    }
}

//TODO: Fill the struct with respective fields
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct RefundResponse {
    id: String,
    status: RefundStatus,
}

impl TryFrom<RefundsResponseRouterData<Execute, RefundResponse>> for RefundsRouterData<Execute> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<Execute, RefundResponse>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(RefundsResponseData {
                connector_refund_id: item.response.id.to_string(),
                refund_status: enums::RefundStatus::from(item.response.status),
            }),
            ..item.data
        })
    }
}

impl TryFrom<RefundsResponseRouterData<RSync, RefundResponse>> for RefundsRouterData<RSync> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<RSync, RefundResponse>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(RefundsResponseData {
                connector_refund_id: item.response.id.to_string(),
                refund_status: enums::RefundStatus::from(item.response.status),
            }),
            ..item.data
        })
    }
}

#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
pub struct ChargebeeErrorResponse {
    pub api_error_code: String,
    pub message: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct ChargebeeWebhookBody {
    pub content: ChargebeeWebhookContent,
    pub event_type: ChargebeeEventType,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct ChargebeeInvoiceBody {
    pub content: ChargebeeInvoiceContent,
    pub event_type: ChargebeeEventType,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct ChargebeeInvoiceContent {
    pub invoice: ChargebeeInvoiceData,
    pub subscription: Option<ChargebeeSubscriptionData>,
}

#[derive(Serialize, Deserialize, Debug)]

pub struct ChargebeeWebhookContent {
    pub transaction: ChargebeeTransactionData,
    pub invoice: ChargebeeInvoiceData,
    pub customer: Option<ChargebeeCustomer>,
    pub subscription: Option<ChargebeeSubscriptionData>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct ChargebeeSubscriptionData {
    #[serde(default, with = "common_utils::custom_serde::timestamp::option")]
    pub current_term_start: Option<PrimitiveDateTime>,
    #[serde(default, with = "common_utils::custom_serde::timestamp::option")]
    pub next_billing_at: Option<PrimitiveDateTime>,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum ChargebeeEventType {
    PaymentSucceeded,
    PaymentFailed,
    InvoiceDeleted,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct ChargebeeInvoiceData {
    // invoice id
    pub id: String,
    pub total: MinorUnit,
    pub currency_code: enums::Currency,
    pub billing_address: Option<ChargebeeInvoiceBillingAddress>,
    pub linked_payments: Option<Vec<ChargebeeInvoicePayments>>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct ChargebeeInvoicePayments {
    pub txn_status: Option<String>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct ChargebeeTransactionData {
    id_at_gateway: Option<String>,
    status: ChargebeeTranasactionStatus,
    error_code: Option<String>,
    error_text: Option<String>,
    gateway_account_id: String,
    currency_code: enums::Currency,
    amount: MinorUnit,
    #[serde(default, with = "common_utils::custom_serde::timestamp::option")]
    date: Option<PrimitiveDateTime>,
    payment_method: ChargebeeTransactionPaymentMethod,
    payment_method_details: String,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum ChargebeeTransactionPaymentMethod {
    Card,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct ChargebeePaymentMethodDetails {
    card: ChargebeeCardDetails,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct ChargebeeCardDetails {
    funding_type: ChargebeeFundingType,
    brand: common_enums::CardNetwork,
    iin: String,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum ChargebeeFundingType {
    Credit,
    Debit,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum ChargebeeTranasactionStatus {
    // Waiting for response from the payment gateway.
    InProgress,
    // The transaction is successful.
    Success,
    // Transaction failed.
    Failure,
    // No response received while trying to charge the card.
    Timeout,
    // Indicates that a successful payment transaction has failed now due to a late failure notification from the payment gateway,
    // typically caused by issues like insufficient funds or a closed bank account.
    LateFailure,
    // Connection with Gateway got terminated abruptly. So, status of this transaction needs to be resolved manually
    NeedsAttention,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct ChargebeeCustomer {
    pub payment_method: ChargebeePaymentMethod,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct ChargebeeInvoiceBillingAddress {
    pub line1: Option<Secret<String>>,
    pub line2: Option<Secret<String>>,
    pub line3: Option<Secret<String>>,
    pub state: Option<Secret<String>>,
    pub country: Option<enums::CountryAlpha2>,
    pub zip: Option<Secret<String>>,
    pub city: Option<String>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct ChargebeePaymentMethod {
    pub reference_id: String,
    pub gateway: ChargebeeGateway,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum ChargebeeGateway {
    Stripe,
    Braintree,
}

impl ChargebeeWebhookBody {
    pub fn get_webhook_object_from_body(body: &[u8]) -> CustomResult<Self, errors::ConnectorError> {
        let webhook_body = body
            .parse_struct::<Self>("ChargebeeWebhookBody")
            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
        Ok(webhook_body)
    }
}

impl ChargebeeInvoiceBody {
    pub fn get_invoice_webhook_data_from_body(
        body: &[u8],
    ) -> CustomResult<Self, errors::ConnectorError> {
        let webhook_body = body
            .parse_struct::<Self>("ChargebeeInvoiceBody")
            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
        Ok(webhook_body)
    }
}

pub struct ChargebeeMandateDetails {
    pub customer_id: String,
    pub mandate_id: String,
}

impl ChargebeeCustomer {
    // the logic to find connector customer id & mandate id is different for different gateways, reference : https://apidocs.chargebee.com/docs/api/customers?prod_cat_ver=2#customer_payment_method_reference_id .
    pub fn find_connector_ids(&self) -> Result<ChargebeeMandateDetails, errors::ConnectorError> {
        match self.payment_method.gateway {
            ChargebeeGateway::Stripe | ChargebeeGateway::Braintree => {
                let mut parts = self.payment_method.reference_id.split('/');
                let customer_id = parts
                    .next()
                    .ok_or(errors::ConnectorError::WebhookBodyDecodingFailed)?
                    .to_string();
                let mandate_id = parts
                    .next_back()
                    .ok_or(errors::ConnectorError::WebhookBodyDecodingFailed)?
                    .to_string();
                Ok(ChargebeeMandateDetails {
                    customer_id,
                    mandate_id,
                })
            }
        }
    }
}

#[cfg(all(feature = "revenue_recovery", feature = "v2"))]
impl TryFrom<ChargebeeWebhookBody> for revenue_recovery::RevenueRecoveryAttemptData {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: ChargebeeWebhookBody) -> Result<Self, Self::Error> {
        let amount = item.content.transaction.amount;
        let currency = item.content.transaction.currency_code.to_owned();
        let merchant_reference_id =
            common_utils::id_type::PaymentReferenceId::from_str(&item.content.invoice.id)
                .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
        let connector_transaction_id = item
            .content
            .transaction
            .id_at_gateway
            .map(common_utils::types::ConnectorTransactionId::TxnId);
        let error_code = item.content.transaction.error_code.clone();
        let error_message = item.content.transaction.error_text.clone();
        let connector_mandate_details = item
            .content
            .customer
            .as_ref()
            .map(|customer| customer.find_connector_ids())
            .transpose()?
            .ok_or(errors::ConnectorError::MissingRequiredField {
                field_name: "connector_mandate_details",
            })?;
        let connector_account_reference_id = item.content.transaction.gateway_account_id.clone();
        let transaction_created_at = item.content.transaction.date;
        let status = enums::AttemptStatus::from(item.content.transaction.status);
        let payment_method_type =
            enums::PaymentMethod::from(item.content.transaction.payment_method);
        let payment_method_details: ChargebeePaymentMethodDetails =
            serde_json::from_str(&item.content.transaction.payment_method_details)
                .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
        let payment_method_sub_type =
            enums::PaymentMethodType::from(payment_method_details.card.funding_type);
        // Chargebee retry count will always be less than u16 always. Chargebee can have maximum 12 retry attempts
        #[allow(clippy::as_conversions)]
        let retry_count = item
            .content
            .invoice
            .linked_payments
            .map(|linked_payments| linked_payments.len() as u16);
        let invoice_next_billing_time = item
            .content
            .subscription
            .as_ref()
            .and_then(|subscription| subscription.next_billing_at);
        let invoice_billing_started_at_time = item
            .content
            .subscription
            .as_ref()
            .and_then(|subscription| subscription.current_term_start);
        Ok(Self {
            amount,
            currency,
            merchant_reference_id,
            connector_transaction_id,
            error_code,
            error_message,
            processor_payment_method_token: connector_mandate_details.mandate_id,
            connector_customer_id: connector_mandate_details.customer_id,
            connector_account_reference_id,
            transaction_created_at,
            status,
            payment_method_type,
            payment_method_sub_type,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            retry_count,
            invoice_next_billing_time,
            invoice_billing_started_at_time,
            // This field is none because it is specific to stripebilling.
            charge_id: None,
            // Need to populate these card info field
            card_info: api_models::payments::AdditionalCardInfo {
                card_network: Some(payment_method_details.card.brand),
                card_isin: Some(payment_method_details.card.iin),
                card_issuer: None,
                card_type: None,
                card_issuing_country: None,
                bank_code: None,
                last4: None,
                card_extended_bin: None,
                card_exp_month: None,
                card_exp_year: None,
                card_holder_name: None,
                payment_checks: None,
                authentication_data: None,
                is_regulated: None,
                signature_network: None,
            },
        })
    }
}

impl From<ChargebeeTranasactionStatus> for enums::AttemptStatus {
    fn from(status: ChargebeeTranasactionStatus) -> Self {
        match status {
            ChargebeeTranasactionStatus::InProgress
            | ChargebeeTranasactionStatus::NeedsAttention => Self::Pending,
            ChargebeeTranasactionStatus::Success => Self::Charged,
            ChargebeeTranasactionStatus::Failure
            | ChargebeeTranasactionStatus::Timeout
            | ChargebeeTranasactionStatus::LateFailure => Self::Failure,
        }
    }
}

impl From<ChargebeeTransactionPaymentMethod> for enums::PaymentMethod {
    fn from(payment_method: ChargebeeTransactionPaymentMethod) -> Self {
        match payment_method {
            ChargebeeTransactionPaymentMethod::Card => Self::Card,
        }
    }
}

impl From<ChargebeeFundingType> for enums::PaymentMethodType {
    fn from(funding_type: ChargebeeFundingType) -> Self {
        match funding_type {
            ChargebeeFundingType::Credit => Self::Credit,
            ChargebeeFundingType::Debit => Self::Debit,
        }
    }
}
#[cfg(all(feature = "revenue_recovery", feature = "v2"))]
impl From<ChargebeeEventType> for api_models::webhooks::IncomingWebhookEvent {
    fn from(event: ChargebeeEventType) -> Self {
        match event {
            ChargebeeEventType::PaymentSucceeded => Self::RecoveryPaymentSuccess,
            ChargebeeEventType::PaymentFailed => Self::RecoveryPaymentFailure,
            ChargebeeEventType::InvoiceDeleted => Self::RecoveryInvoiceCancel,
        }
    }
}

#[cfg(all(feature = "revenue_recovery", feature = "v2"))]
impl TryFrom<ChargebeeInvoiceBody> for revenue_recovery::RevenueRecoveryInvoiceData {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: ChargebeeInvoiceBody) -> Result<Self, Self::Error> {
        let merchant_reference_id =
            common_utils::id_type::PaymentReferenceId::from_str(&item.content.invoice.id)
                .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;

        // The retry count will never exceed u16 limit in a billing connector. It can have maximum of 12 in case of charge bee so its ok to suppress this
        #[allow(clippy::as_conversions)]
        let retry_count = item
            .content
            .invoice
            .linked_payments
            .as_ref()
            .map(|linked_payments| linked_payments.len() as u16);
        let invoice_next_billing_time = item
            .content
            .subscription
            .as_ref()
            .and_then(|subscription| subscription.next_billing_at);
        let billing_started_at = item
            .content
            .subscription
            .as_ref()
            .and_then(|subscription| subscription.current_term_start);
        Ok(Self {
            amount: item.content.invoice.total,
            currency: item.content.invoice.currency_code,
            merchant_reference_id,
            billing_address: Some(api_models::payments::Address::from(item.content.invoice)),
            retry_count,
            next_billing_at: invoice_next_billing_time,
            billing_started_at,
            metadata: None,
            // TODO! This field should be handled for billing connnector integrations
            enable_partial_authorization: None,
        })
    }
}

#[cfg(all(feature = "revenue_recovery", feature = "v2"))]
impl From<ChargebeeInvoiceData> for api_models::payments::Address {
    fn from(item: ChargebeeInvoiceData) -> Self {
        Self {
            address: item
                .billing_address
                .map(api_models::payments::AddressDetails::from),
            phone: None,
            email: None,
        }
    }
}

#[cfg(all(feature = "revenue_recovery", feature = "v2"))]
impl From<ChargebeeInvoiceBillingAddress> for api_models::payments::AddressDetails {
    fn from(item: ChargebeeInvoiceBillingAddress) -> Self {
        Self {
            city: item.city,
            country: item.country,
            state: item.state,
            zip: item.zip,
            line1: item.line1,
            line2: item.line2,
            line3: item.line3,
            first_name: None,
            last_name: None,
            origin_zip: None,
        }
    }
}

#[derive(Debug, Serialize)]
pub struct ChargebeeRecordPaymentRequest {
    #[serde(rename = "transaction[amount]")]
    pub amount: MinorUnit,
    #[serde(rename = "transaction[payment_method]")]
    pub payment_method: ChargebeeRecordPaymentMethod,
    #[serde(rename = "transaction[id_at_gateway]")]
    pub connector_payment_id: Option<String>,
    #[serde(rename = "transaction[status]")]
    pub status: ChargebeeRecordStatus,
}

#[derive(Debug, Serialize, Clone, Copy)]
#[serde(rename_all = "snake_case")]
pub enum ChargebeeRecordPaymentMethod {
    Other,
}

#[derive(Debug, Serialize, Clone, Copy)]
#[serde(rename_all = "snake_case")]
pub enum ChargebeeRecordStatus {
    Success,
    Failure,
}

impl TryFrom<&ChargebeeRouterData<&InvoiceRecordBackRouterData>> for ChargebeeRecordPaymentRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: &ChargebeeRouterData<&InvoiceRecordBackRouterData>,
    ) -> Result<Self, Self::Error> {
        let req = &item.router_data.request;
        Ok(Self {
            amount: req.amount,
            payment_method: ChargebeeRecordPaymentMethod::Other,
            connector_payment_id: req
                .connector_transaction_id
                .as_ref()
                .map(|connector_payment_id| connector_payment_id.get_id().to_string()),
            status: ChargebeeRecordStatus::try_from(req.attempt_status)?,
        })
    }
}

impl TryFrom<enums::AttemptStatus> for ChargebeeRecordStatus {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(status: enums::AttemptStatus) -> Result<Self, Self::Error> {
        match status {
            enums::AttemptStatus::Charged
            | enums::AttemptStatus::PartialCharged
            | enums::AttemptStatus::PartialChargedAndChargeable => Ok(Self::Success),
            enums::AttemptStatus::Failure
            | enums::AttemptStatus::CaptureFailed
            | enums::AttemptStatus::RouterDeclined => Ok(Self::Failure),
            enums::AttemptStatus::AuthenticationFailed
            | enums::AttemptStatus::Started
            | enums::AttemptStatus::AuthenticationPending
            | enums::AttemptStatus::AuthenticationSuccessful
            | enums::AttemptStatus::Authorized
            | enums::AttemptStatus::PartiallyAuthorized
            | enums::AttemptStatus::AuthorizationFailed
            | enums::AttemptStatus::Authorizing
            | enums::AttemptStatus::CodInitiated
            | enums::AttemptStatus::Voided
            | enums::AttemptStatus::VoidedPostCharge
            | enums::AttemptStatus::VoidInitiated
            | enums::AttemptStatus::CaptureInitiated
            | enums::AttemptStatus::VoidFailed
            | enums::AttemptStatus::AutoRefunded
            | enums::AttemptStatus::Unresolved
            | enums::AttemptStatus::Pending
            | enums::AttemptStatus::PaymentMethodAwaited
            | enums::AttemptStatus::ConfirmationAwaited
            | enums::AttemptStatus::DeviceDataCollectionPending
            | enums::AttemptStatus::IntegrityFailure
            | enums::AttemptStatus::Expired => Err(errors::ConnectorError::NotSupported {
                message: "Record back flow is only supported for terminal status".to_string(),
                connector: "chargebee",
            }
            .into()),
        }
    }
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ChargebeeRecordbackResponse {
    pub invoice: ChargebeeRecordbackInvoice,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ChargebeeRecordbackInvoice {
    pub id: common_utils::id_type::PaymentReferenceId,
}

impl
    TryFrom<
        ResponseRouterData<
            InvoiceRecordBack,
            ChargebeeRecordbackResponse,
            InvoiceRecordBackRequest,
            InvoiceRecordBackResponse,
        >,
    > for InvoiceRecordBackRouterData
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            InvoiceRecordBack,
            ChargebeeRecordbackResponse,
            InvoiceRecordBackRequest,
            InvoiceRecordBackResponse,
        >,
    ) -> Result<Self, Self::Error> {
        let merchant_reference_id = item.response.invoice.id;
        Ok(Self {
            response: Ok(InvoiceRecordBackResponse {
                merchant_reference_id,
            }),
            ..item.data
        })
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChargebeeListPlansResponse {
    pub list: Vec<ChargebeeItemList>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChargebeeItemList {
    pub item: ChargebeeItem,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChargebeeItem {
    pub id: String,
    pub name: String,
    #[serde(rename = "type")]
    pub plan_type: String,
    pub is_giftable: bool,
    pub enabled_for_checkout: bool,
    pub enabled_in_portal: bool,
    pub metered: bool,
    pub deleted: bool,
    pub description: Option<String>,
}

impl<F, T>
    TryFrom<ResponseRouterData<F, SubscriptionEstimateResponse, T, GetSubscriptionEstimateResponse>>
    for RouterData<F, T, GetSubscriptionEstimateResponse>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            F,
            SubscriptionEstimateResponse,
            T,
            GetSubscriptionEstimateResponse,
        >,
    ) -> Result<Self, Self::Error> {
        let estimate = item.response.estimate;
        Ok(Self {
            response: Ok(GetSubscriptionEstimateResponse {
                sub_total: estimate.invoice_estimate.sub_total,
                total: estimate.invoice_estimate.total,
                amount_paid: Some(estimate.invoice_estimate.amount_paid),
                amount_due: Some(estimate.invoice_estimate.amount_due),
                currency: estimate.subscription_estimate.currency_code,
                next_billing_at: estimate.subscription_estimate.next_billing_at,
                credits_applied: Some(estimate.invoice_estimate.credits_applied),
                line_items: estimate
                    .invoice_estimate
                    .line_items
                    .into_iter()
                    .map(|line_item| SubscriptionLineItem {
                        item_id: line_item.entity_id,
                        item_type: line_item.entity_type,
                        description: line_item.description,
                        amount: line_item.amount,
                        currency: estimate.invoice_estimate.currency_code,
                        unit_amount: Some(line_item.unit_amount),
                        quantity: line_item.quantity,
                        pricing_model: Some(line_item.pricing_model),
                    })
                    .collect(),
            }),
            ..item.data
        })
    }
}

impl<F, T>
    TryFrom<ResponseRouterData<F, ChargebeeListPlansResponse, T, GetSubscriptionPlansResponse>>
    for RouterData<F, T, GetSubscriptionPlansResponse>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<F, ChargebeeListPlansResponse, T, GetSubscriptionPlansResponse>,
    ) -> Result<Self, Self::Error> {
        let plans = item
            .response
            .list
            .into_iter()
            .map(|plan| subscriptions::SubscriptionPlans {
                subscription_provider_plan_id: plan.item.id,
                name: plan.item.name,
                description: plan.item.description,
            })
            .collect();
        Ok(Self {
            response: Ok(GetSubscriptionPlansResponse { list: plans }),
            ..item.data
        })
    }
}

#[derive(Debug, Serialize)]
pub struct ChargebeeCustomerCreateRequest {
    #[serde(rename = "id")]
    pub customer_id: CustomerId,
    #[serde(rename = "first_name")]
    pub name: Option<Secret<String>>,
    pub email: Option<Email>,
    #[serde(rename = "billing_address[first_name]")]
    pub billing_address_first_name: Option<Secret<String>>,
    #[serde(rename = "billing_address[last_name]")]
    pub billing_address_last_name: Option<Secret<String>>,
    #[serde(rename = "billing_address[line1]")]
    pub billing_address_line1: Option<Secret<String>>,
    #[serde(rename = "billing_address[city]")]
    pub billing_address_city: Option<String>,
    #[serde(rename = "billing_address[state]")]
    pub billing_address_state: Option<Secret<String>>,
    #[serde(rename = "billing_address[zip]")]
    pub billing_address_zip: Option<Secret<String>>,
    #[serde(rename = "billing_address[country]")]
    pub billing_address_country: Option<String>,
}

impl TryFrom<&ChargebeeRouterData<&hyperswitch_domain_models::types::ConnectorCustomerRouterData>>
    for ChargebeeCustomerCreateRequest
{
    type Error = error_stack::Report<errors::ConnectorError>;

    fn try_from(
        item: &ChargebeeRouterData<&hyperswitch_domain_models::types::ConnectorCustomerRouterData>,
    ) -> Result<Self, Self::Error> {
        let req = &item.router_data.request;

        Ok(Self {
            customer_id: req
                .customer_id
                .as_ref()
                .ok_or_else(|| errors::ConnectorError::MissingRequiredField {
                    field_name: "customer_id",
                })?
                .clone(),
            name: req.name.clone(),
            email: req.email.clone(),
            billing_address_first_name: req
                .billing_address


// Struct: CoingateErrorResponse
// File: crates/hyperswitch_connectors/src/connectors/coingate/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CoingateErrorResponse


// Implementation: impl ConnectorSpecifications for for Trustpayments
// File: crates/hyperswitch_connectors/src/connectors/trustpayments.rs
// Module: hyperswitch_connectors
// Methods: 3 total (0 public)

impl ConnectorSpecifications for for Trustpayments