Every purchase receipt is populated with the same product info - ruby-on-rails

I have a store where you can buy digital products via download. Every product purchased (I've tested multiple products) displays the same product's information (title, art_link, and download_url) on the thank you page right after purchase.
What Am I doing wrong here that is preventing it from loading the correct data from the pack just purchased?
I'm using Stripe for payments. Everything else works perfectly, the money goes through, the email is sent and links to the receipt, the UUID works, etc.
UPDATE: I've checked my DB and Everything is saving correctly. The only problem is with the purchases/show view not rendering properly.
purchases/show:
<p><b><%= #pack.title %></b></p>
<%= image_tag("#{#pack.art_link}", :alt => "#{#pack.title} sound library.", :width => 330, :height => 330, class: "img-center img-responsive shade") %>
<p><a class="btn btn-success top-drop" href="<%= #pack.download_url %>" target="_blank">Download Files</a></p>
purchases_controller:
def show
#purchase = Purchase.find_by_uuid(params[:id])
#pack = Pack.find(#purchase.product_id)
set_meta_tags noindex: true
end
Purchase model:
attr_accessor :download_token
after_create :email_purchaser
def to_param
uuid
end
def email_purchaser
PurchaseMailer.purchase_receipt(self).deliver
end
def Purchase.new_token
SecureRandom.urlsafe_base64
end
def create_download
self.download_token = Purchase.email.new_token
update_attribute(:download, Purchase.email(download_token))
update_attribute(:download_sent_at, Time.zone.now)
end
charges_controller:
def create
pack = Pack.find(params[:product_id])
customer = Stripe::Customer.create(
:email => params[:stripeEmail],
:source => params[:stripeToken],
)
# Amount in cents
charge = Stripe::Charge.create(
:customer => customer.id,
:amount => pack.price_in_cents,
:description => 'Rails Stripe customer',
:currency => 'usd',
)
purchase = Purchase.create(
email: params[:stripeEmail],
card: params[:stripeToken],
amount: pack.price_in_cents,
description: charge.description,
currency: charge.currency,
customer_id: customer.id,
product_id: pack.id,
uuid: SecureRandom.uuid,
)
redirect_to purchase
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to new_charge_path
end
Thank you very much, this really has me stuck.
Routes.rb:
resources :packs, :path => 'products'
resources :charges
resources :purchases, only: [:show]

The problem was solved on a chat.
In routes.rb, there were following lines:
get 'purchase' => 'purchases#show', as: 'purchase'
...
resources :purchases, only: [:show]
So when OP called: redirect_to purchase the URL was:
http://localhost:3000/purchase.4c77a556-299e-4611-b683-3ff6eb672738
From that, the params[:id] was nil. In DB, there were 4 purchases with UUID equal nil, and the first one was always returned (because find_by returns the first matched record).

Related

stripe CardError (Cannot charge a customer that has no active card)

def create_charge
#amount = 500
customer = Stripe::Customer.create(email: params[:email])
pay = Stripe::Charge.create(
:amount => params[:amount],
:currency =>params[:currency],
# :source=>params[:token],
:customer=>customer.id, # obtained with Stripe.js
:description => "Charge for ")
send_json_response("Payment","success",{:pay=>pay})
end
Am trying to create a customer and charge that customer using Rails and Stripe. The customer is getting created in Stripe, but I keep getting the error Cannot charge a customer that has no active card when trying to do the charge
if you are taking info of card on this time ... first check card is valid or not
begin
#token = Stripe::Token.create(
:card => {
:number => params[:card][:card_number],
:exp_month => params[:card][:exp_month],
:exp_year => params[:card][:exp_year],
:cvc => params[:card][:ccv]
},
)
rescue Stripe::CardError, Stripe::InvalidRequestError => e
flash[:error] = e.message and return
rescue
flash[:notice] = 'Something went wrong! Try Again' and return
end
if customer is connected to your website
run webhooks of stripe to check if customer has valid card if not then take that customer to update card page ... to update its card before any purchase
check event type where ( "type": "customer.source.updated")
https://stripe.com/docs/api#event_types
on update card try to check again card is valid or not

Rails Stripe Retrieve ID Error "No such plan"

So my Plan says Stripe::InvalidRequestError at /orders/26/payments
No such plan: The title of my plan.
This code should check if the the plan already exists and if not create it and subscribe the user to it. I thought this worked because it was working for the case where I already had a plan with the same ID and it said "Plan already exists". How can I prevent this Error from happening?
This is my code:
class PaymentsController < ApplicationController
before_action :set_order
def new
end
def create
#user = current_user
customer = Stripe::Customer.create(
source: params[:stripeToken],
email: params[:stripeEmail],
)
# Storing the customer.id in the customer_id field of user
#user.customer_id = customer.id
#plan = Stripe::Plan.retrieve(#order.service.title)
unless #plan
plan = Stripe::Plan.create(
:name => #order.service.title,
:id => #order.service.title,
:interval => "month",
:currency => #order.amount.currency,
:amount => #order.amount_pennies,
)
else
subscription = Stripe::Subscription.create(
:customer => #user.customer_id,
:plan => #order.service.title
)
end
#order.update(payment: plan.to_json, state: 'paid')
redirect_to order_path(#order)
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to new_order_payment_path(#order)
end
private
def set_order
#order = Order.where(state: 'pending').find(params[:order_id])
end
end
The documentation says that if you try to retrieve a plan that does not exist, it will raise an error. So you just need to catch the error:
begin
#plan = Stripe::Plan.retrieve(#order.service.title)
rescue
#plan = Stripe::Plan.create(...)
end
Little bit improved version. It's sad that there is no way to check if plan exists and you have to rely on exception swallowing it. Here is my version, it tries to retrieve the plan, if error is 404, it creates the plan. Otherwise, lets exception to pop up. So it won't swallow all of the exceptions, which is important IMO when you work with finance API.
def retrieve_or_create_plan(id)
begin
Stripe::Plan.retrieve(id)
rescue Stripe::InvalidRequestError => e
if e.response.http_status == 404
Stripe::Plan.create(
name: 'Your plan name',
id: id,
interval: :month,
currency: :usd,
amount: 100
)
else
raise e
end
end
end

cant add application fee to stripe payment in ruby

New to stripe, and ruby. Trying to add an application fee to my stripe payment flow. The charges are all making it through to my stripe account, but I can't seem to figure out how/where to add the stripe application fee code.
charges/new.html.erb
<%= form_tag charges_path do %>
<div id="error_explanation">
<% if flash[:error].present? %>
<p><%= flash[:error] %></p>
<% end %>
</div>
<article>
<%= label_tag(:amount, 'Payment Amount:') %>
<%= text_field_tag(:amount) %>
</article>
<article>
<%= hidden_field_tag(:stripeToken) %>
</article>
<button id='donateButton'>Pay</button>
<% end %>
<script src="https://checkout.stripe.com/checkout.js"></script>
<script>
var handler = StripeCheckout.configure({
key: '<%= Rails.configuration.stripe[:publishable_key] %>',
locale: 'auto',
name: 'Payments',
description: 'Pay Someone',
token: function(token) {
$('input#stripeToken').val(token.id);
$('form').submit();
}
});
$('#donateButton').on('click', function(e) {
e.preventDefault();
$('#error_explanation').html('');
var amount = $('input#amount').val();
amount = amount.replace(/\$/g, '').replace(/\,/g, '')
amount = parseFloat(amount);
if (isNaN(amount)) {
$('#error_explanation').html('<p>Please enter a valid amount in CAD ($).</p>');
}
else if (amount < 5.00) {
$('#error_explanation').html('<p>Wage amount must be at least $5.</p>');
}
else {
amount = amount * 100; // Needs to be an integer!
handler.open({
amount: Math.round(amount)
})
}
});
// Close Checkout on page navigation
$(window).on('popstate', function() {
handler.close();
});
</script>
charges_controller.rb
class ChargesController < ApplicationController
def new
end
def create
#amount = params[:amount]
#amount = #amount.gsub('$', '').gsub(',', '')
begin
#amount = Float(#amount).round(2)
rescue
flash[:error] = 'Charge not completed. Please enter a valid amount in USD ($).'
redirect_to new_charge_path
return
end
#amount = (#amount * 100).to_i # Must be an integer!
if #amount < 500
flash[:error] = 'Charge not completed. Donation amount must be at least $5.'
redirect_to new_charge_path
return
end
Stripe::Charge.create(
:amount => #amount,
:currency => 'usd',
:source => params[:stripeToken],
:description => 'Custom donation'
)
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to new_charge_path
end
end
As I've mentioned, the payment flow works fine, Stripe docs says it must be a number, but I would prefer a percentage if that is possible. this is the code given in the examples:
# See your keys here: https://dashboard.stripe.com/account/apikeys
Stripe.api_key = "secret key"
# Get the credit card details submitted by the form
token = params[:stripeToken]
# Create the charge with Stripe
charge = Stripe::Charge.create({
:amount => 1000, # amount in cents
:currency => "cad",
:source => token,
:description => "Example charge",
:application_fee => 123 # amount in cents
},
{:stripe_account => CONNECTED_STRIPE_ACCOUNT_ID}
)
I just dont know where or how to add the application fee code! my payment flow works in that the user can enter their own payment amount, and I cant seem to find any answers here or in the documentation which reflects the code in that form. I'm sure its a simple solution, but I'm very new to working with Stripe.
You can only specify an application_fee when creating a charge with Connect, either directly on a connected account (with the Stripe-Account header) or through the platform (with the destination parameter).
From your code, it doesn't look like you're using Connect at all, so application fees wouldn't apply. Can you clarify what exactly you're trying to do? How should the funds from the charge be split?

no implicit conversion of Symbol into Integer - working with param from URL

Trying to convert a param included in the the URL into an integer, to operate with it within a Controller - The format of the URL is like http://localhost:3000/charges?data=149&email=email#gmail.com
The charges_controller.rb looks like:
class ChargesController < ApplicationController
protect_from_forgery with: :null_session
def new
end
def create
#amount = {}
#amount = params [:**data**][:email].map(&:to_i)
#amount.save
customer = Stripe::Customer.create(
:email => params[:stripeEmail],
:source => params[:stripeToken]
)
charge = Stripe::Charge.create(
:customer => customer.id,
:amount => #amount,
:description => 'Rails Stripe customer',
:currency => 'eur'
)
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to new_charge_path
end
end
And the params I can see in better_errors screen detect already the 'data' amount:
{"stripeToken"=>"asdfasdf", "stripeTokenType"=>"card", "stripeEmail"=>"email#gmail.com", "data"=>"149", "email"=>"email#gmail.com", "action"=>"create", "controller"=>"charges"}
In the live shell in better errors if I do params[:data].to_i it returns 149, but if I include it directly in the controller like:
#amount = {}
#amount = params [:data].to_i[:email]
#amount.save
it returns undefined method `to_i' for [:data]:Array
Tried also mapping them like: #amount = params [:data][:email].map(&:to_i),same result "no implicit conversion of Symbol into Integer"
You should remove space while calling :data on your params hash from params [:data] to params[:data].

Showing item price, item id, item name in paypal payment screen

I have used gem "active_paypal_adaptive_payment" also set the payment options
def checkout
recipients = [recipientarray]
response = gateway.setup_purchase(
:return_url => url_for(:action => 'action', :only_path => false),
:cancel_url => url_for(:action => 'action', :only_path => false),
:ipn_notification_url => url_for(:action => 'notify_action', :only_path => false),
:receiver_list => recipients
)
# For redirecting the customer to the actual paypal site to finish the payment.
redirect_to (gateway.redirect_url_for(response["payKey"]))
end
It is redirecting to the paypal payment page..
This is the page
In payment summary it does not displaying any item name , price, etc..
can any one suggest how to configure it . Please help
Thanks
You may want to try using the "ActiveMerchant" gem instead - it's updated by Shofify and we've got it to do exactly what you're looking for.
Problem
The way to get PayPal to list the items is to use the ExpressCheckout version (I think you're just setting up a peer-to-peer payment), and then pass the items in a hash array. We use a cart, but you may have something else.
The trick with paypal epxress is that you have to get all the totals to add up properly. As you will see in the code I post, we are just using a static shipping value for now (we're still developing this current project), but you can omit shipping if you don't need it.
Solution
I can only vouch for ActiveMerchant, because that's the only code I've got, but here is what we do:
Routes
#config/routes.rb
get 'checkout/paypal' => 'orders#paypal_express', :as => 'checkout'
get 'checkout/paypal/go' => 'orders#create_payment', :as => 'go_paypal'
Orders Controller
#controllers/orders_controller.rb
class OrdersController < ApplicationController
#Paypal Express
def paypal_express
response = EXPRESS_GATEWAY.setup_purchase(total,
:items => cart_session.build_order, #this is where you create the hash of items
:subtotal => subtotal,
:shipping => 50,
:handling => 0,
:tax => 0,
:return_url => url_for(:action => 'create_payment'),
:cancel_return_url => url_for(:controller => 'cart', :action => 'index')
)
redirect_to EXPRESS_GATEWAY.redirect_url_for(response.token)
end
#some other stuff is here....
end
Build Items
#models/cart_session.rb (we use this with a cart)
#Build Hash For ActiveMerchant
def build_order
#Take cart objects & add them to items hash
products = cart_contents
#order = []
products.each do |product|
#order << {name: product[0].name, quantity: product[1]["qty"], amount: (product[0].price * 100).to_i }
end
return #order
end
end

Resources