mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-01 11:06:50 +08:00
Co-authored-by: Sahkal Poddar <sahkal.poddar@juspay.in> Co-authored-by: Narayan Bhat <narayan.bhat@juspay.in>
855 lines
28 KiB
Rust
855 lines
28 KiB
Rust
pub mod transformers;
|
|
|
|
use std::fmt::Debug;
|
|
|
|
use common_utils::ext_traits::ByteSliceExt;
|
|
use diesel_models::enums;
|
|
use error_stack::{IntoReport, ResultExt};
|
|
use masking::PeekInterface;
|
|
use transformers as stax;
|
|
|
|
use self::stax::StaxWebhookEventType;
|
|
use super::utils::{self as connector_utils, to_connector_meta, RefundsRequestData};
|
|
use crate::{
|
|
configs::settings,
|
|
consts,
|
|
core::errors::{self, CustomResult},
|
|
headers,
|
|
services::{
|
|
self,
|
|
request::{self, Mask},
|
|
ConnectorIntegration, ConnectorValidation,
|
|
},
|
|
types::{
|
|
self,
|
|
api::{self, ConnectorCommon, ConnectorCommonExt},
|
|
domain, ErrorResponse, Response,
|
|
},
|
|
utils::{self, BytesExt},
|
|
};
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct Stax;
|
|
|
|
impl api::Payment for Stax {}
|
|
impl api::PaymentSession for Stax {}
|
|
impl api::ConnectorAccessToken for Stax {}
|
|
impl api::PreVerify for Stax {}
|
|
impl api::PaymentAuthorize for Stax {}
|
|
impl api::PaymentSync for Stax {}
|
|
impl api::PaymentCapture for Stax {}
|
|
impl api::PaymentVoid for Stax {}
|
|
impl api::Refund for Stax {}
|
|
impl api::RefundExecute for Stax {}
|
|
impl api::RefundSync for Stax {}
|
|
impl api::PaymentToken for Stax {}
|
|
|
|
impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Stax
|
|
where
|
|
Self: ConnectorIntegration<Flow, Request, Response>,
|
|
{
|
|
fn build_headers(
|
|
&self,
|
|
req: &types::RouterData<Flow, Request, Response>,
|
|
_connectors: &settings::Connectors,
|
|
) -> CustomResult<Vec<(String, request::Maskable<String>)>, errors::ConnectorError> {
|
|
let mut header = vec![(
|
|
headers::CONTENT_TYPE.to_string(),
|
|
types::PaymentsAuthorizeType::get_content_type(self)
|
|
.to_string()
|
|
.into(),
|
|
)];
|
|
let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
|
|
header.append(&mut api_key);
|
|
Ok(header)
|
|
}
|
|
}
|
|
|
|
impl ConnectorCommon for Stax {
|
|
fn id(&self) -> &'static str {
|
|
"stax"
|
|
}
|
|
|
|
fn common_get_content_type(&self) -> &'static str {
|
|
"application/json"
|
|
}
|
|
|
|
fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str {
|
|
connectors.stax.base_url.as_ref()
|
|
}
|
|
|
|
fn get_auth_header(
|
|
&self,
|
|
auth_type: &types::ConnectorAuthType,
|
|
) -> CustomResult<Vec<(String, request::Maskable<String>)>, errors::ConnectorError> {
|
|
let auth = stax::StaxAuthType::try_from(auth_type)
|
|
.change_context(errors::ConnectorError::FailedToObtainAuthType)?;
|
|
|
|
Ok(vec![(
|
|
headers::AUTHORIZATION.to_string(),
|
|
format!("Bearer {}", auth.api_key.peek()).into_masked(),
|
|
)])
|
|
}
|
|
|
|
fn build_error_response(
|
|
&self,
|
|
res: Response,
|
|
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
|
|
Ok(ErrorResponse {
|
|
status_code: res.status_code,
|
|
code: consts::NO_ERROR_CODE.to_string(),
|
|
message: consts::NO_ERROR_MESSAGE.to_string(),
|
|
reason: Some(
|
|
std::str::from_utf8(&res.response)
|
|
.into_report()
|
|
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?
|
|
.to_owned(),
|
|
),
|
|
})
|
|
}
|
|
}
|
|
|
|
impl ConnectorValidation for Stax {
|
|
fn validate_capture_method(
|
|
&self,
|
|
capture_method: Option<enums::CaptureMethod>,
|
|
) -> CustomResult<(), errors::ConnectorError> {
|
|
let capture_method = capture_method.unwrap_or_default();
|
|
match capture_method {
|
|
enums::CaptureMethod::Automatic | enums::CaptureMethod::Manual => Ok(()),
|
|
enums::CaptureMethod::ManualMultiple | enums::CaptureMethod::Scheduled => Err(
|
|
connector_utils::construct_not_supported_error_report(capture_method, self.id()),
|
|
),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl api::ConnectorCustomer for Stax {}
|
|
|
|
impl
|
|
ConnectorIntegration<
|
|
api::CreateConnectorCustomer,
|
|
types::ConnectorCustomerData,
|
|
types::PaymentsResponseData,
|
|
> for Stax
|
|
{
|
|
fn get_headers(
|
|
&self,
|
|
req: &types::ConnectorCustomerRouterData,
|
|
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(
|
|
&self,
|
|
_req: &types::ConnectorCustomerRouterData,
|
|
connectors: &settings::Connectors,
|
|
) -> CustomResult<String, errors::ConnectorError> {
|
|
Ok(format!("{}customer", self.base_url(connectors),))
|
|
}
|
|
|
|
fn get_request_body(
|
|
&self,
|
|
req: &types::ConnectorCustomerRouterData,
|
|
) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> {
|
|
let connector_request = stax::StaxCustomerRequest::try_from(req)?;
|
|
|
|
let stax_req = types::RequestBody::log_and_get_request_body(
|
|
&connector_request,
|
|
utils::Encode::<stax::StaxCustomerRequest>::encode_to_string_of_json,
|
|
)
|
|
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
|
Ok(Some(stax_req))
|
|
}
|
|
|
|
fn build_request(
|
|
&self,
|
|
req: &types::ConnectorCustomerRouterData,
|
|
connectors: &settings::Connectors,
|
|
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
|
|
Ok(Some(
|
|
services::RequestBuilder::new()
|
|
.method(services::Method::Post)
|
|
.url(&types::ConnectorCustomerType::get_url(
|
|
self, req, connectors,
|
|
)?)
|
|
.attach_default_headers()
|
|
.headers(types::ConnectorCustomerType::get_headers(
|
|
self, req, connectors,
|
|
)?)
|
|
.body(types::ConnectorCustomerType::get_request_body(self, req)?)
|
|
.build(),
|
|
))
|
|
}
|
|
|
|
fn handle_response(
|
|
&self,
|
|
data: &types::ConnectorCustomerRouterData,
|
|
res: Response,
|
|
) -> CustomResult<types::ConnectorCustomerRouterData, errors::ConnectorError>
|
|
where
|
|
types::PaymentsResponseData: Clone,
|
|
{
|
|
let response: stax::StaxCustomerResponse = res
|
|
.response
|
|
.parse_struct("StaxCustomerResponse")
|
|
.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)
|
|
}
|
|
}
|
|
|
|
impl
|
|
ConnectorIntegration<
|
|
api::PaymentMethodToken,
|
|
types::PaymentMethodTokenizationData,
|
|
types::PaymentsResponseData,
|
|
> for Stax
|
|
{
|
|
fn get_headers(
|
|
&self,
|
|
req: &types::TokenizationRouterData,
|
|
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(
|
|
&self,
|
|
_req: &types::TokenizationRouterData,
|
|
connectors: &settings::Connectors,
|
|
) -> CustomResult<String, errors::ConnectorError> {
|
|
Ok(format!("{}payment-method/", self.base_url(connectors)))
|
|
}
|
|
|
|
fn get_request_body(
|
|
&self,
|
|
req: &types::TokenizationRouterData,
|
|
) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> {
|
|
let connector_request = stax::StaxTokenRequest::try_from(req)?;
|
|
|
|
let stax_req = types::RequestBody::log_and_get_request_body(
|
|
&connector_request,
|
|
utils::Encode::<stax::StaxTokenRequest>::encode_to_string_of_json,
|
|
)
|
|
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
|
Ok(Some(stax_req))
|
|
}
|
|
|
|
fn build_request(
|
|
&self,
|
|
req: &types::TokenizationRouterData,
|
|
connectors: &settings::Connectors,
|
|
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
|
|
Ok(Some(
|
|
services::RequestBuilder::new()
|
|
.method(services::Method::Post)
|
|
.url(&types::TokenizationType::get_url(self, req, connectors)?)
|
|
.attach_default_headers()
|
|
.headers(types::TokenizationType::get_headers(self, req, connectors)?)
|
|
.body(types::TokenizationType::get_request_body(self, req)?)
|
|
.build(),
|
|
))
|
|
}
|
|
|
|
fn handle_response(
|
|
&self,
|
|
data: &types::TokenizationRouterData,
|
|
res: Response,
|
|
) -> CustomResult<types::TokenizationRouterData, errors::ConnectorError>
|
|
where
|
|
types::PaymentsResponseData: Clone,
|
|
{
|
|
let response: stax::StaxTokenResponse = res
|
|
.response
|
|
.parse_struct("StaxTokenResponse")
|
|
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
|
|
|
types::RouterData::try_from(types::ResponseRouterData {
|
|
response,
|
|
data: data.clone(),
|
|
http_code: res.status_code,
|
|
})
|
|
.change_context(errors::ConnectorError::ResponseHandlingFailed)
|
|
}
|
|
fn get_error_response(
|
|
&self,
|
|
res: Response,
|
|
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
|
|
self.build_error_response(res)
|
|
}
|
|
}
|
|
|
|
impl ConnectorIntegration<api::Session, types::PaymentsSessionData, types::PaymentsResponseData>
|
|
for Stax
|
|
{
|
|
//TODO: implement sessions flow
|
|
}
|
|
|
|
impl ConnectorIntegration<api::AccessTokenAuth, types::AccessTokenRequestData, types::AccessToken>
|
|
for Stax
|
|
{
|
|
}
|
|
|
|
impl ConnectorIntegration<api::Verify, types::VerifyRequestData, types::PaymentsResponseData>
|
|
for Stax
|
|
{
|
|
}
|
|
|
|
impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::PaymentsResponseData>
|
|
for Stax
|
|
{
|
|
fn get_headers(
|
|
&self,
|
|
req: &types::PaymentsAuthorizeRouterData,
|
|
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(
|
|
&self,
|
|
_req: &types::PaymentsAuthorizeRouterData,
|
|
connectors: &settings::Connectors,
|
|
) -> CustomResult<String, errors::ConnectorError> {
|
|
Ok(format!("{}charge", self.base_url(connectors),))
|
|
}
|
|
|
|
fn get_request_body(
|
|
&self,
|
|
req: &types::PaymentsAuthorizeRouterData,
|
|
) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> {
|
|
let req_obj = stax::StaxPaymentsRequest::try_from(req)?;
|
|
|
|
let stax_req = types::RequestBody::log_and_get_request_body(
|
|
&req_obj,
|
|
utils::Encode::<stax::StaxPaymentsRequest>::encode_to_string_of_json,
|
|
)
|
|
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
|
Ok(Some(stax_req))
|
|
}
|
|
|
|
fn build_request(
|
|
&self,
|
|
req: &types::PaymentsAuthorizeRouterData,
|
|
connectors: &settings::Connectors,
|
|
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
|
|
self.validate_capture_method(req.request.capture_method)?;
|
|
Ok(Some(
|
|
services::RequestBuilder::new()
|
|
.method(services::Method::Post)
|
|
.url(&types::PaymentsAuthorizeType::get_url(
|
|
self, req, connectors,
|
|
)?)
|
|
.attach_default_headers()
|
|
.headers(types::PaymentsAuthorizeType::get_headers(
|
|
self, req, connectors,
|
|
)?)
|
|
.body(types::PaymentsAuthorizeType::get_request_body(self, req)?)
|
|
.build(),
|
|
))
|
|
}
|
|
|
|
fn handle_response(
|
|
&self,
|
|
data: &types::PaymentsAuthorizeRouterData,
|
|
res: Response,
|
|
) -> CustomResult<types::PaymentsAuthorizeRouterData, errors::ConnectorError> {
|
|
let response: stax::StaxPaymentsResponse = res
|
|
.response
|
|
.parse_struct("StaxPaymentsAuthorizeResponse")
|
|
.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)
|
|
}
|
|
}
|
|
|
|
impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsResponseData>
|
|
for Stax
|
|
{
|
|
fn get_headers(
|
|
&self,
|
|
req: &types::PaymentsSyncRouterData,
|
|
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(
|
|
&self,
|
|
req: &types::PaymentsSyncRouterData,
|
|
connectors: &settings::Connectors,
|
|
) -> CustomResult<String, errors::ConnectorError> {
|
|
let connector_payment_id = req
|
|
.request
|
|
.connector_transaction_id
|
|
.get_connector_transaction_id()
|
|
.change_context(errors::ConnectorError::MissingConnectorTransactionID)?;
|
|
|
|
Ok(format!(
|
|
"{}/transaction/{connector_payment_id}",
|
|
self.base_url(connectors),
|
|
))
|
|
}
|
|
|
|
fn build_request(
|
|
&self,
|
|
req: &types::PaymentsSyncRouterData,
|
|
connectors: &settings::Connectors,
|
|
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
|
|
Ok(Some(
|
|
services::RequestBuilder::new()
|
|
.method(services::Method::Get)
|
|
.url(&types::PaymentsSyncType::get_url(self, req, connectors)?)
|
|
.attach_default_headers()
|
|
.headers(types::PaymentsSyncType::get_headers(self, req, connectors)?)
|
|
.build(),
|
|
))
|
|
}
|
|
|
|
fn handle_response(
|
|
&self,
|
|
data: &types::PaymentsSyncRouterData,
|
|
res: Response,
|
|
) -> CustomResult<types::PaymentsSyncRouterData, errors::ConnectorError> {
|
|
let response: stax::StaxPaymentsResponse = res
|
|
.response
|
|
.parse_struct("StaxPaymentsSyncResponse")
|
|
.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)
|
|
}
|
|
}
|
|
|
|
impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::PaymentsResponseData>
|
|
for Stax
|
|
{
|
|
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(
|
|
&self,
|
|
req: &types::PaymentsCaptureRouterData,
|
|
connectors: &settings::Connectors,
|
|
) -> CustomResult<String, errors::ConnectorError> {
|
|
Ok(format!(
|
|
"{}/transaction/{}/capture",
|
|
self.base_url(connectors),
|
|
req.request.connector_transaction_id,
|
|
))
|
|
}
|
|
|
|
fn get_request_body(
|
|
&self,
|
|
req: &types::PaymentsCaptureRouterData,
|
|
) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> {
|
|
let connector_req = stax::StaxCaptureRequest::try_from(req)?;
|
|
let stax_req = types::RequestBody::log_and_get_request_body(
|
|
&connector_req,
|
|
utils::Encode::<stax::StaxCaptureRequest>::encode_to_string_of_json,
|
|
)
|
|
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
|
Ok(Some(stax_req))
|
|
}
|
|
|
|
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(),
|
|
))
|
|
}
|
|
|
|
fn handle_response(
|
|
&self,
|
|
data: &types::PaymentsCaptureRouterData,
|
|
res: Response,
|
|
) -> CustomResult<types::PaymentsCaptureRouterData, errors::ConnectorError> {
|
|
let response: stax::StaxPaymentsResponse = res
|
|
.response
|
|
.parse_struct("StaxPaymentsCaptureResponse")
|
|
.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)
|
|
}
|
|
}
|
|
|
|
impl ConnectorIntegration<api::Void, types::PaymentsCancelData, types::PaymentsResponseData>
|
|
for Stax
|
|
{
|
|
fn get_headers(
|
|
&self,
|
|
req: &types::PaymentsCancelRouterData,
|
|
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(
|
|
&self,
|
|
req: &types::PaymentsCancelRouterData,
|
|
connectors: &settings::Connectors,
|
|
) -> CustomResult<String, errors::ConnectorError> {
|
|
Ok(format!(
|
|
"{}/transaction/{}/void-or-refund",
|
|
self.base_url(connectors),
|
|
req.request.connector_transaction_id,
|
|
))
|
|
}
|
|
|
|
fn build_request(
|
|
&self,
|
|
req: &types::PaymentsCancelRouterData,
|
|
connectors: &settings::Connectors,
|
|
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
|
|
Ok(Some(
|
|
services::RequestBuilder::new()
|
|
.method(services::Method::Post)
|
|
.url(&types::PaymentsVoidType::get_url(self, req, connectors)?)
|
|
.attach_default_headers()
|
|
.headers(types::PaymentsVoidType::get_headers(self, req, connectors)?)
|
|
.build(),
|
|
))
|
|
}
|
|
|
|
fn handle_response(
|
|
&self,
|
|
data: &types::PaymentsCancelRouterData,
|
|
res: Response,
|
|
) -> CustomResult<types::PaymentsCancelRouterData, errors::ConnectorError> {
|
|
let response: stax::StaxPaymentsResponse = res
|
|
.response
|
|
.parse_struct("StaxPaymentsVoidResponse")
|
|
.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)
|
|
}
|
|
}
|
|
|
|
impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsResponseData> for Stax {
|
|
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(
|
|
&self,
|
|
req: &types::RefundsRouterData<api::Execute>,
|
|
connectors: &settings::Connectors,
|
|
) -> CustomResult<String, errors::ConnectorError> {
|
|
let connector_transaction_id = if req.request.connector_metadata.is_some() {
|
|
let stax_capture: stax::StaxMetaData =
|
|
to_connector_meta(req.request.connector_metadata.clone())?;
|
|
stax_capture.capture_id
|
|
} else {
|
|
req.request.connector_transaction_id.clone()
|
|
};
|
|
|
|
Ok(format!(
|
|
"{}/transaction/{}/refund",
|
|
self.base_url(connectors),
|
|
connector_transaction_id,
|
|
))
|
|
}
|
|
|
|
fn get_request_body(
|
|
&self,
|
|
req: &types::RefundsRouterData<api::Execute>,
|
|
) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> {
|
|
let req_obj = stax::StaxRefundRequest::try_from(req)?;
|
|
let stax_req = types::RequestBody::log_and_get_request_body(
|
|
&req_obj,
|
|
utils::Encode::<stax::StaxRefundRequest>::encode_to_string_of_json,
|
|
)
|
|
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
|
Ok(Some(stax_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: stax::RefundResponse = res
|
|
.response
|
|
.parse_struct("StaxRefundResponse")
|
|
.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)
|
|
}
|
|
}
|
|
|
|
impl ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponseData> for Stax {
|
|
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(
|
|
&self,
|
|
req: &types::RefundSyncRouterData,
|
|
connectors: &settings::Connectors,
|
|
) -> CustomResult<String, errors::ConnectorError> {
|
|
Ok(format!(
|
|
"{}/transaction/{}",
|
|
self.base_url(connectors),
|
|
req.request.get_connector_refund_id()?,
|
|
))
|
|
}
|
|
|
|
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)?)
|
|
.build(),
|
|
))
|
|
}
|
|
|
|
fn handle_response(
|
|
&self,
|
|
data: &types::RefundSyncRouterData,
|
|
res: Response,
|
|
) -> CustomResult<types::RefundSyncRouterData, errors::ConnectorError> {
|
|
let response: stax::RefundResponse = res
|
|
.response
|
|
.parse_struct("StaxRefundSyncResponse")
|
|
.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)
|
|
}
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
impl api::IncomingWebhook for Stax {
|
|
async fn verify_webhook_source(
|
|
&self,
|
|
_request: &api::IncomingWebhookRequestDetails<'_>,
|
|
_merchant_account: &domain::MerchantAccount,
|
|
_merchant_connector_account: domain::MerchantConnectorAccount,
|
|
_connector_label: &str,
|
|
) -> CustomResult<bool, errors::ConnectorError> {
|
|
Ok(false)
|
|
}
|
|
|
|
fn get_webhook_object_reference_id(
|
|
&self,
|
|
request: &api::IncomingWebhookRequestDetails<'_>,
|
|
) -> CustomResult<api::webhooks::ObjectReferenceId, errors::ConnectorError> {
|
|
let webhook_body: stax::StaxWebhookBody = request
|
|
.body
|
|
.parse_struct("StaxWebhookBody")
|
|
.change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
|
|
|
|
match webhook_body.transaction_type {
|
|
stax::StaxWebhookEventType::Refund => {
|
|
Ok(api_models::webhooks::ObjectReferenceId::RefundId(
|
|
api_models::webhooks::RefundIdType::ConnectorRefundId(webhook_body.id),
|
|
))
|
|
}
|
|
stax::StaxWebhookEventType::Unknown => {
|
|
Err(errors::ConnectorError::WebhookEventTypeNotFound.into())
|
|
}
|
|
stax::StaxWebhookEventType::PreAuth
|
|
| stax::StaxWebhookEventType::Capture
|
|
| stax::StaxWebhookEventType::Charge
|
|
| stax::StaxWebhookEventType::Void => {
|
|
Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
|
|
api_models::payments::PaymentIdType::ConnectorTransactionId(match webhook_body
|
|
.transaction_type
|
|
{
|
|
stax::StaxWebhookEventType::Capture => webhook_body
|
|
.auth_id
|
|
.ok_or(errors::ConnectorError::WebhookReferenceIdNotFound)?,
|
|
_ => webhook_body.id,
|
|
}),
|
|
))
|
|
}
|
|
}
|
|
}
|
|
|
|
fn get_webhook_event_type(
|
|
&self,
|
|
request: &api::IncomingWebhookRequestDetails<'_>,
|
|
) -> CustomResult<api::IncomingWebhookEvent, errors::ConnectorError> {
|
|
let details: stax::StaxWebhookBody = request
|
|
.body
|
|
.parse_struct("StaxWebhookEventType")
|
|
.change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
|
|
|
|
Ok(match &details.transaction_type {
|
|
StaxWebhookEventType::Refund => match &details.success {
|
|
true => api::IncomingWebhookEvent::RefundSuccess,
|
|
false => api::IncomingWebhookEvent::RefundFailure,
|
|
},
|
|
StaxWebhookEventType::Capture | StaxWebhookEventType::Charge => {
|
|
match &details.success {
|
|
true => api::IncomingWebhookEvent::PaymentIntentSuccess,
|
|
false => api::IncomingWebhookEvent::PaymentIntentFailure,
|
|
}
|
|
}
|
|
StaxWebhookEventType::PreAuth
|
|
| StaxWebhookEventType::Void
|
|
| StaxWebhookEventType::Unknown => api::IncomingWebhookEvent::EventNotSupported,
|
|
})
|
|
}
|
|
|
|
fn get_webhook_resource_object(
|
|
&self,
|
|
request: &api::IncomingWebhookRequestDetails<'_>,
|
|
) -> CustomResult<serde_json::Value, errors::ConnectorError> {
|
|
let reference_object: serde_json::Value = serde_json::from_slice(request.body)
|
|
.into_report()
|
|
.change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
|
|
Ok(reference_object)
|
|
}
|
|
}
|