diff --git a/config/config.example.toml b/config/config.example.toml index d8b3b054ed..6f78d60626 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -1044,6 +1044,9 @@ ach = { country = "US", currency = "USD" } [payout_method_filters.loonio] interac = { currency = "CAD" } +[payout_method_filters.gigadat] +interac = { currency = "CAD" } + [payment_link] sdk_url = "http://localhost:9090/0.16.7/v0/HyperLoader.js" diff --git a/config/deployments/integration_test.toml b/config/deployments/integration_test.toml index c84a9c8d2e..35861786c2 100644 --- a/config/deployments/integration_test.toml +++ b/config/deployments/integration_test.toml @@ -798,6 +798,9 @@ ach = { country = "US", currency = "USD" } [payout_method_filters.loonio] interac = { currency = "CAD" } +[payout_method_filters.gigadat] +interac = { currency = "CAD" } + [pm_filters.inespay] sepa = { country = "ES", currency = "EUR"} diff --git a/config/deployments/production.toml b/config/deployments/production.toml index 1f89e0bffe..75b5cae3a8 100644 --- a/config/deployments/production.toml +++ b/config/deployments/production.toml @@ -868,6 +868,9 @@ ach = { country = "US", currency = "USD" } [payout_method_filters.loonio] interac = { currency = "CAD" } +[payout_method_filters.gigadat] +interac = { currency = "CAD" } + [temp_locker_enable_config] bluesnap.payment_method = "card" nuvei.payment_method = "card" diff --git a/config/deployments/sandbox.toml b/config/deployments/sandbox.toml index a23f76be7a..e4cc619ef4 100644 --- a/config/deployments/sandbox.toml +++ b/config/deployments/sandbox.toml @@ -874,6 +874,9 @@ ach = { country = "US", currency = "USD" } [payout_method_filters.loonio] interac = { currency = "CAD" } +[payout_method_filters.gigadat] +interac = { currency = "CAD" } + [temp_locker_enable_config] bluesnap.payment_method = "card" nuvei.payment_method = "card" diff --git a/config/development.toml b/config/development.toml index 547e49e3df..9247390227 100644 --- a/config/development.toml +++ b/config/development.toml @@ -1196,6 +1196,9 @@ ach = { country = "US", currency = "USD" } [payout_method_filters.loonio] interac = { currency = "CAD" } +[payout_method_filters.gigadat] +interac = { currency = "CAD" } + [payment_link] sdk_url = "http://localhost:9050/HyperLoader.js" diff --git a/config/docker_compose.toml b/config/docker_compose.toml index 9fde7959fc..4fee4bee9f 100644 --- a/config/docker_compose.toml +++ b/config/docker_compose.toml @@ -1205,6 +1205,9 @@ ach = { country = "US", currency = "USD" } [payout_method_filters.loonio] interac = { currency = "CAD" } +[payout_method_filters.gigadat] +interac = { currency = "CAD" } + [locker_based_open_banking_connectors] connector_list = "tokenio" diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs index 1f3f5bdd15..a12b0cf6e9 100644 --- a/crates/api_models/src/enums.rs +++ b/crates/api_models/src/enums.rs @@ -121,6 +121,7 @@ impl TryFrom for PayoutConnectors { Connector::Adyenplatform => Ok(Self::Adyenplatform), Connector::Cybersource => Ok(Self::Cybersource), Connector::Ebanx => Ok(Self::Ebanx), + Connector::Gigadat => Ok(Self::Gigadat), Connector::Loonio => Ok(Self::Loonio), Connector::Nuvei => Ok(Self::Nuvei), Connector::Nomupay => Ok(Self::Nomupay), diff --git a/crates/common_enums/src/connector_enums.rs b/crates/common_enums/src/connector_enums.rs index f6e7348e1e..518d89b5e5 100644 --- a/crates/common_enums/src/connector_enums.rs +++ b/crates/common_enums/src/connector_enums.rs @@ -392,7 +392,7 @@ impl Connector { } #[cfg(feature = "payouts")] pub fn is_payout_quote_call_required(self) -> bool { - matches!(self, Self::Wise) + matches!(self, Self::Wise | Self::Gigadat) } #[cfg(feature = "payouts")] pub fn supports_access_token_for_payout(self, payout_method: Option) -> bool { diff --git a/crates/diesel_models/src/payout_attempt.rs b/crates/diesel_models/src/payout_attempt.rs index a908ef7bdf..834539e2e3 100644 --- a/crates/diesel_models/src/payout_attempt.rs +++ b/crates/diesel_models/src/payout_attempt.rs @@ -1,5 +1,5 @@ use common_utils::{ - payout_method_utils, + payout_method_utils, pii, types::{UnifiedCode, UnifiedMessage}, }; use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable}; @@ -38,6 +38,7 @@ pub struct PayoutAttempt { pub unified_message: Option, pub additional_payout_method_data: Option, pub merchant_order_reference_id: Option, + pub payout_connector_metadata: Option, } #[derive( @@ -78,6 +79,7 @@ pub struct PayoutAttemptNew { pub unified_message: Option, pub additional_payout_method_data: Option, pub merchant_order_reference_id: Option, + pub payout_connector_metadata: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -90,6 +92,7 @@ pub enum PayoutAttemptUpdate { is_eligible: Option, unified_code: Option, unified_message: Option, + payout_connector_metadata: Option, }, PayoutTokenUpdate { payout_token: String, @@ -131,6 +134,7 @@ pub struct PayoutAttemptUpdateInternal { pub unified_message: Option, pub additional_payout_method_data: Option, pub merchant_order_reference_id: Option, + pub payout_connector_metadata: Option, } impl Default for PayoutAttemptUpdateInternal { @@ -154,6 +158,7 @@ impl Default for PayoutAttemptUpdateInternal { unified_message: None, additional_payout_method_data: None, merchant_order_reference_id: None, + payout_connector_metadata: None, } } } @@ -173,6 +178,7 @@ impl From for PayoutAttemptUpdateInternal { is_eligible, unified_code, unified_message, + payout_connector_metadata, } => Self { connector_payout_id, status: Some(status), @@ -181,6 +187,7 @@ impl From for PayoutAttemptUpdateInternal { is_eligible, unified_code, unified_message, + payout_connector_metadata, ..Default::default() }, PayoutAttemptUpdate::BusinessUpdate { @@ -236,6 +243,7 @@ impl PayoutAttemptUpdate { unified_message, additional_payout_method_data, merchant_order_reference_id, + payout_connector_metadata, } = self.into(); PayoutAttempt { payout_token: payout_token.or(source.payout_token), @@ -258,6 +266,8 @@ impl PayoutAttemptUpdate { .or(source.additional_payout_method_data), merchant_order_reference_id: merchant_order_reference_id .or(source.merchant_order_reference_id), + payout_connector_metadata: payout_connector_metadata + .or(source.payout_connector_metadata), ..source } } diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs index 7d4e1609e4..0488754b93 100644 --- a/crates/diesel_models/src/schema.rs +++ b/crates/diesel_models/src/schema.rs @@ -1335,6 +1335,7 @@ diesel::table! { additional_payout_method_data -> Nullable, #[max_length = 255] merchant_order_reference_id -> Nullable, + payout_connector_metadata -> Nullable, } } diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs index 11533805ce..cea9e67444 100644 --- a/crates/diesel_models/src/schema_v2.rs +++ b/crates/diesel_models/src/schema_v2.rs @@ -1279,6 +1279,7 @@ diesel::table! { additional_payout_method_data -> Nullable, #[max_length = 255] merchant_order_reference_id -> Nullable, + payout_connector_metadata -> Nullable, } } diff --git a/crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs b/crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs index 3ff273557f..e62ef33144 100644 --- a/crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs @@ -5843,6 +5843,7 @@ impl TryFrom> for PayoutsRo should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) diff --git a/crates/hyperswitch_connectors/src/connectors/adyenplatform/transformers/payouts.rs b/crates/hyperswitch_connectors/src/connectors/adyenplatform/transformers/payouts.rs index e97cc8aa0e..90e431ecca 100644 --- a/crates/hyperswitch_connectors/src/connectors/adyenplatform/transformers/payouts.rs +++ b/crates/hyperswitch_connectors/src/connectors/adyenplatform/transformers/payouts.rs @@ -615,6 +615,7 @@ impl TryFrom> for Payouts should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) diff --git a/crates/hyperswitch_connectors/src/connectors/cybersource/transformers.rs b/crates/hyperswitch_connectors/src/connectors/cybersource/transformers.rs index eaf6304ef2..2d34c19837 100644 --- a/crates/hyperswitch_connectors/src/connectors/cybersource/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/cybersource/transformers.rs @@ -5085,6 +5085,7 @@ impl TryFrom> for Pa should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) diff --git a/crates/hyperswitch_connectors/src/connectors/ebanx/transformers.rs b/crates/hyperswitch_connectors/src/connectors/ebanx/transformers.rs index 42caad6c2f..353f1bd885 100644 --- a/crates/hyperswitch_connectors/src/connectors/ebanx/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/ebanx/transformers.rs @@ -218,6 +218,7 @@ impl TryFrom> for PayoutsRo should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) @@ -302,6 +303,7 @@ impl TryFrom> for PayoutsR should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) @@ -393,6 +395,7 @@ impl TryFrom> for PayoutsRo should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) diff --git a/crates/hyperswitch_connectors/src/connectors/gigadat.rs b/crates/hyperswitch_connectors/src/connectors/gigadat.rs index 7ca6b9639a..8d7857a072 100644 --- a/crates/hyperswitch_connectors/src/connectors/gigadat.rs +++ b/crates/hyperswitch_connectors/src/connectors/gigadat.rs @@ -35,11 +35,13 @@ use hyperswitch_domain_models::{ }; #[cfg(feature = "payouts")] use hyperswitch_domain_models::{ - router_flow_types::{PoCreate, PoFulfill, PoQuote}, + router_flow_types::{PoCreate, PoFulfill, PoQuote, PoSync}, types::{PayoutsData, PayoutsResponseData, PayoutsRouterData}, }; #[cfg(feature = "payouts")] -use hyperswitch_interfaces::types::{PayoutCreateType, PayoutFulfillType, PayoutQuoteType}; +use hyperswitch_interfaces::types::{ + PayoutCreateType, PayoutFulfillType, PayoutQuoteType, PayoutSyncType, +}; use hyperswitch_interfaces::{ api::{ self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorSpecifications, @@ -52,13 +54,15 @@ use hyperswitch_interfaces::{ webhooks, }; use lazy_static::lazy_static; -use masking::{Mask, PeekInterface}; +use masking::{ExposeInterface, Mask, PeekInterface}; #[cfg(feature = "payouts")] use router_env::{instrument, tracing}; use transformers as gigadat; use url::form_urlencoded; use uuid::Uuid; +#[cfg(feature = "payouts")] +use crate::utils::{to_payout_connector_meta, RouterData as RouterDataTrait}; use crate::{constants::headers, types::ResponseRouterData, utils}; #[derive(Clone)] @@ -86,12 +90,15 @@ impl api::Refund for Gigadat {} impl api::RefundExecute for Gigadat {} impl api::RefundSync for Gigadat {} impl api::PaymentToken for Gigadat {} +impl api::Payouts for Gigadat {} #[cfg(feature = "payouts")] impl api::PayoutQuote for Gigadat {} #[cfg(feature = "payouts")] impl api::PayoutCreate for Gigadat {} #[cfg(feature = "payouts")] impl api::PayoutFulfill for Gigadat {} +#[cfg(feature = "payouts")] +impl api::PayoutSync for Gigadat {} impl ConnectorIntegration for Gigadat @@ -658,9 +665,9 @@ impl ConnectorIntegration for Gigadat event_builder: Option<&mut ConnectorEvent>, res: Response, ) -> CustomResult, errors::ConnectorError> { - let response: gigadat::GigadatPayoutResponse = res + let response: gigadat::GigadatPayoutQuoteResponse = res .response - .parse_struct("GigadatPayoutResponse") + .parse_struct("GigadatPayoutQuoteResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; event_builder.map(|i| i.set_response_body(&response)); @@ -698,15 +705,17 @@ impl ConnectorIntegration for Gigada req: &PayoutsRouterData, connectors: &Connectors, ) -> CustomResult { - let transfer_id = req.request.connector_payout_id.to_owned().ok_or( - errors::ConnectorError::MissingRequiredField { - field_name: "transfer_id", - }, - )?; + let transfer_id = req.get_quote_id()?; + + let metadata = Some(req.get_connector_meta()?.clone().expose()); + + let gigatad_meta: gigadat::GigadatPayoutMeta = to_payout_connector_meta(metadata.clone())?; + Ok(format!( - "{}webflow?transaction={}", + "{}webflow?transaction={}&token={}", self.base_url(connectors), transfer_id, + gigatad_meta.token.peek(), )) } @@ -729,26 +738,21 @@ impl ConnectorIntegration for Gigada fn handle_response( &self, data: &PayoutsRouterData, - _event_builder: Option<&mut ConnectorEvent>, + event_builder: Option<&mut ConnectorEvent>, res: Response, ) -> CustomResult, errors::ConnectorError> { - router_env::logger::debug!("Expected zero bytes response, skipped parsing of the response"); + let response: gigadat::GigadatPayoutResponse = res + .response + .parse_struct("GigadatPayoutResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; - let status = if res.status_code == 200 { - enums::PayoutStatus::RequiresFulfillment - } else { - enums::PayoutStatus::Failed - }; - Ok(PayoutsRouterData { - response: Ok(PayoutsResponseData { - status: Some(status), - connector_payout_id: None, - payout_eligible: None, - should_add_next_step_to_process_tracker: false, - error_code: None, - error_message: None, - }), - ..data.clone() + 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, }) } @@ -778,13 +782,22 @@ impl ConnectorIntegration for Gigad ) -> CustomResult { let transfer_id = req.request.connector_payout_id.to_owned().ok_or( errors::ConnectorError::MissingRequiredField { - field_name: "transfer_id", + field_name: "transaction_id", }, )?; + let metadata = req + .request + .payout_connector_metadata + .clone() + .map(|secret| secret.peek().clone()); + + let gigatad_meta: gigadat::GigadatPayoutMeta = to_payout_connector_meta(metadata.clone())?; + Ok(format!( - "{}webflow?transaction={}", + "{}webflow/deposit?transaction={}&token={}", self.base_url(connectors), transfer_id, + gigatad_meta.token.peek(), )) } @@ -834,6 +847,77 @@ impl ConnectorIntegration for Gigad } } +#[cfg(feature = "payouts")] +impl ConnectorIntegration for Gigadat { + fn get_url( + &self, + req: &PayoutsRouterData, + connectors: &Connectors, + ) -> CustomResult { + let transfer_id = req.request.connector_payout_id.to_owned().ok_or( + errors::ConnectorError::MissingRequiredField { + field_name: "transaction_id", + }, + )?; + Ok(format!( + "{}api/transactions/{}", + connectors.gigadat.base_url, transfer_id + )) + } + + fn get_headers( + &self, + req: &PayoutsRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { + self.build_headers(req, connectors) + } + + fn build_request( + &self, + req: &PayoutsRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + let request = RequestBuilder::new() + .method(Method::Get) + .url(&PayoutSyncType::get_url(self, req, connectors)?) + .attach_default_headers() + .headers(PayoutSyncType::get_headers(self, req, connectors)?) + .build(); + + Ok(Some(request)) + } + + fn handle_response( + &self, + data: &PayoutsRouterData, + event_builder: Option<&mut ConnectorEvent>, + res: Response, + ) -> CustomResult, errors::ConnectorError> { + let response: gigadat::GigadatPayoutSyncResponse = res + .response + .parse_struct("GigadatPayoutSyncResponse") + .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 { + self.build_error_response(res, event_builder) + } +} + fn get_webhook_query_params( request: &webhooks::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { diff --git a/crates/hyperswitch_connectors/src/connectors/gigadat/transformers.rs b/crates/hyperswitch_connectors/src/connectors/gigadat/transformers.rs index 2ef10458a3..948992116f 100644 --- a/crates/hyperswitch_connectors/src/connectors/gigadat/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/gigadat/transformers.rs @@ -1,4 +1,8 @@ -use api_models; +#[cfg(feature = "payouts")] +use api_models::{ + self, + payouts::{BankRedirect, PayoutMethodData}, +}; use common_enums::{enums, Currency}; use common_utils::{ id_type, @@ -367,6 +371,7 @@ pub struct GigadatPayoutQuoteRequest { pub transaction_type: GidadatTransactionType, pub user_id: id_type::CustomerId, pub user_ip: Secret, + pub sandbox: bool, } // Payouts fulfill request transform @@ -376,39 +381,58 @@ impl TryFrom<&GigadatRouterData<&PayoutsRouterData>> for GigadatPayoutQ fn try_from( item: &GigadatRouterData<&PayoutsRouterData>, ) -> Result { - let metadata: GigadatConnectorMetadataObject = - utils::to_connector_meta_from_secret(item.router_data.connector_meta_data.clone()) - .change_context(errors::ConnectorError::InvalidConnectorConfig { - config: "merchant_connector_account.metadata", - })?; + match item.router_data.get_payout_method_data()? { + PayoutMethodData::BankRedirect(BankRedirect::Interac(interac_data)) => { + let metadata: GigadatConnectorMetadataObject = + utils::to_connector_meta_from_secret( + item.router_data.connector_meta_data.clone(), + ) + .change_context( + errors::ConnectorError::InvalidConnectorConfig { + config: "merchant_connector_account.metadata", + }, + )?; - let router_data = item.router_data; - let name = router_data.get_billing_full_name()?; - let email = router_data.get_billing_email()?; - let mobile = router_data.get_billing_phone_number()?; - let currency = item.router_data.request.destination_currency; + let router_data = item.router_data; + let name = router_data.get_billing_full_name()?; + let email = interac_data.email; + let mobile = router_data.get_billing_phone_number()?; + let currency = item.router_data.request.destination_currency; - let user_ip = router_data.request.get_browser_info()?.get_ip_address()?; - let auth_type = GigadatAuthType::try_from(&item.router_data.connector_auth_type)?; + let user_ip = router_data.request.get_browser_info()?.get_ip_address()?; + let auth_type = GigadatAuthType::try_from(&item.router_data.connector_auth_type)?; + let sandbox = match item.router_data.test_mode { + Some(true) => true, + Some(false) | None => false, + }; - Ok(Self { - user_id: router_data.get_customer_id()?, - site: metadata.site, - user_ip, - currency, - amount: item.amount, - transaction_id: router_data.connector_request_reference_id.clone(), - transaction_type: GidadatTransactionType::Eto, - name, - email, - mobile, - campaign: auth_type.campaign_id, - }) + Ok(Self { + user_id: router_data.get_customer_id()?, + site: metadata.site, + user_ip, + currency, + amount: item.amount, + transaction_id: router_data.connector_request_reference_id.clone(), + transaction_type: GidadatTransactionType::Eto, + name, + email, + mobile, + campaign: auth_type.campaign_id, + sandbox, + }) + } + PayoutMethodData::Card(_) | PayoutMethodData::Bank(_) | PayoutMethodData::Wallet(_) => { + Err(errors::ConnectorError::NotSupported { + message: "Payment Method Not Supported".to_string(), + connector: "Gigadat", + })? + } + } } } #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct GigadatPayoutResponse { +pub struct GigadatPayoutQuoteResponse { pub token: Secret, pub data: GigadatPayoutData, } @@ -421,12 +445,20 @@ pub struct GigadatPayoutData { pub transaction_type: String, } +#[derive(Debug, Serialize, Deserialize)] +pub struct GigadatPayoutMeta { + pub token: Secret, +} + #[cfg(feature = "payouts")] -impl TryFrom> for PayoutsRouterData { +impl TryFrom> for PayoutsRouterData { type Error = error_stack::Report; fn try_from( - item: PayoutsResponseRouterData, + item: PayoutsResponseRouterData, ) -> Result { + let connector_meta = serde_json::json!(GigadatPayoutMeta { + token: item.response.token, + }); Ok(Self { response: Ok(PayoutsResponseData { status: None, @@ -435,6 +467,92 @@ impl TryFrom> for Payouts should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: Some(Secret::new(connector_meta)), + }), + ..item.data + }) + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct GigadatPayoutResponse { + pub id: String, + pub status: GigadatPayoutStatus, + pub data: GigadatPayoutData, +} + +#[cfg(feature = "payouts")] +impl TryFrom> for PayoutsRouterData { + type Error = error_stack::Report; + fn try_from( + item: PayoutsResponseRouterData, + ) -> Result { + Ok(Self { + response: Ok(PayoutsResponseData { + status: Some(enums::PayoutStatus::from(item.response.status)), + connector_payout_id: Some(item.response.data.transaction_id), + payout_eligible: None, + should_add_next_step_to_process_tracker: false, + error_code: None, + error_message: None, + payout_connector_metadata: None, + }), + ..item.data + }) + } +} + +#[cfg(feature = "payouts")] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct GigadatPayoutSyncResponse { + pub status: GigadatPayoutStatus, +} + +#[cfg(feature = "payouts")] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum GigadatPayoutStatus { + StatusInited, + StatusSuccess, + StatusRejected, + StatusRejected1, + StatusExpired, + StatusAborted1, + StatusPending, + StatusFailed, +} + +#[cfg(feature = "payouts")] +impl From for enums::PayoutStatus { + fn from(item: GigadatPayoutStatus) -> Self { + match item { + GigadatPayoutStatus::StatusSuccess => Self::Success, + GigadatPayoutStatus::StatusPending => Self::RequiresFulfillment, + GigadatPayoutStatus::StatusInited => Self::Pending, + GigadatPayoutStatus::StatusRejected + | GigadatPayoutStatus::StatusExpired + | GigadatPayoutStatus::StatusRejected1 + | GigadatPayoutStatus::StatusAborted1 + | GigadatPayoutStatus::StatusFailed => Self::Failed, + } + } +} + +#[cfg(feature = "payouts")] +impl TryFrom> for PayoutsRouterData { + type Error = error_stack::Report; + fn try_from( + item: PayoutsResponseRouterData, + ) -> Result { + Ok(Self { + response: Ok(PayoutsResponseData { + status: Some(enums::PayoutStatus::from(item.response.status)), + connector_payout_id: None, + payout_eligible: None, + should_add_next_step_to_process_tracker: false, + error_code: None, + error_message: None, + payout_connector_metadata: None, }), ..item.data }) diff --git a/crates/hyperswitch_connectors/src/connectors/loonio/transformers.rs b/crates/hyperswitch_connectors/src/connectors/loonio/transformers.rs index 85bbe1ab31..824957f4a9 100644 --- a/crates/hyperswitch_connectors/src/connectors/loonio/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/loonio/transformers.rs @@ -537,6 +537,7 @@ impl TryFrom> should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) @@ -564,6 +565,7 @@ impl TryFrom> for Payo should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) diff --git a/crates/hyperswitch_connectors/src/connectors/nomupay/transformers.rs b/crates/hyperswitch_connectors/src/connectors/nomupay/transformers.rs index 1d47ed5639..d71acd35ae 100644 --- a/crates/hyperswitch_connectors/src/connectors/nomupay/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/nomupay/transformers.rs @@ -413,6 +413,7 @@ impl TryFrom> for Pay should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) @@ -479,6 +480,7 @@ impl TryFrom> should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) @@ -525,6 +527,7 @@ impl TryFrom> for Payout should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) diff --git a/crates/hyperswitch_connectors/src/connectors/nuvei/transformers.rs b/crates/hyperswitch_connectors/src/connectors/nuvei/transformers.rs index eaace6b8e8..5d9544a376 100644 --- a/crates/hyperswitch_connectors/src/connectors/nuvei/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/nuvei/transformers.rs @@ -2557,6 +2557,7 @@ impl TryFrom> should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }), @@ -2570,6 +2571,7 @@ impl TryFrom> should_add_next_step_to_process_tracker: false, error_code: Some(error_response_data.err_code.to_string()), error_message: error_response_data.reason.clone(), + payout_connector_metadata: None, }), ..item.data }), diff --git a/crates/hyperswitch_connectors/src/connectors/payone/transformers.rs b/crates/hyperswitch_connectors/src/connectors/payone/transformers.rs index b51bb3d389..a523687c84 100644 --- a/crates/hyperswitch_connectors/src/connectors/payone/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/payone/transformers.rs @@ -273,6 +273,7 @@ impl TryFrom> should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) diff --git a/crates/hyperswitch_connectors/src/connectors/paypal/transformers.rs b/crates/hyperswitch_connectors/src/connectors/paypal/transformers.rs index 8883213736..61961c5238 100644 --- a/crates/hyperswitch_connectors/src/connectors/paypal/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/paypal/transformers.rs @@ -2640,6 +2640,7 @@ impl TryFrom> for Payouts should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) @@ -2660,6 +2661,7 @@ impl TryFrom> for Payo should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) diff --git a/crates/hyperswitch_connectors/src/connectors/stripe/transformers/connect.rs b/crates/hyperswitch_connectors/src/connectors/stripe/transformers/connect.rs index fc3f6bfdc1..786abbaaca 100644 --- a/crates/hyperswitch_connectors/src/connectors/stripe/transformers/connect.rs +++ b/crates/hyperswitch_connectors/src/connectors/stripe/transformers/connect.rs @@ -239,6 +239,7 @@ impl TryFrom> should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) @@ -275,6 +276,7 @@ impl TryFrom should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) @@ -307,6 +309,7 @@ impl TryFrom> should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) @@ -382,6 +385,7 @@ impl TryFrom TryFrom TryFrom> should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) @@ -506,6 +507,7 @@ impl TryFrom> for Payou should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) @@ -570,6 +572,7 @@ impl TryFrom> for PayoutsRou should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) @@ -618,6 +621,7 @@ impl TryFrom> for PayoutsRo should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) @@ -706,6 +710,7 @@ impl TryFrom> for Payout should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) diff --git a/crates/hyperswitch_connectors/src/connectors/worldpay/payout_transformers.rs b/crates/hyperswitch_connectors/src/connectors/worldpay/payout_transformers.rs index 873dc8100c..ed81aadc30 100644 --- a/crates/hyperswitch_connectors/src/connectors/worldpay/payout_transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/worldpay/payout_transformers.rs @@ -186,6 +186,7 @@ impl TryFrom> should_add_next_step_to_process_tracker: false, error_code: None, error_message: None, + payout_connector_metadata: None, }), ..item.data }) diff --git a/crates/hyperswitch_connectors/src/default_implementations.rs b/crates/hyperswitch_connectors/src/default_implementations.rs index 6aee074756..cfd2c9c256 100644 --- a/crates/hyperswitch_connectors/src/default_implementations.rs +++ b/crates/hyperswitch_connectors/src/default_implementations.rs @@ -3847,7 +3847,6 @@ default_imp_for_payouts!( connectors::Flexiti, connectors::Forte, connectors::Getnet, - connectors::Gigadat, connectors::Globalpay, connectors::Globepay, connectors::Gocardless, @@ -4135,7 +4134,6 @@ default_imp_for_payouts_retrieve!( connectors::Flexiti, connectors::Forte, connectors::Getnet, - connectors::Gigadat, connectors::Globalpay, connectors::Globepay, connectors::Gocardless, diff --git a/crates/hyperswitch_connectors/src/utils.rs b/crates/hyperswitch_connectors/src/utils.rs index 0b1b73fa22..6c8de9a11d 100644 --- a/crates/hyperswitch_connectors/src/utils.rs +++ b/crates/hyperswitch_connectors/src/utils.rs @@ -392,6 +392,15 @@ where json.parse_value(std::any::type_name::()).switch() } +#[cfg(feature = "payouts")] +pub(crate) fn to_payout_connector_meta(connector_meta: Option) -> Result +where + T: serde::de::DeserializeOwned, +{ + let json = connector_meta.ok_or_else(missing_field_err("payout_connector_meta_data"))?; + json.parse_value(std::any::type_name::()).switch() +} + pub(crate) fn convert_amount( amount_convertor: &dyn AmountConvertor, amount: MinorUnit, diff --git a/crates/hyperswitch_domain_models/src/payouts/payout_attempt.rs b/crates/hyperswitch_domain_models/src/payouts/payout_attempt.rs index b6293faa84..3b7223febd 100644 --- a/crates/hyperswitch_domain_models/src/payouts/payout_attempt.rs +++ b/crates/hyperswitch_domain_models/src/payouts/payout_attempt.rs @@ -1,7 +1,7 @@ use api_models::enums::PayoutConnectors; use common_enums as storage_enums; use common_utils::{ - id_type, payout_method_utils, + id_type, payout_method_utils, pii, types::{UnifiedCode, UnifiedMessage}, }; use serde::{Deserialize, Serialize}; @@ -92,6 +92,7 @@ pub struct PayoutAttempt { pub unified_message: Option, pub additional_payout_method_data: Option, pub merchant_order_reference_id: Option, + pub payout_connector_metadata: Option, } #[derive(Clone, Debug, PartialEq)] @@ -119,6 +120,7 @@ pub struct PayoutAttemptNew { pub unified_message: Option, pub additional_payout_method_data: Option, pub merchant_order_reference_id: Option, + pub payout_connector_metadata: Option, } #[derive(Debug, Clone)] @@ -132,6 +134,7 @@ pub enum PayoutAttemptUpdate { unified_code: Option, unified_message: Option, + payout_connector_metadata: Option, }, PayoutTokenUpdate { payout_token: String, @@ -170,6 +173,7 @@ pub struct PayoutAttemptUpdateInternal { pub unified_code: Option, pub unified_message: Option, pub additional_payout_method_data: Option, + pub payout_connector_metadata: Option, } impl From for PayoutAttemptUpdateInternal { @@ -187,6 +191,7 @@ impl From for PayoutAttemptUpdateInternal { is_eligible, unified_code, unified_message, + payout_connector_metadata, } => Self { connector_payout_id, status: Some(status), @@ -195,6 +200,7 @@ impl From for PayoutAttemptUpdateInternal { is_eligible, unified_code, unified_message, + payout_connector_metadata, ..Default::default() }, PayoutAttemptUpdate::BusinessUpdate { diff --git a/crates/hyperswitch_domain_models/src/router_request_types.rs b/crates/hyperswitch_domain_models/src/router_request_types.rs index 995fd9f2f3..7bfc64adb6 100644 --- a/crates/hyperswitch_domain_models/src/router_request_types.rs +++ b/crates/hyperswitch_domain_models/src/router_request_types.rs @@ -1341,6 +1341,7 @@ pub struct PayoutsData { pub connector_transfer_method_id: Option, pub webhook_url: Option, pub browser_info: Option, + pub payout_connector_metadata: Option, } #[derive(Debug, Default, Clone)] diff --git a/crates/hyperswitch_domain_models/src/router_response_types.rs b/crates/hyperswitch_domain_models/src/router_response_types.rs index 5b50037b61..8268bf85a9 100644 --- a/crates/hyperswitch_domain_models/src/router_response_types.rs +++ b/crates/hyperswitch_domain_models/src/router_response_types.rs @@ -584,6 +584,7 @@ pub struct PayoutsResponseData { pub should_add_next_step_to_process_tracker: bool, pub error_code: Option, pub error_message: Option, + pub payout_connector_metadata: Option, } #[derive(Debug, Clone)] diff --git a/crates/router/src/configs/defaults/payout_required_fields.rs b/crates/router/src/configs/defaults/payout_required_fields.rs index 56e975d81c..1e4ca2107c 100644 --- a/crates/router/src/configs/defaults/payout_required_fields.rs +++ b/crates/router/src/configs/defaults/payout_required_fields.rs @@ -246,7 +246,7 @@ fn get_connector_payment_method_type_fields( // Bank Redirect PaymentMethodType::Interac => { - common_fields.extend(get_interac_fields()); + common_fields.extend(get_interac_fields(connector)); ( payment_method_type, ConnectorFields { @@ -393,36 +393,86 @@ fn get_paypal_fields() -> HashMap { )]) } -fn get_interac_fields() -> HashMap { - HashMap::from([ - ( - "payout_method_data.bank_redirect.interac.email".to_string(), - RequiredFieldInfo { - required_field: "payout_method_data.bank_redirect.interac.email".to_string(), - display_name: "email".to_string(), - field_type: FieldType::Text, - value: None, - }, - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "billing.address.first_name".to_string(), - display_name: "billing_address_first_name".to_string(), - field_type: FieldType::Text, - value: None, - }, - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "billing.address.last_name".to_string(), - display_name: "billing_address_last_name".to_string(), - field_type: FieldType::Text, - value: None, - }, - ), - ]) +fn get_interac_fields(connector: PayoutConnectors) -> HashMap { + match connector { + PayoutConnectors::Loonio => HashMap::from([ + ( + "payout_method_data.bank_redirect.interac.email".to_string(), + RequiredFieldInfo { + required_field: "payout_method_data.bank_redirect.interac.email".to_string(), + display_name: "email".to_string(), + field_type: FieldType::Text, + value: None, + }, + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "billing.address.first_name".to_string(), + display_name: "billing_address_first_name".to_string(), + field_type: FieldType::Text, + value: None, + }, + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "billing.address.last_name".to_string(), + display_name: "billing_address_last_name".to_string(), + field_type: FieldType::Text, + value: None, + }, + ), + ]), + PayoutConnectors::Gigadat => HashMap::from([ + ( + "payout_method_data.bank_redirect.interac.email".to_string(), + RequiredFieldInfo { + required_field: "payout_method_data.bank_redirect.interac.email".to_string(), + display_name: "email".to_string(), + field_type: FieldType::Text, + value: None, + }, + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "billing.address.first_name".to_string(), + display_name: "billing_address_first_name".to_string(), + field_type: FieldType::Text, + value: None, + }, + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "billing.address.last_name".to_string(), + display_name: "billing_address_last_name".to_string(), + field_type: FieldType::Text, + value: None, + }, + ), + ( + "billing.phone.number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.number".to_string(), + display_name: "phone".to_string(), + field_type: FieldType::UserPhoneNumber, + value: None, + }, + ), + ( + "billing.phone.country_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.country_code".to_string(), + display_name: "dialing_code".to_string(), + field_type: FieldType::UserPhoneNumberCountryCode, + value: None, + }, + ), + ]), + _ => HashMap::from([]), + } } fn get_countries_for_connector(connector: PayoutConnectors) -> Vec { diff --git a/crates/router/src/core/payouts.rs b/crates/router/src/core/payouts.rs index 59f83799a5..a123fd3dc2 100644 --- a/crates/router/src/core/payouts.rs +++ b/crates/router/src/core/payouts.rs @@ -586,6 +586,7 @@ pub async fn payouts_cancel_core( is_eligible: None, unified_code: None, unified_message: None, + payout_connector_metadata: None, }; payout_data.payout_attempt = state .store @@ -1258,6 +1259,10 @@ pub async fn create_recipient( is_eligible: recipient_create_data.payout_eligible, unified_code: None, unified_message: None, + payout_connector_metadata: payout_data + .payout_attempt + .payout_connector_metadata + .to_owned(), }; payout_data.payout_attempt = db .update_payout_attempt( @@ -1294,6 +1299,10 @@ pub async fn create_recipient( is_eligible: recipient_create_data.payout_eligible, unified_code: None, unified_message: None, + payout_connector_metadata: payout_data + .payout_attempt + .payout_connector_metadata + .to_owned(), }; payout_data.payout_attempt = db .update_payout_attempt( @@ -1353,6 +1362,10 @@ pub async fn create_recipient( .change_context(errors::ApiErrorResponse::InvalidDataValue { field_name: "unified_message", })?, + payout_connector_metadata: payout_data + .payout_attempt + .payout_connector_metadata + .to_owned(), }; let db = &*state.store; payout_data.payout_attempt = db @@ -1480,6 +1493,7 @@ pub async fn check_payout_eligibility( is_eligible: payout_response_data.payout_eligible, unified_code: None, unified_message: None, + payout_connector_metadata: payout_response_data.payout_connector_metadata, }; payout_data.payout_attempt = db .update_payout_attempt( @@ -1538,6 +1552,10 @@ pub async fn check_payout_eligibility( .change_context(errors::ApiErrorResponse::InvalidDataValue { field_name: "unified_message", })?, + payout_connector_metadata: payout_data + .payout_attempt + .payout_connector_metadata + .to_owned(), }; payout_data.payout_attempt = db .update_payout_attempt( @@ -1594,6 +1612,10 @@ pub async fn complete_create_payout( is_eligible: None, unified_code: None, unified_message: None, + payout_connector_metadata: payout_data + .payout_attempt + .payout_connector_metadata + .to_owned(), }; payout_data.payout_attempt = db .update_payout_attempt( @@ -1662,6 +1684,8 @@ pub async fn create_payout( complete_payout_quote_steps_if_required(state, connector_data, &mut router_data).await?; }; + let connector_meta_data = router_data.connector_meta_data.clone(); + // 4. Call connector service let router_data_resp = match helpers::should_continue_payout(&router_data) { true => { @@ -1701,6 +1725,7 @@ pub async fn create_payout( is_eligible: payout_response_data.payout_eligible, unified_code: None, unified_message: None, + payout_connector_metadata: connector_meta_data.clone(), }; payout_data.payout_attempt = db .update_payout_attempt( @@ -1759,6 +1784,7 @@ pub async fn create_payout( .change_context(errors::ApiErrorResponse::InvalidDataValue { field_name: "unified_message", })?, + payout_connector_metadata: connector_meta_data, }; payout_data.payout_attempt = db .update_payout_attempt( @@ -1816,6 +1842,7 @@ async fn complete_payout_quote_steps_if_required( match router_data_resp.response.to_owned() { Ok(resp) => { router_data.quote_id = resp.connector_payout_id; + router_data.connector_meta_data = resp.payout_connector_metadata; } Err(_err) => { router_data.response = router_data_resp.response; @@ -1834,12 +1861,12 @@ pub async fn complete_payout_retrieve( ) -> RouterResult<()> { match connector_call_type { api::ConnectorCallType::PreDetermined(routing_data) => { - create_payout_retrieve( + Box::pin(create_payout_retrieve( state, merchant_context, &routing_data.connector_data, payout_data, - ) + )) .await .attach_printable("Payout retrieval failed for given Payout request")?; } @@ -1968,6 +1995,9 @@ pub async fn update_retrieve_payout_tracker( .change_context(errors::ApiErrorResponse::InvalidDataValue { field_name: "unified_message", })?, + payout_connector_metadata: payout_response_data + .payout_connector_metadata + .clone(), } } else { storage::PayoutAttemptUpdate::StatusUpdate { @@ -1978,6 +2008,9 @@ pub async fn update_retrieve_payout_tracker( is_eligible: payout_response_data.payout_eligible, unified_code: None, unified_message: None, + payout_connector_metadata: payout_response_data + .payout_connector_metadata + .clone(), } }; @@ -2092,6 +2125,7 @@ pub async fn create_recipient_disburse_account( is_eligible: payout_response_data.payout_eligible, unified_code: None, unified_message: None, + payout_connector_metadata: payout_response_data.payout_connector_metadata, }; payout_data.payout_attempt = db .update_payout_attempt( @@ -2218,6 +2252,10 @@ pub async fn create_recipient_disburse_account( .change_context(errors::ApiErrorResponse::InvalidDataValue { field_name: "unified_message", })?, + payout_connector_metadata: payout_data + .payout_attempt + .payout_connector_metadata + .to_owned(), }; payout_data.payout_attempt = db .update_payout_attempt( @@ -2284,6 +2322,7 @@ pub async fn cancel_payout( is_eligible: payout_response_data.payout_eligible, unified_code: None, unified_message: None, + payout_connector_metadata: payout_response_data.payout_connector_metadata, }; payout_data.payout_attempt = db .update_payout_attempt( @@ -2342,6 +2381,10 @@ pub async fn cancel_payout( .change_context(errors::ApiErrorResponse::InvalidDataValue { field_name: "unified_message", })?, + payout_connector_metadata: payout_data + .payout_attempt + .payout_connector_metadata + .to_owned(), }; payout_data.payout_attempt = db .update_payout_attempt( @@ -2433,6 +2476,7 @@ pub async fn fulfill_payout( is_eligible: payout_response_data.payout_eligible, unified_code: None, unified_message: None, + payout_connector_metadata: payout_response_data.payout_connector_metadata, }; payout_data.payout_attempt = db .update_payout_attempt( @@ -2517,6 +2561,10 @@ pub async fn fulfill_payout( .change_context(errors::ApiErrorResponse::InvalidDataValue { field_name: "unified_message", })?, + payout_connector_metadata: payout_data + .payout_attempt + .payout_connector_metadata + .to_owned(), }; payout_data.payout_attempt = db .update_payout_attempt( @@ -2857,6 +2905,7 @@ pub async fn payout_create_db_entries( routing_info: None, unified_code: None, unified_message: None, + payout_connector_metadata: None, }; let payout_attempt = db .insert_payout_attempt( diff --git a/crates/router/src/core/payouts/retry.rs b/crates/router/src/core/payouts/retry.rs index e457961360..daeff0de95 100644 --- a/crates/router/src/core/payouts/retry.rs +++ b/crates/router/src/core/payouts/retry.rs @@ -280,6 +280,7 @@ pub async fn modify_trackers( .payout_attempt .additional_payout_method_data .to_owned(), + payout_connector_metadata: None, }; payout_data.payout_attempt = db .insert_payout_attempt( diff --git a/crates/router/src/core/utils.rs b/crates/router/src/core/utils.rs index 176b49eb14..768e215809 100644 --- a/crates/router/src/core/utils.rs +++ b/crates/router/src/core/utils.rs @@ -63,9 +63,6 @@ use crate::{ pub const IRRELEVANT_CONNECTOR_REQUEST_REFERENCE_ID_IN_DISPUTE_FLOW: &str = "irrelevant_connector_request_reference_id_in_dispute_flow"; -#[cfg(feature = "payouts")] -pub const IRRELEVANT_CONNECTOR_REQUEST_REFERENCE_ID_IN_PAYOUTS_FLOW: &str = - "irrelevant_connector_request_reference_id_in_payouts_flow"; const IRRELEVANT_ATTEMPT_ID_IN_DISPUTE_FLOW: &str = "irrelevant_attempt_id_in_dispute_flow"; #[cfg(all(feature = "payouts", feature = "v2"))] @@ -202,6 +199,7 @@ pub async fn construct_payout_router_data<'a, F>( connector_transfer_method_id, webhook_url: Some(webhook_url), browser_info, + payout_connector_metadata: payout_attempt.payout_connector_metadata.to_owned(), }, response: Ok(types::PayoutsResponseData::default()), access_token: None, diff --git a/crates/router/src/core/webhooks/incoming.rs b/crates/router/src/core/webhooks/incoming.rs index bb76c664b5..bc2e702867 100644 --- a/crates/router/src/core/webhooks/incoming.rs +++ b/crates/router/src/core/webhooks/incoming.rs @@ -1216,6 +1216,7 @@ async fn payouts_incoming_webhook_flow( is_eligible: payout_attempt.is_eligible, unified_code: None, unified_message: None, + payout_connector_metadata: payout_attempt.payout_connector_metadata.clone(), }; let action_req = diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index 7320a2a4f0..9381a94184 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -123,8 +123,6 @@ pub use hyperswitch_interfaces::{ #[cfg(feature = "v2")] use crate::core::errors; pub use crate::core::payments::CustomerDetails; -#[cfg(feature = "payouts")] -use crate::core::utils::IRRELEVANT_CONNECTOR_REQUEST_REFERENCE_ID_IN_PAYOUTS_FLOW; use crate::{ consts, core::payments::{OperationSessionGetters, PaymentData}, @@ -1359,8 +1357,7 @@ impl recurring_mandate_payment_data: None, preprocessing_id: None, connector_customer: data.connector_customer.clone(), - connector_request_reference_id: - IRRELEVANT_CONNECTOR_REQUEST_REFERENCE_ID_IN_PAYOUTS_FLOW.to_string(), + connector_request_reference_id: data.connector_request_reference_id.clone(), payout_method_data: data.payout_method_data.clone(), quote_id: data.quote_id.clone(), test_mode: data.test_mode, diff --git a/crates/router/tests/connectors/utils.rs b/crates/router/tests/connectors/utils.rs index a7c1e60898..946035125b 100644 --- a/crates/router/tests/connectors/utils.rs +++ b/crates/router/tests/connectors/utils.rs @@ -479,6 +479,7 @@ pub trait ConnectorActions: Connector { connector_transfer_method_id: None, webhook_url: None, browser_info: None, + payout_connector_metadata: None, }, payment_info, ) diff --git a/crates/storage_impl/src/payouts/payout_attempt.rs b/crates/storage_impl/src/payouts/payout_attempt.rs index a81fac45e9..536320bb55 100644 --- a/crates/storage_impl/src/payouts/payout_attempt.rs +++ b/crates/storage_impl/src/payouts/payout_attempt.rs @@ -91,6 +91,7 @@ impl PayoutAttemptInterface for KVRouterStore { merchant_order_reference_id: new_payout_attempt .merchant_order_reference_id .clone(), + payout_connector_metadata: new_payout_attempt.payout_connector_metadata.clone(), }; let redis_entry = kv::TypedSql { @@ -574,6 +575,7 @@ impl DataModelExt for PayoutAttempt { unified_message: self.unified_message, additional_payout_method_data: self.additional_payout_method_data, merchant_order_reference_id: self.merchant_order_reference_id, + payout_connector_metadata: self.payout_connector_metadata, } } @@ -602,6 +604,7 @@ impl DataModelExt for PayoutAttempt { unified_message: storage_model.unified_message, additional_payout_method_data: storage_model.additional_payout_method_data, merchant_order_reference_id: storage_model.merchant_order_reference_id, + payout_connector_metadata: storage_model.payout_connector_metadata, } } } @@ -633,6 +636,7 @@ impl DataModelExt for PayoutAttemptNew { unified_message: self.unified_message, additional_payout_method_data: self.additional_payout_method_data, merchant_order_reference_id: self.merchant_order_reference_id, + payout_connector_metadata: self.payout_connector_metadata, } } @@ -661,6 +665,7 @@ impl DataModelExt for PayoutAttemptNew { unified_message: storage_model.unified_message, additional_payout_method_data: storage_model.additional_payout_method_data, merchant_order_reference_id: storage_model.merchant_order_reference_id, + payout_connector_metadata: storage_model.payout_connector_metadata, } } } @@ -676,6 +681,7 @@ impl DataModelExt for PayoutAttemptUpdate { is_eligible, unified_code, unified_message, + payout_connector_metadata, } => DieselPayoutAttemptUpdate::StatusUpdate { connector_payout_id, status, @@ -684,6 +690,7 @@ impl DataModelExt for PayoutAttemptUpdate { is_eligible, unified_code, unified_message, + payout_connector_metadata, }, Self::PayoutTokenUpdate { payout_token } => { DieselPayoutAttemptUpdate::PayoutTokenUpdate { payout_token } diff --git a/migrations/2025-10-10-101024-0000_add_payout_connector_metadata_in_payout_attempt_table/down.sql b/migrations/2025-10-10-101024-0000_add_payout_connector_metadata_in_payout_attempt_table/down.sql new file mode 100644 index 0000000000..03ae412015 --- /dev/null +++ b/migrations/2025-10-10-101024-0000_add_payout_connector_metadata_in_payout_attempt_table/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +ALTER TABLE payout_attempt DROP COLUMN IF EXISTS payout_connector_metadata; diff --git a/migrations/2025-10-10-101024-0000_add_payout_connector_metadata_in_payout_attempt_table/up.sql b/migrations/2025-10-10-101024-0000_add_payout_connector_metadata_in_payout_attempt_table/up.sql new file mode 100644 index 0000000000..b8935baa82 --- /dev/null +++ b/migrations/2025-10-10-101024-0000_add_payout_connector_metadata_in_payout_attempt_table/up.sql @@ -0,0 +1,2 @@ +-- Your SQL goes here +ALTER TABLE payout_attempt ADD COLUMN IF NOT EXISTS payout_connector_metadata JSONB DEFAULT NULL; \ No newline at end of file