Rails & Stripe - Stock shipping address in a var, in the ChargesController - ruby-on-rails

with Stripe on Rails 4, I want to stock the shipping address of my customer in a variable #testvar, in my ChargesController, so I can :
- Display it in the charges#create page, as a "Here is where we will deliver"
- Send an email to the admin with this info.
Here is my ChargesController : (UPDATED 3rd April)
class ChargesController < ApplicationController
def new
end
def create
admin = Admin.last
customer = Stripe::Customer.create(
email: params[:stripeEmail],
card: params[:stripeToken],
)
charge = Stripe::Charge.create(
:customer => customer.id,
:amount => #amount,
:currency => 'eur',
:receipt_email => params[:stripeEmail],
)
customer_name = charge["name"]
AdminMailer.outfit_ordered(admin, customer_name).deliver_now
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to :back
end
end
UPDATE 3rd April
I've added a mailer, hence the two following line
customer_name = charge["name"]
AdminMailer.outfit_ordered(admin, customer_name).deliver_now
I've found the following part in another aswer, but I can't get it to work.
stripe_customer_params = JSON.parse customer.to_s
#testvar = stripe_customer_params['cards']['data'].first['shipping_address']
Furthermore, when I assign a random value to my #testvar (like #testvar = "test") and display it in my charges#create view, it works... But #testvar keeps this value with the other tests I run after that.
I am stuck with this problem and can't find anything that helps me in the Stripe's API documentation.
Thanks for your help.

Related

Rails - Stripe::InvalidRequestError (Must provide source or customer.)

I'm building an application (based in online resource). You can sign up or login with devise. Then, you can buy a product. Or make your own list and sell your products.
I'm integrating Stripe. When I create the Charge, I get this error in the console: Stripe::InvalidRequestError (Must provide source or customer.).
Here is the code of the orders_controller.rb for the charge action:
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
Of course I'm taking a look in the Stripe API Documentation here: Charge documentation example and here: Charge full API Reference
I'm not sure how to handle the :resource or customer. I saw in other materials in the web that some people create a customer. In other sites it says that the :card is deprecated, so I'm a little confused.
I will leave the github repository of my project, and feel free to take a look. I'm trying to deal with Transfers and Recipients too. Project Repository
Thanks.
As mentioned in the docs, stripe expects either customer or source to be mentioned while creating a charge. So, you either need to
Create a customer on stripe(if you want to charge that customer in future too) from the token you received, and mention that customer while creating a charge,
customer = Stripe::Customer.create(source: params[:stripeToken])
charge = Stripe::Charge.create({
:amount => 400,
:currency => "usd",
:customer => customer.id,
:description => "Charge for test#example.com"
})
Or, if you don't want to create a customer, then directly mention received token as a source,
Stripe::Charge.create({
:amount => 400,
:currency => "usd",
:source => params[:stripeToken],
:description => "Charge for test#example.com"
})
For anyone going through the Stripe docs, you may have something like this (using an existing account)
account_links = Stripe::AccountLink.create({
account: 'acct_1032D82eZvKYlo2C',
refresh_url: 'https://example.com/reauth',
return_url: 'https://example.com/return',
type: 'account_onboarding',
})
if so, just change it to look like this (i.e. include the actual account.id you created in the previous step):
account_links = Stripe::AccountLink.create({
account: account.id,
refresh_url: 'https://example.com/reauth',
return_url: 'https://example.com/return',
type: 'account_onboarding',
})

PayPal-Ruby-SDK web-experience-profile creation

I am a bit of a new rails developer and I am not making sense of Paypal's documentation to create a web experience profile before processing a payment with the REST API:
I can make payments ok with code below as long as I do not try to use the experience profile.
When debugging, I get a value for #webprofile similar to:
#<PayPal::SDK::REST::DataTypes::WebProfile:0x007fe0f9344e50 #error=nil,
#name="YeowZa! T-Shirt Shop", #presentation=#<PayPal::SDK::REST::DataTypes::Presentation:0x007fe0f8ec51b8 #error=nil, #brand_name="YeowZa! Paypa
l", #logo_image="http://www.yeowza.com", #locale_code="US">, #input_fields=#<PayPal::SDK::REST::DataTypes::InputFields:0x007fe0f927b0f0 #error=nil, #allow_note=true, #no_shipping=0, #address_override=1>, #flow_config
=#<PayPal::SDK::REST::DataTypes::FlowConfig:0x007fe0f90808e0 #error=nil, #landing_page_type="billing", #bank_txn_pending_url="http://www.yeowza.com">, #request_id="bcc4bc41-b61c-4d28-94f1-a0912121d8e8", #header={}>
On my console I see:
Request[post]: https://api.sandbox.paypal.com/v1/payment-experience/web-profiles/
Response[400]: Bad Request,
My code so far is:
class PaypalController < ApplicationController
require 'paypal-sdk-rest'
include PayPal::SDK::REST
include PayPal::SDK::Core::Logging
def create
PayPal::SDK::REST.set_config(
:mode => "sandbox", # "sandbox" or "live"
:client_id => "my-id",
:client_secret => "my-secret")
# Build Payment object
#payment = Payment.new({
:intent => "sale",
:payer => {
:payment_method => "paypal"},
:experience_profile_id => self.web_experience,
:redirect_urls => {
:return_url => "http://me.com/paypal_complete",
:cancel_url => "http://me.com/paypal_cancel"},
:transactions => [{
:item_list => {
:items => [{
:name => "me.com Thing",
:sku => "the-specific-horse",
:price => "2",
:currency => "USD",
:quantity => "1" }]},
:amount => {
:total => "2.00",
:currency => "USD" },
:description => "Payment for the-specific-thing" }]
})
# Create Payment and return the status(true or false)
if #payment.create
# Redirect the user to given approval url
#redirect_url = #payment.links.find{|v| v.method == "REDIRECT" }.href
logger.info "Payment[#{#payment.id}]"
logger.info "Redirect: #{#redirect_url}"
redirect_to #redirect_url
else
logger.error #payment.error.inspect
end
end
def paypal_complete
begin
# paymentId: PAY-8L3183743T450642VKWDPH7I
# token: EC-57E34614K6825515M
# PayerID: RBWLMFNFF4ZUC
payment_id = params[:paymentId]
# Retrieve the payment object by calling the
# `find` method
# on the Payment class by passing Payment ID
#payment = Payment.find(payment_id)
logger.info "Got Payment Details for Payment[#{#payment.id}]"
rescue ResourceNotFound => err
# It will throw ResourceNotFound exception if the payment not found
logger.error "Payment Not Found"
end
end
def web_experience
#this is not used right now...don't know how
#webprofile = WebProfile.new(
{
:name => "YeowZa! T-Shirt Shop",
:presentation => {
:brand_name => "YeowZa! Paypal",
:logo_image => "http://www.yeowza.com",
:locale_code => "US"
},
:input_fields => {
:allow_note => true,
:no_shipping => 0,
:address_override => 1
},
:flow_config => {
:landing_page_type => "billing",
:bank_txn_pending_url => "http://www.yeowza.com"
}
})
if #webprofile.create
# Redirect the user to given approval url
logger.info "#webprofile[#{#webprofile}]"
debugger
else
logger.error #payment.error.inspect
debugger
end
end
end
This is old but I thought others might end up here like I did.
I had a similar issue with the .NET SDK. Resolved by removing fields from the request object that I shouldn't have been using i.e. the field bank_txn_pending_url I had set to an empty string, when I didn't define this field at all (which would equate to null), the request returned 200. It clearly states in the documentation that this field should only be used in Germany in certain circumstances.
Once created though, subsequent requests fail, because you cannot have two profiles with the same name. You need to get the list of existing profiles and use the existing ID if found. No need to create over and over.
Bummer the dashboard doesn't capture all requests in the transaction section, would make life much easier if it did.

Ticket Dispenser : Array in memory?

I have a ticket dispenser.
It is non efficient. 3300 ms response.
It was previously implemented with a ticker (counter.increment!) which brought problems dealing with concurrency.
It is currently implemented as array.shift.
ticket_roll = [1, 2, 3, 4, 5]
ticket = ticket_roll.shift
Any user can grab a ticket.
The first one to hit the array gets the ticket.
controller
def create
#movie = Movie.find_by(movie: params[:movie])
ticket_roll = TicketRoll.find(1).ticket_roll
#ticket = ticket_roll.shift
customer = Stripe::Customer.create(
:email => params[:stripeEmail],
:card => params[:stripeToken],
)
charge = Stripe::Charge.create(
:customer => customer.id,
:amount => 1500,
)
if charge["paid"]
#movie.update_attributes(status: "sold", email: params[:stripeEmail],
first_name: params[:first_name], last_name: params[:last_name])
Pusher['the_channel'].trigger('the_event', {message: ticket_roll[0]})
else
ticket_roll.unshift(#ticket)
end
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to charges_path
end
Can I store the ticket_roll array in memory/cache so that each user does not = a full DB query ?
As you already mentioned having all the tickets in the memory is inefficient and simply using increment! poses concurrency issues. One basic solution to that is to use locks when updating a record.
An example from the guide:
Item.transaction do
i = Item.lock.first
i.name = 'Jones'
i.save
end
In your case you only need to have the number of latest ticket in DB. Before giving out a new ticket number you should lock the record, increment the value and release the lock.

Stripe charge and Subscription

I have a rails 4 app that I'm using Stripe checkout. I've followed their tutorial, and my controller looks like:
def create
s = Subscription.new
s.user_id = current_user.id
s.plan_id = params[:plan_id]
s.stripe_token = params[:stripeToken]
s.save
# Amount in cents
#amount = 699
customer = Stripe::Customer.create(
:email => current_user.email,
:card => params[:stripeToken]
)
charge = Stripe::Charge.create(
:customer => customer.id,
:amount => #amount,
:description => 'Sitekite Pro',
:currency => 'usd'
)
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to charges_path
end
I looked at a couple other tutorials, looking for help with creating a subscription with Stripe checkout. Some of them dont have the Stripe::Charge part. Is the Stripe::Charge part only for single charges? How do I sign the user up for a monthly subscription with the same #amount?
The Stripe::Charge is indeed for single charges. The Customer create is what you need, but when you create the customer you specify a plan (plans are defined in your Stripe dashboard). The plan will specify the amount to charge and how often to charge it.
When the charge is actually made, which might be the same day or might be several days later depending on whether your plan provides, say, some free access time... the Stripe service can send the charge to a webhook... which is to say a route in your project for the dedicated use of the Stripe service.
Stripe will post charges (and failures) to your webhook, and you can handle them appropriately (logging the payments and maybe restricting the user if his card becomes expired or a regular payment fails for some other reason)

Rails 4 - ActiveMerchant Paypal Express Checkout Issue with Passing Item Quantity

I have a weird issue with the PayPal express checkout. When I pass in an options[:item][:quantity], I get an error code from PayPal that the transaction in invalid.
#controllers/orders_controller.rb
def express
options = {
:ip => request.remote_ip,
:return_url => new_order_url,
:cancel_return_url => products_url,
:items => current_cart.line_items_hash
}
response = EXPRESS_GATEWAY.setup_purchase(current_cart.build_order.price_in_cents,
options)
redirect_to EXPRESS_GATEWAY.redirect_url_for(response.token)
end
# models/cart.rb
def line_items_hash
self.line_items.map do |line_item|
{
:name => Product.find(line_item.product_id).name
# :quantity => line_item.quantity,
:description => line_item.product.description,
:amount => line_item.gross_price_in_cents}
end
end
So this works fine. The problem is that the correct quantity is not shown on the PayPal order confirmation page. However, if I uncomment the quantity variable in the line_items_hash function the whole thing breaks and I get "invalid transaction from paypal". Any ideas?
Silly old me. Paypal keeps invalidating my transaction because I'm passing bad information. I was setting the amount to line_item total which is already the total of quantity * product.price. So the information that Paypal was receiving is quantity * (quantity * product.price).
Silly little mistake but I managed to catch it in the end.
# models/cart.rb
def line_items_hash
self.line_items.map do |line_item|
{
:name => Product.find(line_item.product_id).name
:quantity => line_item.quantity,
:description => line_item.product.description,
:amount => line_item.price.in_cents}
end
end

Resources