mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
feat(connector): add psync for authorizedotnet (#7)
This commit is contained in:
@ -60,7 +60,6 @@ impl
|
||||
// Not Implemented (R)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
type PSync = dyn services::ConnectorIntegration<
|
||||
api::PSync,
|
||||
types::PaymentsRequestSyncData,
|
||||
@ -73,7 +72,109 @@ impl
|
||||
types::PaymentsResponseData,
|
||||
> for Authorizedotnet
|
||||
{
|
||||
// Not Implemented (R)
|
||||
fn get_headers(
|
||||
&self,
|
||||
_req: &types::PaymentsRouterSyncData,
|
||||
) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
|
||||
// This connector does not require an auth header, the authentication details are sent in the request body
|
||||
Ok(vec![
|
||||
(
|
||||
headers::CONTENT_TYPE.to_string(),
|
||||
PSync::get_content_type(self).to_string(),
|
||||
),
|
||||
(headers::X_ROUTER.to_string(), "test".to_string()),
|
||||
])
|
||||
}
|
||||
|
||||
fn get_content_type(&self) -> &'static str {
|
||||
"application/json"
|
||||
}
|
||||
|
||||
fn get_url(
|
||||
&self,
|
||||
_req: &types::PaymentsRouterSyncData,
|
||||
connectors: Connectors,
|
||||
) -> CustomResult<String, errors::ConnectorError> {
|
||||
Ok(self.base_url(connectors))
|
||||
}
|
||||
|
||||
fn get_request_body(
|
||||
&self,
|
||||
req: &types::PaymentsRouterSyncData,
|
||||
) -> CustomResult<Option<String>, errors::ConnectorError> {
|
||||
let sync_request =
|
||||
utils::Encode::<authorizedotnet::AuthorizedotnetCreateSyncRequest>::convert_and_encode(
|
||||
req,
|
||||
)
|
||||
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
||||
Ok(Some(sync_request))
|
||||
}
|
||||
|
||||
fn build_request(
|
||||
&self,
|
||||
req: &types::PaymentsRouterSyncData,
|
||||
connectors: Connectors,
|
||||
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
|
||||
let request = services::RequestBuilder::new()
|
||||
.method(services::Method::Post)
|
||||
.url(&PSync::get_url(self, req, connectors)?)
|
||||
.headers(PSync::get_headers(self, req)?)
|
||||
.body(PSync::get_request_body(self, req)?)
|
||||
.build();
|
||||
Ok(Some(request))
|
||||
}
|
||||
|
||||
fn handle_response(
|
||||
&self,
|
||||
data: &types::PaymentsRouterSyncData,
|
||||
res: Response,
|
||||
) -> CustomResult<types::PaymentsRouterSyncData, errors::ConnectorError> {
|
||||
use bytes::Buf;
|
||||
|
||||
// Handle the case where response bytes contains U+FEFF (BOM) character sent by connector
|
||||
let encoding = encoding_rs::UTF_8;
|
||||
let intermediate_response = encoding.decode_with_bom_removal(res.response.chunk());
|
||||
let intermediate_response =
|
||||
bytes::Bytes::copy_from_slice(intermediate_response.0.as_bytes());
|
||||
|
||||
let response: authorizedotnet::AuthorizedotnetSyncResponse = intermediate_response
|
||||
.parse_struct("AuthorizedotnetSyncResponse")
|
||||
.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: Bytes,
|
||||
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
|
||||
let response: authorizedotnet::AuthorizedotnetPaymentsResponse = res
|
||||
.parse_struct("AuthorizedotnetPaymentsResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
|
||||
let error = response
|
||||
.transaction_response
|
||||
.errors
|
||||
.and_then(|errors| {
|
||||
errors.first().map(|error| types::ErrorResponse {
|
||||
code: error.error_code.clone(),
|
||||
message: error.error_text.clone(),
|
||||
reason: None,
|
||||
})
|
||||
})
|
||||
.unwrap_or_else(|| types::ErrorResponse {
|
||||
code: consts::NO_ERROR_CODE.to_string(),
|
||||
message: consts::NO_ERROR_MESSAGE.to_string(),
|
||||
reason: None,
|
||||
});
|
||||
|
||||
Ok(error)
|
||||
}
|
||||
}
|
||||
|
||||
type Authorize = dyn services::ConnectorIntegration<
|
||||
@ -487,8 +588,10 @@ impl
|
||||
req: &types::RefundsRouterData<api::RSync>,
|
||||
) -> CustomResult<Option<String>, errors::ConnectorError> {
|
||||
let sync_request =
|
||||
utils::Encode::<authorizedotnet::CreateSyncRequest>::convert_and_encode(req)
|
||||
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
||||
utils::Encode::<authorizedotnet::AuthorizedotnetCreateSyncRequest>::convert_and_encode(
|
||||
req,
|
||||
)
|
||||
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
||||
Ok(Some(sync_request))
|
||||
}
|
||||
|
||||
@ -519,8 +622,8 @@ impl
|
||||
let intermediate_response =
|
||||
bytes::Bytes::copy_from_slice(intermediate_response.0.as_bytes());
|
||||
|
||||
let response: authorizedotnet::SyncResponse = intermediate_response
|
||||
.parse_struct("SyncResponse")
|
||||
let response: authorizedotnet::AuthorizedotnetSyncResponse = intermediate_response
|
||||
.parse_struct("AuthorizedotnetSyncResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
|
||||
types::RouterData::try_from(types::ResponseRouterData {
|
||||
|
||||
@ -427,11 +427,11 @@ pub struct TransactionDetails {
|
||||
}
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateSyncRequest {
|
||||
pub struct AuthorizedotnetCreateSyncRequest {
|
||||
get_transaction_details_request: TransactionDetails,
|
||||
}
|
||||
|
||||
impl<F> TryFrom<&types::RefundsRouterData<F>> for CreateSyncRequest {
|
||||
impl<F> TryFrom<&types::RefundsRouterData<F>> for AuthorizedotnetCreateSyncRequest {
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
|
||||
fn try_from(item: &types::RefundsRouterData<F>) -> Result<Self, Self::Error> {
|
||||
@ -441,7 +441,27 @@ impl<F> TryFrom<&types::RefundsRouterData<F>> for CreateSyncRequest {
|
||||
.map(|refund_response_data| refund_response_data.connector_refund_id.clone());
|
||||
let merchant_authentication = MerchantAuthentication::try_from(&item.connector_auth_type)?;
|
||||
|
||||
let payload = CreateSyncRequest {
|
||||
let payload = AuthorizedotnetCreateSyncRequest {
|
||||
get_transaction_details_request: TransactionDetails {
|
||||
merchant_authentication,
|
||||
transaction_id,
|
||||
},
|
||||
};
|
||||
Ok(payload)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&types::PaymentsRouterSyncData> for AuthorizedotnetCreateSyncRequest {
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
|
||||
fn try_from(item: &types::PaymentsRouterSyncData) -> Result<Self, Self::Error> {
|
||||
let transaction_id = item
|
||||
.response
|
||||
.as_ref()
|
||||
.map(|payment_response_data| payment_response_data.connector_transaction_id.clone());
|
||||
let merchant_authentication = MerchantAuthentication::try_from(&item.connector_auth_type)?;
|
||||
|
||||
let payload = AuthorizedotnetCreateSyncRequest {
|
||||
get_transaction_details_request: TransactionDetails {
|
||||
merchant_authentication,
|
||||
transaction_id,
|
||||
@ -456,6 +476,13 @@ impl<F> TryFrom<&types::RefundsRouterData<F>> for CreateSyncRequest {
|
||||
pub enum SyncStatus {
|
||||
RefundSettledSuccessfully,
|
||||
RefundPendingSettlement,
|
||||
AuthorizedPendingCapture,
|
||||
CapturedPendingSettlement,
|
||||
SettledSuccessfully,
|
||||
Declined,
|
||||
Voided,
|
||||
CouldNotVoid,
|
||||
GeneralError,
|
||||
}
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@ -466,7 +493,7 @@ pub struct SyncTransactionResponse {
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct SyncResponse {
|
||||
pub struct AuthorizedotnetSyncResponse {
|
||||
transaction: SyncTransactionResponse,
|
||||
}
|
||||
|
||||
@ -475,17 +502,33 @@ impl From<SyncStatus> for enums::RefundStatus {
|
||||
match transaction_status {
|
||||
SyncStatus::RefundSettledSuccessfully => enums::RefundStatus::Success,
|
||||
SyncStatus::RefundPendingSettlement => enums::RefundStatus::Pending,
|
||||
_ => enums::RefundStatus::Failure,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<types::RefundsResponseRouterData<api::RSync, SyncResponse>>
|
||||
impl From<SyncStatus> for enums::AttemptStatus {
|
||||
fn from(transaction_status: SyncStatus) -> Self {
|
||||
match transaction_status {
|
||||
SyncStatus::SettledSuccessfully | SyncStatus::CapturedPendingSettlement => {
|
||||
enums::AttemptStatus::Charged
|
||||
}
|
||||
SyncStatus::Declined => enums::AttemptStatus::AuthenticationFailed,
|
||||
SyncStatus::Voided => enums::AttemptStatus::Voided,
|
||||
SyncStatus::CouldNotVoid => enums::AttemptStatus::VoidFailed,
|
||||
SyncStatus::GeneralError => enums::AttemptStatus::Failure,
|
||||
_ => enums::AttemptStatus::Pending,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<types::RefundsResponseRouterData<api::RSync, AuthorizedotnetSyncResponse>>
|
||||
for types::RefundsRouterData<api::RSync>
|
||||
{
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
|
||||
fn try_from(
|
||||
item: types::RefundsResponseRouterData<api::RSync, SyncResponse>,
|
||||
item: types::RefundsResponseRouterData<api::RSync, AuthorizedotnetSyncResponse>,
|
||||
) -> Result<Self, Self::Error> {
|
||||
let refund_status = enums::RefundStatus::from(item.response.transaction.transaction_status);
|
||||
Ok(types::RouterData {
|
||||
@ -498,6 +541,35 @@ impl TryFrom<types::RefundsResponseRouterData<api::RSync, SyncResponse>>
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, Req>
|
||||
TryFrom<
|
||||
types::ResponseRouterData<F, AuthorizedotnetSyncResponse, Req, types::PaymentsResponseData>,
|
||||
> for types::RouterData<F, Req, types::PaymentsResponseData>
|
||||
{
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
|
||||
fn try_from(
|
||||
item: types::ResponseRouterData<
|
||||
F,
|
||||
AuthorizedotnetSyncResponse,
|
||||
Req,
|
||||
types::PaymentsResponseData,
|
||||
>,
|
||||
) -> Result<Self, Self::Error> {
|
||||
let payment_status =
|
||||
enums::AttemptStatus::from(item.response.transaction.transaction_status);
|
||||
Ok(types::RouterData {
|
||||
response: Some(types::PaymentsResponseData {
|
||||
connector_transaction_id: item.response.transaction.transaction_id,
|
||||
redirection_data: None,
|
||||
redirect: false,
|
||||
}),
|
||||
status: payment_status,
|
||||
..item.data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Eq, PartialEq, Deserialize)]
|
||||
pub struct ErrorDetails {
|
||||
pub code: Option<String>,
|
||||
|
||||
Reference in New Issue
Block a user