feat(connector): [Globepay] add authorize and psync flow (#1639)

Signed-off-by: chikke srujan <121822803+srujanchikke@users.noreply.github.com>
Co-authored-by: Arjun Karthik <m.arjunkarthik@gmail.com>
This commit is contained in:
chikke srujan
2023-07-13 14:06:25 +05:30
committed by GitHub
parent f7d369afa8
commit c119bfdd7e
10 changed files with 334 additions and 284 deletions

View File

@ -642,7 +642,7 @@ pub enum Connector {
Fiserv,
Forte,
Globalpay,
// Globepay, added as template code for future usage
Globepay,
Klarna,
Mollie,
Multisafepay,
@ -747,7 +747,7 @@ pub enum RoutableConnectors {
Fiserv,
Forte,
Globalpay,
// Globepay, added as template code for future usage
Globepay,
Iatapay,
Klarna,
Mollie,

View File

@ -895,6 +895,8 @@ pub struct BankDebitBilling {
#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum WalletData {
/// The wallet data for Ali Pay QrCode
AliPay(Box<AliPay>),
/// The wallet data for Ali Pay redirect
AliPayRedirect(AliPayRedirection),
/// The wallet data for Ali Pay HK redirect
@ -969,6 +971,9 @@ pub struct WeChatPay {}
#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct PaypalRedirection {}
#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct AliPay {}
#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct AliPayRedirection {}

View File

@ -765,6 +765,32 @@ impl Default for super::settings::RequiredFields {
)]),
},
),
(
enums::PaymentMethodType::AliPay,
ConnectorFields {
fields: HashMap::from([(
enums::Connector::Globepay,
vec![RequiredFieldInfo {
required_field: "description".to_string(),
display_name: "description".to_string(),
field_type: enums::FieldType::Text,
}],
)]),
},
),
(
enums::PaymentMethodType::WeChatPay,
ConnectorFields {
fields: HashMap::from([(
enums::Connector::Globepay,
vec![RequiredFieldInfo {
required_field: "description".to_string(),
display_name: "description".to_string(),
field_type: enums::FieldType::Text,
}],
)]),
},
),
])),
),
(

View File

@ -2,22 +2,24 @@ mod transformers;
use std::fmt::Debug;
use common_utils::crypto::{self, GenerateDigest};
use error_stack::{IntoReport, ResultExt};
use hex::encode;
use masking::ExposeInterface;
use rand::distributions::DistString;
use time::OffsetDateTime;
use transformers as globepay;
use crate::{
configs::settings,
consts,
core::errors::{self, CustomResult},
headers,
services::{
self,
request::{self, Mask},
ConnectorIntegration,
},
services::{self, request, ConnectorIntegration},
types::{
self,
api::{self, ConnectorCommon, ConnectorCommonExt},
storage::enums,
ErrorResponse, Response,
},
utils::{self, BytesExt},
@ -55,21 +57,44 @@ where
{
fn build_headers(
&self,
req: &types::RouterData<Flow, Request, Response>,
_req: &types::RouterData<Flow, Request, Response>,
_connectors: &settings::Connectors,
) -> CustomResult<Vec<(String, request::Maskable<String>)>, errors::ConnectorError> {
let mut header = vec![(
let header = vec![(
headers::CONTENT_TYPE.to_string(),
types::PaymentsAuthorizeType::get_content_type(self)
.to_string()
.into(),
self.get_content_type().to_string().into(),
)];
let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
header.append(&mut api_key);
Ok(header)
}
}
fn get_globlepay_query_params(
connector_auth_type: &types::ConnectorAuthType,
) -> CustomResult<String, errors::ConnectorError> {
let auth_type = globepay::GlobepayAuthType::try_from(connector_auth_type)?;
let time = (OffsetDateTime::now_utc().unix_timestamp_nanos() / 1_000_000).to_string();
let nonce_str = rand::distributions::Alphanumeric.sample_string(&mut rand::thread_rng(), 12);
let valid_string = format!(
"{}&{time}&{nonce_str}&{}",
auth_type.partner_code.expose(),
auth_type.credential_code.expose()
);
let digest = crypto::Sha256
.generate_digest(valid_string.as_bytes())
.change_context(errors::ConnectorError::RequestEncodingFailed)
.attach_printable("error encoding the query params")?;
let sign = encode(digest).to_lowercase();
let param = format!("?sign={sign}&time={time}&nonce_str={nonce_str}");
Ok(param)
}
fn get_partner_code(
connector_auth_type: &types::ConnectorAuthType,
) -> CustomResult<String, errors::ConnectorError> {
let auth_type = globepay::GlobepayAuthType::try_from(connector_auth_type)?;
Ok(auth_type.partner_code.expose())
}
impl ConnectorCommon for Globepay {
fn id(&self) -> &'static str {
"globepay"
@ -83,18 +108,6 @@ impl ConnectorCommon for Globepay {
connectors.globepay.base_url.as_ref()
}
fn get_auth_header(
&self,
auth_type: &types::ConnectorAuthType,
) -> CustomResult<Vec<(String, request::Maskable<String>)>, errors::ConnectorError> {
let auth = globepay::GlobepayAuthType::try_from(auth_type)
.change_context(errors::ConnectorError::FailedToObtainAuthType)?;
Ok(vec![(
headers::AUTHORIZATION.to_string(),
auth.api_key.expose().into_masked(),
)])
}
fn build_error_response(
&self,
res: Response,
@ -106,9 +119,9 @@ impl ConnectorCommon for Globepay {
Ok(ErrorResponse {
status_code: res.status_code,
code: response.code,
message: response.message,
reason: response.reason,
code: response.return_code.to_string(),
message: consts::NO_ERROR_MESSAGE.to_string(),
reason: Some(response.return_msg),
})
}
}
@ -116,7 +129,6 @@ impl ConnectorCommon for Globepay {
impl ConnectorIntegration<api::Session, types::PaymentsSessionData, types::PaymentsResponseData>
for Globepay
{
//TODO: implement sessions flow
}
impl ConnectorIntegration<api::AccessTokenAuth, types::AccessTokenRequestData, types::AccessToken>
@ -146,10 +158,24 @@ impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::P
fn get_url(
&self,
_req: &types::PaymentsAuthorizeRouterData,
_connectors: &settings::Connectors,
req: &types::PaymentsAuthorizeRouterData,
connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
let query_params = get_globlepay_query_params(&req.connector_auth_type)?;
if req.request.capture_method == Some(enums::CaptureMethod::Automatic) {
Ok(format!(
"{}api/v1.0/gateway/partners/{}/orders/{}{query_params}",
self.base_url(connectors),
get_partner_code(&req.connector_auth_type)?,
req.payment_id
))
} else {
Err(errors::ConnectorError::FlowNotSupported {
flow: "Manual Capture".to_owned(),
connector: "Globepay".to_owned(),
}
.into())
}
}
fn get_request_body(
@ -172,7 +198,7 @@ impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::P
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
Ok(Some(
services::RequestBuilder::new()
.method(services::Method::Post)
.method(services::Method::Put)
.url(&types::PaymentsAuthorizeType::get_url(
self, req, connectors,
)?)
@ -226,10 +252,16 @@ impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsRe
fn get_url(
&self,
_req: &types::PaymentsSyncRouterData,
_connectors: &settings::Connectors,
req: &types::PaymentsSyncRouterData,
connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
let query_params = get_globlepay_query_params(&req.connector_auth_type)?;
Ok(format!(
"{}api/v1.0/gateway/partners/{}/orders/{}{query_params}",
self.base_url(connectors),
get_partner_code(&req.connector_auth_type)?,
req.payment_id
))
}
fn build_request(
@ -252,7 +284,7 @@ impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsRe
data: &types::PaymentsSyncRouterData,
res: Response,
) -> CustomResult<types::PaymentsSyncRouterData, errors::ConnectorError> {
let response: globepay::GlobepayPaymentsResponse = res
let response: globepay::GlobepaySyncResponse = res
.response
.parse_struct("globepay PaymentsSyncResponse")
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
@ -274,72 +306,16 @@ impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsRe
impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::PaymentsResponseData>
for Globepay
{
fn get_headers(
&self,
req: &types::PaymentsCaptureRouterData,
connectors: &settings::Connectors,
) -> CustomResult<Vec<(String, request::Maskable<String>)>, errors::ConnectorError> {
self.build_headers(req, connectors)
}
fn get_content_type(&self) -> &'static str {
self.common_get_content_type()
}
fn get_url(
fn build_request(
&self,
_req: &types::PaymentsCaptureRouterData,
_connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
}
fn get_request_body(
&self,
_req: &types::PaymentsCaptureRouterData,
) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> {
Err(errors::ConnectorError::NotImplemented("get_request_body method".to_string()).into())
}
fn build_request(
&self,
req: &types::PaymentsCaptureRouterData,
connectors: &settings::Connectors,
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
Ok(Some(
services::RequestBuilder::new()
.method(services::Method::Post)
.url(&types::PaymentsCaptureType::get_url(self, req, connectors)?)
.attach_default_headers()
.headers(types::PaymentsCaptureType::get_headers(
self, req, connectors,
)?)
.body(types::PaymentsCaptureType::get_request_body(self, req)?)
.build(),
))
Err(errors::ConnectorError::FlowNotSupported {
flow: "Manual Capture".to_owned(),
connector: "Globepay".to_owned(),
}
fn handle_response(
&self,
data: &types::PaymentsCaptureRouterData,
res: Response,
) -> CustomResult<types::PaymentsCaptureRouterData, errors::ConnectorError> {
let response: globepay::GlobepayPaymentsResponse = res
.response
.parse_struct("Globepay PaymentsCaptureResponse")
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
types::RouterData::try_from(types::ResponseRouterData {
response,
data: data.clone(),
http_code: res.status_code,
})
}
fn get_error_response(
&self,
res: Response,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
self.build_error_response(res)
.into())
}
}
@ -351,138 +327,22 @@ impl ConnectorIntegration<api::Void, types::PaymentsCancelData, types::PaymentsR
impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsResponseData>
for Globepay
{
fn get_headers(
&self,
req: &types::RefundsRouterData<api::Execute>,
connectors: &settings::Connectors,
) -> CustomResult<Vec<(String, request::Maskable<String>)>, errors::ConnectorError> {
self.build_headers(req, connectors)
}
fn get_content_type(&self) -> &'static str {
self.common_get_content_type()
}
fn get_url(
fn build_request(
&self,
_req: &types::RefundsRouterData<api::Execute>,
_connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
}
fn get_request_body(
&self,
req: &types::RefundsRouterData<api::Execute>,
) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> {
let req_obj = globepay::GlobepayRefundRequest::try_from(req)?;
let globepay_req = types::RequestBody::log_and_get_request_body(
&req_obj,
utils::Encode::<globepay::GlobepayRefundRequest>::encode_to_string_of_json,
)
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
Ok(Some(globepay_req))
}
fn build_request(
&self,
req: &types::RefundsRouterData<api::Execute>,
connectors: &settings::Connectors,
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
let request = services::RequestBuilder::new()
.method(services::Method::Post)
.url(&types::RefundExecuteType::get_url(self, req, connectors)?)
.attach_default_headers()
.headers(types::RefundExecuteType::get_headers(
self, req, connectors,
)?)
.body(types::RefundExecuteType::get_request_body(self, req)?)
.build();
Ok(Some(request))
}
fn handle_response(
&self,
data: &types::RefundsRouterData<api::Execute>,
res: Response,
) -> CustomResult<types::RefundsRouterData<api::Execute>, errors::ConnectorError> {
let response: globepay::RefundResponse = res
.response
.parse_struct("globepay RefundResponse")
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
types::RouterData::try_from(types::ResponseRouterData {
response,
data: data.clone(),
http_code: res.status_code,
})
}
fn get_error_response(
&self,
res: Response,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
self.build_error_response(res)
Err(errors::ConnectorError::NotImplemented("Refund".to_string()).into())
}
}
impl ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponseData> for Globepay {
fn get_headers(
&self,
req: &types::RefundSyncRouterData,
connectors: &settings::Connectors,
) -> CustomResult<Vec<(String, request::Maskable<String>)>, errors::ConnectorError> {
self.build_headers(req, connectors)
}
fn get_content_type(&self) -> &'static str {
self.common_get_content_type()
}
fn get_url(
fn build_request(
&self,
_req: &types::RefundSyncRouterData,
_connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
}
fn build_request(
&self,
req: &types::RefundSyncRouterData,
connectors: &settings::Connectors,
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
Ok(Some(
services::RequestBuilder::new()
.method(services::Method::Get)
.url(&types::RefundSyncType::get_url(self, req, connectors)?)
.attach_default_headers()
.headers(types::RefundSyncType::get_headers(self, req, connectors)?)
.body(types::RefundSyncType::get_request_body(self, req)?)
.build(),
))
}
fn handle_response(
&self,
data: &types::RefundSyncRouterData,
res: Response,
) -> CustomResult<types::RefundSyncRouterData, errors::ConnectorError> {
let response: globepay::RefundResponse = res
.response
.parse_struct("globepay RefundSyncResponse")
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
types::RouterData::try_from(types::ResponseRouterData {
response,
data: data.clone(),
http_code: res.status_code,
})
}
fn get_error_response(
&self,
res: Response,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
self.build_error_response(res)
Err(errors::ConnectorError::NotImplemented("Refund Sync".to_string()).into())
}
}

View File

@ -1,90 +1,115 @@
use error_stack::ResultExt;
use masking::Secret;
use serde::{Deserialize, Serialize};
use crate::{
connector::utils::PaymentsAuthorizeRequestData,
connector::utils::RouterData,
consts,
core::errors,
types::{self, api, storage::enums},
};
#[derive(Default, Debug, Serialize, Eq, PartialEq)]
#[derive(Debug, Serialize)]
pub struct GlobepayPaymentsRequest {
amount: i64,
card: GlobepayCard,
price: i64,
description: String,
currency: enums::Currency,
channel: GlobepayChannel,
}
#[derive(Default, Debug, Serialize, Eq, PartialEq)]
pub struct GlobepayCard {
name: Secret<String>,
number: cards::CardNumber,
expiry_month: Secret<String>,
expiry_year: Secret<String>,
cvc: Secret<String>,
complete: bool,
#[derive(Debug, Serialize)]
pub enum GlobepayChannel {
Alipay,
Wechat,
}
impl TryFrom<&types::PaymentsAuthorizeRouterData> for GlobepayPaymentsRequest {
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result<Self, Self::Error> {
match item.request.payment_method_data.clone() {
api::PaymentMethodData::Card(req_card) => {
let card = GlobepayCard {
name: req_card.card_holder_name,
number: req_card.card_number,
expiry_month: req_card.card_exp_month,
expiry_year: req_card.card_exp_year,
cvc: req_card.card_cvc,
complete: item.request.is_auto_capture()?,
let channel: GlobepayChannel = match &item.request.payment_method_data {
api::PaymentMethodData::Wallet(ref wallet_data) => match wallet_data {
api::WalletData::AliPay(_) => GlobepayChannel::Alipay,
api::WalletData::WeChatPay(_) => GlobepayChannel::Wechat,
_ => Err(errors::ConnectorError::NotImplemented(
"Payment method".to_string(),
))?,
},
_ => Err(errors::ConnectorError::NotImplemented(
"Payment method".to_string(),
))?,
};
let description = item.get_description()?;
Ok(Self {
amount: item.request.amount,
card,
price: item.request.amount,
description,
currency: item.request.currency,
channel,
})
}
_ => Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()),
}
}
}
pub struct GlobepayAuthType {
pub(super) api_key: Secret<String>,
pub(super) partner_code: Secret<String>,
pub(super) credential_code: Secret<String>,
}
impl TryFrom<&types::ConnectorAuthType> for GlobepayAuthType {
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(auth_type: &types::ConnectorAuthType) -> Result<Self, Self::Error> {
match auth_type {
types::ConnectorAuthType::HeaderKey { api_key } => Ok(Self {
api_key: Secret::new(api_key.to_string()),
types::ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self {
partner_code: Secret::new(api_key.to_owned()),
credential_code: Secret::new(key1.to_owned()),
}),
_ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
#[derive(Debug, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum GlobepayPaymentStatus {
Succeeded,
Failed,
#[default]
Processing,
Success,
Exists,
}
impl From<GlobepayPaymentStatus> for enums::AttemptStatus {
fn from(item: GlobepayPaymentStatus) -> Self {
match item {
GlobepayPaymentStatus::Succeeded => Self::Charged,
GlobepayPaymentStatus::Failed => Self::Failure,
GlobepayPaymentStatus::Processing => Self::Authorizing,
GlobepayPaymentStatus::Success => Self::AuthenticationPending, // this connector only have redirection flows so "Success" is mapped to authenticatoin pending ,ref = "https://pay.globepay.co/docs/en/#api-QRCode-NewQRCode"
GlobepayPaymentStatus::Exists => Self::Failure,
}
}
}
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Deserialize, Serialize)]
pub struct GlobepayConnectorMetadata {
image_data_url: url::Url,
}
#[derive(Debug, Deserialize)]
pub struct GlobepayPaymentsResponse {
status: GlobepayPaymentStatus,
id: String,
result_code: Option<GlobepayPaymentStatus>,
order_id: Option<String>,
qrcode_img: Option<url::Url>,
return_code: GlobepayReturnCode, //Execution result
return_msg: Option<String>,
}
#[derive(Debug, Deserialize, PartialEq, strum::Display)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum GlobepayReturnCode {
Success,
OrderNotExist,
OrderMismatch,
Systemerror,
InvalidShortId,
SignTimeout,
InvalidSign,
ParamInvalid,
NotPermitted,
InvalidChannel,
DuplicateOrderId,
}
impl<F, T>
@ -100,10 +125,104 @@ impl<F, T>
types::PaymentsResponseData,
>,
) -> Result<Self, Self::Error> {
if item.response.return_code == GlobepayReturnCode::Success {
let globepay_metadata = GlobepayConnectorMetadata {
image_data_url: item
.response
.qrcode_img
.ok_or(errors::ConnectorError::ResponseHandlingFailed)?,
};
let connector_metadata = Some(common_utils::ext_traits::Encode::<
GlobepayConnectorMetadata,
>::encode_to_value(&globepay_metadata))
.transpose()
.change_context(errors::ConnectorError::ResponseHandlingFailed)?;
let globepay_status = item
.response
.result_code
.ok_or(errors::ConnectorError::ResponseHandlingFailed)?;
Ok(Self {
status: enums::AttemptStatus::from(item.response.status),
status: enums::AttemptStatus::from(globepay_status),
response: Ok(types::PaymentsResponseData::TransactionResponse {
resource_id: types::ResponseId::ConnectorTransactionId(item.response.id),
resource_id: types::ResponseId::ConnectorTransactionId(
item.response
.order_id
.ok_or(errors::ConnectorError::ResponseHandlingFailed)?,
),
redirection_data: None,
mandate_reference: None,
connector_metadata,
network_txn_id: None,
connector_response_reference_id: None,
}),
..item.data
})
} else {
Ok(Self {
status: enums::AttemptStatus::Failure, //As this connector gives 200 in failed scenarios . if return_code is not success status is mapped to failure. ref = "https://pay.globepay.co/docs/en/#api-QRCode-NewQRCode"
response: Err(get_error_response(
item.response.return_code,
item.response.return_msg,
item.http_code,
)),
..item.data
})
}
}
}
#[derive(Debug, Deserialize)]
pub struct GlobepaySyncResponse {
pub result_code: Option<GlobepayPaymentPsyncStatus>,
pub order_id: Option<String>,
pub return_code: GlobepayReturnCode,
pub return_msg: Option<String>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum GlobepayPaymentPsyncStatus {
Paying,
CreateFail,
Closed,
PayFail,
PaySuccess,
}
impl From<GlobepayPaymentPsyncStatus> for enums::AttemptStatus {
fn from(item: GlobepayPaymentPsyncStatus) -> Self {
match item {
GlobepayPaymentPsyncStatus::PaySuccess => Self::Charged,
GlobepayPaymentPsyncStatus::PayFail
| GlobepayPaymentPsyncStatus::CreateFail
| GlobepayPaymentPsyncStatus::Closed => Self::Failure,
GlobepayPaymentPsyncStatus::Paying => Self::AuthenticationPending,
}
}
}
impl<F, T>
TryFrom<types::ResponseRouterData<F, GlobepaySyncResponse, T, types::PaymentsResponseData>>
for types::RouterData<F, T, types::PaymentsResponseData>
{
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(
item: types::ResponseRouterData<F, GlobepaySyncResponse, T, types::PaymentsResponseData>,
) -> Result<Self, Self::Error> {
if item.response.return_code == GlobepayReturnCode::Success {
let globepay_status = item
.response
.result_code
.ok_or(errors::ConnectorError::ResponseHandlingFailed)?;
let globepay_id = item
.response
.order_id
.ok_or(errors::ConnectorError::ResponseHandlingFailed)?;
Ok(Self {
status: enums::AttemptStatus::from(globepay_status),
response: Ok(types::PaymentsResponseData::TransactionResponse {
resource_id: types::ResponseId::ConnectorTransactionId(globepay_id),
redirection_data: None,
mandate_reference: None,
connector_metadata: None,
@ -112,10 +231,34 @@ impl<F, T>
}),
..item.data
})
} else {
Ok(Self {
status: enums::AttemptStatus::Failure, //As this connector gives 200 in failed scenarios . if return_code is not success status is mapped to failure. ref = "https://pay.globepay.co/docs/en/#api-QRCode-NewQRCode"
response: Err(get_error_response(
item.response.return_code,
item.response.return_msg,
item.http_code,
)),
..item.data
})
}
}
}
#[derive(Default, Debug, Serialize)]
fn get_error_response(
return_code: GlobepayReturnCode,
return_msg: Option<String>,
status_code: u16,
) -> types::ErrorResponse {
types::ErrorResponse {
code: return_code.to_string(),
message: consts::NO_ERROR_MESSAGE.to_string(),
reason: return_msg,
status_code,
}
}
#[derive(Debug, Serialize)]
pub struct GlobepayRefundRequest {
pub amount: i64,
}
@ -188,10 +331,9 @@ impl TryFrom<types::RefundsResponseRouterData<api::RSync, RefundResponse>>
}
}
#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Deserialize)]
pub struct GlobepayErrorResponse {
pub status_code: u16,
pub code: String,
pub return_msg: String,
pub return_code: GlobepayReturnCode,
pub message: String,
pub reason: Option<String>,
}

View File

@ -165,6 +165,7 @@ Never share your secret api keys. Keep them guarded and secure.
api_models::disputes::DisputeResponsePaymentsRetrieve,
api_models::payments::AddressDetails,
api_models::payments::BankDebitData,
api_models::payments::AliPay,
api_models::payments::AliPayRedirection,
api_models::payments::AliPayHkRedirection,
api_models::payments::MbWayRedirection,

View File

@ -232,6 +232,7 @@ impl ConnectorData {
enums::Connector::Fiserv => Ok(Box::new(&connector::Fiserv)),
enums::Connector::Forte => Ok(Box::new(&connector::Forte)),
enums::Connector::Globalpay => Ok(Box::new(&connector::Globalpay)),
enums::Connector::Globepay => Ok(Box::new(&connector::Globepay)),
enums::Connector::Iatapay => Ok(Box::new(&connector::Iatapay)),
enums::Connector::Klarna => Ok(Box::new(&connector::Klarna)),
enums::Connector::Mollie => Ok(Box::new(&connector::Mollie)),

View File

@ -144,8 +144,8 @@ api_key="Classic PMT API Key"
key1 = "Evoucher PMT API Key"
[globepay]
api_key="API Key"
api_key = "Partner code"
key1 = "Credential code"
[powertranz]
api_key="API Key"

View File

@ -25,7 +25,7 @@ pub struct ConnectorAuthentication {
pub fiserv: Option<SignatureKey>,
pub forte: Option<MultiAuthKey>,
pub globalpay: Option<BodyKey>,
pub globepay: Option<HeaderKey>,
pub globepay: Option<BodyKey>,
pub iatapay: Option<SignatureKey>,
pub mollie: Option<HeaderKey>,
pub multisafepay: Option<HeaderKey>,

View File

@ -1739,6 +1739,9 @@
}
}
},
"AliPay": {
"type": "object"
},
"AliPayHkRedirection": {
"type": "object"
},
@ -2939,6 +2942,7 @@
"fiserv",
"forte",
"globalpay",
"globepay",
"klarna",
"mollie",
"multisafepay",
@ -8535,6 +8539,17 @@
},
"WalletData": {
"oneOf": [
{
"type": "object",
"required": [
"ali_pay"
],
"properties": {
"ali_pay": {
"$ref": "#/components/schemas/AliPay"
}
}
},
{
"type": "object",
"required": [