feat: add an api for retrieving the extended card info from redis (#4484)

This commit is contained in:
Chethan Rao
2024-05-01 16:07:39 +05:30
committed by GitHub
parent b562e62ac8
commit dfa4b50dbd
13 changed files with 92 additions and 5 deletions

View File

@ -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 {}

View File

@ -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)]

View File

@ -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,

View File

@ -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

View File

@ -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 {

View File

@ -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))
}
} }
} }
} }

View File

@ -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 },
))
}

View File

@ -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")
}

View File

@ -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

View File

@ -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

View File

@ -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<()> {

View File

@ -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,
} }
/// ///

View File

@ -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": [