Skip to content

feat(connector): [Barclaycard] Add Google Pay Payment Method #8786

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Aug 6, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions crates/hyperswitch_connectors/src/connectors/barclaycard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1003,19 +1003,30 @@ static BARCLAYCARD_SUPPORTED_PAYMENT_METHODS: LazyLock<SupportedPaymentMethods>
PaymentMethodDetails {
mandates: enums::FeatureStatus::NotSupported,
refunds: enums::FeatureStatus::Supported,
supported_capture_methods,
supported_capture_methods: supported_capture_methods.clone(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dashboard changes for google pay via barclays?

specific_features: Some(
api_models::feature_matrix::PaymentMethodSpecificFeatures::Card({
api_models::feature_matrix::CardSpecificFeatures {
three_ds: common_enums::FeatureStatus::NotSupported,
no_three_ds: common_enums::FeatureStatus::Supported,
supported_card_networks: supported_card_network,
supported_card_networks: supported_card_network.clone(),
}
}),
),
},
);

barclaycard_supported_payment_methods.add(
enums::PaymentMethod::Wallet,
enums::PaymentMethodType::GooglePay,
PaymentMethodDetails {
mandates: enums::FeatureStatus::NotSupported,
refunds: enums::FeatureStatus::Supported,
supported_capture_methods,
specific_features: None,
},
);

barclaycard_supported_payment_methods
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use base64::Engine;
use common_enums::enums;
use common_utils::pii;
use common_utils::{consts, pii};
use hyperswitch_domain_models::{
payment_method_data::PaymentMethodData,
payment_method_data::{GooglePayWalletData, PaymentMethodData, WalletData},
router_data::{
AdditionalPaymentMethodConnectorResponse, ConnectorAuthType, ConnectorResponseData,
ErrorResponse, RouterData,
Expand Down Expand Up @@ -99,6 +100,7 @@ pub struct BarclaycardPaymentsRequest {
pub struct ProcessingInformation {
commerce_indicator: String,
capture: Option<bool>,
payment_solution: Option<String>,
}

#[derive(Debug, Serialize)]
Expand All @@ -125,10 +127,17 @@ pub struct CardPaymentInformation {
card: Card,
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GooglePayPaymentInformation {
fluid_data: FluidData,
}

#[derive(Debug, Serialize)]
#[serde(untagged)]
pub enum PaymentInformation {
Cards(Box<CardPaymentInformation>),
GooglePay(Box<GooglePayPaymentInformation>),
}

#[derive(Debug, Serialize)]
Expand All @@ -142,6 +151,12 @@ pub struct Card {
card_type: Option<String>,
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FluidData {
value: Secret<String>,
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct OrderInformationWithBill {
Expand All @@ -161,53 +176,60 @@ pub struct Amount {
pub struct BillTo {
first_name: Option<Secret<String>>,
last_name: Option<Secret<String>>,
address1: Option<Secret<String>>,
locality: Option<String>,
address1: Secret<String>,
locality: String,
#[serde(skip_serializing_if = "Option::is_none")]
administrative_area: Option<Secret<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
postal_code: Option<Secret<String>>,
country: Option<enums::CountryAlpha2>,
country: enums::CountryAlpha2,
email: pii::Email,
}

fn build_bill_to(
address_details: Option<&hyperswitch_domain_models::address::Address>,
email: pii::Email,
) -> Result<BillTo, error_stack::Report<errors::ConnectorError>> {
let default_address = BillTo {
first_name: None,
last_name: None,
address1: None,
locality: None,
administrative_area: None,
postal_code: None,
country: None,
email: email.clone(),
};

Ok(address_details
.and_then(|addr| {
addr.address.as_ref().map(|addr| {
let administrative_area = addr.to_state_code_as_optional().unwrap_or_else(|_| {
addr.state
.clone()
.map(|state| Secret::new(format!("{:.20}", state.expose())))
});

BillTo {
first_name: addr.first_name.clone(),
last_name: addr.last_name.clone(),
address1: addr.line1.clone(),
locality: addr.city.clone(),
administrative_area,
postal_code: addr.zip.clone(),
country: addr.country,
email,
}
})
})
.unwrap_or(default_address))
let addr = address_details
.and_then(|addr| addr.address.as_ref())
.ok_or_else(|| errors::ConnectorError::MissingRequiredField {
field_name: "billing_address_details",
})?;

let administrative_area = addr.to_state_code_as_optional().unwrap_or_else(|_| {
addr.state
.clone()
.map(|state| Secret::new(format!("{:.20}", state.expose())))
});

let address1 =
addr.line1
.clone()
.ok_or_else(|| errors::ConnectorError::MissingRequiredField {
field_name: "billing_address.line1",
})?;
let locality =
addr.city
.clone()
.ok_or_else(|| errors::ConnectorError::MissingRequiredField {
field_name: "billing_address.city",
})?;
let country = addr
.country
.ok_or_else(|| errors::ConnectorError::MissingRequiredField {
field_name: "billing_address.country",
})?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use utils here from crates/hyperswitch_connectors/src/utils.rs


Ok(BillTo {
first_name: addr.first_name.clone(),
last_name: addr.last_name.clone(),
address1,
locality,
administrative_area,
postal_code: addr.zip.clone(),
country,
email,
})
}

fn get_barclaycard_card_type(card_network: common_enums::CardNetwork) -> Option<&'static str> {
Expand All @@ -231,6 +253,20 @@ fn get_barclaycard_card_type(card_network: common_enums::CardNetwork) -> Option<
}
}

#[derive(Debug, Serialize)]
pub enum PaymentSolution {
GooglePay,
}

impl From<PaymentSolution> for String {
fn from(solution: PaymentSolution) -> Self {
let payment_solution = match solution {
PaymentSolution::GooglePay => "012",
};
payment_solution.to_string()
}
}

impl
From<(
&BarclaycardRouterData<&PaymentsAuthorizeRouterData>,
Expand All @@ -256,14 +292,16 @@ impl
impl
TryFrom<(
&BarclaycardRouterData<&PaymentsAuthorizeRouterData>,
Option<PaymentSolution>,
Option<String>,
)> for ProcessingInformation
{
type Error = error_stack::Report<errors::ConnectorError>;

fn try_from(
(item, network): (
(item, solution, network): (
&BarclaycardRouterData<&PaymentsAuthorizeRouterData>,
Option<PaymentSolution>,
Option<String>,
),
) -> Result<Self, Self::Error> {
Expand All @@ -274,6 +312,7 @@ impl
item.router_data.request.capture_method,
Some(enums::CaptureMethod::Automatic) | None
)),
payment_solution: solution.map(String::from),
commerce_indicator,
})
}
Expand Down Expand Up @@ -435,7 +474,45 @@ impl
let bill_to = build_bill_to(item.router_data.get_optional_billing(), email)?;
let order_information = OrderInformationWithBill::from((item, Some(bill_to)));
let payment_information = PaymentInformation::try_from(&ccard)?;
let processing_information = ProcessingInformation::try_from((item, None))?;
let processing_information = ProcessingInformation::try_from((item, None, None))?;
let client_reference_information = ClientReferenceInformation::from(item);
let merchant_defined_information = item
.router_data
.request
.metadata
.clone()
.map(convert_metadata_to_merchant_defined_info);

Ok(Self {
processing_information,
payment_information,
order_information,
client_reference_information,
merchant_defined_information,
consumer_authentication_information: None,
})
}
}

impl
TryFrom<(
&BarclaycardRouterData<&PaymentsAuthorizeRouterData>,
GooglePayWalletData,
)> for BarclaycardPaymentsRequest
{
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(
(item, google_pay_data): (
&BarclaycardRouterData<&PaymentsAuthorizeRouterData>,
GooglePayWalletData,
),
) -> Result<Self, Self::Error> {
let email = item.router_data.request.get_email()?;
let bill_to = build_bill_to(item.router_data.get_optional_billing(), email)?;
let order_information = OrderInformationWithBill::from((item, Some(bill_to)));
let payment_information = PaymentInformation::from(&google_pay_data);
let processing_information =
ProcessingInformation::try_from((item, Some(PaymentSolution::GooglePay), None))?;
let client_reference_information = ClientReferenceInformation::from(item);
let merchant_defined_information = item
.router_data
Expand All @@ -462,8 +539,44 @@ impl TryFrom<&BarclaycardRouterData<&PaymentsAuthorizeRouterData>> for Barclayca
) -> Result<Self, Self::Error> {
match item.router_data.request.payment_method_data.clone() {
PaymentMethodData::Card(ccard) => Self::try_from((item, ccard)),
PaymentMethodData::Wallet(_)
| PaymentMethodData::MandatePayment
PaymentMethodData::Wallet(wallet_data) => match wallet_data {
WalletData::GooglePay(google_pay_data) => Self::try_from((item, google_pay_data)),
WalletData::AliPayQr(_)
| WalletData::AliPayRedirect(_)
| WalletData::AliPayHkRedirect(_)
| WalletData::AmazonPayRedirect(_)
| WalletData::ApplePay(_)
| WalletData::MomoRedirect(_)
| WalletData::KakaoPayRedirect(_)
| WalletData::GoPayRedirect(_)
| WalletData::GcashRedirect(_)
| WalletData::ApplePayRedirect(_)
| WalletData::ApplePayThirdPartySdk(_)
| WalletData::DanaRedirect {}
| WalletData::GooglePayRedirect(_)
| WalletData::GooglePayThirdPartySdk(_)
| WalletData::MbWayRedirect(_)
| WalletData::MobilePayRedirect(_)
| WalletData::PaypalRedirect(_)
| WalletData::PaypalSdk(_)
| WalletData::Paze(_)
| WalletData::RevolutPay(_)
| WalletData::SamsungPay(_)
| WalletData::TwintRedirect {}
| WalletData::VippsRedirect {}
| WalletData::TouchNGoRedirect(_)
| WalletData::WeChatPayRedirect(_)
| WalletData::WeChatPayQr(_)
| WalletData::CashappQr(_)
| WalletData::SwishQr(_)
| WalletData::Paysera(_)
| WalletData::Skrill(_)
| WalletData::Mifinity(_) => Err(errors::ConnectorError::NotImplemented(
utils::get_unimplemented_payment_method_error_message("Barclaycard"),
)
.into()),
},
PaymentMethodData::MandatePayment
| PaymentMethodData::CardRedirect(_)
| PaymentMethodData::PayLater(_)
| PaymentMethodData::BankRedirect(_)
Expand Down Expand Up @@ -1575,6 +1688,18 @@ impl TryFrom<&hyperswitch_domain_models::payment_method_data::Card> for PaymentI
}
}

impl From<&GooglePayWalletData> for PaymentInformation {
fn from(google_pay_data: &GooglePayWalletData) -> Self {
Self::GooglePay(Box::new(GooglePayPaymentInformation {
fluid_data: FluidData {
value: Secret::from(
consts::BASE64_ENGINE.encode(google_pay_data.tokenization_data.token.clone()),
),
},
}))
}
}

fn get_commerce_indicator(network: Option<String>) -> String {
match network {
Some(card_network) => match card_network.to_lowercase().as_str() {
Expand Down
Loading