feat(connector): [Stripe] Add support for WeChat Pay and Qr code support in next action (#1555)

Co-authored-by: AkshayaFoiger <akshaya.shankar@juspay.in>
Co-authored-by: chikke srujan <121822803+srujanchikke@users.noreply.github.com>
This commit is contained in:
Sangamesh Kulkarni
2023-07-06 15:29:18 +05:30
committed by GitHub
parent ca4e242d20
commit a15a77dea3
8 changed files with 140 additions and 27 deletions

View File

@ -687,6 +687,9 @@ pub enum StripeNextAction {
ThirdPartySdkSessionToken {
session_token: Option<payments::SessionToken>,
},
QrCodeInformation {
image_data_url: url::Url,
},
}
pub(crate) fn into_stripe_next_action(
@ -710,5 +713,8 @@ pub(crate) fn into_stripe_next_action(
payments::NextActionData::ThirdPartySdkSessionToken { session_token } => {
StripeNextAction::ThirdPartySdkSessionToken { session_token }
}
payments::NextActionData::QrCodeInformation { image_data_url } => {
StripeNextAction::QrCodeInformation { image_data_url }
}
})
}

View File

@ -345,6 +345,9 @@ pub enum StripeNextAction {
ThirdPartySdkSessionToken {
session_token: Option<payments::SessionToken>,
},
QrCodeInformation {
image_data_url: url::Url,
},
}
pub(crate) fn into_stripe_next_action(
@ -368,6 +371,9 @@ pub(crate) fn into_stripe_next_action(
payments::NextActionData::ThirdPartySdkSessionToken { session_token } => {
StripeNextAction::ThirdPartySdkSessionToken { session_token }
}
payments::NextActionData::QrCodeInformation { image_data_url } => {
StripeNextAction::QrCodeInformation { image_data_url }
}
})
}

View File

@ -1060,8 +1060,7 @@ fn create_stripe_payment_method(
StripePaymentMethodType::ApplePay,
StripeBillingAddress::default(),
)),
payments::WalletData::WeChatPayRedirect(_) => Ok((
payments::WalletData::WeChatPay(_) => Ok((
StripePaymentMethodData::Wallet(StripeWallet::WechatpayPayment(WechatpayPayment {
client: WechatClient::Web,
payment_method_types: StripePaymentMethodType::Wechatpay,
@ -1515,6 +1514,12 @@ pub struct SepaAndBacsBankTransferInstructions {
pub receiver: SepaAndBacsReceiver,
}
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Serialize)]
pub struct WechatPayNextInstructions {
pub image_data_url: Url,
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct SepaAndBacsReceiver {
pub amount_received: i64,
@ -1699,26 +1704,47 @@ pub fn get_connector_metadata(
amount: i64,
) -> CustomResult<Option<serde_json::Value>, errors::ConnectorError> {
let next_action_response = next_action
.and_then(|next_action_response| match next_action_response {
StripeNextActionResponse::DisplayBankTransferInstructions(response) => {
Some(SepaAndBacsBankTransferInstructions {
sepa_bank_instructions: response.financial_addresses[0].iban.to_owned(),
bacs_bank_instructions: response.financial_addresses[0]
.sort_code
.to_owned(),
receiver: SepaAndBacsReceiver {
amount_received: amount - response.amount_remaining,
amount_remaining: response.amount_remaining,
},
})
}
_ => None,
}).map(|response| {
common_utils::ext_traits::Encode::<SepaAndBacsBankTransferInstructions>::encode_to_value(
&response,
)
.change_context(errors::ConnectorError::ResponseHandlingFailed)
}).transpose()?;
.and_then(|next_action_response| match next_action_response {
StripeNextActionResponse::DisplayBankTransferInstructions(response) => {
let bank_instructions = response.financial_addresses.get(0);
let (sepa_bank_instructions, bacs_bank_instructions) =
bank_instructions.map_or((None, None), |financial_address| {
(
financial_address.iban.to_owned(),
financial_address.sort_code.to_owned(),
)
});
let bank_transfer_instructions = SepaAndBacsBankTransferInstructions {
sepa_bank_instructions,
bacs_bank_instructions,
receiver: SepaAndBacsReceiver {
amount_received: amount - response.amount_remaining,
amount_remaining: response.amount_remaining,
},
};
Some(common_utils::ext_traits::Encode::<
SepaAndBacsBankTransferInstructions,
>::encode_to_value(
&bank_transfer_instructions
))
}
StripeNextActionResponse::WechatPayDisplayQrCode(response) => {
let wechat_pay_instructions = WechatPayNextInstructions {
image_data_url: response.image_data_url.to_owned(),
};
Some(
common_utils::ext_traits::Encode::<WechatPayNextInstructions>::encode_to_value(
&wechat_pay_instructions,
),
)
}
_ => None,
})
.transpose()
.change_context(errors::ConnectorError::ResponseHandlingFailed)?;
Ok(next_action_response)
}
@ -1848,7 +1874,7 @@ impl StripeNextActionResponse {
Self::RedirectToUrl(redirect_to_url) | Self::AlipayHandleRedirect(redirect_to_url) => {
Some(redirect_to_url.url.to_owned())
}
Self::WechatPayDisplayQrCode(redirect_to_url) => Some(redirect_to_url.data.to_owned()),
Self::WechatPayDisplayQrCode(_) => None,
Self::VerifyWithMicrodeposits(verify_with_microdeposits) => {
Some(verify_with_microdeposits.hosted_verification_url.to_owned())
}
@ -1885,7 +1911,11 @@ pub struct StripeRedirectToUrlResponse {
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct StripeRedirectToQr {
// This data contains url, it should be converted to QR code.
// Note: The url in this data is not redirection url
data: Url,
// This is the image source, this image_data_url can directly be used by sdk to show the QR code
image_data_url: Url,
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize)]

View File

@ -431,7 +431,8 @@ impl PaymentRedirectFlow for PaymentRedirectCompleteAuthorize {
.and_then(|next_action_data| match next_action_data {
api_models::payments::NextActionData::RedirectToUrl { redirect_to_url } => Some(redirect_to_url),
api_models::payments::NextActionData::DisplayBankTransferInformation { .. } => None,
api_models::payments::NextActionData::ThirdPartySdkSessionToken { .. } => None
api_models::payments::NextActionData::ThirdPartySdkSessionToken { .. } => None,
api_models::payments::NextActionData::QrCodeInformation{..} => None
})
.ok_or(errors::ApiErrorResponse::InternalServerError)
.into_report()

View File

@ -322,6 +322,9 @@ where
let bank_transfer_next_steps =
bank_transfer_next_steps_check(payment_attempt.clone())?;
let next_action_containing_qr_code =
qr_code_next_steps_check(payment_attempt.clone())?;
if payment_intent.status == enums::IntentStatus::RequiresCustomerAction
|| bank_transfer_next_steps.is_some()
{
@ -331,6 +334,11 @@ where
bank_transfer_steps_and_charges_details: bank_transfer,
}
})
.or(next_action_containing_qr_code.map(|qr_code_data| {
api_models::payments::NextActionData::QrCodeInformation {
image_data_url: qr_code_data.image_data_url,
}
}))
.or(Some(api_models::payments::NextActionData::RedirectToUrl {
redirect_to_url: helpers::create_startpay_url(
server,
@ -554,6 +562,18 @@ where
}
}
pub fn qr_code_next_steps_check(
payment_attempt: storage::PaymentAttempt,
) -> RouterResult<Option<api_models::payments::QrCodeNextStepsInstruction>> {
let qr_code_steps: Option<Result<api_models::payments::QrCodeNextStepsInstruction, _>> =
payment_attempt
.connector_metadata
.map(|metadata| metadata.parse_value("QrCodeNextStepsInstruction"));
let qr_code_instructions = qr_code_steps.transpose().ok().flatten();
Ok(qr_code_instructions)
}
impl ForeignFrom<(storage::PaymentIntent, storage::PaymentAttempt)> for api::PaymentsResponse {
fn foreign_from(item: (storage::PaymentIntent, storage::PaymentAttempt)) -> Self {
let pi = item.0;

View File

@ -233,6 +233,7 @@ Never share your secret api keys. Keep them guarded and secure.
api_models::payments::SdkNextAction,
api_models::payments::NextActionCall,
api_models::payments::SamsungPayWalletData,
api_models::payments::WeChatPay,
api_models::payments::GpayTokenizationData,
api_models::payments::GooglePayPaymentMethodInfo,
api_models::payments::ApplePayWalletData,