mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
feat(connector): [Adyen] Add support for Blik (#1727)
This commit is contained in:
@ -1353,6 +1353,7 @@ pub enum NextActionType {
|
||||
InvokeSdkClient,
|
||||
TriggerApi,
|
||||
DisplayBankTransferInformation,
|
||||
DisplayWaitScreen,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, ToSchema)]
|
||||
@ -1376,6 +1377,11 @@ pub enum NextActionData {
|
||||
#[schema(value_type = String)]
|
||||
voucher_details: VoucherNextStepData,
|
||||
},
|
||||
/// Contains duration for displaying a wait screen, wait screen with timer is displayed by sdk
|
||||
WaitScreenInformation {
|
||||
display_from_timestamp: i128,
|
||||
display_to_timestamp: Option<i128>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, ToSchema)]
|
||||
@ -1400,6 +1406,12 @@ pub struct QrCodeNextStepsInstruction {
|
||||
pub image_data_url: Url,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, serde::Deserialize)]
|
||||
pub struct WaitScreenInstructions {
|
||||
pub display_from_timestamp: i128,
|
||||
pub display_to_timestamp: Option<i128>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum BankTransferInstructions {
|
||||
|
||||
@ -840,6 +840,8 @@ pub enum PaymentExperience {
|
||||
LinkWallet,
|
||||
/// Contains the data for invoking the sdk client for completing the payment.
|
||||
InvokePaymentApp,
|
||||
/// Contains the data for displaying wait screen
|
||||
DisplayWaitScreen,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
|
||||
@ -773,6 +773,10 @@ pub enum StripeNextAction {
|
||||
DisplayVoucherInformation {
|
||||
voucher_details: payments::VoucherNextStepData,
|
||||
},
|
||||
WaitScreenInformation {
|
||||
display_from_timestamp: i128,
|
||||
display_to_timestamp: Option<i128>,
|
||||
},
|
||||
}
|
||||
|
||||
pub(crate) fn into_stripe_next_action(
|
||||
@ -802,6 +806,13 @@ pub(crate) fn into_stripe_next_action(
|
||||
payments::NextActionData::DisplayVoucherInformation { voucher_details } => {
|
||||
StripeNextAction::DisplayVoucherInformation { voucher_details }
|
||||
}
|
||||
payments::NextActionData::WaitScreenInformation {
|
||||
display_from_timestamp,
|
||||
display_to_timestamp,
|
||||
} => StripeNextAction::WaitScreenInformation {
|
||||
display_from_timestamp,
|
||||
display_to_timestamp,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -374,6 +374,10 @@ pub enum StripeNextAction {
|
||||
DisplayVoucherInformation {
|
||||
voucher_details: payments::VoucherNextStepData,
|
||||
},
|
||||
WaitScreenInformation {
|
||||
display_from_timestamp: i128,
|
||||
display_to_timestamp: Option<i128>,
|
||||
},
|
||||
}
|
||||
|
||||
pub(crate) fn into_stripe_next_action(
|
||||
@ -403,6 +407,13 @@ pub(crate) fn into_stripe_next_action(
|
||||
payments::NextActionData::DisplayVoucherInformation { voucher_details } => {
|
||||
StripeNextAction::DisplayVoucherInformation { voucher_details }
|
||||
}
|
||||
payments::NextActionData::WaitScreenInformation {
|
||||
display_from_timestamp,
|
||||
display_to_timestamp,
|
||||
} => StripeNextAction::WaitScreenInformation {
|
||||
display_from_timestamp,
|
||||
display_to_timestamp,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ use error_stack::ResultExt;
|
||||
use masking::PeekInterface;
|
||||
use reqwest::Url;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::PrimitiveDateTime;
|
||||
use time::{Duration, OffsetDateTime, PrimitiveDateTime};
|
||||
|
||||
#[cfg(feature = "payouts")]
|
||||
use crate::connector::utils::AddressDetailsData;
|
||||
@ -2367,13 +2367,10 @@ pub fn get_connector_metadata(
|
||||
response: &NextActionResponse,
|
||||
) -> errors::CustomResult<Option<serde_json::Value>, errors::ConnectorError> {
|
||||
let connector_metadata = match response.action.type_of_response {
|
||||
ActionType::QrCode => {
|
||||
let metadata = get_qr_metadata(response);
|
||||
Some(metadata)
|
||||
}
|
||||
_ => None,
|
||||
ActionType::QrCode => get_qr_metadata(response),
|
||||
ActionType::Await => get_wait_screen_metadata(response),
|
||||
_ => Ok(None),
|
||||
}
|
||||
.transpose()
|
||||
.change_context(errors::ConnectorError::ResponseHandlingFailed)?;
|
||||
|
||||
Ok(connector_metadata)
|
||||
@ -2381,7 +2378,7 @@ pub fn get_connector_metadata(
|
||||
|
||||
pub fn get_qr_metadata(
|
||||
response: &NextActionResponse,
|
||||
) -> errors::CustomResult<serde_json::Value, errors::ConnectorError> {
|
||||
) -> errors::CustomResult<Option<serde_json::Value>, errors::ConnectorError> {
|
||||
let image_data = response
|
||||
.action
|
||||
.qr_code_data
|
||||
@ -2396,12 +2393,41 @@ pub fn get_qr_metadata(
|
||||
|
||||
let qr_code_instructions = payments::QrCodeNextStepsInstruction { image_data_url };
|
||||
|
||||
common_utils::ext_traits::Encode::<payments::QrCodeNextStepsInstruction>::encode_to_value(
|
||||
&qr_code_instructions,
|
||||
)
|
||||
Some(common_utils::ext_traits::Encode::<
|
||||
payments::QrCodeNextStepsInstruction,
|
||||
>::encode_to_value(&qr_code_instructions))
|
||||
.transpose()
|
||||
.change_context(errors::ConnectorError::ResponseHandlingFailed)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct WaitScreenData {
|
||||
display_from_timestamp: i128,
|
||||
display_to_timestamp: Option<i128>,
|
||||
}
|
||||
|
||||
pub fn get_wait_screen_metadata(
|
||||
next_action: &NextActionResponse,
|
||||
) -> errors::CustomResult<Option<serde_json::Value>, errors::ConnectorError> {
|
||||
match next_action.action.payment_method_type {
|
||||
PaymentType::Blik => {
|
||||
let current_time = OffsetDateTime::now_utc().unix_timestamp_nanos();
|
||||
Ok(Some(serde_json::json!(WaitScreenData {
|
||||
display_from_timestamp: current_time,
|
||||
display_to_timestamp: Some(current_time + Duration::minutes(1).whole_nanoseconds())
|
||||
})))
|
||||
}
|
||||
PaymentType::Mbway => {
|
||||
let current_time = OffsetDateTime::now_utc().unix_timestamp_nanos();
|
||||
Ok(Some(serde_json::json!(WaitScreenData {
|
||||
display_from_timestamp: current_time,
|
||||
display_to_timestamp: None
|
||||
})))
|
||||
}
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, Req>
|
||||
TryFrom<(
|
||||
types::ResponseRouterData<F, AdyenPaymentResponse, Req, types::PaymentsResponseData>,
|
||||
|
||||
@ -431,6 +431,7 @@ impl PaymentRedirectFlow for PaymentRedirectCompleteAuthorize {
|
||||
api_models::payments::NextActionData::ThirdPartySdkSessionToken { .. } => None,
|
||||
api_models::payments::NextActionData::QrCodeInformation{..} => None,
|
||||
api_models::payments::NextActionData::DisplayVoucherInformation{ .. } => None,
|
||||
api_models::payments::NextActionData::WaitScreenInformation{..} => None,
|
||||
})
|
||||
.ok_or(errors::ApiErrorResponse::InternalServerError)
|
||||
.into_report()
|
||||
|
||||
@ -375,13 +375,17 @@ where
|
||||
|
||||
let next_action_voucher = voucher_next_steps_check(payment_attempt.clone())?;
|
||||
|
||||
let next_action_containing_qr_code =
|
||||
let next_action_containing_qr_code_url =
|
||||
qr_code_next_steps_check(payment_attempt.clone())?;
|
||||
|
||||
let next_action_containing_wait_screen =
|
||||
wait_screen_next_steps_check(payment_attempt.clone())?;
|
||||
|
||||
if payment_intent.status == enums::IntentStatus::RequiresCustomerAction
|
||||
|| bank_transfer_next_steps.is_some()
|
||||
|| next_action_voucher.is_some()
|
||||
|| next_action_containing_qr_code.is_some()
|
||||
|| next_action_containing_qr_code_url.is_some()
|
||||
|| next_action_containing_wait_screen.is_some()
|
||||
{
|
||||
next_action_response = bank_transfer_next_steps
|
||||
.map(|bank_transfer| {
|
||||
@ -394,11 +398,17 @@ where
|
||||
voucher_details: voucher_data,
|
||||
}
|
||||
}))
|
||||
.or(next_action_containing_qr_code.map(|qr_code_data| {
|
||||
.or(next_action_containing_qr_code_url.map(|qr_code_data| {
|
||||
api_models::payments::NextActionData::QrCodeInformation {
|
||||
image_data_url: qr_code_data.image_data_url,
|
||||
}
|
||||
}))
|
||||
.or(next_action_containing_wait_screen.map(|wait_screen_data| {
|
||||
api_models::payments::NextActionData::WaitScreenInformation {
|
||||
display_from_timestamp: wait_screen_data.display_from_timestamp,
|
||||
display_to_timestamp: wait_screen_data.display_to_timestamp,
|
||||
}
|
||||
}))
|
||||
.or(redirection_data.map(|_| {
|
||||
api_models::payments::NextActionData::RedirectToUrl {
|
||||
redirect_to_url: helpers::create_startpay_url(
|
||||
@ -624,6 +634,20 @@ pub fn qr_code_next_steps_check(
|
||||
Ok(qr_code_instructions)
|
||||
}
|
||||
|
||||
pub fn wait_screen_next_steps_check(
|
||||
payment_attempt: storage::PaymentAttempt,
|
||||
) -> RouterResult<Option<api_models::payments::WaitScreenInstructions>> {
|
||||
let display_info_with_timer_steps: Option<
|
||||
Result<api_models::payments::WaitScreenInstructions, _>,
|
||||
> = payment_attempt
|
||||
.connector_metadata
|
||||
.map(|metadata| metadata.parse_value("WaitScreenInstructions"));
|
||||
|
||||
let display_info_with_timer_instructions =
|
||||
display_info_with_timer_steps.transpose().ok().flatten();
|
||||
Ok(display_info_with_timer_instructions)
|
||||
}
|
||||
|
||||
impl ForeignFrom<(storage::PaymentIntent, storage::PaymentAttempt)> for api::PaymentsResponse {
|
||||
fn foreign_from(item: (storage::PaymentIntent, storage::PaymentAttempt)) -> Self {
|
||||
let pi = item.0;
|
||||
|
||||
@ -332,21 +332,6 @@ async fn should_make_adyen_eps_payment(web_driver: WebDriver) -> Result<(), WebD
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn should_make_adyen_blik_payment(web_driver: WebDriver) -> Result<(), WebDriverError> {
|
||||
let conn = AdyenSeleniumTest {};
|
||||
conn.make_redirection_payment(
|
||||
web_driver,
|
||||
vec![
|
||||
Event::Trigger(Trigger::Goto(&format!("{CHEKOUT_BASE_URL}/saved/64"))),
|
||||
Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
|
||||
Event::Assert(Assert::IsPresent("Status")),
|
||||
Event::Assert(Assert::IsPresent("processing")), //final status of this payment method will remain in processing state
|
||||
],
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn should_make_adyen_bancontact_card_payment(
|
||||
web_driver: WebDriver,
|
||||
) -> Result<(), WebDriverError> {
|
||||
@ -634,6 +619,21 @@ async fn should_make_adyen_swish_payment(web_driver: WebDriver) -> Result<(), We
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn should_make_adyen_blik_payment(driver: WebDriver) -> Result<(), WebDriverError> {
|
||||
let conn = AdyenSeleniumTest {};
|
||||
conn.make_redirection_payment(
|
||||
driver,
|
||||
vec![
|
||||
Event::Trigger(Trigger::Goto(&format!("{CHEKOUT_BASE_URL}/saved/64"))),
|
||||
Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
|
||||
Event::Assert(Assert::IsPresent("Next Action Type")),
|
||||
Event::Assert(Assert::IsPresent("wait_screen_information")),
|
||||
],
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[ignore]
|
||||
@ -752,12 +752,6 @@ fn should_make_adyen_eps_payment_test() {
|
||||
tester!(should_make_adyen_eps_payment);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn should_make_adyen_blik_payment_test() {
|
||||
tester!(should_make_adyen_blik_payment);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn should_make_adyen_bancontact_card_payment_test() {
|
||||
@ -808,6 +802,12 @@ fn should_make_adyen_dana_payment_test() {
|
||||
tester!(should_make_adyen_dana_payment);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn should_make_adyen_blik_payment_test() {
|
||||
tester!(should_make_adyen_blik_payment);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn should_make_adyen_online_banking_fpx_payment_test() {
|
||||
|
||||
@ -6395,6 +6395,29 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"description": "Contains duration for displaying a wait screen, wait screen with timer is displayed by sdk",
|
||||
"required": [
|
||||
"display_from_timestamp",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"display_from_timestamp": {
|
||||
"type": "integer"
|
||||
},
|
||||
"display_to_timestamp": {
|
||||
"type": "integer",
|
||||
"nullable": true
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"wait_screen_information"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"discriminator": {
|
||||
@ -6408,7 +6431,8 @@
|
||||
"display_qr_code",
|
||||
"invoke_sdk_client",
|
||||
"trigger_api",
|
||||
"display_bank_transfer_information"
|
||||
"display_bank_transfer_information",
|
||||
"display_wait_screen"
|
||||
]
|
||||
},
|
||||
"NoThirdPartySdkSessionResponse": {
|
||||
@ -6827,7 +6851,8 @@
|
||||
"display_qr_code",
|
||||
"one_click",
|
||||
"link_wallet",
|
||||
"invoke_payment_app"
|
||||
"invoke_payment_app",
|
||||
"display_wait_screen"
|
||||
]
|
||||
},
|
||||
"PaymentIdType": {
|
||||
|
||||
Reference in New Issue
Block a user