mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-01 11:06:50 +08:00
feat(connector): [Authorizedotnet] implement Capture flow and webhooks for Authorizedotnet (#1171)
Signed-off-by: chikke srujan <121822803+srujanchikke@users.noreply.github.com> Co-authored-by: Jagan <jaganelavarasan@gmail.com>
This commit is contained in:
@ -3,6 +3,7 @@ mod transformers;
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
use common_utils::{crypto, ext_traits::ByteSliceExt};
|
||||
use error_stack::{IntoReport, ResultExt};
|
||||
use transformers as authorizedotnet;
|
||||
|
||||
@ -10,11 +11,12 @@ use crate::{
|
||||
configs::settings,
|
||||
consts,
|
||||
core::errors::{self, CustomResult},
|
||||
db::StorageInterface,
|
||||
headers,
|
||||
services::{self, logger},
|
||||
services::{self, ConnectorIntegration},
|
||||
types::{
|
||||
self,
|
||||
api::{self, ConnectorCommon},
|
||||
api::{self, ConnectorCommon, ConnectorCommonExt},
|
||||
},
|
||||
utils::{self, BytesExt},
|
||||
};
|
||||
@ -22,6 +24,22 @@ use crate::{
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Authorizedotnet;
|
||||
|
||||
impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Authorizedotnet
|
||||
where
|
||||
Self: ConnectorIntegration<Flow, Request, Response>,
|
||||
{
|
||||
fn build_headers(
|
||||
&self,
|
||||
_req: &types::RouterData<Flow, Request, Response>,
|
||||
_connectors: &settings::Connectors,
|
||||
) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
|
||||
Ok(vec![(
|
||||
headers::CONTENT_TYPE.to_string(),
|
||||
self.get_content_type().to_string(),
|
||||
)])
|
||||
}
|
||||
}
|
||||
|
||||
impl ConnectorCommon for Authorizedotnet {
|
||||
fn id(&self) -> &'static str {
|
||||
"authorizedotnet"
|
||||
@ -46,7 +64,7 @@ impl api::ConnectorAccessToken for Authorizedotnet {}
|
||||
impl api::PaymentToken for Authorizedotnet {}
|
||||
|
||||
impl
|
||||
services::ConnectorIntegration<
|
||||
ConnectorIntegration<
|
||||
api::PaymentMethodToken,
|
||||
types::PaymentMethodTokenizationData,
|
||||
types::PaymentsResponseData,
|
||||
@ -55,62 +73,121 @@ impl
|
||||
// Not Implemented (R)
|
||||
}
|
||||
|
||||
impl
|
||||
services::ConnectorIntegration<
|
||||
api::Session,
|
||||
types::PaymentsSessionData,
|
||||
types::PaymentsResponseData,
|
||||
> for Authorizedotnet
|
||||
impl ConnectorIntegration<api::Session, types::PaymentsSessionData, types::PaymentsResponseData>
|
||||
for Authorizedotnet
|
||||
{
|
||||
// Not Implemented (R)
|
||||
}
|
||||
|
||||
impl
|
||||
services::ConnectorIntegration<
|
||||
api::AccessTokenAuth,
|
||||
types::AccessTokenRequestData,
|
||||
types::AccessToken,
|
||||
> for Authorizedotnet
|
||||
impl ConnectorIntegration<api::AccessTokenAuth, types::AccessTokenRequestData, types::AccessToken>
|
||||
for Authorizedotnet
|
||||
{
|
||||
// Not Implemented (R)
|
||||
}
|
||||
|
||||
impl api::PreVerify for Authorizedotnet {}
|
||||
|
||||
impl
|
||||
services::ConnectorIntegration<
|
||||
api::Verify,
|
||||
types::VerifyRequestData,
|
||||
types::PaymentsResponseData,
|
||||
> for Authorizedotnet
|
||||
impl ConnectorIntegration<api::Verify, types::VerifyRequestData, types::PaymentsResponseData>
|
||||
for Authorizedotnet
|
||||
{
|
||||
// Issue: #173
|
||||
}
|
||||
|
||||
impl
|
||||
services::ConnectorIntegration<
|
||||
api::Capture,
|
||||
types::PaymentsCaptureData,
|
||||
types::PaymentsResponseData,
|
||||
> for Authorizedotnet
|
||||
{
|
||||
// Not Implemented (R)
|
||||
}
|
||||
|
||||
impl
|
||||
services::ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsResponseData>
|
||||
impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::PaymentsResponseData>
|
||||
for Authorizedotnet
|
||||
{
|
||||
fn get_headers(
|
||||
&self,
|
||||
_req: &types::PaymentsSyncRouterData,
|
||||
_connectors: &settings::Connectors,
|
||||
req: &types::PaymentsCaptureRouterData,
|
||||
connectors: &settings::Connectors,
|
||||
) -> CustomResult<Vec<(String, 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(self.base_url(connectors).to_string())
|
||||
}
|
||||
fn get_request_body(
|
||||
&self,
|
||||
req: &types::PaymentsCaptureRouterData,
|
||||
) -> CustomResult<Option<String>, errors::ConnectorError> {
|
||||
let connector_req = authorizedotnet::CancelOrCaptureTransactionRequest::try_from(req)?;
|
||||
let authorizedotnet_req =
|
||||
utils::Encode::<authorizedotnet::CancelOrCaptureTransactionRequest>::encode_to_string_of_json(
|
||||
&connector_req,
|
||||
)
|
||||
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
||||
Ok(Some(authorizedotnet_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: types::Response,
|
||||
) -> CustomResult<types::PaymentsCaptureRouterData, 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::AuthorizedotnetPaymentsResponse = intermediate_response
|
||||
.parse_struct("AuthorizedotnetPaymentsResponse")
|
||||
.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: types::Response,
|
||||
) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
|
||||
get_error_response(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsResponseData>
|
||||
for Authorizedotnet
|
||||
{
|
||||
fn get_headers(
|
||||
&self,
|
||||
req: &types::PaymentsSyncRouterData,
|
||||
connectors: &settings::Connectors,
|
||||
) -> 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(),
|
||||
types::PaymentsSyncType::get_content_type(self).to_string(),
|
||||
)])
|
||||
self.build_headers(req, connectors)
|
||||
}
|
||||
|
||||
fn get_content_type(&self) -> &'static str {
|
||||
@ -175,7 +252,6 @@ impl
|
||||
data: data.clone(),
|
||||
http_code: res.status_code,
|
||||
})
|
||||
.change_context(errors::ConnectorError::ResponseHandlingFailed)
|
||||
}
|
||||
|
||||
fn get_error_response(
|
||||
@ -186,23 +262,16 @@ impl
|
||||
}
|
||||
}
|
||||
|
||||
impl
|
||||
services::ConnectorIntegration<
|
||||
api::Authorize,
|
||||
types::PaymentsAuthorizeData,
|
||||
types::PaymentsResponseData,
|
||||
> for Authorizedotnet
|
||||
impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::PaymentsResponseData>
|
||||
for Authorizedotnet
|
||||
{
|
||||
fn get_headers(
|
||||
&self,
|
||||
_req: &types::PaymentsAuthorizeRouterData,
|
||||
_connectors: &settings::Connectors,
|
||||
req: &types::PaymentsAuthorizeRouterData,
|
||||
connectors: &settings::Connectors,
|
||||
) -> 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(),
|
||||
types::PaymentsAuthorizeType::get_content_type(self).to_string(),
|
||||
)])
|
||||
self.build_headers(req, connectors)
|
||||
}
|
||||
|
||||
fn get_content_type(&self) -> &'static str {
|
||||
@ -221,7 +290,6 @@ impl
|
||||
&self,
|
||||
req: &types::PaymentsAuthorizeRouterData,
|
||||
) -> CustomResult<Option<String>, errors::ConnectorError> {
|
||||
logger::debug!(request=?req);
|
||||
let connector_req = authorizedotnet::CreateTransactionRequest::try_from(req)?;
|
||||
let authorizedotnet_req =
|
||||
utils::Encode::<authorizedotnet::CreateTransactionRequest>::encode_to_string_of_json(
|
||||
@ -261,7 +329,6 @@ impl
|
||||
res: types::Response,
|
||||
) -> CustomResult<types::PaymentsAuthorizeRouterData, errors::ConnectorError> {
|
||||
use bytes::Buf;
|
||||
logger::debug!(authorizedotnetpayments_create_response=?res);
|
||||
|
||||
// Handle the case where response bytes contains U+FEFF (BOM) character sent by connector
|
||||
let encoding = encoding_rs::UTF_8;
|
||||
@ -272,40 +339,30 @@ impl
|
||||
let response: authorizedotnet::AuthorizedotnetPaymentsResponse = intermediate_response
|
||||
.parse_struct("AuthorizedotnetPaymentsResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
|
||||
types::RouterData::try_from(types::ResponseRouterData {
|
||||
response,
|
||||
data: data.clone(),
|
||||
http_code: res.status_code,
|
||||
})
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)
|
||||
}
|
||||
|
||||
fn get_error_response(
|
||||
&self,
|
||||
res: types::Response,
|
||||
) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
|
||||
logger::debug!(authorizedotnetpayments_create_error_response=?res);
|
||||
get_error_response(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl
|
||||
services::ConnectorIntegration<
|
||||
api::Void,
|
||||
types::PaymentsCancelData,
|
||||
types::PaymentsResponseData,
|
||||
> for Authorizedotnet
|
||||
impl ConnectorIntegration<api::Void, types::PaymentsCancelData, types::PaymentsResponseData>
|
||||
for Authorizedotnet
|
||||
{
|
||||
fn get_headers(
|
||||
&self,
|
||||
_req: &types::PaymentsCancelRouterData,
|
||||
_connectors: &settings::Connectors,
|
||||
req: &types::PaymentsCancelRouterData,
|
||||
connectors: &settings::Connectors,
|
||||
) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
|
||||
Ok(vec![(
|
||||
headers::CONTENT_TYPE.to_string(),
|
||||
types::PaymentsAuthorizeType::get_content_type(self).to_string(),
|
||||
)])
|
||||
self.build_headers(req, connectors)
|
||||
}
|
||||
|
||||
fn get_content_type(&self) -> &'static str {
|
||||
@ -324,9 +381,9 @@ impl
|
||||
&self,
|
||||
req: &types::PaymentsCancelRouterData,
|
||||
) -> CustomResult<Option<String>, errors::ConnectorError> {
|
||||
let connector_req = authorizedotnet::CancelTransactionRequest::try_from(req)?;
|
||||
let connector_req = authorizedotnet::CancelOrCaptureTransactionRequest::try_from(req)?;
|
||||
let authorizedotnet_req =
|
||||
utils::Encode::<authorizedotnet::CancelTransactionRequest>::encode_to_string_of_json(
|
||||
utils::Encode::<authorizedotnet::CancelOrCaptureTransactionRequest>::encode_to_string_of_json(
|
||||
&connector_req,
|
||||
)
|
||||
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
||||
@ -361,17 +418,15 @@ impl
|
||||
let intermediate_response =
|
||||
bytes::Bytes::copy_from_slice(intermediate_response.0.as_bytes());
|
||||
|
||||
let response: authorizedotnet::AuthorizedotnetPaymentsResponse = intermediate_response
|
||||
let response: authorizedotnet::AuthorizedotnetVoidResponse = intermediate_response
|
||||
.parse_struct("AuthorizedotnetPaymentsResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
logger::debug!(authorizedotnetpayments_create_response=?response);
|
||||
|
||||
types::RouterData::try_from(types::ResponseRouterData {
|
||||
response,
|
||||
data: data.clone(),
|
||||
http_code: res.status_code,
|
||||
})
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)
|
||||
}
|
||||
|
||||
fn get_error_response(
|
||||
@ -386,19 +441,16 @@ impl api::Refund for Authorizedotnet {}
|
||||
impl api::RefundExecute for Authorizedotnet {}
|
||||
impl api::RefundSync for Authorizedotnet {}
|
||||
|
||||
impl services::ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsResponseData>
|
||||
impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsResponseData>
|
||||
for Authorizedotnet
|
||||
{
|
||||
fn get_headers(
|
||||
&self,
|
||||
_req: &types::RefundsRouterData<api::Execute>,
|
||||
_connectors: &settings::Connectors,
|
||||
req: &types::RefundsRouterData<api::Execute>,
|
||||
connectors: &settings::Connectors,
|
||||
) -> 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(),
|
||||
types::PaymentsAuthorizeType::get_content_type(self).to_string(),
|
||||
)])
|
||||
self.build_headers(req, connectors)
|
||||
}
|
||||
|
||||
fn get_content_type(&self) -> &'static str {
|
||||
@ -417,7 +469,6 @@ impl services::ConnectorIntegration<api::Execute, types::RefundsData, types::Ref
|
||||
&self,
|
||||
req: &types::RefundsRouterData<api::Execute>,
|
||||
) -> CustomResult<Option<String>, errors::ConnectorError> {
|
||||
logger::debug!(refund_request=?req);
|
||||
let connector_req = authorizedotnet::CreateRefundRequest::try_from(req)?;
|
||||
let authorizedotnet_req =
|
||||
utils::Encode::<authorizedotnet::CreateRefundRequest>::encode_to_string_of_json(
|
||||
@ -450,7 +501,6 @@ impl services::ConnectorIntegration<api::Execute, types::RefundsData, types::Ref
|
||||
res: types::Response,
|
||||
) -> CustomResult<types::RefundsRouterData<api::Execute>, errors::ConnectorError> {
|
||||
use bytes::Buf;
|
||||
logger::debug!(response=?res);
|
||||
|
||||
// Handle the case where response bytes contains U+FEFF (BOM) character sent by connector
|
||||
let encoding = encoding_rs::UTF_8;
|
||||
@ -461,14 +511,12 @@ impl services::ConnectorIntegration<api::Execute, types::RefundsData, types::Ref
|
||||
let response: authorizedotnet::AuthorizedotnetRefundResponse = intermediate_response
|
||||
.parse_struct("AuthorizedotnetRefundResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
logger::info!(response=?res);
|
||||
|
||||
types::RouterData::try_from(types::ResponseRouterData {
|
||||
response,
|
||||
data: data.clone(),
|
||||
http_code: res.status_code,
|
||||
})
|
||||
.change_context(errors::ConnectorError::ResponseHandlingFailed)
|
||||
}
|
||||
|
||||
fn get_error_response(
|
||||
@ -479,19 +527,16 @@ impl services::ConnectorIntegration<api::Execute, types::RefundsData, types::Ref
|
||||
}
|
||||
}
|
||||
|
||||
impl services::ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponseData>
|
||||
impl ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponseData>
|
||||
for Authorizedotnet
|
||||
{
|
||||
fn get_headers(
|
||||
&self,
|
||||
_req: &types::RefundsRouterData<api::RSync>,
|
||||
_connectors: &settings::Connectors,
|
||||
req: &types::RefundsRouterData<api::RSync>,
|
||||
connectors: &settings::Connectors,
|
||||
) -> 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(),
|
||||
types::RefundSyncType::get_content_type(self).to_string(),
|
||||
)])
|
||||
self.build_headers(req, connectors)
|
||||
}
|
||||
|
||||
fn get_content_type(&self) -> &'static str {
|
||||
@ -556,7 +601,6 @@ impl services::ConnectorIntegration<api::RSync, types::RefundsData, types::Refun
|
||||
data: data.clone(),
|
||||
http_code: res.status_code,
|
||||
})
|
||||
.change_context(errors::ConnectorError::ResponseHandlingFailed)
|
||||
}
|
||||
|
||||
fn get_error_response(
|
||||
@ -569,25 +613,109 @@ impl services::ConnectorIntegration<api::RSync, types::RefundsData, types::Refun
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl api::IncomingWebhook for Authorizedotnet {
|
||||
fn get_webhook_object_reference_id(
|
||||
fn get_webhook_source_verification_algorithm(
|
||||
&self,
|
||||
_request: &api::IncomingWebhookRequestDetails<'_>,
|
||||
) -> CustomResult<Box<dyn crypto::VerifySignature + Send>, errors::ConnectorError> {
|
||||
Ok(Box::new(crypto::HmacSha512))
|
||||
}
|
||||
|
||||
fn get_webhook_source_verification_signature(
|
||||
&self,
|
||||
request: &api::IncomingWebhookRequestDetails<'_>,
|
||||
) -> CustomResult<Vec<u8>, errors::ConnectorError> {
|
||||
let security_header = request
|
||||
.headers
|
||||
.get("X-ANET-Signature")
|
||||
.map(|header_value| {
|
||||
header_value
|
||||
.to_str()
|
||||
.map(String::from)
|
||||
.map_err(|_| errors::ConnectorError::WebhookSignatureNotFound)
|
||||
.into_report()
|
||||
})
|
||||
.ok_or(errors::ConnectorError::WebhookSignatureNotFound)
|
||||
.into_report()??
|
||||
.to_lowercase();
|
||||
let (_, sig_value) = security_header
|
||||
.split_once('=')
|
||||
.ok_or(errors::ConnectorError::WebhookSourceVerificationFailed)
|
||||
.into_report()?;
|
||||
hex::decode(sig_value)
|
||||
.into_report()
|
||||
.change_context(errors::ConnectorError::WebhookSignatureNotFound)
|
||||
}
|
||||
|
||||
fn get_webhook_source_verification_message(
|
||||
&self,
|
||||
request: &api::IncomingWebhookRequestDetails<'_>,
|
||||
_merchant_id: &str,
|
||||
_secret: &[u8],
|
||||
) -> CustomResult<Vec<u8>, errors::ConnectorError> {
|
||||
Ok(request.body.to_vec())
|
||||
}
|
||||
|
||||
fn get_webhook_object_reference_id(
|
||||
&self,
|
||||
request: &api::IncomingWebhookRequestDetails<'_>,
|
||||
) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
|
||||
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
|
||||
let details: authorizedotnet::AuthorizedotnetWebhookObjectId = request
|
||||
.body
|
||||
.parse_struct("AuthorizedotnetWebhookObjectId")
|
||||
.change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
|
||||
match details.event_type {
|
||||
authorizedotnet::AuthorizedotnetWebhookEvent::RefundCreated => {
|
||||
Ok(api_models::webhooks::ObjectReferenceId::RefundId(
|
||||
api_models::webhooks::RefundIdType::ConnectorRefundId(
|
||||
authorizedotnet::get_trans_id(details)?,
|
||||
),
|
||||
))
|
||||
}
|
||||
_ => Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
|
||||
api_models::payments::PaymentIdType::ConnectorTransactionId(
|
||||
authorizedotnet::get_trans_id(details)?,
|
||||
),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_webhook_source_verification_merchant_secret(
|
||||
&self,
|
||||
db: &dyn StorageInterface,
|
||||
merchant_id: &str,
|
||||
) -> CustomResult<Vec<u8>, errors::ConnectorError> {
|
||||
let key = format!("whsec_verification_{}_{}", self.id(), merchant_id);
|
||||
let secret = match db.find_config_by_key(&key).await {
|
||||
Ok(config) => Some(config),
|
||||
Err(e) => {
|
||||
crate::logger::warn!("Unable to fetch merchant webhook secret from DB: {:#?}", e);
|
||||
None
|
||||
}
|
||||
};
|
||||
Ok(secret
|
||||
.map(|conf| conf.config.into_bytes())
|
||||
.unwrap_or_default())
|
||||
}
|
||||
|
||||
fn get_webhook_event_type(
|
||||
&self,
|
||||
_request: &api::IncomingWebhookRequestDetails<'_>,
|
||||
request: &api::IncomingWebhookRequestDetails<'_>,
|
||||
) -> CustomResult<api::IncomingWebhookEvent, errors::ConnectorError> {
|
||||
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
|
||||
let details: authorizedotnet::AuthorizedotnetWebhookEventType = request
|
||||
.body
|
||||
.parse_struct("AuthorizedotnetWebhookEventType")
|
||||
.change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
|
||||
Ok(api::IncomingWebhookEvent::from(details.event_type))
|
||||
}
|
||||
|
||||
fn get_webhook_resource_object(
|
||||
&self,
|
||||
_request: &api::IncomingWebhookRequestDetails<'_>,
|
||||
request: &api::IncomingWebhookRequestDetails<'_>,
|
||||
) -> CustomResult<serde_json::Value, errors::ConnectorError> {
|
||||
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
|
||||
let payload = serde_json::to_value(request.body)
|
||||
.into_report()
|
||||
.change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
|
||||
Ok(payload)
|
||||
}
|
||||
}
|
||||
|
||||
@ -603,23 +731,33 @@ fn get_error_response(
|
||||
.parse_struct("AuthorizedotnetPaymentsResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
|
||||
logger::info!(response=?response);
|
||||
|
||||
Ok(response
|
||||
.transaction_response
|
||||
.errors
|
||||
.and_then(|errors| {
|
||||
errors.into_iter().next().map(|error| types::ErrorResponse {
|
||||
code: error.error_code,
|
||||
message: error.error_text,
|
||||
match response.transaction_response {
|
||||
Some(transaction_response) => Ok({
|
||||
transaction_response
|
||||
.errors
|
||||
.and_then(|errors| {
|
||||
errors.into_iter().next().map(|error| types::ErrorResponse {
|
||||
code: error.error_code,
|
||||
message: error.error_text,
|
||||
reason: None,
|
||||
status_code,
|
||||
})
|
||||
})
|
||||
.unwrap_or_else(|| types::ErrorResponse {
|
||||
code: consts::NO_ERROR_CODE.to_string(),
|
||||
message: consts::NO_ERROR_MESSAGE.to_string(),
|
||||
reason: None,
|
||||
status_code,
|
||||
})
|
||||
}),
|
||||
None => {
|
||||
let message = &response.messages.message[0].text;
|
||||
Ok(types::ErrorResponse {
|
||||
code: consts::NO_ERROR_CODE.to_string(),
|
||||
message: message.to_string(),
|
||||
reason: None,
|
||||
status_code,
|
||||
})
|
||||
})
|
||||
.unwrap_or_else(|| types::ErrorResponse {
|
||||
code: consts::NO_ERROR_CODE.to_string(),
|
||||
message: consts::NO_ERROR_MESSAGE.to_string(),
|
||||
reason: None,
|
||||
status_code,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ use error_stack::ResultExt;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
connector::utils::{CardData, RefundsRequestData},
|
||||
connector::utils::{CardData, PaymentsSyncRequestData, RefundsRequestData},
|
||||
core::errors,
|
||||
types::{self, api, storage::enums},
|
||||
utils::OptionExt,
|
||||
@ -13,6 +13,10 @@ use crate::{
|
||||
pub enum TransactionType {
|
||||
#[serde(rename = "authCaptureTransaction")]
|
||||
Payment,
|
||||
#[serde(rename = "authOnlyTransaction")]
|
||||
Authorization,
|
||||
#[serde(rename = "priorAuthCaptureTransaction")]
|
||||
Capture,
|
||||
#[serde(rename = "refundTransaction")]
|
||||
Refund,
|
||||
#[serde(rename = "voidTransaction")]
|
||||
@ -191,8 +195,9 @@ struct AuthorizationIndicator {
|
||||
|
||||
#[derive(Debug, Serialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct TransactionVoidRequest {
|
||||
struct TransactionVoidOrCaptureRequest {
|
||||
transaction_type: TransactionType,
|
||||
amount: Option<i64>,
|
||||
ref_trans_id: String,
|
||||
}
|
||||
|
||||
@ -205,9 +210,9 @@ pub struct AuthorizedotnetPaymentsRequest {
|
||||
|
||||
#[derive(Debug, Serialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AuthorizedotnetPaymentCancelRequest {
|
||||
pub struct AuthorizedotnetPaymentCancelOrCaptureRequest {
|
||||
merchant_authentication: MerchantAuthentication,
|
||||
transaction_request: TransactionVoidRequest,
|
||||
transaction_request: TransactionVoidOrCaptureRequest,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, PartialEq)]
|
||||
@ -219,8 +224,8 @@ pub struct CreateTransactionRequest {
|
||||
|
||||
#[derive(Debug, Serialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CancelTransactionRequest {
|
||||
create_transaction_request: AuthorizedotnetPaymentCancelRequest,
|
||||
pub struct CancelOrCaptureTransactionRequest {
|
||||
create_transaction_request: AuthorizedotnetPaymentCancelOrCaptureRequest,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, PartialEq, Eq)]
|
||||
@ -249,7 +254,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for CreateTransactionRequest {
|
||||
authorization_indicator: c.into(),
|
||||
});
|
||||
let transaction_request = TransactionRequest {
|
||||
transaction_type: TransactionType::Payment,
|
||||
transaction_type: TransactionType::from(item.request.capture_method),
|
||||
amount: item.request.amount,
|
||||
payment: payment_details,
|
||||
currency_code: item.request.currency.to_string(),
|
||||
@ -269,10 +274,11 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for CreateTransactionRequest {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&types::PaymentsCancelRouterData> for CancelTransactionRequest {
|
||||
impl TryFrom<&types::PaymentsCancelRouterData> for CancelOrCaptureTransactionRequest {
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
fn try_from(item: &types::PaymentsCancelRouterData) -> Result<Self, Self::Error> {
|
||||
let transaction_request = TransactionVoidRequest {
|
||||
let transaction_request = TransactionVoidOrCaptureRequest {
|
||||
amount: item.request.amount,
|
||||
transaction_type: TransactionType::Void,
|
||||
ref_trans_id: item.request.connector_transaction_id.to_string(),
|
||||
};
|
||||
@ -280,7 +286,27 @@ impl TryFrom<&types::PaymentsCancelRouterData> for CancelTransactionRequest {
|
||||
let merchant_authentication = MerchantAuthentication::try_from(&item.connector_auth_type)?;
|
||||
|
||||
Ok(Self {
|
||||
create_transaction_request: AuthorizedotnetPaymentCancelRequest {
|
||||
create_transaction_request: AuthorizedotnetPaymentCancelOrCaptureRequest {
|
||||
merchant_authentication,
|
||||
transaction_request,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&types::PaymentsCaptureRouterData> for CancelOrCaptureTransactionRequest {
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
fn try_from(item: &types::PaymentsCaptureRouterData) -> Result<Self, Self::Error> {
|
||||
let transaction_request = TransactionVoidOrCaptureRequest {
|
||||
amount: Some(item.request.amount_to_capture),
|
||||
transaction_type: TransactionType::Capture,
|
||||
ref_trans_id: item.request.connector_transaction_id.to_string(),
|
||||
};
|
||||
|
||||
let merchant_authentication = MerchantAuthentication::try_from(&item.connector_auth_type)?;
|
||||
|
||||
Ok(Self {
|
||||
create_transaction_request: AuthorizedotnetPaymentCancelOrCaptureRequest {
|
||||
merchant_authentication,
|
||||
transaction_request,
|
||||
},
|
||||
@ -306,7 +332,7 @@ pub type AuthorizedotnetRefundStatus = AuthorizedotnetPaymentStatus;
|
||||
impl From<AuthorizedotnetPaymentStatus> for enums::AttemptStatus {
|
||||
fn from(item: AuthorizedotnetPaymentStatus) -> Self {
|
||||
match item {
|
||||
AuthorizedotnetPaymentStatus::Approved => Self::Charged,
|
||||
AuthorizedotnetPaymentStatus::Approved => Self::Pending,
|
||||
AuthorizedotnetPaymentStatus::Declined | AuthorizedotnetPaymentStatus::Error => {
|
||||
Self::Failure
|
||||
}
|
||||
@ -316,9 +342,9 @@ impl From<AuthorizedotnetPaymentStatus> for enums::AttemptStatus {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||
struct ResponseMessage {
|
||||
pub struct ResponseMessage {
|
||||
code: String,
|
||||
text: String,
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||
@ -331,14 +357,14 @@ enum ResultCode {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ResponseMessages {
|
||||
result_code: ResultCode,
|
||||
message: Vec<ResponseMessage>,
|
||||
pub message: Vec<ResponseMessage>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(super) struct ErrorMessage {
|
||||
pub(super) error_code: String,
|
||||
pub(super) error_text: String,
|
||||
pub struct ErrorMessage {
|
||||
pub error_code: String,
|
||||
pub error_text: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
|
||||
@ -356,10 +382,51 @@ pub struct TransactionResponse {
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AuthorizedotnetPaymentsResponse {
|
||||
pub transaction_response: TransactionResponse,
|
||||
pub transaction_response: Option<TransactionResponse>,
|
||||
pub messages: ResponseMessages,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AuthorizedotnetVoidResponse {
|
||||
pub transaction_response: Option<VoidResponse>,
|
||||
pub messages: ResponseMessages,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct VoidResponse {
|
||||
response_code: AuthorizedotnetVoidStatus,
|
||||
auth_code: String,
|
||||
#[serde(rename = "transId")]
|
||||
transaction_id: String,
|
||||
network_trans_id: Option<String>,
|
||||
pub account_number: Option<String>,
|
||||
pub errors: Option<Vec<ErrorMessage>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub enum AuthorizedotnetVoidStatus {
|
||||
#[serde(rename = "1")]
|
||||
Approved,
|
||||
#[serde(rename = "2")]
|
||||
Declined,
|
||||
#[serde(rename = "3")]
|
||||
Error,
|
||||
#[serde(rename = "4")]
|
||||
HeldForReview,
|
||||
}
|
||||
|
||||
impl From<AuthorizedotnetVoidStatus> for enums::AttemptStatus {
|
||||
fn from(item: AuthorizedotnetVoidStatus) -> Self {
|
||||
match item {
|
||||
AuthorizedotnetVoidStatus::Approved => Self::VoidInitiated,
|
||||
AuthorizedotnetVoidStatus::Declined | AuthorizedotnetVoidStatus::Error => Self::Failure,
|
||||
AuthorizedotnetVoidStatus::HeldForReview => Self::Pending,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, T>
|
||||
TryFrom<
|
||||
types::ResponseRouterData<
|
||||
@ -379,50 +446,115 @@ impl<F, T>
|
||||
types::PaymentsResponseData,
|
||||
>,
|
||||
) -> Result<Self, Self::Error> {
|
||||
let status = enums::AttemptStatus::from(item.response.transaction_response.response_code);
|
||||
let error = item
|
||||
.response
|
||||
.transaction_response
|
||||
.errors
|
||||
.and_then(|errors| {
|
||||
errors.into_iter().next().map(|error| types::ErrorResponse {
|
||||
code: error.error_code,
|
||||
message: error.error_text,
|
||||
reason: None,
|
||||
status_code: item.http_code,
|
||||
match &item.response.transaction_response {
|
||||
Some(transaction_response) => {
|
||||
let status = enums::AttemptStatus::from(transaction_response.response_code.clone());
|
||||
let error = transaction_response.errors.as_ref().and_then(|errors| {
|
||||
errors.iter().next().map(|error| types::ErrorResponse {
|
||||
code: error.error_code.clone(),
|
||||
message: error.error_text.clone(),
|
||||
reason: None,
|
||||
status_code: item.http_code,
|
||||
})
|
||||
});
|
||||
let metadata = transaction_response
|
||||
.account_number
|
||||
.as_ref()
|
||||
.map(|acc_no| {
|
||||
Encode::<'_, PaymentDetails>::encode_to_value(
|
||||
&construct_refund_payment_details(acc_no.clone()),
|
||||
)
|
||||
})
|
||||
.transpose()
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "connector_metadata",
|
||||
})?;
|
||||
Ok(Self {
|
||||
status,
|
||||
response: match error {
|
||||
Some(err) => Err(err),
|
||||
None => Ok(types::PaymentsResponseData::TransactionResponse {
|
||||
resource_id: types::ResponseId::ConnectorTransactionId(
|
||||
transaction_response.transaction_id.clone(),
|
||||
),
|
||||
redirection_data: None,
|
||||
mandate_reference: None,
|
||||
connector_metadata: metadata,
|
||||
network_txn_id: transaction_response.network_trans_id.clone(),
|
||||
}),
|
||||
},
|
||||
..item.data
|
||||
})
|
||||
});
|
||||
}
|
||||
None => Ok(Self {
|
||||
status: enums::AttemptStatus::Failure,
|
||||
response: Err(get_err_response(item.http_code, item.response.messages)),
|
||||
..item.data
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let metadata = item
|
||||
.response
|
||||
.transaction_response
|
||||
.account_number
|
||||
.map(|acc_no| {
|
||||
Encode::<'_, PaymentDetails>::encode_to_value(&construct_refund_payment_details(
|
||||
acc_no,
|
||||
))
|
||||
})
|
||||
.transpose()
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "connector_metadata",
|
||||
})?;
|
||||
|
||||
Ok(Self {
|
||||
status,
|
||||
response: match error {
|
||||
Some(err) => Err(err),
|
||||
None => Ok(types::PaymentsResponseData::TransactionResponse {
|
||||
resource_id: types::ResponseId::ConnectorTransactionId(
|
||||
item.response.transaction_response.transaction_id,
|
||||
),
|
||||
redirection_data: None,
|
||||
mandate_reference: None,
|
||||
connector_metadata: metadata,
|
||||
network_txn_id: item.response.transaction_response.network_trans_id,
|
||||
}),
|
||||
},
|
||||
..item.data
|
||||
})
|
||||
impl<F, T>
|
||||
TryFrom<
|
||||
types::ResponseRouterData<F, AuthorizedotnetVoidResponse, T, types::PaymentsResponseData>,
|
||||
> for types::RouterData<F, T, types::PaymentsResponseData>
|
||||
{
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
fn try_from(
|
||||
item: types::ResponseRouterData<
|
||||
F,
|
||||
AuthorizedotnetVoidResponse,
|
||||
T,
|
||||
types::PaymentsResponseData,
|
||||
>,
|
||||
) -> Result<Self, Self::Error> {
|
||||
match &item.response.transaction_response {
|
||||
Some(transaction_response) => {
|
||||
let status = enums::AttemptStatus::from(transaction_response.response_code.clone());
|
||||
let error = transaction_response.errors.as_ref().and_then(|errors| {
|
||||
errors.iter().next().map(|error| types::ErrorResponse {
|
||||
code: error.error_code.clone(),
|
||||
message: error.error_text.clone(),
|
||||
reason: None,
|
||||
status_code: item.http_code,
|
||||
})
|
||||
});
|
||||
let metadata = transaction_response
|
||||
.account_number
|
||||
.as_ref()
|
||||
.map(|acc_no| {
|
||||
Encode::<'_, PaymentDetails>::encode_to_value(
|
||||
&construct_refund_payment_details(acc_no.clone()),
|
||||
)
|
||||
})
|
||||
.transpose()
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "connector_metadata",
|
||||
})?;
|
||||
Ok(Self {
|
||||
status,
|
||||
response: match error {
|
||||
Some(err) => Err(err),
|
||||
None => Ok(types::PaymentsResponseData::TransactionResponse {
|
||||
resource_id: types::ResponseId::ConnectorTransactionId(
|
||||
transaction_response.transaction_id.clone(),
|
||||
),
|
||||
redirection_data: None,
|
||||
mandate_reference: None,
|
||||
connector_metadata: metadata,
|
||||
network_txn_id: transaction_response.network_trans_id.clone(),
|
||||
}),
|
||||
},
|
||||
..item.data
|
||||
})
|
||||
}
|
||||
None => Ok(Self {
|
||||
status: enums::AttemptStatus::Failure,
|
||||
response: Err(get_err_response(item.http_code, item.response.messages)),
|
||||
..item.data
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -571,22 +703,11 @@ impl TryFrom<&types::PaymentsSyncRouterData> for AuthorizedotnetCreateSyncReques
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
|
||||
fn try_from(item: &types::PaymentsSyncRouterData) -> Result<Self, Self::Error> {
|
||||
let transaction_id = item
|
||||
.response
|
||||
.as_ref()
|
||||
.ok()
|
||||
.map(|payment_response_data| match payment_response_data {
|
||||
types::PaymentsResponseData::TransactionResponse { resource_id, .. } => {
|
||||
resource_id.get_connector_transaction_id()
|
||||
}
|
||||
_ => Err(error_stack::report!(
|
||||
errors::ValidationError::MissingRequiredField {
|
||||
field_name: "transaction_id".to_string()
|
||||
}
|
||||
)),
|
||||
})
|
||||
.transpose()
|
||||
.change_context(errors::ConnectorError::ResponseHandlingFailed)?;
|
||||
let transaction_id = Some(
|
||||
item.request
|
||||
.get_connector_transaction_id()
|
||||
.change_context(errors::ConnectorError::MissingConnectorTransactionID)?,
|
||||
);
|
||||
|
||||
let merchant_authentication = MerchantAuthentication::try_from(&item.connector_auth_type)?;
|
||||
|
||||
@ -612,6 +733,8 @@ pub enum SyncStatus {
|
||||
Voided,
|
||||
CouldNotVoid,
|
||||
GeneralError,
|
||||
#[serde(rename = "FDSPendingReview")]
|
||||
FDSPendingReview,
|
||||
}
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@ -623,7 +746,8 @@ pub struct SyncTransactionResponse {
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct AuthorizedotnetSyncResponse {
|
||||
transaction: SyncTransactionResponse,
|
||||
transaction: Option<SyncTransactionResponse>,
|
||||
messages: ResponseMessages,
|
||||
}
|
||||
|
||||
impl From<SyncStatus> for enums::RefundStatus {
|
||||
@ -639,9 +763,9 @@ impl From<SyncStatus> for enums::RefundStatus {
|
||||
impl From<SyncStatus> for enums::AttemptStatus {
|
||||
fn from(transaction_status: SyncStatus) -> Self {
|
||||
match transaction_status {
|
||||
SyncStatus::SettledSuccessfully | SyncStatus::CapturedPendingSettlement => {
|
||||
Self::Charged
|
||||
}
|
||||
SyncStatus::SettledSuccessfully => Self::Charged,
|
||||
SyncStatus::CapturedPendingSettlement => Self::CaptureInitiated,
|
||||
SyncStatus::AuthorizedPendingCapture => Self::Authorized,
|
||||
SyncStatus::Declined => Self::AuthenticationFailed,
|
||||
SyncStatus::Voided => Self::Voided,
|
||||
SyncStatus::CouldNotVoid => Self::VoidFailed,
|
||||
@ -659,14 +783,22 @@ impl TryFrom<types::RefundsResponseRouterData<api::RSync, AuthorizedotnetSyncRes
|
||||
fn try_from(
|
||||
item: types::RefundsResponseRouterData<api::RSync, AuthorizedotnetSyncResponse>,
|
||||
) -> Result<Self, Self::Error> {
|
||||
let refund_status = enums::RefundStatus::from(item.response.transaction.transaction_status);
|
||||
Ok(Self {
|
||||
response: Ok(types::RefundsResponseData {
|
||||
connector_refund_id: item.response.transaction.transaction_id.clone(),
|
||||
refund_status,
|
||||
match item.response.transaction {
|
||||
Some(transaction) => {
|
||||
let refund_status = enums::RefundStatus::from(transaction.transaction_status);
|
||||
Ok(Self {
|
||||
response: Ok(types::RefundsResponseData {
|
||||
connector_refund_id: transaction.transaction_id,
|
||||
refund_status,
|
||||
}),
|
||||
..item.data
|
||||
})
|
||||
}
|
||||
None => Ok(Self {
|
||||
response: Err(get_err_response(item.http_code, item.response.messages)),
|
||||
..item.data
|
||||
}),
|
||||
..item.data
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -685,21 +817,28 @@ impl<F, Req>
|
||||
types::PaymentsResponseData,
|
||||
>,
|
||||
) -> Result<Self, Self::Error> {
|
||||
let payment_status =
|
||||
enums::AttemptStatus::from(item.response.transaction.transaction_status);
|
||||
Ok(Self {
|
||||
response: Ok(types::PaymentsResponseData::TransactionResponse {
|
||||
resource_id: types::ResponseId::ConnectorTransactionId(
|
||||
item.response.transaction.transaction_id,
|
||||
),
|
||||
redirection_data: None,
|
||||
mandate_reference: None,
|
||||
connector_metadata: None,
|
||||
network_txn_id: None,
|
||||
match item.response.transaction {
|
||||
Some(transaction) => {
|
||||
let payment_status = enums::AttemptStatus::from(transaction.transaction_status);
|
||||
Ok(Self {
|
||||
response: Ok(types::PaymentsResponseData::TransactionResponse {
|
||||
resource_id: types::ResponseId::ConnectorTransactionId(
|
||||
transaction.transaction_id,
|
||||
),
|
||||
redirection_data: None,
|
||||
mandate_reference: None,
|
||||
connector_metadata: None,
|
||||
network_txn_id: None,
|
||||
}),
|
||||
status: payment_status,
|
||||
..item.data
|
||||
})
|
||||
}
|
||||
None => Ok(Self {
|
||||
response: Err(get_err_response(item.http_code, item.response.messages)),
|
||||
..item.data
|
||||
}),
|
||||
status: payment_status,
|
||||
..item.data
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -724,3 +863,78 @@ fn construct_refund_payment_details(masked_number: String) -> PaymentDetails {
|
||||
card_code: None,
|
||||
})
|
||||
}
|
||||
|
||||
impl From<Option<enums::CaptureMethod>> for TransactionType {
|
||||
fn from(capture_method: Option<enums::CaptureMethod>) -> Self {
|
||||
match capture_method {
|
||||
Some(enums::CaptureMethod::Manual) => Self::Authorization,
|
||||
_ => Self::Payment,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_err_response(status_code: u16, message: ResponseMessages) -> types::ErrorResponse {
|
||||
types::ErrorResponse {
|
||||
code: message.message[0].code.clone(),
|
||||
message: message.message[0].text.clone(),
|
||||
reason: None,
|
||||
status_code,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AuthorizedotnetWebhookObjectId {
|
||||
pub webhook_id: String,
|
||||
pub event_type: AuthorizedotnetWebhookEvent,
|
||||
pub payload: AuthorizedotnetWebhookPayload,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct AuthorizedotnetWebhookPayload {
|
||||
pub id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AuthorizedotnetWebhookEventType {
|
||||
pub event_type: AuthorizedotnetWebhookEvent,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub enum AuthorizedotnetWebhookEvent {
|
||||
#[serde(rename = "net.authorize.payment.authorization.created")]
|
||||
AuthorizationCreated,
|
||||
#[serde(rename = "net.authorize.payment.priorAuthCapture.created")]
|
||||
PriorAuthCapture,
|
||||
#[serde(rename = "net.authorize.payment.authcapture.created")]
|
||||
AuthCapCreated,
|
||||
#[serde(rename = "net.authorize.payment.capture.created")]
|
||||
CaptureCreated,
|
||||
#[serde(rename = "net.authorize.payment.void.created")]
|
||||
VoidCreated,
|
||||
#[serde(rename = "net.authorize.payment.refund.created")]
|
||||
RefundCreated,
|
||||
}
|
||||
|
||||
impl From<AuthorizedotnetWebhookEvent> for api::IncomingWebhookEvent {
|
||||
fn from(event_type: AuthorizedotnetWebhookEvent) -> Self {
|
||||
match event_type {
|
||||
AuthorizedotnetWebhookEvent::AuthorizationCreated
|
||||
| AuthorizedotnetWebhookEvent::PriorAuthCapture
|
||||
| AuthorizedotnetWebhookEvent::AuthCapCreated
|
||||
| AuthorizedotnetWebhookEvent::CaptureCreated
|
||||
| AuthorizedotnetWebhookEvent::VoidCreated => Self::PaymentIntentSuccess,
|
||||
AuthorizedotnetWebhookEvent::RefundCreated => Self::RefundSuccess,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_trans_id(
|
||||
details: AuthorizedotnetWebhookObjectId,
|
||||
) -> Result<String, errors::ConnectorError> {
|
||||
details
|
||||
.payload
|
||||
.id
|
||||
.ok_or(errors::ConnectorError::WebhookReferenceIdNotFound)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user