Skip to content

Commit

Permalink
Sync customer info on order translation (#812)
Browse files Browse the repository at this point in the history
  • Loading branch information
nadaismail-stripe authored Oct 3, 2022
1 parent 6e8ba34 commit 9275c05
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 20 deletions.
1 change: 1 addition & 0 deletions lib/stripe-force/constants.rb
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ class FeatureFlags < T::Enum
TEST_CLOCKS = new('test_clocks')
SF_CACHING = new('sf_caching')
CATCH_ALL_ERRORS = new('catch_all_errors')
UPDATE_CUSTOMER_ON_ORDER_TRANSLATION = new('update_customer_on_order_creation')
end
end

Expand Down
17 changes: 12 additions & 5 deletions lib/stripe-force/translate/customer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,24 @@ def translate_account(sf_account)
locker.lock_salesforce_record(sf_account)

catch_errors_with_salesforce_context(secondary: sf_account) do
create_customer_from_sf_account(sf_account)
existing_stripe_customer = retrieve_from_stripe(Stripe::Customer, sf_account)
if existing_stripe_customer.blank?
# creates a new stripe customer
create_customer_from_sf_account(sf_account)
else
# check if the feature flag to update an existing customer is enabled
if @user.feature_enabled?(FeatureFlags::UPDATE_CUSTOMER_ON_ORDER_TRANSLATION)
update_stripe_object(stripe_class: Stripe::Customer, stripe_object_id: existing_stripe_customer.id, sf_object: sf_account)
else
existing_stripe_customer
end
end
end
end

def create_customer_from_sf_account(sf_account)
log.info 'translating customer', salesforce_object: sf_account

if (stripe_customer = retrieve_from_stripe(Stripe::Customer, sf_account))
return stripe_customer
end

customer = create_stripe_object(Stripe::Customer, sf_account) do |generated_stripe_customer|
if @user.feature_enabled?(FeatureFlags::TEST_CLOCKS) && !@user.livemode
log.debug 'adding test clock to customer'
Expand Down
43 changes: 33 additions & 10 deletions lib/stripe-force/translate/translate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -334,28 +334,51 @@ def update_sf_stripe_id(sf_object, stripe_object, additional_salesforce_updates:
stripe_id: stripe_object.id
end

def create_stripe_object(stripe_class, sf_object, additional_stripe_params: {}, skip_field_extraction: false)
stripe_fields = if skip_field_extraction
{}
else
StripeForce::Utilities::SalesforceUtil.extract_salesforce_params!(mapper, sf_object, stripe_class)
end
def construct_stripe_object(stripe_class:, salesforce_object:, additional_stripe_params: {})
stripe_fields = StripeForce::Utilities::SalesforceUtil.extract_salesforce_params!(mapper, salesforce_object, stripe_class)

stripe_object = stripe_class.construct_from(additional_stripe_params)

# the fields in the resulting hash could be dot-paths, so let's assign them using the mapper
mapper.assign_values_from_hash(stripe_object, stripe_fields)

stripe_object.metadata = Metadata.stripe_metadata_for_sf_object(@user, sf_object)
stripe_object.metadata = Metadata.stripe_metadata_for_sf_object(@user, salesforce_object)

apply_mapping(stripe_object, salesforce_object)

sanitize(stripe_object)

stripe_object
end

def update_stripe_object(stripe_class:, stripe_object_id:, sf_object:)
# creates the stripe object from the sf_object
stripe_object = construct_stripe_object(stripe_class: stripe_class, salesforce_object: sf_object)

log.info 'updating stripe object', stripe_id: stripe_object_id, stripe_object_type: stripe_class

# note: the stripe_object should not contain it's id or the Stripe update call will fail
# since we are not allowed to update the id of an existing object
updated_stripe_object = catch_errors_with_salesforce_context(secondary: sf_object) do
stripe_class.update(
stripe_object_id,
stripe_object.to_hash,
@user.stripe_credentials
)
end

apply_mapping(stripe_object, sf_object)
log.info 'updated stripe object', stripe_id: stripe_object_id, stripe_object_type: stripe_class

updated_stripe_object
end

def create_stripe_object(stripe_class, sf_object, additional_stripe_params: {})
stripe_object = construct_stripe_object(stripe_class: stripe_class, salesforce_object: sf_object, additional_stripe_params: additional_stripe_params)

if block_given?
yield(stripe_object)
end

sanitize(stripe_object)

log.info 'creating stripe object', salesforce_object: sf_object, stripe_object_type: stripe_class

# there's a decent chance this causes us issues down the road: we shouldn't be using `construct_from`
Expand Down
41 changes: 37 additions & 4 deletions sorbet/custom/stripe.rbi
Original file line number Diff line number Diff line change
Expand Up @@ -74,30 +74,63 @@ class Stripe::Price
def active=(arg); end
end

# TODO I swear I added some of these in via the netsuite connector
class Stripe::Customer
sig { returns(String) }
def currency; end

sig { returns(T.nilable(Stripe::Address)) }
def address; end

sig { returns(String) }
def description; end

sig { returns(String) }
def email; end

sig { returns(String) }
def name; end

sig { returns(T.nilable(String, Stripe::TestHelpers::TestClock))}
def test_clock; end

# TODO should add proper subhash typing
sig { returns(Stripe::Shipping) }
def shipping; end

sig { returns(T.nilable(String)) }
def phone; end
end

# TODO the address subhash typings need to be cleaned up
class Stripe::Address
class Stripe::Shipping
sig { returns(T.nilable(Stripe::Address)) }
def address; end

sig { returns(T.nilable(String)) }
def name; end

sig { returns(T.nilable(String)) }
def phone; end
end

class Stripe::Address
sig { returns(T.nilable(String)) }
def city; end

sig { returns(T.nilable(String)) }
def country; end

sig { returns(T.nilable(String)) }
def line1; end

sig { returns(T.nilable(String)) }
def line2; end

sig { returns(T.nilable(String)) }
def postal_code; end

sig { returns(T.nilable(String)) }
def state; end
end

class Stripe::SubscriptionSchedulePhaseInvoiceItem < Stripe::StripeObject
sig { returns(T.any(String, Stripe::Price)) }
def price; end
Expand Down
130 changes: 129 additions & 1 deletion test/integration/translate/test_customer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ class Critic::CustomerTranslation < Critic::FunctionalTest
"Name" => "Sales force",
"Phone" => "1231231234",
"Description" => "A CRM company",

"ShippingStreet" => "500 Westover Drive",
"ShippingCity" => "Sanford",
"ShippingState" => "North Carolina",
Expand Down Expand Up @@ -89,4 +88,133 @@ class Critic::CustomerTranslation < Critic::FunctionalTest
stripe_customer = Stripe::Customer.retrieve(stripe_customer_id, @user.stripe_credentials)
refute_nil(stripe_customer.test_clock)
end

it 'updates an existing stripe customer after the salesforce account info has changed' do
@user.enable_feature(FeatureFlags::UPDATE_CUSTOMER_ON_ORDER_TRANSLATION)

# setup
sf_account_initial_name = "Test Account Name"
sf_account_initial_description = "A CRM company"
sf_account_updated_name = "Test Account Name 2"
sf_account_updated_description = "A CRM company 2"

sf_account_id = create_salesforce_account(additional_fields: {
"Name" => sf_account_initial_name,
"Phone" => "1231231234",
"Description" => sf_account_initial_description,
"ShippingStreet" => "500 Briar Forest Drive",
"ShippingCity" => "Houston",
"ShippingState" => "Texas",
"ShippingPostalCode" => "77077",
"ShippingCountry" => "US",
})

# translate sf account
StripeForce::Translate.perform_inline(@user, sf_account_id)

# confirm the sf account was translated
sf_account = sf.find(SF_ACCOUNT, sf_account_id)
stripe_customer_id = sf_account[prefixed_stripe_field(GENERIC_STRIPE_ID)]
refute_nil(stripe_customer_id)

# retrieve the corresponding stripe customer
stripe_customer = Stripe::Customer.retrieve(stripe_customer_id, @user.stripe_credentials)

# update the sf account info
sf.update!(SF_ACCOUNT, {
SF_ID => sf_account_id,
"Name" => sf_account_updated_name,
"Description" => sf_account_updated_description,
})

# sanity check that stripe customer info is the original info
assert_equal(sf_account_id, stripe_customer.metadata['salesforce_account_id'])
assert_equal(sf_account_initial_name, stripe_customer.name)
assert_equal(sf_account_initial_description, stripe_customer.description)

# retranslate and confirm stripe customer info is updated
StripeForce::Translate.perform_inline(@user, sf_account_id)
stripe_customer.refresh

assert_equal(sf_account_updated_name, stripe_customer.name)
assert_equal(sf_account_updated_description, stripe_customer.description)
end

it 'updates stripe customer on order translation only when feature is enabled' do
# setup
sf_account_initial_name = "Test Account Name"
sf_account_initial_postal_code = "77077"
sf_account_updated_name = "Test Account Name 2"
sf_account_updated_postal_code = "77048"

sf_account_id = create_salesforce_account(additional_fields: {
"Name" => sf_account_initial_name,
"Phone" => "1231231234",
"Description" => "A CRM company",
"ShippingStreet" => "500 Briar Forest Drive",
"ShippingCity" => "Houston",
"ShippingState" => "Texas",
"ShippingPostalCode" => sf_account_initial_postal_code,
"ShippingCountry" => "US",
})

# translate the initial sf account
StripeForce::Translate.perform_inline(@user, sf_account_id)

# confirm the sf account was translated
sf_account = sf.find(SF_ACCOUNT, sf_account_id)
stripe_customer_id = sf_account[prefixed_stripe_field(GENERIC_STRIPE_ID)]
refute_nil(stripe_customer_id)

# retrieve the corresponding stripe customer
stripe_customer = Stripe::Customer.retrieve(stripe_customer_id, @user.stripe_credentials)

# sanity check that stripe customer info is the original info
assert_equal(sf_account_id, stripe_customer.metadata['salesforce_account_id'])
assert_equal(sf_account_initial_name, stripe_customer.name)
assert_equal(sf_account_initial_postal_code, T.must(stripe_customer.shipping.address).postal_code)

# update the sf account info
sf.update!(SF_ACCOUNT, {
SF_ID => sf_account_id,
"Name" => sf_account_updated_name,
"ShippingPostalCode" => sf_account_updated_postal_code,
})

# create an sf order and translate the order
sf_order_1 = create_salesforce_order(
sf_account_id: sf_account_id,
additional_quote_fields: {
CPQ_QUOTE_SUBSCRIPTION_START_DATE => format_date_for_salesforce(now_time),
CPQ_QUOTE_SUBSCRIPTION_TERM => TEST_DEFAULT_CONTRACT_TERM,
}
)
SalesforceTranslateRecordJob.translate(@user, sf_order_1)
stripe_customer.refresh

# confirm that customer info was NOT updated on order translation
# since feature_flag UPDATE_CUSTOMER_ON_ORDER_TRANSLATION isn't enabled
assert_equal(sf_account_initial_name, stripe_customer.name)
assert_equal(sf_account_initial_postal_code, T.must(stripe_customer.shipping.address).postal_code)

# now enable feature flag UPDATE_CUSTOMER_ON_ORDER_TRANSLATION
@user.enable_feature(FeatureFlags::UPDATE_CUSTOMER_ON_ORDER_TRANSLATION)
@user.save

# create another sf order and translate the order
sf_order_2 = create_salesforce_order(
sf_account_id: sf_account_id,
additional_quote_fields: {
CPQ_QUOTE_SUBSCRIPTION_START_DATE => format_date_for_salesforce(now_time),
CPQ_QUOTE_SUBSCRIPTION_TERM => TEST_DEFAULT_CONTRACT_TERM,
}
)
SalesforceTranslateRecordJob.translate(@user, sf_order_2)
stripe_customer.refresh

# confirm stripe customer info was updated on order translation
# since feature flag is enabled
assert_equal(sf_account_updated_name, stripe_customer.name)
assert_equal(sf_account_updated_postal_code, T.must(stripe_customer.shipping.address).postal_code)
end
end

0 comments on commit 9275c05

Please sign in to comment.