mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-10-31 10:06:32 +08:00 
			
		
		
		
	refactor(connector): [WorldPay] migrate from modular to standard payment APIs (#6317)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
		
							
								
								
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -6438,6 +6438,7 @@ dependencies = [ | |||||||
|  "unicode-segmentation", |  "unicode-segmentation", | ||||||
|  "unidecode", |  "unidecode", | ||||||
|  "url", |  "url", | ||||||
|  |  "urlencoding", | ||||||
|  "utoipa", |  "utoipa", | ||||||
|  "uuid", |  "uuid", | ||||||
|  "validator", |  "validator", | ||||||
|  | |||||||
| @ -3416,6 +3416,12 @@ key1="Password" | |||||||
| api_secret="Merchant Identifier" | api_secret="Merchant Identifier" | ||||||
| [worldpay.connector_webhook_details] | [worldpay.connector_webhook_details] | ||||||
| merchant_secret="Source verification key" | merchant_secret="Source verification key" | ||||||
|  | [worldpay.metadata.merchant_name] | ||||||
|  | name="merchant_name" | ||||||
|  | label="Name of the merchant to de displayed during 3DS challenge" | ||||||
|  | placeholder="Enter Name of the merchant" | ||||||
|  | required=true | ||||||
|  | type="Text" | ||||||
|  |  | ||||||
| [[worldpay.metadata.apple_pay]] | [[worldpay.metadata.apple_pay]] | ||||||
| name="certificate" | name="certificate" | ||||||
|  | |||||||
| @ -2473,6 +2473,12 @@ merchant_secret="Source verification key" | |||||||
| api_key="Username" | api_key="Username" | ||||||
| key1="Password" | key1="Password" | ||||||
| api_secret="Merchant Identifier" | api_secret="Merchant Identifier" | ||||||
|  | [worldpay.metadata.merchant_name] | ||||||
|  | name="merchant_name" | ||||||
|  | label="Name of the merchant to de displayed during 3DS challenge" | ||||||
|  | placeholder="Enter Name of the merchant" | ||||||
|  | required=true | ||||||
|  | type="Text" | ||||||
|  |  | ||||||
| [[worldpay.metadata.apple_pay]] | [[worldpay.metadata.apple_pay]] | ||||||
| name="certificate" | name="certificate" | ||||||
|  | |||||||
| @ -3406,6 +3406,12 @@ key1="Password" | |||||||
| api_secret="Merchant Identifier" | api_secret="Merchant Identifier" | ||||||
| [worldpay.connector_webhook_details] | [worldpay.connector_webhook_details] | ||||||
| merchant_secret="Source verification key" | merchant_secret="Source verification key" | ||||||
|  | [worldpay.metadata.merchant_name] | ||||||
|  | name="merchant_name" | ||||||
|  | label="Name of the merchant to de displayed during 3DS challenge" | ||||||
|  | placeholder="Enter Name of the merchant" | ||||||
|  | required=true | ||||||
|  | type="Text" | ||||||
|  |  | ||||||
| [[worldpay.metadata.apple_pay]] | [[worldpay.metadata.apple_pay]] | ||||||
| name="certificate" | name="certificate" | ||||||
|  | |||||||
| @ -115,6 +115,7 @@ tracing-futures = { version = "0.2.5", features = ["tokio"] } | |||||||
| unicode-segmentation = "1.11.0" | unicode-segmentation = "1.11.0" | ||||||
| unidecode = "0.3.0" | unidecode = "0.3.0" | ||||||
| url = { version = "2.5.0", features = ["serde"] } | url = { version = "2.5.0", features = ["serde"] } | ||||||
|  | urlencoding = "2.1.3" | ||||||
| utoipa = { version = "4.2.0", features = ["preserve_order", "preserve_path_order", "time"] } | utoipa = { version = "4.2.0", features = ["preserve_order", "preserve_path_order", "time"] } | ||||||
| uuid = { version = "1.8.0", features = ["v4"] } | uuid = { version = "1.8.0", features = ["v4"] } | ||||||
| validator = "0.17.0" | validator = "0.17.0" | ||||||
|  | |||||||
| @ -725,6 +725,7 @@ impl PaymentsPreProcessingData for types::PaymentsPreProcessingData { | |||||||
| pub trait PaymentsCaptureRequestData { | pub trait PaymentsCaptureRequestData { | ||||||
|     fn is_multiple_capture(&self) -> bool; |     fn is_multiple_capture(&self) -> bool; | ||||||
|     fn get_browser_info(&self) -> Result<BrowserInformation, Error>; |     fn get_browser_info(&self) -> Result<BrowserInformation, Error>; | ||||||
|  |     fn get_capture_method(&self) -> Option<enums::CaptureMethod>; | ||||||
| } | } | ||||||
|  |  | ||||||
| impl PaymentsCaptureRequestData for types::PaymentsCaptureData { | impl PaymentsCaptureRequestData for types::PaymentsCaptureData { | ||||||
| @ -736,6 +737,9 @@ impl PaymentsCaptureRequestData for types::PaymentsCaptureData { | |||||||
|             .clone() |             .clone() | ||||||
|             .ok_or_else(missing_field_err("browser_info")) |             .ok_or_else(missing_field_err("browser_info")) | ||||||
|     } |     } | ||||||
|  |     fn get_capture_method(&self) -> Option<enums::CaptureMethod> { | ||||||
|  |         self.capture_method.to_owned() | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| pub trait RevokeMandateRequestData { | pub trait RevokeMandateRequestData { | ||||||
|  | |||||||
| @ -16,6 +16,7 @@ use self::{requests::*, response::*}; | |||||||
| use super::utils::{self as connector_utils, RefundsRequestData}; | use super::utils::{self as connector_utils, RefundsRequestData}; | ||||||
| use crate::{ | use crate::{ | ||||||
|     configs::settings, |     configs::settings, | ||||||
|  |     consts, | ||||||
|     core::errors::{self, CustomResult}, |     core::errors::{self, CustomResult}, | ||||||
|     events::connector_api_logs::ConnectorEvent, |     events::connector_api_logs::ConnectorEvent, | ||||||
|     headers, |     headers, | ||||||
| @ -64,6 +65,7 @@ where | |||||||
|                 headers::CONTENT_TYPE.to_string(), |                 headers::CONTENT_TYPE.to_string(), | ||||||
|                 self.get_content_type().to_string().into(), |                 self.get_content_type().to_string().into(), | ||||||
|             ), |             ), | ||||||
|  |             (headers::X_WP_API_VERSION.to_string(), "2024-06-01".into()), | ||||||
|         ]; |         ]; | ||||||
|         let mut api_key = self.get_auth_header(&req.connector_auth_type)?; |         let mut api_key = self.get_auth_header(&req.connector_auth_type)?; | ||||||
|         headers.append(&mut api_key); |         headers.append(&mut api_key); | ||||||
| @ -81,7 +83,7 @@ impl ConnectorCommon for Worldpay { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn common_get_content_type(&self) -> &'static str { |     fn common_get_content_type(&self) -> &'static str { | ||||||
|         "application/vnd.worldpay.payments-v7+json" |         "application/json" | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { |     fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { | ||||||
| @ -205,8 +207,9 @@ impl ConnectorIntegration<api::Void, types::PaymentsCancelData, types::PaymentsR | |||||||
|     ) -> CustomResult<String, errors::ConnectorError> { |     ) -> CustomResult<String, errors::ConnectorError> { | ||||||
|         let connector_payment_id = req.request.connector_transaction_id.clone(); |         let connector_payment_id = req.request.connector_transaction_id.clone(); | ||||||
|         Ok(format!( |         Ok(format!( | ||||||
|             "{}payments/authorizations/cancellations/{connector_payment_id}", |             "{}api/payments/{}/cancellations", | ||||||
|             self.base_url(connectors), |             self.base_url(connectors), | ||||||
|  |             urlencoding::encode(&connector_payment_id), | ||||||
|         )) |         )) | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -244,15 +247,24 @@ impl ConnectorIntegration<api::Void, types::PaymentsCancelData, types::PaymentsR | |||||||
|                     .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; |                     .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; | ||||||
|                 event_builder.map(|i| i.set_response_body(&response)); |                 event_builder.map(|i| i.set_response_body(&response)); | ||||||
|                 router_env::logger::info!(connector_response=?response); |                 router_env::logger::info!(connector_response=?response); | ||||||
|  |                 let optional_correlation_id = res.headers.and_then(|headers| { | ||||||
|  |                     headers | ||||||
|  |                         .get(consts::WP_CORRELATION_ID) | ||||||
|  |                         .and_then(|header_value| header_value.to_str().ok()) | ||||||
|  |                         .map(|id| id.to_string()) | ||||||
|  |                 }); | ||||||
|                 Ok(types::PaymentsCancelRouterData { |                 Ok(types::PaymentsCancelRouterData { | ||||||
|                     status: enums::AttemptStatus::Voided, |                     status: enums::AttemptStatus::from(response.outcome.clone()), | ||||||
|                     response: Ok(types::PaymentsResponseData::TransactionResponse { |                     response: Ok(types::PaymentsResponseData::TransactionResponse { | ||||||
|                         resource_id: types::ResponseId::foreign_try_from(response.links)?, |                         resource_id: types::ResponseId::foreign_try_from(( | ||||||
|  |                             response, | ||||||
|  |                             Some(data.request.connector_transaction_id.clone()), | ||||||
|  |                         ))?, | ||||||
|                         redirection_data: None, |                         redirection_data: None, | ||||||
|                         mandate_reference: None, |                         mandate_reference: None, | ||||||
|                         connector_metadata: None, |                         connector_metadata: None, | ||||||
|                         network_txn_id: None, |                         network_txn_id: None, | ||||||
|                         connector_response_reference_id: None, |                         connector_response_reference_id: optional_correlation_id, | ||||||
|                         incremental_authorization_allowed: None, |                         incremental_authorization_allowed: None, | ||||||
|                         charge_id: None, |                         charge_id: None, | ||||||
|                     }), |                     }), | ||||||
| @ -306,9 +318,9 @@ impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsRe | |||||||
|             .get_connector_transaction_id() |             .get_connector_transaction_id() | ||||||
|             .change_context(errors::ConnectorError::MissingConnectorTransactionID)?; |             .change_context(errors::ConnectorError::MissingConnectorTransactionID)?; | ||||||
|         Ok(format!( |         Ok(format!( | ||||||
|             "{}payments/events/{}", |             "{}api/payments/{}", | ||||||
|             self.base_url(connectors), |             self.base_url(connectors), | ||||||
|             connector_payment_id |             urlencoding::encode(&connector_payment_id), | ||||||
|         )) |         )) | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -349,6 +361,12 @@ impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsRe | |||||||
|         event_builder.map(|i| i.set_response_body(&response)); |         event_builder.map(|i| i.set_response_body(&response)); | ||||||
|         router_env::logger::info!(connector_response=?response); |         router_env::logger::info!(connector_response=?response); | ||||||
|  |  | ||||||
|  |         let optional_correlation_id = res.headers.and_then(|headers| { | ||||||
|  |             headers | ||||||
|  |                 .get(consts::WP_CORRELATION_ID) | ||||||
|  |                 .and_then(|header_value| header_value.to_str().ok()) | ||||||
|  |                 .map(|id| id.to_string()) | ||||||
|  |         }); | ||||||
|         let attempt_status = data.status; |         let attempt_status = data.status; | ||||||
|         let worldpay_status = response.last_event; |         let worldpay_status = response.last_event; | ||||||
|         let status = match (attempt_status, worldpay_status.clone()) { |         let status = match (attempt_status, worldpay_status.clone()) { | ||||||
| @ -371,7 +389,7 @@ impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsRe | |||||||
|                 mandate_reference: None, |                 mandate_reference: None, | ||||||
|                 connector_metadata: None, |                 connector_metadata: None, | ||||||
|                 network_txn_id: None, |                 network_txn_id: None, | ||||||
|                 connector_response_reference_id: None, |                 connector_response_reference_id: optional_correlation_id, | ||||||
|                 incremental_authorization_allowed: None, |                 incremental_authorization_allowed: None, | ||||||
|                 charge_id: None, |                 charge_id: None, | ||||||
|             }), |             }), | ||||||
| @ -403,9 +421,9 @@ impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::Payme | |||||||
|     ) -> CustomResult<String, errors::ConnectorError> { |     ) -> CustomResult<String, errors::ConnectorError> { | ||||||
|         let connector_payment_id = req.request.connector_transaction_id.clone(); |         let connector_payment_id = req.request.connector_transaction_id.clone(); | ||||||
|         Ok(format!( |         Ok(format!( | ||||||
|             "{}payments/settlements/partials/{}", |             "{}api/payments/{}/partialSettlements", | ||||||
|             self.base_url(connectors), |             self.base_url(connectors), | ||||||
|             connector_payment_id |             urlencoding::encode(&connector_payment_id), | ||||||
|         )) |         )) | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -457,15 +475,24 @@ impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::Payme | |||||||
|                     .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; |                     .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; | ||||||
|                 event_builder.map(|i| i.set_response_body(&response)); |                 event_builder.map(|i| i.set_response_body(&response)); | ||||||
|                 router_env::logger::info!(connector_response=?response); |                 router_env::logger::info!(connector_response=?response); | ||||||
|  |                 let optional_correlation_id = res.headers.and_then(|headers| { | ||||||
|  |                     headers | ||||||
|  |                         .get(consts::WP_CORRELATION_ID) | ||||||
|  |                         .and_then(|header_value| header_value.to_str().ok()) | ||||||
|  |                         .map(|id| id.to_string()) | ||||||
|  |                 }); | ||||||
|                 Ok(types::PaymentsCaptureRouterData { |                 Ok(types::PaymentsCaptureRouterData { | ||||||
|                     status: enums::AttemptStatus::Pending, |                     status: enums::AttemptStatus::Pending, | ||||||
|                     response: Ok(types::PaymentsResponseData::TransactionResponse { |                     response: Ok(types::PaymentsResponseData::TransactionResponse { | ||||||
|                         resource_id: types::ResponseId::foreign_try_from(response.links)?, |                         resource_id: types::ResponseId::foreign_try_from(( | ||||||
|  |                             response, | ||||||
|  |                             Some(data.request.connector_transaction_id.clone()), | ||||||
|  |                         ))?, | ||||||
|                         redirection_data: None, |                         redirection_data: None, | ||||||
|                         mandate_reference: None, |                         mandate_reference: None, | ||||||
|                         connector_metadata: None, |                         connector_metadata: None, | ||||||
|                         network_txn_id: None, |                         network_txn_id: None, | ||||||
|                         connector_response_reference_id: None, |                         connector_response_reference_id: optional_correlation_id, | ||||||
|                         incremental_authorization_allowed: None, |                         incremental_authorization_allowed: None, | ||||||
|                         charge_id: None, |                         charge_id: None, | ||||||
|                     }), |                     }), | ||||||
| @ -514,10 +541,7 @@ impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::P | |||||||
|         _req: &types::PaymentsAuthorizeRouterData, |         _req: &types::PaymentsAuthorizeRouterData, | ||||||
|         connectors: &settings::Connectors, |         connectors: &settings::Connectors, | ||||||
|     ) -> CustomResult<String, errors::ConnectorError> { |     ) -> CustomResult<String, errors::ConnectorError> { | ||||||
|         Ok(format!( |         Ok(format!("{}api/payments", self.base_url(connectors))) | ||||||
|             "{}cardPayments/customerInitiatedTransactions", |  | ||||||
|             self.base_url(connectors) |  | ||||||
|         )) |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn get_request_body( |     fn get_request_body( | ||||||
| @ -573,12 +597,21 @@ impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::P | |||||||
|  |  | ||||||
|         event_builder.map(|i| i.set_response_body(&response)); |         event_builder.map(|i| i.set_response_body(&response)); | ||||||
|         router_env::logger::info!(connector_response=?response); |         router_env::logger::info!(connector_response=?response); | ||||||
|  |         let optional_correlation_id = res.headers.and_then(|headers| { | ||||||
|  |             headers | ||||||
|  |                 .get(consts::WP_CORRELATION_ID) | ||||||
|  |                 .and_then(|header_value| header_value.to_str().ok()) | ||||||
|  |                 .map(|id| id.to_string()) | ||||||
|  |         }); | ||||||
|  |  | ||||||
|         types::RouterData::try_from(types::ResponseRouterData { |         types::RouterData::foreign_try_from(( | ||||||
|             response, |             types::ResponseRouterData { | ||||||
|             data: data.clone(), |                 response, | ||||||
|             http_code: res.status_code, |                 data: data.clone(), | ||||||
|         }) |                 http_code: res.status_code, | ||||||
|  |             }, | ||||||
|  |             optional_correlation_id, | ||||||
|  |         )) | ||||||
|         .change_context(errors::ConnectorError::ResponseHandlingFailed) |         .change_context(errors::ConnectorError::ResponseHandlingFailed) | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -631,9 +664,9 @@ impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsRespon | |||||||
|     ) -> CustomResult<String, errors::ConnectorError> { |     ) -> CustomResult<String, errors::ConnectorError> { | ||||||
|         let connector_payment_id = req.request.connector_transaction_id.clone(); |         let connector_payment_id = req.request.connector_transaction_id.clone(); | ||||||
|         Ok(format!( |         Ok(format!( | ||||||
|             "{}payments/settlements/refunds/partials/{}", |             "{}api/payments/{}/partialRefunds", | ||||||
|             self.base_url(connectors), |             self.base_url(connectors), | ||||||
|             connector_payment_id |             urlencoding::encode(&connector_payment_id), | ||||||
|         )) |         )) | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -670,9 +703,19 @@ impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsRespon | |||||||
|                     .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; |                     .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; | ||||||
|                 event_builder.map(|i| i.set_response_body(&response)); |                 event_builder.map(|i| i.set_response_body(&response)); | ||||||
|                 router_env::logger::info!(connector_response=?response); |                 router_env::logger::info!(connector_response=?response); | ||||||
|  |                 let optional_correlation_id = res.headers.and_then(|headers| { | ||||||
|  |                     headers | ||||||
|  |                         .get(consts::WP_CORRELATION_ID) | ||||||
|  |                         .and_then(|header_value| header_value.to_str().ok()) | ||||||
|  |                         .map(|id| id.to_string()) | ||||||
|  |                 }); | ||||||
|                 Ok(types::RefundExecuteRouterData { |                 Ok(types::RefundExecuteRouterData { | ||||||
|                     response: Ok(types::RefundsResponseData { |                     response: Ok(types::RefundsResponseData { | ||||||
|                         connector_refund_id: ResponseIdStr::try_from(response.links)?.id, |                         connector_refund_id: ResponseIdStr::foreign_try_from(( | ||||||
|  |                             response, | ||||||
|  |                             optional_correlation_id, | ||||||
|  |                         ))? | ||||||
|  |                         .id, | ||||||
|                         refund_status: enums::RefundStatus::Pending, |                         refund_status: enums::RefundStatus::Pending, | ||||||
|                     }), |                     }), | ||||||
|                     ..data.clone() |                     ..data.clone() | ||||||
| @ -710,9 +753,9 @@ impl ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponse | |||||||
|         connectors: &settings::Connectors, |         connectors: &settings::Connectors, | ||||||
|     ) -> CustomResult<String, errors::ConnectorError> { |     ) -> CustomResult<String, errors::ConnectorError> { | ||||||
|         Ok(format!( |         Ok(format!( | ||||||
|             "{}payments/events/{}", |             "{}api/payments/{}", | ||||||
|             self.base_url(connectors), |             self.base_url(connectors), | ||||||
|             req.request.get_connector_refund_id()? |             urlencoding::encode(&req.request.get_connector_refund_id()?), | ||||||
|         )) |         )) | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -813,7 +856,7 @@ impl api::IncomingWebhook for Worldpay { | |||||||
|             .parse_struct("WorldpayWebhookTransactionId") |             .parse_struct("WorldpayWebhookTransactionId") | ||||||
|             .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?; |             .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?; | ||||||
|         Ok(api_models::webhooks::ObjectReferenceId::PaymentId( |         Ok(api_models::webhooks::ObjectReferenceId::PaymentId( | ||||||
|             api::PaymentIdType::ConnectorTransactionId(body.event_details.transaction_reference), |             api::PaymentIdType::PaymentAttemptId(body.event_details.transaction_reference), | ||||||
|         )) |         )) | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -829,13 +872,14 @@ impl api::IncomingWebhook for Worldpay { | |||||||
|             EventType::Authorized => { |             EventType::Authorized => { | ||||||
|                 Ok(api::IncomingWebhookEvent::PaymentIntentAuthorizationSuccess) |                 Ok(api::IncomingWebhookEvent::PaymentIntentAuthorizationSuccess) | ||||||
|             } |             } | ||||||
|             EventType::SentForSettlement => Ok(api::IncomingWebhookEvent::PaymentIntentProcessing), |  | ||||||
|             EventType::Settled => Ok(api::IncomingWebhookEvent::PaymentIntentSuccess), |             EventType::Settled => Ok(api::IncomingWebhookEvent::PaymentIntentSuccess), | ||||||
|  |             EventType::SentForSettlement | EventType::SentForAuthorization => { | ||||||
|  |                 Ok(api::IncomingWebhookEvent::PaymentIntentProcessing) | ||||||
|  |             } | ||||||
|             EventType::Error | EventType::Expired | EventType::SettlementFailed => { |             EventType::Error | EventType::Expired | EventType::SettlementFailed => { | ||||||
|                 Ok(api::IncomingWebhookEvent::PaymentIntentFailure) |                 Ok(api::IncomingWebhookEvent::PaymentIntentFailure) | ||||||
|             } |             } | ||||||
|             EventType::Unknown |             EventType::Unknown | ||||||
|             | EventType::SentForAuthorization |  | ||||||
|             | EventType::Cancelled |             | EventType::Cancelled | ||||||
|             | EventType::Refused |             | EventType::Refused | ||||||
|             | EventType::Refunded |             | EventType::Refunded | ||||||
|  | |||||||
| @ -1,5 +1,99 @@ | |||||||
| use masking::Secret; | use masking::Secret; | ||||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug, PartialEq, Serialize)] | ||||||
|  | #[serde(rename_all = "camelCase")] | ||||||
|  | pub struct WorldpayPaymentsRequest { | ||||||
|  |     pub transaction_reference: String, | ||||||
|  |     pub merchant: Merchant, | ||||||
|  |     pub instruction: Instruction, | ||||||
|  |     #[serde(skip_serializing_if = "Option::is_none")] | ||||||
|  |     pub customer: Option<Customer>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] | ||||||
|  | #[serde(rename_all = "camelCase")] | ||||||
|  | pub struct Merchant { | ||||||
|  |     pub entity: Secret<String>, | ||||||
|  |     #[serde(skip_serializing_if = "Option::is_none")] | ||||||
|  |     pub mcc: Option<String>, | ||||||
|  |     #[serde(skip_serializing_if = "Option::is_none")] | ||||||
|  |     pub payment_facilitator: Option<PaymentFacilitator>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug, PartialEq, Serialize)] | ||||||
|  | #[serde(rename_all = "camelCase")] | ||||||
|  | pub struct Instruction { | ||||||
|  |     pub settlement: Option<AutoSettlement>, | ||||||
|  |     pub method: PaymentMethod, | ||||||
|  |     pub payment_instrument: PaymentInstrument, | ||||||
|  |     pub narrative: InstructionNarrative, | ||||||
|  |     pub value: PaymentValue, | ||||||
|  |     #[serde(skip_serializing_if = "Option::is_none")] | ||||||
|  |     pub debt_repayment: Option<bool>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | ||||||
|  | #[serde(untagged)] | ||||||
|  | pub enum PaymentInstrument { | ||||||
|  |     Card(CardPayment), | ||||||
|  |     CardToken(CardToken), | ||||||
|  |     Googlepay(WalletPayment), | ||||||
|  |     Applepay(WalletPayment), | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] | ||||||
|  | #[serde(rename_all = "camelCase")] | ||||||
|  | pub struct CardPayment { | ||||||
|  |     #[serde(rename = "type")] | ||||||
|  |     pub payment_type: PaymentType, | ||||||
|  |     #[serde(skip_serializing_if = "Option::is_none")] | ||||||
|  |     pub card_holder_name: Option<Secret<String>>, | ||||||
|  |     pub card_number: cards::CardNumber, | ||||||
|  |     pub expiry_date: ExpiryDate, | ||||||
|  |     #[serde(skip_serializing_if = "Option::is_none")] | ||||||
|  |     pub billing_address: Option<BillingAddress>, | ||||||
|  |     pub cvc: Secret<String>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] | ||||||
|  | #[serde(rename_all = "camelCase")] | ||||||
|  | pub struct CardToken { | ||||||
|  |     #[serde(rename = "type")] | ||||||
|  |     pub payment_type: PaymentType, | ||||||
|  |     pub href: String, | ||||||
|  |     #[serde(skip_serializing_if = "Option::is_none")] | ||||||
|  |     pub cvc: Option<Secret<String>>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] | ||||||
|  | #[serde(rename_all = "camelCase")] | ||||||
|  | pub struct WalletPayment { | ||||||
|  |     #[serde(rename = "type")] | ||||||
|  |     pub payment_type: PaymentType, | ||||||
|  |     pub wallet_token: Secret<String>, | ||||||
|  |     #[serde(skip_serializing_if = "Option::is_none")] | ||||||
|  |     pub billing_address: Option<BillingAddress>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive( | ||||||
|  |     Clone, Copy, Debug, Eq, Default, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, | ||||||
|  | )] | ||||||
|  | #[serde(rename_all = "lowercase")] | ||||||
|  | pub enum PaymentType { | ||||||
|  |     #[default] | ||||||
|  |     Plain, | ||||||
|  |     Token, | ||||||
|  |     Encrypted, | ||||||
|  |     Checkout, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] | ||||||
|  | pub struct ExpiryDate { | ||||||
|  |     pub month: Secret<i8>, | ||||||
|  |     pub year: Secret<i32>, | ||||||
|  | } | ||||||
|  |  | ||||||
| #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] | #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] | ||||||
| #[serde(rename_all = "camelCase")] | #[serde(rename_all = "camelCase")] | ||||||
| pub struct BillingAddress { | pub struct BillingAddress { | ||||||
| @ -17,17 +111,6 @@ pub struct BillingAddress { | |||||||
|     pub country_code: common_enums::CountryAlpha2, |     pub country_code: common_enums::CountryAlpha2, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Clone, Debug, PartialEq, Serialize)] |  | ||||||
| #[serde(rename_all = "camelCase")] |  | ||||||
| pub struct WorldpayPaymentsRequest { |  | ||||||
|     pub transaction_reference: String, |  | ||||||
|     pub merchant: Merchant, |  | ||||||
|     pub instruction: Instruction, |  | ||||||
|     pub channel: Channel, |  | ||||||
|     #[serde(skip_serializing_if = "Option::is_none")] |  | ||||||
|     pub customer: Option<Customer>, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[derive( | #[derive( | ||||||
|     Clone, Copy, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, |     Clone, Copy, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, | ||||||
| )] | )] | ||||||
| @ -100,89 +183,23 @@ pub struct NetworkToken { | |||||||
|  |  | ||||||
| #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | ||||||
| #[serde(rename_all = "camelCase")] | #[serde(rename_all = "camelCase")] | ||||||
| pub struct Instruction { | pub struct AutoSettlement { | ||||||
|     pub request_auto_settlement: RequestAutoSettlement, |     pub auto: bool, | ||||||
|     pub narrative: InstructionNarrative, |  | ||||||
|     pub value: PaymentValue, |  | ||||||
|     pub payment_instrument: PaymentInstrument, |  | ||||||
|     #[serde(skip_serializing_if = "Option::is_none")] |  | ||||||
|     pub debt_repayment: Option<bool>, |  | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] | ||||||
| #[serde(rename_all = "camelCase")] | #[serde(rename_all = "lowercase")] | ||||||
| pub struct RequestAutoSettlement { | pub enum PaymentMethod { | ||||||
|     pub enabled: bool, |     #[default] | ||||||
|  |     Card, | ||||||
|  |     ApplePay, | ||||||
|  |     GooglePay, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] | #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] | ||||||
| #[serde(rename_all = "camelCase")] | #[serde(rename_all = "camelCase")] | ||||||
| pub struct InstructionNarrative { | pub struct InstructionNarrative { | ||||||
|     pub line1: String, |     pub line1: String, | ||||||
|     #[serde(skip_serializing_if = "Option::is_none")] |  | ||||||
|     pub line2: Option<String>, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] |  | ||||||
| #[serde(untagged)] |  | ||||||
| pub enum PaymentInstrument { |  | ||||||
|     Card(CardPayment), |  | ||||||
|     CardToken(CardToken), |  | ||||||
|     Googlepay(WalletPayment), |  | ||||||
|     Applepay(WalletPayment), |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[derive( |  | ||||||
|     Clone, Copy, Debug, Eq, Default, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, |  | ||||||
| )] |  | ||||||
| pub enum PaymentType { |  | ||||||
|     #[default] |  | ||||||
|     #[serde(rename = "card/plain")] |  | ||||||
|     Card, |  | ||||||
|     #[serde(rename = "card/token")] |  | ||||||
|     CardToken, |  | ||||||
|     #[serde(rename = "card/wallet+googlepay")] |  | ||||||
|     Googlepay, |  | ||||||
|     #[serde(rename = "card/wallet+applepay")] |  | ||||||
|     Applepay, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] |  | ||||||
| #[serde(rename_all = "camelCase")] |  | ||||||
| pub struct CardPayment { |  | ||||||
|     #[serde(rename = "type")] |  | ||||||
|     pub payment_type: PaymentType, |  | ||||||
|     pub card_number: cards::CardNumber, |  | ||||||
|     pub expiry_date: ExpiryDate, |  | ||||||
|     #[serde(skip_serializing_if = "Option::is_none")] |  | ||||||
|     pub card_holder_name: Option<Secret<String>>, |  | ||||||
|     #[serde(skip_serializing_if = "Option::is_none")] |  | ||||||
|     pub billing_address: Option<BillingAddress>, |  | ||||||
|     pub cvc: Secret<String>, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] |  | ||||||
| #[serde(rename_all = "camelCase")] |  | ||||||
| pub struct CardToken { |  | ||||||
|     #[serde(rename = "type")] |  | ||||||
|     pub payment_type: PaymentType, |  | ||||||
|     pub href: String, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] |  | ||||||
| #[serde(rename_all = "camelCase")] |  | ||||||
| pub struct WalletPayment { |  | ||||||
|     #[serde(rename = "type")] |  | ||||||
|     pub payment_type: PaymentType, |  | ||||||
|     pub wallet_token: Secret<String>, |  | ||||||
|     #[serde(skip_serializing_if = "Option::is_none")] |  | ||||||
|     pub billing_address: Option<BillingAddress>, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] |  | ||||||
| pub struct ExpiryDate { |  | ||||||
|     pub month: Secret<i8>, |  | ||||||
|     pub year: Secret<i32>, |  | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] | #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] | ||||||
| @ -191,16 +208,6 @@ pub struct PaymentValue { | |||||||
|     pub currency: api_models::enums::Currency, |     pub currency: api_models::enums::Currency, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] |  | ||||||
| #[serde(rename_all = "camelCase")] |  | ||||||
| pub struct Merchant { |  | ||||||
|     pub entity: Secret<String>, |  | ||||||
|     #[serde(skip_serializing_if = "Option::is_none")] |  | ||||||
|     pub mcc: Option<String>, |  | ||||||
|     #[serde(skip_serializing_if = "Option::is_none")] |  | ||||||
|     pub payment_facilitator: Option<PaymentFacilitator>, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] | #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] | ||||||
| #[serde(rename_all = "camelCase")] | #[serde(rename_all = "camelCase")] | ||||||
| pub struct PaymentFacilitator { | pub struct PaymentFacilitator { | ||||||
|  | |||||||
| @ -1,25 +1,97 @@ | |||||||
|  | use error_stack::ResultExt; | ||||||
| use masking::Secret; | use masking::Secret; | ||||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||||
|  |  | ||||||
| use super::requests::*; | use super::requests::*; | ||||||
| use crate::{core::errors, types, types::transformers::ForeignTryFrom}; | use crate::core::errors; | ||||||
| #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | ||||||
| #[serde(rename_all = "camelCase")] | #[serde(rename_all = "camelCase")] | ||||||
| pub struct WorldpayPaymentsResponse { | pub struct WorldpayPaymentsResponse { | ||||||
|     pub outcome: Option<PaymentOutcome>, |     pub outcome: PaymentOutcome, | ||||||
|     /// Any risk factors which have been identified for the authorization. This section will not appear if no risks are identified. |     pub transaction_reference: Option<String>, | ||||||
|  |     #[serde(flatten)] | ||||||
|  |     pub other_fields: WorldpayPaymentResponseFields, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | ||||||
|  | #[serde(untagged)] | ||||||
|  | pub enum WorldpayPaymentResponseFields { | ||||||
|  |     AuthorizedResponse(Box<AuthorizedResponse>), | ||||||
|  |     DDCResponse(DDCResponse), | ||||||
|  |     FraudHighRisk(FraudHighRiskResponse), | ||||||
|  |     RefusedResponse(RefusedResponse), | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | ||||||
|  | #[serde(rename_all = "camelCase")] | ||||||
|  | pub struct AuthorizedResponse { | ||||||
|     #[serde(skip_serializing_if = "Option::is_none")] |     #[serde(skip_serializing_if = "Option::is_none")] | ||||||
|     pub risk_factors: Option<Vec<RiskFactorsInner>>, |     pub payment_instrument: Option<PaymentsResPaymentInstrument>, | ||||||
|     #[serde(skip_serializing_if = "Option::is_none")] |     #[serde(skip_serializing_if = "Option::is_none")] | ||||||
|     pub issuer: Option<Issuer>, |     pub issuer: Option<Issuer>, | ||||||
|     #[serde(skip_serializing_if = "Option::is_none")] |     #[serde(skip_serializing_if = "Option::is_none")] | ||||||
|     pub scheme: Option<PaymentsResponseScheme>, |     pub scheme: Option<PaymentsResponseScheme>, | ||||||
|     #[serde(skip_serializing_if = "Option::is_none")] |  | ||||||
|     pub payment_instrument: Option<PaymentsResPaymentInstrument>, |  | ||||||
|     #[serde(rename = "_links", skip_serializing_if = "Option::is_none")] |     #[serde(rename = "_links", skip_serializing_if = "Option::is_none")] | ||||||
|     pub links: Option<PaymentLinks>, |     pub links: Option<SelfLink>, | ||||||
|  |     #[serde(rename = "_actions")] | ||||||
|  |     pub actions: Option<ActionLinks>, | ||||||
|     #[serde(skip_serializing_if = "Option::is_none")] |     #[serde(skip_serializing_if = "Option::is_none")] | ||||||
|     pub description: Option<String>, |     pub description: Option<String>, | ||||||
|  |     pub risk_factors: Option<Vec<RiskFactorsInner>>, | ||||||
|  |     pub fraud: Option<Fraud>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | ||||||
|  | pub struct FraudHighRiskResponse { | ||||||
|  |     pub score: f32, | ||||||
|  |     pub reason: Vec<String>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | ||||||
|  | #[serde(rename_all = "camelCase")] | ||||||
|  | pub struct RefusedResponse { | ||||||
|  |     pub refusal_description: String, | ||||||
|  |     pub refusal_code: String, | ||||||
|  |     pub risk_factors: Vec<RiskFactorsInner>, | ||||||
|  |     pub fraud: Fraud, | ||||||
|  |     #[serde(rename = "threeDS")] | ||||||
|  |     pub three_ds: Option<ThreeDsResponse>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | ||||||
|  | #[serde(rename_all = "camelCase")] | ||||||
|  | pub struct ThreeDsResponse { | ||||||
|  |     pub outcome: String, | ||||||
|  |     pub issuer_response: IssuerResponse, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | ||||||
|  | #[serde(rename_all = "camelCase")] | ||||||
|  | pub enum IssuerResponse { | ||||||
|  |     Challenged, | ||||||
|  |     Frictionless, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | ||||||
|  | #[serde(rename_all = "camelCase")] | ||||||
|  | pub struct DDCResponse { | ||||||
|  |     pub device_data_collection: DDCToken, | ||||||
|  |     #[serde(rename = "_actions")] | ||||||
|  |     pub actions: DDCActionLink, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | ||||||
|  | pub struct DDCToken { | ||||||
|  |     pub jwt: String, | ||||||
|  |     pub url: String, | ||||||
|  |     pub bin: String, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | ||||||
|  | pub struct DDCActionLink { | ||||||
|  |     #[serde(rename = "supply3dsDeviceData")] | ||||||
|  |     supply_ddc_data: ActionLink, | ||||||
|  |     method: String, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | ||||||
| @ -28,16 +100,57 @@ pub enum PaymentOutcome { | |||||||
|     #[serde(alias = "authorized", alias = "Authorized")] |     #[serde(alias = "authorized", alias = "Authorized")] | ||||||
|     Authorized, |     Authorized, | ||||||
|     Refused, |     Refused, | ||||||
|     #[serde(alias = "Sent for Settlement")] |  | ||||||
|     SentForSettlement, |     SentForSettlement, | ||||||
|     #[serde(alias = "Sent for Refund")] |  | ||||||
|     SentForRefund, |     SentForRefund, | ||||||
|  |     FraudHighRisk, | ||||||
|  |     #[serde(alias = "3dsDeviceDataRequired")] | ||||||
|  |     ThreeDsDeviceDataRequired, | ||||||
|  |     ThreeDsChallenged, | ||||||
|  |     SentForCancellation, | ||||||
|  |     #[serde(alias = "3dsAuthenticationFailed")] | ||||||
|  |     ThreeDsAuthenticationFailed, | ||||||
|  |     SentForPartialRefund, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | ||||||
| pub enum RefundOutcome { | pub struct SelfLink { | ||||||
|     #[serde(alias = "Sent for Refund")] |     #[serde(rename = "self")] | ||||||
|     SentForRefund, |     pub self_link: SelfLinkInner, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | ||||||
|  | pub struct SelfLinkInner { | ||||||
|  |     pub href: String, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | ||||||
|  | #[serde(rename_all = "camelCase")] | ||||||
|  | pub struct ActionLinks { | ||||||
|  |     supply_3ds_device_data: Option<ActionLink>, | ||||||
|  |     settle_payment: Option<ActionLink>, | ||||||
|  |     partially_settle_payment: Option<ActionLink>, | ||||||
|  |     refund_payment: Option<ActionLink>, | ||||||
|  |     partiall_refund_payment: Option<ActionLink>, | ||||||
|  |     cancel_payment: Option<ActionLink>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | ||||||
|  | pub struct ActionLink { | ||||||
|  |     pub href: String, | ||||||
|  |     pub method: String, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | ||||||
|  | pub struct Fraud { | ||||||
|  |     pub outcome: FraudOutcome, | ||||||
|  |     pub score: f32, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | ||||||
|  | #[serde(rename_all = "camelCase")] | ||||||
|  | pub enum FraudOutcome { | ||||||
|  |     LowRisk, | ||||||
|  |     HighRisk, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | ||||||
| @ -70,40 +183,6 @@ pub enum EventType { | |||||||
|     Unknown, |     Unknown, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] |  | ||||||
| pub struct PaymentLinks { |  | ||||||
|     #[serde( |  | ||||||
|         rename = "cardPayments:events", |  | ||||||
|         skip_serializing_if = "Option::is_none" |  | ||||||
|     )] |  | ||||||
|     pub events: Option<PaymentLink>, |  | ||||||
|     #[serde( |  | ||||||
|         rename = "cardPayments:settle", |  | ||||||
|         skip_serializing_if = "Option::is_none" |  | ||||||
|     )] |  | ||||||
|     pub settle_event: Option<PaymentLink>, |  | ||||||
|     #[serde( |  | ||||||
|         rename = "cardPayments:partialSettle", |  | ||||||
|         skip_serializing_if = "Option::is_none" |  | ||||||
|     )] |  | ||||||
|     pub partial_settle_event: Option<PaymentLink>, |  | ||||||
|     #[serde( |  | ||||||
|         rename = "cardPayments:refund", |  | ||||||
|         skip_serializing_if = "Option::is_none" |  | ||||||
|     )] |  | ||||||
|     pub refund_event: Option<PaymentLink>, |  | ||||||
|     #[serde( |  | ||||||
|         rename = "cardPayments:partialRefund", |  | ||||||
|         skip_serializing_if = "Option::is_none" |  | ||||||
|     )] |  | ||||||
|     pub partial_refund_event: Option<PaymentLink>, |  | ||||||
|     #[serde( |  | ||||||
|         rename = "cardPayments:reverse", |  | ||||||
|         skip_serializing_if = "Option::is_none" |  | ||||||
|     )] |  | ||||||
|     pub reverse_event: Option<PaymentLink>, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] | #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] | ||||||
| pub struct EventLinks { | pub struct EventLinks { | ||||||
|     #[serde(rename = "payments:events", skip_serializing_if = "Option::is_none")] |     #[serde(rename = "payments:events", skip_serializing_if = "Option::is_none")] | ||||||
| @ -115,43 +194,51 @@ pub struct PaymentLink { | |||||||
|     pub href: String, |     pub href: String, | ||||||
| } | } | ||||||
|  |  | ||||||
| fn get_resource_id<T, F>( | pub fn get_resource_id<T, F>( | ||||||
|     links: Option<PaymentLinks>, |     response: WorldpayPaymentsResponse, | ||||||
|  |     connector_transaction_id: Option<String>, | ||||||
|     transform_fn: F, |     transform_fn: F, | ||||||
| ) -> Result<T, error_stack::Report<errors::ConnectorError>> | ) -> Result<T, error_stack::Report<errors::ConnectorError>> | ||||||
| where | where | ||||||
|     F: Fn(String) -> T, |     F: Fn(String) -> T, | ||||||
| { | { | ||||||
|     let reference_id = links |     let reference_id = match response.other_fields { | ||||||
|         .and_then(|l| l.events) |         WorldpayPaymentResponseFields::AuthorizedResponse(res) => res | ||||||
|         .and_then(|e| e.href.rsplit_once('/').map(|h| h.1.to_string())) |             .links | ||||||
|         .map(transform_fn); |             .as_ref() | ||||||
|     reference_id.ok_or_else(|| { |             .and_then(|link| link.self_link.href.rsplit_once('/')) | ||||||
|         errors::ConnectorError::MissingRequiredField { |             .map(|(_, h)| urlencoding::decode(h)) | ||||||
|             field_name: "links.events", |             .transpose() | ||||||
|         } |             .change_context(errors::ConnectorError::ResponseHandlingFailed)? | ||||||
|         .into() |             .map(|s| transform_fn(s.into_owned())), | ||||||
|     }) |         WorldpayPaymentResponseFields::DDCResponse(res) => res | ||||||
|  |             .actions | ||||||
|  |             .supply_ddc_data | ||||||
|  |             .href | ||||||
|  |             .split('/') | ||||||
|  |             .rev() | ||||||
|  |             .nth(1) | ||||||
|  |             .map(urlencoding::decode) | ||||||
|  |             .transpose() | ||||||
|  |             .change_context(errors::ConnectorError::ResponseHandlingFailed)? | ||||||
|  |             .map(|s| transform_fn(s.into_owned())), | ||||||
|  |         WorldpayPaymentResponseFields::FraudHighRisk(_) => None, | ||||||
|  |         WorldpayPaymentResponseFields::RefusedResponse(_) => None, | ||||||
|  |     }; | ||||||
|  |     reference_id | ||||||
|  |         .or_else(|| connector_transaction_id.map(transform_fn)) | ||||||
|  |         .ok_or_else(|| { | ||||||
|  |             errors::ConnectorError::MissingRequiredField { | ||||||
|  |                 field_name: "_links.self.href", | ||||||
|  |             } | ||||||
|  |             .into() | ||||||
|  |         }) | ||||||
| } | } | ||||||
|  |  | ||||||
| pub struct ResponseIdStr { | pub struct ResponseIdStr { | ||||||
|     pub id: String, |     pub id: String, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl TryFrom<Option<PaymentLinks>> for ResponseIdStr { |  | ||||||
|     type Error = error_stack::Report<errors::ConnectorError>; |  | ||||||
|     fn try_from(links: Option<PaymentLinks>) -> Result<Self, Self::Error> { |  | ||||||
|         get_resource_id(links, |id| Self { id }) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl ForeignTryFrom<Option<PaymentLinks>> for types::ResponseId { |  | ||||||
|     type Error = error_stack::Report<errors::ConnectorError>; |  | ||||||
|     fn foreign_try_from(links: Option<PaymentLinks>) -> Result<Self, Self::Error> { |  | ||||||
|         get_resource_id(links, Self::ConnectorTransactionId) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] | #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] | ||||||
| #[serde(rename_all = "camelCase")] | #[serde(rename_all = "camelCase")] | ||||||
| pub struct Issuer { | pub struct Issuer { | ||||||
| @ -173,10 +260,10 @@ pub struct PaymentsResPaymentInstrument { | |||||||
|     pub payment_instrument_type: Option<String>, |     pub payment_instrument_type: Option<String>, | ||||||
|     pub card_bin: Option<String>, |     pub card_bin: Option<String>, | ||||||
|     pub last_four: Option<String>, |     pub last_four: Option<String>, | ||||||
|     pub category: Option<String>, |  | ||||||
|     pub expiry_date: Option<ExpiryDate>, |     pub expiry_date: Option<ExpiryDate>, | ||||||
|     pub card_brand: Option<String>, |     pub card_brand: Option<String>, | ||||||
|     pub funding_type: Option<String>, |     pub funding_type: Option<String>, | ||||||
|  |     pub category: Option<String>, | ||||||
|     pub issuer_name: Option<String>, |     pub issuer_name: Option<String>, | ||||||
|     pub payment_account_reference: Option<String>, |     pub payment_account_reference: Option<String>, | ||||||
| } | } | ||||||
| @ -231,7 +318,7 @@ pub enum RiskType { | |||||||
| #[derive( | #[derive( | ||||||
|     Clone, Copy, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, |     Clone, Copy, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, | ||||||
| )] | )] | ||||||
| #[serde(rename_all = "camelCase")] | #[serde(rename_all = "lowercase")] | ||||||
| pub enum Detail { | pub enum Detail { | ||||||
|     #[default] |     #[default] | ||||||
|     Address, |     Address, | ||||||
|  | |||||||
| @ -1,11 +1,11 @@ | |||||||
| use api_models::payments::Address; | use api_models::payments::Address; | ||||||
| use base64::Engine; | use base64::Engine; | ||||||
| use common_utils::{errors::CustomResult, ext_traits::OptionExt, types::MinorUnit}; | use common_utils::{errors::CustomResult, ext_traits::OptionExt, pii, types::MinorUnit}; | ||||||
| use diesel_models::enums; | use diesel_models::enums; | ||||||
| use error_stack::ResultExt; | use error_stack::ResultExt; | ||||||
| use hyperswitch_connectors::utils::RouterData; | use hyperswitch_connectors::utils::RouterData; | ||||||
| use masking::{PeekInterface, Secret}; | use masking::{ExposeInterface, PeekInterface, Secret}; | ||||||
| use serde::Serialize; | use serde::{Deserialize, Serialize}; | ||||||
|  |  | ||||||
| use super::{requests::*, response::*}; | use super::{requests::*, response::*}; | ||||||
| use crate::{ | use crate::{ | ||||||
| @ -45,53 +45,79 @@ impl<T> | |||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[derive(Debug, Default, Serialize, Deserialize)] | ||||||
|  | pub struct WorldpayConnectorMetadataObject { | ||||||
|  |     pub merchant_name: Option<Secret<String>>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl TryFrom<&Option<pii::SecretSerdeValue>> for WorldpayConnectorMetadataObject { | ||||||
|  |     type Error = error_stack::Report<errors::ConnectorError>; | ||||||
|  |     fn try_from(meta_data: &Option<pii::SecretSerdeValue>) -> Result<Self, Self::Error> { | ||||||
|  |         let metadata: Self = utils::to_connector_meta_from_secret::<Self>(meta_data.clone()) | ||||||
|  |             .change_context(errors::ConnectorError::InvalidConnectorConfig { | ||||||
|  |                 config: "metadata", | ||||||
|  |             })?; | ||||||
|  |         Ok(metadata) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| fn fetch_payment_instrument( | fn fetch_payment_instrument( | ||||||
|     payment_method: domain::PaymentMethodData, |     payment_method: domain::PaymentMethodData, | ||||||
|     billing_address: Option<&Address>, |     billing_address: Option<&Address>, | ||||||
|  |     auth_type: enums::AuthenticationType, | ||||||
| ) -> CustomResult<PaymentInstrument, errors::ConnectorError> { | ) -> CustomResult<PaymentInstrument, errors::ConnectorError> { | ||||||
|     match payment_method { |     match payment_method { | ||||||
|         domain::PaymentMethodData::Card(card) => Ok(PaymentInstrument::Card(CardPayment { |         domain::PaymentMethodData::Card(card) => { | ||||||
|             payment_type: PaymentType::Card, |             if auth_type == enums::AuthenticationType::ThreeDs { | ||||||
|             expiry_date: ExpiryDate { |                 return Err(errors::ConnectorError::NotImplemented( | ||||||
|                 month: utils::CardData::get_expiry_month_as_i8(&card)?, |                     "ThreeDS flow through worldpay".to_string(), | ||||||
|                 year: utils::CardData::get_expiry_year_as_i32(&card)?, |                 ) | ||||||
|             }, |                 .into()); | ||||||
|             card_number: card.card_number, |             } | ||||||
|             cvc: card.card_cvc, |             Ok(PaymentInstrument::Card(CardPayment { | ||||||
|             card_holder_name: card.nick_name, |                 payment_type: PaymentType::Plain, | ||||||
|             billing_address: if let Some(address) = |                 expiry_date: ExpiryDate { | ||||||
|                 billing_address.and_then(|addr| addr.address.clone()) |                     month: utils::CardData::get_expiry_month_as_i8(&card)?, | ||||||
|             { |                     year: utils::CardData::get_expiry_year_as_i32(&card)?, | ||||||
|                 Some(BillingAddress { |                 }, | ||||||
|                     address1: address.line1, |                 card_number: card.card_number, | ||||||
|                     address2: address.line2, |                 cvc: card.card_cvc, | ||||||
|                     address3: address.line3, |                 card_holder_name: card.nick_name, | ||||||
|                     city: address.city, |                 billing_address: if let Some(address) = | ||||||
|                     state: address.state, |                     billing_address.and_then(|addr| addr.address.clone()) | ||||||
|                     postal_code: address.zip.get_required_value("zip").change_context( |                 { | ||||||
|                         errors::ConnectorError::MissingRequiredField { field_name: "zip" }, |                     Some(BillingAddress { | ||||||
|                     )?, |                         address1: address.line1, | ||||||
|                     country_code: address |                         address2: address.line2, | ||||||
|                         .country |                         address3: address.line3, | ||||||
|                         .get_required_value("country_code") |                         city: address.city, | ||||||
|                         .change_context(errors::ConnectorError::MissingRequiredField { |                         state: address.state, | ||||||
|                             field_name: "country_code", |                         postal_code: address.zip.get_required_value("zip").change_context( | ||||||
|                         })?, |                             errors::ConnectorError::MissingRequiredField { field_name: "zip" }, | ||||||
|                 }) |                         )?, | ||||||
|             } else { |                         country_code: address | ||||||
|                 None |                             .country | ||||||
|             }, |                             .get_required_value("country_code") | ||||||
|         })), |                             .change_context(errors::ConnectorError::MissingRequiredField { | ||||||
|  |                                 field_name: "country_code", | ||||||
|  |                             })?, | ||||||
|  |                     }) | ||||||
|  |                 } else { | ||||||
|  |                     None | ||||||
|  |                 }, | ||||||
|  |             })) | ||||||
|  |         } | ||||||
|         domain::PaymentMethodData::Wallet(wallet) => match wallet { |         domain::PaymentMethodData::Wallet(wallet) => match wallet { | ||||||
|             domain::WalletData::GooglePay(data) => { |             domain::WalletData::GooglePay(data) => { | ||||||
|                 Ok(PaymentInstrument::Googlepay(WalletPayment { |                 Ok(PaymentInstrument::Googlepay(WalletPayment { | ||||||
|                     payment_type: PaymentType::Googlepay, |                     payment_type: PaymentType::Encrypted, | ||||||
|                     wallet_token: Secret::new(data.tokenization_data.token), |                     wallet_token: Secret::new(data.tokenization_data.token), | ||||||
|                     ..WalletPayment::default() |                     ..WalletPayment::default() | ||||||
|                 })) |                 })) | ||||||
|             } |             } | ||||||
|             domain::WalletData::ApplePay(data) => Ok(PaymentInstrument::Applepay(WalletPayment { |             domain::WalletData::ApplePay(data) => Ok(PaymentInstrument::Applepay(WalletPayment { | ||||||
|                 payment_type: PaymentType::Applepay, |                 payment_type: PaymentType::Encrypted, | ||||||
|                 wallet_token: Secret::new(data.payment_data), |                 wallet_token: Secret::new(data.payment_data), | ||||||
|                 ..WalletPayment::default() |                 ..WalletPayment::default() | ||||||
|             })), |             })), | ||||||
| @ -149,6 +175,27 @@ fn fetch_payment_instrument( | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | impl TryFrom<(enums::PaymentMethod, enums::PaymentMethodType)> for PaymentMethod { | ||||||
|  |     type Error = error_stack::Report<errors::ConnectorError>; | ||||||
|  |     fn try_from( | ||||||
|  |         src: (enums::PaymentMethod, enums::PaymentMethodType), | ||||||
|  |     ) -> Result<Self, Self::Error> { | ||||||
|  |         match (src.0, src.1) { | ||||||
|  |             (enums::PaymentMethod::Card, _) => Ok(Self::Card), | ||||||
|  |             (enums::PaymentMethod::Wallet, enums::PaymentMethodType::ApplePay) => { | ||||||
|  |                 Ok(Self::ApplePay) | ||||||
|  |             } | ||||||
|  |             (enums::PaymentMethod::Wallet, enums::PaymentMethodType::GooglePay) => { | ||||||
|  |                 Ok(Self::GooglePay) | ||||||
|  |             } | ||||||
|  |             _ => Err(errors::ConnectorError::NotImplemented( | ||||||
|  |                 utils::get_unimplemented_payment_method_error_message("worldpay"), | ||||||
|  |             ) | ||||||
|  |             .into()), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| impl | impl | ||||||
|     TryFrom<( |     TryFrom<( | ||||||
|         &WorldpayRouterData< |         &WorldpayRouterData< | ||||||
| @ -176,28 +223,44 @@ impl | |||||||
|         ), |         ), | ||||||
|     ) -> Result<Self, Self::Error> { |     ) -> Result<Self, Self::Error> { | ||||||
|         let (item, entity_id) = req; |         let (item, entity_id) = req; | ||||||
|  |         let worldpay_connector_metadata_object: WorldpayConnectorMetadataObject = | ||||||
|  |             WorldpayConnectorMetadataObject::try_from(&item.router_data.connector_meta_data)?; | ||||||
|  |         let merchant_name = worldpay_connector_metadata_object.merchant_name.ok_or( | ||||||
|  |             errors::ConnectorError::InvalidConnectorConfig { | ||||||
|  |                 config: "metadata.merchant_name", | ||||||
|  |             }, | ||||||
|  |         )?; | ||||||
|         Ok(Self { |         Ok(Self { | ||||||
|             instruction: Instruction { |             instruction: Instruction { | ||||||
|                 request_auto_settlement: RequestAutoSettlement { |                 settlement: item | ||||||
|                     enabled: item.router_data.request.capture_method |                     .router_data | ||||||
|                         == Some(enums::CaptureMethod::Automatic), |                     .request | ||||||
|  |                     .capture_method | ||||||
|  |                     .map(|capture_method| AutoSettlement { | ||||||
|  |                         auto: capture_method == enums::CaptureMethod::Automatic, | ||||||
|  |                     }), | ||||||
|  |                 method: item | ||||||
|  |                     .router_data | ||||||
|  |                     .request | ||||||
|  |                     .payment_method_type | ||||||
|  |                     .map(|pmt| PaymentMethod::try_from((item.router_data.payment_method, pmt))) | ||||||
|  |                     .transpose()? | ||||||
|  |                     .get_required_value("payment_method") | ||||||
|  |                     .change_context(errors::ConnectorError::MissingRequiredField { | ||||||
|  |                         field_name: "payment_method", | ||||||
|  |                     })?, | ||||||
|  |                 payment_instrument: fetch_payment_instrument( | ||||||
|  |                     item.router_data.request.payment_method_data.clone(), | ||||||
|  |                     item.router_data.get_optional_billing(), | ||||||
|  |                     item.router_data.auth_type, | ||||||
|  |                 )?, | ||||||
|  |                 narrative: InstructionNarrative { | ||||||
|  |                     line1: merchant_name.expose(), | ||||||
|                 }, |                 }, | ||||||
|                 value: PaymentValue { |                 value: PaymentValue { | ||||||
|                     amount: item.amount, |                     amount: item.amount, | ||||||
|                     currency: item.router_data.request.currency, |                     currency: item.router_data.request.currency, | ||||||
|                 }, |                 }, | ||||||
|                 narrative: InstructionNarrative { |  | ||||||
|                     line1: item |  | ||||||
|                         .router_data |  | ||||||
|                         .merchant_id |  | ||||||
|                         .get_string_repr() |  | ||||||
|                         .replace('_', "-"), |  | ||||||
|                     ..Default::default() |  | ||||||
|                 }, |  | ||||||
|                 payment_instrument: fetch_payment_instrument( |  | ||||||
|                     item.router_data.request.payment_method_data.clone(), |  | ||||||
|                     item.router_data.get_optional_billing(), |  | ||||||
|                 )?, |  | ||||||
|                 debt_repayment: None, |                 debt_repayment: None, | ||||||
|             }, |             }, | ||||||
|             merchant: Merchant { |             merchant: Merchant { | ||||||
| @ -205,7 +268,6 @@ impl | |||||||
|                 ..Default::default() |                 ..Default::default() | ||||||
|             }, |             }, | ||||||
|             transaction_reference: item.router_data.connector_request_reference_id.clone(), |             transaction_reference: item.router_data.connector_request_reference_id.clone(), | ||||||
|             channel: Channel::Ecom, |  | ||||||
|             customer: None, |             customer: None, | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| @ -250,9 +312,15 @@ impl From<PaymentOutcome> for enums::AttemptStatus { | |||||||
|     fn from(item: PaymentOutcome) -> Self { |     fn from(item: PaymentOutcome) -> Self { | ||||||
|         match item { |         match item { | ||||||
|             PaymentOutcome::Authorized => Self::Authorized, |             PaymentOutcome::Authorized => Self::Authorized, | ||||||
|             PaymentOutcome::Refused => Self::Failure, |  | ||||||
|             PaymentOutcome::SentForSettlement => Self::CaptureInitiated, |             PaymentOutcome::SentForSettlement => Self::CaptureInitiated, | ||||||
|             PaymentOutcome::SentForRefund => Self::AutoRefunded, |             PaymentOutcome::ThreeDsDeviceDataRequired => Self::DeviceDataCollectionPending, | ||||||
|  |             PaymentOutcome::ThreeDsAuthenticationFailed => Self::AuthenticationFailed, | ||||||
|  |             PaymentOutcome::ThreeDsChallenged => Self::AuthenticationPending, | ||||||
|  |             PaymentOutcome::SentForCancellation => Self::VoidInitiated, | ||||||
|  |             PaymentOutcome::SentForPartialRefund | PaymentOutcome::SentForRefund => { | ||||||
|  |                 Self::AutoRefunded | ||||||
|  |             } | ||||||
|  |             PaymentOutcome::Refused | PaymentOutcome::FraudHighRisk => Self::Failure, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -295,32 +363,43 @@ impl From<EventType> for enums::RefundStatus { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl TryFrom<types::PaymentsResponseRouterData<WorldpayPaymentsResponse>> | impl | ||||||
|     for types::PaymentsAuthorizeRouterData |     ForeignTryFrom<( | ||||||
|  |         types::PaymentsResponseRouterData<WorldpayPaymentsResponse>, | ||||||
|  |         Option<String>, | ||||||
|  |     )> for types::PaymentsAuthorizeRouterData | ||||||
| { | { | ||||||
|     type Error = error_stack::Report<errors::ConnectorError>; |     type Error = error_stack::Report<errors::ConnectorError>; | ||||||
|     fn try_from( |     fn foreign_try_from( | ||||||
|         item: types::PaymentsResponseRouterData<WorldpayPaymentsResponse>, |         item: ( | ||||||
|  |             types::PaymentsResponseRouterData<WorldpayPaymentsResponse>, | ||||||
|  |             Option<String>, | ||||||
|  |         ), | ||||||
|     ) -> Result<Self, Self::Error> { |     ) -> Result<Self, Self::Error> { | ||||||
|  |         let (router_data, optional_correlation_id) = item; | ||||||
|  |         let description = match router_data.response.other_fields { | ||||||
|  |             WorldpayPaymentResponseFields::AuthorizedResponse(ref res) => res.description.clone(), | ||||||
|  |             WorldpayPaymentResponseFields::DDCResponse(_) | ||||||
|  |             | WorldpayPaymentResponseFields::FraudHighRisk(_) | ||||||
|  |             | WorldpayPaymentResponseFields::RefusedResponse(_) => None, | ||||||
|  |         }; | ||||||
|         Ok(Self { |         Ok(Self { | ||||||
|             status: match item.response.outcome { |             status: enums::AttemptStatus::from(router_data.response.outcome.clone()), | ||||||
|                 Some(outcome) => enums::AttemptStatus::from(outcome), |             description, | ||||||
|                 None => Err(errors::ConnectorError::MissingRequiredField { |  | ||||||
|                     field_name: "outcome", |  | ||||||
|                 })?, |  | ||||||
|             }, |  | ||||||
|             description: item.response.description, |  | ||||||
|             response: Ok(PaymentsResponseData::TransactionResponse { |             response: Ok(PaymentsResponseData::TransactionResponse { | ||||||
|                 resource_id: types::ResponseId::foreign_try_from(item.response.links)?, |                 resource_id: types::ResponseId::foreign_try_from(( | ||||||
|  |                     router_data.response, | ||||||
|  |                     optional_correlation_id.clone(), | ||||||
|  |                 ))?, | ||||||
|                 redirection_data: None, |                 redirection_data: None, | ||||||
|                 mandate_reference: None, |                 mandate_reference: None, | ||||||
|                 connector_metadata: None, |                 connector_metadata: None, | ||||||
|                 network_txn_id: None, |                 network_txn_id: None, | ||||||
|                 connector_response_reference_id: None, |                 connector_response_reference_id: optional_correlation_id, | ||||||
|                 incremental_authorization_allowed: None, |                 incremental_authorization_allowed: None, | ||||||
|                 charge_id: None, |                 charge_id: None, | ||||||
|             }), |             }), | ||||||
|             ..item.data |             ..router_data.data | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -362,3 +441,21 @@ impl TryFrom<WorldpayWebhookEventType> for WorldpayEventResponse { | |||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | impl ForeignTryFrom<(WorldpayPaymentsResponse, Option<String>)> for ResponseIdStr { | ||||||
|  |     type Error = error_stack::Report<errors::ConnectorError>; | ||||||
|  |     fn foreign_try_from( | ||||||
|  |         item: (WorldpayPaymentsResponse, Option<String>), | ||||||
|  |     ) -> Result<Self, Self::Error> { | ||||||
|  |         get_resource_id(item.0, item.1, |id| Self { id }) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl ForeignTryFrom<(WorldpayPaymentsResponse, Option<String>)> for types::ResponseId { | ||||||
|  |     type Error = error_stack::Report<errors::ConnectorError>; | ||||||
|  |     fn foreign_try_from( | ||||||
|  |         item: (WorldpayPaymentsResponse, Option<String>), | ||||||
|  |     ) -> Result<Self, Self::Error> { | ||||||
|  |         get_resource_id(item.0, item.1, Self::ConnectorTransactionId) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
| @ -177,3 +177,6 @@ pub const VAULT_DELETE_FLOW_TYPE: &str = "delete_from_vault"; | |||||||
| /// Vault Fingerprint fetch flow type | /// Vault Fingerprint fetch flow type | ||||||
| #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] | #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] | ||||||
| pub const VAULT_GET_FINGERPRINT_FLOW_TYPE: &str = "get_fingerprint_vault"; | pub const VAULT_GET_FINGERPRINT_FLOW_TYPE: &str = "get_fingerprint_vault"; | ||||||
|  |  | ||||||
|  | /// Worldpay's unique reference ID for a request TODO: Move to hyperswitch_connectors/constants once Worldpay is moved to connectors crate | ||||||
|  | pub const WP_CORRELATION_ID: &str = "WP-CorrelationId"; | ||||||
|  | |||||||
| @ -87,6 +87,7 @@ pub mod headers { | |||||||
|     pub const X_APP_ID: &str = "x-app-id"; |     pub const X_APP_ID: &str = "x-app-id"; | ||||||
|     pub const X_REDIRECT_URI: &str = "x-redirect-uri"; |     pub const X_REDIRECT_URI: &str = "x-redirect-uri"; | ||||||
|     pub const X_TENANT_ID: &str = "x-tenant-id"; |     pub const X_TENANT_ID: &str = "x-tenant-id"; | ||||||
|  |     pub const X_WP_API_VERSION: &str = "WP-Api-Version"; | ||||||
| } | } | ||||||
|  |  | ||||||
| pub mod pii { | pub mod pii { | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Kashif
					Kashif