mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-11-04 05:59:48 +08:00 
			
		
		
		
	feat(connector): [Stripebilling] add incoming webhook support (#7417)
Co-authored-by: Nishanth Challa <nishanth.challa@Nishanth-Challa-C0WGKCFHLF.local> Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
		
				
					committed by
					
						
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							0be1f878ed
						
					
				
				
					commit
					3282444132
				
			@ -237,6 +237,7 @@ pub struct ConnectorConfig {
 | 
				
			|||||||
    pub stripe: Option<ConnectorTomlConfig>,
 | 
					    pub stripe: Option<ConnectorTomlConfig>,
 | 
				
			||||||
    #[cfg(feature = "payouts")]
 | 
					    #[cfg(feature = "payouts")]
 | 
				
			||||||
    pub stripe_payout: Option<ConnectorTomlConfig>,
 | 
					    pub stripe_payout: Option<ConnectorTomlConfig>,
 | 
				
			||||||
 | 
					    // pub stripebilling : Option<ConnectorTomlConfig>,
 | 
				
			||||||
    pub signifyd: Option<ConnectorTomlConfig>,
 | 
					    pub signifyd: Option<ConnectorTomlConfig>,
 | 
				
			||||||
    pub trustpay: Option<ConnectorTomlConfig>,
 | 
					    pub trustpay: Option<ConnectorTomlConfig>,
 | 
				
			||||||
    pub threedsecureio: Option<ConnectorTomlConfig>,
 | 
					    pub threedsecureio: Option<ConnectorTomlConfig>,
 | 
				
			||||||
@ -408,6 +409,7 @@ impl ConnectorConfig {
 | 
				
			|||||||
            Connector::Square => Ok(connector_data.square),
 | 
					            Connector::Square => Ok(connector_data.square),
 | 
				
			||||||
            Connector::Stax => Ok(connector_data.stax),
 | 
					            Connector::Stax => Ok(connector_data.stax),
 | 
				
			||||||
            Connector::Stripe => Ok(connector_data.stripe),
 | 
					            Connector::Stripe => Ok(connector_data.stripe),
 | 
				
			||||||
 | 
					            // Connector::Stripebilling => Ok(connector_data.stripebilling),
 | 
				
			||||||
            Connector::Trustpay => Ok(connector_data.trustpay),
 | 
					            Connector::Trustpay => Ok(connector_data.trustpay),
 | 
				
			||||||
            Connector::Threedsecureio => Ok(connector_data.threedsecureio),
 | 
					            Connector::Threedsecureio => Ok(connector_data.threedsecureio),
 | 
				
			||||||
            Connector::Taxjar => Ok(connector_data.taxjar),
 | 
					            Connector::Taxjar => Ok(connector_data.taxjar),
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,7 @@
 | 
				
			|||||||
pub mod transformers;
 | 
					pub mod transformers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use std::collections::HashMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use common_utils::{
 | 
					use common_utils::{
 | 
				
			||||||
    errors::CustomResult,
 | 
					    errors::CustomResult,
 | 
				
			||||||
    ext_traits::BytesExt,
 | 
					    ext_traits::BytesExt,
 | 
				
			||||||
@ -550,13 +552,89 @@ impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Stripebil
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[async_trait::async_trait]
 | 
					#[async_trait::async_trait]
 | 
				
			||||||
impl webhooks::IncomingWebhook for Stripebilling {
 | 
					impl webhooks::IncomingWebhook for Stripebilling {
 | 
				
			||||||
 | 
					    fn get_webhook_source_verification_algorithm(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
 | 
				
			||||||
 | 
					    ) -> CustomResult<Box<dyn common_utils::crypto::VerifySignature + Send>, errors::ConnectorError>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Ok(Box::new(common_utils::crypto::HmacSha256))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn get_webhook_source_verification_signature(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        request: &webhooks::IncomingWebhookRequestDetails<'_>,
 | 
				
			||||||
 | 
					        _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
 | 
				
			||||||
 | 
					    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
 | 
				
			||||||
 | 
					        let mut header_hashmap = get_signature_elements_from_header(request.headers)?;
 | 
				
			||||||
 | 
					        let signature = header_hashmap
 | 
				
			||||||
 | 
					            .remove("v1")
 | 
				
			||||||
 | 
					            .ok_or(errors::ConnectorError::WebhookSignatureNotFound)?;
 | 
				
			||||||
 | 
					        hex::decode(signature).change_context(errors::ConnectorError::WebhookSignatureNotFound)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn get_webhook_source_verification_message(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        request: &webhooks::IncomingWebhookRequestDetails<'_>,
 | 
				
			||||||
 | 
					        _merchant_id: &common_utils::id_type::MerchantId,
 | 
				
			||||||
 | 
					        _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
 | 
				
			||||||
 | 
					    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
 | 
				
			||||||
 | 
					        let mut header_hashmap = get_signature_elements_from_header(request.headers)?;
 | 
				
			||||||
 | 
					        let timestamp = header_hashmap
 | 
				
			||||||
 | 
					            .remove("t")
 | 
				
			||||||
 | 
					            .ok_or(errors::ConnectorError::WebhookSignatureNotFound)?;
 | 
				
			||||||
 | 
					        Ok(format!(
 | 
				
			||||||
 | 
					            "{}.{}",
 | 
				
			||||||
 | 
					            String::from_utf8_lossy(×tamp),
 | 
				
			||||||
 | 
					            String::from_utf8_lossy(request.body)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .into_bytes())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[cfg(all(feature = "revenue_recovery", feature = "v2"))]
 | 
				
			||||||
 | 
					    fn get_webhook_object_reference_id(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        request: &webhooks::IncomingWebhookRequestDetails<'_>,
 | 
				
			||||||
 | 
					    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
 | 
				
			||||||
 | 
					        //  For Stripe billing, we need an additional call to fetch the required recovery data. So, instead of the Invoice ID, we send the Charge ID.
 | 
				
			||||||
 | 
					        let webhook =
 | 
				
			||||||
 | 
					            stripebilling::StripebillingWebhookBody::get_webhook_object_from_body(request.body)
 | 
				
			||||||
 | 
					                .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
 | 
				
			||||||
 | 
					        Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
 | 
				
			||||||
 | 
					            api_models::payments::PaymentIdType::ConnectorTransactionId(webhook.data.object.charge),
 | 
				
			||||||
 | 
					        ))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[cfg(any(feature = "v1", not(all(feature = "revenue_recovery", feature = "v2"))))]
 | 
				
			||||||
    fn get_webhook_object_reference_id(
 | 
					    fn get_webhook_object_reference_id(
 | 
				
			||||||
        &self,
 | 
					        &self,
 | 
				
			||||||
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
 | 
					        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
 | 
				
			||||||
    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
 | 
					    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
 | 
				
			||||||
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
 | 
					        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    #[cfg(all(feature = "revenue_recovery", feature = "v2"))]
 | 
				
			||||||
 | 
					    fn get_webhook_event_type(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        request: &webhooks::IncomingWebhookRequestDetails<'_>,
 | 
				
			||||||
 | 
					    ) -> CustomResult<api_models::webhooks::IncomingWebhookEvent, errors::ConnectorError> {
 | 
				
			||||||
 | 
					        let webhook =
 | 
				
			||||||
 | 
					            stripebilling::StripebillingWebhookBody::get_webhook_object_from_body(request.body)
 | 
				
			||||||
 | 
					                .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let event = match webhook.event_type {
 | 
				
			||||||
 | 
					            stripebilling::StripebillingEventType::PaymentSucceeded => {
 | 
				
			||||||
 | 
					                api_models::webhooks::IncomingWebhookEvent::RecoveryPaymentSuccess
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            stripebilling::StripebillingEventType::PaymentFailed => {
 | 
				
			||||||
 | 
					                api_models::webhooks::IncomingWebhookEvent::RecoveryPaymentFailure
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            stripebilling::StripebillingEventType::InvoiceDeleted => {
 | 
				
			||||||
 | 
					                api_models::webhooks::IncomingWebhookEvent::RecoveryInvoiceCancel
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        Ok(event)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[cfg(any(feature = "v1", not(all(feature = "revenue_recovery", feature = "v2"))))]
 | 
				
			||||||
    fn get_webhook_event_type(
 | 
					    fn get_webhook_event_type(
 | 
				
			||||||
        &self,
 | 
					        &self,
 | 
				
			||||||
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
 | 
					        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
 | 
				
			||||||
@ -564,12 +642,47 @@ impl webhooks::IncomingWebhook for Stripebilling {
 | 
				
			|||||||
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
 | 
					        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[cfg(any(feature = "v1", not(all(feature = "revenue_recovery", feature = "v2"))))]
 | 
				
			||||||
    fn get_webhook_resource_object(
 | 
					    fn get_webhook_resource_object(
 | 
				
			||||||
        &self,
 | 
					        &self,
 | 
				
			||||||
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
 | 
					        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
 | 
				
			||||||
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
 | 
					    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
 | 
				
			||||||
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
 | 
					        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[cfg(all(feature = "revenue_recovery", feature = "v2"))]
 | 
				
			||||||
 | 
					    fn get_webhook_resource_object(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        request: &webhooks::IncomingWebhookRequestDetails<'_>,
 | 
				
			||||||
 | 
					    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
 | 
				
			||||||
 | 
					        let webhook = stripebilling::StripebillingInvoiceBody::get_invoice_webhook_data_from_body(
 | 
				
			||||||
 | 
					            request.body,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
 | 
				
			||||||
 | 
					        Ok(Box::new(webhook))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn get_signature_elements_from_header(
 | 
				
			||||||
 | 
					    headers: &actix_web::http::header::HeaderMap,
 | 
				
			||||||
 | 
					) -> CustomResult<HashMap<String, Vec<u8>>, errors::ConnectorError> {
 | 
				
			||||||
 | 
					    let security_header = headers
 | 
				
			||||||
 | 
					        .get("stripe-signature")
 | 
				
			||||||
 | 
					        .ok_or(errors::ConnectorError::WebhookSignatureNotFound)?;
 | 
				
			||||||
 | 
					    let security_header_str = security_header
 | 
				
			||||||
 | 
					        .to_str()
 | 
				
			||||||
 | 
					        .change_context(errors::ConnectorError::WebhookSignatureNotFound)?;
 | 
				
			||||||
 | 
					    let header_parts = security_header_str.split(',').collect::<Vec<&str>>();
 | 
				
			||||||
 | 
					    let mut header_hashmap: HashMap<String, Vec<u8>> = HashMap::with_capacity(header_parts.len());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for header_part in header_parts {
 | 
				
			||||||
 | 
					        let (header_key, header_value) = header_part
 | 
				
			||||||
 | 
					            .split_once('=')
 | 
				
			||||||
 | 
					            .ok_or(errors::ConnectorError::WebhookSignatureNotFound)?;
 | 
				
			||||||
 | 
					        header_hashmap.insert(header_key.to_string(), header_value.bytes().collect());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(header_hashmap)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ConnectorSpecifications for Stripebilling {}
 | 
					impl ConnectorSpecifications for Stripebilling {}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,11 @@
 | 
				
			|||||||
 | 
					#[cfg(feature = "v2")]
 | 
				
			||||||
 | 
					use std::str::FromStr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use common_enums::enums;
 | 
					use common_enums::enums;
 | 
				
			||||||
use common_utils::types::StringMinorUnit;
 | 
					use common_utils::{errors::CustomResult, ext_traits::ByteSliceExt, types::StringMinorUnit};
 | 
				
			||||||
 | 
					use error_stack::ResultExt;
 | 
				
			||||||
 | 
					#[cfg(all(feature = "revenue_recovery", feature = "v2"))]
 | 
				
			||||||
 | 
					use hyperswitch_domain_models::revenue_recovery;
 | 
				
			||||||
use hyperswitch_domain_models::{
 | 
					use hyperswitch_domain_models::{
 | 
				
			||||||
    payment_method_data::PaymentMethodData,
 | 
					    payment_method_data::PaymentMethodData,
 | 
				
			||||||
    router_data::{ConnectorAuthType, RouterData},
 | 
					    router_data::{ConnectorAuthType, RouterData},
 | 
				
			||||||
@ -14,7 +20,7 @@ use serde::{Deserialize, Serialize};
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    types::{RefundsResponseRouterData, ResponseRouterData},
 | 
					    types::{RefundsResponseRouterData, ResponseRouterData},
 | 
				
			||||||
    utils::PaymentsAuthorizeRequestData,
 | 
					    utils::{convert_uppercase, PaymentsAuthorizeRequestData},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//TODO: Fill the struct with respective fields
 | 
					//TODO: Fill the struct with respective fields
 | 
				
			||||||
@ -94,7 +100,7 @@ impl TryFrom<&ConnectorAuthType> for StripebillingAuthType {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
// PaymentsResponse
 | 
					// PaymentsResponse
 | 
				
			||||||
//TODO: Append the remaining status flags
 | 
					//TODO: Append the remaining status flags
 | 
				
			||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
 | 
					#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Copy)]
 | 
				
			||||||
#[serde(rename_all = "lowercase")]
 | 
					#[serde(rename_all = "lowercase")]
 | 
				
			||||||
pub enum StripebillingPaymentStatus {
 | 
					pub enum StripebillingPaymentStatus {
 | 
				
			||||||
    Succeeded,
 | 
					    Succeeded,
 | 
				
			||||||
@ -166,7 +172,7 @@ impl<F> TryFrom<&StripebillingRouterData<&RefundsRouterData<F>>> for Stripebilli
 | 
				
			|||||||
// Type definition for Refund Response
 | 
					// Type definition for Refund Response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[allow(dead_code)]
 | 
					#[allow(dead_code)]
 | 
				
			||||||
#[derive(Debug, Serialize, Default, Deserialize, Clone)]
 | 
					#[derive(Debug, Serialize, Default, Deserialize, Clone, Copy)]
 | 
				
			||||||
pub enum RefundStatus {
 | 
					pub enum RefundStatus {
 | 
				
			||||||
    Succeeded,
 | 
					    Succeeded,
 | 
				
			||||||
    Failed,
 | 
					    Failed,
 | 
				
			||||||
@ -230,3 +236,136 @@ pub struct StripebillingErrorResponse {
 | 
				
			|||||||
    pub message: String,
 | 
					    pub message: String,
 | 
				
			||||||
    pub reason: Option<String>,
 | 
					    pub reason: Option<String>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Serialize, Deserialize)]
 | 
				
			||||||
 | 
					pub struct StripebillingWebhookBody {
 | 
				
			||||||
 | 
					    #[serde(rename = "type")]
 | 
				
			||||||
 | 
					    pub event_type: StripebillingEventType,
 | 
				
			||||||
 | 
					    pub data: StripebillingWebhookData,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Serialize, Deserialize)]
 | 
				
			||||||
 | 
					pub struct StripebillingInvoiceBody {
 | 
				
			||||||
 | 
					    #[serde(rename = "type")]
 | 
				
			||||||
 | 
					    pub event_type: StripebillingEventType,
 | 
				
			||||||
 | 
					    pub data: StripebillingInvoiceData,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
 | 
				
			||||||
 | 
					#[serde(rename_all = "snake_case")]
 | 
				
			||||||
 | 
					pub enum StripebillingEventType {
 | 
				
			||||||
 | 
					    #[serde(rename = "invoice.paid")]
 | 
				
			||||||
 | 
					    PaymentSucceeded,
 | 
				
			||||||
 | 
					    #[serde(rename = "invoice.payment_failed")]
 | 
				
			||||||
 | 
					    PaymentFailed,
 | 
				
			||||||
 | 
					    #[serde(rename = "invoice.voided")]
 | 
				
			||||||
 | 
					    InvoiceDeleted,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Serialize, Deserialize, Debug)]
 | 
				
			||||||
 | 
					pub struct StripebillingWebhookData {
 | 
				
			||||||
 | 
					    pub object: StripebillingWebhookObject,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Serialize, Deserialize, Debug)]
 | 
				
			||||||
 | 
					pub struct StripebillingInvoiceData {
 | 
				
			||||||
 | 
					    pub object: StripebillingWebhookObject,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Serialize, Deserialize, Debug)]
 | 
				
			||||||
 | 
					pub struct StripebillingWebhookObject {
 | 
				
			||||||
 | 
					    #[serde(rename = "id")]
 | 
				
			||||||
 | 
					    pub invoice_id: String,
 | 
				
			||||||
 | 
					    #[serde(deserialize_with = "convert_uppercase")]
 | 
				
			||||||
 | 
					    pub currency: enums::Currency,
 | 
				
			||||||
 | 
					    pub customer: String,
 | 
				
			||||||
 | 
					    #[serde(rename = "amount_remaining")]
 | 
				
			||||||
 | 
					    pub amount: common_utils::types::MinorUnit,
 | 
				
			||||||
 | 
					    pub charge: String,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Serialize, Deserialize)]
 | 
				
			||||||
 | 
					pub struct StripebillingInvoiceObject {
 | 
				
			||||||
 | 
					    #[serde(rename = "id")]
 | 
				
			||||||
 | 
					    pub invoice_id: String,
 | 
				
			||||||
 | 
					    #[serde(deserialize_with = "convert_uppercase")]
 | 
				
			||||||
 | 
					    pub currency: enums::Currency,
 | 
				
			||||||
 | 
					    #[serde(rename = "amount_remaining")]
 | 
				
			||||||
 | 
					    pub amount: common_utils::types::MinorUnit,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Serialize, Deserialize, Debug, Clone)]
 | 
				
			||||||
 | 
					pub struct StripePaymentMethodDetails {
 | 
				
			||||||
 | 
					    #[serde(rename = "type")]
 | 
				
			||||||
 | 
					    pub type_of_payment_method: StripebillingPaymentMethod,
 | 
				
			||||||
 | 
					    #[serde(rename = "card")]
 | 
				
			||||||
 | 
					    pub card_funding_type: StripeCardFundingTypeDetails,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
 | 
				
			||||||
 | 
					#[serde(rename_all = "snake_case")]
 | 
				
			||||||
 | 
					pub enum StripebillingPaymentMethod {
 | 
				
			||||||
 | 
					    Card,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Serialize, Deserialize, Debug, Clone)]
 | 
				
			||||||
 | 
					pub struct StripeCardFundingTypeDetails {
 | 
				
			||||||
 | 
					    pub funding: StripebillingFundingTypes,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
 | 
				
			||||||
 | 
					#[serde(rename = "snake_case")]
 | 
				
			||||||
 | 
					pub enum StripebillingFundingTypes {
 | 
				
			||||||
 | 
					    #[serde(rename = "credit")]
 | 
				
			||||||
 | 
					    Credit,
 | 
				
			||||||
 | 
					    #[serde(rename = "debit")]
 | 
				
			||||||
 | 
					    Debit,
 | 
				
			||||||
 | 
					    #[serde(rename = "prepaid")]
 | 
				
			||||||
 | 
					    Prepaid,
 | 
				
			||||||
 | 
					    #[serde(rename = "unknown")]
 | 
				
			||||||
 | 
					    Unknown,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
 | 
				
			||||||
 | 
					#[serde(rename_all = "snake_case")]
 | 
				
			||||||
 | 
					pub enum StripebillingChargeStatus {
 | 
				
			||||||
 | 
					    Succeeded,
 | 
				
			||||||
 | 
					    Failed,
 | 
				
			||||||
 | 
					    Pending,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl StripebillingWebhookBody {
 | 
				
			||||||
 | 
					    pub fn get_webhook_object_from_body(body: &[u8]) -> CustomResult<Self, errors::ConnectorError> {
 | 
				
			||||||
 | 
					        let webhook_body: Self = body
 | 
				
			||||||
 | 
					            .parse_struct::<Self>("StripebillingWebhookBody")
 | 
				
			||||||
 | 
					            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(webhook_body)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl StripebillingInvoiceBody {
 | 
				
			||||||
 | 
					    pub fn get_invoice_webhook_data_from_body(
 | 
				
			||||||
 | 
					        body: &[u8],
 | 
				
			||||||
 | 
					    ) -> CustomResult<Self, errors::ConnectorError> {
 | 
				
			||||||
 | 
					        let webhook_body = body
 | 
				
			||||||
 | 
					            .parse_struct::<Self>("StripebillingInvoiceBody")
 | 
				
			||||||
 | 
					            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
 | 
				
			||||||
 | 
					        Ok(webhook_body)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(all(feature = "revenue_recovery", feature = "v2"))]
 | 
				
			||||||
 | 
					impl TryFrom<StripebillingInvoiceBody> for revenue_recovery::RevenueRecoveryInvoiceData {
 | 
				
			||||||
 | 
					    type Error = error_stack::Report<errors::ConnectorError>;
 | 
				
			||||||
 | 
					    fn try_from(item: StripebillingInvoiceBody) -> Result<Self, Self::Error> {
 | 
				
			||||||
 | 
					        let merchant_reference_id =
 | 
				
			||||||
 | 
					            common_utils::id_type::PaymentReferenceId::from_str(&item.data.object.invoice_id)
 | 
				
			||||||
 | 
					                .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
 | 
				
			||||||
 | 
					        Ok(Self {
 | 
				
			||||||
 | 
					            amount: item.data.object.amount,
 | 
				
			||||||
 | 
					            currency: item.data.object.currency,
 | 
				
			||||||
 | 
					            merchant_reference_id,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,7 @@
 | 
				
			|||||||
use std::collections::{HashMap, HashSet};
 | 
					use std::{
 | 
				
			||||||
 | 
					    collections::{HashMap, HashSet},
 | 
				
			||||||
 | 
					    str::FromStr,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use api_models::payments;
 | 
					use api_models::payments;
 | 
				
			||||||
#[cfg(feature = "payouts")]
 | 
					#[cfg(feature = "payouts")]
 | 
				
			||||||
@ -58,6 +61,7 @@ use masking::{ExposeInterface, PeekInterface, Secret};
 | 
				
			|||||||
use once_cell::sync::Lazy;
 | 
					use once_cell::sync::Lazy;
 | 
				
			||||||
use regex::Regex;
 | 
					use regex::Regex;
 | 
				
			||||||
use router_env::logger;
 | 
					use router_env::logger;
 | 
				
			||||||
 | 
					use serde::Deserialize;
 | 
				
			||||||
use serde_json::Value;
 | 
					use serde_json::Value;
 | 
				
			||||||
use time::PrimitiveDateTime;
 | 
					use time::PrimitiveDateTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -5840,3 +5844,14 @@ impl NetworkTokenData for payment_method_data::NetworkTokenData {
 | 
				
			|||||||
        self.cryptogram.clone()
 | 
					        self.cryptogram.clone()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn convert_uppercase<'de, D, T>(v: D) -> Result<T, D::Error>
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    D: serde::Deserializer<'de>,
 | 
				
			||||||
 | 
					    T: FromStr,
 | 
				
			||||||
 | 
					    <T as FromStr>::Err: std::fmt::Debug + std::fmt::Display + std::error::Error,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use serde::de::Error;
 | 
				
			||||||
 | 
					    let output = <&str>::deserialize(v)?;
 | 
				
			||||||
 | 
					    output.to_uppercase().parse::<T>().map_err(D::Error::custom)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1559,6 +1559,10 @@ impl ConnectorAuthTypeAndMetadataValidation<'_> {
 | 
				
			|||||||
                stripe::transformers::StripeAuthType::try_from(self.auth_type)?;
 | 
					                stripe::transformers::StripeAuthType::try_from(self.auth_type)?;
 | 
				
			||||||
                Ok(())
 | 
					                Ok(())
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            // api_enums::Connector::Stripebilling => {
 | 
				
			||||||
 | 
					            //     stripebilling::transformers::StripebillingAuthType::try_from(self.auth_type)?;
 | 
				
			||||||
 | 
					            //     Ok(())
 | 
				
			||||||
 | 
					            // }
 | 
				
			||||||
            api_enums::Connector::Trustpay => {
 | 
					            api_enums::Connector::Trustpay => {
 | 
				
			||||||
                trustpay::transformers::TrustpayAuthType::try_from(self.auth_type)?;
 | 
					                trustpay::transformers::TrustpayAuthType::try_from(self.auth_type)?;
 | 
				
			||||||
                Ok(())
 | 
					                Ok(())
 | 
				
			||||||
 | 
				
			|||||||
@ -538,7 +538,9 @@ impl ConnectorData {
 | 
				
			|||||||
                enums::Connector::Stripe => {
 | 
					                enums::Connector::Stripe => {
 | 
				
			||||||
                    Ok(ConnectorEnum::Old(Box::new(connector::Stripe::new())))
 | 
					                    Ok(ConnectorEnum::Old(Box::new(connector::Stripe::new())))
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                // enums::Connector::Stripebilling => Ok(ConnectorEnum::Old(Box::new(connector::Stripebilling))),
 | 
					                // enums::Connector::Stripebilling =>{
 | 
				
			||||||
 | 
					                //     Ok(ConnectorEnum::Old(Box::new(connector::Stripebilling::new())))
 | 
				
			||||||
 | 
					                // },
 | 
				
			||||||
                enums::Connector::Wise => Ok(ConnectorEnum::Old(Box::new(connector::Wise::new()))),
 | 
					                enums::Connector::Wise => Ok(ConnectorEnum::Old(Box::new(connector::Wise::new()))),
 | 
				
			||||||
                enums::Connector::Worldline => {
 | 
					                enums::Connector::Worldline => {
 | 
				
			||||||
                    Ok(ConnectorEnum::Old(Box::new(&connector::Worldline)))
 | 
					                    Ok(ConnectorEnum::Old(Box::new(&connector::Worldline)))
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user