Skip to content

Commit

Permalink
refactor(payments_v2): create customer at connector end and populate …
Browse files Browse the repository at this point in the history
…connector customer ID (#7246)
  • Loading branch information
SanchithHegde authored Feb 14, 2025
1 parent 3c7cb9e commit 17f9e6e
Show file tree
Hide file tree
Showing 11 changed files with 356 additions and 114 deletions.
42 changes: 32 additions & 10 deletions crates/diesel_models/src/customers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,7 @@ impl From<CustomerNew> for Customer {

#[cfg(all(feature = "v2", feature = "customer_v2"))]
#[derive(
Clone,
Debug,
PartialEq,
Insertable,
router_derive::DebugAsDisplay,
serde::Deserialize,
serde::Serialize,
Clone, Debug, Insertable, router_derive::DebugAsDisplay, serde::Deserialize, serde::Serialize,
)]
#[diesel(table_name = customers, primary_key(id))]
pub struct CustomerNew {
Expand All @@ -82,7 +76,7 @@ pub struct CustomerNew {
pub description: Option<Description>,
pub created_at: PrimitiveDateTime,
pub metadata: Option<pii::SecretSerdeValue>,
pub connector_customer: Option<pii::SecretSerdeValue>,
pub connector_customer: Option<ConnectorCustomerMap>,
pub modified_at: PrimitiveDateTime,
pub default_payment_method_id: Option<common_utils::id_type::GlobalPaymentMethodId>,
pub updated_by: Option<String>,
Expand Down Expand Up @@ -164,7 +158,7 @@ pub struct Customer {
pub description: Option<Description>,
pub created_at: PrimitiveDateTime,
pub metadata: Option<pii::SecretSerdeValue>,
pub connector_customer: Option<pii::SecretSerdeValue>,
pub connector_customer: Option<ConnectorCustomerMap>,
pub modified_at: PrimitiveDateTime,
pub default_payment_method_id: Option<common_utils::id_type::GlobalPaymentMethodId>,
pub updated_by: Option<String>,
Expand Down Expand Up @@ -242,7 +236,7 @@ pub struct CustomerUpdateInternal {
pub phone_country_code: Option<String>,
pub metadata: Option<pii::SecretSerdeValue>,
pub modified_at: PrimitiveDateTime,
pub connector_customer: Option<pii::SecretSerdeValue>,
pub connector_customer: Option<ConnectorCustomerMap>,
pub default_payment_method_id: Option<Option<common_utils::id_type::GlobalPaymentMethodId>>,
pub updated_by: Option<String>,
pub default_billing_address: Option<Encryption>,
Expand Down Expand Up @@ -289,3 +283,31 @@ impl CustomerUpdateInternal {
}
}
}

#[cfg(all(feature = "v2", feature = "customer_v2"))]
#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize, diesel::AsExpression)]
#[diesel(sql_type = diesel::sql_types::Jsonb)]
#[serde(transparent)]
pub struct ConnectorCustomerMap(
std::collections::HashMap<common_utils::id_type::MerchantConnectorAccountId, String>,
);

#[cfg(all(feature = "v2", feature = "customer_v2"))]
common_utils::impl_to_sql_from_sql_json!(ConnectorCustomerMap);

#[cfg(all(feature = "v2", feature = "customer_v2"))]
impl std::ops::Deref for ConnectorCustomerMap {
type Target =
std::collections::HashMap<common_utils::id_type::MerchantConnectorAccountId, String>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

#[cfg(all(feature = "v2", feature = "customer_v2"))]
impl std::ops::DerefMut for ConnectorCustomerMap {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
2 changes: 1 addition & 1 deletion crates/hyperswitch_domain_models/src/business_profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -985,7 +985,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
is_network_tokenization_enabled,
is_auto_retries_enabled: None,
max_auto_retries_enabled: None,
is_click_to_pay_enabled: None,
is_click_to_pay_enabled,
authentication_product_ids,
three_ds_decision_manager_config,
}
Expand Down
116 changes: 74 additions & 42 deletions crates/hyperswitch_domain_models/src/customer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ pub struct Customer {
pub description: Option<Description>,
pub created_at: PrimitiveDateTime,
pub metadata: Option<pii::SecretSerdeValue>,
pub connector_customer: Option<pii::SecretSerdeValue>,
pub connector_customer: Option<diesel_models::ConnectorCustomerMap>,
pub modified_at: PrimitiveDateTime,
pub default_payment_method_id: Option<id_type::GlobalPaymentMethodId>,
pub updated_by: Option<String>,
Expand All @@ -80,6 +80,31 @@ impl Customer {
pub fn get_id(&self) -> &id_type::GlobalCustomerId {
&self.id
}

/// Get the connector customer ID for the specified connector label, if present
#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
pub fn get_connector_customer_id(&self, connector_label: &str) -> Option<&str> {
use masking::PeekInterface;

self.connector_customer
.as_ref()
.and_then(|connector_customer_value| {
connector_customer_value.peek().get(connector_label)
})
.and_then(|connector_customer| connector_customer.as_str())
}

/// Get the connector customer ID for the specified merchant connector account ID, if present
#[cfg(all(feature = "v2", feature = "customer_v2"))]
pub fn get_connector_customer_id(
&self,
merchant_connector_id: &id_type::MerchantConnectorAccountId,
) -> Option<&str> {
self.connector_customer
.as_ref()
.and_then(|connector_customer_map| connector_customer_map.get(merchant_connector_id))
.map(|connector_customer_id| connector_customer_id.as_str())
}
}

#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
Expand Down Expand Up @@ -300,24 +325,28 @@ impl super::behaviour::Conversion for Customer {
}
}

#[cfg(all(feature = "v2", feature = "customer_v2"))]
#[derive(Clone, Debug)]
pub struct CustomerGeneralUpdate {
pub name: crypto::OptionalEncryptableName,
pub email: Box<crypto::OptionalEncryptableEmail>,
pub phone: Box<crypto::OptionalEncryptablePhone>,
pub description: Option<Description>,
pub phone_country_code: Option<String>,
pub metadata: Option<pii::SecretSerdeValue>,
pub connector_customer: Box<Option<diesel_models::ConnectorCustomerMap>>,
pub default_billing_address: Option<Encryption>,
pub default_shipping_address: Option<Encryption>,
pub default_payment_method_id: Option<Option<id_type::GlobalPaymentMethodId>>,
pub status: Option<DeleteStatus>,
}

#[cfg(all(feature = "v2", feature = "customer_v2"))]
#[derive(Clone, Debug)]
pub enum CustomerUpdate {
Update {
name: crypto::OptionalEncryptableName,
email: Box<crypto::OptionalEncryptableEmail>,
phone: Box<crypto::OptionalEncryptablePhone>,
description: Option<Description>,
phone_country_code: Option<String>,
metadata: Option<pii::SecretSerdeValue>,
connector_customer: Box<Option<pii::SecretSerdeValue>>,
default_billing_address: Option<Encryption>,
default_shipping_address: Option<Encryption>,
default_payment_method_id: Option<Option<id_type::GlobalPaymentMethodId>>,
status: Option<DeleteStatus>,
},
Update(Box<CustomerGeneralUpdate>),
ConnectorCustomer {
connector_customer: Option<pii::SecretSerdeValue>,
connector_customer: Option<diesel_models::ConnectorCustomerMap>,
},
UpdateDefaultPaymentMethod {
default_payment_method_id: Option<Option<id_type::GlobalPaymentMethodId>>,
Expand All @@ -328,33 +357,36 @@ pub enum CustomerUpdate {
impl From<CustomerUpdate> for CustomerUpdateInternal {
fn from(customer_update: CustomerUpdate) -> Self {
match customer_update {
CustomerUpdate::Update {
name,
email,
phone,
description,
phone_country_code,
metadata,
connector_customer,
default_billing_address,
default_shipping_address,
default_payment_method_id,
status,
} => Self {
name: name.map(Encryption::from),
email: email.map(Encryption::from),
phone: phone.map(Encryption::from),
description,
phone_country_code,
metadata,
connector_customer: *connector_customer,
modified_at: date_time::now(),
default_billing_address,
default_shipping_address,
default_payment_method_id,
updated_by: None,
status,
},
CustomerUpdate::Update(update) => {
let CustomerGeneralUpdate {
name,
email,
phone,
description,
phone_country_code,
metadata,
connector_customer,
default_billing_address,
default_shipping_address,
default_payment_method_id,
status,
} = *update;
Self {
name: name.map(Encryption::from),
email: email.map(Encryption::from),
phone: phone.map(Encryption::from),
description,
phone_country_code,
metadata,
connector_customer: *connector_customer,
modified_at: date_time::now(),
default_billing_address,
default_shipping_address,
default_payment_method_id,
updated_by: None,
status,
}
}
CustomerUpdate::ConnectorCustomer { connector_customer } => Self {
connector_customer,
name: None,
Expand Down
31 changes: 16 additions & 15 deletions crates/router/src/core/customers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -679,19 +679,20 @@ impl CustomerDeleteBridge for id_type::GlobalCustomerId {
redacted_encrypted_value.clone().into_encrypted(),
);

let updated_customer = storage::CustomerUpdate::Update {
name: Some(redacted_encrypted_value.clone()),
email: Box::new(Some(redacted_encrypted_email)),
phone: Box::new(Some(redacted_encrypted_value.clone())),
description: Some(Description::from_str_unchecked(REDACTED)),
phone_country_code: Some(REDACTED.to_string()),
metadata: None,
connector_customer: Box::new(None),
default_billing_address: None,
default_shipping_address: None,
default_payment_method_id: None,
status: Some(common_enums::DeleteStatus::Redacted),
};
let updated_customer =
storage::CustomerUpdate::Update(Box::new(storage::CustomerGeneralUpdate {
name: Some(redacted_encrypted_value.clone()),
email: Box::new(Some(redacted_encrypted_email)),
phone: Box::new(Some(redacted_encrypted_value.clone())),
description: Some(Description::from_str_unchecked(REDACTED)),
phone_country_code: Some(REDACTED.to_string()),
metadata: None,
connector_customer: Box::new(None),
default_billing_address: None,
default_shipping_address: None,
default_payment_method_id: None,
status: Some(common_enums::DeleteStatus::Redacted),
}));

db.update_customer_by_global_id(
key_manager_state,
Expand Down Expand Up @@ -1338,7 +1339,7 @@ impl CustomerUpdateBridge for customers::CustomerUpdateRequest {
&domain_customer.id,
domain_customer.to_owned(),
merchant_account.get_id(),
storage::CustomerUpdate::Update {
storage::CustomerUpdate::Update(Box::new(storage::CustomerGeneralUpdate {
name: encryptable_customer.name,
email: Box::new(encryptable_customer.email.map(|email| {
let encryptable: Encryptable<Secret<String, pii::EmailStrategy>> =
Expand All @@ -1357,7 +1358,7 @@ impl CustomerUpdateBridge for customers::CustomerUpdateRequest {
default_shipping_address: encrypted_customer_shipping_address.map(Into::into),
default_payment_method_id: Some(self.default_payment_method_id.clone()),
status: None,
},
})),
key_store,
merchant_account.storage_scheme,
)
Expand Down
Loading

0 comments on commit 17f9e6e

Please sign in to comment.