mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-11-01 02:57:02 +08:00 
			
		
		
		
	feat(connector): [Trustpay] add authorize (cards 3ds, no3ds and bank redirects), refund, psync, rsync (#717)
Co-authored-by: Sangamesh <sangamesh.kulkarni@juspay.in> Co-authored-by: sai harsha <sai.harsha@sai.harsha-MacBookPro> Co-authored-by: Arun Raj M <jarnura47@gmail.com>
This commit is contained in:
		| @ -251,6 +251,7 @@ pub struct Connectors { | ||||
|     pub stripe: ConnectorParams, | ||||
|     pub worldline: ConnectorParams, | ||||
|     pub worldpay: ConnectorParams, | ||||
|     pub trustpay: ConnectorParamsWithMoreUrls, | ||||
|  | ||||
|     // Keep this field separate from the remaining fields | ||||
|     pub supported: SupportedConnectors, | ||||
| @ -262,6 +263,13 @@ pub struct ConnectorParams { | ||||
|     pub base_url: String, | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Deserialize, Clone, Default)] | ||||
| #[serde(default)] | ||||
| pub struct ConnectorParamsWithMoreUrls { | ||||
|     pub base_url: String, | ||||
|     pub base_url_bank_redirects: String, | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Clone, Deserialize)] | ||||
| #[serde(default)] | ||||
| pub struct SchedulerSettings { | ||||
|  | ||||
| @ -18,6 +18,7 @@ pub mod payu; | ||||
| pub mod rapyd; | ||||
| pub mod shift4; | ||||
| pub mod stripe; | ||||
| pub mod trustpay; | ||||
| pub mod utils; | ||||
| pub mod worldline; | ||||
| pub mod worldpay; | ||||
| @ -27,5 +28,6 @@ pub use self::{ | ||||
|     authorizedotnet::Authorizedotnet, bambora::Bambora, bluesnap::Bluesnap, braintree::Braintree, | ||||
|     checkout::Checkout, cybersource::Cybersource, dlocal::Dlocal, fiserv::Fiserv, | ||||
|     globalpay::Globalpay, klarna::Klarna, multisafepay::Multisafepay, nuvei::Nuvei, payu::Payu, | ||||
|     rapyd::Rapyd, shift4::Shift4, stripe::Stripe, worldline::Worldline, worldpay::Worldpay, | ||||
|     rapyd::Rapyd, shift4::Shift4, stripe::Stripe, trustpay::Trustpay, worldline::Worldline, | ||||
|     worldpay::Worldpay, | ||||
| }; | ||||
|  | ||||
| @ -346,7 +346,7 @@ impl | ||||
|         req: &types::PaymentsAuthorizeRouterData, | ||||
|     ) -> CustomResult<Option<String>, errors::ConnectorError> { | ||||
|         let req = stripe::PaymentIntentRequest::try_from(req)?; | ||||
|         let stripe_req = utils::Encode::<stripe::PaymentIntentRequest>::encode(&req) | ||||
|         let stripe_req = utils::Encode::<stripe::PaymentIntentRequest>::url_encode(&req) | ||||
|             .change_context(errors::ConnectorError::RequestEncodingFailed)?; | ||||
|         Ok(Some(stripe_req)) | ||||
|     } | ||||
|  | ||||
							
								
								
									
										630
									
								
								crates/router/src/connector/trustpay.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										630
									
								
								crates/router/src/connector/trustpay.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,630 @@ | ||||
| mod transformers; | ||||
|  | ||||
| use std::fmt::Debug; | ||||
|  | ||||
| use base64::Engine; | ||||
| use error_stack::{IntoReport, ResultExt}; | ||||
| use transformers as trustpay; | ||||
|  | ||||
| use crate::{ | ||||
|     configs::settings, | ||||
|     consts, | ||||
|     core::{ | ||||
|         errors::{self, CustomResult}, | ||||
|         payments, | ||||
|     }, | ||||
|     headers, | ||||
|     services::{self, ConnectorIntegration}, | ||||
|     types::{ | ||||
|         self, | ||||
|         api::{self, ConnectorCommon, ConnectorCommonExt}, | ||||
|         ErrorResponse, Response, | ||||
|     }, | ||||
|     utils::{self, BytesExt}, | ||||
| }; | ||||
|  | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct Trustpay; | ||||
|  | ||||
| impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Trustpay | ||||
| 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> { | ||||
|         match req.payment_method { | ||||
|             storage_models::enums::PaymentMethod::BankRedirect => { | ||||
|                 let token = req | ||||
|                     .access_token | ||||
|                     .clone() | ||||
|                     .ok_or(errors::ConnectorError::FailedToObtainAuthType)?; | ||||
|                 Ok(vec![ | ||||
|                     ( | ||||
|                         headers::CONTENT_TYPE.to_string(), | ||||
|                         "application/json".to_owned(), | ||||
|                     ), | ||||
|                     ( | ||||
|                         headers::AUTHORIZATION.to_string(), | ||||
|                         format!("Bearer {}", token.token), | ||||
|                     ), | ||||
|                 ]) | ||||
|             } | ||||
|             _ => { | ||||
|                 let mut header = vec![( | ||||
|                     headers::CONTENT_TYPE.to_string(), | ||||
|                     self.get_content_type().to_string(), | ||||
|                 )]; | ||||
|                 let mut api_key = self.get_auth_header(&req.connector_auth_type)?; | ||||
|                 header.append(&mut api_key); | ||||
|                 Ok(header) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl ConnectorCommon for Trustpay { | ||||
|     fn id(&self) -> &'static str { | ||||
|         "trustpay" | ||||
|     } | ||||
|  | ||||
|     fn common_get_content_type(&self) -> &'static str { | ||||
|         "application/x-www-form-urlencoded" | ||||
|     } | ||||
|  | ||||
|     fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { | ||||
|         connectors.trustpay.base_url.as_ref() | ||||
|     } | ||||
|  | ||||
|     fn get_auth_header( | ||||
|         &self, | ||||
|         auth_type: &types::ConnectorAuthType, | ||||
|     ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> { | ||||
|         let auth = trustpay::TrustpayAuthType::try_from(auth_type) | ||||
|             .change_context(errors::ConnectorError::FailedToObtainAuthType)?; | ||||
|         Ok(vec![(headers::X_API_KEY.to_string(), auth.api_key)]) | ||||
|     } | ||||
|  | ||||
|     fn build_error_response( | ||||
|         &self, | ||||
|         res: Response, | ||||
|     ) -> CustomResult<ErrorResponse, errors::ConnectorError> { | ||||
|         let response: trustpay::TrustpayErrorResponse = res | ||||
|             .response | ||||
|             .parse_struct("trustpay ErrorResponse") | ||||
|             .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; | ||||
|         let default_error = trustpay::Errors { | ||||
|             code: 0, | ||||
|             description: consts::NO_ERROR_CODE.to_string(), | ||||
|         }; | ||||
|         Ok(ErrorResponse { | ||||
|             status_code: res.status_code, | ||||
|             code: response.status.to_string(), | ||||
|             message: format!("{:?}", response.errors.first().unwrap_or(&default_error)), | ||||
|             reason: None, | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl api::Payment for Trustpay {} | ||||
|  | ||||
| impl api::PreVerify for Trustpay {} | ||||
| impl ConnectorIntegration<api::Verify, types::VerifyRequestData, types::PaymentsResponseData> | ||||
|     for Trustpay | ||||
| { | ||||
| } | ||||
|  | ||||
| impl api::PaymentVoid for Trustpay {} | ||||
|  | ||||
| impl ConnectorIntegration<api::Void, types::PaymentsCancelData, types::PaymentsResponseData> | ||||
|     for Trustpay | ||||
| { | ||||
| } | ||||
|  | ||||
| impl api::ConnectorAccessToken for Trustpay {} | ||||
|  | ||||
| impl ConnectorIntegration<api::AccessTokenAuth, types::AccessTokenRequestData, types::AccessToken> | ||||
|     for Trustpay | ||||
| { | ||||
|     fn get_url( | ||||
|         &self, | ||||
|         _req: &types::RefreshTokenRouterData, | ||||
|         connectors: &settings::Connectors, | ||||
|     ) -> CustomResult<String, errors::ConnectorError> { | ||||
|         Ok(format!( | ||||
|             "{}{}", | ||||
|             connectors.trustpay.base_url_bank_redirects, "api/oauth2/token" | ||||
|         )) | ||||
|     } | ||||
|  | ||||
|     fn get_content_type(&self) -> &'static str { | ||||
|         self.common_get_content_type() | ||||
|     } | ||||
|  | ||||
|     fn get_headers( | ||||
|         &self, | ||||
|         req: &types::RefreshTokenRouterData, | ||||
|         _connectors: &settings::Connectors, | ||||
|     ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> { | ||||
|         let auth = trustpay::TrustpayAuthType::try_from(&req.connector_auth_type) | ||||
|             .change_context(errors::ConnectorError::FailedToObtainAuthType)?; | ||||
|         let auth_value = format!( | ||||
|             "Basic {}", | ||||
|             consts::BASE64_ENGINE.encode(format!("{}:{}", auth.project_id, auth.secret_key)) | ||||
|         ); | ||||
|         Ok(vec![ | ||||
|             ( | ||||
|                 headers::CONTENT_TYPE.to_string(), | ||||
|                 types::RefreshTokenType::get_content_type(self).to_string(), | ||||
|             ), | ||||
|             (headers::AUTHORIZATION.to_string(), auth_value), | ||||
|         ]) | ||||
|     } | ||||
|  | ||||
|     fn get_request_body( | ||||
|         &self, | ||||
|         req: &types::RefreshTokenRouterData, | ||||
|     ) -> CustomResult<Option<String>, errors::ConnectorError> { | ||||
|         let trustpay_req = | ||||
|             utils::Encode::<trustpay::TrustpayAuthUpdateRequest>::convert_and_url_encode(req) | ||||
|                 .change_context(errors::ConnectorError::RequestEncodingFailed)?; | ||||
|         Ok(Some(trustpay_req)) | ||||
|     } | ||||
|  | ||||
|     fn build_request( | ||||
|         &self, | ||||
|         req: &types::RefreshTokenRouterData, | ||||
|         connectors: &settings::Connectors, | ||||
|     ) -> CustomResult<Option<services::Request>, errors::ConnectorError> { | ||||
|         let req = Some( | ||||
|             services::RequestBuilder::new() | ||||
|                 .method(services::Method::Post) | ||||
|                 .headers(types::RefreshTokenType::get_headers(self, req, connectors)?) | ||||
|                 .url(&types::RefreshTokenType::get_url(self, req, connectors)?) | ||||
|                 .body(types::RefreshTokenType::get_request_body(self, req)?) | ||||
|                 .build(), | ||||
|         ); | ||||
|         Ok(req) | ||||
|     } | ||||
|  | ||||
|     fn handle_response( | ||||
|         &self, | ||||
|         data: &types::RefreshTokenRouterData, | ||||
|         res: Response, | ||||
|     ) -> CustomResult<types::RefreshTokenRouterData, errors::ConnectorError> { | ||||
|         let response: trustpay::TrustpayAuthUpdateResponse = res | ||||
|             .response | ||||
|             .parse_struct("trustpay TrustpayAuthUpdateResponse") | ||||
|             .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> { | ||||
|         let response: trustpay::TrustpayAccessTokenErrorResponse = res | ||||
|             .response | ||||
|             .parse_struct("Trustpay AccessTokenErrorResponse") | ||||
|             .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; | ||||
|         Ok(ErrorResponse { | ||||
|             status_code: res.status_code, | ||||
|             code: response.result_info.result_code.to_string(), | ||||
|             message: response.result_info.additional_info.unwrap_or_default(), | ||||
|             reason: None, | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl api::PaymentSync for Trustpay {} | ||||
| impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsResponseData> | ||||
|     for Trustpay | ||||
| { | ||||
|     fn get_headers( | ||||
|         &self, | ||||
|         req: &types::PaymentsSyncRouterData, | ||||
|         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::PaymentsSyncRouterData, | ||||
|         connectors: &settings::Connectors, | ||||
|     ) -> CustomResult<String, errors::ConnectorError> { | ||||
|         let id = req.request.connector_transaction_id.clone(); | ||||
|         match req.payment_method { | ||||
|             storage_models::enums::PaymentMethod::BankRedirect => Ok(format!( | ||||
|                 "{}{}/{}", | ||||
|                 connectors.trustpay.base_url_bank_redirects, | ||||
|                 "api/Payments/Payment", | ||||
|                 id.get_connector_transaction_id() | ||||
|                     .change_context(errors::ConnectorError::MissingConnectorTransactionID)? | ||||
|             )), | ||||
|             _ => Ok(format!( | ||||
|                 "{}{}/{}", | ||||
|                 self.base_url(connectors), | ||||
|                 "api/v1/instance", | ||||
|                 id.get_connector_transaction_id() | ||||
|                     .change_context(errors::ConnectorError::MissingConnectorTransactionID)? | ||||
|             )), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     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)?) | ||||
|                 .headers(types::PaymentsSyncType::get_headers(self, req, connectors)?) | ||||
|                 .build(), | ||||
|         )) | ||||
|     } | ||||
|  | ||||
|     fn get_error_response( | ||||
|         &self, | ||||
|         res: Response, | ||||
|     ) -> CustomResult<ErrorResponse, errors::ConnectorError> { | ||||
|         self.build_error_response(res) | ||||
|     } | ||||
|  | ||||
|     fn handle_response( | ||||
|         &self, | ||||
|         data: &types::PaymentsSyncRouterData, | ||||
|         res: Response, | ||||
|     ) -> CustomResult<types::PaymentsSyncRouterData, errors::ConnectorError> { | ||||
|         let response: trustpay::TrustpayPaymentsResponse = res | ||||
|             .response | ||||
|             .parse_struct("trustpay PaymentsResponse") | ||||
|             .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) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl api::PaymentCapture for Trustpay {} | ||||
| impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::PaymentsResponseData> | ||||
|     for Trustpay | ||||
| { | ||||
| } | ||||
|  | ||||
| impl api::PaymentSession for Trustpay {} | ||||
|  | ||||
| impl ConnectorIntegration<api::Session, types::PaymentsSessionData, types::PaymentsResponseData> | ||||
|     for Trustpay | ||||
| { | ||||
| } | ||||
|  | ||||
| impl api::PaymentAuthorize for Trustpay {} | ||||
|  | ||||
| impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::PaymentsResponseData> | ||||
|     for Trustpay | ||||
| { | ||||
|     fn get_headers( | ||||
|         &self, | ||||
|         req: &types::PaymentsAuthorizeRouterData, | ||||
|         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::PaymentsAuthorizeRouterData, | ||||
|         connectors: &settings::Connectors, | ||||
|     ) -> CustomResult<String, errors::ConnectorError> { | ||||
|         match req.payment_method { | ||||
|             storage_models::enums::PaymentMethod::BankRedirect => Ok(format!( | ||||
|                 "{}{}", | ||||
|                 connectors.trustpay.base_url_bank_redirects, "api/Payments/Payment" | ||||
|             )), | ||||
|             _ => Ok(format!( | ||||
|                 "{}{}", | ||||
|                 self.base_url(connectors), | ||||
|                 "api/v1/purchase" | ||||
|             )), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn get_request_body( | ||||
|         &self, | ||||
|         req: &types::PaymentsAuthorizeRouterData, | ||||
|     ) -> CustomResult<Option<String>, errors::ConnectorError> { | ||||
|         let trustpay_req = trustpay::TrustpayPaymentsRequest::try_from(req)?; | ||||
|         let trustpay_req_string = match req.payment_method { | ||||
|             storage_models::enums::PaymentMethod::BankRedirect => { | ||||
|                 utils::Encode::<trustpay::PaymentRequestBankRedirect>::encode_to_string_of_json( | ||||
|                     &trustpay_req, | ||||
|                 ) | ||||
|                 .change_context(errors::ConnectorError::RequestEncodingFailed)? | ||||
|             } | ||||
|             _ => utils::Encode::<trustpay::PaymentRequestCards>::url_encode(&trustpay_req) | ||||
|                 .change_context(errors::ConnectorError::RequestEncodingFailed)?, | ||||
|         }; | ||||
|         Ok(Some(trustpay_req_string)) | ||||
|     } | ||||
|  | ||||
|     fn build_request( | ||||
|         &self, | ||||
|         req: &types::PaymentsAuthorizeRouterData, | ||||
|         connectors: &settings::Connectors, | ||||
|     ) -> CustomResult<Option<services::Request>, 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, | ||||
|                 )?) | ||||
|                 .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: trustpay::TrustpayPaymentsResponse = res | ||||
|             .response | ||||
|             .parse_struct("trustpay PaymentsResponse") | ||||
|             .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 api::Refund for Trustpay {} | ||||
| impl api::RefundExecute for Trustpay {} | ||||
| impl api::RefundSync for Trustpay {} | ||||
|  | ||||
| impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsResponseData> | ||||
|     for Trustpay | ||||
| { | ||||
|     fn get_headers( | ||||
|         &self, | ||||
|         req: &types::RefundsRouterData<api::Execute>, | ||||
|         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::RefundsRouterData<api::Execute>, | ||||
|         connectors: &settings::Connectors, | ||||
|     ) -> CustomResult<String, errors::ConnectorError> { | ||||
|         match req.payment_method { | ||||
|             storage_models::enums::PaymentMethod::BankRedirect => Ok(format!( | ||||
|                 "{}{}{}{}", | ||||
|                 connectors.trustpay.base_url_bank_redirects, | ||||
|                 "api/Payments/Payment/", | ||||
|                 req.request.connector_transaction_id, | ||||
|                 "/Refund" | ||||
|             )), | ||||
|             _ => Ok(format!("{}{}", self.base_url(connectors), "api/v1/Reverse")), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn get_request_body( | ||||
|         &self, | ||||
|         req: &types::RefundsRouterData<api::Execute>, | ||||
|     ) -> CustomResult<Option<String>, errors::ConnectorError> { | ||||
|         let trustpay_req = trustpay::TrustpayRefundRequest::try_from(req)?; | ||||
|         let trustpay_req_string = match req.payment_method { | ||||
|             storage_models::enums::PaymentMethod::BankRedirect => utils::Encode::< | ||||
|                 trustpay::TrustpayRefundRequestBankRedirect, | ||||
|             >::encode_to_string_of_json( | ||||
|                 &trustpay_req | ||||
|             ) | ||||
|             .change_context(errors::ConnectorError::RequestEncodingFailed)?, | ||||
|             _ => utils::Encode::<trustpay::TrustpayRefundRequestCards>::url_encode(&trustpay_req) | ||||
|                 .change_context(errors::ConnectorError::RequestEncodingFailed)?, | ||||
|         }; | ||||
|         Ok(Some(trustpay_req_string)) | ||||
|     } | ||||
|  | ||||
|     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)?) | ||||
|             .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: trustpay::RefundResponse = res | ||||
|             .response | ||||
|             .parse_struct("trustpay RefundResponse") | ||||
|             .change_context(errors::ConnectorError::RequestEncodingFailed)?; | ||||
|         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::RSync, types::RefundsData, types::RefundsResponseData> for Trustpay { | ||||
|     fn get_headers( | ||||
|         &self, | ||||
|         req: &types::RefundSyncRouterData, | ||||
|         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::RefundSyncRouterData, | ||||
|         connectors: &settings::Connectors, | ||||
|     ) -> CustomResult<String, errors::ConnectorError> { | ||||
|         let id = req | ||||
|             .request | ||||
|             .connector_refund_id | ||||
|             .to_owned() | ||||
|             .ok_or_else(|| errors::ConnectorError::MissingConnectorRefundID)?; | ||||
|         match req.payment_method { | ||||
|             storage_models::enums::PaymentMethod::BankRedirect => Ok(format!( | ||||
|                 "{}{}/{}", | ||||
|                 connectors.trustpay.base_url_bank_redirects, "api/Payments/Payment", id | ||||
|             )), | ||||
|             _ => Ok(format!( | ||||
|                 "{}{}/{}", | ||||
|                 self.base_url(connectors), | ||||
|                 "api/v1/instance", | ||||
|                 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)?) | ||||
|                 .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: trustpay::RefundResponse = res | ||||
|             .response | ||||
|             .parse_struct("trustpay RefundResponse") | ||||
|             .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) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[async_trait::async_trait] | ||||
| impl api::IncomingWebhook for Trustpay { | ||||
|     fn get_webhook_object_reference_id( | ||||
|         &self, | ||||
|         _request: &api::IncomingWebhookRequestDetails<'_>, | ||||
|     ) -> CustomResult<String, errors::ConnectorError> { | ||||
|         Err(errors::ConnectorError::WebhooksNotImplemented).into_report() | ||||
|     } | ||||
|  | ||||
|     fn get_webhook_event_type( | ||||
|         &self, | ||||
|         _request: &api::IncomingWebhookRequestDetails<'_>, | ||||
|     ) -> CustomResult<api::IncomingWebhookEvent, errors::ConnectorError> { | ||||
|         Err(errors::ConnectorError::WebhooksNotImplemented).into_report() | ||||
|     } | ||||
|  | ||||
|     fn get_webhook_resource_object( | ||||
|         &self, | ||||
|         _request: &api::IncomingWebhookRequestDetails<'_>, | ||||
|     ) -> CustomResult<serde_json::Value, errors::ConnectorError> { | ||||
|         Err(errors::ConnectorError::WebhooksNotImplemented).into_report() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl services::ConnectorRedirectResponse for Trustpay { | ||||
|     fn get_flow_type( | ||||
|         &self, | ||||
|         query_params: &str, | ||||
|     ) -> CustomResult<payments::CallConnectorAction, errors::ConnectorError> { | ||||
|         let query = | ||||
|             serde_urlencoded::from_str::<transformers::TrustpayRedirectResponse>(query_params) | ||||
|                 .into_report() | ||||
|                 .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; | ||||
|         crate::logger::debug!(trustpay_redirect_response=?query); | ||||
|         Ok(query.status.map_or( | ||||
|             payments::CallConnectorAction::Trigger, | ||||
|             |status| match status.as_str() { | ||||
|                 "SuccessOk" => payments::CallConnectorAction::StatusUpdate( | ||||
|                     storage_models::enums::AttemptStatus::Charged, | ||||
|                 ), | ||||
|                 _ => payments::CallConnectorAction::Trigger, | ||||
|             }, | ||||
|         )) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										1070
									
								
								crates/router/src/connector/trustpay/transformers.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1070
									
								
								crates/router/src/connector/trustpay/transformers.rs
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -222,6 +222,7 @@ pub enum CardIssuer { | ||||
| pub trait CardData { | ||||
|     fn get_card_expiry_year_2_digit(&self) -> Secret<String>; | ||||
|     fn get_card_issuer(&self) -> Result<CardIssuer, Error>; | ||||
|     fn get_card_expiry_month_year_2_digit_with_delimiter(&self, delimiter: String) -> String; | ||||
| } | ||||
|  | ||||
| impl CardData for api::Card { | ||||
| @ -237,6 +238,15 @@ impl CardData for api::Card { | ||||
|             .map(|card| card.split_whitespace().collect()); | ||||
|         get_card_issuer(card.peek().clone().as_str()) | ||||
|     } | ||||
|     fn get_card_expiry_month_year_2_digit_with_delimiter(&self, delimiter: String) -> String { | ||||
|         let year = self.get_card_expiry_year_2_digit(); | ||||
|         format!( | ||||
|             "{}{}{}", | ||||
|             self.card_exp_month.peek().clone(), | ||||
|             delimiter, | ||||
|             year.peek() | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn get_card_issuer(card_number: &str) -> Result<CardIssuer, Error> { | ||||
|  | ||||
| @ -86,7 +86,7 @@ pub fn mk_add_card_request( | ||||
|         name_on_card: Some("John Doe".to_string().into()),         // [#256] | ||||
|         nickname: Some("router".to_string()),                      // | ||||
|     }; | ||||
|     let body = utils::Encode::<AddCardRequest<'_>>::encode(&add_card_req) | ||||
|     let body = utils::Encode::<AddCardRequest<'_>>::url_encode(&add_card_req) | ||||
|         .change_context(errors::VaultError::RequestEncodingFailed)?; | ||||
|     let mut url = locker.host.to_owned(); | ||||
|     url.push_str("/card/addCard"); | ||||
| @ -139,7 +139,7 @@ pub fn mk_get_card_request<'a>( | ||||
|         card_id, | ||||
|     }; | ||||
|  | ||||
|     let body = utils::Encode::<GetCard<'_>>::encode(&get_card_req) | ||||
|     let body = utils::Encode::<GetCard<'_>>::url_encode(&get_card_req) | ||||
|         .change_context(errors::VaultError::RequestEncodingFailed)?; | ||||
|     let mut url = locker.host.to_owned(); | ||||
|     url.push_str("/card/getCard"); | ||||
| @ -158,7 +158,7 @@ pub fn mk_delete_card_request<'a>( | ||||
|         merchant_id, | ||||
|         card_id, | ||||
|     }; | ||||
|     let body = utils::Encode::<GetCard<'_>>::encode(&delete_card_req) | ||||
|     let body = utils::Encode::<GetCard<'_>>::url_encode(&delete_card_req) | ||||
|         .change_context(errors::VaultError::RequestEncodingFailed)?; | ||||
|     let mut url = locker.host.to_owned(); | ||||
|     url.push_str("/card/deleteCard"); | ||||
|  | ||||
| @ -10,7 +10,7 @@ use crate::{ | ||||
|     }, | ||||
|     routes::AppState, | ||||
|     services, | ||||
|     types::{self, api as api_types, storage}, | ||||
|     types::{self, api as api_types, storage, transformers::ForeignInto}, | ||||
| }; | ||||
|  | ||||
| /// This function replaces the request and response type of routerdata with the | ||||
| @ -82,7 +82,10 @@ pub async fn add_access_token< | ||||
|     merchant_account: &storage::MerchantAccount, | ||||
|     router_data: &types::RouterData<F, Req, Res>, | ||||
| ) -> RouterResult<types::AddAccessTokenResult> { | ||||
|     if connector.connector_name.supports_access_token() { | ||||
|     if connector | ||||
|         .connector_name | ||||
|         .supports_access_token(router_data.payment_method.foreign_into()) | ||||
|     { | ||||
|         let merchant_id = &merchant_account.merchant_id; | ||||
|         let store = &*state.store; | ||||
|         let old_access_token = store | ||||
|  | ||||
| @ -182,6 +182,7 @@ impl ConnectorData { | ||||
|             "worldline" => Ok(Box::new(&connector::Worldline)), | ||||
|             "worldpay" => Ok(Box::new(&connector::Worldpay)), | ||||
|             "multisafepay" => Ok(Box::new(&connector::Multisafepay)), | ||||
|             "trustpay" => Ok(Box::new(&connector::Trustpay)), | ||||
|             _ => Err(report!(errors::ConnectorError::InvalidConnectorName) | ||||
|                 .attach_printable(format!("invalid connector name: {connector_name}"))) | ||||
|             .change_context(errors::ApiErrorResponse::InternalServerError), | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 saiharsha-juspay
					saiharsha-juspay