I have a built a peer to peer marketplace using Stripe Connect to process credit card payments with stripe checkout and transfer that charge to a connected stripe account with their bank account information and my account will take a commission.
My code was working previously in development mode but once I pushed it live to heroku I'm getting an error after the charge is sent through stripe checkout.
This is the current error I'm catching from running heroku logs...
Stripe::AuthenticationError (The provided key 'sk_live_********************3yOZ' does not have access to account 'ca_*******************1LR1' (or that account does not exist). Application access may have been revoked.):
Here is my spaghetti code... (Note: I'm just a weekend warrior at Rails... it's amazing I've gotten this far along not having any prior programming experience.)
Orders Controller
class OrdersController < ApplicationController
before_action :set_order, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
def sales
#orders = Order.all.where(seller: current_user).order("created_at DESC")
end
def purchases
#orders = Order.all.where(buyer: current_user).order("created_at DESC")
end
# GET /orders/new
def new
#order = Order.new
#item = Item.find(params[:item_id])
end
# POST /orders
# POST /orders.json
def create
#order = Order.new(order_params)
#item = Item.find(params[:item_id])
#seller = #item.user
#order.item_id = #item.id
#order.buyer_id = current_user.id
#order.seller_id = #seller.id
token = params[:stripeToken]
begin
customer = Stripe::Customer.create(
:email => params[:stripeEmail],
:source => token
)
require 'json'
charge = Stripe::Charge.create({
:customer => customer.id,
:amount => (#item.price * 91.1).floor - 30,
:currency => "usd",
:description => #item.title,
:application_fee => ((#item.price * 100) * 0.089).floor + 30
},
{:stripe_account => ENV["STRIPE_CONNECT_CLIENT_ID"] }
)
#order.name = params[:stripeShippingName]
#order.address = params[:stripeShippingAddressLine1]
#order.city = params[:stripeShippingAddressCity]
#order.state = params[:stripeShippingAddressState]
#order.zip = params[:stripeShippingAddressZip]
#order.country = params[:stripeShippingAddressCountry]
flash[:notice] = "Thanks for ordering!"
rescue Stripe::CardError => e
flash[:danger] = e.message
redirect_to new_order_path
end
respond_to do |format|
if #order.save
format.html { redirect_to root_url }
format.json { render :show, status: :created, location: #order }
else
flash[:alert] = "Something went wrong :("
# gon.client_token = generate_client_token
format.html { render :new }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_order
#order = Order.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def order_params
if params[:orders] && params[:orders][:stripe_card_token].present?
params.require(:orders).permit(:stripe_card_token)
end
end
end
OmniAuth Callbacks Controller
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def stripe_connect
#user = current_user
if #user.update_attributes({
provider: request.env["omniauth.auth"].provider,
uid: request.env["omniauth.auth"].uid,
access_code: request.env["omniauth.auth"].credentials.token,
publishable_key: request.env["omniauth.auth"].info.stripe_publishable_key
})
# anything else you need to do in response..
sign_in_and_redirect #user, :event => :authentication
set_flash_message(:notice, :success, :kind => "Stripe") if is_navigational_format?
else
session["devise.stripe_connect_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
end
Items Coffee Script (User must connect bank account info with Stripe Connect before listing)
jQuery ->
Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content'))
item.setupForm()
item =
setupForm: ->
$('#new_item').submit ->
$('input[type=submit]').attr('disabled', true)
Stripe.bankAccount.createToken($('#new_item'), item.handleStripeResponse)
false
handleStripeResponse: (status, response) ->
if status == 200
$('#new_item').append($('<input type="hidden" name="stripeToken" />').val(response.id))
$('#new_item')[0].submit()
else
$('#stripe_error').text(response.error.message).show()
$('input[type=submit]').attr('disabled', false)
Orders Coffee Script (Stripe will handle the card information at checkout)
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)
devise.rb initializer
config.omniauth :stripe_connect,
ENV['STRIPE_CONNECT_CLIENT_ID'],
ENV['STRIPE_SECRET_KEY'],
:scope => 'read_write',
:stripe_landing => 'register'
stripe.rb initializer
Rails.configuration.stripe = {
:publishable_key => ENV['STRIPE_PUBLISHABLE_KEY'],
:secret_key => ENV['STRIPE_SECRET_KEY']
}
Stripe.api_key = Rails.configuration.stripe[:secret_key]
application.yml (figaro) (keys censored)
production:
STRIPE_SECRET_KEY: "sk_live_****************3yOZ"
STRIPE_PUBLISHABLE_KEY: "pk_live_******************HhWi"
STRIPE_CONNECT_CLIENT_ID: "ca_**********************1LR1"
CONNECTED_STRIPE_ACCOUNT_ID: "acct_***********crNm"
orders _form.html.erb (just the stripe script)
<script src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="<%= Rails.configuration.stripe[:publishable_key] %>"
data-description="<%= #item.title %>"
data-amount="<%= (#item.price * 100).floor %>"
data-email="<%= current_user.email %>"
data-shipping-address="true"
data-locale="auto"></script>
The issue here is that you're mixing your constants. Whenever you make an API request on behalf of a connected account, you want to pass the connected account's id, acct_XXXYYYZZZ, in the Stripe-Account header.
The problem here is that you're instead passing your platform's client id ca_XXXX there. Stripe is then trying to find the account with the id ca_XXXX connected to your platform and it doesn't exist.
You need to fix your charge code to pass the correct constant:
charge = Stripe::Charge.create({
customer: customer.id,
amount: (#item.price * 91.1).floor - 30,
currency: 'usd',
description: #item.title,
application_fee: ((#item.price * 100) * 0.089).floor + 30
},
{
stripe_account: ENV["CONNECTED_STRIPE_ACCOUNT_ID"]
}
)
Related
My OrdersController is as follows below, but I keep getting this message:
undefined method `listing_id=' for #
Extracted source (around line #31):
29
30
31 #order.listing_id = #listing.id
Is there something I am doing incorrectly? Am following a tutorial so followed the instructions, then when it wasn't working decided to copy and paste, and it's still not working. Please, any help is appreciated.
Full code is as follows
class OrdersController < ApplicationController
before_action :set_order, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
def sales
#orders = Order.all.where(seller: current_user).order("created_at DESC")
end
def purchases
#orders = Order.all.where(buyer: current_user).order("created_at DESC")
end
# GET /orders/new
def new
#order = Order.new
#listing = Listing.find(params[:listing_id])
end
# POST /orders
# POST /orders.json
def create
#order = Order.new(order_params)
#listing = Listing.find(params[:listing_id])
#seller = #listing.user
#order.listing_id = #listing.id
#order.buyer_id = current_user.id
#order.seller_id = #seller.id
Stripe.api_key = ENV["STRIPE_API_KEY"]
token = params[:stripeToken]
begin
charge = Stripe::Charge.create(
:amount => (#listing.price * 100).floor,
:currency => "usd",
:card => token
)
flash[:notice] = "Thanks for ordering!"
rescue Stripe::CardError => e
flash[:danger] = e.message
end
respond_to do |format|
if #order.save
format.html { redirect_to root_url, notice: 'Order was successfully created.' }
format.json { render action: 'show', status: :created, location: #order }
else
format.html { render action: 'new' }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_order
#order = Order.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def order_params
params.require(:order).permit(:address, :city, :state)
end
end
Check Fields of the Order Model. Do you have listing_id as a column on the orders table ? Check the migration files to make sure that somewhere along the way you have added a "listing_id" field to the "orders" table.
Define strong params:
def order_params
params.require(:order).permit(:address, :city, :state, :listing_id, :buyer_id, :seller_id )
end
Completely banging my head against the wall trying to figure out how to cancel a user subscription. I have been all through StackOverflow and cant seem to find anything to help. Because I am fairly new to RoR the Stripe API only confuses me a bit more. I do understand that I need to capture and save the user ID somehow before i can cancel. I have not been able to figure this out...hence why i cant cancel subscriptions. HELP PLEASE
Subscribe_controller.rb
class SubscribeController < ApplicationController
before_filter :authenticate_user!
def new
unless (params[:plan_id] == '1' || params[:plan_id] == '2' || params[:plan_id] == '3')
flash[:notice] = "Please select a plan to sign up."
redirect_to new_subscribe_path
end
end
def update
# Amount in cents
token = params[:stripeToken]
customer = Stripe::Customer.create(
:email => current_user.email,
:card => token,
plan: params[:id]
)
current_user.subscribed = true
current_user.stripe_id = customer.id
current_user.save
redirect_to demo_path, notice: "Your Plan was created. Enjoy the demo!"
end
def cancel_plan
#user = current_user
if #user.cancel_user_plan(params[:customer_id])
#user.update_attributes(customer_id: nil, plan_id: 1)
flash[:notice] = "Canceled subscription."
redirect_to pricing_path
else
flash[:error] = "There was an error canceling your subscription. Please notify us."
redirect_to edit_user_registration_path
end
end
def update_plan
#user = current_user
if (params[:user][:stripe_id] != nil) && (params[:plan] == "2")
#user.update_attributes(plan_id: params[:plan], email: params[:email], stripe_id: params[:user][:stripe_id])
#user.save_with_payment
redirect_to edit_user_registration_path, notice: "Updated to premium!"
else
flash[:error] = "Unable to update plan."
redirect_to :back
end
end
end
User_controller.rb
class UsersController < ApplicationController
before_action :authenticate_user!
def update
if current_user.update_attributes(user_params)
flash[:notice] = "User information updated"
redirect_to edit_user_registration_path
else
flash[:error] = "Invalid user information"
redirect_to edit_user_registration_path
end
end
private
def user_params
params.require(:user).permit(:name)
end
end
Edit User Info Page
<div class="col-md-9 text-center">
<h2>Manage Plan</h2>
</div>
<div class="text-center">
<%= button_to "Cancel my account", cancel_plan_path, :data => { :confirm => "Are you sure?" }, :method => :delete, class: "btn btn-danger" %>
<button class="btn-lg btn btn-primary" disabled="disabled">Update Plan</button>
</div>
Routes.rb
get 'cancel_plan' => 'subscribe#cancel_plan'
resources :subscribe
devise_for :users
I am sure that you have seen this before stripe cancel subscription
first you have to get the customer the you can find there subscriptions so you can delete it
# Definition
customer = Stripe::Customer.retrieve({CUSTOMER_ID})
customer.subscriptions.retrieve({SUBSCRIPTION_ID}).delete
# Example
require "stripe"
Stripe.api_key = "sk_test_fSaKtH5qZMmhyXiF7YXup2wz"
customer = Stripe::Customer.retrieve("cus_5LXt66ikj5nYz5")
# customer.subscriptions returns a list of all subscriptions
customer.subscriptions.retrieve("sub_5TGMEBBALjNcD6").delete
Ultimate Answer
token = params[:stripeToken]
customer = Stripe::Customer.create(
:email => current_user.email,
:card => token,
plan: params[:id]
)
current_user.subscribed = true
current_user.stripe_id = customer.id
current_user.stripe_subscription_id = customer.subscriptions['data'][0].id
current_user.plan_name = customer.subscriptions['data'][0].plan.name
current_user.save
redirect_to demo_path, notice: "Your Plan was created. Enjoy the demo!"
In order to make this easier, you need to store the stripe_id and subscription_id in your database. Hence, after creating the columns stripe_id and subscription_id in your User model, you will have to save that:
customer = Stripe::Customer.create({
email: params[:stripeEmail],
source: params[:stripeToken],
plan: params[:plan]
})
subscription_id = customer.subscriptions['data'][0].id
user.update_attributes(stripe_id: customer.id, subscription_id: subscription_id)
Now you can always call the user's subscription since you have its id:
user = current_user
stripe_subscription = Stripe::Subscription.retrieve(user.subscription_id)
stripe_subscription.delete
If you only have the customer_id in your database, you can:
user = current_user
stripe_customer = Stripe::Customer.retrieve(user.stripe_id)
stripe_subscription = stripe_customer.['data'][0].delete
I have PayPal setup using the paypal recurring gem. I need help understanding how to implement PayPal IPN.
Any help would be greatly appreciated as this is the last step for my project. I need to have the IPN setup so that when users cancel/suspend billing from their PayPal account that it will show as cancelled from my database.
Paypal_payment.rb:
def initialize(subscription)
#subscription = subscription
end
def checkout_details
process :checkout_details
end
def checkout_url(options)
process(:checkout, options).checkout_url
end
def make_recurring
process :request_payment
process :create_recurring_profile, period: :monthly, frequency: 1, start_at: Time.zone.now
end
def suspend
process :suspend, :profile_id => #subscription.paypal_recurring_profile_token
end
def reactivate
process :reactivate, :profile_id => #subscription.paypal_recurring_profile_token
end
private
def process(action, options = {})
options = options.reverse_merge(
token: #subscription.paypal_payment_token,
payer_id: #subscription.paypal_customer_token,
description: #subscription.plan.name,
amount: #subscription.plan.price,
ipn_url: "http://mydomain.com/paypal/ipn",
currency: "USD"
)
response = PayPal::Recurring.new(options).send(action)
raise response.errors.inspect if response.errors.present?
response
end
end
Subscription.rb:
belongs_to :plan
belongs_to :subscription
belongs_to :user
validates_presence_of :plan_id
validates_presence_of :email
attr_accessor :stripe_card_token, :paypal_payment_token
def expires_at
self.updated_at + plan.duration.days
end
def save_with_payment
if valid?
if paypal_payment_token.present?
save_with_paypal_payment
else
save_with_stripe_payment
end
end
end
def paypal
PaypalPayment.new(self)
end
def save_with_paypal_payment
response = paypal.make_recurring
self.paypal_recurring_profile_token = response.profile_id
save!
end
def save_with_stripe_payment
customer = Stripe::Customer.create(description: email, plan: plan_id, card: stripe_card_token)
self.stripe_customer_token = customer.id
save!
rescue Stripe::InvalidRequestError => e
logger.error "Stripe error while creating customer: #{e.message}"
errors.add :base, "There was a problem with your credit card."
false
end
def payment_provided?
stripe_card_token.present? || paypal_payment_token.present?
end
def suspend_paypal
paypal.suspend
save
end
def reactivate_paypal
paypal.reactivate
save
end
def update_card(subscriber, card_info)
token = Stripe::Token.create(
card: {
number: card_info[:number],
exp_month: card_info[:exp_month],
exp_year: card_info[:exp_year],
cvc: card_info[:cvc]
}
)
customer = Stripe::Customer.retrieve(user.subscription.stripe_customer_token)
card = customer.cards.create(card: token.id)
card.save
customer.default_card = card.id
customer.save
rescue Stripe::InvalidRequestError => e
logger.error "Stripe error while updating card info: #{e.message}"
errors.add :base, "#{e.message}"
false
end
end
Subscriptions controller:
def new
plan = Plan.find(params[:plan_id])
#subscription = plan.subscriptions.build
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])
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()
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
routes:
post "paypal/ipn" => "notifications#create"
Payment Notifications controller:
def index
redirect_to root_url
end
def create
PaymentNotification.create!(:params => params, :status => params[:payment_status], :transaction_id => params[:txn_id])
render :nothing => true
end
end
Notifications controller:
def create
query = params
query[:cmd] = "_notify-validate"
if(response.body == "VERIFIED")
Rails.logger.debug params.inspect "Notification is valid"
end
end
end
You need to fix your routes.
It should be:
match '/paypal/ipn' => 'notifications#create', :via => [:get, :post], :as => 'notifications_create'
In the PayPal developer site there is an IPN test tool. You can provide it your callback URL and send sample calls. You'll have to register first to use it.
So you're only problem is getting the IPN's to trigger in your test account..?? When you use the Simulator does everything work as expected?
To get IPN working in the sandbox all you need to do is make sure it's enabled in your sandbox seller account profile. You can login to your sandbox account at http://sandbox.paypal.com just like you would a live account. Once you're in there go into the profile and then into IPN settings so you can enable it and set the URL accordingly.
I am looking to setup payment suspension for the paypal recurring gem (followed rails cast). I'm not sure if setting up IPN is required as there's no mention of it in the docs for the gem. The code I currently have takes no action.
I defined cancel recurring in the model, though I am not sure how to finish the code as it is hard for me to understand how this all works. This question has been asked by others but there are no answers to it.
If someone has the time to asset me that would be great!
The question is how to suspend/cancel the user recurring payment.
Paypal_payment.rb:
def initialize(subscription)
#subscription = subscription
end
def checkout_details
process :checkout_details
end
def checkout_url(options)
process(:checkout, options).checkout_url
end
def make_recurring
process :request_payment
process :create_recurring_profile, period: :monthly, frequency: 1, start_at: Time.zone.now
end
def suspend
process :suspend, :profile_id => #subscription.paypal_recurring_profile_token
end
private
def process(action, options = {})
options = options.reverse_merge(
token: #subscription.paypal_payment_token,
payer_id: #subscription.paypal_customer_token,
description: #subscription.plan.name,
amount: #subscription.plan.price,
currency: "USD"
)
response = PayPal::Recurring.new(options).send(action)
raise response.errors.inspect if response.errors.present?
response
end
end
Subscriptions controller:
def new
plan = Plan.find(params[:plan_id])
#subscription = plan.subscriptions.build
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])
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)
#customer.update_subscription(:plan => "1", :prorate => true)
current_user.save!
flash.alert = 'Your subscription has been updated!'
redirect_to root_url
end
def cancelsubscription
#user = current_user
#customer = Stripe::Customer.retrieve(#user.subscription.stripe_customer_token)
#customer.cancel_subscription()
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 changecard
#user = current_user
#customer = Stripe::Customer.retrieve(#user.subscription.stripe_customer_token)
card = #customer.cards.create({
:card => #user.subscription.stripe_customer_token
})
#customer.default_card = card
#customer.save
end
def suspend
#user = current_user
#user.subscription.suspend_paypal
end
def updatebilling
#user = current_user
customer = Stripe::Customer.retrieve(#user.subscription.stripe_customer_token)
customer.cards.retrieve("#{#user.subscription.stripe_card_id}").delete()
customer.cards.create({
card: {
number: params[:user][:scardnumber],
exp_month: params[:user][:sexp_month],
exp_year: params[:user][:sexp_year],
cvc: params[:user][:scvc],
name: params[:user][:sname],
address_line1: params[:user][:sbilling_address1],
address_line2: params[:user][:sbilling_address2],
address_city: params[:user][:saddress_city],
address_zip: params[:user][:saddress_zip],
address_state: params[:user][:saddress_state],
address_country: params[:user][:saddress_country]
}
})
if customer.save!
#user.stripe_card_id = customer.active_card.id
#user.save!
flash.alert = 'Billing information updated successfully!'
redirect_to root_url
else
flash.alert = 'Stripe error'
redirect_to root_url
end
end
end
Subscription Model:
belongs_to :plan
belongs_to :subscription
belongs_to :user
validates_presence_of :plan_id
validates_presence_of :email
attr_accessor :stripe_card_token, :paypal_payment_token
def save_with_payment
if valid?
if paypal_payment_token.present?
save_with_paypal_payment
else
save_with_stripe_payment
end
end
end
def paypal
PaypalPayment.new(self)
end
def save_with_paypal_payment
response = paypal.make_recurring
self.paypal_recurring_profile_token = response.profile_id
save!
end
def save_with_stripe_payment
customer = Stripe::Customer.create(description: email, plan: plan_id, card: stripe_card_token)
self.stripe_customer_token = customer.id
save!
rescue Stripe::InvalidRequestError => e
logger.error "Stripe error while creating customer: #{e.message}"
errors.add :base, "There was a problem with your credit card."
false
end
def payment_provided?
stripe_card_token.present? || paypal_payment_token.present?
end
def suspend_paypal
paypal.suspend
self.status = "canceled"
save
end
end
Routes:
get "subscriptions/cancelsubscription"
get "subscriptions/updatesubscription"
get "subscriptions/changecard"
get "subscriptions/suspend"
get "subscriptions/updatebilling"
resources :charges
resources :subscriptions
resources :plans
get 'paypal/checkout', to: 'subscriptions#paypal_checkout'
View:
<%= link_to "Suspend paypal", subscriptions_suspend_path, :data => { :confirm => "Are you sure?" } %>
This PaypalPayment is a kind of wrapper for the paypal-recurring gem. So all of the methods in this class just prepare and delegate to PayPal::Recurring that's why all of the methods just call the 'process' method which instantiate and pass the action.
So for suspending/cancelling you just need to add a method for each of this actions. As the document states you need to do this for cancel
ppr = PayPal::Recurring.new(:profile_id => "I-VCEL6TRG35CU")
ppr.suspend
So for your PaypalPayment class it would look like this:
def suspend
process :suspend, :profile_id => #subscription.paypal_recurring_profile_token
end
So your model subscription.rb
def suspend_paypal
paypal.suspend
self.status = "canceled"
save
end
And the controller susbcription_controller.rb
def suspend
current_user.suspend_paypal
end
About IPN, I don't think its necessary if the user suspend through your site, but as the user might cancel it directly through paypal you have to handle this case so the User don't stop paying but keep with an active subscription.
in my app I am using the 'Stripe' gem to setup payments. Everything was going fine but whenever I submit the payment it gives me the error 'You must supply a valid card'.
Below is my code.
Ad Controller
class AdsController < ApplicationController
before_action :set_ad, only: [:show, :edit, :update, :destroy]
# GET /ads
# GET /ads.json
def index
#ads = Ad.order('created_at DESC').search(params[:search])
#ads_small = Ad.where(:size => "small").order('created_at DESC')
#ads_medium = Ad.where(:size => "medium").order('created_at DESC')
#ads_featured = Ad.where(:size => "featured").order('created_at DESC')
end
def myads
#ads_mine = Ad.where(:user_id => current_user.id )
end
# GET /ads/1
# GET /ads/1.json
def show
end
# GET /ads/new
def new
#ad = Ad.new
end
# GET /ads/1/edit
def edit
end
# POST /ads
# POST /ads.json
def create
#ad = Ad.new(ad_params)
#ad.user_id = current_user.id
respond_to do |format|
if #ad.save_with_payment
format.html { redirect_to #ad, notice: 'Ad was successfully created.' }
format.json { render action: 'show', status: :created, location: #ad }
else
format.html { render action: 'new' }
format.json { render json: #ad.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /ads/1
# PATCH/PUT /ads/1.json
def update
respond_to do |format|
if #ad.update(ad_params)
format.html { redirect_to #ad, notice: 'Ad was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #ad.errors, status: :unprocessable_entity }
end
end
end
# DELETE /ads/1
# DELETE /ads/1.json
def destroy
#ad.destroy
respond_to do |format|
format.html { redirect_to ads_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_ad
#ad = Ad.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def ad_params
params.require(:ad).permit(:title, :url, :preview, :location, :size, :info, :search)
end
end
Ad Model
class Ad < ActiveRecord::Base
belongs_to :user
has_attached_file :preview, :styles => { :medium => "125x125^", :featured => "250x250^", :showpg => "400x400^" }, :convert_options => {:medium => "-gravity center -extent 125x125", :featured => "-gravity center -extent 250x250", :showpg => "-gravity center -extent 400x400"}
validates :title, length: { maximum: 35 }
validates :url, length: { maximum: 40 }
attr_accessor :stripe_card_token
def self.search(search)
if search
find(:all, :conditions => ['LOWER(title) ILIKE ? or LOWER(info) ILIKE ? or LOWER(location) ILIKE ?', ("%#{search.downcase}%"), ("%#{search.downcase}%"), ("%#{search.downcase}%")])
else
find(:all)
end
end
def save_with_payment
if valid?
customer = Stripe::Customer.create(description: "ad stripe customer", plan: "ad_f", card: stripe_card_token)
self.stripe_customer_token = customer.id
save!
end
end
end
ads.js.coffee
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
jQuery ->
Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content'))
ad.setupForm()
ad =
setupForm: ->
$('#new_ad').submit ->
$('input[type=submit]').attr('disabled', true)
ad.processCard()
false
processCard: ->
card =
number: $('#card_number').val()
cvc: $('#card_code').val()
expMonth: $('#card_month').val()
expYear: $('#card_year').val()
Stripe.createToken(card, ad.handleStripeResponse)
handleStripeResponse: (status, response) ->
if status == 200
$('#ad_stripe_card_token').val(response.id)
$('#new_ad')[0].submit()
else
alert(response.error.message)
$('input[type=submit]').attr('disabled', false)
Any help would be greatly appreciated. :)
In your Ad model, you have:
attr_accessor :stripe_card_token
and then you use the token in save_with_payment:
customer = Stripe::Customer.create(..., card: stripe_card_token)
self.stripe_customer_token = customer.id
So far so good. But you use ad_params to filter params in your controller when you create your Ad:
def ad_params
params.require(:ad).permit(:title, :url, :preview, :location, :size, :info, :search)
end
and I don't see :stripe_card_token in the permitted list anywhere. Presumably the #ad_stripe_card_token in your HTML looks like this:
<input type="hidden" name="ad[stripe_card_token]">
so you should be able to add :stripe_card_token to the permitted list in ad_params and get things going.