mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-10-31 01:57:45 +08:00 
			
		
		
		
	feat(payment_method_validate): add new operation to payments_operation_core for payment method validation (#53)
Co-authored-by: Arun Raj M <jarnura47@gmail.com>
This commit is contained in:
		| @ -53,6 +53,7 @@ impl api::PaymentVoid for Braintree {} | |||||||
| impl api::PaymentCapture for Braintree {} | impl api::PaymentCapture for Braintree {} | ||||||
| impl api::PreVerify for Braintree {} | impl api::PreVerify for Braintree {} | ||||||
|  |  | ||||||
|  | #[allow(dead_code)] | ||||||
| impl | impl | ||||||
|     services::ConnectorIntegration< |     services::ConnectorIntegration< | ||||||
|         api::Verify, |         api::Verify, | ||||||
| @ -60,6 +61,7 @@ impl | |||||||
|         types::PaymentsResponseData, |         types::PaymentsResponseData, | ||||||
|     > for Braintree |     > for Braintree | ||||||
| { | { | ||||||
|  |     // Not Implemented (R) | ||||||
| } | } | ||||||
|  |  | ||||||
| #[allow(dead_code)] | #[allow(dead_code)] | ||||||
|  | |||||||
| @ -20,7 +20,7 @@ use crate::{ | |||||||
|     routes::AppState, |     routes::AppState, | ||||||
|     services, |     services, | ||||||
|     types::{ |     types::{ | ||||||
|         api::{self, PgRedirectResponse}, |         api, | ||||||
|         storage::{self, enums}, |         storage::{self, enums}, | ||||||
|     }, |     }, | ||||||
|     utils::{ |     utils::{ | ||||||
| @ -226,7 +226,10 @@ pub fn validate_request_amount_and_amount_to_capture( | |||||||
|     ) |     ) | ||||||
| } | } | ||||||
|  |  | ||||||
| pub fn validate_mandate(req: &api::PaymentsRequest) -> RouterResult<Option<api::MandateTxnType>> { | pub fn validate_mandate( | ||||||
|  |     req: impl Into<api::MandateValidationFields>, | ||||||
|  | ) -> RouterResult<Option<api::MandateTxnType>> { | ||||||
|  |     let req: api::MandateValidationFields = req.into(); | ||||||
|     match req.is_mandate() { |     match req.is_mandate() { | ||||||
|         Some(api::MandateTxnType::NewMandateTxn) => { |         Some(api::MandateTxnType::NewMandateTxn) => { | ||||||
|             validate_new_mandate_request(req)?; |             validate_new_mandate_request(req)?; | ||||||
| @ -240,7 +243,7 @@ pub fn validate_mandate(req: &api::PaymentsRequest) -> RouterResult<Option<api:: | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| fn validate_new_mandate_request(req: &api::PaymentsRequest) -> RouterResult<()> { | fn validate_new_mandate_request(req: api::MandateValidationFields) -> RouterResult<()> { | ||||||
|     let confirm = req.confirm.get_required_value("confirm")?; |     let confirm = req.confirm.get_required_value("confirm")?; | ||||||
|  |  | ||||||
|     if !confirm { |     if !confirm { | ||||||
| @ -302,8 +305,7 @@ pub fn create_redirect_url(server: &Server, payment_attempt: &storage::PaymentAt | |||||||
|         payment_attempt.connector |         payment_attempt.connector | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
|  | fn validate_recurring_mandate(req: api::MandateValidationFields) -> RouterResult<()> { | ||||||
| fn validate_recurring_mandate(req: &api::PaymentsRequest) -> RouterResult<()> { |  | ||||||
|     req.mandate_id.check_value_present("mandate_id")?; |     req.mandate_id.check_value_present("mandate_id")?; | ||||||
|  |  | ||||||
|     req.customer_id.check_value_present("customer_id")?; |     req.customer_id.check_value_present("customer_id")?; | ||||||
| @ -844,7 +846,7 @@ pub fn get_handle_response_url( | |||||||
|  |  | ||||||
| pub fn make_merchant_url_with_response( | pub fn make_merchant_url_with_response( | ||||||
|     merchant_account: &storage::MerchantAccount, |     merchant_account: &storage::MerchantAccount, | ||||||
|     redirection_response: PgRedirectResponse, |     redirection_response: api::PgRedirectResponse, | ||||||
|     request_return_url: Option<&String>, |     request_return_url: Option<&String>, | ||||||
| ) -> RouterResult<String> { | ) -> RouterResult<String> { | ||||||
|     // take return url if provided in the request else use merchant return url |     // take return url if provided in the request else use merchant return url | ||||||
| @ -889,8 +891,8 @@ pub fn make_pg_redirect_response( | |||||||
|     payment_id: String, |     payment_id: String, | ||||||
|     response: &api::PaymentsResponse, |     response: &api::PaymentsResponse, | ||||||
|     connector: String, |     connector: String, | ||||||
| ) -> PgRedirectResponse { | ) -> api::PgRedirectResponse { | ||||||
|     PgRedirectResponse { |     api::PgRedirectResponse { | ||||||
|         payment_id, |         payment_id, | ||||||
|         status: response.status, |         status: response.status, | ||||||
|         gateway_id: connector, |         gateway_id: connector, | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ mod payment_cancel; | |||||||
| mod payment_capture; | mod payment_capture; | ||||||
| mod payment_confirm; | mod payment_confirm; | ||||||
| mod payment_create; | mod payment_create; | ||||||
|  | mod payment_method_validate; | ||||||
| mod payment_response; | mod payment_response; | ||||||
| mod payment_session; | mod payment_session; | ||||||
| mod payment_start; | mod payment_start; | ||||||
|  | |||||||
| @ -364,7 +364,7 @@ impl PaymentCreate { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[instrument(skip_all)] |     #[instrument(skip_all)] | ||||||
|     fn make_connector_response( |     pub fn make_connector_response( | ||||||
|         payment_attempt: &storage::PaymentAttempt, |         payment_attempt: &storage::PaymentAttempt, | ||||||
|     ) -> storage::ConnectorResponseNew { |     ) -> storage::ConnectorResponseNew { | ||||||
|         storage::ConnectorResponseNew { |         storage::ConnectorResponseNew { | ||||||
|  | |||||||
| @ -0,0 +1,307 @@ | |||||||
|  | use std::marker::PhantomData; | ||||||
|  |  | ||||||
|  | use async_trait::async_trait; | ||||||
|  | use common_utils::{date_time, errors::CustomResult}; | ||||||
|  | use error_stack::ResultExt; | ||||||
|  | use router_derive::PaymentOperation; | ||||||
|  | use router_env::{instrument, tracing}; | ||||||
|  | use uuid::Uuid; | ||||||
|  |  | ||||||
|  | use super::{BoxedOperation, Domain, GetTracker, PaymentCreate, UpdateTracker, ValidateRequest}; | ||||||
|  | use crate::{ | ||||||
|  |     consts, | ||||||
|  |     core::{ | ||||||
|  |         errors::{self, RouterResult, StorageErrorExt}, | ||||||
|  |         payments::{self, helpers, Operation, PaymentData}, | ||||||
|  |         utils as core_utils, | ||||||
|  |     }, | ||||||
|  |     db::StorageInterface, | ||||||
|  |     routes::AppState, | ||||||
|  |     types::{ | ||||||
|  |         self, api, | ||||||
|  |         storage::{self, enums}, | ||||||
|  |     }, | ||||||
|  |     utils, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #[derive(Debug, Clone, Copy, PaymentOperation)] | ||||||
|  | #[operation(ops = "all", flow = "verify")] | ||||||
|  | pub struct PaymentMethodValidate; | ||||||
|  |  | ||||||
|  | impl<F: Send + Clone> ValidateRequest<F, api::VerifyRequest> for PaymentMethodValidate { | ||||||
|  |     #[instrument(skip_all)] | ||||||
|  |     fn validate_request<'a, 'b>( | ||||||
|  |         &'b self, | ||||||
|  |         request: &api::VerifyRequest, | ||||||
|  |         merchant_account: &'a types::storage::MerchantAccount, | ||||||
|  |     ) -> RouterResult<( | ||||||
|  |         BoxedOperation<'b, F, api::VerifyRequest>, | ||||||
|  |         &'a str, | ||||||
|  |         api::PaymentIdType, | ||||||
|  |         Option<api::MandateTxnType>, | ||||||
|  |     )> { | ||||||
|  |         let request_merchant_id = Some(&request.merchant_id[..]); | ||||||
|  |         helpers::validate_merchant_id(&merchant_account.merchant_id, request_merchant_id) | ||||||
|  |             .change_context(errors::ApiErrorResponse::MerchantAccountNotFound)?; | ||||||
|  |  | ||||||
|  |         let mandate_type = helpers::validate_mandate(request)?; | ||||||
|  |         let validation_id = core_utils::get_or_generate_id("validation_id", &None, "val")?; | ||||||
|  |  | ||||||
|  |         Ok(( | ||||||
|  |             Box::new(self), | ||||||
|  |             &merchant_account.merchant_id, | ||||||
|  |             api::PaymentIdType::PaymentIntentId(validation_id), | ||||||
|  |             mandate_type, | ||||||
|  |         )) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[async_trait] | ||||||
|  | impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::VerifyRequest> for PaymentMethodValidate { | ||||||
|  |     #[instrument(skip_all)] | ||||||
|  |     async fn get_trackers<'a>( | ||||||
|  |         &'a self, | ||||||
|  |         state: &'a AppState, | ||||||
|  |         payment_id: &api::PaymentIdType, | ||||||
|  |         merchant_id: &str, | ||||||
|  |         connector: types::Connector, | ||||||
|  |         request: &api::VerifyRequest, | ||||||
|  |         _mandate_type: Option<api::MandateTxnType>, | ||||||
|  |     ) -> RouterResult<( | ||||||
|  |         BoxedOperation<'a, F, api::VerifyRequest>, | ||||||
|  |         PaymentData<F>, | ||||||
|  |         Option<payments::CustomerDetails>, | ||||||
|  |     )> { | ||||||
|  |         let db = &state.store; | ||||||
|  |         let (payment_intent, payment_attempt, connector_response); | ||||||
|  |  | ||||||
|  |         let payment_id = payment_id | ||||||
|  |             .get_payment_intent_id() | ||||||
|  |             .change_context(errors::ApiErrorResponse::InternalServerError)?; | ||||||
|  |  | ||||||
|  |         payment_attempt = match db | ||||||
|  |             .insert_payment_attempt(Self::make_payment_attempt( | ||||||
|  |                 &payment_id, | ||||||
|  |                 merchant_id, | ||||||
|  |                 connector, | ||||||
|  |                 request.payment_method, | ||||||
|  |                 request, | ||||||
|  |             )) | ||||||
|  |             .await | ||||||
|  |         { | ||||||
|  |             Ok(payment_attempt) => Ok(payment_attempt), | ||||||
|  |             Err(err) => { | ||||||
|  |                 Err(err.change_context(errors::ApiErrorResponse::VerificationFailed { data: None })) | ||||||
|  |             } | ||||||
|  |         }?; | ||||||
|  |  | ||||||
|  |         payment_intent = match db | ||||||
|  |             .insert_payment_intent(Self::make_payment_intent( | ||||||
|  |                 &payment_id, | ||||||
|  |                 merchant_id, | ||||||
|  |                 connector, | ||||||
|  |                 request, | ||||||
|  |             )) | ||||||
|  |             .await | ||||||
|  |         { | ||||||
|  |             Ok(payment_intent) => Ok(payment_intent), | ||||||
|  |             Err(err) => { | ||||||
|  |                 Err(err.change_context(errors::ApiErrorResponse::VerificationFailed { data: None })) | ||||||
|  |             } | ||||||
|  |         }?; | ||||||
|  |  | ||||||
|  |         connector_response = match db | ||||||
|  |             .insert_connector_response(PaymentCreate::make_connector_response(&payment_attempt)) | ||||||
|  |             .await | ||||||
|  |         { | ||||||
|  |             Ok(connector_resp) => Ok(connector_resp), | ||||||
|  |             Err(err) => { | ||||||
|  |                 Err(err.change_context(errors::ApiErrorResponse::VerificationFailed { data: None })) | ||||||
|  |             } | ||||||
|  |         }?; | ||||||
|  |  | ||||||
|  |         Ok(( | ||||||
|  |             Box::new(self), | ||||||
|  |             PaymentData { | ||||||
|  |                 flow: PhantomData, | ||||||
|  |                 payment_intent, | ||||||
|  |                 payment_attempt, | ||||||
|  |                 /// currency and amount are irrelevant in this scenario | ||||||
|  |                 currency: enums::Currency::default(), | ||||||
|  |                 amount: 0, | ||||||
|  |                 mandate_id: None, | ||||||
|  |                 setup_mandate: request.mandate_data.clone(), | ||||||
|  |                 token: request.payment_token.clone(), | ||||||
|  |                 connector_response, | ||||||
|  |                 payment_method_data: request.payment_method_data.clone(), | ||||||
|  |                 confirm: Some(true), | ||||||
|  |                 address: types::PaymentAddress::default(), | ||||||
|  |                 force_sync: None, | ||||||
|  |                 refunds: vec![], | ||||||
|  |             }, | ||||||
|  |             Some(payments::CustomerDetails { | ||||||
|  |                 customer_id: request.customer_id.clone(), | ||||||
|  |                 name: request.name.clone(), | ||||||
|  |                 email: request.email.clone(), | ||||||
|  |                 phone: request.phone.clone(), | ||||||
|  |                 phone_country_code: request.phone_country_code.clone(), | ||||||
|  |             }), | ||||||
|  |         )) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[async_trait] | ||||||
|  | impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::VerifyRequest> for PaymentMethodValidate { | ||||||
|  |     #[instrument(skip_all)] | ||||||
|  |     async fn update_trackers<'b>( | ||||||
|  |         &'b self, | ||||||
|  |         db: &dyn StorageInterface, | ||||||
|  |         _payment_id: &api::PaymentIdType, | ||||||
|  |         mut payment_data: PaymentData<F>, | ||||||
|  |         _customer: Option<storage::Customer>, | ||||||
|  |     ) -> RouterResult<(BoxedOperation<'b, F, api::VerifyRequest>, PaymentData<F>)> | ||||||
|  |     where | ||||||
|  |         F: 'b + Send, | ||||||
|  |     { | ||||||
|  |         // There is no fsm involved in this operation all the change of states must happen in a single request | ||||||
|  |         let status = Some(enums::IntentStatus::Processing); | ||||||
|  |  | ||||||
|  |         let customer_id = payment_data.payment_intent.customer_id.clone(); | ||||||
|  |  | ||||||
|  |         payment_data.payment_intent = db | ||||||
|  |             .update_payment_intent( | ||||||
|  |                 payment_data.payment_intent, | ||||||
|  |                 storage::PaymentIntentUpdate::ReturnUrlUpdate { | ||||||
|  |                     return_url: None, | ||||||
|  |                     status, | ||||||
|  |                     customer_id, | ||||||
|  |                     shipping_address_id: None, | ||||||
|  |                     billing_address_id: None, | ||||||
|  |                 }, | ||||||
|  |             ) | ||||||
|  |             .await | ||||||
|  |             .map_err(|err| { | ||||||
|  |                 err.to_not_found_response(errors::ApiErrorResponse::VerificationFailed { | ||||||
|  |                     data: None, | ||||||
|  |                 }) | ||||||
|  |             })?; | ||||||
|  |  | ||||||
|  |         Ok((Box::new(self), payment_data)) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[async_trait] | ||||||
|  | impl<F, Op> Domain<F, api::VerifyRequest> for Op | ||||||
|  | where | ||||||
|  |     F: Clone + Send, | ||||||
|  |     Op: Send + Sync + Operation<F, api::VerifyRequest>, | ||||||
|  |     for<'a> &'a Op: Operation<F, api::VerifyRequest>, | ||||||
|  | { | ||||||
|  |     #[instrument(skip_all)] | ||||||
|  |     async fn get_or_create_customer_details<'a>( | ||||||
|  |         &'a self, | ||||||
|  |         db: &dyn StorageInterface, | ||||||
|  |         payment_data: &mut PaymentData<F>, | ||||||
|  |         request: Option<payments::CustomerDetails>, | ||||||
|  |         merchant_id: &str, | ||||||
|  |     ) -> CustomResult< | ||||||
|  |         ( | ||||||
|  |             BoxedOperation<'a, F, api::VerifyRequest>, | ||||||
|  |             Option<api::CustomerResponse>, | ||||||
|  |         ), | ||||||
|  |         errors::StorageError, | ||||||
|  |     > { | ||||||
|  |         helpers::create_customer_if_not_exist( | ||||||
|  |             Box::new(self), | ||||||
|  |             db, | ||||||
|  |             payment_data, | ||||||
|  |             request, | ||||||
|  |             merchant_id, | ||||||
|  |         ) | ||||||
|  |         .await | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[instrument(skip_all)] | ||||||
|  |     async fn make_pm_data<'a>( | ||||||
|  |         &'a self, | ||||||
|  |         state: &'a AppState, | ||||||
|  |         payment_method: Option<enums::PaymentMethodType>, | ||||||
|  |         txn_id: &str, | ||||||
|  |         payment_attempt: &storage::PaymentAttempt, | ||||||
|  |         request: &Option<api::PaymentMethod>, | ||||||
|  |         token: &Option<String>, | ||||||
|  |     ) -> RouterResult<( | ||||||
|  |         BoxedOperation<'a, F, api::VerifyRequest>, | ||||||
|  |         Option<api::PaymentMethod>, | ||||||
|  |     )> { | ||||||
|  |         helpers::make_pm_data( | ||||||
|  |             Box::new(self), | ||||||
|  |             state, | ||||||
|  |             payment_method, | ||||||
|  |             txn_id, | ||||||
|  |             payment_attempt, | ||||||
|  |             request, | ||||||
|  |             token, | ||||||
|  |         ) | ||||||
|  |         .await | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl PaymentMethodValidate { | ||||||
|  |     #[instrument(skip_all)] | ||||||
|  |     fn make_payment_attempt( | ||||||
|  |         payment_id: &str, | ||||||
|  |         merchant_id: &str, | ||||||
|  |         connector: types::Connector, | ||||||
|  |         payment_method: Option<enums::PaymentMethodType>, | ||||||
|  |         _request: &api::VerifyRequest, | ||||||
|  |     ) -> storage::PaymentAttemptNew { | ||||||
|  |         let created_at @ modified_at @ last_synced = Some(date_time::now()); | ||||||
|  |         let status = enums::AttemptStatus::Pending; | ||||||
|  |  | ||||||
|  |         storage::PaymentAttemptNew { | ||||||
|  |             payment_id: payment_id.to_string(), | ||||||
|  |             merchant_id: merchant_id.to_string(), | ||||||
|  |             txn_id: Uuid::new_v4().to_string(), | ||||||
|  |             status, | ||||||
|  |             // Amount & Currency will be zero in this case | ||||||
|  |             amount: 0, | ||||||
|  |             currency: Default::default(), | ||||||
|  |             connector: connector.to_string(), | ||||||
|  |             payment_method, | ||||||
|  |             confirm: true, | ||||||
|  |             created_at, | ||||||
|  |             modified_at, | ||||||
|  |             last_synced, | ||||||
|  |             ..Default::default() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn make_payment_intent( | ||||||
|  |         payment_id: &str, | ||||||
|  |         merchant_id: &str, | ||||||
|  |         connector: types::Connector, | ||||||
|  |         request: &api::VerifyRequest, | ||||||
|  |     ) -> storage::PaymentIntentNew { | ||||||
|  |         let created_at @ modified_at @ last_synced = Some(date_time::now()); | ||||||
|  |         let status = helpers::payment_intent_status_fsm(&request.payment_method_data, Some(true)); | ||||||
|  |  | ||||||
|  |         let client_secret = | ||||||
|  |             utils::generate_id(consts::ID_LENGTH, format!("{}_secret", payment_id).as_str()); | ||||||
|  |         storage::PaymentIntentNew { | ||||||
|  |             payment_id: payment_id.to_string(), | ||||||
|  |             merchant_id: merchant_id.to_string(), | ||||||
|  |             status, | ||||||
|  |             amount: 0, | ||||||
|  |             currency: Default::default(), | ||||||
|  |             connector_id: Some(connector.to_string()), | ||||||
|  |             created_at, | ||||||
|  |             modified_at, | ||||||
|  |             last_synced, | ||||||
|  |             client_secret: Some(client_secret), | ||||||
|  |             setup_future_usage: request.setup_future_usage, | ||||||
|  |             off_session: request.off_session, | ||||||
|  |             ..Default::default() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -3,7 +3,6 @@ use masking::{PeekInterface, Secret}; | |||||||
| use router_derive::Setter; | use router_derive::Setter; | ||||||
| use time::PrimitiveDateTime; | use time::PrimitiveDateTime; | ||||||
|  |  | ||||||
| use super::{ConnectorCommon, RefundResponse}; |  | ||||||
| use crate::{ | use crate::{ | ||||||
|     core::errors, |     core::errors, | ||||||
|     pii, |     pii, | ||||||
| @ -89,9 +88,9 @@ pub struct VerifyRequest { | |||||||
|     pub phone_country_code: Option<String>, |     pub phone_country_code: Option<String>, | ||||||
|     pub payment_method: Option<enums::PaymentMethodType>, |     pub payment_method: Option<enums::PaymentMethodType>, | ||||||
|     pub payment_method_data: Option<PaymentMethod>, |     pub payment_method_data: Option<PaymentMethod>, | ||||||
|     pub payment_token: Option<i32>, |     pub payment_token: Option<String>, | ||||||
|     pub mandate_data: Option<MandateData>, |     pub mandate_data: Option<MandateData>, | ||||||
|     pub setup_future_usage: Option<super::FutureUsage>, |     pub setup_future_usage: Option<api_types::FutureUsage>, | ||||||
|     pub off_session: Option<bool>, |     pub off_session: Option<bool>, | ||||||
|     pub client_secret: Option<String>, |     pub client_secret: Option<String>, | ||||||
| } | } | ||||||
| @ -338,7 +337,7 @@ pub struct PaymentsResponse { | |||||||
|     pub currency: String, |     pub currency: String, | ||||||
|     pub customer_id: Option<String>, |     pub customer_id: Option<String>, | ||||||
|     pub description: Option<String>, |     pub description: Option<String>, | ||||||
|     pub refunds: Option<Vec<RefundResponse>>, |     pub refunds: Option<Vec<api_types::RefundResponse>>, | ||||||
|     pub mandate_id: Option<String>, |     pub mandate_id: Option<String>, | ||||||
|     pub mandate_data: Option<MandateData>, |     pub mandate_data: Option<MandateData>, | ||||||
|     pub setup_future_usage: Option<enums::FutureUsage>, |     pub setup_future_usage: Option<enums::FutureUsage>, | ||||||
| @ -426,6 +425,51 @@ pub struct PaymentsRedirectionResponse { | |||||||
|     pub redirect_url: String, |     pub redirect_url: String, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | pub struct MandateValidationFields { | ||||||
|  |     pub mandate_id: Option<String>, | ||||||
|  |     pub confirm: Option<bool>, | ||||||
|  |     pub customer_id: Option<String>, | ||||||
|  |     pub mandate_data: Option<MandateData>, | ||||||
|  |     pub setup_future_usage: Option<api_types::FutureUsage>, | ||||||
|  |     pub off_session: Option<bool>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl MandateValidationFields { | ||||||
|  |     pub fn is_mandate(&self) -> Option<MandateTxnType> { | ||||||
|  |         match (&self.mandate_data, &self.mandate_id) { | ||||||
|  |             (None, None) => None, | ||||||
|  |             (_, Some(_)) => Some(MandateTxnType::RecurringMandateTxn), | ||||||
|  |             (Some(_), _) => Some(MandateTxnType::NewMandateTxn), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl From<&PaymentsRequest> for MandateValidationFields { | ||||||
|  |     fn from(req: &PaymentsRequest) -> Self { | ||||||
|  |         Self { | ||||||
|  |             mandate_id: req.mandate_id.clone(), | ||||||
|  |             confirm: req.confirm, | ||||||
|  |             customer_id: req.customer_id.clone(), | ||||||
|  |             mandate_data: req.mandate_data.clone(), | ||||||
|  |             setup_future_usage: req.setup_future_usage, | ||||||
|  |             off_session: req.off_session, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl From<&VerifyRequest> for MandateValidationFields { | ||||||
|  |     fn from(req: &VerifyRequest) -> Self { | ||||||
|  |         Self { | ||||||
|  |             mandate_id: None, | ||||||
|  |             confirm: Some(true), | ||||||
|  |             customer_id: req.customer_id.clone(), | ||||||
|  |             mandate_data: req.mandate_data.clone(), | ||||||
|  |             off_session: req.off_session, | ||||||
|  |             setup_future_usage: req.setup_future_usage, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| impl PaymentsRedirectionResponse { | impl PaymentsRedirectionResponse { | ||||||
|     pub fn new(redirect_url: &str) -> Self { |     pub fn new(redirect_url: &str) -> Self { | ||||||
|         Self { |         Self { | ||||||
| @ -659,7 +703,12 @@ pub trait PreVerify: | |||||||
| } | } | ||||||
|  |  | ||||||
| pub trait Payment: | pub trait Payment: | ||||||
|     ConnectorCommon + PaymentAuthorize + PaymentSync + PaymentCapture + PaymentVoid + PreVerify |     api_types::ConnectorCommon | ||||||
|  |     + PaymentAuthorize | ||||||
|  |     + PaymentSync | ||||||
|  |     + PaymentCapture | ||||||
|  |     + PaymentVoid | ||||||
|  |     + PreVerify | ||||||
| { | { | ||||||
| } | } | ||||||
| #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)] | #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)] | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ enum Derives { | |||||||
|     Canceldata, |     Canceldata, | ||||||
|     Capturedata, |     Capturedata, | ||||||
|     Start, |     Start, | ||||||
|  |     Verify, | ||||||
|     Session, |     Session, | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -30,6 +31,7 @@ impl From<String> for Derives { | |||||||
|             "capture" => Self::Capture, |             "capture" => Self::Capture, | ||||||
|             "capturedata" => Self::Capturedata, |             "capturedata" => Self::Capturedata, | ||||||
|             "start" => Self::Start, |             "start" => Self::Start, | ||||||
|  |             "verify" => Self::Verify, | ||||||
|             "session" => Self::Session, |             "session" => Self::Session, | ||||||
|             _ => Self::Authorize, |             _ => Self::Authorize, | ||||||
|         } |         } | ||||||
| @ -100,6 +102,7 @@ impl Conversion { | |||||||
|             Derives::Capture => syn::Ident::new("PaymentsCaptureRequest", Span::call_site()), |             Derives::Capture => syn::Ident::new("PaymentsCaptureRequest", Span::call_site()), | ||||||
|             Derives::Capturedata => syn::Ident::new("PaymentsCaptureData", Span::call_site()), |             Derives::Capturedata => syn::Ident::new("PaymentsCaptureData", Span::call_site()), | ||||||
|             Derives::Start => syn::Ident::new("PaymentsStartRequest", Span::call_site()), |             Derives::Start => syn::Ident::new("PaymentsStartRequest", Span::call_site()), | ||||||
|  |             Derives::Verify => syn::Ident::new("VerifyRequest", Span::call_site()), | ||||||
|             Derives::Session => syn::Ident::new("PaymentsSessionRequest", Span::call_site()), |             Derives::Session => syn::Ident::new("PaymentsSessionRequest", Span::call_site()), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -288,7 +291,8 @@ pub fn operation_derive_inner(token: proc_macro::TokenStream) -> proc_macro::Tok | |||||||
|                         PaymentsRetrieveRequest, |                         PaymentsRetrieveRequest, | ||||||
|                         PaymentsRequest, |                         PaymentsRequest, | ||||||
|                         PaymentsStartRequest, |                         PaymentsStartRequest, | ||||||
|                         PaymentsSessionRequest |                         PaymentsSessionRequest, | ||||||
|  |                         VerifyRequest | ||||||
|                     } |                     } | ||||||
|                 }; |                 }; | ||||||
|                 #trait_derive |                 #trait_derive | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Nishant Joshi
					Nishant Joshi