Repository: juspay/hyperswitch
File: crates/api_models/src/subscription.rs (Rust)

Code before:

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct CreateSubscriptionPaymentDetails {
    /// The url to which user must be redirected to after completion of the purchase
    #[schema(value_type = String)]
    pub return_url: Url,
    pub setup_future_usage: Option<FutureUsage>,
    pub capture_method: Option<CaptureMethod>,
    pub authentication_type: Option<AuthenticationType>,
    pub payment_type: Option<PaymentType>,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct PaymentDetails {
    pub payment_method: Option<PaymentMethod>,
    pub payment_method_type: Option<PaymentMethodType>,
    pub payment_method_data: Option<PaymentMethodDataRequest>,
    pub setup_future_usage: Option<FutureUsage>,
    pub customer_acceptance: Option<CustomerAcceptance>,
    /// The url to which user must be redirected to after completion of the purchase
    #[schema(value_type = Option<String>)]
    pub return_url: Option<Url>,
    pub capture_method: Option<CaptureMethod>,
    pub authentication_type: Option<AuthenticationType>,
    pub payment_type: Option<PaymentType>,
    pub payment_method_id: Option<String>,
}

impl PaymentDetails {
    pub fn validate(&self) -> Result<(), error_stack::Report<ValidationError>> {
        fp_utils::when(
            self.payment_method_data.is_none() && self.payment_method_id.is_none(),
            || {
                Err(ValidationError::MissingRequiredField {
                    field_name: String::from(
                        "either of payment_method_data or payment_method_id must be present",
                    ),
                }
                .into())
            },
        )
    }
}

// Creating new type for PaymentRequest API call as usage of api_models::PaymentsRequest will result in invalid payment request during serialization
// Eg: Amount will be serialized as { amount: {Value: 100 }}
#[derive(Debug, Clone, serde::Serialize, ToSchema)]
pub struct CreatePaymentsRequestData {
    pub amount: MinorUnit,
    pub currency: Currency,
    pub customer_id: Option<CustomerId>,

Review comment (security):
```suggestion
    pub payment_method_id: Option<Secret<String>>,
```

Code after:
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct CreateSubscriptionPaymentDetails {
    /// The url to which user must be redirected to after completion of the purchase
    #[schema(value_type = String)]
    pub return_url: Url,
    pub setup_future_usage: Option<FutureUsage>,
    pub capture_method: Option<CaptureMethod>,
    pub authentication_type: Option<AuthenticationType>,
    pub payment_type: Option<PaymentType>,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct PaymentDetails {
    pub payment_method: Option<PaymentMethod>,
    pub payment_method_type: Option<PaymentMethodType>,
    pub payment_method_data: Option<PaymentMethodDataRequest>,
    pub setup_future_usage: Option<FutureUsage>,
    pub customer_acceptance: Option<CustomerAcceptance>,
    /// The url to which user must be redirected to after completion of the purchase
    #[schema(value_type = Option<String>)]
    pub return_url: Option<Url>,
    pub capture_method: Option<CaptureMethod>,
    pub authentication_type: Option<AuthenticationType>,
    pub payment_type: Option<PaymentType>,
    #[schema(value_type = Option<String>, example = "pm_01926c58bc6e77c09e809964e72af8c8")]
    pub payment_method_id: Option<Secret<String>>,
}

impl PaymentDetails {
    pub fn validate(&self) -> Result<(), error_stack::Report<ValidationError>> {
        fp_utils::when(
            self.payment_method_data.is_none() && self.payment_method_id.is_none(),
            || {
                Err(ValidationError::MissingRequiredField {
                    field_name: String::from(
                        "Either payment_method_data or payment_method_id must be present",
                    ),
                }
                .into())
            },
        )
    }
}

// Creating new type for PaymentRequest API call as usage of api_models::PaymentsRequest will result in invalid payment request during serialization
// Eg: Amount will be serialized as { amount: {Value: 100 }}
#[derive(Debug, Clone, serde::Serialize, ToSchema)]
pub struct CreatePaymentsRequestData {
    pub amount: MinorUnit,