mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-11-01 02:57:02 +08:00 
			
		
		
		
	feat(router): added incoming refund webhooks flow (#683)
Co-authored-by: sai harsha <sai.harsha@sai.harsha-MacBookPro>
This commit is contained in:
		| @ -264,6 +264,8 @@ pub enum Currency { | |||||||
| #[strum(serialize_all = "snake_case")] | #[strum(serialize_all = "snake_case")] | ||||||
| pub enum EventType { | pub enum EventType { | ||||||
|     PaymentSucceeded, |     PaymentSucceeded, | ||||||
|  |     RefundSucceeded, | ||||||
|  |     RefundFailed, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive( | #[derive( | ||||||
|  | |||||||
| @ -2,13 +2,15 @@ use common_utils::custom_serde; | |||||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||||
| use time::PrimitiveDateTime; | use time::PrimitiveDateTime; | ||||||
|  |  | ||||||
| use crate::{enums as api_enums, payments}; | use crate::{enums as api_enums, payments, refunds}; | ||||||
|  |  | ||||||
| #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] | #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] | ||||||
| #[serde(rename_all = "snake_case")] | #[serde(rename_all = "snake_case")] | ||||||
| pub enum IncomingWebhookEvent { | pub enum IncomingWebhookEvent { | ||||||
|     PaymentIntentFailure, |     PaymentIntentFailure, | ||||||
|     PaymentIntentSuccess, |     PaymentIntentSuccess, | ||||||
|  |     RefundFailure, | ||||||
|  |     RefundSuccess, | ||||||
|     EndpointVerification, |     EndpointVerification, | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -24,6 +26,8 @@ impl From<IncomingWebhookEvent> for WebhookFlow { | |||||||
|         match evt { |         match evt { | ||||||
|             IncomingWebhookEvent::PaymentIntentFailure => Self::Payment, |             IncomingWebhookEvent::PaymentIntentFailure => Self::Payment, | ||||||
|             IncomingWebhookEvent::PaymentIntentSuccess => Self::Payment, |             IncomingWebhookEvent::PaymentIntentSuccess => Self::Payment, | ||||||
|  |             IncomingWebhookEvent::RefundSuccess => Self::Refund, | ||||||
|  |             IncomingWebhookEvent::RefundFailure => Self::Refund, | ||||||
|             IncomingWebhookEvent::EndpointVerification => Self::ReturnResponse, |             IncomingWebhookEvent::EndpointVerification => Self::ReturnResponse, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -56,4 +60,5 @@ pub struct OutgoingWebhook { | |||||||
| #[serde(tag = "type", content = "object", rename_all = "snake_case")] | #[serde(tag = "type", content = "object", rename_all = "snake_case")] | ||||||
| pub enum OutgoingWebhookContent { | pub enum OutgoingWebhookContent { | ||||||
|     PaymentDetails(payments::PaymentsResponse), |     PaymentDetails(payments::PaymentsResponse), | ||||||
|  |     RefundDetails(refunds::RefundResponse), | ||||||
| } | } | ||||||
|  | |||||||
| @ -733,11 +733,7 @@ impl api::IncomingWebhook for Adyen { | |||||||
|     ) -> CustomResult<api::IncomingWebhookEvent, errors::ConnectorError> { |     ) -> CustomResult<api::IncomingWebhookEvent, errors::ConnectorError> { | ||||||
|         let notif = get_webhook_object_from_body(request.body) |         let notif = get_webhook_object_from_body(request.body) | ||||||
|             .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?; |             .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?; | ||||||
|  |         Ok(notif.event_code.into()) | ||||||
|         Ok(match notif.event_code.as_str() { |  | ||||||
|             "AUTHORISATION" => api::IncomingWebhookEvent::PaymentIntentSuccess, |  | ||||||
|             _ => Err(errors::ConnectorError::WebhookEventTypeNotFound).into_report()?, |  | ||||||
|         }) |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn get_webhook_resource_object( |     fn get_webhook_resource_object( | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | use api_models::webhooks::IncomingWebhookEvent; | ||||||
| use base64::Engine; | use base64::Engine; | ||||||
| use error_stack::ResultExt; | use error_stack::ResultExt; | ||||||
| use masking::PeekInterface; | use masking::PeekInterface; | ||||||
| @ -1168,6 +1169,27 @@ pub struct AdyenAmountWH { | |||||||
|     pub currency: String, |     pub currency: String, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[derive(Debug, Deserialize, strum::Display)] | ||||||
|  | #[serde(rename_all = "SCREAMING_SNAKE_CASE")] | ||||||
|  | #[strum(serialize_all = "SCREAMING_SNAKE_CASE")] | ||||||
|  | pub enum WebhookEventCode { | ||||||
|  |     Authorisation, | ||||||
|  |     Refund, | ||||||
|  |     CancelOrRefund, | ||||||
|  |     RefundFailed, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl From<WebhookEventCode> for IncomingWebhookEvent { | ||||||
|  |     fn from(code: WebhookEventCode) -> Self { | ||||||
|  |         match code { | ||||||
|  |             WebhookEventCode::Authorisation => Self::PaymentIntentSuccess, | ||||||
|  |             WebhookEventCode::Refund => Self::RefundSuccess, | ||||||
|  |             WebhookEventCode::CancelOrRefund => Self::RefundSuccess, | ||||||
|  |             WebhookEventCode::RefundFailed => Self::RefundFailure, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| #[derive(Debug, Deserialize)] | #[derive(Debug, Deserialize)] | ||||||
| #[serde(rename_all = "camelCase")] | #[serde(rename_all = "camelCase")] | ||||||
| pub struct AdyenNotificationRequestItemWH { | pub struct AdyenNotificationRequestItemWH { | ||||||
| @ -1175,7 +1197,7 @@ pub struct AdyenNotificationRequestItemWH { | |||||||
|     pub amount: AdyenAmountWH, |     pub amount: AdyenAmountWH, | ||||||
|     pub original_reference: Option<String>, |     pub original_reference: Option<String>, | ||||||
|     pub psp_reference: String, |     pub psp_reference: String, | ||||||
|     pub event_code: String, |     pub event_code: WebhookEventCode, | ||||||
|     pub merchant_account_code: String, |     pub merchant_account_code: String, | ||||||
|     pub merchant_reference: String, |     pub merchant_reference: String, | ||||||
|     pub success: String, |     pub success: String, | ||||||
|  | |||||||
| @ -400,6 +400,8 @@ pub enum WebhooksFlowError { | |||||||
|     MerchantWebhookURLNotConfigured, |     MerchantWebhookURLNotConfigured, | ||||||
|     #[error("Payments core flow failed")] |     #[error("Payments core flow failed")] | ||||||
|     PaymentsCoreFailed, |     PaymentsCoreFailed, | ||||||
|  |     #[error("Refunds core flow failed")] | ||||||
|  |     RefundsCoreFailed, | ||||||
|     #[error("Webhook event creation failed")] |     #[error("Webhook event creation failed")] | ||||||
|     WebhookEventCreationFailed, |     WebhookEventCreationFailed, | ||||||
|     #[error("Unable to fork webhooks flow for outgoing webhooks")] |     #[error("Unable to fork webhooks flow for outgoing webhooks")] | ||||||
| @ -408,6 +410,8 @@ pub enum WebhooksFlowError { | |||||||
|     CallToMerchantFailed, |     CallToMerchantFailed, | ||||||
|     #[error("Webhook not received by merchant")] |     #[error("Webhook not received by merchant")] | ||||||
|     NotReceivedByMerchant, |     NotReceivedByMerchant, | ||||||
|  |     #[error("Resource not found")] | ||||||
|  |     ResourceNotFound, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Debug, thiserror::Error)] | #[derive(Debug, thiserror::Error)] | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ use crate::{ | |||||||
|     consts, |     consts, | ||||||
|     core::{ |     core::{ | ||||||
|         errors::{self, CustomResult, RouterResponse}, |         errors::{self, CustomResult, RouterResponse}, | ||||||
|         payments, |         payments, refunds, | ||||||
|     }, |     }, | ||||||
|     db::StorageInterface, |     db::StorageInterface, | ||||||
|     logger, |     logger, | ||||||
| @ -90,6 +90,87 @@ async fn payments_incoming_webhook_flow( | |||||||
|     Ok(()) |     Ok(()) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[instrument(skip_all)] | ||||||
|  | async fn refunds_incoming_webhook_flow( | ||||||
|  |     state: AppState, | ||||||
|  |     merchant_account: storage::MerchantAccount, | ||||||
|  |     webhook_details: api::IncomingWebhookDetails, | ||||||
|  |     connector_name: &str, | ||||||
|  |     source_verified: bool, | ||||||
|  |     event_type: api_models::webhooks::IncomingWebhookEvent, | ||||||
|  | ) -> CustomResult<(), errors::WebhooksFlowError> { | ||||||
|  |     let db = &*state.store; | ||||||
|  |     //find refund by connector refund id | ||||||
|  |     let refund = db | ||||||
|  |         .find_refund_by_merchant_id_connector_refund_id_connector( | ||||||
|  |             &merchant_account.merchant_id, | ||||||
|  |             &webhook_details.object_reference_id, | ||||||
|  |             connector_name, | ||||||
|  |             merchant_account.storage_scheme, | ||||||
|  |         ) | ||||||
|  |         .await | ||||||
|  |         .change_context(errors::WebhooksFlowError::ResourceNotFound) | ||||||
|  |         .attach_printable_lazy(|| "Failed fetching the refund")?; | ||||||
|  |     let refund_id = refund.refund_id.to_owned(); | ||||||
|  |     //if source verified then update refund status else trigger refund sync | ||||||
|  |     let updated_refund = if source_verified { | ||||||
|  |         let refund_update = storage::RefundUpdate::StatusUpdate { | ||||||
|  |             connector_refund_id: None, | ||||||
|  |             sent_to_gateway: true, | ||||||
|  |             refund_status: event_type | ||||||
|  |                 .foreign_try_into() | ||||||
|  |                 .into_report() | ||||||
|  |                 .change_context(errors::WebhooksFlowError::RefundsCoreFailed)?, | ||||||
|  |         }; | ||||||
|  |         state | ||||||
|  |             .store | ||||||
|  |             .update_refund( | ||||||
|  |                 refund.to_owned(), | ||||||
|  |                 refund_update, | ||||||
|  |                 merchant_account.storage_scheme, | ||||||
|  |             ) | ||||||
|  |             .await | ||||||
|  |             .change_context(errors::WebhooksFlowError::RefundsCoreFailed) | ||||||
|  |             .attach_printable_lazy(|| { | ||||||
|  |                 format!( | ||||||
|  |                     "Failed while updating refund: refund_id: {}", | ||||||
|  |                     refund_id.to_owned() | ||||||
|  |                 ) | ||||||
|  |             })? | ||||||
|  |     } else { | ||||||
|  |         refunds::refund_retrieve_core(&state, merchant_account.clone(), refund_id.to_owned()) | ||||||
|  |             .await | ||||||
|  |             .change_context(errors::WebhooksFlowError::RefundsCoreFailed) | ||||||
|  |             .attach_printable_lazy(|| { | ||||||
|  |                 format!( | ||||||
|  |                     "Failed while updating refund: refund_id: {}", | ||||||
|  |                     refund_id.to_owned() | ||||||
|  |                 ) | ||||||
|  |             })? | ||||||
|  |     }; | ||||||
|  |     let event_type: enums::EventType = updated_refund | ||||||
|  |         .refund_status | ||||||
|  |         .foreign_try_into() | ||||||
|  |         .into_report() | ||||||
|  |         .change_context(errors::WebhooksFlowError::RefundsCoreFailed)?; | ||||||
|  |     let refund_response: api_models::refunds::RefundResponse = updated_refund | ||||||
|  |         .foreign_try_into() | ||||||
|  |         .into_report() | ||||||
|  |         .change_context(errors::WebhooksFlowError::RefundsCoreFailed)?; | ||||||
|  |     create_event_and_trigger_outgoing_webhook( | ||||||
|  |         state, | ||||||
|  |         merchant_account, | ||||||
|  |         event_type, | ||||||
|  |         enums::EventClass::Refunds, | ||||||
|  |         None, | ||||||
|  |         refund_id, | ||||||
|  |         enums::EventObjectType::RefundDetails, | ||||||
|  |         api::OutgoingWebhookContent::RefundDetails(refund_response), | ||||||
|  |     ) | ||||||
|  |     .await?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  |  | ||||||
| #[allow(clippy::too_many_arguments)] | #[allow(clippy::too_many_arguments)] | ||||||
| #[instrument(skip_all)] | #[instrument(skip_all)] | ||||||
| async fn create_event_and_trigger_outgoing_webhook( | async fn create_event_and_trigger_outgoing_webhook( | ||||||
| @ -272,7 +353,7 @@ pub async fn webhooks_core( | |||||||
|                 )?, |                 )?, | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         let flow_type: api::WebhookFlow = event_type.into(); |         let flow_type: api::WebhookFlow = event_type.to_owned().into(); | ||||||
|         match flow_type { |         match flow_type { | ||||||
|             api::WebhookFlow::Payment => payments_incoming_webhook_flow( |             api::WebhookFlow::Payment => payments_incoming_webhook_flow( | ||||||
|                 state.clone(), |                 state.clone(), | ||||||
| @ -284,6 +365,18 @@ pub async fn webhooks_core( | |||||||
|             .change_context(errors::ApiErrorResponse::InternalServerError) |             .change_context(errors::ApiErrorResponse::InternalServerError) | ||||||
|             .attach_printable("Incoming webhook flow for payments failed")?, |             .attach_printable("Incoming webhook flow for payments failed")?, | ||||||
|  |  | ||||||
|  |             api::WebhookFlow::Refund => refunds_incoming_webhook_flow( | ||||||
|  |                 state.clone(), | ||||||
|  |                 merchant_account, | ||||||
|  |                 webhook_details, | ||||||
|  |                 connector_name, | ||||||
|  |                 source_verified, | ||||||
|  |                 event_type, | ||||||
|  |             ) | ||||||
|  |             .await | ||||||
|  |             .change_context(errors::ApiErrorResponse::InternalServerError) | ||||||
|  |             .attach_printable("Incoming webhook flow for refunds failed")?, | ||||||
|  |  | ||||||
|             api::WebhookFlow::ReturnResponse => {} |             api::WebhookFlow::ReturnResponse => {} | ||||||
|  |  | ||||||
|             _ => Err(errors::ApiErrorResponse::InternalServerError) |             _ => Err(errors::ApiErrorResponse::InternalServerError) | ||||||
|  | |||||||
| @ -36,6 +36,14 @@ pub trait RefundInterface { | |||||||
|         storage_scheme: enums::MerchantStorageScheme, |         storage_scheme: enums::MerchantStorageScheme, | ||||||
|     ) -> CustomResult<storage_types::Refund, errors::StorageError>; |     ) -> CustomResult<storage_types::Refund, errors::StorageError>; | ||||||
|  |  | ||||||
|  |     async fn find_refund_by_merchant_id_connector_refund_id_connector( | ||||||
|  |         &self, | ||||||
|  |         merchant_id: &str, | ||||||
|  |         connector_refund_id: &str, | ||||||
|  |         connector: &str, | ||||||
|  |         storage_scheme: enums::MerchantStorageScheme, | ||||||
|  |     ) -> CustomResult<storage_types::Refund, errors::StorageError>; | ||||||
|  |  | ||||||
|     async fn update_refund( |     async fn update_refund( | ||||||
|         &self, |         &self, | ||||||
|         this: storage_types::Refund, |         this: storage_types::Refund, | ||||||
| @ -149,6 +157,25 @@ mod storage { | |||||||
|                 .into_report() |                 .into_report() | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         async fn find_refund_by_merchant_id_connector_refund_id_connector( | ||||||
|  |             &self, | ||||||
|  |             merchant_id: &str, | ||||||
|  |             connector_refund_id: &str, | ||||||
|  |             connector: &str, | ||||||
|  |             _storage_scheme: enums::MerchantStorageScheme, | ||||||
|  |         ) -> CustomResult<storage_types::Refund, errors::StorageError> { | ||||||
|  |             let conn = pg_connection(&self.master_pool).await?; | ||||||
|  |             storage_types::Refund::find_by_merchant_id_connector_refund_id_connector( | ||||||
|  |                 &conn, | ||||||
|  |                 merchant_id, | ||||||
|  |                 connector_refund_id, | ||||||
|  |                 connector, | ||||||
|  |             ) | ||||||
|  |             .await | ||||||
|  |             .map_err(Into::into) | ||||||
|  |             .into_report() | ||||||
|  |         } | ||||||
|  |  | ||||||
|         // async fn find_refund_by_payment_id_merchant_id_refund_id( |         // async fn find_refund_by_payment_id_merchant_id_refund_id( | ||||||
|         //     &self, |         //     &self, | ||||||
|         //     payment_id: &str, |         //     payment_id: &str, | ||||||
| @ -311,7 +338,7 @@ mod storage { | |||||||
|                         Ok(HsetnxReply::KeySet) => { |                         Ok(HsetnxReply::KeySet) => { | ||||||
|                             let conn = pg_connection(&self.master_pool).await?; |                             let conn = pg_connection(&self.master_pool).await?; | ||||||
|  |  | ||||||
|                             let reverse_lookups = vec![ |                             let mut reverse_lookups = vec![ | ||||||
|                                 storage_types::ReverseLookupNew { |                                 storage_types::ReverseLookupNew { | ||||||
|                                     sk_id: field.clone(), |                                     sk_id: field.clone(), | ||||||
|                                     lookup_id: format!( |                                     lookup_id: format!( | ||||||
| @ -329,10 +356,25 @@ mod storage { | |||||||
|                                         created_refund.merchant_id, |                                         created_refund.merchant_id, | ||||||
|                                         created_refund.internal_reference_id |                                         created_refund.internal_reference_id | ||||||
|                                     ), |                                     ), | ||||||
|                                     pk_id: key, |                                     pk_id: key.clone(), | ||||||
|                                     source: "refund".to_string(), |                                     source: "refund".to_string(), | ||||||
|                                 }, |                                 }, | ||||||
|                             ]; |                             ]; | ||||||
|  |                             if let Some(connector_refund_id) = | ||||||
|  |                                 created_refund.to_owned().connector_refund_id | ||||||
|  |                             { | ||||||
|  |                                 reverse_lookups.push(storage_types::ReverseLookupNew { | ||||||
|  |                                     sk_id: field.clone(), | ||||||
|  |                                     lookup_id: format!( | ||||||
|  |                                         "{}_{}_{}", | ||||||
|  |                                         created_refund.merchant_id, | ||||||
|  |                                         connector_refund_id, | ||||||
|  |                                         created_refund.connector | ||||||
|  |                                     ), | ||||||
|  |                                     pk_id: key, | ||||||
|  |                                     source: "refund".to_string(), | ||||||
|  |                                 }) | ||||||
|  |                             }; | ||||||
|                             storage_types::ReverseLookupNew::batch_insert(reverse_lookups, &conn) |                             storage_types::ReverseLookupNew::batch_insert(reverse_lookups, &conn) | ||||||
|                                 .await |                                 .await | ||||||
|                                 .change_context(errors::StorageError::KVError)?; |                                 .change_context(errors::StorageError::KVError)?; | ||||||
| @ -495,6 +537,47 @@ mod storage { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         async fn find_refund_by_merchant_id_connector_refund_id_connector( | ||||||
|  |             &self, | ||||||
|  |             merchant_id: &str, | ||||||
|  |             connector_refund_id: &str, | ||||||
|  |             connector: &str, | ||||||
|  |             storage_scheme: enums::MerchantStorageScheme, | ||||||
|  |         ) -> CustomResult<storage_types::Refund, errors::StorageError> { | ||||||
|  |             let database_call = || async { | ||||||
|  |                 let conn = pg_connection(&self.master_pool).await?; | ||||||
|  |                 storage_types::Refund::find_by_merchant_id_connector_refund_id_connector( | ||||||
|  |                     &conn, | ||||||
|  |                     merchant_id, | ||||||
|  |                     connector_refund_id, | ||||||
|  |                     connector, | ||||||
|  |                 ) | ||||||
|  |                 .await | ||||||
|  |                 .map_err(Into::into) | ||||||
|  |                 .into_report() | ||||||
|  |             }; | ||||||
|  |             match storage_scheme { | ||||||
|  |                 enums::MerchantStorageScheme::PostgresOnly => database_call().await, | ||||||
|  |                 enums::MerchantStorageScheme::RedisKv => { | ||||||
|  |                     let lookup_id = format!("{merchant_id}_{connector_refund_id}_{connector}"); | ||||||
|  |                     let lookup = self | ||||||
|  |                         .get_lookup_by_lookup_id(&lookup_id) | ||||||
|  |                         .await | ||||||
|  |                         .map_err(Into::<errors::StorageError>::into) | ||||||
|  |                         .into_report()?; | ||||||
|  |  | ||||||
|  |                     let key = &lookup.pk_id; | ||||||
|  |                     db_utils::try_redis_get_else_try_database_get( | ||||||
|  |                         self.redis_conn() | ||||||
|  |                             .map_err(Into::<errors::StorageError>::into)? | ||||||
|  |                             .get_hash_field_and_deserialize(key, &lookup.sk_id, "Refund"), | ||||||
|  |                         database_call, | ||||||
|  |                     ) | ||||||
|  |                     .await | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|         // async fn find_refund_by_payment_id_merchant_id_refund_id( |         // async fn find_refund_by_payment_id_merchant_id_refund_id( | ||||||
|         //     &self, |         //     &self, | ||||||
|         //     payment_id: &str, |         //     payment_id: &str, | ||||||
| @ -661,6 +744,28 @@ impl RefundInterface for MockDb { | |||||||
|             }) |             }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     async fn find_refund_by_merchant_id_connector_refund_id_connector( | ||||||
|  |         &self, | ||||||
|  |         merchant_id: &str, | ||||||
|  |         connector_refund_id: &str, | ||||||
|  |         connector: &str, | ||||||
|  |         _storage_scheme: enums::MerchantStorageScheme, | ||||||
|  |     ) -> CustomResult<storage_types::Refund, errors::StorageError> { | ||||||
|  |         let refunds = self.refunds.lock().await; | ||||||
|  |  | ||||||
|  |         refunds | ||||||
|  |             .iter() | ||||||
|  |             .find(|refund| { | ||||||
|  |                 refund.merchant_id == merchant_id | ||||||
|  |                     && refund.connector_refund_id == Some(connector_refund_id.to_string()) | ||||||
|  |                     && refund.connector == connector | ||||||
|  |             }) | ||||||
|  |             .cloned() | ||||||
|  |             .ok_or_else(|| { | ||||||
|  |                 errors::StorageError::DatabaseError(DatabaseError::NotFound.into()).into() | ||||||
|  |             }) | ||||||
|  |     } | ||||||
|  |  | ||||||
|     async fn find_refund_by_payment_id_merchant_id( |     async fn find_refund_by_payment_id_merchant_id( | ||||||
|         &self, |         &self, | ||||||
|         _payment_id: &str, |         _payment_id: &str, | ||||||
|  | |||||||
| @ -214,6 +214,40 @@ impl TryFrom<F<api_enums::IntentStatus>> for F<storage_enums::EventType> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | impl TryFrom<F<storage_enums::RefundStatus>> for F<storage_enums::EventType> { | ||||||
|  |     type Error = errors::ValidationError; | ||||||
|  |  | ||||||
|  |     fn try_from(value: F<storage_enums::RefundStatus>) -> Result<Self, Self::Error> { | ||||||
|  |         match value.0 { | ||||||
|  |             storage_enums::RefundStatus::Success => Ok(storage_enums::EventType::RefundSucceeded), | ||||||
|  |             storage_enums::RefundStatus::Failure => Ok(storage_enums::EventType::RefundFailed), | ||||||
|  |             _ => Err(errors::ValidationError::IncorrectValueProvided { | ||||||
|  |                 field_name: "refund_status", | ||||||
|  |             }), | ||||||
|  |         } | ||||||
|  |         .map(Into::into) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl TryFrom<F<api_models::webhooks::IncomingWebhookEvent>> for F<storage_enums::RefundStatus> { | ||||||
|  |     type Error = errors::ValidationError; | ||||||
|  |  | ||||||
|  |     fn try_from(value: F<api_models::webhooks::IncomingWebhookEvent>) -> Result<Self, Self::Error> { | ||||||
|  |         match value.0 { | ||||||
|  |             api_models::webhooks::IncomingWebhookEvent::RefundSuccess => { | ||||||
|  |                 Ok(storage_enums::RefundStatus::Success) | ||||||
|  |             } | ||||||
|  |             api_models::webhooks::IncomingWebhookEvent::RefundFailure => { | ||||||
|  |                 Ok(storage_enums::RefundStatus::Failure) | ||||||
|  |             } | ||||||
|  |             _ => Err(errors::ValidationError::IncorrectValueProvided { | ||||||
|  |                 field_name: "incoming_webhook_event_type", | ||||||
|  |             }), | ||||||
|  |         } | ||||||
|  |         .map(Into::into) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| impl From<F<storage_enums::EventType>> for F<api_enums::EventType> { | impl From<F<storage_enums::EventType>> for F<api_enums::EventType> { | ||||||
|     fn from(event_type: F<storage_enums::EventType>) -> Self { |     fn from(event_type: F<storage_enums::EventType>) -> Self { | ||||||
|         Self(frunk::labelled_convert_from(event_type.0)) |         Self(frunk::labelled_convert_from(event_type.0)) | ||||||
|  | |||||||
| @ -272,6 +272,7 @@ pub enum Currency { | |||||||
| #[strum(serialize_all = "snake_case")] | #[strum(serialize_all = "snake_case")] | ||||||
| pub enum EventClass { | pub enum EventClass { | ||||||
|     Payments, |     Payments, | ||||||
|  |     Refunds, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive( | #[derive( | ||||||
| @ -290,6 +291,7 @@ pub enum EventClass { | |||||||
| #[strum(serialize_all = "snake_case")] | #[strum(serialize_all = "snake_case")] | ||||||
| pub enum EventObjectType { | pub enum EventObjectType { | ||||||
|     PaymentDetails, |     PaymentDetails, | ||||||
|  |     RefundDetails, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive( | #[derive( | ||||||
| @ -309,6 +311,8 @@ pub enum EventObjectType { | |||||||
| #[strum(serialize_all = "snake_case")] | #[strum(serialize_all = "snake_case")] | ||||||
| pub enum EventType { | pub enum EventType { | ||||||
|     PaymentSucceeded, |     PaymentSucceeded, | ||||||
|  |     RefundSucceeded, | ||||||
|  |     RefundFailed, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive( | #[derive( | ||||||
|  | |||||||
| @ -57,6 +57,23 @@ impl Refund { | |||||||
|         .await |         .await | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     #[instrument(skip(conn))] | ||||||
|  |     pub async fn find_by_merchant_id_connector_refund_id_connector( | ||||||
|  |         conn: &PgPooledConn, | ||||||
|  |         merchant_id: &str, | ||||||
|  |         connector_refund_id: &str, | ||||||
|  |         connector: &str, | ||||||
|  |     ) -> StorageResult<Self> { | ||||||
|  |         generics::generic_find_one::<<Self as HasTable>::Table, _, _>( | ||||||
|  |             conn, | ||||||
|  |             dsl::merchant_id | ||||||
|  |                 .eq(merchant_id.to_owned()) | ||||||
|  |                 .and(dsl::connector_refund_id.eq(connector_refund_id.to_owned())) | ||||||
|  |                 .and(dsl::connector.eq(connector.to_owned())), | ||||||
|  |         ) | ||||||
|  |         .await | ||||||
|  |     } | ||||||
|  |  | ||||||
|     #[instrument(skip(conn))] |     #[instrument(skip(conn))] | ||||||
|     pub async fn find_by_internal_reference_id_merchant_id( |     pub async fn find_by_internal_reference_id_merchant_id( | ||||||
|         conn: &PgPooledConn, |         conn: &PgPooledConn, | ||||||
|  | |||||||
| @ -0,0 +1 @@ | |||||||
|  | -- This file should undo anything in `up.sql` | ||||||
| @ -0,0 +1,8 @@ | |||||||
|  | -- Your SQL goes here | ||||||
|  | ALTER TYPE "EventClass" ADD VALUE 'refunds'; | ||||||
|  |  | ||||||
|  | ALTER TYPE "EventObjectType" ADD VALUE 'refund_details'; | ||||||
|  |  | ||||||
|  | ALTER TYPE "EventType" ADD VALUE 'refund_succeeded'; | ||||||
|  |  | ||||||
|  | ALTER TYPE "EventType" ADD VALUE 'refund_failed'; | ||||||
		Reference in New Issue
	
	Block a user
	 saiharsha-juspay
					saiharsha-juspay