Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iloveitaly/e1415e812512a51535354f22d00ad29c to your computer and use it in GitHub Desktop.
Save iloveitaly/e1415e812512a51535354f22d00ad29c to your computer and use it in GitHub Desktop.
Match Stripe customers to data in a CSV based on card metadata (last4, zip, etc). Useful when migrating card data to Stripe.
# Michael Bianco <mike@suitesync.io>
# NOTE tabs are used for easy copy/paste into google sheets
require 'stripe'
require 'csv'
require 'pry'
Stripe.api_key = 'sk_live_'
if ARGV.empty?
puts "No CSV path specified"
exit 1
end
csv_path = ARGV.first
csv_mapping = CSV.read(csv_path, headers: true)
used_mappings = []
dry_run = false
allow_multiple_sources = true
overwrite_description = true
# Mapping:
#
# - LastFour
# - ExpMonth
# - ExpYear. 2 digit.
# - Brand
#
# Map to:
#
# - Description
# - Email
multiple_sources = []
no_stripe_match = []
Stripe::Customer.list(limit: 100).auto_paging_each do |customer|
if customer.sources.count > 1 && !allow_multiple_sources
multiple_sources << customer
puts "#{customer.id}\tcustomer has multiple payment sources"
next
end
if !customer.description.nil? && !customer.description.empty? && !overwrite_description
puts "#{customer.id}\tcustomer has description"
next
end
# find matching customer by:
# - last 4
# - expiration (MM & YY)
# - zip?
stripe_card = customer.sources.first
last_four = stripe_card.last4
zip = stripe_card.address_zip
brand = stripe_card.brand.strip.gsub(/[^a-zA-Z]*/, '').downcase
expiration_month = stripe_card.exp_month
expiration_year = stripe_card.exp_year - 2000
csv_mapping.each_with_index do |row, i|
if row['Brand'].downcase.strip.gsub(/[^a-zA-Z]*/, '') == brand &&
last_four == row['LastFour'] &&
expiration_month == row['ExpMonth'].to_i &&
expiration_year == row['ExpYear'].to_i
if used_mappings.include?(i)
puts "#{customer.id}\tmapping row #{i + 1}\tmapping is already used"
end
used_mappings << i
customer.description = row['Description']
customer.email = row['Email']
if !dry_run
customer.save
end
break
end
end
if customer.description.nil?
puts "#{customer.id}\tno match found"
end
end
puts "\nUnmatched CSV rows"
((0..(csv_mapping.count - 1)).to_a - used_mappings).each do |index|
puts csv_mapping[index].to_csv(col_sep: "\t")
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment