mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-27 19:46:48 +08:00
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
266 lines
9.5 KiB
Rust
266 lines
9.5 KiB
Rust
use std::fmt::Debug;
|
|
|
|
#[cfg(feature = "payouts")]
|
|
use api_models::payouts;
|
|
use api_models::{enums as api_enums, payment_methods as api};
|
|
use common_enums::enums as common_enums;
|
|
#[cfg(feature = "v2")]
|
|
use common_utils::encryption;
|
|
use common_utils::{crypto, ext_traits, id_type, type_name, types::keymanager};
|
|
use error_stack::ResultExt;
|
|
use hyperswitch_domain_models::{merchant_key_store, payment_methods, type_encryption};
|
|
use masking::{PeekInterface, Secret};
|
|
use scheduler::errors as sch_errors;
|
|
use serde::{Deserialize, Serialize};
|
|
use storage_impl::{errors as storage_errors, payment_method};
|
|
|
|
use crate::core::errors;
|
|
|
|
#[derive(Debug, Deserialize, Serialize)]
|
|
pub struct DeleteCardResp {
|
|
pub status: String,
|
|
pub error_message: Option<String>,
|
|
pub error_code: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, Serialize, PartialEq)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub enum DataDuplicationCheck {
|
|
Duplicated,
|
|
MetaDataChanged,
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
pub trait PaymentMethodsController {
|
|
#[cfg(feature = "v1")]
|
|
#[allow(clippy::too_many_arguments)]
|
|
async fn create_payment_method(
|
|
&self,
|
|
req: &api::PaymentMethodCreate,
|
|
customer_id: &id_type::CustomerId,
|
|
payment_method_id: &str,
|
|
locker_id: Option<String>,
|
|
merchant_id: &id_type::MerchantId,
|
|
pm_metadata: Option<serde_json::Value>,
|
|
customer_acceptance: Option<serde_json::Value>,
|
|
payment_method_data: crypto::OptionalEncryptableValue,
|
|
connector_mandate_details: Option<serde_json::Value>,
|
|
status: Option<common_enums::PaymentMethodStatus>,
|
|
network_transaction_id: Option<String>,
|
|
payment_method_billing_address: crypto::OptionalEncryptableValue,
|
|
card_scheme: Option<String>,
|
|
network_token_requestor_reference_id: Option<String>,
|
|
network_token_locker_id: Option<String>,
|
|
network_token_payment_method_data: crypto::OptionalEncryptableValue,
|
|
) -> errors::PmResult<payment_methods::PaymentMethod>;
|
|
|
|
#[cfg(feature = "v1")]
|
|
#[allow(clippy::too_many_arguments)]
|
|
async fn insert_payment_method(
|
|
&self,
|
|
resp: &api::PaymentMethodResponse,
|
|
req: &api::PaymentMethodCreate,
|
|
key_store: &merchant_key_store::MerchantKeyStore,
|
|
merchant_id: &id_type::MerchantId,
|
|
customer_id: &id_type::CustomerId,
|
|
pm_metadata: Option<serde_json::Value>,
|
|
customer_acceptance: Option<serde_json::Value>,
|
|
locker_id: Option<String>,
|
|
connector_mandate_details: Option<serde_json::Value>,
|
|
network_transaction_id: Option<String>,
|
|
payment_method_billing_address: crypto::OptionalEncryptableValue,
|
|
network_token_requestor_reference_id: Option<String>,
|
|
network_token_locker_id: Option<String>,
|
|
network_token_payment_method_data: crypto::OptionalEncryptableValue,
|
|
) -> errors::PmResult<payment_methods::PaymentMethod>;
|
|
|
|
#[cfg(feature = "v2")]
|
|
#[allow(clippy::too_many_arguments)]
|
|
async fn insert_payment_method(
|
|
&self,
|
|
resp: &api::PaymentMethodResponse,
|
|
req: &api::PaymentMethodCreate,
|
|
key_store: &merchant_key_store::MerchantKeyStore,
|
|
merchant_id: &id_type::MerchantId,
|
|
customer_id: &id_type::CustomerId,
|
|
pm_metadata: Option<serde_json::Value>,
|
|
customer_acceptance: Option<serde_json::Value>,
|
|
locker_id: Option<String>,
|
|
connector_mandate_details: Option<serde_json::Value>,
|
|
network_transaction_id: Option<String>,
|
|
payment_method_billing_address: Option<encryption::Encryption>,
|
|
) -> errors::PmResult<payment_methods::PaymentMethod>;
|
|
|
|
#[cfg(feature = "v1")]
|
|
async fn add_payment_method(
|
|
&self,
|
|
req: &api::PaymentMethodCreate,
|
|
) -> errors::PmResponse<api::PaymentMethodResponse>;
|
|
|
|
#[cfg(feature = "v1")]
|
|
async fn retrieve_payment_method(
|
|
&self,
|
|
pm: api::PaymentMethodId,
|
|
) -> errors::PmResponse<api::PaymentMethodResponse>;
|
|
|
|
#[cfg(feature = "v1")]
|
|
async fn delete_payment_method(
|
|
&self,
|
|
pm_id: api::PaymentMethodId,
|
|
) -> errors::PmResponse<api::PaymentMethodDeleteResponse>;
|
|
|
|
async fn add_card_hs(
|
|
&self,
|
|
req: api::PaymentMethodCreate,
|
|
card: &api::CardDetail,
|
|
customer_id: &id_type::CustomerId,
|
|
locker_choice: api_enums::LockerChoice,
|
|
card_reference: Option<&str>,
|
|
) -> errors::VaultResult<(api::PaymentMethodResponse, Option<DataDuplicationCheck>)>;
|
|
|
|
/// The response will be the tuple of PaymentMethodResponse and the duplication check of payment_method
|
|
async fn add_card_to_locker(
|
|
&self,
|
|
req: api::PaymentMethodCreate,
|
|
card: &api::CardDetail,
|
|
customer_id: &id_type::CustomerId,
|
|
card_reference: Option<&str>,
|
|
) -> errors::VaultResult<(api::PaymentMethodResponse, Option<DataDuplicationCheck>)>;
|
|
|
|
#[cfg(feature = "payouts")]
|
|
async fn add_bank_to_locker(
|
|
&self,
|
|
req: api::PaymentMethodCreate,
|
|
key_store: &merchant_key_store::MerchantKeyStore,
|
|
bank: &payouts::Bank,
|
|
customer_id: &id_type::CustomerId,
|
|
) -> errors::VaultResult<(api::PaymentMethodResponse, Option<DataDuplicationCheck>)>;
|
|
|
|
#[cfg(feature = "v1")]
|
|
async fn get_or_insert_payment_method(
|
|
&self,
|
|
req: api::PaymentMethodCreate,
|
|
resp: &mut api::PaymentMethodResponse,
|
|
customer_id: &id_type::CustomerId,
|
|
key_store: &merchant_key_store::MerchantKeyStore,
|
|
) -> errors::PmResult<payment_methods::PaymentMethod>;
|
|
|
|
#[cfg(feature = "v2")]
|
|
async fn get_or_insert_payment_method(
|
|
&self,
|
|
req: api::PaymentMethodCreate,
|
|
resp: &mut api::PaymentMethodResponse,
|
|
customer_id: &id_type::CustomerId,
|
|
key_store: &merchant_key_store::MerchantKeyStore,
|
|
) -> errors::PmResult<payment_methods::PaymentMethod> {
|
|
todo!()
|
|
}
|
|
|
|
#[cfg(feature = "v1")]
|
|
async fn get_card_details_with_locker_fallback(
|
|
&self,
|
|
pm: &payment_methods::PaymentMethod,
|
|
) -> errors::PmResult<Option<api::CardDetailFromLocker>>;
|
|
|
|
#[cfg(feature = "v1")]
|
|
async fn get_card_details_without_locker_fallback(
|
|
&self,
|
|
pm: &payment_methods::PaymentMethod,
|
|
) -> errors::PmResult<api::CardDetailFromLocker>;
|
|
|
|
async fn delete_card_from_locker(
|
|
&self,
|
|
customer_id: &id_type::CustomerId,
|
|
merchant_id: &id_type::MerchantId,
|
|
card_reference: &str,
|
|
) -> errors::PmResult<DeleteCardResp>;
|
|
|
|
#[cfg(feature = "v1")]
|
|
fn store_default_payment_method(
|
|
&self,
|
|
req: &api::PaymentMethodCreate,
|
|
customer_id: &id_type::CustomerId,
|
|
merchant_id: &id_type::MerchantId,
|
|
) -> (api::PaymentMethodResponse, Option<DataDuplicationCheck>);
|
|
|
|
#[cfg(feature = "v2")]
|
|
fn store_default_payment_method(
|
|
&self,
|
|
req: &api::PaymentMethodCreate,
|
|
customer_id: &id_type::CustomerId,
|
|
merchant_id: &id_type::MerchantId,
|
|
) -> (api::PaymentMethodResponse, Option<DataDuplicationCheck>);
|
|
|
|
#[cfg(feature = "v1")]
|
|
#[allow(clippy::too_many_arguments)]
|
|
async fn save_network_token_and_update_payment_method(
|
|
&self,
|
|
req: &api::PaymentMethodMigrate,
|
|
key_store: &merchant_key_store::MerchantKeyStore,
|
|
network_token_data: &api_models::payment_methods::MigrateNetworkTokenData,
|
|
network_token_requestor_ref_id: String,
|
|
pm_id: String,
|
|
) -> errors::PmResult<bool>;
|
|
|
|
#[cfg(feature = "v1")]
|
|
async fn set_default_payment_method(
|
|
&self,
|
|
merchant_id: &id_type::MerchantId,
|
|
customer_id: &id_type::CustomerId,
|
|
payment_method_id: String,
|
|
) -> errors::PmResponse<api_models::payment_methods::CustomerDefaultPaymentMethodResponse>;
|
|
|
|
#[cfg(feature = "v1")]
|
|
async fn add_payment_method_status_update_task(
|
|
&self,
|
|
payment_method: &payment_methods::PaymentMethod,
|
|
prev_status: common_enums::PaymentMethodStatus,
|
|
curr_status: common_enums::PaymentMethodStatus,
|
|
merchant_id: &id_type::MerchantId,
|
|
) -> Result<(), sch_errors::ProcessTrackerError>;
|
|
|
|
#[cfg(feature = "v1")]
|
|
async fn validate_merchant_connector_ids_in_connector_mandate_details(
|
|
&self,
|
|
key_store: &merchant_key_store::MerchantKeyStore,
|
|
connector_mandate_details: &api_models::payment_methods::CommonMandateReference,
|
|
merchant_id: &id_type::MerchantId,
|
|
card_network: Option<common_enums::CardNetwork>,
|
|
) -> errors::PmResult<()>;
|
|
}
|
|
|
|
pub async fn create_encrypted_data<T>(
|
|
key_manager_state: &keymanager::KeyManagerState,
|
|
key_store: &merchant_key_store::MerchantKeyStore,
|
|
data: T,
|
|
) -> Result<
|
|
crypto::Encryptable<Secret<serde_json::Value>>,
|
|
error_stack::Report<storage_errors::StorageError>,
|
|
>
|
|
where
|
|
T: Debug + Serialize,
|
|
{
|
|
let key = key_store.key.get_inner().peek();
|
|
let identifier = keymanager::Identifier::Merchant(key_store.merchant_id.clone());
|
|
|
|
let encoded_data = ext_traits::Encode::encode_to_value(&data)
|
|
.change_context(storage_errors::StorageError::SerializationFailed)
|
|
.attach_printable("Unable to encode data")?;
|
|
|
|
let secret_data = Secret::<_, masking::WithType>::new(encoded_data);
|
|
|
|
let encrypted_data = type_encryption::crypto_operation(
|
|
key_manager_state,
|
|
type_name!(payment_method::PaymentMethod),
|
|
type_encryption::CryptoOperation::Encrypt(secret_data),
|
|
identifier.clone(),
|
|
key,
|
|
)
|
|
.await
|
|
.and_then(|val| val.try_into_operation())
|
|
.change_context(storage_errors::StorageError::EncryptionError)
|
|
.attach_printable("Unable to encrypt data")?;
|
|
|
|
Ok(encrypted_data)
|
|
}
|