generalised the config of the gateway and site-specific options, so the code is no longer
tied to a specific UK site... (changes are explained in the README)
This commit is contained in:
parent
56838c90ef
commit
5e271e0fd7
|
@ -1,11 +1,12 @@
|
|||
# WARNING: the details of UK tax and my site's shipping are a bit hard-coded here for now
|
||||
# aim to unpick this later
|
||||
module Spree::PaypalExpress
|
||||
include ERB::Util
|
||||
include Spree::PaymentGateway
|
||||
include ActiveMerchant::RequiresParameters
|
||||
|
||||
|
||||
def fixed_opts
|
||||
{ :description => "Goods from a Spree-based site", # site details...
|
||||
{ :description => "Goods from #{Spree::Config[:site_name]}", # site details...
|
||||
|
||||
#:page_style => "foobar", # merchant account can set named config
|
||||
:header_image => "https://" + Spree::Config[:site_url] + "/images/logo.png",
|
||||
|
@ -15,9 +16,16 @@ module Spree::PaypalExpress
|
|||
|
||||
:allow_note => true,
|
||||
:locale => Spree::Config[:default_locale],
|
||||
:notify_url => 'to be done', # this is a callback
|
||||
:notify_url => 'to be done', # this is a callback, not tried it yet
|
||||
|
||||
:req_confirm_shipping => false, # for security, might make an option later
|
||||
|
||||
# :no_shipping => false,
|
||||
# :address_override => false,
|
||||
|
||||
# WARNING -- don't use :ship_discount, :insurance_offered, :insurance since
|
||||
# they've not been tested and may trigger some paypal bugs, eg not showing order
|
||||
# see http://www.pdncommunity.com/t5/PayPal-Developer-Blog/Displaying-Order-Details-in-Express-Checkout/bc-p/92902#C851
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -25,12 +33,13 @@ module Spree::PaypalExpress
|
|||
# might be able to get paypal to do some of the shipping choice and costing
|
||||
def order_opts(order)
|
||||
items = order.line_items.map do |item|
|
||||
tax = paypal_variant_tax(item.price, item.variant)
|
||||
{ :name => item.variant.product.name,
|
||||
:description => item.variant.product.description[0..120],
|
||||
:sku => item.variant.sku,
|
||||
:qty => item.quantity,
|
||||
:amount => item.price - 0.15 * item.price, # avoid some rounding err, more needed
|
||||
:tax => 0.15 * item.price,
|
||||
:amount => item.price - tax, # TODO: test if ok on multi-qty orders
|
||||
:tax => tax,
|
||||
:weight => item.variant.weight,
|
||||
:height => item.variant.height,
|
||||
:width => item.variant.width,
|
||||
|
@ -42,47 +51,65 @@ module Spree::PaypalExpress
|
|||
:order_id => order.number,
|
||||
:custom => order.number,
|
||||
|
||||
# :no_shipping => false,
|
||||
# :address_override => false,
|
||||
|
||||
:items => items,
|
||||
:subtotal => items.map {|i| i[:amount] * i[:qty] }.sum,
|
||||
:handling => 0,
|
||||
:tax => items.map {|i| i[:tax] * i[:qty]}.sum
|
||||
|
||||
# WARNING -- don't use :ship_discount, => :insurance_offered, :insurance since
|
||||
# they've not been tested and may trigger some paypal bugs, eg not showing order
|
||||
# see http://www.pdncommunity.com/t5/PayPal-Developer-Blog/Displaying-Order-Details-in-Express-Checkout/bc-p/92902#C851
|
||||
}
|
||||
|
||||
opts[:email] = current_user.email if current_user
|
||||
|
||||
opts
|
||||
end
|
||||
|
||||
def all_opts(order)
|
||||
shipping_cost = NetstoresShipping::Calculator.calculate_order_shipping(order)
|
||||
opts = fixed_opts.merge(:shipping => shipping_cost).merge(order_opts order)
|
||||
# hook for supplying tax amount for a single unit of a variant
|
||||
# expects the sale price from the line_item and the variant itself, since
|
||||
# line_item price and variant price can diverge in time
|
||||
def paypal_variant_tax(sale_price, variant)
|
||||
{}
|
||||
end
|
||||
|
||||
# WARNING: paypal expects this sum to work (TODO: shift to AM code? and throw wobbly?)
|
||||
# however: might be rounding issues when it comes to tax, though you can capture slightly extra
|
||||
opts[:money] = opts.slice(:subtotal, :shipping, :handling, :tax).values.sum
|
||||
if opts[:money] != order.total
|
||||
raise "Ouch - precision problems: #{opts[:money]} vs #{order.total}"
|
||||
# hook for easy site configuration, needs to return a hash
|
||||
# you probably wanto over-ride the description option here, maybe the colours and logo
|
||||
def paypal_site_options(order)
|
||||
{}
|
||||
end
|
||||
|
||||
# hook to allow applications to load in their own shipping and handling costs
|
||||
# eg might want to estimate from cheapest shipping option and rely on ability to
|
||||
# claim an extra 15% in the final auth
|
||||
def paypal_shipping_and_handling_costs(order)
|
||||
{}
|
||||
end
|
||||
|
||||
def all_opts(order)
|
||||
|
||||
opts = fixed_opts.merge(order_opts order).
|
||||
merge({ :shipping => 0, :handling => 0 } ).
|
||||
merge(paypal_shipping_and_handling_costs order).
|
||||
merge(paypal_site_options order)
|
||||
|
||||
# add the shipping and handling estimates to spree's order total
|
||||
# (spree won't add them yet, since we've not officially chosen the shipping method)
|
||||
spree_total = order.total + opts[:shipping] + opts[:handling]
|
||||
|
||||
# paypal expects this sum to work out (TODO: shift to AM code? and throw wobbly?)
|
||||
# there might be rounding issues when it comes to tax, though you can capture slightly extra
|
||||
opts[:money] = opts.slice(:subtotal, :tax, :shipping, :handling).values.sum
|
||||
if opts[:money] != spree_total
|
||||
raise "Ouch - precision problems: #{opts[:money]} vs #{spree_total}"
|
||||
end
|
||||
|
||||
# prepare the numbers for the gateway
|
||||
[:money, :subtotal, :shipping, :handling, :tax].each {|amt| opts[amt] *= 100}
|
||||
opts[:items].each {|item| [:amount,:tax].each {|amt| item[amt] *= 100} }
|
||||
|
||||
# suggest current user's email or any email stored in the order
|
||||
opts[:email] = current_user ? current_user.email : order.checkout.email
|
||||
|
||||
opts
|
||||
end
|
||||
|
||||
def paypal_checkout
|
||||
# need build etc? at least to finalise the total?
|
||||
gateway = paypal_gateway
|
||||
@order.update_totals
|
||||
|
||||
opts = all_opts(@order)
|
||||
gateway = paypal_gateway
|
||||
response = gateway.setup_authorization(opts[:money], opts)
|
||||
|
||||
gateway_error(response) unless response.success?
|
||||
|
@ -91,9 +118,8 @@ module Spree::PaypalExpress
|
|||
end
|
||||
|
||||
def paypal_finish
|
||||
opts = { :token => params[:token], :payer_id => params[:PayerID] }.merge all_opts(@order)
|
||||
gateway = paypal_gateway
|
||||
opts = { :token => params[:token],
|
||||
:payer_id => params[:PayerID] }.merge all_opts(@order)
|
||||
info = gateway.details_for params[:token]
|
||||
response = gateway.authorize(opts[:money], opts)
|
||||
|
||||
|
@ -141,14 +167,15 @@ module Spree::PaypalExpress
|
|||
payment.creditcard_txns << transaction
|
||||
|
||||
order.user = current_user
|
||||
|
||||
order.save!
|
||||
|
||||
order.complete # get return of status? throw of problems??? else weak go-ahead
|
||||
session[:order_id] = nil if order.checkout_complete
|
||||
redirect_to order_url(order, :checkout_complete => true, :order_token => session[:order_token])
|
||||
end
|
||||
|
||||
flash[:notice] = t('order_processed_successfully')
|
||||
order_params = {:checkout_complete => true}
|
||||
order_params[:order_token] = @order.token unless @order.user
|
||||
session[:order_id] = nil if @order.checkout.completed_at
|
||||
redirect_to order_url(@order, order_params)
|
||||
end
|
||||
|
||||
def do_capture(authorization)
|
||||
response = paypal_gateway.capture((100 * authorization.amount).to_i, authorization.response_code)
|
||||
|
@ -167,17 +194,20 @@ module Spree::PaypalExpress
|
|||
|
||||
private
|
||||
|
||||
# copied from main spree code, and slightly tweaked
|
||||
# create the gateway from the supplied options
|
||||
def paypal_gateway
|
||||
#? return Spree::BogusGateway.new if ENV['RAILS_ENV'] == "development" and Spree::Gateway::Config[:use_bogus]
|
||||
paypal_gw = ::Gateway.find_by_name("Paypal Express UK")
|
||||
gateway_config = GatewayConfiguration.find_by_gateway_id(paypal_gw.id)
|
||||
config_options = {}
|
||||
gateway_config.gateway_option_values.each do |option_value|
|
||||
key = option_value.gateway_option.name.to_sym
|
||||
config_options[key] = option_value.value
|
||||
end
|
||||
gateway = gateway_config.gateway.clazz.constantize.new(config_options)
|
||||
end
|
||||
gw_defaults = { :ppx_class => "ActiveMerchant::Billing::PaypalExpressUkGateway" }
|
||||
gw_opts = gw_defaults.merge(paypal_site_options @order)
|
||||
|
||||
begin
|
||||
requires!(gw_opts, :ppx_class, :login, :password, :signature)
|
||||
rescue ArgumentError => err
|
||||
raise ArgumentError.new(<<"EOM" + err.message)
|
||||
Problem with configuring Paypal Express Gateway:
|
||||
You need to ensure that hook "paypal_site_options" sets values for login, password, and signature.
|
||||
EOM
|
||||
end
|
||||
|
||||
gateway = gw_opts[:ppx_class].constantize.new(gw_opts)
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue