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.
Related
I'm using paypal-recurring gem for my app and i can't figure out how to cancel a user's subscription. i tried gabriel's answer from a similar question on here, but i get a NoMethodError in SubscriptionsController#suspend undefined method 'suspend_paypal' for User` when trying to cancel the subscription.
In my subscriptions.rb model
class Subscription < ApplicationRecord
belongs_to :plan
belongs_to :user
validates_presence_of :plan_id
validates_presence_of :user_id
attr_accessor :paypal_payment_token
def save_with_payment
if valid?
if paypal_payment_token.present?
save_with_paypal_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 suspend_paypal
paypal.suspend
self.status = "canceled"
save
end
def payment_provided?
paypal_payment_token.present?
end
end
subscriptions_controller
class SubscriptionsController < ApplicationController
before_action :authenticate_user! , only: [:new, :edit]
def new
plan = Plan.find(params[:plan_id])
#subscription = plan.subscriptions.build
#subscription.user_id = current_user.id
if params[:PayerID]
#subscription.paypal_cutomer_token = params[:PayerID]
#subscription.paypal_payment_token = params[:token]
#subscription.email = #subscription.paypal.checkout_details.email
end
end
def index
end
def create
#user = current_user
#subscription = Subscription.new(subscription_params)
if #subscription.save_with_payment
redirect_to root_path, :notice => "Thank you for subscribing"
#user.premium!
else
render :new
end
end
def suspend
#user = current_user
#user.suspend_paypal
flash[:success] = 'Subscription Canceled.'
#user.free!
redirect_to root_path
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
private
def subscription_params
params.require(:subscription).permit!
end
end
paypal_payment.rb
class PaypalPayment
def initialize(subscription)
#subscription = subscription
end
def checkout_details
process :checkout_details
end
def payment_active?
self.status = "active"
end
def suspend
process :suspend, :profile_id => #subscription.paypal_recurring_profile_token
end
def checkout_url(options)
process(:checkout, options).checkout_url
end
def save_with_paypal_payment
response = paypal.make_recurring
self.paypal_recurring_profile_token = response.profile_id
save!
end
def make_recurring
process :request_payment
process :create_recurring_profile, period: :monthly, frequency: 1, start_at: Time.zone.now
end
private
def process(action, options = {})
options = options.reverse_merge(
token: #subscription.paypal_payment_token,
payer_id: #subscription.paypal_cutomer_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
View
<%= link_to "Suspend paypal", subscriptions_suspend_path, :data => { :confirm => "Are you sure?" } %>
You have defined suspend_paypal on the Subscription model, but you're trying to call it on user. Get the subscription instead and call the method:
# class SubscriptionsController
def suspend
#subscription = Subscription.find(params[:id])
#subscription.suspend_paypal
flash[:success] = 'Subscription Canceled.'
current_user.free!
redirect_to root_path
end
Note -- you should add authorization logic, otherwise any user who can authenticate can suspend an arbitrary subscription by sending its ID. If a user has_many subscriptions, subscription = current_user.subscriptions.find(params[:id]). If has_one, just current_user.subscription and validate that that matches params[:id] for good measure.
You probably also don't need subscription to be an ivar since you're simply redirecting to root. Just replace #subscription with subscription. Use ivars when you need to access those variables in the views.
I have Stripe setup and I am trying to delete the current user card on file and add a new one.
In doing so I get the error message Stripe::InvalidRequestError Customer cus_3hWPcPgUi04tCO does not have card with ID {#user.subscription.stripe_card_id}
It points to the subscription controller on line customer.cards.retrieve("{#user.subscription.stripe_card_id}").delete()
I'm not sure how to get it to call the card id, as it should be using the test card id of card_103hWP26pFykwX9Rv8dExvYh.
class SubscriptionsController < ApplicationController
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
flash.alert = 'Billing has been suspended!'
redirect_to root_url
end
def reactivate
#user = current_user
#user.subscription.reactivate_paypal
flash.alert = 'Billing has been activated!'
redirect_to root_url
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
Just use
customer.cards.retrieve(#user.subscription.stripe_card_id).delete()
instead of
customer.cards.retrieve("{#user.subscription.stripe_card_id}").delete().
The field should be a string already, just do
customer.cards.retrieve(#user.subscription.stripe_card_id).delete()
I have this setup for Stripe, but I can't seem to figure it out for PayPal recurring gem. I am looking to allow users to switch their payment plan. If user is subscribed to the 1 month subscription (plan_id 1) they should be able to upgrade to year subscription (plan_id 12).
Any help would be appreciated!
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 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
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 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
PayPal Payment model:
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,
currency: "USD"
)
response = PayPal::Recurring.new(options).send(action)
raise response.errors.inspect if response.errors.present?
response
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
save
end
def reactivate_paypal
paypal.reactivate
save
end
end
Unfortunately it is not possible to update or change a subscription's term on PayPal. This subscription would have to be cancelled and a new one set up.
API Reference for UpdateRecurringPaymentsProfile
You would need to calculate the prorated difference, and charge them an INITAMT when setting up the new profile, then set the start date for new AMT that is to be collected after their term is up.
Edit: This is assuming you are using this gem. Since I am unable to find anywhere that it tries to do this automatically for you.
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.
I have a Question & Answer feature and I am just about finished with it. I have no idea how to do the code that would send a message to user when another user has asked them a question. For example, User A sends User B a question, a inbox message is sent to User B notifying them that they have a new question.
There's two ways I thought how to go about this.
Method #1
Inside the message it will link user to the page with the Question on it so it can be answered
Method #2
Inside the message it will include the question that was asked. User can reply to message which would submit as their answer.
Questions controller:
respond_to :js, :html
def index
#questions = Question.all
respond_with(#questions)
end
def show
#question = Question.find(params[:id])
#questions = Question.order("created_at DESC")
respond_with(#questions)
end
def new
#question = Question.new
respond_with(#question)
end
def create
#question = Question.new(params[:question])
if #question.save
redirect_to questions_path, notice: 'Your question was saved successfully. Thanks!'
else
render :new, alert: 'Sorry. There was a problem saving your question.'
end
end
end
Answers controller:
def new
#question = Question.find(params[:question_id])
end
def create
#question = Question.find(params[:question_id])
if #question.update_attributes(params[:question])
redirect_to questions_path
else
render :new
end
end
end
Messages controller:
before_filter :set_user
def index
if params[:mailbox] == "sent"
#messages = #user.sent_messages
elsif params[:mailbox] == "inbox"
#messages = #user.received_messages
#elsif params[:mailbox] == "archived"
# #messages = #user.archived_messages
end
if params[:mailbox] == "unread"
#messages = #user.unread_messages
end
end
def new
#message = Message.new
if params[:reply_to]
#reply_to = User.find_by_sender_id(params[:reply_to])
unless #reply_to.nil?
#message.recipient_id = #reply_to.sender_id
end
end
end
def create
#message = Message.new(params[:message])
#message.sender_id = #user.id
if #message.save
flash[:notice] = "Message has been sent"
redirect_to user_messages_path(current_user, :mailbox=>:inbox)
else
render :action => :new
end
end
def show
#message = Message.find(params[:id])
#message.readingmessage if #message.recipient == current_user
end
def destroy
#message = Message.find(params[:id])
#message.destroy
flash[:notice] = "Successfully deleted message."
redirect_to user_messages_path(#user, #messages)
end
def delete_multiple
if params[:delete]
params[:delete].each { |id|
#message = Message.find(id)
#message.mark_message_deleted(#message.id,#user.id) unless #message.nil?
}
flash[:notice] = "Messages deleted"
end
redirect_to user_messages_path(#user, #messages)
end
private
def set_user
#user = current_user
end
end
Message model:
attr_accessible :subject, :body, :sender_id, :recipient_id, :read_at,:sender_deleted,:recipient_deleted
validates_presence_of :subject, :message => "Please enter message title"
has_many :notifications, as: :event
scope :unread, -> {where('read_at IS NULL')}
scope :not_deleted_by_recipient, where('messages.recipient_deleted IS NULL OR messages.recipient_deleted = ?', false)
scope :not_deleted_by_sender, where('messages.sender_deleted IS NULL OR messages.sender_deleted = ?', false)
belongs_to :sender,
:class_name => 'User',
:foreign_key => 'sender_id'
belongs_to :recipient,
:class_name => 'User',
:foreign_key => 'recipient_id'
# marks a message as deleted by either the sender or the recipient, which ever the user that was passed is.
# When both sender and recipient marks it deleted, it is destroyed.
def mark_message_deleted(id,user_id)
self.sender_deleted = true if self.sender_id == user_id
self.recipient_deleted = true if self.recipient_id == user_id
(self.sender_deleted && self.recipient_deleted) ? self.destroy : self.save!
end
# Read message and if it is read by recipient then mark it is read
def readingmessage
self.read_at ||= Time.now
save
end
# Based on if a message has been read by it's recipient returns true or false.
def read?
self.read_at.nil? ? false : true
end
def self.received_by(user)
where(:recipient_id => user.id)
end
def self.not_recipient_deleted
where("recipient_deleted = ?", false)
end
def self.sent_by(user)
Message.where(:sender_id => user.id)
end
def previous(same_recipient = true)
collection = Message.where('id <> ? AND created_at > ?', self.id, self.created_at).order('created_at ASC')
collection = collection.where(recipient_id: self.recipient_id) if same_recipient
collection = collection.not_deleted_by_recipient
collection.first
end
def next(same_recipient = true)
collection = Message.where('id <> ? AND created_at < ?', self.id, self.created_at).order('created_at DESC')
collection = collection.where(recipient_id: self.recipient_id) if same_recipient
collection = collection.not_deleted_by_recipient
collection.first
end
end
private
def send_notification(message)
message.notifications.create(user: message.recipient)
end
I have solved this.
Questions Controller:
def create
#question = Question.new(params[:question])
if #question.save
#message = Message.create(:subject => "Hey you have a message from #{#question.sender_id}",
:sender_id => #question.sender_id,
:recipient_id => #question.recipient_id,
:body => #question.question)
#question.message = #message
#question.save
redirect_to questions_path, notice: 'Your question was saved successfully. Thanks!'
else
render :new, alert: 'Sorry. There was a problem saving your question.'
end
end
Every time a notification is needed, you should create it. It would go for having a Notification model that takes at least the object for which the notification was created, the user that the notification goes to and a flag whether it has been read or not.
To display the notifications, the easiest way of course is to integrate that into your layout file and do something like this:
Notification.where(:user_id => #current_user).size > 0
<%= "You have #{Notification.where(:user_id => #current_user).size} notification(s)" %>
end
And to nicen things up you can create a scope inside of the Notification object which will give you the notifications for a specific user. Of course if you want all the magic like Stackoverflow has with updating the notifications through AJAX calls, you will have to do some JavaScript lifting.