mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-30 09:38:33 +08:00
feat: add an api for retrieving the extended card info from redis (#4484)
This commit is contained in:
@ -8,9 +8,10 @@ use crate::{
|
|||||||
PaymentMethodResponse, PaymentMethodUpdate,
|
PaymentMethodResponse, PaymentMethodUpdate,
|
||||||
},
|
},
|
||||||
payments::{
|
payments::{
|
||||||
PaymentIdType, PaymentListConstraints, PaymentListFilterConstraints, PaymentListFilters,
|
ExtendedCardInfoResponse, PaymentIdType, PaymentListConstraints,
|
||||||
PaymentListFiltersV2, PaymentListResponse, PaymentListResponseV2, PaymentsApproveRequest,
|
PaymentListFilterConstraints, PaymentListFilters, PaymentListFiltersV2,
|
||||||
PaymentsCancelRequest, PaymentsCaptureRequest, PaymentsExternalAuthenticationRequest,
|
PaymentListResponse, PaymentListResponseV2, PaymentsApproveRequest, PaymentsCancelRequest,
|
||||||
|
PaymentsCaptureRequest, PaymentsExternalAuthenticationRequest,
|
||||||
PaymentsExternalAuthenticationResponse, PaymentsIncrementalAuthorizationRequest,
|
PaymentsExternalAuthenticationResponse, PaymentsIncrementalAuthorizationRequest,
|
||||||
PaymentsRejectRequest, PaymentsRequest, PaymentsResponse, PaymentsRetrieveRequest,
|
PaymentsRejectRequest, PaymentsRequest, PaymentsResponse, PaymentsRetrieveRequest,
|
||||||
PaymentsStartRequest, RedirectionResponse,
|
PaymentsStartRequest, RedirectionResponse,
|
||||||
@ -201,3 +202,5 @@ impl ApiEventMetric for PaymentsExternalAuthenticationRequest {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ApiEventMetric for ExtendedCardInfoResponse {}
|
||||||
|
|||||||
@ -4622,6 +4622,12 @@ pub enum PaymentLinkStatusWrap {
|
|||||||
IntentStatus(api_enums::IntentStatus),
|
IntentStatus(api_enums::IntentStatus),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, serde::Deserialize, serde::Serialize, Clone, ToSchema)]
|
||||||
|
pub struct ExtendedCardInfoResponse {
|
||||||
|
// Encrypted customer payment method data
|
||||||
|
pub payload: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod payments_request_api_contract {
|
mod payments_request_api_contract {
|
||||||
#![allow(clippy::unwrap_used)]
|
#![allow(clippy::unwrap_used)]
|
||||||
|
|||||||
@ -470,6 +470,7 @@ Never share your secret api keys. Keep them guarded and secure.
|
|||||||
api_models::payments::PaymentLinkResponse,
|
api_models::payments::PaymentLinkResponse,
|
||||||
api_models::payments::RetrievePaymentLinkResponse,
|
api_models::payments::RetrievePaymentLinkResponse,
|
||||||
api_models::payments::PaymentLinkInitiateRequest,
|
api_models::payments::PaymentLinkInitiateRequest,
|
||||||
|
api_models::payments::ExtendedCardInfoResponse,
|
||||||
api_models::routing::RoutingConfigRequest,
|
api_models::routing::RoutingConfigRequest,
|
||||||
api_models::routing::RoutingDictionaryRecord,
|
api_models::routing::RoutingDictionaryRecord,
|
||||||
api_models::routing::RoutingKind,
|
api_models::routing::RoutingKind,
|
||||||
|
|||||||
@ -262,6 +262,8 @@ pub enum StripeErrorCode {
|
|||||||
CurrencyConversionFailed,
|
CurrencyConversionFailed,
|
||||||
#[error(error_type = StripeErrorType::InvalidRequestError, code = "IR_25", message = "Cannot delete the default payment method")]
|
#[error(error_type = StripeErrorType::InvalidRequestError, code = "IR_25", message = "Cannot delete the default payment method")]
|
||||||
PaymentMethodDeleteFailed,
|
PaymentMethodDeleteFailed,
|
||||||
|
#[error(error_type = StripeErrorType::InvalidRequestError, code = "", message = "Extended card info does not exist")]
|
||||||
|
ExtendedCardInfoNotFound,
|
||||||
// [#216]: https://github.com/juspay/hyperswitch/issues/216
|
// [#216]: https://github.com/juspay/hyperswitch/issues/216
|
||||||
// Implement the remaining stripe error codes
|
// Implement the remaining stripe error codes
|
||||||
|
|
||||||
@ -643,6 +645,7 @@ impl From<errors::ApiErrorResponse> for StripeErrorCode {
|
|||||||
errors::ApiErrorResponse::InvalidWalletToken { wallet_name } => {
|
errors::ApiErrorResponse::InvalidWalletToken { wallet_name } => {
|
||||||
Self::InvalidWalletToken { wallet_name }
|
Self::InvalidWalletToken { wallet_name }
|
||||||
}
|
}
|
||||||
|
errors::ApiErrorResponse::ExtendedCardInfoNotFound => Self::ExtendedCardInfoNotFound,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -714,7 +717,8 @@ impl actix_web::ResponseError for StripeErrorCode {
|
|||||||
| Self::PaymentMethodUnactivated
|
| Self::PaymentMethodUnactivated
|
||||||
| Self::InvalidConnectorConfiguration { .. }
|
| Self::InvalidConnectorConfiguration { .. }
|
||||||
| Self::CurrencyConversionFailed
|
| Self::CurrencyConversionFailed
|
||||||
| Self::PaymentMethodDeleteFailed => StatusCode::BAD_REQUEST,
|
| Self::PaymentMethodDeleteFailed
|
||||||
|
| Self::ExtendedCardInfoNotFound => StatusCode::BAD_REQUEST,
|
||||||
Self::RefundFailed
|
Self::RefundFailed
|
||||||
| Self::PayoutFailed
|
| Self::PayoutFailed
|
||||||
| Self::PaymentLinkNotFound
|
| Self::PaymentLinkNotFound
|
||||||
|
|||||||
@ -269,6 +269,8 @@ pub enum ApiErrorResponse {
|
|||||||
message = "Invalid Cookie"
|
message = "Invalid Cookie"
|
||||||
)]
|
)]
|
||||||
InvalidCookie,
|
InvalidCookie,
|
||||||
|
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_27", message = "Extended card info does not exist")]
|
||||||
|
ExtendedCardInfoNotFound,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PTError for ApiErrorResponse {
|
impl PTError for ApiErrorResponse {
|
||||||
|
|||||||
@ -301,6 +301,9 @@ impl ErrorSwitch<api_models::errors::types::ApiErrorResponse> for ApiErrorRespon
|
|||||||
Self::InvalidCookie => {
|
Self::InvalidCookie => {
|
||||||
AER::BadRequest(ApiError::new("IR", 26, "Invalid Cookie", None))
|
AER::BadRequest(ApiError::new("IR", 26, "Invalid Cookie", None))
|
||||||
}
|
}
|
||||||
|
Self::ExtendedCardInfoNotFound => {
|
||||||
|
AER::NotFound(ApiError::new("IR", 27, "Extended card info does not exist", None))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4034,3 +4034,26 @@ pub async fn payment_external_authentication(
|
|||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip_all)]
|
||||||
|
pub async fn get_extended_card_info(
|
||||||
|
state: AppState,
|
||||||
|
merchant_id: String,
|
||||||
|
payment_id: String,
|
||||||
|
) -> RouterResponse<payments_api::ExtendedCardInfoResponse> {
|
||||||
|
let redis_conn = state
|
||||||
|
.store
|
||||||
|
.get_redis_conn()
|
||||||
|
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Failed to get redis connection")?;
|
||||||
|
|
||||||
|
let key = helpers::get_redis_key_for_extended_card_info(&merchant_id, &payment_id);
|
||||||
|
let payload = redis_conn
|
||||||
|
.get_key::<String>(&key)
|
||||||
|
.await
|
||||||
|
.change_context(errors::ApiErrorResponse::ExtendedCardInfoNotFound)?;
|
||||||
|
|
||||||
|
Ok(services::ApplicationResponse::Json(
|
||||||
|
payments_api::ExtendedCardInfoResponse { payload },
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|||||||
@ -4319,3 +4319,7 @@ pub fn validate_mandate_data_and_future_usage(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_redis_key_for_extended_card_info(merchant_id: &str, payment_id: &str) -> String {
|
||||||
|
format!("{merchant_id}_{payment_id}_extended_card_info")
|
||||||
|
}
|
||||||
|
|||||||
@ -382,6 +382,9 @@ impl Payments {
|
|||||||
)
|
)
|
||||||
.service(
|
.service(
|
||||||
web::resource("/{payment_id}/3ds/authentication").route(web::post().to(payments_external_authentication)),
|
web::resource("/{payment_id}/3ds/authentication").route(web::post().to(payments_external_authentication)),
|
||||||
|
)
|
||||||
|
.service(
|
||||||
|
web::resource("/{payment_id}/extended_card_info").route(web::get().to(retrieve_extended_card_info)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
route
|
route
|
||||||
|
|||||||
@ -120,7 +120,8 @@ impl From<Flow> for ApiIdentifier {
|
|||||||
| Flow::PaymentsRedirect
|
| Flow::PaymentsRedirect
|
||||||
| Flow::PaymentsIncrementalAuthorization
|
| Flow::PaymentsIncrementalAuthorization
|
||||||
| Flow::PaymentsExternalAuthentication
|
| Flow::PaymentsExternalAuthentication
|
||||||
| Flow::PaymentsAuthorize => Self::Payments,
|
| Flow::PaymentsAuthorize
|
||||||
|
| Flow::GetExtendedCardInfo => Self::Payments,
|
||||||
|
|
||||||
Flow::PayoutsCreate
|
Flow::PayoutsCreate
|
||||||
| Flow::PayoutsRetrieve
|
| Flow::PayoutsRetrieve
|
||||||
|
|||||||
@ -1357,6 +1357,30 @@ pub async fn post_3ds_payments_authorize(
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieve endpoint for merchant to fetch the encrypted customer payment method data
|
||||||
|
#[instrument(skip_all, fields(flow = ?Flow::GetExtendedCardInfo, payment_id))]
|
||||||
|
pub async fn retrieve_extended_card_info(
|
||||||
|
state: web::Data<app::AppState>,
|
||||||
|
req: actix_web::HttpRequest,
|
||||||
|
path: web::Path<String>,
|
||||||
|
) -> impl Responder {
|
||||||
|
let flow = Flow::GetExtendedCardInfo;
|
||||||
|
let payment_id = path.into_inner();
|
||||||
|
|
||||||
|
Box::pin(api::server_wrap(
|
||||||
|
flow,
|
||||||
|
state,
|
||||||
|
&req,
|
||||||
|
payment_id,
|
||||||
|
|state, auth, payment_id, _| {
|
||||||
|
payments::get_extended_card_info(state, auth.merchant_account.merchant_id, payment_id)
|
||||||
|
},
|
||||||
|
&auth::ApiKeyAuth,
|
||||||
|
api_locking::LockAction::NotApplicable,
|
||||||
|
))
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_or_generate_payment_id(
|
pub fn get_or_generate_payment_id(
|
||||||
payload: &mut payment_types::PaymentsRequest,
|
payload: &mut payment_types::PaymentsRequest,
|
||||||
) -> errors::RouterResult<()> {
|
) -> errors::RouterResult<()> {
|
||||||
|
|||||||
@ -402,6 +402,8 @@ pub enum Flow {
|
|||||||
RetrievePollStatus,
|
RetrievePollStatus,
|
||||||
/// Toggles the extended card info feature in profile level
|
/// Toggles the extended card info feature in profile level
|
||||||
ToggleExtendedCardInfo,
|
ToggleExtendedCardInfo,
|
||||||
|
/// Get the extended card info associated to a payment_id
|
||||||
|
GetExtendedCardInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
|||||||
@ -8707,6 +8707,17 @@
|
|||||||
"mandate_revoked"
|
"mandate_revoked"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"ExtendedCardInfoResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"payload"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"payload": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"ExternalAuthenticationDetailsResponse": {
|
"ExternalAuthenticationDetailsResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
|||||||
Reference in New Issue
Block a user