From e4ed1e63951873f299f076332671f4a043aa86ab Mon Sep 17 00:00:00 2001 From: Sakil Mostak <73734619+Sakilmostak@users.noreply.github.com> Date: Thu, 2 May 2024 15:45:17 +0530 Subject: [PATCH] feat(connector): [Paypal] Add payout flow for wallet(Paypal and Venmo) (#4406) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- crates/api_models/src/payouts.rs | 16 ++ crates/common_enums/src/enums.rs | 1 + crates/common_enums/src/transformers.rs | 1 + crates/euclid/src/frontend/dir/enums.rs | 1 + crates/euclid/src/frontend/dir/lowering.rs | 1 + .../euclid/src/frontend/dir/transformers.rs | 1 + crates/kgraph_utils/src/transformers.rs | 1 + crates/openapi/src/openapi.rs | 1 + crates/router/src/connector/adyen.rs | 1 + .../src/connector/adyen/transformers.rs | 6 + crates/router/src/connector/klarna.rs | 1 + crates/router/src/connector/paypal.rs | 112 ++++++++++ .../src/connector/paypal/transformers.rs | 208 ++++++++++++++++++ .../src/connector/stripe/transformers.rs | 1 + crates/router/src/consts.rs | 2 + .../router/src/core/payment_methods/vault.rs | 27 ++- crates/router/src/core/payments/flows.rs | 3 - crates/router/src/types/transformers.rs | 4 +- crates/router/tests/connectors/adyen.rs | 2 + openapi/openapi_spec.json | 39 +++- 20 files changed, 421 insertions(+), 8 deletions(-) diff --git a/crates/api_models/src/payouts.rs b/crates/api_models/src/payouts.rs index 891033c1ae..815234d57e 100644 --- a/crates/api_models/src/payouts.rs +++ b/crates/api_models/src/payouts.rs @@ -289,6 +289,7 @@ pub struct PixBankTransfer { #[serde(rename_all = "snake_case")] pub enum Wallet { Paypal(Paypal), + Venmo(Venmo), } #[derive(Default, Eq, PartialEq, Clone, Debug, Deserialize, Serialize, ToSchema)] @@ -296,6 +297,21 @@ pub struct Paypal { /// Email linked with paypal account #[schema(value_type = String, example = "john.doe@example.com")] pub email: Option, + + /// mobile number linked to paypal account + #[schema(value_type = String, example = "16608213349")] + pub telephone_number: Option>, + + /// id of the paypal account + #[schema(value_type = String, example = "G83KXTJ5EHCQ2")] + pub paypal_id: Option>, +} + +#[derive(Default, Eq, PartialEq, Clone, Debug, Deserialize, Serialize, ToSchema)] +pub struct Venmo { + /// mobile number linked to venmo account + #[schema(value_type = String, example = "16608213349")] + pub telephone_number: Option>, } #[derive(Debug, Default, ToSchema, Clone, Serialize)] diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index 5323a2dcf5..18545eb4a4 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -1429,6 +1429,7 @@ pub enum PaymentMethodType { Twint, UpiCollect, Vipps, + Venmo, Walley, WeChatPay, SevenEleven, diff --git a/crates/common_enums/src/transformers.rs b/crates/common_enums/src/transformers.rs index 922d2a71c1..faca2579c0 100644 --- a/crates/common_enums/src/transformers.rs +++ b/crates/common_enums/src/transformers.rs @@ -1855,6 +1855,7 @@ impl From for PaymentMethod { PaymentMethodType::Twint => Self::Wallet, PaymentMethodType::UpiCollect => Self::Upi, PaymentMethodType::Vipps => Self::Wallet, + PaymentMethodType::Venmo => Self::Wallet, PaymentMethodType::Walley => Self::PayLater, PaymentMethodType::WeChatPay => Self::Wallet, PaymentMethodType::TouchNGo => Self::Wallet, diff --git a/crates/euclid/src/frontend/dir/enums.rs b/crates/euclid/src/frontend/dir/enums.rs index 22ab023586..941fc9d746 100644 --- a/crates/euclid/src/frontend/dir/enums.rs +++ b/crates/euclid/src/frontend/dir/enums.rs @@ -89,6 +89,7 @@ pub enum WalletType { TouchNGo, Swish, Cashapp, + Venmo, } #[derive( diff --git a/crates/euclid/src/frontend/dir/lowering.rs b/crates/euclid/src/frontend/dir/lowering.rs index f89877ca21..f6b156bf90 100644 --- a/crates/euclid/src/frontend/dir/lowering.rs +++ b/crates/euclid/src/frontend/dir/lowering.rs @@ -56,6 +56,7 @@ impl From for global_enums::PaymentMethodType { enums::WalletType::TouchNGo => Self::TouchNGo, enums::WalletType::Swish => Self::Swish, enums::WalletType::Cashapp => Self::Cashapp, + enums::WalletType::Venmo => Self::Venmo, } } } diff --git a/crates/euclid/src/frontend/dir/transformers.rs b/crates/euclid/src/frontend/dir/transformers.rs index 929b878f2c..bcc951b005 100644 --- a/crates/euclid/src/frontend/dir/transformers.rs +++ b/crates/euclid/src/frontend/dir/transformers.rs @@ -167,6 +167,7 @@ impl IntoDirValue for (global_enums::PaymentMethodType, global_enums::PaymentMet global_enums::PaymentMethodType::CardRedirect => { Ok(dirval!(CardRedirectType = CardRedirect)) } + global_enums::PaymentMethodType::Venmo => Ok(dirval!(WalletType = Venmo)), } } } diff --git a/crates/kgraph_utils/src/transformers.rs b/crates/kgraph_utils/src/transformers.rs index 000a16a263..3e43a4324f 100644 --- a/crates/kgraph_utils/src/transformers.rs +++ b/crates/kgraph_utils/src/transformers.rs @@ -286,6 +286,7 @@ impl IntoDirValue for (api_enums::PaymentMethodType, api_enums::PaymentMethod) { api_enums::PaymentMethodType::CardRedirect => { Ok(dirval!(CardRedirectType = CardRedirect)) } + api_enums::PaymentMethodType::Venmo => Ok(dirval!(WalletType = Venmo)), } } } diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs index aa30a48040..1e6746a87a 100644 --- a/crates/openapi/src/openapi.rs +++ b/crates/openapi/src/openapi.rs @@ -428,6 +428,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payouts::Card, api_models::payouts::Wallet, api_models::payouts::Paypal, + api_models::payouts::Venmo, api_models::payouts::AchBankTransfer, api_models::payouts::BacsBankTransfer, api_models::payouts::SepaBankTransfer, diff --git a/crates/router/src/connector/adyen.rs b/crates/router/src/connector/adyen.rs index 481eba0df7..85e650390f 100644 --- a/crates/router/src/connector/adyen.rs +++ b/crates/router/src/connector/adyen.rs @@ -106,6 +106,7 @@ impl ConnectorValidation for Adyen { | PaymentMethodType::PayBright | PaymentMethodType::Sepa | PaymentMethodType::Vipps + | PaymentMethodType::Venmo | PaymentMethodType::Paypal => match capture_method { enums::CaptureMethod::Automatic | enums::CaptureMethod::Manual diff --git a/crates/router/src/connector/adyen/transformers.rs b/crates/router/src/connector/adyen/transformers.rs index ec55a0be1c..6dfe899f2d 100644 --- a/crates/router/src/connector/adyen/transformers.rs +++ b/crates/router/src/connector/adyen/transformers.rs @@ -4674,6 +4674,12 @@ impl TryFrom<&AdyenRouterData<&types::PayoutsRouterData>> for AdyenPayoutC }, )?, }, + api_models::payouts::Wallet::Venmo(_) => { + Err(errors::ConnectorError::NotSupported { + message: "Venmo Wallet is not supported".to_string(), + connector: "Adyen", + })? + } }; let address: &payments::AddressDetails = item.router_data.get_billing_address()?; let payout_wallet = PayoutWalletData { diff --git a/crates/router/src/connector/klarna.rs b/crates/router/src/connector/klarna.rs index 814bd68da6..5c174c69e3 100644 --- a/crates/router/src/connector/klarna.rs +++ b/crates/router/src/connector/klarna.rs @@ -398,6 +398,7 @@ impl | common_enums::PaymentMethodType::Trustly | common_enums::PaymentMethodType::Twint | common_enums::PaymentMethodType::UpiCollect + | common_enums::PaymentMethodType::Venmo | common_enums::PaymentMethodType::Vipps | common_enums::PaymentMethodType::Walley | common_enums::PaymentMethodType::WeChatPay diff --git a/crates/router/src/connector/paypal.rs b/crates/router/src/connector/paypal.rs index e9e986b66f..6391239178 100644 --- a/crates/router/src/connector/paypal.rs +++ b/crates/router/src/connector/paypal.rs @@ -6,6 +6,8 @@ use common_utils::{ext_traits::ByteSliceExt, request::RequestContent}; use diesel_models::enums; use error_stack::ResultExt; use masking::{ExposeInterface, PeekInterface, Secret}; +#[cfg(feature = "payouts")] +use router_env::{instrument, tracing}; use transformers as paypal; use self::transformers::{auth_headers, PaypalAuthResponse, PaypalMeta, PaypalWebhookEventType}; @@ -56,6 +58,12 @@ impl api::RefundExecute for Paypal {} impl api::RefundSync for Paypal {} impl api::ConnectorVerifyWebhookSource for Paypal {} +impl api::Payouts for Paypal {} +#[cfg(feature = "payouts")] +impl api::PayoutCreate for Paypal {} +#[cfg(feature = "payouts")] +impl api::PayoutFulfill for Paypal {} + impl Paypal { pub fn get_order_error_response( &self, @@ -425,6 +433,110 @@ impl ConnectorIntegration + for Paypal +{ + fn get_url( + &self, + _req: &types::PayoutsRouterData, + connectors: &settings::Connectors, + ) -> CustomResult { + Ok(format!("{}v1/payments/payouts", self.base_url(connectors))) + } + + fn get_headers( + &self, + req: &types::PayoutsRouterData, + connectors: &settings::Connectors, + ) -> CustomResult)>, errors::ConnectorError> { + self.build_headers(req, connectors) + } + + fn get_request_body( + &self, + req: &types::PayoutsRouterData, + _connectors: &settings::Connectors, + ) -> CustomResult { + let connector_router_data = paypal::PaypalRouterData::try_from(( + &self.get_currency_unit(), + req.request.destination_currency, + req.request.amount, + req, + ))?; + let connector_req = paypal::PaypalFulfillRequest::try_from(&connector_router_data)?; + Ok(RequestContent::Json(Box::new(connector_req))) + } + + fn build_request( + &self, + req: &types::PayoutsRouterData, + connectors: &settings::Connectors, + ) -> CustomResult, errors::ConnectorError> { + let request = services::RequestBuilder::new() + .method(services::Method::Post) + .url(&types::PayoutFulfillType::get_url(self, req, connectors)?) + .attach_default_headers() + .headers(types::PayoutFulfillType::get_headers( + self, req, connectors, + )?) + .set_body(types::PayoutFulfillType::get_request_body( + self, req, connectors, + )?) + .build(); + + Ok(Some(request)) + } + + #[instrument(skip_all)] + fn handle_response( + &self, + data: &types::PayoutsRouterData, + event_builder: Option<&mut ConnectorEvent>, + res: Response, + ) -> CustomResult, errors::ConnectorError> { + let response: paypal::PaypalFulfillResponse = res + .response + .parse_struct("PaypalFulfillResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + + event_builder.map(|i| i.set_response_body(&response)); + router_env::logger::info!(connector_response=?response); + + types::RouterData::try_from(types::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) + } +} + +#[async_trait::async_trait] +#[cfg(feature = "payouts")] +impl ConnectorIntegration + for Paypal +{ + fn build_request( + &self, + _req: &types::PayoutsRouterData, + _connectors: &settings::Connectors, + ) -> CustomResult, errors::ConnectorError> { + // Eligibility check for wallet is not implemented + Err( + errors::ConnectorError::NotImplemented("Payout Eligibility for Paypal".to_string()) + .into(), + ) + } +} + impl ConnectorIntegration< api::SetupMandate, diff --git a/crates/router/src/connector/paypal/transformers.rs b/crates/router/src/connector/paypal/transformers.rs index f136ba8783..21b0f04af8 100644 --- a/crates/router/src/connector/paypal/transformers.rs +++ b/crates/router/src/connector/paypal/transformers.rs @@ -1,6 +1,8 @@ use api_models::enums; use base64::Engine; use common_utils::errors::CustomResult; +#[cfg(feature = "payouts")] +use common_utils::pii::Email; use error_stack::ResultExt; use masking::{ExposeInterface, Secret}; use serde::{Deserialize, Serialize}; @@ -1468,6 +1470,212 @@ impl } } +#[cfg(feature = "payouts")] +#[derive(Debug, Serialize)] +pub struct PaypalFulfillRequest { + sender_batch_header: PayoutBatchHeader, + items: Vec, +} + +#[cfg(feature = "payouts")] +#[derive(Debug, Serialize)] +pub struct PayoutBatchHeader { + sender_batch_id: String, +} + +#[cfg(feature = "payouts")] +#[derive(Debug, Serialize)] +pub struct PaypalPayoutItem { + amount: PayoutAmount, + note: Option, + notification_language: String, + #[serde(flatten)] + payout_method_data: PaypalPayoutMethodData, +} + +#[cfg(feature = "payouts")] +#[derive(Debug, Serialize)] +pub struct PaypalPayoutMethodData { + recipient_type: PayoutRecipientType, + recipient_wallet: PayoutWalletType, + receiver: PaypalPayoutDataType, +} + +#[cfg(feature = "payouts")] +#[derive(Debug, Serialize)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum PayoutRecipientType { + Email, + PaypalId, + Phone, +} + +#[cfg(feature = "payouts")] +#[derive(Debug, Serialize)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum PayoutWalletType { + Paypal, + Venmo, +} + +#[cfg(feature = "payouts")] +#[derive(Debug, Serialize)] +#[serde(untagged)] +pub enum PaypalPayoutDataType { + EmailType(Email), + OtherType(Secret), +} + +#[cfg(feature = "payouts")] +#[derive(Debug, Serialize)] +pub struct PayoutAmount { + value: String, + currency: storage_enums::Currency, +} + +#[cfg(feature = "payouts")] +impl TryFrom<&PaypalRouterData<&types::PayoutsRouterData>> + for PaypalFulfillRequest +{ + type Error = error_stack::Report; + fn try_from( + item: &PaypalRouterData<&types::PayoutsRouterData>, + ) -> Result { + let item_data = PaypalPayoutItem::try_from(item)?; + Ok(Self { + sender_batch_header: PayoutBatchHeader { + sender_batch_id: item.router_data.request.payout_id.to_owned(), + }, + items: vec![item_data], + }) + } +} + +#[cfg(feature = "payouts")] +impl TryFrom<&PaypalRouterData<&types::PayoutsRouterData>> for PaypalPayoutItem { + type Error = error_stack::Report; + fn try_from( + item: &PaypalRouterData<&types::PayoutsRouterData>, + ) -> Result { + let amount = PayoutAmount { + value: item.amount.to_owned(), + currency: item.router_data.request.destination_currency, + }; + + let payout_method_data = match item.router_data.get_payout_method_data()? { + api::PayoutMethodData::Wallet(wallet_data) => match wallet_data { + api::WalletPayout::Paypal(data) => { + let (recipient_type, receiver) = + match (data.email, data.telephone_number, data.paypal_id) { + (Some(email), _, _) => ( + PayoutRecipientType::Email, + PaypalPayoutDataType::EmailType(email), + ), + (_, Some(phone), _) => ( + PayoutRecipientType::Phone, + PaypalPayoutDataType::OtherType(phone), + ), + (_, _, Some(paypal_id)) => ( + PayoutRecipientType::PaypalId, + PaypalPayoutDataType::OtherType(paypal_id), + ), + _ => Err(errors::ConnectorError::MissingRequiredField { + field_name: "receiver_data", + })?, + }; + + PaypalPayoutMethodData { + recipient_type, + recipient_wallet: PayoutWalletType::Paypal, + receiver, + } + } + api::WalletPayout::Venmo(data) => { + let receiver = PaypalPayoutDataType::OtherType(data.telephone_number.ok_or( + errors::ConnectorError::MissingRequiredField { + field_name: "telephone_number", + }, + )?); + PaypalPayoutMethodData { + recipient_type: PayoutRecipientType::Phone, + recipient_wallet: PayoutWalletType::Venmo, + receiver, + } + } + }, + _ => Err(errors::ConnectorError::NotSupported { + message: "PayoutMethodType is not supported".to_string(), + connector: "Paypal", + })?, + }; + + Ok(Self { + amount, + payout_method_data, + note: item.router_data.description.to_owned(), + notification_language: consts::DEFAULT_NOTIFICATION_SCRIPT_LANGUAGE.to_string(), + }) + } +} + +#[cfg(feature = "payouts")] +#[derive(Debug, Deserialize, Serialize)] +pub struct PaypalFulfillResponse { + batch_header: PaypalBatchResponse, +} + +#[cfg(feature = "payouts")] +#[derive(Debug, Deserialize, Serialize)] +pub struct PaypalBatchResponse { + payout_batch_id: String, + batch_status: PaypalFulfillStatus, +} + +#[cfg(feature = "payouts")] +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum PaypalFulfillStatus { + Denied, + Pending, + Processing, + Success, + Cancelled, +} + +#[cfg(feature = "payouts")] +impl ForeignFrom for storage_enums::PayoutStatus { + fn foreign_from(status: PaypalFulfillStatus) -> Self { + match status { + PaypalFulfillStatus::Success => Self::Success, + PaypalFulfillStatus::Denied => Self::Failed, + PaypalFulfillStatus::Cancelled => Self::Cancelled, + PaypalFulfillStatus::Pending | PaypalFulfillStatus::Processing => Self::Pending, + } + } +} + +#[cfg(feature = "payouts")] +impl TryFrom> + for types::PayoutsRouterData +{ + type Error = error_stack::Report; + fn try_from( + item: types::PayoutsResponseRouterData, + ) -> Result { + Ok(Self { + response: Ok(types::PayoutsResponseData { + status: Some(storage_enums::PayoutStatus::foreign_from( + item.response.batch_header.batch_status, + )), + connector_payout_id: item.response.batch_header.payout_batch_id, + payout_eligible: None, + should_add_next_step_to_process_tracker: false, + }), + ..item.data + }) + } +} + #[derive(Debug, Serialize)] pub struct PaypalPaymentsCaptureRequest { amount: OrderAmount, diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index c561b26bcf..093a319f87 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -702,6 +702,7 @@ impl TryFrom for StripePaymentMethodType { | enums::PaymentMethodType::Trustly | enums::PaymentMethodType::Twint | enums::PaymentMethodType::Vipps + | enums::PaymentMethodType::Venmo | enums::PaymentMethodType::Alfamart | enums::PaymentMethodType::BcaBankTransfer | enums::PaymentMethodType::BniVa diff --git a/crates/router/src/consts.rs b/crates/router/src/consts.rs index 2c4ec3f5e7..c40d284ee3 100644 --- a/crates/router/src/consts.rs +++ b/crates/router/src/consts.rs @@ -38,6 +38,8 @@ pub(crate) const LOW_BALANCE_ERROR_MESSAGE: &str = "Insufficient balance in the pub(crate) const CONNECTOR_UNAUTHORIZED_ERROR: &str = "Authentication Error from the connector"; pub(crate) const CANNOT_CONTINUE_AUTH: &str = "Cannot continue with Authorization due to failed Liability Shift."; +#[cfg(feature = "payouts")] +pub(crate) const DEFAULT_NOTIFICATION_SCRIPT_LANGUAGE: &str = "en-US"; // General purpose base64 engines pub(crate) const BASE64_ENGINE: base64::engine::GeneralPurpose = diff --git a/crates/router/src/core/payment_methods/vault.rs b/crates/router/src/core/payment_methods/vault.rs index fafff7253a..6d4f2322a8 100644 --- a/crates/router/src/core/payment_methods/vault.rs +++ b/crates/router/src/core/payment_methods/vault.rs @@ -1,3 +1,4 @@ +use common_enums::PaymentMethodType; use common_utils::{ crypto::{DecodeMessage, EncodeMessage, GcmAes256}, ext_traits::{BytesExt, Encode}, @@ -419,6 +420,9 @@ impl Vaultable for api::CardPayout { #[derive(Debug, serde::Serialize, serde::Deserialize)] pub struct TokenizedWalletSensitiveValues { pub email: Option, + pub telephone_number: Option>, + pub wallet_id: Option>, + pub wallet_type: PaymentMethodType, } #[derive(Debug, serde::Serialize, serde::Deserialize)] @@ -432,6 +436,15 @@ impl Vaultable for api::WalletPayout { let value1 = match self { Self::Paypal(paypal_data) => TokenizedWalletSensitiveValues { email: paypal_data.email.clone(), + telephone_number: paypal_data.telephone_number.clone(), + wallet_id: paypal_data.paypal_id.clone(), + wallet_type: PaymentMethodType::Paypal, + }, + Self::Venmo(venmo_data) => TokenizedWalletSensitiveValues { + email: None, + telephone_number: venmo_data.telephone_number.clone(), + wallet_id: None, + wallet_type: PaymentMethodType::Venmo, }, }; @@ -464,9 +477,17 @@ impl Vaultable for api::WalletPayout { .change_context(errors::VaultError::ResponseDeserializationFailed) .attach_printable("Could not deserialize into wallet data wallet_insensitive_data")?; - let wallet = Self::Paypal(api_models::payouts::Paypal { - email: value1.email, - }); + let wallet = match value1.wallet_type { + PaymentMethodType::Paypal => Self::Paypal(api_models::payouts::Paypal { + email: value1.email, + telephone_number: value1.telephone_number, + paypal_id: value1.wallet_id, + }), + PaymentMethodType::Venmo => Self::Venmo(api_models::payouts::Venmo { + telephone_number: value1.telephone_number, + }), + _ => Err(errors::VaultError::PayoutMethodNotSupported)?, + }; let supp_data = SupplementaryVaultData { customer_id: value2.customer_id, payment_method_id: None, diff --git a/crates/router/src/core/payments/flows.rs b/crates/router/src/core/payments/flows.rs index c96f6f2c14..c7ec86ac5e 100644 --- a/crates/router/src/core/payments/flows.rs +++ b/crates/router/src/core/payments/flows.rs @@ -997,7 +997,6 @@ default_imp_for_payouts!( connector::Opennode, connector::Payeezy, connector::Payme, - connector::Paypal, connector::Payu, connector::Placetopay, connector::Powertranz, @@ -1082,7 +1081,6 @@ default_imp_for_payouts_create!( connector::Opennode, connector::Payeezy, connector::Payme, - connector::Paypal, connector::Payu, connector::Placetopay, connector::Powertranz, @@ -1256,7 +1254,6 @@ default_imp_for_payouts_fulfill!( connector::Opennode, connector::Payeezy, connector::Payme, - connector::Paypal, connector::Payu, connector::Placetopay, connector::Powertranz, diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index b1b185eb92..ba60da5748 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -426,7 +426,8 @@ impl ForeignFrom for api_enums::PaymentMethod { | api_enums::PaymentMethodType::Gcash | api_enums::PaymentMethodType::Momo | api_enums::PaymentMethodType::Cashapp - | api_enums::PaymentMethodType::KakaoPay => Self::Wallet, + | api_enums::PaymentMethodType::KakaoPay + | api_enums::PaymentMethodType::Venmo => Self::Wallet, api_enums::PaymentMethodType::Affirm | api_enums::PaymentMethodType::Alma | api_enums::PaymentMethodType::AfterpayClearpay @@ -971,6 +972,7 @@ impl ForeignFrom for api_enums::PaymentMethodType { fn foreign_from(value: api_models::payouts::Wallet) -> Self { match value { api_models::payouts::Wallet::Paypal(_) => Self::Paypal, + api_models::payouts::Wallet::Venmo(_) => Self::Venmo, } } } diff --git a/crates/router/tests/connectors/adyen.rs b/crates/router/tests/connectors/adyen.rs index 4ecf73d533..468834ca49 100644 --- a/crates/router/tests/connectors/adyen.rs +++ b/crates/router/tests/connectors/adyen.rs @@ -122,6 +122,8 @@ impl AdyenTest { enums::PayoutType::Wallet => Some(types::api::PayoutMethodData::Wallet( types::api::payouts::WalletPayout::Paypal(api_models::payouts::Paypal { email: Email::from_str("EmailUsedForPayPalAccount@example.com").ok(), + telephone_number: None, + paypal_id: None, }), )), }, diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index 42ea3e5455..90d81793d2 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -13023,6 +13023,7 @@ "twint", "upi_collect", "vipps", + "venmo", "walley", "we_chat_pay", "seven_eleven", @@ -16287,13 +16288,25 @@ "Paypal": { "type": "object", "required": [ - "email" + "email", + "telephone_number", + "paypal_id" ], "properties": { "email": { "type": "string", "description": "Email linked with paypal account", "example": "john.doe@example.com" + }, + "telephone_number": { + "type": "string", + "description": "mobile number linked to paypal account", + "example": "16608213349" + }, + "paypal_id": { + "type": "string", + "description": "id of the paypal account", + "example": "G83KXTJ5EHCQ2" } } }, @@ -18294,6 +18307,19 @@ "propertyName": "type" } }, + "Venmo": { + "type": "object", + "required": [ + "telephone_number" + ], + "properties": { + "telephone_number": { + "type": "string", + "description": "mobile number linked to venmo account", + "example": "16608213349" + } + } + }, "VoucherData": { "oneOf": [ { @@ -18439,6 +18465,17 @@ "$ref": "#/components/schemas/Paypal" } } + }, + { + "type": "object", + "required": [ + "venmo" + ], + "properties": { + "venmo": { + "$ref": "#/components/schemas/Venmo" + } + } } ] },