Blog
StripeのSubscriptionをまとめて作り直すコード
Posted over 2 years ago
この記事をシェア:
請求サイクルを変更する必要が出てきたのですが、Stripeではアクティブなsubscriptionの請求サイクルを更新することはできません。
まぁ、ユーザーからしたら当然のことですが。
ただ、開発環境だとたまにこのあたりを変更したくなる時があったりするので、plan_id指定で一括再生成するコードを書いてみました。
コード
長いです。
import * as Stripe from 'stripe'
import * as moment from 'moment'
const stripe = new Stripe(process.env.STRIPE_API_KEY as string)
import subscriptions = Stripe.subscriptions
import ISubscription = subscriptions.ISubscription
/**
* Subscriptionを再帰的に全取得する
* @param {string} planId
* @param [stripe.subscriptions.ISubscription[] = []] subscriptions
* @param [string] finalId
*/
const getAllSubscription = async (planId: string, subscriptions: ISubscription[] = [], finalId?: string): Promise<ISubscription[]> => {
const props: subscriptions.ISubscriptionListOptions = {
plan: planId,
limit: 100
}
if (finalId) props.starting_after = finalId
const sub = await stripe.subscriptions.list(props)
const merged = sub.data.concat(subscriptions)
if (sub.has_more) {
const finalId = sub.data[sub.data.length - 1].id
return getAllSubscription(planId, merged, finalId)
}
return merged
}
/**
* Subscriptionを再作成する
* @param {stripe.subscriptions.ISubscription} subscription
*/
const replaceSubscription = async (subscription: ISubscription) => {
if (subscription.items.data.length > 1) return
await stripe.subscriptions.del(subscription.id)
const customerId = typeof subscription.customer === "string" ? subscription.customer : subscription.customer.id
const options: subscriptions.ISubscriptionCreationOptions ={
customer: customerId,
billing_cycle_anchor: moment().add(1, 'month').startOf('month').unix(),
items: subscription.items.data.map(
(item): subscriptions.ISubscriptionCreationItem => {
return {
plan: item.plan.id,
quantity: item.quantity,
metadata: item.metadata
}
}
),
metadata: subscription.metadata
}
return stripe.subscriptions.create(options)
}
const replaceAllSubscriptions = async (planId: string): Promise<void> => {
const subscriptions = await getAllSubscription('free')
const legacyPlanSubscriptions = subscriptions
.filter(subscription => {
return subscription.items.data.length < 2
})
console.log(`free subscription has a ${legacyPlanSubscriptions.length} items`)
let p: Promise<void> = Promise.resolve()
legacyPlanSubscriptions.forEach(subscription => {
console.log(`subscription id: ${subscription.id}`)
if (subscription.items.data.length > 1) return
p = p.then(async() => {
try {
const result = await replaceSubscription(subscription)
if (!result) {
console.log('SKIPPED')
return
}
console.log('=====')
console.log(`ID: https://dashboard.stripe.com/test/subscriptions/${result.id}`)
console.log(`Customer: https://dashboard.stripe.com/test/customers/${result.customer}`)
console.log(`Period: ${moment.unix(result.current_period_start).toISOString()}`)
} catch (e) {
console.log(e)
}
})
})
p.then(() => {
console.log('===FINISH===')
})
}
やっていること
- subscriptions.listを再帰的に回して対象のsubscriptionを全取得
- 更新したい部分だけ上書きしてsubscriptions.createを実行
- 非同期に実行するとスロットリングされるので、foreach + Promiseで逐次実行
参考
Tools to Support Stripe Development
We provide helpful tools to extend the Stripe Dashboard and streamline development and testing.
View All ToolsSupport This Project
If you find this content helpful, consider supporting the project through GitHub Sponsors. Your support helps maintain and improve these tools.
