在结算周期后显示用户订阅已取消

时间:2014-07-22 18:18:36

标签: ruby-on-rails

我正在使用Stripe进行订阅,因此当用户取消订阅时(关闭自动续订),它会保持订阅有效,直到Stripe的结算周期结束。

该操作通过Stripe工作,但是如何设置以便我的数据库中的cancelled列具有相同的效果?目前,如果用户点击取消订阅链接,则会将其cancelled列标记为1。我希望它不会在结算期结束前标记为已取消,因此用户可以继续访问该网站,直到最后一个结算日(我已打开autorenwal)

我已阅读txdavidtx建议。他建议将所有用户标记为在结算周期结束时取消。那种方法不适合我想要完成的任务。

我订阅设置为autorenew。我需要创建一个cancel操作,只会将current_user标记为在结算周期结束时取消。

例如:

用户A在9月27日注册月度订阅。用户A在12月15日决定取消订阅。用户A的订阅还剩12天。用户A点击cancel链接。用户A在其PayPal或Stripe帐户中已取消自动更新和订阅。在我的数据库中,他们的cancelled属性值在12天(12月27日)结束前不会改变。

如果有人可以提供帮助那就太好了。

订阅控制器:

  def new
    plan = Plan.find(params[:plan_id])
    @subscription = plan.subscriptions.build
    render layout: 'new_application'
    if params[:PayerID]
      @subscription.paypal_customer_token = params[:PayerID]
      @subscription.paypal_payment_token = params[:token]
      @subscription.email = @subscription.paypal.checkout_details.email
    end
  end

  def create
    @subscription = Subscription.new(params[:subscription])
    if @subscription.save_with_payment
      redirect_to @subscription, :notice => "Thank you for subscribing!"
    else
      render :new
    end
  end

  def show
    @subscription = Subscription.find(params[:id])
    render layout: 'new_application'
  end

  def paypal_checkout
    plan = Plan.find(params[:plan_id])
    subscription = plan.subscriptions.build
    redirect_to subscription.paypal.checkout_url(
      return_url: new_subscription_url(:plan_id => plan.id),
      cancel_url: root_url
    )
  end

    def updatesubscription
      @user = current_user
      @customer = Stripe::Customer.retrieve(@user.subscription.stripe_customer_token)
      if @user.subscription.plan_id == 12
      @customer.update_subscription(:plan => "1", :prorate => true)
      current_user.subscription.update_attributes(:plan_id => 1)
      flash.alert = 'Your subscription has been changed to monthly!'
      redirect_to root_url
    elsif @user.subscription.plan_id == 1
      @customer.update_subscription(:plan => "12", :prorate => true)
      current_user.subscription.update_attributes(:plan_id => 12)
     current_user.save!
      flash.alert = 'Your subscription has been changed to annually!'
      redirect_to root_url
    end
     end

     def cancelsubscription
       @user = current_user
         @customer = Stripe::Customer.retrieve(@user.subscription.stripe_customer_token)
         @customer.cancel_subscription(:at_period_end => true) 
         current_user.subscription.update_attributes(:cancelled => 1)
         current_user.save!
         flash.alert = 'Your subscription has been cancelled successfully!'
         redirect_to root_url
       end

       def showcard
         @user = current_user
         Stripe::Customer.retrieve(@user.subscription.stripe_customer_token).cards.all()
       end

           def suspend
             @user = current_user
             @user.subscription.suspend_paypal
             current_user.subscription.update_attributes(:cancelled => 1)
               flash.alert = 'Billing has been suspended!'
                redirect_to root_url
           end

           def reactivate
             @user = current_user
             @user.subscription.reactivate_paypal
             current_user.subscription.update_attributes(:cancelled => nil)
               flash.alert = 'Billing has been activated!'
                redirect_to root_url
           end


               def edit_card
                 @user = current_user
               end

               def update_card
                 @user = current_user
                 card_info = {
                   name:    params[:name],
                   number:    params[:number],
                   exp_month: params[:date][:month],
                   exp_year:  params[:date][:year],
                   cvc:       params[:cvc]
                 }
                 if @user.subscription.update_card(@subscriber, card_info)
                   flash.alert = 'Saved. Your card information has been updated.'
                   redirect_to root_url
                 else
                   flash.alert = 'Stripe reported an error while updating your card. Please try again.'
                   redirect_to root_url
                 end
               end
end

5 个答案:

答案 0 :(得分:8)

我认为最简单的方法是使用条带webhooks,只要订阅结束,条带将使用customer.subscription.deleted事件ping您的系统,此时您应该取消用户订阅。

设置非常简单。

  1. 您只需转到设置页面并添加webhook网址,然后条带将开始向您发送系统事件。
  2. 然后创建一个条带事件控制器,它将解析后端的条带事件。
  3. 使用at_period_end params true检测用户并取消订阅

    customer = Stripe::Customer.retrieve("cus_3R1W8PG2DmsmM9")
    customer.subscriptions.retrieve("sub_3R3PlB2YlJe84a").delete(:at_period_end => true
    
  4. 如果您在结算周期结束时取消订阅,则会立即触发customer.subscription.updated事件,反映订阅的cancel_at_period_end值的更改。当订阅在期末实际取消时,将发生customer.subscription.deleted事件。 Stripe Doc

    4-然后设置回调控制器并检测订阅已删除

    <pre>
    class StripeEventsController
    
      skip_before_filter  :verify_authenticity_token
    
      def catch
        object = params[:data][:object]
        case params[:type]
        when "customer.subscription.deleted"
         customer = object[:id]
         user = User.find_by_stripe_id(customer)
         user.subscription.update_attributes(cancelled: "1")
        end
      end
    

    端     

答案 1 :(得分:0)

我建议两件事之一。

第一个选项:

添加:cancellation_date属性,然后在应用程序控制器中创建一个帮助程序方法,以便在登录时检查取消日期。如果他们超过了他们的订阅结束日期,请将您的:订阅设置为&#34 1#34;

# application_controller.rb
def my_helper
  if current_user.has_cancelled?
    redirect_to registration_path
  end
end

# user.rb although better to have the subscription do it instead
def has_cancelled?
  if cancellation_date.present? && cancellation_date > (paid_on + 30)
    subscription.update_attributes(cancelled: "1")
    return true
  else
    return false
  end
end

第二个选项:

使用像sucker_punch或sidekiq这样的后台工作每天早上运行并将过期的订阅设置为&#34; 1&#34;。

答案 2 :(得分:0)

错误的计划IMO:

您的订阅似乎是基于剩余的天数。因此,您只需要确保在请求user_is_subscripted时剩余的天数不为0.

current_user.subscription_expired?

def subscription_expired?
  days == 0
end

创建一个列:订阅日期,每次用户续订订阅时,都会在计数中添加30天。每天运行一个脚本,将该列中的订阅日减少1.这样您就不需要考虑帐户日期。

此外:

if subscription_expired? and autorenewal?
  renew_subscription(days)
end

def renew_subscription(days)
  #paypal magic
  current_user.subscription_days += days
end

当要求到期日时:

 def expiration_day
   Time.now + current_user.subscription_days.days
 end

答案 3 :(得分:0)

问题

您需要在试用期结束时更新用户的已取消列,而不是在实际取消时。

解决方案

Kimooz几乎是对的。你将使用Stripe Webhook,我将解释你需要做什么才能达到你想要的效果。

首先,如果我理解正确,你想模仿Stripe中发生的事情。基本上,您希望数据库取消列在用户保持错误状态,直到用户所有时间都过期。这意味着如果您的用户单击“取消”,则取消列中的任何内容都不会更改,直到所有时间到期,此时应将其设置为true。

因此,使用Stripe取消用户帐户,就像用户点击取消时一样。此时,您的用户Stripe :: Subscription对象唯一不同的是属性cancel_at_period_end设置为true。 subscription.status属性保持active,直到所有时间都过期。在所有时间到期之前,您的用户记录保持不变。

然后,设置一个Stripe Controller来处理webhook。通过这个过程似乎很痛苦,但这是实现解决方案的正确方法。

重要

此时您需要解析customer.subscription.updated事件 customer.subscription.deleted事件的webhook。 Stripe只会更新您的客户订阅。

如果您取消订阅,Stripe将不会删除您的客户订阅

...如果您取消订阅,它只会更新订阅状态。这意味着订阅以及与之相关的信息将保留在Stripe中,如果他们稍后续订,它仍然属于您的用户。

好的,所以..说你的用户在12月15日取消,但他们的订阅将于12月31日结束.Stripe会向你的webhook发送两个事件。

  • <强>十二月15 :此事件将是customer.subscription.updated事件,它会告诉您cancel_at_period_end属性已更新为true。 (status属性保持不变,active

  • <强>十二月31。:此活动将是customer.subscription.updated事件,它会告诉您status媒体资源已从active更改为cancelled

    < / LI>

当第二个事件发送到Stripe Webhook时,您现在可以解析事件并更改您自己数据库中的cancelled状态,因为所有时间都已到期。

答案 4 :(得分:0)

对此最简单的解决方案是,检查用户是否仍有访问权限的方法,检查下一个重复日期是否在将来。

这样您就可以立即将canceled标记为1