StripeのSubscriptionをまとめて作り直すコード

請求サイクルを変更する必要が出てきたのですが、Stripeではアクティブなsubscriptionの請求サイクルを更新することはできません。 まぁ、ユーザーからしたら当然のことですが。 ただ、開発環境だとたまにこのあたり […]

広告ここから
広告ここまで

目次

    請求サイクルを変更する必要が出てきたのですが、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で逐次実行

    参考

    広告ここから
    広告ここまで
    Home
    Search
    Bookmark