mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 04:04:55 +08:00
fix(connector): [Peachpayments] Fix Bugs (#9393)
Co-authored-by: Anurag Singh <anurag.singh.001@MacBookPro.lan>
This commit is contained in:
@ -16,7 +16,6 @@ use hyperswitch_interfaces::{
|
|||||||
};
|
};
|
||||||
use masking::Secret;
|
use masking::Secret;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use strum::Display;
|
|
||||||
use time::{format_description::well_known::Rfc3339, OffsetDateTime};
|
use time::{format_description::well_known::Rfc3339, OffsetDateTime};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -70,50 +69,72 @@ pub struct EcommerceCardPaymentOnlyTransactionData {
|
|||||||
pub routing: Routing,
|
pub routing: Routing,
|
||||||
pub card: CardDetails,
|
pub card: CardDetails,
|
||||||
pub amount: AmountDetails,
|
pub amount: AmountDetails,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub three_ds_data: Option<ThreeDSData>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
#[serde[rename_all = "camelCase"]]
|
#[serde[rename_all = "camelCase"]]
|
||||||
pub struct MerchantInformation {
|
pub struct MerchantInformation {
|
||||||
pub client_merchant_reference_id: String,
|
pub client_merchant_reference_id: Secret<String>,
|
||||||
pub name: String,
|
pub name: Secret<String>,
|
||||||
pub mcc: String,
|
pub mcc: Secret<String>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub phone: Option<String>,
|
pub phone: Option<Secret<String>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub email: Option<String>,
|
pub email: Option<pii::Email>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub mobile: Option<String>,
|
pub mobile: Option<Secret<String>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub address: Option<String>,
|
pub address: Option<Secret<String>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub city: Option<String>,
|
pub city: Option<Secret<String>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub postal_code: Option<String>,
|
pub postal_code: Option<Secret<String>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub region_code: Option<String>,
|
pub region_code: Option<Secret<String>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub merchant_type: Option<String>,
|
pub merchant_type: Option<MerchantType>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub website_url: Option<String>,
|
pub website_url: Option<url::Url>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde[rename_all = "lowercase"]]
|
||||||
|
pub enum MerchantType {
|
||||||
|
Standard,
|
||||||
|
Sub,
|
||||||
|
Iso,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
#[serde[rename_all = "camelCase"]]
|
#[serde[rename_all = "camelCase"]]
|
||||||
pub struct Routing {
|
pub struct Routing {
|
||||||
pub route: String,
|
pub route: Route,
|
||||||
pub mid: String,
|
pub mid: Secret<String>,
|
||||||
pub tid: String,
|
pub tid: Secret<String>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub visa_payment_facilitator_id: Option<String>,
|
pub visa_payment_facilitator_id: Option<Secret<String>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub master_card_payment_facilitator_id: Option<String>,
|
pub master_card_payment_facilitator_id: Option<Secret<String>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub sub_mid: Option<String>,
|
pub sub_mid: Option<Secret<String>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub amex_id: Option<String>,
|
pub amex_id: Option<Secret<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde[rename_all = "snake_case"]]
|
||||||
|
pub enum Route {
|
||||||
|
ExipayEmulator,
|
||||||
|
AbsaBase24,
|
||||||
|
NedbankPostbridge,
|
||||||
|
AbsaPostbridgeEcentric,
|
||||||
|
PostbridgeDirecttransact,
|
||||||
|
PostbridgeEfficacy,
|
||||||
|
FiservLloyds,
|
||||||
|
NfsIzwe,
|
||||||
|
AbsaHpsZambia,
|
||||||
|
EcentricEcommerce,
|
||||||
|
UnitTestEmptyConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, PartialEq)]
|
#[derive(Debug, Serialize, PartialEq)]
|
||||||
@ -128,38 +149,13 @@ pub struct CardDetails {
|
|||||||
pub cvv: Option<Secret<String>>,
|
pub cvv: Option<Secret<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, PartialEq)]
|
|
||||||
#[serde[rename_all = "camelCase"]]
|
|
||||||
pub struct RefundCardDetails {
|
|
||||||
pub pan: Secret<String>,
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub cardholder_name: Option<Secret<String>>,
|
|
||||||
pub expiry_year: Secret<String>,
|
|
||||||
pub expiry_month: Secret<String>,
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub cvv: Option<Secret<String>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||||
#[serde[rename_all = "camelCase"]]
|
#[serde[rename_all = "camelCase"]]
|
||||||
pub struct AmountDetails {
|
pub struct AmountDetails {
|
||||||
pub amount: MinorUnit,
|
pub amount: MinorUnit,
|
||||||
pub currency_code: String,
|
pub currency_code: String,
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, PartialEq)]
|
|
||||||
#[serde[rename_all = "camelCase"]]
|
|
||||||
pub struct ThreeDSData {
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub cavv: Option<Secret<String>>,
|
pub display_amount: Option<String>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub tavv: Option<Secret<String>>,
|
|
||||||
pub eci: String,
|
|
||||||
pub ds_trans_id: String,
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub xid: Option<String>,
|
|
||||||
pub authentication_status: AuthenticationStatus,
|
|
||||||
pub three_ds_version: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Confirm Transaction Request (for capture)
|
// Confirm Transaction Request (for capture)
|
||||||
@ -199,6 +195,7 @@ impl TryFrom<&PeachpaymentsRouterData<&PaymentsCaptureRouterData>> for Peachpaym
|
|||||||
let amount = AmountDetails {
|
let amount = AmountDetails {
|
||||||
amount: amount_in_cents,
|
amount: amount_in_cents,
|
||||||
currency_code: item.router_data.request.currency.to_string(),
|
currency_code: item.router_data.request.currency.to_string(),
|
||||||
|
display_amount: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let confirmation_data = EcommerceCardPaymentOnlyConfirmationData { amount };
|
let confirmation_data = EcommerceCardPaymentOnlyConfirmationData { amount };
|
||||||
@ -271,57 +268,40 @@ impl TryFrom<&PaymentsCancelRouterData> for PeachpaymentsVoidRequest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, PartialEq)]
|
|
||||||
pub enum AuthenticationStatus {
|
|
||||||
Y, // Fully authenticated
|
|
||||||
A, // Attempted authentication / liability shift
|
|
||||||
N, // Not authenticated / failed
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&str> for AuthenticationStatus {
|
|
||||||
fn from(eci: &str) -> Self {
|
|
||||||
match eci {
|
|
||||||
"05" | "06" => Self::Y,
|
|
||||||
"07" => Self::A,
|
|
||||||
_ => Self::N,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct PeachPaymentsConnectorMetadataObject {
|
pub struct PeachPaymentsConnectorMetadataObject {
|
||||||
pub client_merchant_reference_id: String,
|
pub client_merchant_reference_id: Secret<String>,
|
||||||
pub name: String,
|
pub name: Secret<String>,
|
||||||
pub mcc: String,
|
pub mcc: Secret<String>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub phone: Option<String>,
|
pub phone: Option<Secret<String>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub email: Option<String>,
|
pub email: Option<pii::Email>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub mobile: Option<String>,
|
pub mobile: Option<Secret<String>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub address: Option<String>,
|
pub address: Option<Secret<String>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub city: Option<String>,
|
pub city: Option<Secret<String>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub postal_code: Option<String>,
|
pub postal_code: Option<Secret<String>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub region_code: Option<String>,
|
pub region_code: Option<Secret<String>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub merchant_type: Option<String>,
|
pub merchant_type: Option<MerchantType>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub website_url: Option<String>,
|
pub website_url: Option<url::Url>,
|
||||||
pub route: String,
|
pub route: Route,
|
||||||
pub mid: String,
|
pub mid: Secret<String>,
|
||||||
pub tid: String,
|
pub tid: Secret<String>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub visa_payment_facilitator_id: Option<String>,
|
pub visa_payment_facilitator_id: Option<Secret<String>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub master_card_payment_facilitator_id: Option<String>,
|
pub master_card_payment_facilitator_id: Option<Secret<String>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub sub_mid: Option<String>,
|
pub sub_mid: Option<Secret<String>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub amex_id: Option<String>,
|
pub amex_id: Option<Secret<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&PeachpaymentsRouterData<&PaymentsAuthorizeRouterData>>
|
impl TryFrom<&PeachpaymentsRouterData<&PaymentsAuthorizeRouterData>>
|
||||||
@ -379,55 +359,14 @@ impl TryFrom<&PeachpaymentsRouterData<&PaymentsAuthorizeRouterData>>
|
|||||||
let amount = AmountDetails {
|
let amount = AmountDetails {
|
||||||
amount: amount_in_cents,
|
amount: amount_in_cents,
|
||||||
currency_code: item.router_data.request.currency.to_string(),
|
currency_code: item.router_data.request.currency.to_string(),
|
||||||
|
display_amount: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Extract 3DS data if available
|
|
||||||
let three_ds_data = item
|
|
||||||
.router_data
|
|
||||||
.request
|
|
||||||
.authentication_data
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|auth_data| {
|
|
||||||
// Only include 3DS data if we have essential fields (ECI is most critical)
|
|
||||||
if let Some(eci) = &auth_data.eci {
|
|
||||||
let ds_trans_id = auth_data
|
|
||||||
.ds_trans_id
|
|
||||||
.clone()
|
|
||||||
.or_else(|| auth_data.threeds_server_transaction_id.clone())?;
|
|
||||||
|
|
||||||
// Determine authentication status based on ECI value
|
|
||||||
let authentication_status = eci.as_str().into();
|
|
||||||
|
|
||||||
// Convert message version to string, handling None case
|
|
||||||
let three_ds_version = auth_data.message_version.as_ref().map(|v| {
|
|
||||||
let version_str = v.to_string();
|
|
||||||
let mut parts = version_str.split('.');
|
|
||||||
match (parts.next(), parts.next()) {
|
|
||||||
(Some(major), Some(minor)) => format!("{}.{}", major, minor),
|
|
||||||
_ => v.to_string(), // fallback if format unexpected
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Some(ThreeDSData {
|
|
||||||
cavv: Some(auth_data.cavv.clone()),
|
|
||||||
tavv: None, // Network token field - not available in Hyperswitch AuthenticationData
|
|
||||||
eci: eci.clone(),
|
|
||||||
ds_trans_id,
|
|
||||||
xid: None, // Legacy 3DS 1.x/network token field - not available in Hyperswitch AuthenticationData
|
|
||||||
authentication_status,
|
|
||||||
three_ds_version,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let ecommerce_data = EcommerceCardPaymentOnlyTransactionData {
|
let ecommerce_data = EcommerceCardPaymentOnlyTransactionData {
|
||||||
merchant_information,
|
merchant_information,
|
||||||
routing,
|
routing,
|
||||||
card,
|
card,
|
||||||
amount,
|
amount,
|
||||||
three_ds_data,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generate current timestamp for sendDateTime (ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ)
|
// Generate current timestamp for sendDateTime (ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ)
|
||||||
@ -469,18 +408,16 @@ impl TryFrom<&ConnectorAuthType> for PeachpaymentsAuthType {
|
|||||||
}
|
}
|
||||||
// Card Gateway API Response
|
// Card Gateway API Response
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum PeachpaymentsPaymentStatus {
|
pub enum PeachpaymentsPaymentStatus {
|
||||||
Successful,
|
Successful,
|
||||||
Pending,
|
Pending,
|
||||||
Authorized,
|
Authorized,
|
||||||
Approved,
|
Approved,
|
||||||
#[serde(rename = "approved_confirmed")]
|
|
||||||
ApprovedConfirmed,
|
ApprovedConfirmed,
|
||||||
Declined,
|
Declined,
|
||||||
Failed,
|
Failed,
|
||||||
Reversed,
|
Reversed,
|
||||||
#[serde(rename = "threeds_required")]
|
|
||||||
ThreedsRequired,
|
ThreedsRequired,
|
||||||
Voided,
|
Voided,
|
||||||
}
|
}
|
||||||
@ -509,9 +446,8 @@ impl From<PeachpaymentsPaymentStatus> for common_enums::AttemptStatus {
|
|||||||
#[serde[rename_all = "camelCase"]]
|
#[serde[rename_all = "camelCase"]]
|
||||||
pub struct PeachpaymentsPaymentsResponse {
|
pub struct PeachpaymentsPaymentsResponse {
|
||||||
pub transaction_id: String,
|
pub transaction_id: String,
|
||||||
pub response_code: ResponseCode,
|
pub response_code: Option<ResponseCode>,
|
||||||
pub transaction_result: PeachpaymentsPaymentStatus,
|
pub transaction_result: PeachpaymentsPaymentStatus,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub ecommerce_card_payment_only_transaction_data: Option<EcommerceCardPaymentOnlyResponseData>,
|
pub ecommerce_card_payment_only_transaction_data: Option<EcommerceCardPaymentOnlyResponseData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -520,24 +456,26 @@ pub struct PeachpaymentsPaymentsResponse {
|
|||||||
#[serde[rename_all = "camelCase"]]
|
#[serde[rename_all = "camelCase"]]
|
||||||
pub struct PeachpaymentsConfirmResponse {
|
pub struct PeachpaymentsConfirmResponse {
|
||||||
pub transaction_id: String,
|
pub transaction_id: String,
|
||||||
pub response_code: ResponseCode,
|
pub response_code: Option<ResponseCode>,
|
||||||
pub transaction_result: PeachpaymentsPaymentStatus,
|
pub transaction_result: PeachpaymentsPaymentStatus,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub authorization_code: Option<String>,
|
pub authorization_code: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde[rename_all = "camelCase"]]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum ResponseCode {
|
pub enum ResponseCode {
|
||||||
Text(String),
|
Text(String),
|
||||||
Structured {
|
Structured {
|
||||||
value: ResponseCodeValue,
|
value: String,
|
||||||
description: String,
|
description: String,
|
||||||
|
terminal_outcome_string: Option<String>,
|
||||||
|
receipt_string: Option<String>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResponseCode {
|
impl ResponseCode {
|
||||||
pub fn value(&self) -> Option<&ResponseCodeValue> {
|
pub fn value(&self) -> Option<&String> {
|
||||||
match self {
|
match self {
|
||||||
Self::Structured { value, .. } => Some(value),
|
Self::Structured { value, .. } => Some(value),
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -559,33 +497,48 @@ impl ResponseCode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Display, Clone, Serialize, Deserialize, PartialEq)]
|
|
||||||
pub enum ResponseCodeValue {
|
|
||||||
#[serde(rename = "00", alias = "08")]
|
|
||||||
Success,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
|
||||||
pub struct EcommerceCardPaymentOnlyResponseData {
|
|
||||||
pub card: Option<CardResponseData>,
|
|
||||||
pub amount: Option<AmountDetails>,
|
|
||||||
pub stan: Option<String>,
|
|
||||||
pub rrn: Option<String>,
|
|
||||||
#[serde(rename = "approvalCode")]
|
|
||||||
pub approval_code: Option<String>,
|
|
||||||
#[serde(rename = "merchantAdviceCode")]
|
|
||||||
pub merchant_advice_code: Option<String>,
|
|
||||||
pub description: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
#[serde[rename_all = "camelCase"]]
|
#[serde[rename_all = "camelCase"]]
|
||||||
pub struct CardResponseData {
|
pub struct EcommerceCardPaymentOnlyResponseData {
|
||||||
pub bin_number: Option<String>,
|
pub amount: Option<AmountDetails>,
|
||||||
pub masked_pan: Option<String>,
|
pub stan: Option<Secret<String>>,
|
||||||
pub cardholder_name: Option<String>,
|
pub rrn: Option<Secret<String>>,
|
||||||
pub expiry_month: Option<String>,
|
pub approval_code: Option<String>,
|
||||||
pub expiry_year: Option<String>,
|
pub merchant_advice_code: Option<String>,
|
||||||
|
pub description: Option<String>,
|
||||||
|
pub trace_id: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_payment_success(value: Option<&String>) -> bool {
|
||||||
|
if let Some(val) = value {
|
||||||
|
val == "00" || val == "08" || val == "X94"
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_error_code(response_code: Option<&ResponseCode>) -> String {
|
||||||
|
response_code
|
||||||
|
.and_then(|code| code.value())
|
||||||
|
.map(|val| val.to_string())
|
||||||
|
.unwrap_or(
|
||||||
|
response_code
|
||||||
|
.and_then(|code| code.as_text())
|
||||||
|
.map(|text| text.to_string())
|
||||||
|
.unwrap_or(NO_ERROR_CODE.to_string()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_error_message(response_code: Option<&ResponseCode>) -> String {
|
||||||
|
response_code
|
||||||
|
.and_then(|code| code.description())
|
||||||
|
.map(|desc| desc.to_string())
|
||||||
|
.unwrap_or(
|
||||||
|
response_code
|
||||||
|
.and_then(|code| code.as_text())
|
||||||
|
.map(|text| text.to_string())
|
||||||
|
.unwrap_or(NO_ERROR_MESSAGE.to_string()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F, T> TryFrom<ResponseRouterData<F, PeachpaymentsPaymentsResponse, T, PaymentsResponseData>>
|
impl<F, T> TryFrom<ResponseRouterData<F, PeachpaymentsPaymentsResponse, T, PaymentsResponseData>>
|
||||||
@ -598,20 +551,15 @@ impl<F, T> TryFrom<ResponseRouterData<F, PeachpaymentsPaymentsResponse, T, Payme
|
|||||||
let status = common_enums::AttemptStatus::from(item.response.transaction_result);
|
let status = common_enums::AttemptStatus::from(item.response.transaction_result);
|
||||||
|
|
||||||
// Check if it's an error response
|
// Check if it's an error response
|
||||||
let response = if item.response.response_code.value() != Some(&ResponseCodeValue::Success) {
|
let response = if !is_payment_success(
|
||||||
|
item.response
|
||||||
|
.response_code
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|code| code.value()),
|
||||||
|
) {
|
||||||
Err(ErrorResponse {
|
Err(ErrorResponse {
|
||||||
code: item
|
code: get_error_code(item.response.response_code.as_ref()),
|
||||||
.response
|
message: get_error_message(item.response.response_code.as_ref()),
|
||||||
.response_code
|
|
||||||
.value()
|
|
||||||
.map(|val| val.to_string())
|
|
||||||
.unwrap_or(NO_ERROR_CODE.to_string()),
|
|
||||||
message: item
|
|
||||||
.response
|
|
||||||
.response_code
|
|
||||||
.description()
|
|
||||||
.map(|desc| desc.to_string())
|
|
||||||
.unwrap_or(NO_ERROR_MESSAGE.to_string()),
|
|
||||||
reason: item
|
reason: item
|
||||||
.response
|
.response
|
||||||
.ecommerce_card_payment_only_transaction_data
|
.ecommerce_card_payment_only_transaction_data
|
||||||
@ -658,20 +606,15 @@ impl<F, T> TryFrom<ResponseRouterData<F, PeachpaymentsConfirmResponse, T, Paymen
|
|||||||
let status = common_enums::AttemptStatus::from(item.response.transaction_result);
|
let status = common_enums::AttemptStatus::from(item.response.transaction_result);
|
||||||
|
|
||||||
// Check if it's an error response
|
// Check if it's an error response
|
||||||
let response = if item.response.response_code.value() != Some(&ResponseCodeValue::Success) {
|
let response = if !is_payment_success(
|
||||||
|
item.response
|
||||||
|
.response_code
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|code| code.value()),
|
||||||
|
) {
|
||||||
Err(ErrorResponse {
|
Err(ErrorResponse {
|
||||||
code: item
|
code: get_error_code(item.response.response_code.as_ref()),
|
||||||
.response
|
message: get_error_message(item.response.response_code.as_ref()),
|
||||||
.response_code
|
|
||||||
.value()
|
|
||||||
.map(|val| val.to_string())
|
|
||||||
.unwrap_or(NO_ERROR_CODE.to_string()),
|
|
||||||
message: item
|
|
||||||
.response
|
|
||||||
.response_code
|
|
||||||
.description()
|
|
||||||
.map(|desc| desc.to_string())
|
|
||||||
.unwrap_or(NO_ERROR_MESSAGE.to_string()),
|
|
||||||
reason: None,
|
reason: None,
|
||||||
status_code: item.http_code,
|
status_code: item.http_code,
|
||||||
attempt_status: Some(status),
|
attempt_status: Some(status),
|
||||||
@ -720,6 +663,7 @@ impl TryFrom<&PeachpaymentsRouterData<&PaymentsAuthorizeRouterData>>
|
|||||||
let amount = AmountDetails {
|
let amount = AmountDetails {
|
||||||
amount: amount_in_cents,
|
amount: amount_in_cents,
|
||||||
currency_code: item.router_data.request.currency.to_string(),
|
currency_code: item.router_data.request.currency.to_string(),
|
||||||
|
display_amount: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let confirmation_data = EcommerceCardPaymentOnlyConfirmationData { amount };
|
let confirmation_data = EcommerceCardPaymentOnlyConfirmationData { amount };
|
||||||
|
|||||||
@ -1538,6 +1538,10 @@ fn get_cards_required_fields() -> HashMap<Connector, RequiredFieldFinal> {
|
|||||||
),
|
),
|
||||||
(Connector::Paypal, fields(vec![], card_basic(), vec![])),
|
(Connector::Paypal, fields(vec![], card_basic(), vec![])),
|
||||||
(Connector::Payu, fields(vec![], card_basic(), vec![])),
|
(Connector::Payu, fields(vec![], card_basic(), vec![])),
|
||||||
|
(
|
||||||
|
Connector::Peachpayments,
|
||||||
|
fields(vec![], vec![], card_with_name()),
|
||||||
|
),
|
||||||
(
|
(
|
||||||
Connector::Powertranz,
|
Connector::Powertranz,
|
||||||
fields(vec![], card_with_name(), vec![]),
|
fields(vec![], card_with_name(), vec![]),
|
||||||
|
|||||||
Reference in New Issue
Block a user