mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-10-31 01:57:45 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			590 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			590 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| mod transformers;
 | |
| 
 | |
| use std::fmt::Debug;
 | |
| 
 | |
| use common_utils::crypto;
 | |
| use error_stack::{IntoReport, ResultExt};
 | |
| use transformers as opennode;
 | |
| 
 | |
| use self::opennode::OpennodeWebhookDetails;
 | |
| use crate::{
 | |
|     configs::settings,
 | |
|     connector::utils as conn_utils,
 | |
|     core::errors::{self, CustomResult},
 | |
|     db, headers,
 | |
|     services::{self, ConnectorIntegration},
 | |
|     types::{
 | |
|         self,
 | |
|         api::{self, ConnectorCommon, ConnectorCommonExt},
 | |
|         ErrorResponse, Response,
 | |
|     },
 | |
|     utils::{BytesExt, Encode},
 | |
| };
 | |
| 
 | |
| #[derive(Debug, Clone)]
 | |
| pub struct Opennode;
 | |
| 
 | |
| impl api::Payment for Opennode {}
 | |
| impl api::PaymentSession for Opennode {}
 | |
| impl api::PaymentToken for Opennode {}
 | |
| impl api::ConnectorAccessToken for Opennode {}
 | |
| 
 | |
| impl api::PreVerify for Opennode {}
 | |
| impl api::PaymentAuthorize for Opennode {}
 | |
| impl api::PaymentSync for Opennode {}
 | |
| impl api::PaymentCapture for Opennode {}
 | |
| impl api::PaymentVoid for Opennode {}
 | |
| impl api::Refund for Opennode {}
 | |
| impl api::RefundExecute for Opennode {}
 | |
| impl api::RefundSync for Opennode {}
 | |
| 
 | |
| impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Opennode
 | |
| 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> {
 | |
|         let mut header = vec![
 | |
|             (
 | |
|                 headers::CONTENT_TYPE.to_string(),
 | |
|                 self.common_get_content_type().to_string(),
 | |
|             ),
 | |
|             (
 | |
|                 headers::ACCEPT.to_string(),
 | |
|                 self.common_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 Opennode {
 | |
|     fn id(&self) -> &'static str {
 | |
|         "opennode"
 | |
|     }
 | |
| 
 | |
|     fn common_get_content_type(&self) -> &'static str {
 | |
|         "application/json"
 | |
|     }
 | |
| 
 | |
|     fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str {
 | |
|         connectors.opennode.base_url.as_ref()
 | |
|     }
 | |
| 
 | |
|     fn get_auth_header(
 | |
|         &self,
 | |
|         auth_type: &types::ConnectorAuthType,
 | |
|     ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
 | |
|         let auth = opennode::OpennodeAuthType::try_from(auth_type)
 | |
|             .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
 | |
|         Ok(vec![(headers::AUTHORIZATION.to_string(), auth.api_key)])
 | |
|     }
 | |
| 
 | |
|     fn build_error_response(
 | |
|         &self,
 | |
|         res: Response,
 | |
|     ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
 | |
|         let response: opennode::OpennodeErrorResponse = res
 | |
|             .response
 | |
|             .parse_struct("OpennodeErrorResponse")
 | |
|             .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
 | |
| 
 | |
|         Ok(ErrorResponse {
 | |
|             status_code: res.status_code,
 | |
|             code: response.code,
 | |
|             message: response.message,
 | |
|             reason: response.reason,
 | |
|         })
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl
 | |
|     ConnectorIntegration<
 | |
|         api::PaymentMethodToken,
 | |
|         types::PaymentMethodTokenizationData,
 | |
|         types::PaymentsResponseData,
 | |
|     > for Opennode
 | |
| {
 | |
|     // Not Implemented (R)
 | |
| }
 | |
| 
 | |
| impl ConnectorIntegration<api::Session, types::PaymentsSessionData, types::PaymentsResponseData>
 | |
|     for Opennode
 | |
| {
 | |
|     //TODO: implement sessions flow
 | |
| }
 | |
| 
 | |
| impl ConnectorIntegration<api::AccessTokenAuth, types::AccessTokenRequestData, types::AccessToken>
 | |
|     for Opennode
 | |
| {
 | |
| }
 | |
| 
 | |
| impl ConnectorIntegration<api::Verify, types::VerifyRequestData, types::PaymentsResponseData>
 | |
|     for Opennode
 | |
| {
 | |
| }
 | |
| 
 | |
| impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::PaymentsResponseData>
 | |
|     for Opennode
 | |
| {
 | |
|     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> {
 | |
|         Ok(format!("{}/v1/charges", self.base_url(_connectors)))
 | |
|     }
 | |
| 
 | |
|     fn get_request_body(
 | |
|         &self,
 | |
|         req: &types::PaymentsAuthorizeRouterData,
 | |
|     ) -> CustomResult<Option<String>, errors::ConnectorError> {
 | |
|         let req_obj = opennode::OpennodePaymentsRequest::try_from(req)?;
 | |
|         let opennode_req =
 | |
|             Encode::<opennode::OpennodePaymentsRequest>::encode_to_string_of_json(&req_obj)
 | |
|                 .change_context(errors::ConnectorError::RequestEncodingFailed)?;
 | |
|         Ok(Some(opennode_req))
 | |
|     }
 | |
| 
 | |
|     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: opennode::OpennodePaymentsResponse = res
 | |
|             .response
 | |
|             .parse_struct("Opennode PaymentsAuthorizeResponse")
 | |
|             .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
 | |
|         types::RouterData::try_from(types::ResponseRouterData {
 | |
|             response,
 | |
|             data: data.clone(),
 | |
|             http_code: res.status_code,
 | |
|         })
 | |
|         .change_context(errors::ConnectorError::ResponseHandlingFailed)
 | |
|     }
 | |
| 
 | |
|     fn get_error_response(
 | |
|         &self,
 | |
|         res: Response,
 | |
|     ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
 | |
|         self.build_error_response(res)
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsResponseData>
 | |
|     for Opennode
 | |
| {
 | |
|     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 connector_id = _req
 | |
|             .request
 | |
|             .connector_transaction_id
 | |
|             .get_connector_transaction_id()
 | |
|             .change_context(errors::ConnectorError::MissingConnectorTransactionID)?;
 | |
|         Ok(format!(
 | |
|             "{}/v2/charge/{}",
 | |
|             self.base_url(_connectors),
 | |
|             connector_id
 | |
|         ))
 | |
|     }
 | |
| 
 | |
|     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 handle_response(
 | |
|         &self,
 | |
|         data: &types::PaymentsSyncRouterData,
 | |
|         res: Response,
 | |
|     ) -> CustomResult<types::PaymentsSyncRouterData, errors::ConnectorError> {
 | |
|         let response: opennode::OpennodePaymentsResponse = res
 | |
|             .response
 | |
|             .parse_struct("opennode PaymentsSyncResponse")
 | |
|             .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
 | |
|         types::RouterData::try_from(types::ResponseRouterData {
 | |
|             response,
 | |
|             data: data.clone(),
 | |
|             http_code: res.status_code,
 | |
|         })
 | |
|         .change_context(errors::ConnectorError::ResponseHandlingFailed)
 | |
|     }
 | |
| 
 | |
|     fn get_error_response(
 | |
|         &self,
 | |
|         res: Response,
 | |
|     ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
 | |
|         self.build_error_response(res)
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::PaymentsResponseData>
 | |
|     for Opennode
 | |
| {
 | |
|     fn get_headers(
 | |
|         &self,
 | |
|         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> {
 | |
|         Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
 | |
|     }
 | |
| 
 | |
|     fn get_request_body(
 | |
|         &self,
 | |
|         _req: &types::PaymentsCaptureRouterData,
 | |
|     ) -> CustomResult<Option<String>, errors::ConnectorError> {
 | |
|         Err(errors::ConnectorError::NotImplemented("get_request_body method".to_string()).into())
 | |
|     }
 | |
| 
 | |
|     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)?)
 | |
|                 .headers(types::PaymentsCaptureType::get_headers(
 | |
|                     self, req, connectors,
 | |
|                 )?)
 | |
|                 .build(),
 | |
|         ))
 | |
|     }
 | |
| 
 | |
|     fn handle_response(
 | |
|         &self,
 | |
|         data: &types::PaymentsCaptureRouterData,
 | |
|         res: Response,
 | |
|     ) -> CustomResult<types::PaymentsCaptureRouterData, errors::ConnectorError> {
 | |
|         let response: opennode::OpennodePaymentsResponse = res
 | |
|             .response
 | |
|             .parse_struct("Opennode PaymentsCaptureResponse")
 | |
|             .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
 | |
|         types::RouterData::try_from(types::ResponseRouterData {
 | |
|             response,
 | |
|             data: data.clone(),
 | |
|             http_code: res.status_code,
 | |
|         })
 | |
|         .change_context(errors::ConnectorError::ResponseHandlingFailed)
 | |
|     }
 | |
| 
 | |
|     fn get_error_response(
 | |
|         &self,
 | |
|         res: Response,
 | |
|     ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
 | |
|         self.build_error_response(res)
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl ConnectorIntegration<api::Void, types::PaymentsCancelData, types::PaymentsResponseData>
 | |
|     for Opennode
 | |
| {
 | |
| }
 | |
| 
 | |
| impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsResponseData>
 | |
|     for Opennode
 | |
| {
 | |
|     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> {
 | |
|         Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
 | |
|     }
 | |
| 
 | |
|     fn get_request_body(
 | |
|         &self,
 | |
|         req: &types::RefundsRouterData<api::Execute>,
 | |
|     ) -> CustomResult<Option<String>, errors::ConnectorError> {
 | |
|         let req_obj = opennode::OpennodeRefundRequest::try_from(req)?;
 | |
|         let opennode_req =
 | |
|             Encode::<opennode::OpennodeRefundRequest>::encode_to_string_of_json(&req_obj)
 | |
|                 .change_context(errors::ConnectorError::RequestEncodingFailed)?;
 | |
|         Ok(Some(opennode_req))
 | |
|     }
 | |
| 
 | |
|     fn build_request(
 | |
|         &self,
 | |
|         req: &types::RefundsRouterData<api::Execute>,
 | |
|         connectors: &settings::Connectors,
 | |
|     ) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
 | |
|         let request = services::RequestBuilder::new()
 | |
|             .method(services::Method::Post)
 | |
|             .url(&types::RefundExecuteType::get_url(self, req, connectors)?)
 | |
|             .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: opennode::RefundResponse = res
 | |
|             .response
 | |
|             .parse_struct("opennode 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)
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponseData> for Opennode {
 | |
|     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> {
 | |
|         Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
 | |
|     }
 | |
| 
 | |
|     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: opennode::RefundResponse = res
 | |
|             .response
 | |
|             .parse_struct("opennode RefundSyncResponse")
 | |
|             .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 Opennode {
 | |
|     fn get_webhook_source_verification_algorithm(
 | |
|         &self,
 | |
|         _request: &api::IncomingWebhookRequestDetails<'_>,
 | |
|     ) -> CustomResult<Box<dyn crypto::VerifySignature + Send>, errors::ConnectorError> {
 | |
|         Ok(Box::new(crypto::HmacSha256))
 | |
|     }
 | |
| 
 | |
|     fn get_webhook_source_verification_signature(
 | |
|         &self,
 | |
|         request: &api::IncomingWebhookRequestDetails<'_>,
 | |
|     ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
 | |
|         let notif = serde_urlencoded::from_bytes::<OpennodeWebhookDetails>(request.body)
 | |
|             .into_report()
 | |
|             .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
 | |
|         let base64_signature = notif.hashed_order;
 | |
|         hex::decode(base64_signature)
 | |
|             .into_report()
 | |
|             .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)
 | |
|     }
 | |
| 
 | |
|     fn get_webhook_source_verification_message(
 | |
|         &self,
 | |
|         request: &api::IncomingWebhookRequestDetails<'_>,
 | |
|         _merchant_id: &str,
 | |
|         _secret: &[u8],
 | |
|     ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
 | |
|         let message = std::str::from_utf8(request.body)
 | |
|             .into_report()
 | |
|             .change_context(errors::ConnectorError::ParsingFailed)?;
 | |
|         Ok(message.to_string().into_bytes())
 | |
|     }
 | |
| 
 | |
|     async fn get_webhook_source_verification_merchant_secret(
 | |
|         &self,
 | |
|         db: &dyn db::StorageInterface,
 | |
|         merchant_id: &str,
 | |
|     ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
 | |
|         let key = conn_utils::get_webhook_merchant_secret_key(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_object_reference_id(
 | |
|         &self,
 | |
|         request: &api::IncomingWebhookRequestDetails<'_>,
 | |
|     ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
 | |
|         let notif = serde_urlencoded::from_bytes::<OpennodeWebhookDetails>(request.body)
 | |
|             .into_report()
 | |
|             .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
 | |
|         Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
 | |
|             api_models::payments::PaymentIdType::ConnectorTransactionId(notif.id),
 | |
|         ))
 | |
|     }
 | |
| 
 | |
|     fn get_webhook_event_type(
 | |
|         &self,
 | |
|         request: &api::IncomingWebhookRequestDetails<'_>,
 | |
|     ) -> CustomResult<api::IncomingWebhookEvent, errors::ConnectorError> {
 | |
|         let notif = serde_urlencoded::from_bytes::<OpennodeWebhookDetails>(request.body)
 | |
|             .into_report()
 | |
|             .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
 | |
| 
 | |
|         match notif.status {
 | |
|             opennode::OpennodePaymentStatus::Paid => {
 | |
|                 Ok(api::IncomingWebhookEvent::PaymentIntentSuccess)
 | |
|             }
 | |
|             opennode::OpennodePaymentStatus::Underpaid
 | |
|             | opennode::OpennodePaymentStatus::Expired => {
 | |
|                 Ok(api::IncomingWebhookEvent::PaymentActionRequired)
 | |
|             }
 | |
|             opennode::OpennodePaymentStatus::Processing => {
 | |
|                 Ok(api::IncomingWebhookEvent::PaymentIntentProcessing)
 | |
|             }
 | |
|             _ => Ok(api::IncomingWebhookEvent::EventNotSupported),
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     fn get_webhook_resource_object(
 | |
|         &self,
 | |
|         request: &api::IncomingWebhookRequestDetails<'_>,
 | |
|     ) -> CustomResult<serde_json::Value, errors::ConnectorError> {
 | |
|         let notif = serde_urlencoded::from_bytes::<OpennodeWebhookDetails>(request.body)
 | |
|             .into_report()
 | |
|             .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
 | |
|         Encode::<OpennodeWebhookDetails>::encode_to_value(¬if.status)
 | |
|             .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)
 | |
|     }
 | |
| }
 | 
