Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
4 changes: 3 additions & 1 deletion .typos.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ caf = "caf" # part of café (URL-encoding / Unicode examples)
Automatico = "Automatico" # Brazilian Portuguese — Globalgetnet's PIX_AUTOMATICO API method
AUTOMATICO = "AUTOMATICO" # Brazilian Portuguese — Globalgetnet's PIX_AUTOMATICO API method
UE = "UE" # Hyperswitch internal error code prefix (e.g. UE_9000)
Payed = "Payed" # Santander API returns "PAYED" as a status
Payed = "Payed" # Santander API returns "PAYED" as a status
Threed = "Threed" # Ilixium spells its 3DS-completion operation type "THREED_SECURE_COMPLETE"
THREED = "THREED" # Ilixium spells its 3DS-completion operation type "THREED_SECURE_COMPLETE"

[default.extend-identifiers]
ACI = "ACI" # Name of a connector
Expand Down
1 change: 1 addition & 0 deletions config/development.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ psync = "GW_TXN_SYNC"
connectors_with_webhook_source_verification_call = "paypal, truelayer"

[connectors]
ilixium.base_url = "https://prprocessing.ilixium.com/platform/ili"
grabpay.base_url = "https://partner-api.grab.com/grabpay/partner/v2"
maya.base_url = "https://pg-sandbox.paymaya.com"
boost.base_url = "https://stage-api.boostconnect.biz/gateway"
Expand Down
1 change: 1 addition & 0 deletions config/production.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ connector_request_timeout = 30
bypass_urls = ["localhost", "local"]

[connectors]
ilixium.base_url = "https://prprocessing.ilixium.com/platform/ili"
grabpay.base_url = "https://partner-api.grab.com/grabpay/partner/v2"
maya.base_url = "https://pg.maya.ph"
boost.base_url = "https://api.boostconnect.biz/gateway"
Expand Down
1 change: 1 addition & 0 deletions config/sandbox.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ connector_request_timeout = 30
bypass_urls = ["localhost", "local"]

[connectors]
ilixium.base_url = "https://prprocessing.ilixium.com/platform/ili"
grabpay.base_url = "https://partner-api.stg-myteksi.com/grabpay/partner/v2"
maya.base_url = "https://pg-sandbox.paymaya.com"
boost.base_url = "https://stage-api.boostconnect.biz/gateway"
Expand Down
9 changes: 8 additions & 1 deletion config/superposition.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ api_tags_tags_psync = { value = "", schema = { type = "string" } }
environment = { position = 1, schema = { type = "string", enum = ["sandbox", "development", "production"] } }

# Connector dimension - determines which payment processor URLs to use
connector = { position = 2, schema = { type = "string", enum = ["glomopay", "stripe", "adyen", "paypal", "razorpay", "checkout", "braintree", "worldpay", "cybersource", "payme", "bluesnap", "fiserv", "trustpay", "volt", "hipay", "xendit", "phonepe", "cashfree", "payu", "paytm", "dlocal", "rapyd", "aci", "nuvei", "forte", "authorizedotnet", "elavon", "bamboraapac", "billwerk", "paysafe", "worldpayvantiv", "worldpayxml", "tsys", "tsys_transit", "bankofamerica", "powertranz", "revolut", "airwallex", "bambora", "shift4", "multisafepay", "iatapay", "jpmorgan", "nmi", "nexixpay", "authipay", "stax", "trustpayments", "fiservemea", "datatrans", "silverflow", "celero", "globalpay", "razorpayv2", "fiuu", "payload", "cashtocode", "novalnet", "nexinets", "noon", "mifinity", "calida", "cryptopay", "helcim", "placetopay", "barclaycard", "gigadat", "loonio", "mollie", "absa_sanlam", "truelayer", "trustly", "twoc_twop_paco", "zift", "revolv3", "fiservcommercehub", "finix", "wellsfargo", "imerchantsolutions", "qwikcilver", "flywire", "boost", "plaid", "grabpay", "maya"] } }
connector = { position = 2, schema = { type = "string", enum = ["glomopay", "stripe", "adyen", "paypal", "razorpay", "checkout", "braintree", "worldpay", "cybersource", "payme", "bluesnap", "fiserv", "trustpay", "volt", "hipay", "xendit", "phonepe", "cashfree", "payu", "paytm", "dlocal", "rapyd", "aci", "nuvei", "forte", "authorizedotnet", "elavon", "bamboraapac", "billwerk", "paysafe", "worldpayvantiv", "worldpayxml", "tsys", "tsys_transit", "bankofamerica", "powertranz", "revolut", "airwallex", "bambora", "shift4", "multisafepay", "iatapay", "jpmorgan", "nmi", "nexixpay", "authipay", "stax", "trustpayments", "fiservemea", "datatrans", "silverflow", "celero", "globalpay", "razorpayv2", "fiuu", "payload", "cashtocode", "novalnet", "nexinets", "noon", "mifinity", "calida", "cryptopay", "helcim", "placetopay", "barclaycard", "gigadat", "loonio", "mollie", "absa_sanlam", "truelayer", "trustly", "twoc_twop_paco", "zift", "revolv3", "fiservcommercehub", "finix", "wellsfargo", "imerchantsolutions", "qwikcilver", "flywire", "boost", "plaid", "grabpay", "maya", "ilixium"] } }

# ============================================================================
# Development Environment Overrides
Expand Down Expand Up @@ -580,6 +580,13 @@ connector_base_url = "https://api.zift.io/"
_context_ = { connector = "boost" }
connector_base_url = "https://stage-api.boostconnect.biz/gateway"

# Ilixium Direct API — sandbox host. Ilixium does not publish a production
# host; it is supplied per merchant at onboarding, so there is deliberately no
# production override here (see tech spec UNDECIDED #4).
[[overrides]]
_context_ = { connector = "ilixium" }
connector_base_url = "https://prprocessing.ilixium.com/platform/ili"

# ============================================================================
# Production Environment Overrides
# ============================================================================
Expand Down
4 changes: 2 additions & 2 deletions crates/common/external-services/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ where
}
(common_enums::CallConnectorAction::Trigger, TransportType::Http) => {
let mut connector_request = connector
.build_request_v2(&router_data.clone())
.build_request_v2(&router_data)
.map_err(report_connector_request_to_flow)?;

let mut updated_router_data = router_data.clone();
Expand Down Expand Up @@ -991,7 +991,7 @@ where
}
(common_enums::CallConnectorAction::Trigger, TransportType::Kafka) => {
let kafka_record = connector
.build_kafka_record(&router_data.clone())
.build_kafka_record(&router_data)
.map_err(report_connector_request_to_flow)?;

match kafka_record {
Expand Down
50 changes: 41 additions & 9 deletions crates/grpc-server/grpc-server/src/server/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -889,14 +889,25 @@ impl PaymentService for Payments {
// Convert proto request to intermediate type
let payload: AuthorizationRequest = proto_payload.clone().into();

let payment_method_data_action = PaymentMethodDataAction::get_payment_method_data_action(proto_payload.payment_method.clone().ok_or(ucs_env::error::GrpcError::from(IntegrationError::MissingRequiredField { field_name: "payment_method", context: domain_types::errors::IntegrationErrorContext::default() }))?)
.map_err(|err| {
tracing::error!("PAYMENT_AUTHORIZE_FLOW: failed to get payment method data action - error: {:?}", err);
ucs_env::error::GrpcError::from(IntegrationError::InvalidDataFormat { field_name: "payment_method", context: domain_types::errors::IntegrationErrorContext::default() })
})?;
// `payment_method` is required for an ordinary authorization, but not for the
// second leg of a redirect-based one: connectors that finalise 3DS through
// Authorize are re-invoked after the ACS posts back to `TermUrl`, and the
// caller no longer holds the raw instrument at that point. That leg is
// identified by `redirection_response`, exactly as the connectors themselves
// identify it (`request.redirect_response.is_some()`), and it is the only case
// in which an absent `payment_method` is accepted.
let payment_method_data_action = match proto_payload.payment_method.clone() {
Some(payment_method) => Some(PaymentMethodDataAction::get_payment_method_data_action(payment_method)
.map_err(|err| {
tracing::error!("PAYMENT_AUTHORIZE_FLOW: failed to get payment method data action - error: {:?}", err);
ucs_env::error::GrpcError::from(IntegrationError::InvalidDataFormat { field_name: "payment_method", context: domain_types::errors::IntegrationErrorContext::default() })
})?),
None if proto_payload.redirection_response.is_some() => None,
None => Err(ucs_env::error::GrpcError::from(IntegrationError::MissingRequiredField { field_name: "payment_method", context: domain_types::errors::IntegrationErrorContext::default() }))?,
};

let authorize_response = match payment_method_data_action {
PaymentMethodDataAction::CardProxy(proxy_card_details) => {
Some(PaymentMethodDataAction::CardProxy(proxy_card_details)) => {
let token_data = proxy_card_details.to_token_data();
let payment_method_data = payment_method_data::PaymentMethodData::Card(payment_method_data::Card::<VaultTokenHolder>::foreign_try_from(proxy_card_details).map_err(|err| {
tracing::error!("PAYMENT_AUTHORIZE_FLOW: failed to get payment method data action - error: {:?}", err);
Expand All @@ -917,7 +928,7 @@ impl PaymentService for Payments {
))
.await?
}
PaymentMethodDataAction::Card(card_details) => {
Some(PaymentMethodDataAction::Card(card_details)) => {
tracing::info!("REGULAR: Processing regular payment authorization (no injector)");
let payment_method_data = payment_method_data::PaymentMethodData::Card(payment_method_data::Card::<DefaultPCIHolder>::foreign_try_from(card_details).map_err(|err| {
tracing::error!("PAYMENT_AUTHORIZE_FLOW: failed to get payment method data action - error: {:?}", err);
Expand All @@ -938,7 +949,7 @@ impl PaymentService for Payments {
))
.await?
}
PaymentMethodDataAction::Default => {
Some(PaymentMethodDataAction::Default) => {
let payment_method_data = payment_method_data::PaymentMethodData::convert_to_domain_model_for_non_card_payment_methods(proto_payload.payment_method.clone().ok_or(ucs_env::error::GrpcError::from(IntegrationError::MissingRequiredField { field_name: "payment_method", context: domain_types::errors::IntegrationErrorContext::default() }))?)
.map_err(|err| {
tracing::error!("Failed to convert payment method data: {:?}", err);
Expand All @@ -959,7 +970,7 @@ impl PaymentService for Payments {
))
.await?
}
PaymentMethodDataAction::CardWithNoCvc(card_details) => {
Some(PaymentMethodDataAction::CardWithNoCvc(card_details)) => {
tracing::info!("REGULAR: Processing payment authorization with CardWithNoCvc");
let payment_method_data = payment_method_data::PaymentMethodData::CardWithNoCvc(
payment_method_data::CardWithNoCvc::foreign_try_from(card_details).map_err(|err| {
Expand All @@ -981,6 +992,27 @@ impl PaymentService for Payments {
))
.await?
}
// Redirect-return leg: no instrument was sent (guarded above by
// `redirection_response` being present). The connector finalises from the
// redirect payload and its own transaction reference; connectors that
// cannot do so reject `NoInstrumentAfterRedirect` rather than mistaking it
// for a payable instrument.
None => {
tracing::info!("REDIRECT_COMPLETION: authorization re-entered after redirect without payment method data");
Box::pin(self.process_authorization_internal::<DefaultPCIHolder>(
&config,
payload,
metadata_payload.connector.clone(),
metadata_payload.connector_config.clone(),
metadata,
&metadata_payload,
&service_name,
&metadata_payload.request_id,
None,
payment_method_data::PaymentMethodData::NoInstrumentAfterRedirect,
))
.await?
}
};

Ok(tonic::Response::new(authorize_response))
Expand Down
3 changes: 3 additions & 0 deletions crates/integrations/connector-integration/src/connectors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,3 +302,6 @@ pub use self::tesouro::Tesouro;

pub mod boost;
pub use self::boost::Boost;

pub mod ilixium;
pub use self::ilixium::Ilixium;
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,8 @@ impl<T: PaymentMethodDataTypes + Debug + Sync + Send + 'static + Serialize>
| PaymentMethodData::OpenBanking(_)
| PaymentMethodData::PaymentMethodToken(_)
| PaymentMethodData::DecryptedWalletTokenDetailsForNetworkTransactionId(_)
| PaymentMethodData::CardDetailsForNetworkTransactionId(_) => {
| PaymentMethodData::CardDetailsForNetworkTransactionId(_)
| PaymentMethodData::NoInstrumentAfterRedirect => {
Err(IntegrationError::NotImplemented(
utils::get_unimplemented_payment_method_error_message("Aci"),
Default::default(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3905,11 +3905,11 @@ impl<T: PaymentMethodDataTypes + std::fmt::Debug + Sync + Send + 'static + Seria
| PaymentMethodData::CardDetailsForNetworkTransactionId(_)
| PaymentMethodData::DecryptedWalletTokenDetailsForNetworkTransactionId(_)
| PaymentMethodData::CardWithNoCvc(_)
| PaymentMethodData::MobilePayment(_) => Err(IntegrationError::NotImplemented(
("payment method").into(),
Default::default(),
)
.into()),
| PaymentMethodData::MobilePayment(_)
| PaymentMethodData::NoInstrumentAfterRedirect => Err(
IntegrationError::NotImplemented(("payment method").into(), Default::default())
.into(),
),
},
}
}
Expand Down Expand Up @@ -6525,7 +6525,8 @@ impl<T: PaymentMethodDataTypes + std::fmt::Debug + Sync + Send + 'static + Seria
| PaymentMethodData::NetworkToken(_)
| PaymentMethodData::CardWithNoCvc(_)
| PaymentMethodData::MobilePayment(_)
| PaymentMethodData::PaymentMethodToken(_) => Err(
| PaymentMethodData::PaymentMethodToken(_)
| PaymentMethodData::NoInstrumentAfterRedirect => Err(
IntegrationError::NotImplemented(("payment method").into(), Default::default())
.into(),
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,8 @@ impl<T: PaymentMethodDataTypes>
| PaymentMethodData::MobilePayment(_)
| PaymentMethodData::OpenBanking(_)
| PaymentMethodData::DecryptedWalletTokenDetailsForNetworkTransactionId(_)
| PaymentMethodData::CardDetailsForNetworkTransactionId(_) => {
| PaymentMethodData::CardDetailsForNetworkTransactionId(_)
| PaymentMethodData::NoInstrumentAfterRedirect => {
return Err(IntegrationError::NotSupported {
message: "Selected payment method".to_string(),
connector: "bambora",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,8 @@ impl<T: PaymentMethodDataTypes + std::fmt::Debug + Sync + Send + 'static + Seria
| PaymentMethodData::PaymentMethodToken(_)
| PaymentMethodData::NetworkToken(_)
| PaymentMethodData::DecryptedWalletTokenDetailsForNetworkTransactionId(_)
| PaymentMethodData::CardDetailsForNetworkTransactionId(_) => {
| PaymentMethodData::CardDetailsForNetworkTransactionId(_)
| PaymentMethodData::NoInstrumentAfterRedirect => {
Err(IntegrationError::NotImplemented(
domain_types::utils::get_unimplemented_payment_method_error_message(
"Bank of America",
Expand Down Expand Up @@ -2061,7 +2062,8 @@ impl<T: PaymentMethodDataTypes + std::fmt::Debug + Sync + Send + 'static + Seria
| PaymentMethodData::PaymentMethodToken(_)
| PaymentMethodData::NetworkToken(_)
| PaymentMethodData::DecryptedWalletTokenDetailsForNetworkTransactionId(_)
| PaymentMethodData::CardDetailsForNetworkTransactionId(_) => {
| PaymentMethodData::CardDetailsForNetworkTransactionId(_)
| PaymentMethodData::NoInstrumentAfterRedirect => {
Err(IntegrationError::NotImplemented(
utils::get_unimplemented_payment_method_error_message("BankOfAmerica"),
Default::default(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ fn payment_method_data_label<T: PaymentMethodDataTypes>(
PaymentMethodData::NetworkToken(_) => "network_token",
PaymentMethodData::CardWithNoCvc(_) => "card_with_no_cvc",
PaymentMethodData::MobilePayment(_) => "mobile_payment",
PaymentMethodData::NoInstrumentAfterRedirect => "no_instrument_after_redirect",
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,8 @@ impl<T: PaymentMethodDataTypes + std::fmt::Debug + Sync + Send + 'static + Seria
| PaymentMethodData::PaymentMethodToken(_)
| PaymentMethodData::NetworkToken(_)
| PaymentMethodData::DecryptedWalletTokenDetailsForNetworkTransactionId(_)
| PaymentMethodData::CardDetailsForNetworkTransactionId(_) => {
| PaymentMethodData::CardDetailsForNetworkTransactionId(_)
| PaymentMethodData::NoInstrumentAfterRedirect => {
Err(IntegrationError::NotImplemented(
utils::get_unimplemented_payment_method_error_message("billwerk"),
Default::default(),
Expand Down
Loading
Loading