feat: api contract change for wallet (#628)

This commit is contained in:
Sangamesh Kulkarni
2023-02-27 17:38:40 +05:30
committed by GitHub
parent 060c54193e
commit ff86417eee
20 changed files with 1176 additions and 477 deletions

View File

@ -26,7 +26,7 @@ pub struct CreateMerchantAccount {
pub merchant_details: Option<MerchantDetails>, pub merchant_details: Option<MerchantDetails>,
/// The URL to redirect after the completion of the operation /// The URL to redirect after the completion of the operation
#[schema(max_length = 255, example = "https://www.example.com/success")] #[schema(value_type = Option<String>, max_length = 255, example = "https://www.example.com/success")]
pub return_url: Option<url::Url>, pub return_url: Option<url::Url>,
/// Webhook related details /// Webhook related details
@ -311,6 +311,7 @@ pub struct AcceptedCurrencies {
#[serde(rename = "type")] #[serde(rename = "type")]
pub accept_type: String, pub accept_type: String,
/// List of currencies of the provided type /// List of currencies of the provided type
#[schema(value_type = Option<Vec<Currency>>)]
pub list: Option<Vec<api_enums::Currency>>, pub list: Option<Vec<api_enums::Currency>>,
} }

View File

@ -427,7 +427,6 @@ pub enum PaymentMethod {
Card, Card,
PayLater, PayLater,
Wallet, Wallet,
BankRedirect,
} }
#[derive( #[derive(
@ -627,6 +626,7 @@ pub enum SupportedWallets {
strum::Display, strum::Display,
strum::EnumString, strum::EnumString,
frunk::LabelledGeneric, frunk::LabelledGeneric,
ToSchema,
)] )]
#[strum(serialize_all = "snake_case")] #[strum(serialize_all = "snake_case")]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]

View File

@ -4,7 +4,7 @@ use common_utils::pii;
use serde::de; use serde::de;
use utoipa::ToSchema; use utoipa::ToSchema;
use crate::{admin, enums as api_enums}; use crate::{admin, enums as api_enums, payments};
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)] #[derive(Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
@ -480,7 +480,7 @@ pub struct CustomerPaymentMethod {
pub payment_method: api_enums::PaymentMethod, pub payment_method: api_enums::PaymentMethod,
/// This is a sub-category of payment method. /// This is a sub-category of payment method.
#[schema(value_type = Option<PaymentMethodSubType>,example = "credit_card")] #[schema(value_type = Option<PaymentMethodType>,example = "credit_card")]
pub payment_method_type: Option<api_enums::PaymentMethodType>, pub payment_method_type: Option<api_enums::PaymentMethodType>,
/// The name of the bank/ provider issuing the payment method to the end user /// The name of the bank/ provider issuing the payment method to the end user
@ -584,8 +584,7 @@ pub struct TokenizedCardValue2 {
#[derive(Debug, serde::Serialize, serde::Deserialize)] #[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct TokenizedWalletValue1 { pub struct TokenizedWalletValue1 {
pub issuer: String, pub data: payments::WalletData,
pub token: Option<String>,
} }
#[derive(Debug, serde::Serialize, serde::Deserialize)] #[derive(Debug, serde::Serialize, serde::Deserialize)]

View File

@ -97,7 +97,7 @@ pub struct PaymentsRequest {
pub description: Option<String>, pub description: Option<String>,
/// The URL to redirect after the completion of the operation /// The URL to redirect after the completion of the operation
#[schema(example = "https://hyperswitch.io")] #[schema(value_type = Option<String>, example = "https://hyperswitch.io")]
pub return_url: Option<url::Url>, pub return_url: Option<url::Url>,
/// Indicates that you intend to make future payments with this Payments payment method. Providing this parameter will attach the payment method to the Customer, if present, after the Payment is confirmed and any required actions from the user are complete. /// Indicates that you intend to make future payments with this Payments payment method. Providing this parameter will attach the payment method to the Customer, if present, after the Payment is confirmed and any required actions from the user are complete.
#[schema(value_type = Option<FutureUsage>, example = "off_session")] #[schema(value_type = Option<FutureUsage>, example = "off_session")]
@ -112,7 +112,7 @@ pub struct PaymentsRequest {
pub payment_method_data: Option<PaymentMethodData>, pub payment_method_data: Option<PaymentMethodData>,
/// The payment method that is to be used /// The payment method that is to be used
#[schema(value_type = Option<PaymentMethodType>, example = "bank_transfer")] #[schema(value_type = Option<PaymentMethod>, example = "card")]
pub payment_method: Option<api_enums::PaymentMethod>, pub payment_method: Option<api_enums::PaymentMethod>,
/// Provide a reference to a stored payment method /// Provide a reference to a stored payment method
@ -170,7 +170,7 @@ pub struct PaymentsRequest {
pub payment_experience: Option<api_enums::PaymentExperience>, pub payment_experience: Option<api_enums::PaymentExperience>,
/// Payment Method Type /// Payment Method Type
#[schema(value_type = Option<PaymentMethodSubType>, example = "gpay")] #[schema(value_type = Option<PaymentMethodType>, example = "google_pay")]
pub payment_method_type: Option<api_enums::PaymentMethodType>, pub payment_method_type: Option<api_enums::PaymentMethodType>,
} }
@ -441,6 +441,7 @@ pub enum BankRedirectData {
Eps { Eps {
/// The billing details for bank redirection /// The billing details for bank redirection
billing_details: BankRedirectBilling, billing_details: BankRedirectBilling,
#[schema(value_type = BankNames)]
bank_name: api_enums::BankNames, bank_name: api_enums::BankNames,
}, },
Giropay { Giropay {
@ -450,6 +451,7 @@ pub enum BankRedirectData {
Ideal { Ideal {
/// The billing details for bank redirection /// The billing details for bank redirection
billing_details: BankRedirectBilling, billing_details: BankRedirectBilling,
#[schema(value_type = BankNames)]
bank_name: api_enums::BankNames, bank_name: api_enums::BankNames,
}, },
Sofort { Sofort {
@ -472,16 +474,103 @@ pub struct BankRedirectionRequest {}
#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize, ToSchema)] #[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct BankRedirectBilling { pub struct BankRedirectBilling {
/// The name for which billing is issued /// The name for which billing is issued
#[schema(value_type = String)]
pub billing_name: Secret<String>, pub billing_name: Secret<String>,
} }
#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct WalletData { #[serde(rename_all = "snake_case")]
/// The issuer of the wallet pub enum WalletData {
#[schema(value_type = WalletIssuer)] /// The wallet data for Google pay
pub issuer_name: api_enums::WalletIssuer, GooglePay(GpayWalletData),
/// The wallet data for Apple pay
ApplePay(ApplePayWalletData),
/// The wallet data for Paypal
PaypalSdk(PayPalWalletData),
/// This is for paypal redirection
PaypalRedirect(PaypalRedirection),
}
#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct GpayWalletData {
/// The type of payment method
#[serde(rename = "type")]
pub pm_type: String,
/// User-facing message to describe the payment method that funds this transaction.
pub description: String,
/// The information of the payment method
pub info: GpayPaymentMethodInfo,
/// The tokenization data of Google pay
pub tokenization_data: GpayTokenizationData,
}
#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct PaypalRedirection {}
#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct GpayPaymentMethodInfo {
/// The name of the card network
pub card_network: String,
/// The details of the card
pub card_details: String,
}
#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct PayPalWalletData {
/// Token generated for the Apple pay
pub token: String,
}
#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct GpayTokenizationData {
/// The type of the token
#[serde(rename = "type")]
pub token_type: String,
/// Token generated for the wallet /// Token generated for the wallet
pub token: Option<String>, pub token: String,
}
#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct ApplePayWalletData {
/// The payment data of Apple pay
pub payment_data: ApplepayPaymentData,
/// The payment method of Apple pay
pub payment_method: ApplepayPaymentMethod,
/// The unique identifier for the transaction
pub transaction_identifier: String,
}
#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct ApplepayPaymentData {
/// The data of Apple pay payment
pub data: String,
/// A string which represents the properties of a payment
pub signature: String,
/// The Apple pay header
pub header: ApplepayHeader,
/// The Apple Pay version used
pub version: String,
}
#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct ApplepayHeader {
/// The public key hash used
pub public_key_hash: String,
/// The ephemeral public key used
pub ephemeral_public_key: String,
/// The unique identifier for the transaction
pub transaction_id: String,
}
#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct ApplepayPaymentMethod {
/// The name to be displayed on Apple Pay button
pub display_name: String,
/// The network of the Apple pay payment method
pub network: String,
/// The type of the payment method
#[serde(rename = "type")]
pub pm_type: String,
} }
#[derive(Eq, PartialEq, Clone, Debug, serde::Serialize)] #[derive(Eq, PartialEq, Clone, Debug, serde::Serialize)]
@ -785,7 +874,7 @@ pub struct PaymentsResponse {
#[schema(value_type = Option<PaymentExperience>, example = "redirect_to_url")] #[schema(value_type = Option<PaymentExperience>, example = "redirect_to_url")]
pub payment_experience: Option<api_enums::PaymentExperience>, pub payment_experience: Option<api_enums::PaymentExperience>,
/// Payment Method Type /// Payment Method Type
#[schema(value_type = Option<PaymentMethodSubType>, example = "gpay")] #[schema(value_type = Option<PaymentMethodType>, example = "gpay")]
pub payment_method_type: Option<api_enums::PaymentMethodType>, pub payment_method_type: Option<api_enums::PaymentMethodType>,
} }
@ -1097,16 +1186,16 @@ pub struct GpaySessionTokenData {
#[derive(Debug, Clone, serde::Serialize, ToSchema)] #[derive(Debug, Clone, serde::Serialize, ToSchema)]
#[serde(tag = "wallet_name")] #[serde(tag = "wallet_name")]
#[serde(rename_all = "lowercase")] #[serde(rename_all = "snake_case")]
pub enum SessionToken { pub enum SessionToken {
/// The session response structure for Google Pay /// The session response structure for Google Pay
Gpay(Box<GpaySessionTokenResponse>), GooglePay(Box<GpaySessionTokenResponse>),
/// The session response structure for Klarna /// The session response structure for Klarna
Klarna(Box<KlarnaSessionTokenResponse>), Klarna(Box<KlarnaSessionTokenResponse>),
/// The session response structure for PayPal /// The session response structure for PayPal
Paypal(Box<PaypalSessionTokenResponse>), Paypal(Box<PaypalSessionTokenResponse>),
/// The session response structure for Apple Pay /// The session response structure for Apple Pay
Applepay(Box<ApplepaySessionTokenResponse>), ApplePay(Box<ApplepaySessionTokenResponse>),
} }
#[derive(Debug, Clone, serde::Serialize, ToSchema)] #[derive(Debug, Clone, serde::Serialize, ToSchema)]

View File

@ -78,7 +78,7 @@ impl TryFrom<refunds::RefundResponse> for StripeCreateRefundResponse {
payment_intent: res.payment_id, payment_intent: res.payment_id,
status: res.status.into(), status: res.status.into(),
created: res.created_at.map(|t| t.assume_utc().unix_timestamp()), created: res.created_at.map(|t| t.assume_utc().unix_timestamp()),
metadata: res.metadata.unwrap_or(serde_json::json!({})), metadata: res.metadata.unwrap_or_else(|| serde_json::json!({})),
}) })
} }
} }

View File

@ -1,18 +1,16 @@
use base64::Engine;
use error_stack::ResultExt;
use masking::PeekInterface; use masking::PeekInterface;
use reqwest::Url; use reqwest::Url;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
connector::utils::{self, PaymentsRequestData}, connector::utils::PaymentsRequestData,
consts, consts,
core::errors, core::errors,
pii::{self, Email, Secret}, pii::{self, Email, Secret},
services, services,
types::{ types::{self, api, storage::enums as storage_enums},
self,
api::{self, enums as api_enums},
storage::enums as storage_enums,
},
}; };
// Adyen Types Definition // Adyen Types Definition
@ -339,7 +337,6 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for AdyenPaymentRequest {
get_paylater_specific_payment_data(item) get_paylater_specific_payment_data(item)
} }
storage_models::enums::PaymentMethod::Wallet => get_wallet_specific_payment_data(item), storage_models::enums::PaymentMethod::Wallet => get_wallet_specific_payment_data(item),
_ => Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()),
} }
} }
} }
@ -480,29 +477,34 @@ fn get_payment_method_data(
}; };
Ok(AdyenPaymentMethod::AdyenCard(adyen_card)) Ok(AdyenPaymentMethod::AdyenCard(adyen_card))
} }
api::PaymentMethodData::Wallet(ref wallet_data) => match wallet_data.issuer_name { api::PaymentMethodData::Wallet(ref wallet_data) => match wallet_data {
api_enums::WalletIssuer::GooglePay => { api_models::payments::WalletData::GooglePay(data) => {
let gpay_data = AdyenGPay { let gpay_data = AdyenGPay {
payment_type: PaymentType::Googlepay, payment_type: PaymentType::Googlepay,
google_pay_token: wallet_data google_pay_token: data.tokenization_data.token.to_owned(),
.token
.clone()
.ok_or_else(utils::missing_field_err("token"))?,
}; };
Ok(AdyenPaymentMethod::Gpay(gpay_data)) Ok(AdyenPaymentMethod::Gpay(gpay_data))
} }
api_models::payments::WalletData::ApplePay(data) => {
api_enums::WalletIssuer::ApplePay => {
let apple_pay_data = AdyenApplePay { let apple_pay_data = AdyenApplePay {
payment_type: PaymentType::Applepay, payment_type: PaymentType::Applepay,
apple_pay_token: wallet_data apple_pay_token:
.token consts::BASE64_ENGINE.encode(
.clone() common_utils::ext_traits::Encode::<
.ok_or_else(utils::missing_field_err("token"))?, api_models::payments::ApplepayPaymentData,
>::encode_to_string_of_json(
&data.payment_data
)
.change_context(errors::ConnectorError::RequestEncodingFailed)?,
),
}; };
Ok(AdyenPaymentMethod::ApplePay(apple_pay_data)) Ok(AdyenPaymentMethod::ApplePay(apple_pay_data))
} }
api_enums::WalletIssuer::Paypal => { api_models::payments::WalletData::PaypalSdk(_) => {
Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into())
}
api_models::payments::WalletData::PaypalRedirect(_) => {
let wallet = AdyenPaypal { let wallet = AdyenPaypal {
payment_type: PaymentType::Paypal, payment_type: PaymentType::Paypal,
}; };

View File

@ -171,7 +171,7 @@ impl<F>
Ok(Self { Ok(Self {
response: Ok(types::PaymentsResponseData::SessionResponse { response: Ok(types::PaymentsResponseData::SessionResponse {
session_token: { session_token: {
api_models::payments::SessionToken::Applepay(Box::new( api_models::payments::SessionToken::ApplePay(Box::new(
payments::ApplepaySessionTokenResponse { payments::ApplepaySessionTokenResponse {
session_token_data: applepay_session.into(), session_token_data: applepay_session.into(),
payment_request_data: payment_request.into(), payment_request_data: payment_request.into(),

View File

@ -1,6 +1,5 @@
use api_models::payments; use api_models::payments;
use base64::Engine; use base64::Engine;
use error_stack::ResultExt;
use masking::Secret; use masking::Secret;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -8,7 +7,6 @@ use crate::{
consts, consts,
core::errors, core::errors,
types::{self, api, storage::enums}, types::{self, api, storage::enums},
utils::OptionExt,
}; };
#[derive(Default, Debug, Serialize, Eq, PartialEq)] #[derive(Default, Debug, Serialize, Eq, PartialEq)]
@ -111,12 +109,12 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for BraintreePaymentsRequest {
})), })),
api::PaymentMethodData::Wallet(ref wallet_data) => { api::PaymentMethodData::Wallet(ref wallet_data) => {
Ok(PaymentMethodType::PaymentMethodNonce(Nonce { Ok(PaymentMethodType::PaymentMethodNonce(Nonce {
payment_method_nonce: wallet_data payment_method_nonce: match wallet_data {
.token api_models::payments::WalletData::PaypalSdk(wallet_data) => {
.to_owned() Ok(wallet_data.token.to_owned())
.get_required_value("token") }
.change_context(errors::ConnectorError::RequestEncodingFailed) _ => Err(errors::ConnectorError::InvalidWallet),
.attach_printable("No token passed")?, }?,
})) }))
} }
_ => Err(errors::ConnectorError::NotImplemented(format!( _ => Err(errors::ConnectorError::NotImplemented(format!(

View File

@ -8,7 +8,6 @@ use crate::{
core::errors, core::errors,
pii::{self, Secret}, pii::{self, Secret},
types::{self, api, storage::enums}, types::{self, api, storage::enums},
utils::OptionExt,
}; };
const WALLET_IDENTIFIER: &str = "PBL"; const WALLET_IDENTIFIER: &str = "PBL";
@ -78,33 +77,29 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PayuPaymentsRequest {
cvv: ccard.card_cvc, cvv: ccard.card_cvc,
}), }),
}), }),
api::PaymentMethodData::Wallet(wallet_data) => match wallet_data.issuer_name { api::PaymentMethodData::Wallet(wallet_data) => match wallet_data {
api_models::enums::WalletIssuer::GooglePay => Ok(PayuPaymentMethod { api_models::payments::WalletData::GooglePay(data) => Ok(PayuPaymentMethod {
pay_method: PayuPaymentMethodData::Wallet({ pay_method: PayuPaymentMethodData::Wallet({
PayuWallet { PayuWallet {
value: PayuWalletCode::Ap, value: PayuWalletCode::Ap,
wallet_type: WALLET_IDENTIFIER.to_string(), wallet_type: WALLET_IDENTIFIER.to_string(),
authorization_code: consts::BASE64_ENGINE.encode( authorization_code: consts::BASE64_ENGINE
wallet_data .encode(data.tokenization_data.token),
.token
.get_required_value("token")
.change_context(errors::ConnectorError::RequestEncodingFailed)
.attach_printable("No token passed")?,
),
} }
}), }),
}), }),
api_models::enums::WalletIssuer::ApplePay => Ok(PayuPaymentMethod { api_models::payments::WalletData::ApplePay(data) => Ok(PayuPaymentMethod {
pay_method: PayuPaymentMethodData::Wallet({ pay_method: PayuPaymentMethodData::Wallet({
PayuWallet { PayuWallet {
value: PayuWalletCode::Jp, value: PayuWalletCode::Jp,
wallet_type: WALLET_IDENTIFIER.to_string(), wallet_type: WALLET_IDENTIFIER.to_string(),
authorization_code: consts::BASE64_ENGINE.encode( authorization_code: consts::BASE64_ENGINE.encode(
wallet_data common_utils::ext_traits::Encode::<
.token api_models::payments::ApplepayPaymentData,
.get_required_value("token") >::encode_to_string_of_json(
.change_context(errors::ConnectorError::RequestEncodingFailed) &data.payment_data
.attach_printable("No token passed")?, )
.change_context(errors::ConnectorError::RequestEncodingFailed)?,
), ),
} }
}), }),

View File

@ -1,3 +1,4 @@
use base64::Engine;
use error_stack::{IntoReport, ResultExt}; use error_stack::{IntoReport, ResultExt};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use url::Url; use url::Url;
@ -66,7 +67,7 @@ pub struct RapydWallet {
#[serde(rename = "type")] #[serde(rename = "type")]
payment_type: String, payment_type: String,
#[serde(rename = "details")] #[serde(rename = "details")]
apple_pay_token: Option<String>, token: Option<String>,
} }
impl TryFrom<&types::PaymentsAuthorizeRouterData> for RapydPaymentsRequest { impl TryFrom<&types::PaymentsAuthorizeRouterData> for RapydPaymentsRequest {
@ -104,14 +105,23 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for RapydPaymentsRequest {
}) })
} }
api_models::payments::PaymentMethodData::Wallet(ref wallet_data) => { api_models::payments::PaymentMethodData::Wallet(ref wallet_data) => {
let digital_wallet = match wallet_data.issuer_name { let digital_wallet = match wallet_data {
api_models::enums::WalletIssuer::GooglePay => Some(RapydWallet { api_models::payments::WalletData::GooglePay(data) => Some(RapydWallet {
payment_type: "google_pay".to_string(), payment_type: "google_pay".to_string(),
apple_pay_token: wallet_data.token.to_owned(), token: Some(data.tokenization_data.token.to_owned()),
}), }),
api_models::enums::WalletIssuer::ApplePay => Some(RapydWallet { api_models::payments::WalletData::ApplePay(data) => Some(RapydWallet {
payment_type: "apple_pay".to_string(), payment_type: "apple_pay".to_string(),
apple_pay_token: wallet_data.token.to_owned(), token: Some(
consts::BASE64_ENGINE.encode(
common_utils::ext_traits::Encode::<
api_models::payments::ApplepayPaymentData,
>::encode_to_string_of_json(
&data.payment_data
)
.change_context(errors::ConnectorError::RequestEncodingFailed)?,
),
),
}), }),
_ => None, _ => None,
}; };

View File

@ -1,12 +1,13 @@
use base64::Engine;
use common_utils::errors::CustomResult; use common_utils::errors::CustomResult;
use error_stack::ResultExt; use error_stack::ResultExt;
use storage_models::enums; use storage_models::enums;
use super::{requests::*, response::*}; use super::{requests::*, response::*};
use crate::{ use crate::{
consts,
core::errors, core::errors,
types::{self, api}, types::{self, api},
utils::OptionExt,
}; };
fn fetch_payment_instrument( fn fetch_payment_instrument(
@ -21,26 +22,27 @@ fn fetch_payment_instrument(
card_number: card.card_number, card_number: card.card_number,
..CardPayment::default() ..CardPayment::default()
})), })),
api::PaymentMethodData::Wallet(wallet) => match wallet.issuer_name { api::PaymentMethodData::Wallet(wallet) => match wallet {
api_models::enums::WalletIssuer::ApplePay => { api_models::payments::WalletData::GooglePay(data) => {
Ok(PaymentInstrument::Applepay(WalletPayment { Ok(PaymentInstrument::Googlepay(WalletPayment {
payment_type: PaymentType::Applepay, payment_type: PaymentType::Googlepay,
wallet_token: wallet wallet_token: data.tokenization_data.token,
.token
.get_required_value("token")
.change_context(errors::ConnectorError::RequestEncodingFailed)
.attach_printable("No token passed")?,
..WalletPayment::default() ..WalletPayment::default()
})) }))
} }
api_models::enums::WalletIssuer::GooglePay => { api_models::payments::WalletData::ApplePay(data) => {
Ok(PaymentInstrument::Googlepay(WalletPayment { Ok(PaymentInstrument::Applepay(WalletPayment {
payment_type: PaymentType::Googlepay, payment_type: PaymentType::Applepay,
wallet_token: wallet
.token wallet_token:
.get_required_value("token") consts::BASE64_ENGINE.encode(
.change_context(errors::ConnectorError::RequestEncodingFailed) common_utils::ext_traits::Encode::<
.attach_printable("No token passed")?, api_models::payments::ApplepayPaymentData,
>::encode_to_string_of_json(
&data.payment_data
)
.change_context(errors::ConnectorError::RequestEncodingFailed)?,
),
..WalletPayment::default() ..WalletPayment::default()
})) }))
} }

View File

@ -234,6 +234,8 @@ pub enum ConnectorError {
FailedToObtainPreferredConnector, FailedToObtainPreferredConnector,
#[error("An invalid connector name was provided")] #[error("An invalid connector name was provided")]
InvalidConnectorName, InvalidConnectorName,
#[error("An invalid Wallet was used")]
InvalidWallet,
#[error("Failed to handle connector response")] #[error("Failed to handle connector response")]
ResponseHandlingFailed, ResponseHandlingFailed,
#[error("Missing required field: {field_name}")] #[error("Missing required field: {field_name}")]

View File

@ -1,5 +1,3 @@
use std::str::FromStr;
use common_utils::generate_id_with_default_len; use common_utils::generate_id_with_default_len;
use error_stack::{IntoReport, ResultExt}; use error_stack::{IntoReport, ResultExt};
use masking::PeekInterface; use masking::PeekInterface;
@ -103,8 +101,7 @@ impl Vaultable for api::Card {
impl Vaultable for api::WalletData { impl Vaultable for api::WalletData {
fn get_value1(&self, _customer_id: Option<String>) -> CustomResult<String, errors::VaultError> { fn get_value1(&self, _customer_id: Option<String>) -> CustomResult<String, errors::VaultError> {
let value1 = api::TokenizedWalletValue1 { let value1 = api::TokenizedWalletValue1 {
issuer: self.issuer_name.to_string(), data: self.to_owned(),
token: self.token.clone(),
}; };
utils::Encode::<api::TokenizedWalletValue1>::encode_to_string_of_json(&value1) utils::Encode::<api::TokenizedWalletValue1>::encode_to_string_of_json(&value1)
@ -134,13 +131,7 @@ impl Vaultable for api::WalletData {
.change_context(errors::VaultError::ResponseDeserializationFailed) .change_context(errors::VaultError::ResponseDeserializationFailed)
.attach_printable("Could not deserialize into wallet data value2")?; .attach_printable("Could not deserialize into wallet data value2")?;
let wallet = Self { let wallet = value1.data;
issuer_name: api::enums::WalletIssuer::from_str(&value1.issuer)
.into_report()
.change_context(errors::VaultError::ResponseDeserializationFailed)
.attach_printable("Invalid issuer name when deserializing wallet data")?,
token: value1.token,
};
let supp_data = SupplementaryVaultData { let supp_data = SupplementaryVaultData {
customer_id: value2.customer_id, customer_id: value2.customer_id,

View File

@ -91,7 +91,7 @@ fn create_gpay_session_token(
let response_router_data = types::PaymentsSessionRouterData { let response_router_data = types::PaymentsSessionRouterData {
response: Ok(types::PaymentsResponseData::SessionResponse { response: Ok(types::PaymentsResponseData::SessionResponse {
session_token: payment_types::SessionToken::Gpay(Box::new( session_token: payment_types::SessionToken::GooglePay(Box::new(
payment_types::GpaySessionTokenResponse { payment_types::GpaySessionTokenResponse {
merchant_info: gpay_data.data.merchant_info, merchant_info: gpay_data.data.merchant_info,
allowed_payment_methods: gpay_data.data.allowed_payment_methods, allowed_payment_methods: gpay_data.data.allowed_payment_methods,

View File

@ -721,7 +721,9 @@ pub async fn make_pm_data<'a, F: Clone, R>(
payment_data.payment_attempt.payment_method = payment_data.payment_attempt.payment_method =
Some(storage_enums::PaymentMethod::Wallet); Some(storage_enums::PaymentMethod::Wallet);
// TODO: Remove redundant update from wallets. // TODO: Remove redundant update from wallets.
if wallet_data.token.is_some() { match wallet_data {
api_models::payments::WalletData::PaypalRedirect(_) => pm,
_ => {
let updated_pm = api::PaymentMethodData::Wallet(wallet_data); let updated_pm = api::PaymentMethodData::Wallet(wallet_data);
vault::Vault::store_payment_method_data_in_locker( vault::Vault::store_payment_method_data_in_locker(
state, state,
@ -731,8 +733,7 @@ pub async fn make_pm_data<'a, F: Clone, R>(
) )
.await?; .await?;
Some(updated_pm) Some(updated_pm)
} else { }
pm
} }
} }

View File

@ -124,6 +124,8 @@ Never share your secret api keys. Keep them guarded and secure.
crate::types::api::payment_methods::CardDetailFromLocker, crate::types::api::payment_methods::CardDetailFromLocker,
crate::types::api::payment_methods::CardDetail, crate::types::api::payment_methods::CardDetail,
api_models::customers::CustomerResponse, api_models::customers::CustomerResponse,
api_models::admin::AcceptedCountries,
api_models::admin::AcceptedCurrencies,
api_models::enums::RoutingAlgorithm, api_models::enums::RoutingAlgorithm,
api_models::enums::PaymentMethod, api_models::enums::PaymentMethod,
api_models::enums::PaymentMethodType, api_models::enums::PaymentMethodType,
@ -133,17 +135,19 @@ Never share your secret api keys. Keep them guarded and secure.
api_models::enums::CaptureMethod, api_models::enums::CaptureMethod,
api_models::enums::FutureUsage, api_models::enums::FutureUsage,
api_models::enums::AuthenticationType, api_models::enums::AuthenticationType,
api_models::enums::WalletIssuer,
api_models::enums::Connector, api_models::enums::Connector,
api_models::enums::PaymentMethod, api_models::enums::PaymentMethod,
api_models::enums::SupportedWallets, api_models::enums::SupportedWallets,
api_models::enums::PaymentMethodIssuerCode, api_models::enums::PaymentMethodIssuerCode,
api_models::enums::MandateStatus, api_models::enums::MandateStatus,
api_models::enums::PaymentExperience, api_models::enums::PaymentExperience,
api_models::enums::BankNames,
api_models::admin::PaymentConnectorCreate, api_models::admin::PaymentConnectorCreate,
api_models::admin::PaymentMethodsEnabled, api_models::admin::PaymentMethodsEnabled,
api_models::payments::AddressDetails, api_models::payments::AddressDetails,
api_models::payments::Address, api_models::payments::Address,
api_models::payments::BankRedirectData,
api_models::payments::BankRedirectBilling,
api_models::payments::OrderDetails, api_models::payments::OrderDetails,
api_models::payments::NextActionType, api_models::payments::NextActionType,
api_models::payments::Metadata, api_models::payments::Metadata,
@ -172,6 +176,9 @@ Never share your secret api keys. Keep them guarded and secure.
api_models::payments::ApplePaySessionResponse, api_models::payments::ApplePaySessionResponse,
api_models::payments::ApplePayPaymentRequest, api_models::payments::ApplePayPaymentRequest,
api_models::payments::AmountInfo, api_models::payments::AmountInfo,
api_models::payments::GpayWalletData,
api_models::payments::PayPalWalletData,
api_models::payments::PaypalRedirection,
api_models::payments::GpayMerchantInfo, api_models::payments::GpayMerchantInfo,
api_models::payments::GpayAllowedPaymentMethods, api_models::payments::GpayAllowedPaymentMethods,
api_models::payments::GpayAllowedMethodsParameters, api_models::payments::GpayAllowedMethodsParameters,
@ -182,6 +189,12 @@ Never share your secret api keys. Keep them guarded and secure.
api_models::payments::KlarnaSessionTokenResponse, api_models::payments::KlarnaSessionTokenResponse,
api_models::payments::PaypalSessionTokenResponse, api_models::payments::PaypalSessionTokenResponse,
api_models::payments::ApplepaySessionTokenResponse, api_models::payments::ApplepaySessionTokenResponse,
api_models::payments::GpayTokenizationData,
api_models::payments::GpayPaymentMethodInfo,
api_models::payments::ApplePayWalletData,
api_models::payments::ApplepayPaymentData,
api_models::payments::ApplepayHeader,
api_models::payments::ApplepayPaymentMethod,
api_models::payments::PaymentsCancelRequest, api_models::payments::PaymentsCancelRequest,
api_models::payments::PaymentListConstraints, api_models::payments::PaymentListConstraints,
api_models::payments::PaymentListResponse, api_models::payments::PaymentListResponse,

View File

@ -84,15 +84,30 @@ async fn should_authorize_card_payment() {
#[actix_web::test] #[actix_web::test]
async fn should_authorize_gpay_payment() { async fn should_authorize_gpay_payment() {
let authorize_response = Payu {}.authorize_payment(Some(types::PaymentsAuthorizeData{ let authorize_response = Payu {}
payment_method_data: types::api::PaymentMethodData::Wallet(api::WalletData{ .authorize_payment(
issuer_name: api_models::enums::WalletIssuer::GooglePay, Some(types::PaymentsAuthorizeData {
token: Some(r#"{"signature":"MEUCIQD7Ta+d9+buesrH2KKkF+03AqTen+eHHN8KFleHoKaiVAIgGvAXyI0Vg3ws8KlF7agW/gmXJhpJOOPkqiNVbn/4f0Y\u003d","protocolVersion":"ECv1","signedMessage":"{\"encryptedMessage\":\"UcdGP9F/1loU0aXvVj6VqGRPA5EAjHYfJrXD0N+5O13RnaJXKWIjch1zzjpy9ONOZHqEGAqYKIcKcpe5ppN4Fpd0dtbm1H4u+lA+SotCff3euPV6sne22/Pl/MNgbz5QvDWR0UjcXvIKSPNwkds1Ib7QMmH4GfZ3vvn6s534hxAmcv/LlkeM4FFf6py9crJK5fDIxtxRJncfLuuPeAXkyy+u4zE33HmT34Oe5MSW/kYZVz31eWqFy2YCIjbJcC9ElMluoOKSZ305UG7tYGB1LCFGQLtLxphrhPu1lEmGEZE1t2cVDoCzjr3rm1OcfENc7eNC4S+ko6yrXh1ZX06c/F9kunyLn0dAz8K5JLIwLdjw3wPADVSd3L0eM7jkzhH80I6nWkutO0x8BFltxWl+OtzrnAe093OUncH6/DK1pCxtJaHdw1WUWrzULcdaMZmPfA\\u003d\\u003d\",\"ephemeralPublicKey\":\"BH7A1FUBWiePkjh/EYmsjY/63D/6wU+4UmkLh7WW6v7PnoqQkjrFpc4kEP5a1Op4FkIlM9LlEs3wGdFB8xIy9cM\\u003d\",\"tag\":\"e/EOsw2Y2wYpJngNWQqH7J62Fhg/tzmgDl6UFGuAN+A\\u003d\"}"}"# payment_method_data: types::api::PaymentMethodData::Wallet(api::WalletData::GooglePay(
.to_string()) //Generate new GooglePay token this is bound to expire api_models::payments::GpayWalletData {
}), pm_type: "CARD".to_string(),
description: "Visa1234567890".to_string(),
info: api_models::payments::GpayPaymentMethodInfo {
card_network: "VISA".to_string(),
card_details: "1234".to_string(),
},
tokenization_data: api_models::payments::GpayTokenizationData {
token_type: "payu".to_string(),
token: r#"{"signature":"MEUCIQD7Ta+d9+buesrH2KKkF+03AqTen+eHHN8KFleHoKaiVAIgGvAXyI0Vg3ws8KlF7agW/gmXJhpJOOPkqiNVbn/4f0Y\u003d","protocolVersion":"ECv1","signedMessage":"{\"encryptedMessage\":\"UcdGP9F/1loU0aXvVj6VqGRPA5EAjHYfJrXD0N+5O13RnaJXKWIjch1zzjpy9ONOZHqEGAqYKIcKcpe5ppN4Fpd0dtbm1H4u+lA+SotCff3euPV6sne22/Pl/MNgbz5QvDWR0UjcXvIKSPNwkds1Ib7QMmH4GfZ3vvn6s534hxAmcv/LlkeM4FFf6py9crJK5fDIxtxRJncfLuuPeAXkyy+u4zE33HmT34Oe5MSW/kYZVz31eWqFy2YCIjbJcC9ElMluoOKSZ305UG7tYGB1LCFGQLtLxphrhPu1lEmGEZE1t2cVDoCzjr3rm1OcfENc7eNC4S+ko6yrXh1ZX06c/F9kunyLn0dAz8K5JLIwLdjw3wPADVSd3L0eM7jkzhH80I6nWkutO0x8BFltxWl+OtzrnAe093OUncH6/DK1pCxtJaHdw1WUWrzULcdaMZmPfA\\u003d\\u003d\",\"ephemeralPublicKey\":\"BH7A1FUBWiePkjh/EYmsjY/63D/6wU+4UmkLh7WW6v7PnoqQkjrFpc4kEP5a1Op4FkIlM9LlEs3wGdFB8xIy9cM\\u003d\",\"tag\":\"e/EOsw2Y2wYpJngNWQqH7J62Fhg/tzmgDl6UFGuAN+A\\u003d\"}"}"# .to_string()//Generate new GooglePay token this is bound to expire
},
},
)),
currency: enums::Currency::PLN, currency: enums::Currency::PLN,
..PaymentAuthorizeType::default().0 ..PaymentAuthorizeType::default().0
}), get_default_payment_info()).await.unwrap(); }),
get_default_payment_info(),
)
.await
.unwrap();
assert_eq!(authorize_response.status, enums::AttemptStatus::Pending); assert_eq!(authorize_response.status, enums::AttemptStatus::Pending);
if let Some(transaction_id) = utils::get_connector_transaction_id(authorize_response.response) { if let Some(transaction_id) = utils::get_connector_transaction_id(authorize_response.response) {
let sync_response = Payu {} let sync_response = Payu {}

View File

@ -1,9 +1,5 @@
use futures::future::OptionFuture; use futures::future::OptionFuture;
use router::types::{ use router::types::{self, api, storage::enums};
self,
api::{self, enums as api_enums},
storage::enums,
};
use serde_json::json; use serde_json::json;
use serial_test::serial; use serial_test::serial;
use wiremock::{ use wiremock::{
@ -64,10 +60,20 @@ async fn should_authorize_gpay_payment() {
let response = conn let response = conn
.authorize_payment( .authorize_payment(
Some(types::PaymentsAuthorizeData { Some(types::PaymentsAuthorizeData {
payment_method_data: types::api::PaymentMethodData::Wallet(api::WalletData { payment_method_data: types::api::PaymentMethodData::Wallet(
issuer_name: api_enums::WalletIssuer::GooglePay, api::WalletData::GooglePay(api_models::payments::GpayWalletData {
token: Some("someToken".to_string()), pm_type: "CARD".to_string(),
description: "Visa1234567890".to_string(),
info: api_models::payments::GpayPaymentMethodInfo {
card_network: "VISA".to_string(),
card_details: "1234".to_string(),
},
tokenization_data: api_models::payments::GpayTokenizationData {
token_type: "worldpay".to_string(),
token: "someToken".to_string(),
},
}), }),
),
..utils::PaymentAuthorizeType::default().0 ..utils::PaymentAuthorizeType::default().0
}), }),
None, None,
@ -89,10 +95,26 @@ async fn should_authorize_applepay_payment() {
let response = conn let response = conn
.authorize_payment( .authorize_payment(
Some(types::PaymentsAuthorizeData { Some(types::PaymentsAuthorizeData {
payment_method_data: types::api::PaymentMethodData::Wallet(api::WalletData { payment_method_data: types::api::PaymentMethodData::Wallet(
issuer_name: api_enums::WalletIssuer::ApplePay, api::WalletData::ApplePay(api_models::payments::ApplePayWalletData {
token: Some("someToken".to_string()), payment_data: api_models::payments::ApplepayPaymentData {
data: "someData".to_string(),
signature: "someSignature".to_string(),
version: "someVersion".to_string(),
header: api_models::payments::ApplepayHeader {
public_key_hash: "someHash".to_string(),
ephemeral_public_key: "someKey".to_string(),
transaction_id: "someId".to_string(),
},
},
transaction_identifier: "someId".to_string(),
payment_method: api_models::payments::ApplepayPaymentMethod {
display_name: "someName".to_string(),
network: "visa".to_string(),
pm_type: "card".to_string(),
},
}), }),
),
..utils::PaymentAuthorizeType::default().0 ..utils::PaymentAuthorizeType::default().0
}), }),
None, None,

View File

@ -431,7 +431,6 @@ pub enum PaymentMethod {
Card, Card,
PayLater, PayLater,
Wallet, Wallet,
BankRedirect,
} }
#[derive( #[derive(

File diff suppressed because it is too large Load Diff