Stripe, Canceling Subscription Ruby on Rails - ruby-on-rails

Im trying to cancel a subscription which is already created. I did pass the correct customer id and plan id. Yet i get an error in my terminal saying
Stripe::InvalidRequestError (Customer cus_xxxxxxxxxxx does not have a subscription with ID Golden)
Here are my controller methods.
def create
sub_plan = params[:plan_id]
subscription_plan_id = SubscriptionPlan.where(plan_id:sub_plan).first.id
token = params[:stripeToken]
email = current_user.email
customer = Stripe::Customer.create(
:card => token,
:plan => sub_plan,
:email => email
)
Subscription.create(subscription_plan_id:subscription_plan_id,user_id:current_user.id,stripe_customer_token:customer[:id])
redirect_to '/membership'
end
def destroy
p "---------------------------"
subscription_plan_id = SubscriptionPlan.where(plan_id:params[:plan_id]).first.id
customer_id = Subscription.where(subscription_plan_id:subscription_plan_id,user_id:current_user.id).first.stripe_customer_token
customer = Stripe::Customer.retrieve(customer_id)
customer.subscriptions.retrieve(params[:plan_id]).delete()
Subscription.where(subscription_plan_id:subscription_plan_id,user_id:current_user.id).first.destroy
end
in my create method a user creates a subscription which happens successfuly, It appears on my stripe account too..
But on trying to destroy it this error occurs. Is there anything wrong. Pls help. Thanx in advance

A stripe subscription can't be retrieve with a plan id.
To retrieve a subscription : first you need a customer :
customer = Stripe::Customer.retrieve("cus_xxxxxxxxxx")
With the customer you can retrieve all his subscriptions :
subscriptions = customer.subscriptions.data
Or a specific subscription with retrieve method and stripe_id of subscription ( doc ref : https://stripe.com/docs/api/ruby#retrieve_subscription ) :
subscription = customer.subscriptions.retrieve("sub_xxxxxxxxxx")
Hope this helps

Related

Stripe::InvalidRequestError Must provide source or customer

order controller page
begin
Stripe.api_key = ENV["STRIPE_API_KEY"]
token = params[:stripeToken]
charge = Stripe::Charge.create(
:amount => (#listing.price * 100).floor,
:currency => "usd",
:source => params[:stripeToken],
:destination => #seller.recipient
)
flash[:notice] = "Thanks for ordering!"
rescue Stripe::CardError => e
flash[:danger] = e.message
end
order.js.coffee
jQuery ->
Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content'))
payment.setupForm()
payment =
setupForm: ->
$('#new_order').submit ->
$('input[type=submit]').attr('disabled', true)
Stripe.card.createToken($('#new_order'), payment.handleStripeResponse)
false
handleStripeResponse: (status, response) ->
if status == 200
$('#new_order').append($('<input type="hidden" name="stripeToken" />').val(response.id))
$('#new_order')[0].submit()
else
$('#stripe_error').text(response.error.message).show()
$('input[type=submit]').attr('disabled', false)
I am not sure why the source => params[:stripeToken] is not passing thru when I check the log in my stripe account. Is the token null?
Usually when you receive this error is because the publishable key is not in your form so when you send the form to stripe it doesn´t recognize you and it doesn´t send you back the token.
The process of charging a client goes this way.
1.- In your site you tell the user to type his card information in a form (hosted locally or just created by stripe script).
2.- Once the user submit the form. The information is submitted to stripe server with your publishable key. You receive a response from the server with a token. This token is forwarded to the action in your controller and since is linked to your account you can create a customer, a charge or join the user to a plan. This is the 'params[:stripeToken]'. The card information never reaches your controller, you just receive this token.
You can do two things to charge your clients, the first is create the form your self and the second just delegate it to the stripe script.
The first one is more tricky since stripe updates their api from time to time. It requires some knowledge of js and their api. For example Stripe v3 is different from v2. Allows more rationalization but requires more knowledge of js. The information and examples of how to configure can be found in stripe elements.
The second one is pretty easy. I recommend it to not advanced users. You can implement it just following the instructions in this link using checkout and rails.
I usually use the second option since it just takes 5 minutes and you delegate the hard work to stripe.

How to get multiple values of a record with map

In my application I can have multiple accounts and accounts can have multiple emails. I have a method that counts all the unique email from every account, but that is not what I want however.
Instead I want to return all the unique email from just one account NOT all, as the method is currently doing.
Here is my current method:
class AccountEmails
def self.count
accounts = Account.all
alert = accounts.map do |a|
a.users.first.alert_email.split(",")
end
billing = accounts.map do |a|
a.users.first.billing_email.split(",")
end
user = accounts.map do |a|
a.users.first.email.split(",")
end
snitch = accounts.map do |a|
a.snitches.map { |s| s.alert_email.split(",") }
end
[alert, billing, user, snitch].flatten.uniq.count
end
end
This will return all the email that are unique from all the accounts. I want to return all the unique email for each account, so account 1 could have four unique email and account 2 could have five unique email.
It sounds like you're saying you want a single method that gives you all the unique emails for each account. If I'm understanding you, I would do something like this:
class Account
def all_emails
# I'm assuming here that you actually only want the unique
# emails on the first user for each account
user = self.users.first
[
user.alert_email.split(","),
user.billing_email.split(","),
user.email.split(","),
self.snitches.map{|snitch| snitch.alert_email.split(",") }
].flatten
end
def unique_emails
all_emails.uniq
end
end
class AccountEmails
def self.unique
Account.all.includes(:snitches).map do |account|
account.uniq_emails
end
end
def self.count
uniq.flatten.count
end
end

Access subscription details in Stripe payment

I have two subscription plans in my Ruby on Rails application. I use stripe webhook to email to customer when subscription has been created. In the email I want to store data about subscription (and plan) details e.g. when trial_end and plan name or price.
def webhook
stripe_event = Stripe::Event.retrieve(params[:id]) #retrieving Event ID
if stripe_event.type == "customer.subscription.created" #checks if retrieved Event type subscription is created
stripe_customer_token = stripe_event.data.object.customer # Get Customer ID
customer = Stripe::Customer.retrieve(stripe_customer_token) #here I'm able to retrieve Customer data e.g. customer.email
subscription = customer.subscriptions.first.id #according to documentation I need to retrieve Subscription by supplying its ID. I can retrieve Subscription, but don't understand how to retrieve its data, like: subscription.trial_end
UserMailer.customer_subscription_created(customer.email).deliver #this works well
UserMailer.customer_subscription_created(subscription.trial_end).deliver #this does not work
end
end
I have retrieved Subscription of my Customer. When I retrieve customer I can access my customer data like: customer.email I assumed I would be able to do the same when I retrieve Subscription: subscription.trial_end, but this gives me an error. How can I access Subscription data?
Besides when I change plan of a Subscription I do it like so and it works:
def change_user_plan(customer_id, subscription_id)
customer = Stripe::Customer.retrieve("#{customer_id}")
subscription = customer.subscriptions.retrieve("#{subscription_id}")
subscription.plan = 2
subscription.save
end
Here is link to Stripe API to retrieve Subscription
You are correct, you are able to do what you are trying to do. Once you have your subscription, subscription.trial_end works. I just tested it:
2.1.6 :013 > customer = Stripe::Customer.retrieve("#{customer_id}")
=> #<Stripe::Customer:0x3fcd1ed0a630 id=...> JSON: { ... }
2.1.6 :014 > subscription = customer.subscriptions.retrieve("#{subscription_id}")
=> #<Stripe::Subscription:0x3fcd1ecae574 id=...> JSON: { ... }
2.1.6 :015 > subscription.trial_end
=> 1438387199
The problem is this line:
subscription = customer.subscriptions.first.id
You are saving the subscription id itself. You need to do:
subscription = customer.subscriptions.first
to save the whole subscription. Also, you can use subscriptions.retrieve to supply the id for retrieval (as you are doing in your second code example).

PayPal IPN not connecting with canceling recurring billing

I need help to understand how to mark user as cancelled in my database when the user cancels the recurring payment via PayPal.
Notifications controller:
def create
params.permit! # Permit all Paypal input params
#query = params
puts "in method*************************************"
#query[:cmd] = "_notify-validate"
#if params[:txn_type] == 'subscr_cancel'
# user_subscription = Subscription.find_by(paypal_customer_token: params[:payer_id])
# user_subscription.update_column("cancelled",1) if user_subscription.present?
#els
if params[:txn_type] == 'recurring_payment_profile_cancel'
user_subscription = Subscription.find_by(paypal_recurring_profile_token: params[:recurring_payment_id])
user_subscription.update_column("cancelled",1) if user_subscription.present?
end
render :text => 'OK'
end
end
Hm,, I think you have to uncommend the lines you have commented,, somehting like this:
if params[:txn_type] == 'subscr_cancel'
user_subscription = Subscription.find_by(paypal_customer_token: params[:payer_id])
user_subscription.update_column("cancelled",1) if user_subscription.present?
end
I'm using php api and have this 'subscr_cancel' when user cancels subscription

Rails 3: loops and plucking items out best practices

I am working on a small app that allows for users to add a product (or subscription) to their cart. Upon creating their account, the new user is sent to a "bundle" page where it asks if they would like to add a different subscription to a different product altogether for a bundled price.
Here is where I am stuck: Upon submitting the user's credit card info I get slightly "lost in translation" when trying to setup the bundle pricing to submit to Authorize.net (I understand how to authnet, not the question here).
Here is what I have so far:
current_order.products.includes(:client).each do |product|
transaction = current_order.submit_order_to_authnet(product)
if transaction.result_code == 'Ok'
new_group = Group.create!(:name => "#{current_user.full_name} #{product.title}", :type => 'school', :start_date => Time.now, :status => 'active', :site_id => 1)
primary = session[:primary_product_id].eql?(product.id) ? true : false
# Add subscription to Group
new_group.add_subscription(product, current_order, transaction.subscription_id, 'active', primary)
# Add Subscription to CurrentOrder
current_order.subscriptions << new_group.subscriptions.last
# Add user to NewGroup
current_user.groups << new_group
# Create New Group Admin
new_group.group_admins.create(:user_id => current_user.id)
# Send success email
OrderMailer.checkout_confirmation(current_user).deliver
else
errors << transaction.result_code
end
end
I am trying to figure out the best solution when it comes to looping through each product in the users current_order because the second subscription in the users cart is the subscription that gets the discount applied too. I know I can write something like this:
current_order.products.includes(:client).each do |product|
if current_order.products.many? and product == current_order.products.last
# run discount logic
else
# continue with authnet for single subscription
end
end
But I am just not sure if that is a best practice or not. Thoughts?
So the only subscription that doesn't get discounted is the first one? Why not write it like this:
current_order.products.includes(:client).each do |product|
if product == current_order.products.first
# continue with authnet for single subscription
else
# run discount logic
end
end

Resources