feat(connector): [Adyen] Add support for Blik (#1727)

This commit is contained in:
AkshayaFoiger
2023-08-01 20:25:20 +05:30
committed by GitHub
parent 7a0d6f6921
commit 30e41a9f2f
9 changed files with 149 additions and 37 deletions

View File

@ -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 {

View File

@ -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(

View File

@ -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,
},
})
}

View File

@ -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,
},
})
}

View File

@ -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>,

View File

@ -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()

View File

@ -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;

View File

@ -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() {

View File

@ -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": {