#![allow(dead_code)] mod transformers; use std::fmt::Debug; use error_stack::{IntoReport, ResultExt}; use transformers as authorizedotnet; use crate::{ configs::settings, consts, core::errors::{self, CustomResult}, headers, services::{self, logger}, types::{ self, api::{self, ConnectorCommon}, }, utils::{self, BytesExt}, }; #[derive(Debug, Clone)] pub struct Authorizedotnet; impl ConnectorCommon for Authorizedotnet { fn id(&self) -> &'static str { "authorizedotnet" } fn common_get_content_type(&self) -> &'static str { "application/json" } fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { connectors.authorizedotnet.base_url.as_ref() } } impl api::Payment for Authorizedotnet {} impl api::PaymentAuthorize for Authorizedotnet {} impl api::PaymentSync for Authorizedotnet {} impl api::PaymentVoid for Authorizedotnet {} impl api::PaymentCapture for Authorizedotnet {} impl api::PaymentSession for Authorizedotnet {} impl api::ConnectorAccessToken for Authorizedotnet {} impl services::ConnectorIntegration< api::Session, types::PaymentsSessionData, types::PaymentsResponseData, > for Authorizedotnet { // Not Implemented (R) } impl services::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 { // Issue: #173 } impl services::ConnectorIntegration< api::Capture, types::PaymentsCaptureData, types::PaymentsResponseData, > for Authorizedotnet { // Not Implemented (R) } impl services::ConnectorIntegration for Authorizedotnet { fn get_headers( &self, _req: &types::PaymentsSyncRouterData, _connectors: &settings::Connectors, ) -> CustomResult, 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(), ), (headers::X_ROUTER.to_string(), "test".to_string()), ]) } fn get_content_type(&self) -> &'static str { "application/json" } fn get_url( &self, _req: &types::PaymentsSyncRouterData, connectors: &settings::Connectors, ) -> CustomResult { Ok(self.base_url(connectors).to_string()) } fn get_request_body( &self, req: &types::PaymentsSyncRouterData, ) -> CustomResult, errors::ConnectorError> { let connector_req = authorizedotnet::AuthorizedotnetCreateSyncRequest::try_from(req)?; let sync_request = utils::Encode::::encode_to_string_of_json( &connector_req, ) .change_context(errors::ConnectorError::RequestEncodingFailed)?; Ok(Some(sync_request)) } fn build_request( &self, req: &types::PaymentsSyncRouterData, connectors: &settings::Connectors, ) -> CustomResult, errors::ConnectorError> { let request = services::RequestBuilder::new() .method(services::Method::Post) .url(&types::PaymentsSyncType::get_url(self, req, connectors)?) .headers(types::PaymentsSyncType::get_headers(self, req, connectors)?) .body(types::PaymentsSyncType::get_request_body(self, req)?) .build(); Ok(Some(request)) } fn handle_response( &self, data: &types::PaymentsSyncRouterData, res: types::Response, ) -> CustomResult { 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: types::Response, ) -> CustomResult { get_error_response(res) } } impl services::ConnectorIntegration< api::Authorize, types::PaymentsAuthorizeData, types::PaymentsResponseData, > for Authorizedotnet { fn get_headers( &self, _req: &types::PaymentsAuthorizeRouterData, _connectors: &settings::Connectors, ) -> CustomResult, 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(), ), (headers::X_ROUTER.to_string(), "test".to_string()), ]) } fn get_content_type(&self) -> &'static str { self.common_get_content_type() } fn get_url( &self, _req: &types::PaymentsAuthorizeRouterData, connectors: &settings::Connectors, ) -> CustomResult { Ok(self.base_url(connectors).to_string()) } fn get_request_body( &self, req: &types::PaymentsAuthorizeRouterData, ) -> CustomResult, errors::ConnectorError> { logger::debug!(request=?req); let connector_req = authorizedotnet::CreateTransactionRequest::try_from(req)?; let authorizedotnet_req = utils::Encode::::encode_to_string_of_json( &connector_req, ) .change_context(errors::ConnectorError::RequestEncodingFailed)?; Ok(Some(authorizedotnet_req)) } fn build_request( &self, req: &types::RouterData< api::Authorize, types::PaymentsAuthorizeData, types::PaymentsResponseData, >, connectors: &settings::Connectors, ) -> CustomResult, errors::ConnectorError> { Ok(Some( services::RequestBuilder::new() .method(services::Method::Post) .url(&types::PaymentsAuthorizeType::get_url( self, req, connectors, )?) .headers(types::PaymentsAuthorizeType::get_headers( self, req, connectors, )?) .header(headers::X_ROUTER, "test") .body(types::PaymentsAuthorizeType::get_request_body(self, req)?) .build(), )) } fn handle_response( &self, data: &types::PaymentsAuthorizeRouterData, res: types::Response, ) -> CustomResult { 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; 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, }) .change_context(errors::ConnectorError::ResponseDeserializationFailed) } fn get_error_response( &self, res: types::Response, ) -> CustomResult { logger::debug!(authorizedotnetpayments_create_error_response=?res); get_error_response(res) } } impl services::ConnectorIntegration< api::Void, types::PaymentsCancelData, types::PaymentsResponseData, > for Authorizedotnet { fn get_headers( &self, _req: &types::PaymentsCancelRouterData, _connectors: &settings::Connectors, ) -> CustomResult, errors::ConnectorError> { Ok(vec![ ( headers::CONTENT_TYPE.to_string(), types::PaymentsAuthorizeType::get_content_type(self).to_string(), ), (headers::X_ROUTER.to_string(), "test".to_string()), ]) } fn get_content_type(&self) -> &'static str { self.common_get_content_type() } fn get_url( &self, _req: &types::PaymentsCancelRouterData, connectors: &settings::Connectors, ) -> CustomResult { Ok(self.base_url(connectors).to_string()) } fn get_request_body( &self, req: &types::PaymentsCancelRouterData, ) -> CustomResult, errors::ConnectorError> { let connector_req = authorizedotnet::CancelTransactionRequest::try_from(req)?; let authorizedotnet_req = utils::Encode::::encode_to_string_of_json( &connector_req, ) .change_context(errors::ConnectorError::RequestEncodingFailed)?; Ok(Some(authorizedotnet_req)) } fn build_request( &self, req: &types::PaymentsCancelRouterData, connectors: &settings::Connectors, ) -> CustomResult, errors::ConnectorError> { Ok(Some( services::RequestBuilder::new() .method(services::Method::Post) .url(&types::PaymentsVoidType::get_url(self, req, connectors)?) .headers(types::PaymentsVoidType::get_headers(self, req, connectors)?) .header(headers::X_ROUTER, "test") .body(types::PaymentsVoidType::get_request_body(self, req)?) .build(), )) } fn handle_response( &self, data: &types::PaymentsCancelRouterData, res: types::Response, ) -> CustomResult { 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)?; 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( &self, res: types::Response, ) -> CustomResult { get_error_response(res) } } impl api::Refund for Authorizedotnet {} impl api::RefundExecute for Authorizedotnet {} impl api::RefundSync for Authorizedotnet {} impl services::ConnectorIntegration for Authorizedotnet { fn get_headers( &self, _req: &types::RefundsRouterData, _connectors: &settings::Connectors, ) -> CustomResult, 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(), ), (headers::X_ROUTER.to_string(), "test".to_string()), ]) } fn get_content_type(&self) -> &'static str { self.common_get_content_type() } fn get_url( &self, _req: &types::RefundsRouterData, connectors: &settings::Connectors, ) -> CustomResult { Ok(self.base_url(connectors).to_string()) } fn get_request_body( &self, req: &types::RefundsRouterData, ) -> CustomResult, errors::ConnectorError> { logger::debug!(refund_request=?req); let connector_req = authorizedotnet::CreateRefundRequest::try_from(req)?; let authorizedotnet_req = utils::Encode::::encode_to_string_of_json( &connector_req, ) .change_context(errors::ConnectorError::RequestEncodingFailed)?; Ok(Some(authorizedotnet_req)) } fn build_request( &self, req: &types::RefundsRouterData, connectors: &settings::Connectors, ) -> CustomResult, errors::ConnectorError> { let request = services::RequestBuilder::new() .method(services::Method::Post) .url(&types::RefundExecuteType::get_url(self, req, connectors)?) .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, res: types::Response, ) -> CustomResult, 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; 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::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( &self, res: types::Response, ) -> CustomResult { get_error_response(res) } } impl services::ConnectorIntegration for Authorizedotnet { fn get_headers( &self, _req: &types::RefundsRouterData, _connectors: &settings::Connectors, ) -> CustomResult, 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(), ), (headers::X_ROUTER.to_string(), "test".to_string()), ]) } fn get_content_type(&self) -> &'static str { "application/json" } fn get_url( &self, _req: &types::RefundsRouterData, connectors: &settings::Connectors, ) -> CustomResult { Ok(self.base_url(connectors).to_string()) } fn get_request_body( &self, req: &types::RefundsRouterData, ) -> CustomResult, errors::ConnectorError> { let connector_req = authorizedotnet::AuthorizedotnetCreateSyncRequest::try_from(req)?; let sync_request = utils::Encode::::encode_to_string_of_json( &connector_req, ) .change_context(errors::ConnectorError::RequestEncodingFailed)?; Ok(Some(sync_request)) } fn build_request( &self, req: &types::RefundsRouterData, connectors: &settings::Connectors, ) -> CustomResult, errors::ConnectorError> { let request = services::RequestBuilder::new() .method(services::Method::Post) .url(&types::RefundSyncType::get_url(self, req, connectors)?) .headers(types::RefundSyncType::get_headers(self, req, connectors)?) .body(types::RefundSyncType::get_request_body(self, req)?) .build(); Ok(Some(request)) } fn handle_response( &self, data: &types::RefundsRouterData, res: types::Response, ) -> CustomResult, 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: types::Response, ) -> CustomResult { get_error_response(res) } } #[async_trait::async_trait] impl api::IncomingWebhook for Authorizedotnet { fn get_webhook_object_reference_id( &self, _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } fn get_webhook_event_type( &self, _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } fn get_webhook_resource_object( &self, _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } } impl services::ConnectorRedirectResponse for Authorizedotnet {} #[inline] fn get_error_response( types::Response { response, status_code, }: types::Response, ) -> CustomResult { let response: authorizedotnet::AuthorizedotnetPaymentsResponse = 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, 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, })) }