                error_reason: None,
                capture_method: None,
                connector_response_reference_id: None,
                multiple_capture_count: None,
                surcharge_amount: None,
                tax_amount: None,
                amount_capturable: None,
                merchant_connector_id: None,
                authentication_data: None,
                encoded_data: None,
                unified_code: None,
                unified_message: None,
                external_three_ds_authentication_attempted: None,
                authentication_connector: None,
                authentication_id: None,
                fingerprint_id: None,
                payment_method_billing_address_id: None,
                client_source: None,
                client_version: None,
                customer_acceptance: None,
                card_network: None,
                shipping_cost: None,
                order_tax_amount: None,
                capture_before: None,
                extended_authorization_applied: None,
                processor_transaction_data: None,
                connector_mandate_detail: None,
                card_discovery: None,
                charges: None,
                issuer_error_code: None,
                issuer_error_message: None,
                setup_future_usage_applied: None,
                routing_approach: None,
                connector_request_reference_id: None,
                network_transaction_id: None,
            },
            PaymentAttemptUpdate::BlocklistUpdate {
                status,
                error_code,
                error_message,
                updated_by,
            } => Self {
                status: Some(status),
                modified_at: common_utils::date_time::now(),
                error_code,
                connector: Some(None),
                error_message,
                updated_by,
                merchant_connector_id: Some(None),
                amount: None,
                net_amount: None,
                currency: None,
                connector_transaction_id: None,
                amount_to_capture: None,
                authentication_type: None,
                payment_method: None,
                payment_method_id: None,
                cancellation_reason: None,
                mandate_id: None,
                browser_info: None,
                payment_token: None,
                connector_metadata: None,
                payment_method_data: None,
                payment_method_type: None,
                payment_experience: None,
                business_sub_label: None,
                straight_through_algorithm: None,
                preprocessing_step_id: None,
                error_reason: None,
                capture_method: None,
                connector_response_reference_id: None,
                multiple_capture_count: None,
                surcharge_amount: None,
                tax_amount: None,
                amount_capturable: None,
                authentication_data: None,
                encoded_data: None,
                unified_code: None,
                unified_message: None,
                external_three_ds_authentication_attempted: None,
                authentication_connector: None,
                authentication_id: None,
                fingerprint_id: None,
                payment_method_billing_address_id: None,
                client_source: None,
                client_version: None,
                customer_acceptance: None,
                card_network: None,
                shipping_cost: None,
                order_tax_amount: None,
                capture_before: None,
                extended_authorization_applied: None,
                processor_transaction_data: None,
                connector_mandate_detail: None,
                card_discovery: None,
                charges: None,
                issuer_error_code: None,
                issuer_error_message: None,
                setup_future_usage_applied: None,
                routing_approach: None,
                connector_request_reference_id: None,
                network_transaction_id: None,
            },
            PaymentAttemptUpdate::ConnectorMandateDetailUpdate {
                connector_mandate_detail,
                updated_by,
            } => Self {
                payment_method_id: None,
                modified_at: common_utils::date_time::now(),
                updated_by,
                amount: None,
                net_amount: None,
                currency: None,
                status: None,
                connector_transaction_id: None,
                amount_to_capture: None,
                connector: None,
                authentication_type: None,
                payment_method: None,
                error_message: None,
                cancellation_reason: None,
                mandate_id: None,
                browser_info: None,
                payment_token: None,
                error_code: None,
                connector_metadata: None,
                payment_method_data: None,
                payment_method_type: None,
                payment_experience: None,
                business_sub_label: None,
                straight_through_algorithm: None,
                preprocessing_step_id: None,
                error_reason: None,
                capture_method: None,
                connector_response_reference_id: None,
                multiple_capture_count: None,
                surcharge_amount: None,
                tax_amount: None,
                amount_capturable: None,
                merchant_connector_id: None,
                authentication_data: None,
                encoded_data: None,
                unified_code: None,
                unified_message: None,
                external_three_ds_authentication_attempted: None,
                authentication_connector: None,
                authentication_id: None,
                fingerprint_id: None,
                payment_method_billing_address_id: None,
                client_source: None,
                client_version: None,
                customer_acceptance: None,
                card_network: None,
                shipping_cost: None,
                order_tax_amount: None,
                capture_before: None,
                extended_authorization_applied: None,
                processor_transaction_data: None,
                connector_mandate_detail,
                card_discovery: None,
                charges: None,
                issuer_error_code: None,
                issuer_error_message: None,
                setup_future_usage_applied: None,
                routing_approach: None,
                connector_request_reference_id: None,
                network_transaction_id: None,
            },
            PaymentAttemptUpdate::PaymentMethodDetailsUpdate {
                payment_method_id,
                updated_by,
            } => Self {
                payment_method_id,
                modified_at: common_utils::date_time::now(),
                updated_by,
                amount: None,
                net_amount: None,
                currency: None,
                status: None,
                connector_transaction_id: None,
                amount_to_capture: None,
                connector: None,
                authentication_type: None,
                payment_method: None,
                error_message: None,
                cancellation_reason: None,
                mandate_id: None,
                browser_info: None,
                payment_token: None,
                error_code: None,
                connector_metadata: None,
                payment_method_data: None,
                payment_method_type: None,
                payment_experience: None,
                business_sub_label: None,
                straight_through_algorithm: None,
                preprocessing_step_id: None,
                error_reason: None,
                capture_method: None,
                connector_response_reference_id: None,
                multiple_capture_count: None,
                surcharge_amount: None,
                tax_amount: None,
                amount_capturable: None,
                merchant_connector_id: None,
                authentication_data: None,
                encoded_data: None,
                unified_code: None,
                unified_message: None,
                external_three_ds_authentication_attempted: None,
                authentication_connector: None,
                authentication_id: None,
                fingerprint_id: None,
                payment_method_billing_address_id: None,
                client_source: None,
                client_version: None,
                customer_acceptance: None,
                card_network: None,
                shipping_cost: None,
                order_tax_amount: None,
                capture_before: None,
                extended_authorization_applied: None,
                processor_transaction_data: None,
                connector_mandate_detail: None,
                card_discovery: None,
                charges: None,
                issuer_error_code: None,
                issuer_error_message: None,
                setup_future_usage_applied: None,
                routing_approach: None,
                connector_request_reference_id: None,
                network_transaction_id: None,
            },
            PaymentAttemptUpdate::ResponseUpdate {
                status,
                connector,
                connector_transaction_id,
                authentication_type,
                payment_method_id,
                mandate_id,
                connector_metadata,
                payment_token,
                error_code,
                error_message,
                error_reason,
                connector_response_reference_id,
                amount_capturable,
                updated_by,
                authentication_data,
                encoded_data,
                unified_code,
                unified_message,
                capture_before,
                extended_authorization_applied,
                payment_method_data,
                connector_mandate_detail,
                charges,
                setup_future_usage_applied,
                network_transaction_id,
            } => {
                let (connector_transaction_id, processor_transaction_data) =
                    connector_transaction_id
                        .map(ConnectorTransactionId::form_id_and_data)
                        .map(|(txn_id, txn_data)| (Some(txn_id), txn_data))
                        .unwrap_or((None, None));
                Self {
                    status: Some(status),
                    connector: connector.map(Some),
                    connector_transaction_id,
                    authentication_type,
                    payment_method_id,
                    modified_at: common_utils::date_time::now(),
                    mandate_id,
                    connector_metadata,
                    error_code,
                    error_message,
                    payment_token,
                    error_reason,
                    connector_response_reference_id,
                    amount_capturable,
                    updated_by,
                    authentication_data,
                    encoded_data,
                    unified_code,
                    unified_message,
                    payment_method_data,
                    processor_transaction_data,
                    connector_mandate_detail,
                    charges,
                    amount: None,
                    net_amount: None,
                    currency: None,
                    amount_to_capture: None,
                    payment_method: None,
                    cancellation_reason: None,
                    browser_info: None,
                    payment_method_type: None,
                    payment_experience: None,
                    business_sub_label: None,
                    straight_through_algorithm: None,
                    preprocessing_step_id: None,
                    capture_method: None,
                    multiple_capture_count: None,
                    surcharge_amount: None,
                    tax_amount: None,
                    merchant_connector_id: None,
                    external_three_ds_authentication_attempted: None,
                    authentication_connector: None,
                    authentication_id: None,
                    fingerprint_id: None,
                    payment_method_billing_address_id: None,
                    client_source: None,
                    client_version: None,
                    customer_acceptance: None,
                    card_network: None,
                    capture_before,
                    extended_authorization_applied,
                    shipping_cost: None,
                    order_tax_amount: None,
                    card_discovery: None,
                    issuer_error_code: None,
                    issuer_error_message: None,
                    setup_future_usage_applied,
                    routing_approach: None,
                    connector_request_reference_id: None,
                    network_transaction_id,
                }
            }
            PaymentAttemptUpdate::ErrorUpdate {
                connector,
                status,
                error_code,
                error_message,
                error_reason,
                amount_capturable,
                updated_by,
                unified_code,
                unified_message,
                connector_transaction_id,
                payment_method_data,
                authentication_type,
                issuer_error_code,
                issuer_error_message,
            } => {
                let (connector_transaction_id, processor_transaction_data) =
                    connector_transaction_id
                        .map(ConnectorTransactionId::form_id_and_data)
                        .map(|(txn_id, txn_data)| (Some(txn_id), txn_data))
                        .unwrap_or((None, None));
                Self {
                    connector: connector.map(Some),
                    status: Some(status),
                    error_message,
                    error_code,
                    modified_at: common_utils::date_time::now(),
                    error_reason,
                    amount_capturable,
                    updated_by,
                    unified_code,
                    unified_message,
                    connector_transaction_id,
                    payment_method_data,
                    authentication_type,
                    processor_transaction_data,
                    issuer_error_code,
                    issuer_error_message,
                    amount: None,
                    net_amount: None,
                    currency: None,
                    amount_to_capture: None,
                    payment_method: None,
                    payment_method_id: None,
                    cancellation_reason: None,
                    mandate_id: None,
                    browser_info: None,
                    payment_token: None,
                    connector_metadata: None,
                    payment_method_type: None,
                    payment_experience: None,
                    business_sub_label: None,
                    straight_through_algorithm: None,
                    preprocessing_step_id: None,
                    capture_method: None,
                    connector_response_reference_id: None,
                    multiple_capture_count: None,
                    surcharge_amount: None,
                    tax_amount: None,
                    merchant_connector_id: None,
                    authentication_data: None,
                    encoded_data: None,
                    external_three_ds_authentication_attempted: None,
                    authentication_connector: None,
                    authentication_id: None,
                    fingerprint_id: None,
                    payment_method_billing_address_id: None,
                    client_source: None,
                    client_version: None,
                    customer_acceptance: None,
                    card_network: None,
                    capture_before: None,
                    extended_authorization_applied: None,
                    shipping_cost: None,
                    order_tax_amount: None,
                    connector_mandate_detail: None,
                    card_discovery: None,
                    charges: None,
                    setup_future_usage_applied: None,
                    routing_approach: None,
                    connector_request_reference_id: None,
                    network_transaction_id: None,
                }
            }
            PaymentAttemptUpdate::StatusUpdate { status, updated_by } => Self {
                status: Some(status),
                modified_at: common_utils::date_time::now(),
                updated_by,
                amount: None,
                net_amount: None,
                currency: None,
                connector_transaction_id: None,
                amount_to_capture: None,
                connector: None,
                authentication_type: None,
                payment_method: None,
                error_message: None,
                payment_method_id: None,
                cancellation_reason: None,
                mandate_id: None,
                browser_info: None,
                payment_token: None,
                error_code: None,
                connector_metadata: None,
                payment_method_data: None,
                payment_method_type: None,
                payment_experience: None,
                business_sub_label: None,
                straight_through_algorithm: None,
                preprocessing_step_id: None,
                error_reason: None,
                capture_method: None,
                connector_response_reference_id: None,
                multiple_capture_count: None,
                surcharge_amount: None,
                tax_amount: None,
                amount_capturable: None,
                merchant_connector_id: None,
                authentication_data: None,
                encoded_data: None,
                unified_code: None,
                unified_message: None,
                external_three_ds_authentication_attempted: None,
                authentication_connector: None,
                authentication_id: None,
                fingerprint_id: None,
                payment_method_billing_address_id: None,
                client_source: None,
                client_version: None,
                customer_acceptance: None,
                card_network: None,
                shipping_cost: None,
                capture_before: None,
                extended_authorization_applied: None,
                order_tax_amount: None,
                processor_transaction_data: None,
                connector_mandate_detail: None,
                card_discovery: None,
                charges: None,
                issuer_error_code: None,
                issuer_error_message: None,
                setup_future_usage_applied: None,
                routing_approach: None,
                connector_request_reference_id: None,
                network_transaction_id: None,
            },
            PaymentAttemptUpdate::UpdateTrackers {
                payment_token,
                connector,
                straight_through_algorithm,
                amount_capturable,
                surcharge_amount,
                tax_amount,
                updated_by,
                merchant_connector_id,
                routing_approach,
            } => Self {
                payment_token,
                modified_at: common_utils::date_time::now(),
                connector: connector.map(Some),
                straight_through_algorithm,
                amount_capturable,
                surcharge_amount,
                tax_amount,
                updated_by,
                merchant_connector_id: merchant_connector_id.map(Some),
                amount: None,
                net_amount: None,
                currency: None,
                status: None,
                connector_transaction_id: None,
                amount_to_capture: None,
                authentication_type: None,
                payment_method: None,
                error_message: None,
                payment_method_id: None,
                cancellation_reason: None,
                mandate_id: None,
                browser_info: None,
                error_code: None,
                connector_metadata: None,
                payment_method_data: None,
                payment_method_type: None,
                payment_experience: None,
                business_sub_label: None,
                preprocessing_step_id: None,
                error_reason: None,
                capture_method: None,
                connector_response_reference_id: None,
                multiple_capture_count: None,
                authentication_data: None,
                encoded_data: None,
                unified_code: None,
                unified_message: None,
                external_three_ds_authentication_attempted: None,
                authentication_connector: None,
                authentication_id: None,
                fingerprint_id: None,
                payment_method_billing_address_id: None,
                client_source: None,
                client_version: None,
                customer_acceptance: None,
                card_network: None,
                shipping_cost: None,
                capture_before: None,
                extended_authorization_applied: None,
                order_tax_amount: None,
                processor_transaction_data: None,
                connector_mandate_detail: None,
                card_discovery: None,
                charges: None,
                issuer_error_code: None,
                issuer_error_message: None,
                setup_future_usage_applied: None,
                routing_approach,
                connector_request_reference_id: None,
                network_transaction_id: None,
            },
            PaymentAttemptUpdate::UnresolvedResponseUpdate {
                status,
                connector,
                connector_transaction_id,
                payment_method_id,
                error_code,
                error_message,
                error_reason,
                connector_response_reference_id,
                updated_by,
            } => {
                let (connector_transaction_id, processor_transaction_data) =
                    connector_transaction_id
                        .map(ConnectorTransactionId::form_id_and_data)
                        .map(|(txn_id, txn_data)| (Some(txn_id), txn_data))
                        .unwrap_or((None, None));
                Self {
                    status: Some(status),
                    connector: connector.map(Some),
                    connector_transaction_id,
                    payment_method_id,
                    modified_at: common_utils::date_time::now(),
                    error_code,
                    error_message,
                    error_reason,
                    connector_response_reference_id,
                    updated_by,
                    processor_transaction_data,
                    amount: None,
                    net_amount: None,
                    currency: None,
                    amount_to_capture: None,
                    authentication_type: None,
                    payment_method: None,
                    cancellation_reason: None,
                    mandate_id: None,
                    browser_info: None,
                    payment_token: None,
                    connector_metadata: None,
                    payment_method_data: None,
                    payment_method_type: None,
                    payment_experience: None,
                    business_sub_label: None,
                    straight_through_algorithm: None,
                    preprocessing_step_id: None,
                    capture_method: None,
                    multiple_capture_count: None,
                    surcharge_amount: None,
                    tax_amount: None,
                    amount_capturable: None,
                    merchant_connector_id: None,
                    authentication_data: None,
                    encoded_data: None,
                    unified_code: None,
                    unified_message: None,
                    external_three_ds_authentication_attempted: None,
                    authentication_connector: None,
                    authentication_id: None,
                    fingerprint_id: None,
                    payment_method_billing_address_id: None,
                    client_source: None,
                    client_version: None,
                    customer_acceptance: None,
                    card_network: None,
                    shipping_cost: None,
                    capture_before: None,
                    extended_authorization_applied: None,
                    order_tax_amount: None,
                    connector_mandate_detail: None,
                    card_discovery: None,
                    charges: None,
                    issuer_error_code: None,
                    issuer_error_message: None,
                    setup_future_usage_applied: None,
                    routing_approach: None,
                    connector_request_reference_id: None,
                    network_transaction_id: None,
                }
            }
            PaymentAttemptUpdate::PreprocessingUpdate {
                status,
                payment_method_id,
                connector_metadata,
                preprocessing_step_id,
                connector_transaction_id,
                connector_response_reference_id,
                updated_by,
            } => {
                let (connector_transaction_id, processor_transaction_data) =
                    connector_transaction_id
                        .map(ConnectorTransactionId::form_id_and_data)
                        .map(|(txn_id, txn_data)| (Some(txn_id), txn_data))
                        .unwrap_or((None, None));
                Self {
                    status: Some(status),
                    payment_method_id,
                    modified_at: common_utils::date_time::now(),
                    connector_metadata,
                    preprocessing_step_id,
                    connector_transaction_id,
                    connector_response_reference_id,
                    updated_by,
                    processor_transaction_data,
                    amount: None,
                    net_amount: None,
                    currency: None,
                    amount_to_capture: None,
                    connector: None,
                    authentication_type: None,
                    payment_method: None,
                    error_message: None,
                    cancellation_reason: None,
                    mandate_id: None,
                    browser_info: None,
                    payment_token: None,
                    error_code: None,
                    payment_method_data: None,
                    payment_method_type: None,
                    payment_experience: None,
                    business_sub_label: None,
                    straight_through_algorithm: None,
                    error_reason: None,
                    capture_method: None,
                    multiple_capture_count: None,
                    surcharge_amount: None,
                    tax_amount: None,
                    amount_capturable: None,
                    merchant_connector_id: None,
                    authentication_data: None,
                    encoded_data: None,
                    unified_code: None,
                    unified_message: None,
                    external_three_ds_authentication_attempted: None,
                    authentication_connector: None,
                    authentication_id: None,
                    fingerprint_id: None,
                    payment_method_billing_address_id: None,
                    client_source: None,
                    client_version: None,
                    customer_acceptance: None,
                    card_network: None,
                    capture_before: None,
                    extended_authorization_applied: None,
                    shipping_cost: None,
                    order_tax_amount: None,
                    connector_mandate_detail: None,
                    card_discovery: None,
                    charges: None,
                    issuer_error_code: None,
                    issuer_error_message: None,
                    setup_future_usage_applied: None,
                    routing_approach: None,
                    connector_request_reference_id: None,
                    network_transaction_id: None,
                }
            }
            PaymentAttemptUpdate::CaptureUpdate {
                multiple_capture_count,
                updated_by,
                amount_to_capture,
            } => Self {
                multiple_capture_count,
                modified_at: common_utils::date_time::now(),
                updated_by,
                amount_to_capture,
                amount: None,
                net_amount: None,
                currency: None,
                status: None,
                connector_transaction_id: None,
                connector: None,
                authentication_type: None,
                payment_method: None,
                error_message: None,
                payment_method_id: None,
                cancellation_reason: None,
                mandate_id: None,
                browser_info: None,
                payment_token: None,
                error_code: None,
                connector_metadata: None,
                payment_method_data: None,
                payment_method_type: None,
                payment_experience: None,
                business_sub_label: None,
                straight_through_algorithm: None,
                preprocessing_step_id: None,
                error_reason: None,
                capture_method: None,
                connector_response_reference_id: None,
                surcharge_amount: None,
                tax_amount: None,
                amount_capturable: None,
                merchant_connector_id: None,
                authentication_data: None,
                encoded_data: None,
                unified_code: None,
                unified_message: None,
                external_three_ds_authentication_attempted: None,
                authentication_connector: None,
                authentication_id: None,
                fingerprint_id: None,
                payment_method_billing_address_id: None,
                client_source: None,
                client_version: None,
                customer_acceptance: None,
                card_network: None,
                shipping_cost: None,
                order_tax_amount: None,
                capture_before: None,
                extended_authorization_applied: None,
                processor_transaction_data: None,
                connector_mandate_detail: None,
                card_discovery: None,
                charges: None,
                issuer_error_code: None,
                issuer_error_message: None,
                setup_future_usage_applied: None,
                routing_approach: None,
                connector_request_reference_id: None,
                network_transaction_id: None,
            },
            PaymentAttemptUpdate::AmountToCaptureUpdate {
                status,
                amount_capturable,
                updated_by,
            } => Self {
                status: Some(status),
                modified_at: common_utils::date_time::now(),
                amount_capturable: Some(amount_capturable),
                updated_by,
                amount: None,
                net_amount: None,
                currency: None,
                connector_transaction_id: None,
                amount_to_capture: None,
                connector: None,
                authentication_type: None,
                payment_method: None,
                error_message: None,
                payment_method_id: None,
                cancellation_reason: None,
                mandate_id: None,
                browser_info: None,
                payment_token: None,
                error_code: None,
                connector_metadata: None,
                payment_method_data: None,
                payment_method_type: None,
                payment_experience: None,
                business_sub_label: None,
                straight_through_algorithm: None,
                preprocessing_step_id: None,
                error_reason: None,
                capture_method: None,
                connector_response_reference_id: None,
                multiple_capture_count: None,
                surcharge_amount: None,
                tax_amount: None,
                merchant_connector_id: None,
                authentication_data: None,
                encoded_data: None,
                unified_code: None,
                unified_message: None,
                external_three_ds_authentication_attempted: None,
                authentication_connector: None,
                authentication_id: None,
                fingerprint_id: None,
                payment_method_billing_address_id: None,
                client_source: None,
                client_version: None,
                customer_acceptance: None,
                card_network: None,
                shipping_cost: None,
                capture_before: None,
                extended_authorization_applied: None,
                order_tax_amount: None,
                processor_transaction_data: None,
                connector_mandate_detail: None,
                card_discovery: None,
                charges: None,
                issuer_error_code: None,
                issuer_error_message: None,
                setup_future_usage_applied: None,
                routing_approach: None,
                connector_request_reference_id: None,
                network_transaction_id: None,
            },
            PaymentAttemptUpdate::ConnectorResponse {
                authentication_data,
                encoded_data,
                connector_transaction_id,
                connector,
                updated_by,
                charges,
            } => {
                let (connector_transaction_id, processor_transaction_data) =
                    connector_transaction_id
                        .map(ConnectorTransactionId::form_id_and_data)
                        .map(|(txn_id, txn_data)| (Some(txn_id), txn_data))
                        .unwrap_or((None, None));
                Self {
                    authentication_data,
                    encoded_data,
                    connector_transaction_id,
                    connector: connector.map(Some),
                    modified_at: common_utils::date_time::now(),
                    updated_by,
                    processor_transaction_data,
                    charges,
                    amount: None,
                    net_amount: None,
                    currency: None,
                    status: None,
                    amount_to_capture: None,
                    authentication_type: None,
                    payment_method: None,
                    error_message: None,
                    payment_method_id: None,
                    cancellation_reason: None,
                    mandate_id: None,
                    browser_info: None,
                    payment_token: None,
                    error_code: None,
                    connector_metadata: None,
                    payment_method_data: None,
                    payment_method_type: None,
                    payment_experience: None,
                    business_sub_label: None,
                    straight_through_algorithm: None,
                    preprocessing_step_id: None,
                    error_reason: None,
                    capture_method: None,
                    connector_response_reference_id: None,
                    multiple_capture_count: None,
                    surcharge_amount: None,
                    tax_amount: None,
                    amount_capturable: None,
                    merchant_connector_id: None,
                    unified_code: None,
                    unified_message: None,
                    external_three_ds_authentication_attempted: None,
                    authentication_connector: None,
                    authentication_id: None,
                    fingerprint_id: None,
                    payment_method_billing_address_id: None,
                    client_source: None,
                    client_version: None,
                    customer_acceptance: None,
                    card_network: None,
                    shipping_cost: None,
                    capture_before: None,
                    extended_authorization_applied: None,
                    order_tax_amount: None,
                    connector_mandate_detail: None,
                    card_discovery: None,
                    issuer_error_code: None,
                    issuer_error_message: None,
                    setup_future_usage_applied: None,
                    routing_approach: None,
                    connector_request_reference_id: None,
                    network_transaction_id: None,
                }
            }
            PaymentAttemptUpdate::IncrementalAuthorizationAmountUpdate {
                amount,
                amount_capturable,
            } => Self {
                amount: Some(amount),
                modified_at: common_utils::date_time::now(),
                amount_capturable: Some(amount_capturable),
                net_amount: None,
                currency: None,
                status: None,
                connector_transaction_id: None,
                amount_to_capture: None,
                connector: None,
                authentication_type: None,
                payment_method: None,
                error_message: None,
                payment_method_id: None,
                cancellation_reason: None,
                mandate_id: None,
                browser_info: None,
                payment_token: None,
                error_code: None,
                connector_metadata: None,
                payment_method_data: None,
                payment_method_type: None,
                payment_experience: None,
                business_sub_label: None,
                straight_through_algorithm: None,
                preprocessing_step_id: None,
                error_reason: None,
                capture_method: None,
                connector_response_reference_id: None,
                multiple_capture_count: None,
                surcharge_amount: None,
                tax_amount: None,
                updated_by: String::default(),
                merchant_connector_id: None,
                authentication_data: None,
                encoded_data: None,
                unified_code: None,
                unified_message: None,
                external_three_ds_authentication_attempted: None,
                authentication_connector: None,
                authentication_id: None,
                fingerprint_id: None,
                payment_method_billing_address_id: None,
                client_source: None,
                client_version: None,
                customer_acceptance: None,
                card_network: None,
                shipping_cost: None,
                order_tax_amount: None,
                capture_before: None,
                extended_authorization_applied: None,
                processor_transaction_data: None,
                connector_mandate_detail: None,
                card_discovery: None,
                charges: None,
                issuer_error_code: None,
                issuer_error_message: None,
                setup_future_usage_applied: None,
                routing_approach: None,
                connector_request_reference_id: None,
                network_transaction_id: None,
            },
            PaymentAttemptUpdate::AuthenticationUpdate {
                status,
                external_three_ds_authentication_attempted,
                authentication_connector,
                authentication_id,
                updated_by,
            } => Self {
                status: Some(status),
                modified_at: common_utils::date_time::now(),
                external_three_ds_authentication_attempted,
                authentication_connector,
                authentication_id,
                updated_by,
                amount: None,
                net_amount: None,
                currency: None,
                connector_transaction_id: None,
                amount_to_capture: None,
                connector: None,
                authentication_type: None,
                payment_method: None,
                error_message: None,
                payment_method_id: None,
                cancellation_reason: None,
                mandate_id: None,
                browser_info: None,
                payment_token: None,
                error_code: None,
                connector_metadata: None,
                payment_method_data: None,
                payment_method_type: None,
                payment_experience: None,
                business_sub_label: None,
                straight_through_algorithm: None,
                preprocessing_step_id: None,
                error_reason: None,
                capture_method: None,
                connector_response_reference_id: None,
                multiple_capture_count: None,
                surcharge_amount: None,
                tax_amount: None,
                amount_capturable: None,
                merchant_connector_id: None,
                authentication_data: None,
                encoded_data: None,
                unified_code: None,
                unified_message: None,
                fingerprint_id: None,
                payment_method_billing_address_id: None,
                client_source: None,
                client_version: None,
                customer_acceptance: None,
                card_network: None,
                shipping_cost: None,
                order_tax_amount: None,
                capture_before: None,
                extended_authorization_applied: None,
                processor_transaction_data: None,
                connector_mandate_detail: None,
                card_discovery: None,
                charges: None,
                issuer_error_code: None,
                issuer_error_message: None,
                setup_future_usage_applied: None,
                routing_approach: None,
                connector_request_reference_id: None,
                network_transaction_id: None,
            },
            PaymentAttemptUpdate::ManualUpdate {
                status,
                error_code,
                error_message,
                error_reason,
                updated_by,
                unified_code,
                unified_message,
                connector_transaction_id,
            } => {
                let (connector_transaction_id, processor_transaction_data) =
                    connector_transaction_id
                        .map(ConnectorTransactionId::form_id_and_data)
                        .map(|(txn_id, txn_data)| (Some(txn_id), txn_data))
                        .unwrap_or((None, None));
                Self {
                    status,
                    error_code: error_code.map(Some),
                    modified_at: common_utils::date_time::now(),
                    error_message: error_message.map(Some),
                    error_reason: error_reason.map(Some),
                    updated_by,
                    unified_code: unified_code.map(Some),
                    unified_message: unified_message.map(Some),
                    connector_transaction_id,
                    processor_transaction_data,
                    amount: None,
                    net_amount: None,
                    currency: None,
                    amount_to_capture: None,
                    connector: None,
                    authentication_type: None,
                    payment_method: None,
                    payment_method_id: None,
                    cancellation_reason: None,
                    mandate_id: None,
                    browser_info: None,
                    payment_token: None,
                    connector_metadata: None,
                    payment_method_data: None,
                    payment_method_type: None,
                    payment_experience: None,
                    business_sub_label: None,
                    straight_through_algorithm: None,
                    preprocessing_step_id: None,
                    capture_method: None,
                    connector_response_reference_id: None,
                    multiple_capture_count: None,
                    surcharge_amount: None,
                    tax_amount: None,
                    amount_capturable: None,
                    merchant_connector_id: None,
                    authentication_data: None,
                    encoded_data: None,
                    external_three_ds_authentication_attempted: None,
                    authentication_connector: None,
                    authentication_id: None,
                    fingerprint_id: None,
                    payment_method_billing_address_id: None,
                    client_source: None,
                    client_version: None,
                    customer_acceptance: None,
                    card_network: None,
                    shipping_cost: None,
                    capture_before: None,
                    extended_authorization_applied: None,
                    order_tax_amount: None,
                    connector_mandate_detail: None,
                    card_discovery: None,
                    charges: None,
                    issuer_error_code: None,
                    issuer_error_message: None,
                    setup_future_usage_applied: None,
                    routing_approach: None,
                    connector_request_reference_id: None,
                    network_transaction_id: None,
                }
            }
            PaymentAttemptUpdate::PostSessionTokensUpdate {
                updated_by,
                connector_metadata,
            } => Self {
                status: None,
                error_code: None,
                modified_at: common_utils::date_time::now(),
                error_message: None,
                error_reason: None,
                updated_by,
                unified_code: None,
                unified_message: None,
                amount: None,
                net_amount: None,
                currency: None,
                connector_transaction_id: None,
                amount_to_capture: None,
                connector: None,
                authentication_type: None,
                payment_method: None,
                payment_method_id: None,
                cancellation_reason: None,
                mandate_id: None,
                browser_info: None,
                payment_token: None,
                connector_metadata,
                payment_method_data: None,
                payment_method_type: None,
                payment_experience: None,
                business_sub_label: None,
                straight_through_algorithm: None,
                preprocessing_step_id: None,
                capture_method: None,
                connector_response_reference_id: None,
                multiple_capture_count: None,
                surcharge_amount: None,
                tax_amount: None,
                amount_capturable: None,
                merchant_connector_id: None,
                authentication_data: None,
                encoded_data: None,
                external_three_ds_authentication_attempted: None,
                authentication_connector: None,
                authentication_id: None,
                fingerprint_id: None,
                payment_method_billing_address_id: None,
                client_source: None,
                client_version: None,
                customer_acceptance: None,
                card_network: None,
                shipping_cost: None,
                order_tax_amount: None,
                capture_before: None,
                extended_authorization_applied: None,
                processor_transaction_data: None,
                connector_mandate_detail: None,
                card_discovery: None,
                charges: None,
                issuer_error_code: None,
                issuer_error_message: None,
                setup_future_usage_applied: None,
                routing_approach: None,
                connector_request_reference_id: None,
                network_transaction_id: None,
            },
        }
    }
}

#[derive(Eq, PartialEq, Clone, Debug, Deserialize, Serialize, diesel::AsExpression)]
#[diesel(sql_type = diesel::sql_types::Jsonb)]
pub enum RedirectForm {
    Form {
        endpoint: String,
        method: common_utils::request::Method,
        form_fields: std::collections::HashMap<String, String>,
    },
    Html {
        html_data: String,
    },
    BarclaycardAuthSetup {
        access_token: String,
        ddc_url: String,
        reference_id: String,
    },
    BarclaycardConsumerAuth {
        access_token: String,
        step_up_url: String,
    },
    BlueSnap {
        payment_fields_token: String,
    },
    CybersourceAuthSetup {
        access_token: String,
        ddc_url: String,
        reference_id: String,
    },
    CybersourceConsumerAuth {
        access_token: String,
        step_up_url: String,
    },
    DeutschebankThreeDSChallengeFlow {
        acs_url: String,
        creq: String,
    },
    Payme,
    Braintree {
        client_token: String,
        card_token: String,
        bin: String,
        acs_url: String,
    },
    Nmi {
        amount: String,
        currency: common_enums::Currency,
        public_key: masking::Secret<String>,
        customer_vault_id: String,
        order_id: String,
    },
    Mifinity {
        initialization_token: String,
    },
    WorldpayDDCForm {
        endpoint: common_utils::types::Url,
        method: common_utils::request::Method,
        form_fields: std::collections::HashMap<String, String>,
        collection_id: Option<String>,
    },
}

common_utils::impl_to_sql_from_sql_json!(RedirectForm);

#[cfg(feature = "v2")]
#[derive(
    Clone, Debug, serde::Deserialize, serde::Serialize, Eq, PartialEq, diesel::AsExpression,
)]
#[diesel(sql_type = diesel::pg::sql_types::Jsonb)]
pub struct PaymentAttemptFeatureMetadata {
    pub revenue_recovery: Option<PaymentAttemptRecoveryData>,
}

#[cfg(feature = "v2")]
#[derive(
    Clone, Debug, serde::Deserialize, serde::Serialize, Eq, PartialEq, diesel::AsExpression,
)]
#[diesel(sql_type = diesel::pg::sql_types::Jsonb)]
pub struct PaymentAttemptRecoveryData {
    pub attempt_triggered_by: common_enums::TriggeredBy,
    // stripe specific field used to identify duplicate attempts.
    pub charge_id: Option<String>,
}
#[cfg(feature = "v2")]


OpenAPI Block Path: components.schemas.PayoutConfirmRequest
{
  "type": "object",
  "required": [
    "client_secret"
  ],
  "properties": {
    "merchant_order_reference_id": {
      "type": "string",
      "description": "Your unique identifier for this payout or order. This ID helps you reconcile payouts on your system. If provided, it is passed to the connector if supported.",
      "example": "merchant_order_ref_123",
      "nullable": true,
      "maxLength": 255
    },
    "amount": {
      "type": "integer",
      "format": "int64",
      "description": "The payout amount. Amount for the payout in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc.,",
      "example": 1000,
      "nullable": true,
      "minimum": 0
    },
    "currency": {
      "allOf": [
        {
          "$ref": "#/components/schemas/Currency"
        }
      ],
      "nullable": true
    },
    "routing": {
      "allOf": [
        {
          "$ref": "#/components/schemas/StaticRoutingAlgorithm"
        }
      ],
      "nullable": true
    },
    "connector": {
      "type": "array",
      "items": {
        "$ref": "#/components/schemas/PayoutConnectors"
      },
      "description": "This field allows the merchant to manually select a connector with which the payout can go through.",
      "example": [
        "wise",
        "adyen"
      ],
      "nullable": true
    },
    "payout_type": {
      "allOf": [
        {
          "$ref": "#/components/schemas/PayoutType"
        }
      ],
      "nullable": true
    },
    "payout_method_data": {
      "allOf": [
        {
          "$ref": "#/components/schemas/PayoutMethodData"
        }
      ],
      "nullable": true
    },
    "billing": {
      "allOf": [
        {
          "$ref": "#/components/schemas/Address"
        }
      ],
      "nullable": true
    },
    "auto_fulfill": {
      "type": "boolean",
      "description": "Set to true to confirm the payout without review, no further action required",
      "default": false,
      "example": true,
      "nullable": true
    },
    "customer_id": {
      "type": "string",
      "description": "The identifier for the customer object. If not provided the customer ID will be autogenerated. _Deprecated: Use customer_id instead._",
      "deprecated": true,
      "example": "cus_y3oqhf46pyzuxjbcn2giaqnb44",
      "nullable": true,
      "maxLength": 255
    },
    "customer": {
      "allOf": [
        {
          "$ref": "#/components/schemas/CustomerDetails"
        }
      ],
      "nullable": true
    },
    "client_secret": {
      "type": "string",
      "description": "It's a token used for client side verification."
    },
    "return_url": {
      "type": "string",
      "description": "The URL to redirect after the completion of the operation",
      "example": "https://hyperswitch.io",
      "nullable": true
    },
    "business_country": {
      "allOf": [
        {
          "$ref": "#/components/schemas/CountryAlpha2"
        }
      ],
      "nullable": true
    },
    "business_label": {
      "type": "string",
      "description": "Business label of the merchant for this payout. _Deprecated: Use profile_id instead._",
      "deprecated": true,
      "example": "food",
      "nullable": true
    },
    "description": {
      "type": "string",
      "description": "A description of the payout",
      "example": "It's my first payout request",
      "nullable": true
    },
    "entity_type": {
      "allOf": [
        {
          "$ref": "#/components/schemas/PayoutEntityType"
        }
      ],
      "nullable": true
    },
    "recurring": {
      "type": "boolean",
      "description": "Specifies whether or not the payout request is recurring",
      "default": false,
      "nullable": true
    },
    "metadata": {
      "type": "object",
      "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.",
      "nullable": true
    },
    "payout_token": {
      "type": "string",
      "description": "Provide a reference to a stored payout method, used to process the payout.",
      "example": "187282ab-40ef-47a9-9206-5099ba31e432",
      "nullable": true
    },
    "profile_id": {
      "type": "string",
      "description": "The business profile to use for this payout, especially if there are multiple business profiles associated with the account, otherwise default business profile associated with the merchant account will be used.",
      "nullable": true
    },
    "priority": {
      "allOf": [
        {
          "$ref": "#/components/schemas/PayoutSendPriority"
        }
      ],
      "nullable": true
    },
    "payout_link": {
      "type": "boolean",
      "description": "Whether to get the payout link (if applicable). Merchant need to specify this during the Payout _Create_, this field can not be updated during Payout _Update_.",
      "default": false,
      "example": true,
      "nullable": true
    },
    "payout_link_config": {
      "allOf": [
        {
          "$ref": "#/components/schemas/PayoutCreatePayoutLinkConfig"
        }
      ],
      "nullable": true
    },
    "session_expiry": {
      "type": "integer",
      "format": "int32",
      "description": "Will be used to expire client secret after certain amount of time to be supplied in seconds\n(900) for 15 mins",
      "example": 900,
      "nullable": true,
      "minimum": 0
    },
    "email": {
      "type": "string",
      "description": "Customer's email. _Deprecated: Use customer object instead._",
      "deprecated": true,
      "example": "johntest@test.com",
      "nullable": true,
      "maxLength": 255
    },
    "name": {
      "type": "string",
      "description": "Customer's name. _Deprecated: Use customer object instead._",
      "deprecated": true,
      "example": "John Test",
      "nullable": true,
      "maxLength": 255
    },
    "phone": {
      "type": "string",
      "description": "Customer's phone. _Deprecated: Use customer object instead._",
      "deprecated": true,
      "example": "9123456789",
      "nullable": true,
      "maxLength": 255
    },
    "phone_country_code": {
      "type": "string",
      "description": "Customer's phone country code. _Deprecated: Use customer object instead._",
      "deprecated": true,
      "example": "+1",
      "nullable": true,
      "maxLength": 255
    },
    "payout_method_id": {
      "type": "string",
      "description": "Identifier for payout method",
      "nullable": true
    }
  }
}


pub struct TransactionProcessingDetails {
    order_id: String,
    transaction_id: String,
}


pub async fn update_resource<D, R>(
        &self,
        state: &KeyManagerState,
        key_store: &MerchantKeyStore,
        mut resources: MutexGuard<'_, Vec<D>>,
        resource_updated: D,
        filter_fn: impl Fn(&&mut D) -> bool,
        error_message: String,
    ) -> CustomResult<R, StorageError>
    where
        D: Sync + ReverseConversion<R> + Clone,
        R: Conversion,
    {
        if let Some(pm) = resources.iter_mut().find(filter_fn) {
            *pm = resource_updated.clone();
            let result = resource_updated
                .convert(
                    state,
                    key_store.key.get_inner(),
                    key_store.merchant_id.clone().into(),
                )
                .await
                .change_context(StorageError::DecryptionError)?;
            Ok(result)
        } else {
            Err(StorageError::ValueNotFound(error_message).into())
        }
    }


File: crates/hyperswitch_domain_models/src/cards_info.rs

use common_utils::errors;
use diesel_models::cards_info;

#[async_trait::async_trait]
pub trait CardsInfoInterface {
    type Error;
    async fn get_card_info(
        &self,
        _card_iin: &str,
    ) -> errors::CustomResult<Option<cards_info::CardInfo>, Self::Error>;
    async fn add_card_info(
        &self,
        data: cards_info::CardInfo,
    ) -> errors::CustomResult<cards_info::CardInfo, Self::Error>;
    async fn update_card_info(
        &self,
        card_iin: String,
        data: cards_info::UpdateCardInfo,
    ) -> errors::CustomResult<cards_info::CardInfo, Self::Error>;
}


pub struct PaymentAttempt {
    /// Payment id for the payment attempt
    pub payment_id: id_type::GlobalPaymentId,
    /// Merchant id for the payment attempt
    pub merchant_id: id_type::MerchantId,
    /// Amount details for the payment attempt
    pub amount_details: AttemptAmountDetails,
    /// Status of the payment attempt. This is the status that is updated by the connector.
    /// The intent status is updated by the AttemptStatus.
    pub status: storage_enums::AttemptStatus,
    /// Name of the connector that was used for the payment attempt. The connector is either decided by
    /// either running the routing algorithm or by straight through processing request.
    /// This will be updated before calling the connector
    // TODO: use connector enum, this should be done in v1 as well as a part of moving to domain types wherever possible
    pub connector: Option<String>,
    /// Error details in case the payment attempt failed
    pub error: Option<ErrorDetails>,
    /// The authentication type that was requested for the payment attempt.
    /// This authentication type maybe decided by step up 3ds or by running the decision engine.
    pub authentication_type: storage_enums::AuthenticationType,
    /// The time at which the payment attempt was created
    pub created_at: PrimitiveDateTime,
    /// The time at which the payment attempt was last modified
    pub modified_at: PrimitiveDateTime,
    pub last_synced: Option<PrimitiveDateTime>,
    /// The reason for the cancellation of the payment attempt. Some connectors will have strict rules regarding the values this can have
    /// Cancellation reason will be validated at the connector level when building the request
    pub cancellation_reason: Option<String>,
    /// Browser information required for 3DS authentication
    pub browser_info: Option<common_utils::types::BrowserInformation>,
    /// Payment token is the token used for temporary use in case the payment method is stored in vault
    pub payment_token: Option<String>,
    /// Metadata that is returned by the connector.
    pub connector_metadata: Option<pii::SecretSerdeValue>,
    pub payment_experience: Option<storage_enums::PaymentExperience>,
    /// The insensitive data of the payment method data is stored here
    pub payment_method_data: Option<pii::SecretSerdeValue>,
    /// The result of the routing algorithm.
    /// This will store the list of connectors and other related information that was used to route the payment.
    // TODO: change this to type instead of serde_json::Value
    pub routing_result: Option<Value>,
    pub preprocessing_step_id: Option<String>,
    /// Number of captures that have happened for the payment attempt
    pub multiple_capture_count: Option<i16>,
    /// A reference to the payment at connector side. This is returned by the connector
    pub connector_response_reference_id: Option<String>,
    /// Whether the payment was updated by postgres or redis
    pub updated_by: String,
    /// The authentication data which is used for external authentication
    pub redirection_data: Option<router_response_types::RedirectForm>,
    pub encoded_data: Option<Secret<String>>,
    pub merchant_connector_id: Option<id_type::MerchantConnectorAccountId>,
    /// Whether external 3DS authentication was attempted for this payment.
    /// This is based on the configuration of the merchant in the business profile
    pub external_three_ds_authentication_attempted: Option<bool>,
    /// The connector that was used for external authentication
    pub authentication_connector: Option<String>,
    /// The foreign key reference to the authentication details
    pub authentication_id: Option<id_type::AuthenticationId>,
    pub fingerprint_id: Option<String>,
    pub client_source: Option<String>,
    pub client_version: Option<String>,
    pub customer_acceptance: Option<Secret<common_payments_types::CustomerAcceptance>>,
    /// The profile id for the payment attempt. This will be derived from payment intent.
    pub profile_id: id_type::ProfileId,
    /// The organization id for the payment attempt. This will be derived from payment intent.
    pub organization_id: id_type::OrganizationId,
    /// Payment method type for the payment attempt
    pub payment_method_type: storage_enums::PaymentMethod,
    /// Foreig key reference of Payment method id in case the payment instrument was stored
    pub payment_method_id: Option<id_type::GlobalPaymentMethodId>,
    /// The reference to the payment at the connector side
    pub connector_payment_id: Option<String>,
    /// The payment method subtype for the payment attempt.
    pub payment_method_subtype: storage_enums::PaymentMethodType,
    /// The authentication type that was applied for the payment attempt.
    pub authentication_applied: Option<common_enums::AuthenticationType>,
    /// A reference to the payment at connector side. This is returned by the connector
    pub external_reference_id: Option<String>,
    /// The billing address for the payment method
    #[encrypt(ty = Value)]
    pub payment_method_billing_address: Option<Encryptable<Address>>,
    /// The global identifier for the payment attempt
    pub id: id_type::GlobalAttemptId,
    /// Connector token information that can be used to make payments directly by the merchant.
    pub connector_token_details: Option<diesel_models::ConnectorTokenDetails>,
    /// Indicates the method by which a card is discovered during a payment
    pub card_discovery: Option<common_enums::CardDiscovery>,
    /// Split payment data
    pub charges: Option<common_types::payments::ConnectorChargeResponseData>,
    /// Additional data that might be required by hyperswitch, to enable some specific features.
    pub feature_metadata: Option<PaymentAttemptFeatureMetadata>,
    /// merchant who owns the credentials of the processor, i.e. processor owner
    pub processor_merchant_id: id_type::MerchantId,
    /// merchantwho invoked the resource based api (identifier) and through what source (Api, Jwt(Dashboard))
    pub created_by: Option<CreatedBy>,
    pub connector_request_reference_id: Option<String>,
    pub network_transaction_id: Option<String>,
}


impl utils::MultipleCaptureSyncResponse for Box<PaymentsResponse> {
    fn get_connector_capture_id(&self) -> String {
        self.action_id.clone().unwrap_or("".into())
    }

    fn get_capture_attempt_status(&self) -> AttemptStatus {
        get_attempt_status_bal((self.status.clone(), self.balances.clone()))
    }

    fn get_connector_reference_id(&self) -> Option<String> {
        self.reference.clone()
    }

    fn is_capture_response(&self) -> bool {
        self.status == CheckoutPaymentStatus::Captured
    }
    fn get_amount_captured(&self) -> Result<Option<MinorUnit>, error_stack::Report<ParsingError>> {
        Ok(self.amount)
    }
}

impl utils::MultipleCaptureSyncResponse for for Box


pub async fn payments_redirect_response_with_creds_identifier(
    state: web::Data<app::AppState>,
    req: actix_web::HttpRequest,
    path: web::Path<(
        common_utils::id_type::PaymentId,
        common_utils::id_type::MerchantId,
        String,
        String,
    )


pub async fn update_with_capture_id(
        self,
        conn: &PgPooledConn,
        capture: CaptureUpdate,
    ) -> StorageResult<Self> {
        match generics::generic_update_with_unique_predicate_get_result::<
            <Self as HasTable>::Table,
            _,
            _,
            _,
        >(
            conn,
            dsl::capture_id.eq(self.capture_id.to_owned()),
            CaptureUpdateInternal::from(capture),
        )
        .await
        {
            Err(error) => match error.current_context() {
                errors::DatabaseError::NoFieldsToUpdate => Ok(self),
                _ => Err(error),
            },
            result => result,
        }
    }


impl OrganizationInterface for KafkaStore {
    async fn insert_organization(
        &self,
        organization: OrganizationNew,
    ) -> CustomResult<Organization, StorageError> {
        self.diesel_store.insert_organization(organization).await
    }
    async fn find_organization_by_org_id(
        &self,
        org_id: &id_type::OrganizationId,
    ) -> CustomResult<Organization, StorageError> {
        self.diesel_store.find_organization_by_org_id(org_id).await
    }

    async fn update_organization_by_org_id(
        &self,
        org_id: &id_type::OrganizationId,
        update: OrganizationUpdate,
    ) -> CustomResult<Organization, StorageError> {
        self.diesel_store
            .update_organization_by_org_id(org_id, update)
            .await
    }
}

impl OrganizationInterface for for KafkaStore


OpenAPI Block Path: components.schemas.NullObject
{
  "default": null,
  "nullable": true
}


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

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

use api_models::webhooks::{IncomingWebhookEvent, ObjectReferenceId};
use common_enums::enums;
use common_utils::{
    errors::CustomResult,
    ext_traits::{BytesExt, OptionExt, XmlExt},
    request::{Method, Request, RequestBuilder, RequestContent},
    types::{AmountConvertor, MinorUnit, MinorUnitForConnector},
};
use error_stack::{report, Report, ResultExt};
use hyperswitch_domain_models::{
    router_data::{AccessToken, 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, PaymentsCaptureRouterData, PaymentsSyncRouterData,
        RefundSyncRouterData, RefundsRouterData,
    },
};
use hyperswitch_interfaces::{
    api::{
        self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorSpecifications,
        ConnectorValidation,
    },
    configs::Connectors,
    consts::NO_ERROR_CODE,
    errors,
    events::connector_api_logs::ConnectorEvent,
    types::{self, Response},
    webhooks::{IncomingWebhook, IncomingWebhookRequestDetails},
};
use masking::{ExposeInterface, Mask, PeekInterface, Secret, WithType};
use ring::hmac;
use router_env::logger;
use time::OffsetDateTime;
use transformers as boku;

use crate::{
    constants::{headers, UNSUPPORTED_ERROR_MESSAGE},
    metrics,
    types::ResponseRouterData,
    utils::convert_amount,
};

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

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

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

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

impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Boku
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 connector_auth = boku::BokuAuthType::try_from(&req.connector_auth_type)?;

        let boku_url = Self::get_url(self, req, connectors)?;

        let content_type = Self::common_get_content_type(self);

        let connector_method = Self::get_http_method(self);

        let timestamp = OffsetDateTime::now_utc().unix_timestamp_nanos() / 1_000_000;

        let secret_key = boku::BokuAuthType::try_from(&req.connector_auth_type)?
            .key_id
            .expose();

        let to_sign = format!(
            "{} {}\nContent-Type: {}\n{}",
            connector_method, boku_url, &content_type, timestamp
        );

        let key = hmac::Key::new(hmac::HMAC_SHA256, secret_key.as_bytes());

        let tag = hmac::sign(&key, to_sign.as_bytes());

        let signature = hex::encode(tag);

        let auth_val = format!("2/HMAC_SHA256(H+SHA256(E)) timestamp={timestamp}, signature={signature} signed-headers=Content-Type, key-id={}", connector_auth.key_id.peek());

        let header = vec![
            (headers::CONTENT_TYPE.to_string(), content_type.into()),
            (headers::AUTHORIZATION.to_string(), auth_val.into_masked()),
        ];

        Ok(header)
    }
}

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

    fn common_get_content_type(&self) -> &'static str {
        "text/xml;charset=utf-8"
    }

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

    fn build_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        let response_data: Result<boku::BokuErrorResponse, Report<errors::ConnectorError>> = res
            .response
            .parse_struct("boku::BokuErrorResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed);

        match response_data {
            Ok(response) => {
                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,
                })
            }
            Err(_) => get_xml_deserialized(res, event_builder),
        }
    }
}

impl ConnectorValidation for Boku {}

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

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

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

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

    fn get_http_method(&self) -> Method {
        Method::Post
    }

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

    fn get_url(
        &self,
        req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let boku_url = get_country_url(
            req.connector_meta_data.clone(),
            self.base_url(connectors).to_string(),
        )?;

        Ok(format!("{boku_url}/billing/3.0/begin-single-charge"))
    }

    fn get_request_body(
        &self,
        req: &PaymentsAuthorizeRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = convert_amount(
            self.amount_converter,
            req.request.minor_amount,
            req.request.currency,
        )?;

        let connector_router_data = boku::BokuRouterData::from((amount, req));
        let connector_req = boku::BokuPaymentsRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Xml(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_data = String::from_utf8(res.response.to_vec())
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

        let response = response_data
            .parse_xml::<boku::BokuResponse>()
            .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 Boku {
    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 boku_url = get_country_url(
            req.connector_meta_data.clone(),
            self.base_url(connectors).to_string(),
        )?;

        Ok(format!("{boku_url}/billing/3.0/query-charge"))
    }

    fn get_request_body(
        &self,
        req: &PaymentsSyncRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = boku::BokuPsyncRequest::try_from(req)?;
        Ok(RequestContent::Xml(Box::new(connector_req)))
    }

    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)?)
                .set_body(types::PaymentsSyncType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsSyncRouterData, errors::ConnectorError> {
        let response_data = String::from_utf8(res.response.to_vec())
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

        let response = response_data
            .parse_xml::<boku::BokuResponse>()
            .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 Boku {
    fn get_headers(
        &self,
        req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

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

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

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

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

    fn handle_response(
        &self,
        data: &PaymentsCaptureRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCaptureRouterData, errors::ConnectorError> {
        let response_data = String::from_utf8(res.response.to_vec())
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

        let response = response_data
            .parse_xml::<boku::BokuResponse>()
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

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

impl ConnectorIntegration<Void, PaymentsCancelData, PaymentsResponseData> for Boku {}

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

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

    fn get_url(
        &self,
        req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let boku_url = get_country_url(
            req.connector_meta_data.clone(),
            self.base_url(connectors).to_string(),
        )?;

        Ok(format!("{boku_url}/billing/3.0/refund-charge"))
    }

    fn get_request_body(
        &self,
        req: &RefundsRouterData<Execute>,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let refund_amount = convert_amount(
            self.amount_converter,
            req.request.minor_refund_amount,
            req.request.currency,
        )?;

        let connector_router_data = boku::BokuRouterData::from((refund_amount, req));
        let connector_req = boku::BokuRefundRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Xml(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let request = RequestBuilder::new()
            .method(Method::Post)
            .url(&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> {
        let response: boku::RefundResponse = res
            .response
            .parse_struct("boku RefundResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

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

        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

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

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

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

    fn get_url(
        &self,
        req: &RefundSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let boku_url = get_country_url(
            req.connector_meta_data.clone(),
            self.base_url(connectors).to_string(),
        )?;

        Ok(format!("{boku_url}/billing/3.0/query-refund"))
    }

    fn get_request_body(
        &self,
        req: &RefundSyncRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = boku::BokuRsyncRequest::try_from(req)?;
        Ok(RequestContent::Xml(Box::new(connector_req)))
    }

    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> {
        let response: boku::BokuRsyncResponse = res
            .response
            .parse_struct("boku BokuRsyncResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

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

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

    fn get_webhook_event_type(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<IncomingWebhookEvent, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }

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

fn get_country_url(
    meta_data: Option<Secret<serde_json::Value, WithType>>,
    base_url: String,
) -> Result<String, Report<errors::ConnectorError>> {
    let conn_meta_data: boku::BokuMetaData = meta_data
        .parse_value("Object")
        .change_context(errors::ConnectorError::RequestEncodingFailed)?;

    Ok(base_url.replace('$', &conn_meta_data.country.to_lowercase()))
}

// validate xml format for the error
fn get_xml_deserialized(
    res: Response,
    event_builder: Option<&mut ConnectorEvent>,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
    metrics::CONNECTOR_RESPONSE_DESERIALIZATION_FAILURE
        .add(1, router_env::metric_attributes!(("connector", "boku")));

    let response_data = String::from_utf8(res.response.to_vec())
        .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

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

    // check for whether the response is in xml format
    match roxmltree::Document::parse(&response_data) {
        // in case of unexpected response but in xml format
        Ok(_) => Err(errors::ConnectorError::ResponseDeserializationFailed)?,
        // in case of unexpected response but in html or string format
        Err(_) => {
            logger::error!("UNEXPECTED RESPONSE FROM CONNECTOR: {}", response_data);
            Ok(ErrorResponse {
                status_code: res.status_code,
                code: NO_ERROR_CODE.to_string(),
                message: UNSUPPORTED_ERROR_MESSAGE.to_string(),
                reason: Some(response_data),
                attempt_status: None,
                connector_transaction_id: None,
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            })
        }
    }
}

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

    let mut boku_supported_payment_methods = SupportedPaymentMethods::new();

    boku_supported_payment_methods.add(
        enums::PaymentMethod::Wallet,
        enums::PaymentMethodType::Dana,
        PaymentMethodDetails {
            mandates: enums::FeatureStatus::NotSupported,
            refunds: enums::FeatureStatus::Supported,
            supported_capture_methods: supported_capture_methods.clone(),
            specific_features: None,
        },
    );

    boku_supported_payment_methods.add(
        enums::PaymentMethod::Wallet,
        enums::PaymentMethodType::Gcash,
        PaymentMethodDetails {
            mandates: enums::FeatureStatus::NotSupported,
            refunds: enums::FeatureStatus::Supported,
            supported_capture_methods: supported_capture_methods.clone(),
            specific_features: None,
        },
    );

    boku_supported_payment_methods.add(
        enums::PaymentMethod::Wallet,
        enums::PaymentMethodType::GoPay,
        PaymentMethodDetails {
            mandates: enums::FeatureStatus::NotSupported,
            refunds: enums::FeatureStatus::Supported,
            supported_capture_methods: supported_capture_methods.clone(),
            specific_features: None,
        },
    );

    boku_supported_payment_methods.add(
        enums::PaymentMethod::Wallet,
        enums::PaymentMethodType::KakaoPay,
        PaymentMethodDetails {
            mandates: enums::FeatureStatus::NotSupported,
            refunds: enums::FeatureStatus::Supported,
            supported_capture_methods: supported_capture_methods.clone(),
            specific_features: None,
        },
    );

    boku_supported_payment_methods.add(
        enums::PaymentMethod::Wallet,
        enums::PaymentMethodType::Momo,
        PaymentMethodDetails {
            mandates: enums::FeatureStatus::NotSupported,
            refunds: enums::FeatureStatus::Supported,
            supported_capture_methods,
            specific_features: None,
        },
    );

    boku_supported_payment_methods
});

static BOKU_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
    display_name: "Boku",
    description: "Boku, Inc. is a mobile payments company that allows businesses to collect online payments through both carrier billing and mobile wallets.",
    connector_type: enums::HyperswitchConnectorCategory::AlternativePaymentMethod,
    integration_status: enums::ConnectorIntegrationStatus::Alpha,
};

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

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

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

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


pub struct ThreeDSecureIoMetaData {
    pub mcc: String,
    pub merchant_country_code: String,
    pub merchant_name: String,
}


impl api::PaymentVoid for Fiserv {}


pub fn increment_webhook_outgoing_received_count(merchant_id: &common_utils::id_type::MerchantId) {
    metrics::WEBHOOK_OUTGOING_RECEIVED_COUNT.add(
        1,
        router_env::metric_attributes!((MERCHANT_ID, merchant_id.clone())),
    )
}


pub struct CardDetailUpdate {
    /// Card Holder Name
    #[schema(value_type = String,example = "John Doe")]
    pub card_holder_name: Option<masking::Secret<String>>,

    /// Card Holder's Nick Name
    #[schema(value_type = Option<String>,example = "John Doe")]
    pub nick_name: Option<masking::Secret<String>>,
}


pub struct FluidData {
    value: Secret<String>,
}


pub struct PayloadCardResponse {
    pub card_brand: String,
    pub card_number: String, // Masked card number like "xxxxxxxxxxxx4242"
    pub card_type: String,
    pub expiry: Secret<String>,
}