feat(connector): [Adyen] implement Gopay for Adyen (#1557)

Co-authored-by: Sangamesh Kulkarni <59434228+Sangamesh26@users.noreply.github.com>
This commit is contained in:
AkshayaFoiger
2023-07-17 18:07:32 +05:30
committed by GitHub
parent 94a5eb3533
commit de2d9bd059
10 changed files with 113 additions and 14 deletions

View File

@ -952,6 +952,8 @@ pub enum WalletData {
AliPayRedirect(AliPayRedirection),
/// The wallet data for Ali Pay HK redirect
AliPayHkRedirect(AliPayHkRedirection),
/// The wallet data for GoPay redirect
GoPayRedirect(GoPayRedirection),
/// The wallet data for Apple pay
ApplePay(ApplePayWalletData),
/// Wallet data for apple pay redirect flow
@ -1036,6 +1038,9 @@ pub struct AliPayRedirection {}
#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct AliPayHkRedirection {}
#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct GoPayRedirection {}
#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct MobilePayRedirection {}

View File

@ -570,6 +570,7 @@ pub enum PaymentMethodType {
Evoucher,
Giropay,
GooglePay,
GoPay,
Ideal,
Interac,
Klarna,

View File

@ -1554,6 +1554,7 @@ impl From<PaymentMethodType> for PaymentMethod {
PaymentMethodType::Evoucher => Self::Reward,
PaymentMethodType::Giropay => Self::BankRedirect,
PaymentMethodType::GooglePay => Self::Wallet,
PaymentMethodType::GoPay => Self::Wallet,
PaymentMethodType::Ideal => Self::BankRedirect,
PaymentMethodType::Klarna => Self::PayLater,
PaymentMethodType::MbWay => Self::Wallet,

View File

@ -907,7 +907,7 @@ impl api::IncomingWebhook for Adyen {
let notif = get_webhook_object_from_body(request.body)
.change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
let response: adyen::AdyenResponse = notif.into();
let response: adyen::Response = notif.into();
let res_json = serde_json::to_value(response)
.into_report()

View File

@ -116,6 +116,7 @@ pub struct AdyenPaymentRequest<'a> {
delivery_address: Option<Address>,
country_code: Option<api_enums::CountryAlpha2>,
line_items: Option<Vec<LineItem>>,
channel: Option<Channel>,
}
#[derive(Debug, Serialize)]
@ -145,6 +146,11 @@ pub enum AdyenStatus {
Refused,
}
#[derive(Debug, Clone, Serialize)]
pub enum Channel {
Web,
}
/// 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 {
@ -203,13 +209,14 @@ pub struct AdyenThreeDS {
#[derive(Debug, Clone, Deserialize)]
#[serde(untagged)]
pub enum AdyenPaymentResponse {
AdyenResponse(AdyenResponse),
AdyenRedirectResponse(AdyenRedirectionResponse),
Response(Response),
RedirectResponse(RedirectionResponse),
RedirectionErrorResponse(RedirectionErrorResponse),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AdyenResponse {
pub struct Response {
psp_reference: String,
result_code: AdyenStatus,
amount: Option<Amount>,
@ -219,9 +226,16 @@ pub struct AdyenResponse {
additional_data: Option<AdditionalData>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RedirectionErrorResponse {
result_code: AdyenStatus,
refusal_reason: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AdyenRedirectionResponse {
pub struct RedirectionResponse {
result_code: AdyenStatus,
action: AdyenRedirectionAction,
refusal_reason: Option<String>,
@ -271,6 +285,8 @@ pub enum AdyenPaymentMethod<'a> {
Eps(Box<BankRedirectionWithIssuer<'a>>),
Giropay(Box<BankRedirectionPMData>),
Gpay(Box<AdyenGPay>),
#[serde(rename = "gopay_wallet")]
GoPay(Box<GoPayData>),
Ideal(Box<BankRedirectionWithIssuer<'a>>),
Mandate(Box<AdyenMandate>),
Mbway(Box<MbwayData>),
@ -623,6 +639,9 @@ pub struct AliPayHkData {
payment_type: PaymentType,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GoPayData {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdyenGPay {
#[serde(rename = "type")]
@ -685,6 +704,8 @@ pub enum PaymentType {
Eps,
Giropay,
Googlepay,
#[serde(rename = "gopay_wallet")]
GoPay,
Ideal,
Klarna,
Mbway,
@ -869,6 +890,7 @@ fn get_browser_info(
) -> Result<Option<AdyenBrowserInfo>, Error> {
if item.auth_type == storage_enums::AuthenticationType::ThreeDs
|| item.payment_method == storage_enums::PaymentMethod::BankRedirect
|| item.request.payment_method_type == Some(storage_enums::PaymentMethodType::GoPay)
{
let info = item.request.get_browser_info()?;
Ok(Some(AdyenBrowserInfo {
@ -900,6 +922,13 @@ fn get_additional_data(item: &types::PaymentsAuthorizeRouterData) -> Option<Addi
}
}
fn get_channel_type(pm_type: &Option<storage_enums::PaymentMethodType>) -> Option<Channel> {
pm_type.as_ref().and_then(|pmt| match pmt {
storage_enums::PaymentMethodType::GoPay => Some(Channel::Web),
_ => None,
})
}
fn get_amount_data(item: &types::PaymentsAuthorizeRouterData) -> Amount {
Amount {
currency: item.request.currency.to_string(),
@ -1150,6 +1179,10 @@ impl<'a> TryFrom<&api::WalletData> for AdyenPaymentMethod<'a> {
};
Ok(AdyenPaymentMethod::AliPayHk(Box::new(alipay_hk_data)))
}
api_models::payments::WalletData::GoPayRedirect(_) => {
let go_pay_data = GoPayData {};
Ok(AdyenPaymentMethod::GoPay(Box::new(go_pay_data)))
}
api_models::payments::WalletData::MbWayRedirect(data) => {
let mbway_data = MbwayData {
payment_type: PaymentType::Mbway,
@ -1435,6 +1468,7 @@ impl<'a>
line_items: None,
shopper_reference,
store_payment_method,
channel: None,
})
}
}
@ -1473,6 +1507,7 @@ impl<'a> TryFrom<(&types::PaymentsAuthorizeRouterData, &api::Card)> for AdyenPay
line_items: None,
shopper_reference,
store_payment_method,
channel: None,
})
}
}
@ -1521,6 +1556,7 @@ impl<'a>
line_items: None,
shopper_reference: None,
store_payment_method: None,
channel: None,
};
Ok(request)
}
@ -1572,6 +1608,7 @@ impl<'a>
line_items,
shopper_reference,
store_payment_method,
channel: None,
})
}
}
@ -1631,6 +1668,7 @@ impl<'a> TryFrom<(&types::PaymentsAuthorizeRouterData, &api::WalletData)>
let additional_data = get_additional_data(item);
let payment_method = AdyenPaymentMethod::try_from(wallet_data)?;
let shopper_interaction = AdyenShopperInteraction::from(item);
let channel = get_channel_type(&item.request.payment_method_type);
let (recurring_processing_model, store_payment_method, shopper_reference) =
get_recurring_processing_model(item)?;
let return_url = item.request.get_return_url()?;
@ -1655,6 +1693,7 @@ impl<'a> TryFrom<(&types::PaymentsAuthorizeRouterData, &api::WalletData)>
line_items: None,
shopper_reference,
store_payment_method,
channel,
})
}
}
@ -1703,6 +1742,7 @@ impl<'a> TryFrom<(&types::PaymentsAuthorizeRouterData, &api::PayLaterData)>
line_items,
shopper_reference,
store_payment_method,
channel: None,
})
}
}
@ -1750,7 +1790,7 @@ impl TryFrom<types::PaymentsCancelResponseRouterData<AdyenCancelResponse>>
}
pub fn get_adyen_response(
response: AdyenResponse,
response: Response,
is_capture_manual: bool,
status_code: u16,
) -> errors::CustomResult<
@ -1801,7 +1841,7 @@ pub fn get_adyen_response(
}
pub fn get_redirection_response(
response: AdyenRedirectionResponse,
response: RedirectionResponse,
is_manual_capture: bool,
status_code: u16,
) -> errors::CustomResult<
@ -1855,6 +1895,38 @@ pub fn get_redirection_response(
Ok((status, error, payments_response_data))
}
pub fn get_redirection_error_response(
response: RedirectionErrorResponse,
is_manual_capture: bool,
status_code: u16,
) -> errors::CustomResult<
(
storage_enums::AttemptStatus,
Option<types::ErrorResponse>,
types::PaymentsResponseData,
),
errors::ConnectorError,
> {
let status =
storage_enums::AttemptStatus::foreign_from((is_manual_capture, response.result_code));
let error = Some(types::ErrorResponse {
code: status.to_string(),
message: response.refusal_reason.clone(),
reason: Some(response.refusal_reason),
status_code,
});
// We don't get connector transaction id for redirections in Adyen.
let payments_response_data = types::PaymentsResponseData::TransactionResponse {
resource_id: types::ResponseId::NoResponseId,
redirection_data: None,
mandate_reference: None,
connector_metadata: None,
network_txn_id: None,
connector_response_reference_id: None,
};
Ok((status, error, payments_response_data))
}
impl<F, Req>
TryFrom<(
types::ResponseRouterData<F, AdyenPaymentResponse, Req, types::PaymentsResponseData>,
@ -1871,12 +1943,15 @@ impl<F, Req>
let item = items.0;
let is_manual_capture = items.1;
let (status, error, payment_response_data) = match item.response {
AdyenPaymentResponse::AdyenResponse(response) => {
AdyenPaymentResponse::Response(response) => {
get_adyen_response(response, is_manual_capture, item.http_code)?
}
AdyenPaymentResponse::AdyenRedirectResponse(response) => {
AdyenPaymentResponse::RedirectResponse(response) => {
get_redirection_response(response, is_manual_capture, item.http_code)?
}
AdyenPaymentResponse::RedirectionErrorResponse(response) => {
get_redirection_error_response(response, is_manual_capture, item.http_code)?
}
};
Ok(Self {
@ -2182,7 +2257,7 @@ pub struct AdyenIncomingWebhook {
pub notification_items: Vec<AdyenItemObjectWH>,
}
impl From<AdyenNotificationRequestItemWH> for AdyenResponse {
impl From<AdyenNotificationRequestItemWH> for Response {
fn from(notif: AdyenNotificationRequestItemWH) -> Self {
Self {
psp_reference: notif.psp_reference,

View File

@ -171,6 +171,7 @@ Never share your secret api keys. Keep them guarded and secure.
api_models::payments::AliPayQr,
api_models::payments::AliPayRedirection,
api_models::payments::AliPayHkRedirection,
api_models::payments::GoPayRedirection,
api_models::payments::MbWayRedirection,
api_models::payments::MobilePayRedirection,
api_models::payments::WeChatPayRedirection,

View File

@ -174,7 +174,8 @@ impl ForeignFrom<api_enums::PaymentMethodType> for api_enums::PaymentMethod {
| api_enums::PaymentMethodType::MbWay
| api_enums::PaymentMethodType::MobilePay
| api_enums::PaymentMethodType::SamsungPay
| api_enums::PaymentMethodType::WeChatPay => Self::Wallet,
| api_enums::PaymentMethodType::WeChatPay
| api_enums::PaymentMethodType::GoPay => Self::Wallet,
api_enums::PaymentMethodType::Affirm
| api_enums::PaymentMethodType::AfterpayClearpay
| api_enums::PaymentMethodType::Klarna

View File

@ -145,10 +145,10 @@ async fn should_make_adyen_klarna_mandate_payment(
Ok(())
}
async fn should_make_adyen_alipay_hk_payment(c: WebDriver) -> Result<(), WebDriverError> {
async fn should_make_adyen_alipay_hk_payment(web_driver: WebDriver) -> Result<(), WebDriverError> {
let conn = AdyenSeleniumTest {};
conn.make_redirection_payment(
c,
web_driver,
vec![
Event::Trigger(Trigger::Goto(&format!("{CHEKOUT_BASE_URL}/saved/162"))),
Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),

View File

@ -4347,6 +4347,9 @@
"on_session"
]
},
"GoPayRedirection": {
"type": "object"
},
"GooglePayPaymentMethodInfo": {
"type": "object",
"required": [
@ -6801,6 +6804,7 @@
"evoucher",
"giropay",
"google_pay",
"go_pay",
"ideal",
"interac",
"klarna",
@ -8905,6 +8909,17 @@
}
}
},
{
"type": "object",
"required": [
"go_pay_redirect"
],
"properties": {
"go_pay_redirect": {
"$ref": "#/components/schemas/GoPayRedirection"
}
}
},
{
"type": "object",
"required": [