Stripe API / サブスクリプションのキャンセルを予約した時に、サイクル請求の期間に対して中途半端な終了日を指定した時に、次回のインヴォイスが日割計算される場合がある。 ( #Ruby #Stripe ) 

# NOTE

- Subscription は prorate を属性としてもたず、create / update の時の指定としてだけ持つようだ。
- create する時にも update する時にも、それぞれ必要があれば prorate = true を 指定する必要がある。
- Subscription update で cancel_at を指定する時の日割計算の無効フラグ prorate false の効用は限定的で、現在のサブスクリプションを縮める場合だけに限られるように見えた。

# Doc

>cancel_at
>optional
>A timestamp at which the subscription should cancel. If set to a date before the current period ends this will cause a proration if prorate=true.

![image](https://user-images.githubusercontent.com/13635059/71772569-8d431000-2f90-11ea-8cd3-1d6b5e6016a7.png)

https://stripe.com/docs/api/subscriptions/create#create_subscription-cancel_at

# Code

```rb
#! /usr/bin/env ruby

# Docs
# https://stripe.com/docs/api/subscriptions/update#update_subscription-prorate
# https://stripe.com/docs/api/subscriptions/create
# https://stripe.com/docs/billing/subscriptions/billing-cycle#prorations

require 'stripe'

# You Need
# `$ gem install activesupport` befure run ruby script
require 'active_support/core_ext'

Stripe::api_key = ENV['STRIPE_SECRET_KEY']

def create_subscription_and_cancel(name:, cancel_at_type:, prorate_in_update:)
  product1 = Stripe::Product.create(name: "Gold plan #{rand(9999999999)}")
  plan1 = Stripe::Plan.create(interval: 'month', currency: 'jpy', amount: 980, product: product1.id, usage_type: 'licensed')

  tax_rate = Stripe::TaxRate.create(display_name: 'Tax Rate', percentage: 10.0, inclusive: false)
  customer = Stripe::Customer.create
  payment_method = Stripe::PaymentMethod.create(type: 'card', card: { number: '4242424242424242', exp_year: 2030, exp_month: 01})
  customer_payment_method = Stripe::PaymentMethod.attach(payment_method.id, customer: customer.id)

  subscription = Stripe::Subscription.create(
    {
      customer: customer.id,
      default_payment_method: customer_payment_method.id,
      items: [
        [
          { plan: plan1.id },
        ],
      ],
      # You can not give persistence "prorate" property to Subscription
      # It property will not used in update this Subscription
      # prorate: false,
      default_tax_rates: [tax_rate],
    }
  )

  cancel_at = if cancel_at_type == :natural_cycle_end
                subscription.current_period_end
              elsif cancel_at_type == :natural_cycle_end_plus
                Time.at(subscription.current_period_end).since(1.month).to_i
              elsif cancel_at_type == :since_current_period_end
                Time.at(subscription.current_period_end).since(1.day).to_i
              elsif cancel_at_type == :ago_current_period_end
                Time.at(subscription.current_period_end).ago(1.day).to_i
              else
                raise
              end

  updated_subscription = Stripe::Subscription.update(
    subscription.id,
      cancel_at: cancel_at,
      # You need give prorate property as "true" with cancel_at
      # when in update not in create
      prorate: prorate_in_update
  )

  puts '=' * 100
  puts "#{name} SUBSCRIPTION"
  puts '-' * 100
  if ENV['VERBOSE']
    puts '-' * 100
    puts updated_subscription
  end

  begin
    upcoming_invoice = Stripe::Invoice.upcoming(customer: updated_subscription.customer)
    puts 'Upcoming Invoice'
    puts "subtotal: #{upcoming_invoice.subtotal}"
    puts "tax: #{upcoming_invoice.tax}"
    puts "total: #{upcoming_invoice.total}"
  rescue Stripe::InvalidRequestError => e
    puts e.message
  end

  puts "prorate_in_update: #{prorate_in_update}"
  puts "cancel_at_type: #{cancel_at_type}"
  puts "cancel_at: #{updated_subscription.cancel_at} ( #{Time.at(updated_subscription.cancel_at)} ) "

  if ENV['VERBOSE']
    puts '-' * 100
    puts upcoming_invoice
  end

  puts '-' * 100
  puts "https://dashboard.stripe.com/test/subscriptions/#{subscription.id}"

  updated_subscription
end

# Cancel_at Natural cycle end
# No upcoming invoice even if prorate: :true
create_subscription_and_cancel(name: 'A', cancel_at_type: :natural_cycle_end, prorate_in_update: true)
create_subscription_and_cancel(name: 'B', cancel_at_type: :natural_cycle_end, prorate_in_update: false)

# Cancel_at Natural cycle but not current cycle, cancel at next cycle end
# Both occurs Upcoming Invoice
# It seems to ignore "prorate: :false" property that right?
create_subscription_and_cancel(name: 'C', cancel_at_type: :natural_cycle_end_plus, prorate_in_update: true)
create_subscription_and_cancel(name: 'D', cancel_at_type: :natural_cycle_end_plus, prorate_in_update: false)

# Cancel at before current period end
# When prorate true Then Upcoming Invoice occurs
# When prorate false Then No Upcoming Invoice
create_subscription_and_cancel(name: 'E', cancel_at_type: :ago_current_period_end, prorate_in_update: true)
create_subscription_and_cancel(name: 'F', cancel_at_type: :ago_current_period_end, prorate_in_update: false)

# Cancel at after current period end
# Both occurs Upcoming Invoice
# It seems to ignore "prorate: :false" property that right?
create_subscription_and_cancel(name: 'G', cancel_at_type: :since_current_period_end, prorate_in_update: true)
create_subscription_and_cancel(name: 'H', cancel_at_type: :since_current_period_end, prorate_in_update: false)
```


# Result

```
====================================================================================================
A SUBSCRIPTION
----------------------------------------------------------------------------------------------------
No upcoming invoices for customer: cus_GULJInyR4PFTtz
prorate_in_update: true
cancel_at_type: natural_cycle_end
cancel_at: 1580861147 ( 2020-02-05 09:05:47 +0900 )
----------------------------------------------------------------------------------------------------
https://dashboard.stripe.com/test/subscriptions/sub_GULJwFRtsUzvEy
====================================================================================================
B SUBSCRIPTION
----------------------------------------------------------------------------------------------------
No upcoming invoices for customer: cus_GULJmaXrpOsM9m
prorate_in_update: false
cancel_at_type: natural_cycle_end
cancel_at: 1580861154 ( 2020-02-05 09:05:54 +0900 )
----------------------------------------------------------------------------------------------------
https://dashboard.stripe.com/test/subscriptions/sub_GULJMrmQFNRBRn
====================================================================================================
C SUBSCRIPTION
----------------------------------------------------------------------------------------------------
Upcoming Invoice
subtotal: 980
tax: 98
total: 1078
prorate_in_update: true
cancel_at_type: natural_cycle_end_plus
cancel_at: 1583366759 ( 2020-03-05 09:05:59 +0900 )
----------------------------------------------------------------------------------------------------
https://dashboard.stripe.com/test/subscriptions/sub_GULJeUDyNlZVIH
====================================================================================================
D SUBSCRIPTION
----------------------------------------------------------------------------------------------------
Upcoming Invoice
subtotal: 980
tax: 98
total: 1078
prorate_in_update: false
cancel_at_type: natural_cycle_end_plus
cancel_at: 1583366767 ( 2020-03-05 09:06:07 +0900 )
----------------------------------------------------------------------------------------------------
https://dashboard.stripe.com/test/subscriptions/sub_GULJopqK32snfG
====================================================================================================
E SUBSCRIPTION
----------------------------------------------------------------------------------------------------
Upcoming Invoice
subtotal: -32
tax: -3
total: -35
prorate_in_update: true
cancel_at_type: ago_current_period_end
cancel_at: 1580774773 ( 2020-02-04 09:06:13 +0900 )
----------------------------------------------------------------------------------------------------
https://dashboard.stripe.com/test/subscriptions/sub_GULJoomwt1Nqk2
====================================================================================================
F SUBSCRIPTION
----------------------------------------------------------------------------------------------------
No upcoming invoices for customer: cus_GULJSmHKBQHV4o
prorate_in_update: false
cancel_at_type: ago_current_period_end
cancel_at: 1580774780 ( 2020-02-04 09:06:20 +0900 )
----------------------------------------------------------------------------------------------------
https://dashboard.stripe.com/test/subscriptions/sub_GULKd0Aj0hI7sB
====================================================================================================
G SUBSCRIPTION
----------------------------------------------------------------------------------------------------
Upcoming Invoice
subtotal: 32
tax: 3
total: 35
prorate_in_update: true
cancel_at_type: since_current_period_end
cancel_at: 1580947586 ( 2020-02-06 09:06:26 +0900 )
----------------------------------------------------------------------------------------------------
https://dashboard.stripe.com/test/subscriptions/sub_GULKt9K63lH90R
====================================================================================================
H SUBSCRIPTION
----------------------------------------------------------------------------------------------------
Upcoming Invoice
subtotal: 32
tax: 3
total: 35
prorate_in_update: false
cancel_at_type: since_current_period_end
cancel_at: 1580947593 ( 2020-02-06 09:06:33 +0900 )
----------------------------------------------------------------------------------------------------
https://dashboard.stripe.com/test/subscriptions/sub_GULKZamQYbQkZZ
```








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->