feat(connector): [Adyen] Add support for gift cards balance (#1672)

This commit is contained in:
Sangamesh Kulkarni
2023-08-03 16:36:26 +05:30
committed by GitHub
parent 2dec2ca50b
commit c4796ffdb7
16 changed files with 373 additions and 44 deletions

View File

@ -727,19 +727,22 @@ pub enum PaymentMethodData {
#[derive(serde::Deserialize, serde::Serialize, Debug, Clone, ToSchema, Eq, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum GiftCardData {
BabyGiftCard {
/// The gift card number
#[schema(value_type = String)]
number: Secret<String>,
/// The card verification code.
#[schema(value_type = String)]
cvc: Secret<String>,
},
Givex(GiftCardDetails),
PaySafeCard {},
}
#[derive(serde::Deserialize, serde::Serialize, Debug, Clone, ToSchema, Eq, PartialEq)]
#[serde(rename_all = "snake_case")]
pub struct GiftCardDetails {
/// The gift card number
#[schema(value_type = String)]
pub number: Secret<String>,
/// The card verification code.
#[schema(value_type = String)]
pub cvc: Secret<String>,
}
#[derive(Default, Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub struct AdditionalCardInfo {

View File

@ -897,6 +897,7 @@ pub enum PaymentMethodType {
Eps,
Evoucher,
Giropay,
Givex,
GooglePay,
GoPay,
Gcash,

View File

@ -1605,6 +1605,7 @@ impl From<PaymentMethodType> for PaymentMethod {
PaymentMethodType::RedCompra => Self::Voucher,
PaymentMethodType::RedPagos => Self::Voucher,
PaymentMethodType::Cashapp => Self::Wallet,
PaymentMethodType::Givex => Self::GiftCard,
}
}
}

View File

@ -13,9 +13,12 @@ use self::transformers as adyen;
use crate::{
configs::settings,
consts,
core::errors::{self, CustomResult},
core::{
self,
errors::{self, CustomResult},
},
db::StorageInterface,
headers, logger,
headers, logger, routes,
services::{
self,
request::{self, Mask},
@ -477,6 +480,7 @@ impl
}
}
#[async_trait::async_trait]
impl
services::ConnectorIntegration<
api::Authorize,
@ -484,6 +488,49 @@ impl
types::PaymentsResponseData,
> for Adyen
{
async fn execute_pretasks(
&self,
router_data: &mut types::PaymentsAuthorizeRouterData,
app_state: &routes::AppState,
) -> CustomResult<(), errors::ConnectorError> {
match &router_data.request.payment_method_data {
api_models::payments::PaymentMethodData::GiftCard(gift_card_data) => {
match gift_card_data.as_ref() {
api_models::payments::GiftCardData::Givex(_) => {
let integ: Box<
&(dyn services::ConnectorIntegration<
api::Balance,
types::PaymentsAuthorizeData,
types::PaymentsResponseData,
> + Send
+ Sync
+ 'static),
> = Box::new(&Self);
let authorize_data = &types::PaymentsBalanceRouterData::from((
&router_data.to_owned(),
router_data.request.clone(),
));
let resp = services::execute_connector_processing_step(
app_state,
integ,
authorize_data,
core::payments::CallConnectorAction::Trigger,
None,
)
.await?;
router_data.payment_method_balance = resp.payment_method_balance;
Ok(())
}
_ => Ok(()),
}
}
_ => Ok(()),
}
}
fn get_headers(
&self,
req: &types::PaymentsAuthorizeRouterData,
@ -520,13 +567,12 @@ impl
req: &types::PaymentsAuthorizeRouterData,
) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> {
let connector_req = adyen::AdyenPaymentRequest::try_from(req)?;
let adyen_req = types::RequestBody::log_and_get_request_body(
&connector_req,
utils::Encode::<adyen::AdyenPaymentRequest<'_>>::encode_to_string_of_json,
)
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
Ok(Some(adyen_req))
let request_body = types::RequestBody::log_and_get_request_body(
&connector_req,
common_utils::ext_traits::Encode::<adyen::AdyenPaymentRequest<'_>>::encode_to_string_of_json,
)
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
Ok(Some(request_body))
}
fn build_request(
@ -534,6 +580,7 @@ impl
req: &types::PaymentsAuthorizeRouterData,
connectors: &settings::Connectors,
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
check_for_payment_method_balance(req)?;
Ok(Some(
services::RequestBuilder::new()
.method(services::Method::Post)
@ -588,6 +635,104 @@ impl
}
}
impl
services::ConnectorIntegration<
api::Balance,
types::PaymentsAuthorizeData,
types::PaymentsResponseData,
> for Adyen
{
fn get_headers(
&self,
req: &types::PaymentsBalanceRouterData,
_connectors: &settings::Connectors,
) -> CustomResult<Vec<(String, request::Maskable<String>)>, errors::ConnectorError>
where
Self: services::ConnectorIntegration<
api::Balance,
types::PaymentsAuthorizeData,
types::PaymentsResponseData,
>,
{
let mut header = vec![(
headers::CONTENT_TYPE.to_string(),
types::PaymentsBalanceType::get_content_type(self)
.to_string()
.into(),
)];
let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
header.append(&mut api_key);
Ok(header)
}
fn get_url(
&self,
_req: &types::PaymentsBalanceRouterData,
connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
Ok(format!(
"{}v69/paymentMethods/balance",
self.base_url(connectors)
))
}
fn get_request_body(
&self,
req: &types::PaymentsBalanceRouterData,
) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> {
let connector_req = adyen::AdyenBalanceRequest::try_from(req)?;
let adyen_req = types::RequestBody::log_and_get_request_body(
&connector_req,
utils::Encode::<adyen::AdyenBalanceRequest<'_>>::encode_to_string_of_json,
)
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
Ok(Some(adyen_req))
}
fn build_request(
&self,
req: &types::PaymentsBalanceRouterData,
connectors: &settings::Connectors,
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
Ok(Some(
services::RequestBuilder::new()
.method(services::Method::Post)
.url(&types::PaymentsBalanceType::get_url(self, req, connectors)?)
.attach_default_headers()
.headers(types::PaymentsBalanceType::get_headers(
self, req, connectors,
)?)
.body(types::PaymentsBalanceType::get_request_body(self, req)?)
.build(),
))
}
fn handle_response(
&self,
data: &types::PaymentsBalanceRouterData,
res: types::Response,
) -> CustomResult<types::PaymentsBalanceRouterData, errors::ConnectorError> {
let response: adyen::AdyenBalanceResponse = res
.response
.parse_struct("AdyenBalanceResponse")
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
types::RouterData::try_from(types::ResponseRouterData {
response,
data: data.clone(),
http_code: res.status_code,
})
.change_context(errors::ConnectorError::ResponseHandlingFailed)
}
fn get_error_response(
&self,
res: types::Response,
) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
self.build_error_response(res)
}
}
impl
services::ConnectorIntegration<
api::Void,
@ -1352,3 +1497,27 @@ impl api::IncomingWebhook for Adyen {
})
}
}
pub fn check_for_payment_method_balance(
req: &types::PaymentsAuthorizeRouterData,
) -> CustomResult<(), errors::ConnectorError> {
match &req.request.payment_method_data {
api_models::payments::PaymentMethodData::GiftCard(gift_card) => match gift_card.as_ref() {
api_models::payments::GiftCardData::Givex(_) => {
let payment_method_balance = req
.payment_method_balance
.as_ref()
.ok_or(errors::ConnectorError::RequestEncodingFailed)?;
if payment_method_balance.currency != req.request.currency.to_string()
|| payment_method_balance.amount < req.request.amount
{
Err(errors::ConnectorError::InSufficientBalanceInPaymentMethod.into())
} else {
Ok(())
}
}
_ => Ok(()),
},
_ => Ok(()),
}
}

View File

@ -173,6 +173,20 @@ pub enum Channel {
Web,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AdyenBalanceRequest<'a> {
pub payment_method: AdyenPaymentMethod<'a>,
pub merchant_account: Secret<String>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AdyenBalanceResponse {
psp_reference: String,
balance: Amount,
}
/// This implementation will be used only in Authorize, Automatic capture flow.
/// It is also being used in Psync flow, However Psync will be called only after create payment call that too in redirect flow.
impl ForeignFrom<(bool, AdyenStatus)> for storage_enums::AttemptStatus {
@ -433,10 +447,31 @@ pub enum AdyenPaymentMethod<'a> {
Indomaret(Box<DokuBankData>),
#[serde(rename = "doku_alfamart")]
Alfamart(Box<DokuBankData>),
PaymentMethodBalance(Box<BalancePmData>),
AdyenGiftCard(Box<GiftCardData>),
#[serde(rename = "swish")]
Swish,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct BalancePmData {
#[serde(rename = "type")]
payment_type: GiftCardBrand,
number: Secret<String>,
cvc: Secret<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GiftCardData {
#[serde(rename = "type")]
payment_type: PaymentType,
brand: GiftCardBrand,
number: Secret<String>,
cvc: Secret<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AchDirectDebitData {
@ -963,6 +998,7 @@ pub enum PaymentType {
Samsungpay,
Twint,
Vipps,
Giftcard,
Swish,
#[serde(rename = "doku_permata_lite_atm")]
PermataBankTransfer,
@ -980,6 +1016,14 @@ pub enum PaymentType {
MandiriVa,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum GiftCardBrand {
Givex,
Auriga,
Babygiftcard,
}
#[derive(Debug, Eq, PartialEq, Serialize, Clone)]
#[serde(rename_all = "snake_case")]
pub enum OnlineBankingFpxIssuer {
@ -1136,8 +1180,8 @@ impl<'a> TryFrom<&types::PaymentsAuthorizeRouterData> for AdyenPaymentRequest<'a
api_models::payments::PaymentMethodData::Voucher(ref voucher_data) => {
AdyenPaymentRequest::try_from((item, voucher_data))
}
api_models::payments::PaymentMethodData::GiftCard(ref gift_card) => {
AdyenPaymentRequest::try_from((item, gift_card.as_ref()))
api_models::payments::PaymentMethodData::GiftCard(ref gift_card_data) => {
AdyenPaymentRequest::try_from((item, gift_card_data.as_ref()))
}
_ => Err(errors::ConnectorError::NotSupported {
message: format!("{:?}", item.request.payment_method_type),
@ -1150,6 +1194,41 @@ impl<'a> TryFrom<&types::PaymentsAuthorizeRouterData> for AdyenPaymentRequest<'a
}
}
impl<'a> TryFrom<&types::PaymentsBalanceRouterData> for AdyenBalanceRequest<'a> {
type Error = Error;
fn try_from(item: &types::PaymentsBalanceRouterData) -> Result<Self, Self::Error> {
let payment_method = match &item.request.payment_method_data {
payments::PaymentMethodData::GiftCard(gift_card_data) => {
match gift_card_data.as_ref() {
payments::GiftCardData::Givex(gift_card_data) => {
let balance_pm = BalancePmData {
payment_type: GiftCardBrand::Givex,
number: gift_card_data.number.clone(),
cvc: gift_card_data.cvc.clone(),
};
Ok(AdyenPaymentMethod::PaymentMethodBalance(Box::new(
balance_pm,
)))
}
_ => Err(errors::ConnectorError::FlowNotSupported {
flow: "Balance".to_string(),
connector: "adyen".to_string(),
}),
}
}
_ => Err(errors::ConnectorError::FlowNotSupported {
flow: "Balance".to_string(),
connector: "adyen".to_string(),
}),
}?;
let auth_type = AdyenAuthType::try_from(&item.connector_auth_type)?;
Ok(Self {
payment_method,
merchant_account: auth_type.merchant_account,
})
}
}
impl From<&types::PaymentsAuthorizeRouterData> for AdyenShopperInteraction {
fn from(item: &types::PaymentsAuthorizeRouterData) -> Self {
match item.request.off_session {
@ -1430,8 +1509,14 @@ impl<'a> TryFrom<&api_models::payments::GiftCardData> for AdyenPaymentMethod<'a>
fn try_from(gift_card_data: &api_models::payments::GiftCardData) -> Result<Self, Self::Error> {
match gift_card_data {
payments::GiftCardData::PaySafeCard {} => Ok(AdyenPaymentMethod::PaySafeCard),
payments::GiftCardData::BabyGiftCard { .. } => {
Err(errors::ConnectorError::NotImplemented("Payment method".to_string()).into())
payments::GiftCardData::Givex(givex_data) => {
let gift_card_pm = GiftCardData {
payment_type: PaymentType::Giftcard,
brand: GiftCardBrand::Givex,
number: givex_data.number.clone(),
cvc: givex_data.cvc.clone(),
};
Ok(AdyenPaymentMethod::AdyenGiftCard(Box::new(gift_card_pm)))
}
}
}
@ -2396,6 +2481,31 @@ impl TryFrom<types::PaymentsCancelResponseRouterData<AdyenCancelResponse>>
}
}
impl TryFrom<types::PaymentsBalanceResponseRouterData<AdyenBalanceResponse>>
for types::PaymentsBalanceRouterData
{
type Error = Error;
fn try_from(
item: types::PaymentsBalanceResponseRouterData<AdyenBalanceResponse>,
) -> Result<Self, Self::Error> {
Ok(Self {
response: Ok(types::PaymentsResponseData::TransactionResponse {
resource_id: types::ResponseId::ConnectorTransactionId(item.response.psp_reference),
redirection_data: None,
mandate_reference: None,
connector_metadata: None,
network_txn_id: None,
connector_response_reference_id: None,
}),
payment_method_balance: Some(types::PaymentMethodBalance {
amount: item.response.balance.value,
currency: item.response.balance.currency,
}),
..item.data
})
}
}
pub fn get_adyen_response(
response: Response,
is_capture_manual: bool,
@ -2734,6 +2844,7 @@ pub fn get_wait_screen_metadata(
| PaymentType::BriVa
| PaymentType::CimbVa
| PaymentType::DanamonVa
| PaymentType::Giftcard
| PaymentType::MandiriVa
| PaymentType::PaySafeCard => Ok(None),
}
@ -2764,6 +2875,7 @@ pub fn get_present_to_shopper_metadata(
| PaymentType::BriVa
| PaymentType::CimbVa
| PaymentType::DanamonVa
| PaymentType::Giftcard
| PaymentType::MandiriVa => {
let voucher_data = payments::BankTransferInstructions::DokuBankTransferInstructions(
Box::new(payments::DokuBankTransferInstructions {

View File

@ -313,6 +313,8 @@ pub enum ConnectorError {
FailedAtConnector { message: String, code: String },
#[error("Payment Method Type not found")]
MissingPaymentMethodType,
#[error("Balance in the payment method is low")]
InSufficientBalanceInPaymentMethod,
}
#[derive(Debug, thiserror::Error)]

View File

@ -1505,6 +1505,7 @@ pub fn validate_payment_method_type_against_payment_method(
| api_enums::PaymentMethodType::Gcash
| api_enums::PaymentMethodType::Momo
| api_enums::PaymentMethodType::KakaoPay
| api_enums::PaymentMethodType::Cashapp
),
api_enums::PaymentMethod::BankRedirect => matches!(
payment_method_type,
@ -1570,10 +1571,12 @@ pub fn validate_payment_method_type_against_payment_method(
| api_enums::PaymentMethodType::Indomaret
| api_enums::PaymentMethodType::Alfamart
),
api_enums::PaymentMethod::GiftCard => matches!(
payment_method_type,
api_enums::PaymentMethodType::PaySafeCard
),
api_enums::PaymentMethod::GiftCard => {
matches!(
payment_method_type,
api_enums::PaymentMethodType::Givex | api_enums::PaymentMethodType::PaySafeCard
)
}
}
}
@ -2408,6 +2411,7 @@ pub fn router_data_type_conversion<F1, F2, Req1, Req2, Res1, Res2>(
customer_id: router_data.customer_id,
connector_customer: router_data.connector_customer,
preprocessing_id: router_data.preprocessing_id,
payment_method_balance: router_data.payment_method_balance,
recurring_mandate_payment_data: router_data.recurring_mandate_payment_data,
connector_request_reference_id: router_data.connector_request_reference_id,
#[cfg(feature = "payouts")]

View File

@ -137,6 +137,7 @@ where
#[cfg(feature = "payouts")]
quote_id: None,
test_mode,
payment_method_balance: None,
};
Ok(router_data)

View File

@ -181,6 +181,7 @@ pub async fn construct_payout_router_data<'a, F>(
payout_method_data: payout_data.payout_method_data.to_owned(),
quote_id: None,
test_mode,
payment_method_balance: None,
};
Ok(router_data)
@ -287,6 +288,7 @@ pub async fn construct_refund_router_data<'a, F>(
#[cfg(feature = "payouts")]
quote_id: None,
test_mode,
payment_method_balance: None,
};
Ok(router_data)
@ -503,6 +505,7 @@ pub async fn construct_accept_dispute_router_data<'a>(
#[cfg(feature = "payouts")]
quote_id: None,
test_mode,
payment_method_balance: None,
};
Ok(router_data)
}
@ -566,6 +569,7 @@ pub async fn construct_submit_evidence_router_data<'a>(
customer_id: None,
recurring_mandate_payment_data: None,
preprocessing_id: None,
payment_method_balance: None,
connector_request_reference_id: get_connector_request_reference_id(
&state.conf,
&merchant_account.merchant_id,
@ -640,6 +644,7 @@ pub async fn construct_upload_file_router_data<'a>(
customer_id: None,
recurring_mandate_payment_data: None,
preprocessing_id: None,
payment_method_balance: None,
connector_request_reference_id: get_connector_request_reference_id(
&state.conf,
&merchant_account.merchant_id,
@ -716,6 +721,7 @@ pub async fn construct_defend_dispute_router_data<'a>(
connector_customer: None,
recurring_mandate_payment_data: None,
preprocessing_id: None,
payment_method_balance: None,
connector_request_reference_id: get_connector_request_reference_id(
&state.conf,
&merchant_account.merchant_id,
@ -790,6 +796,7 @@ pub async fn construct_retrieve_file_router_data<'a>(
payment_method_token: None,
recurring_mandate_payment_data: None,
preprocessing_id: None,
payment_method_balance: None,
connector_request_reference_id: IRRELEVANT_CONNECTOR_REQUEST_REFERENCE_ID_IN_DISPUTE_FLOW
.to_string(),
#[cfg(feature = "payouts")]

View File

@ -297,6 +297,7 @@ Never share your secret api keys. Keep them guarded and secure.
api_models::ephemeral_key::EphemeralKeyCreateResponse,
api_models::payments::CustomerDetails,
api_models::payments::GiftCardData,
api_models::payments::GiftCardDetails,
api_models::payouts::PayoutCreateRequest,
api_models::payments::Address,
api_models::payouts::Card,

View File

@ -40,6 +40,8 @@ pub type PaymentsCompleteAuthorizeRouterData =
RouterData<api::CompleteAuthorize, CompleteAuthorizeData, PaymentsResponseData>;
pub type PaymentsInitRouterData =
RouterData<api::InitPayment, PaymentsAuthorizeData, PaymentsResponseData>;
pub type PaymentsBalanceRouterData =
RouterData<api::Balance, PaymentsAuthorizeData, PaymentsResponseData>;
pub type PaymentsSyncRouterData = RouterData<api::PSync, PaymentsSyncData, PaymentsResponseData>;
pub type PaymentsCaptureRouterData =
RouterData<api::Capture, PaymentsCaptureData, PaymentsResponseData>;
@ -61,6 +63,8 @@ pub type PaymentsResponseRouterData<R> =
ResponseRouterData<api::Authorize, R, PaymentsAuthorizeData, PaymentsResponseData>;
pub type PaymentsCancelResponseRouterData<R> =
ResponseRouterData<api::Void, R, PaymentsCancelData, PaymentsResponseData>;
pub type PaymentsBalanceResponseRouterData<R> =
ResponseRouterData<api::Balance, R, PaymentsAuthorizeData, PaymentsResponseData>;
pub type PaymentsSyncResponseRouterData<R> =
ResponseRouterData<api::PSync, R, PaymentsSyncData, PaymentsResponseData>;
pub type PaymentsSessionResponseRouterData<R> =
@ -109,6 +113,8 @@ pub type PaymentsInitType = dyn services::ConnectorIntegration<
PaymentsAuthorizeData,
PaymentsResponseData,
>;
pub type PaymentsBalanceType =
dyn services::ConnectorIntegration<api::Balance, PaymentsAuthorizeData, PaymentsResponseData>;
pub type PaymentsSyncType =
dyn services::ConnectorIntegration<api::PSync, PaymentsSyncData, PaymentsResponseData>;
pub type PaymentsCaptureType =
@ -230,7 +236,8 @@ pub struct RouterData<Flow, Request, Response> {
pub payment_method_token: Option<String>,
pub recurring_mandate_payment_data: Option<RecurringMandatePaymentData>,
pub preprocessing_id: Option<String>,
/// This is the balance amount for gift cards or voucher
pub payment_method_balance: Option<PaymentMethodBalance>,
/// Contains flow-specific data required to construct a request and send it to the connector.
pub request: Request,
@ -254,6 +261,12 @@ pub struct RouterData<Flow, Request, Response> {
pub test_mode: Option<bool>,
}
#[derive(Debug, Clone)]
pub struct PaymentMethodBalance {
pub amount: i64,
pub currency: String,
}
#[cfg(feature = "payouts")]
#[derive(Debug, Clone)]
pub struct PayoutsData {
@ -899,6 +912,7 @@ impl<F1, F2, T1, T2> From<(&RouterData<F1, T1, PaymentsResponseData>, T2)>
#[cfg(feature = "payouts")]
quote_id: data.quote_id.clone(),
test_mode: data.test_mode,
payment_method_balance: data.payment_method_balance.clone(),
}
}
}
@ -969,6 +983,7 @@ impl<F1, F2>
payout_method_data: data.payout_method_data.clone(),
quote_id: data.quote_id.clone(),
test_mode: data.test_mode,
payment_method_balance: None,
}
}
}

View File

@ -69,8 +69,13 @@ pub struct AuthorizeSessionToken;
#[derive(Debug, Clone)]
pub struct CompleteAuthorize;
// Used in gift cards balance check
#[derive(Debug, Clone)]
pub struct Balance;
#[derive(Debug, Clone)]
pub struct InitPayment;
#[derive(Debug, Clone)]
pub struct Capture;

View File

@ -236,6 +236,7 @@ impl ForeignFrom<api_enums::PaymentMethodType> for api_enums::PaymentMethod {
| api_enums::PaymentMethodType::DanamonVa
| api_enums::PaymentMethodType::MandiriVa
| api_enums::PaymentMethodType::Pix => Self::BankTransfer,
api_enums::PaymentMethodType::Givex => Self::GiftCard,
api_enums::PaymentMethodType::PaySafeCard => Self::GiftCard,
}
}

View File

@ -87,6 +87,7 @@ fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData {
#[cfg(feature = "payouts")]
quote_id: None,
test_mode: None,
payment_method_balance: None,
}
}
@ -138,6 +139,7 @@ fn construct_refund_router_data<F>() -> types::RefundsRouterData<F> {
#[cfg(feature = "payouts")]
quote_id: None,
test_mode: None,
payment_method_balance: None,
}
}

View File

@ -503,6 +503,7 @@ pub trait ConnectorActions: Connector {
#[cfg(feature = "payouts")]
quote_id: None,
test_mode: None,
payment_method_balance: None,
}
}

View File

@ -5036,25 +5036,11 @@
{
"type": "object",
"required": [
"baby_gift_card"
"givex"
],
"properties": {
"baby_gift_card": {
"type": "object",
"required": [
"number",
"cvc"
],
"properties": {
"number": {
"type": "string",
"description": "The gift card number"
},
"cvc": {
"type": "string",
"description": "The card verification code."
}
}
"givex": {
"$ref": "#/components/schemas/GiftCardDetails"
}
}
},
@ -5071,6 +5057,23 @@
}
]
},
"GiftCardDetails": {
"type": "object",
"required": [
"number",
"cvc"
],
"properties": {
"number": {
"type": "string",
"description": "The gift card number"
},
"cvc": {
"type": "string",
"description": "The card verification code."
}
}
},
"GoPayRedirection": {
"type": "object"
},
@ -7696,6 +7699,7 @@
"eps",
"evoucher",
"giropay",
"givex",
"google_pay",
"go_pay",
"gcash",