mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-10-31 18:17:13 +08:00 
			
		
		
		
	feat(router): add refunds manual-update api (#5094)
This commit is contained in:
		 Sai Harsha Vardhan
					Sai Harsha Vardhan
				
			
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			 GitHub
						GitHub
					
				
			
						parent
						
							618ec41aff
						
					
				
				
					commit
					9bc780151c
				
			| @ -1,8 +1,9 @@ | ||||
| use common_utils::events::{ApiEventMetric, ApiEventsType}; | ||||
|  | ||||
| use crate::refunds::{ | ||||
|     RefundListFilters, RefundListMetaData, RefundListRequest, RefundListResponse, RefundRequest, | ||||
|     RefundResponse, RefundUpdateRequest, RefundsRetrieveRequest, | ||||
|     RefundListFilters, RefundListMetaData, RefundListRequest, RefundListResponse, | ||||
|     RefundManualUpdateRequest, RefundRequest, RefundResponse, RefundUpdateRequest, | ||||
|     RefundsRetrieveRequest, | ||||
| }; | ||||
|  | ||||
| impl ApiEventMetric for RefundRequest { | ||||
| @ -44,6 +45,15 @@ impl ApiEventMetric for RefundUpdateRequest { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl ApiEventMetric for RefundManualUpdateRequest { | ||||
|     fn get_api_event_type(&self) -> Option<ApiEventsType> { | ||||
|         Some(ApiEventsType::Refund { | ||||
|             payment_id: None, | ||||
|             refund_id: self.refund_id.clone(), | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl ApiEventMetric for RefundListRequest { | ||||
|     fn get_api_event_type(&self) -> Option<ApiEventsType> { | ||||
|         Some(ApiEventsType::ResourceListAPI) | ||||
|  | ||||
| @ -97,6 +97,21 @@ pub struct RefundUpdateRequest { | ||||
|     pub metadata: Option<pii::SecretSerdeValue>, | ||||
| } | ||||
|  | ||||
| #[derive(Default, Debug, ToSchema, Clone, Deserialize, Serialize)] | ||||
| #[serde(deny_unknown_fields)] | ||||
| pub struct RefundManualUpdateRequest { | ||||
|     #[serde(skip)] | ||||
|     pub refund_id: String, | ||||
|     /// Merchant ID | ||||
|     pub merchant_id: String, | ||||
|     /// The status for refund | ||||
|     pub status: Option<RefundStatus>, | ||||
|     /// The code for the error | ||||
|     pub error_code: Option<String>, | ||||
|     /// The error message | ||||
|     pub error_message: Option<String>, | ||||
| } | ||||
|  | ||||
| /// To indicate whether to refund needs to be instant or scheduled | ||||
| #[derive( | ||||
|     Default, Debug, Clone, Copy, ToSchema, Deserialize, Serialize, Eq, PartialEq, strum::Display, | ||||
| @ -244,3 +259,14 @@ impl From<enums::RefundStatus> for RefundStatus { | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<RefundStatus> for enums::RefundStatus { | ||||
|     fn from(status: RefundStatus) -> Self { | ||||
|         match status { | ||||
|             RefundStatus::Failed => Self::Failure, | ||||
|             RefundStatus::Review => Self::ManualReview, | ||||
|             RefundStatus::Pending => Self::Pending, | ||||
|             RefundStatus::Succeeded => Self::Success, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -115,6 +115,12 @@ pub enum RefundUpdate { | ||||
|         refund_error_code: Option<String>, | ||||
|         updated_by: String, | ||||
|     }, | ||||
|     ManualUpdate { | ||||
|         refund_status: Option<storage_enums::RefundStatus>, | ||||
|         refund_error_message: Option<String>, | ||||
|         refund_error_code: Option<String>, | ||||
|         updated_by: String, | ||||
|     }, | ||||
| } | ||||
|  | ||||
| #[derive(Clone, Debug, Default, AsChangeset, router_derive::DebugAsDisplay)] | ||||
| @ -201,6 +207,18 @@ impl From<RefundUpdate> for RefundUpdateInternal { | ||||
|                 updated_by, | ||||
|                 ..Default::default() | ||||
|             }, | ||||
|             RefundUpdate::ManualUpdate { | ||||
|                 refund_status, | ||||
|                 refund_error_message, | ||||
|                 refund_error_code, | ||||
|                 updated_by, | ||||
|             } => Self { | ||||
|                 refund_status, | ||||
|                 refund_error_message, | ||||
|                 refund_error_code, | ||||
|                 updated_by, | ||||
|                 ..Default::default() | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -836,6 +836,60 @@ pub async fn refund_filter_list( | ||||
|     Ok(services::ApplicationResponse::Json(filter_list)) | ||||
| } | ||||
|  | ||||
| #[instrument(skip_all)] | ||||
| #[cfg(feature = "olap")] | ||||
| pub async fn refund_manual_update( | ||||
|     state: SessionState, | ||||
|     req: api_models::refunds::RefundManualUpdateRequest, | ||||
| ) -> RouterResponse<serde_json::Value> { | ||||
|     let key_store = state | ||||
|         .store | ||||
|         .get_merchant_key_store_by_merchant_id( | ||||
|             &req.merchant_id, | ||||
|             &state.store.get_master_key().to_vec().into(), | ||||
|         ) | ||||
|         .await | ||||
|         .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound) | ||||
|         .attach_printable("Error while fetching the key store by merchant_id")?; | ||||
|     let merchant_account = state | ||||
|         .store | ||||
|         .find_merchant_account_by_merchant_id(&req.merchant_id, &key_store) | ||||
|         .await | ||||
|         .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound) | ||||
|         .attach_printable("Error while fetching the merchant_account by merchant_id")?; | ||||
|     let refund = state | ||||
|         .store | ||||
|         .find_refund_by_merchant_id_refund_id( | ||||
|             &merchant_account.merchant_id, | ||||
|             &req.refund_id, | ||||
|             merchant_account.storage_scheme, | ||||
|         ) | ||||
|         .await | ||||
|         .to_not_found_response(errors::ApiErrorResponse::RefundNotFound)?; | ||||
|     let refund_update = storage::RefundUpdate::ManualUpdate { | ||||
|         refund_status: req.status.map(common_enums::RefundStatus::from), | ||||
|         refund_error_message: req.error_message, | ||||
|         refund_error_code: req.error_code, | ||||
|         updated_by: merchant_account.storage_scheme.to_string(), | ||||
|     }; | ||||
|     state | ||||
|         .store | ||||
|         .update_refund( | ||||
|             refund.to_owned(), | ||||
|             refund_update, | ||||
|             merchant_account.storage_scheme, | ||||
|         ) | ||||
|         .await | ||||
|         .to_not_found_response(errors::ApiErrorResponse::InternalServerError) | ||||
|         .attach_printable_lazy(|| { | ||||
|             format!( | ||||
|                 "Failed while updating refund: refund_id: {}", | ||||
|                 refund.refund_id | ||||
|             ) | ||||
|         })?; | ||||
|     Ok(services::ApplicationResponse::StatusOk) | ||||
| } | ||||
|  | ||||
| #[instrument(skip_all)] | ||||
| #[cfg(feature = "olap")] | ||||
| pub async fn get_filters_for_refunds( | ||||
|  | ||||
| @ -855,7 +855,11 @@ impl Refunds { | ||||
|             route = route | ||||
|                 .service(web::resource("/list").route(web::post().to(refunds_list))) | ||||
|                 .service(web::resource("/filter").route(web::post().to(refunds_filter_list))) | ||||
|                 .service(web::resource("/v2/filter").route(web::get().to(get_refunds_filters))); | ||||
|                 .service(web::resource("/v2/filter").route(web::get().to(get_refunds_filters))) | ||||
|                 .service( | ||||
|                     web::resource("/{id}/manual-update") | ||||
|                         .route(web::put().to(refunds_manual_update)), | ||||
|                 ); | ||||
|         } | ||||
|         #[cfg(feature = "oltp")] | ||||
|         { | ||||
|  | ||||
| @ -143,7 +143,8 @@ impl From<Flow> for ApiIdentifier { | ||||
|             | Flow::RefundsRetrieveForceSync | ||||
|             | Flow::RefundsUpdate | ||||
|             | Flow::RefundsList | ||||
|             | Flow::RefundsFilters => Self::Refunds, | ||||
|             | Flow::RefundsFilters | ||||
|             | Flow::RefundsManualUpdate => Self::Refunds, | ||||
|  | ||||
|             Flow::FrmFulfillment | ||||
|             | Flow::IncomingWebhookReceive | ||||
|  | ||||
| @ -301,3 +301,26 @@ pub async fn get_refunds_filters(state: web::Data<AppState>, req: HttpRequest) - | ||||
|     )) | ||||
|     .await | ||||
| } | ||||
|  | ||||
| #[instrument(skip_all, fields(flow = ?Flow::RefundsManualUpdate))] | ||||
| #[cfg(feature = "olap")] | ||||
| pub async fn refunds_manual_update( | ||||
|     state: web::Data<AppState>, | ||||
|     req: HttpRequest, | ||||
|     payload: web::Json<api_models::refunds::RefundManualUpdateRequest>, | ||||
|     path: web::Path<String>, | ||||
| ) -> HttpResponse { | ||||
|     let flow = Flow::RefundsManualUpdate; | ||||
|     let mut refund_manual_update_req = payload.into_inner(); | ||||
|     refund_manual_update_req.refund_id = path.into_inner(); | ||||
|     Box::pin(api::server_wrap( | ||||
|         flow, | ||||
|         state, | ||||
|         &req, | ||||
|         refund_manual_update_req, | ||||
|         |state, _auth, req, _| refund_manual_update(state, req), | ||||
|         &auth::AdminApiAuth, | ||||
|         api_locking::LockAction::NotApplicable, | ||||
|     )) | ||||
|     .await | ||||
| } | ||||
|  | ||||
| @ -452,6 +452,8 @@ pub enum Flow { | ||||
|     ToggleConnectorAgnosticMit, | ||||
|     /// Get the extended card info associated to a payment_id | ||||
|     GetExtendedCardInfo, | ||||
|     /// Manually update the refund details like status, error code, error message etc. | ||||
|     RefundsManualUpdate, | ||||
|     /// Manually update the payment details like status, error code, error message etc. | ||||
|     PaymentsManualUpdate, | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user