Last active
August 21, 2023 05:40
-
-
Save ashleyrudland/88c27c0289ecc78561b15d07c1fe9793 to your computer and use it in GitHub Desktop.
Find churn reasons by sucking out all Stripe subscriptions (includes all subscriptions)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const fs = require('fs'); | |
const moment = require('moment'); | |
const stripe = require('../stripe'); | |
const hashCode = (str) => { | |
let hash = 0; | |
if (typeof str !== 'string' || str.length === 0) { | |
return String(hash); | |
} | |
for (let i = 0; i < str.length; i++) { | |
const char = str.charCodeAt(i); | |
hash = ((hash << 5) - hash) + char; | |
hash = hash & hash; | |
} | |
hash = hash >>> 0; | |
return Number(hash).toString(32).toLowerCase(); | |
}; | |
const VAT_RATE = 0; | |
const exportSubscriptionData = async () => { | |
let hasMore = false; | |
let lastId = ''; | |
let page = 1; | |
const subs = []; | |
const collection = []; | |
while (subs.length === 0 || hasMore) { | |
console.log(`getting page ${page} of subs...`) | |
const opt = { | |
limit: 100, | |
expand: ['data.customer'], | |
status: 'all', | |
}; | |
if (lastId) opt.starting_after = lastId; | |
const result = await stripe.subscriptions.list(opt); | |
hasMore = result.has_more; | |
if (result && result.data?.length > 0) { | |
result.data.forEach((item) => { | |
subs.push(item); | |
let amount = item.plan.amount; | |
if (item.discount && item.discount.coupon) { | |
amount = (amount * (1 + VAT_RATE)) * (1 - (item.discount.coupon.percent_off / 100)); | |
} | |
amount = amount / 100; | |
let interval = item.plan.interval; | |
if (item.plan.interval_count === 3) { | |
interval = 'quarter'; | |
} | |
let monthly = amount; | |
if (interval === 'quarter') { | |
monthly = amount / 3; | |
} else if (interval === 'year') { | |
monthly = amount / 12; | |
} | |
monthly = monthly; | |
const discount = item.discount && item.discount.coupon ? item.discount.coupon.id : ''; | |
collection.push({ | |
customer: hashCode(item.customer.email), | |
start: moment(item.start_date * 1000).format('YYYY-MM-DD'), | |
end: item.canceled_at ? moment(item.canceled_at * 1000).format('YYYY-MM-DD') : '', | |
status: item.status, | |
plan: item.plan.id, | |
amount, | |
interval, | |
monthly, | |
discount, | |
cancellation_reason: item.cancellation_details && item.cancellation_details.feedback ? item.cancellation_details.feedback : '', | |
cancellation_comment: item.cancellation_details && item.cancellation_details.comment ? item.cancellation_details.comment : '', | |
}); | |
}) | |
lastId = result.data[result.data.length - 1].id | |
} else { | |
break | |
} | |
page += 1 | |
console.log(`${collection.length} subs collected...`); | |
} | |
collection.sort((a, b) => new Date(b.start) - new Date(a.start)); | |
let csv = 'Customer,Start,End,Status,Plan,Amount,Interval,Monthly,Discount,Cancellation Reason,Cancellation Comment\n'; | |
csv += collection.map((item) => `${item.customer},${item.start},${item.end},${item.status},${item.plan},${item.amount.toFixed(2)},${item.interval},${item.monthly.toFixed(2)},${item.discount},${item.cancellation_reason},"${item.cancellation_comment}"`).join('\n'); | |
fs.writeFileSync('./subscription.csv', csv, { encoding: 'utf8' }); | |
}; | |
exportSubscriptionData().then(() => process.exit()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment