require 'paypal-sdk-merchant' module Spree class Gateway::PayPalExpress < Gateway preference :login, :string preference :password, :string preference :signature, :string preference :server, :string, default: 'sandbox' def supports?(source) true end def provider_class ::PayPal::SDK::Merchant::API end def provider ::PayPal::SDK.configure( :mode => preferred_server.present? ? preferred_server : "sandbox", :username => preferred_login, :password => preferred_password, :signature => preferred_signature) provider_class.new end def auto_capture? true end def method_type 'paypal' end def purchase(amount, express_checkout, gateway_options={}) pp_request = provider.build_do_express_checkout_payment({ :DoExpressCheckoutPaymentRequestDetails => { :PaymentAction => "Sale", :Token => express_checkout.token, :PayerID => express_checkout.payer_id, :PaymentDetails => [{ :OrderTotal => { :currencyID => Spree::Config[:currency], # gsub is here because PayPal fails to acknowledge # that some people like their currencies written as: # 21,99 # As opposed to: # 21.99 # The international payments company fails to handle # international payment amounts. SMH. :value => ::Money.new(amount, Spree::Config[:currency]).to_s.gsub(',', '.') } }] } }) pp_response = provider.do_express_checkout_payment(pp_request) if pp_response.success? # We need to store the transaction id for the future. # This is mainly so we can use it later on to refund the payment if the user wishes. transaction_id = pp_response.do_express_checkout_payment_response_details.payment_info.first.transaction_id express_checkout.update_column(:transaction_id, transaction_id) # This is rather hackish, required for payment/processing handle_response code. Class.new do def success?; true; end def authorization; nil; end end.new else class << pp_response def to_s errors.map(&:long_message).join(" ") end end pp_response end end def refund(payment, amount) refund_type = payment.amount == amount.to_f ? "Full" : "Partial" refund_transaction = provider.build_refund_transaction({ :TransactionID => payment.source.transaction_id, :RefundType => refund_type, :Amount => { :currencyID => payment.currency, :value => amount }, :RefundSource => "any" }) refund_transaction_response = provider.refund_transaction(refund_transaction) if refund_transaction_response.success? payment.source.update_attributes({ :refunded_at => Time.now, :refund_transaction_id => refund_transaction_response.RefundTransactionID, :state => "refunded", :refund_type => refund_type } ) end refund_transaction_response end end end # payment.state = 'completed' # current_order.state = 'complete'