Updated to support core Billing Integrations
This commit is contained in:
parent
7da2fed7ac
commit
c14eefa55a
144
README.markdown
144
README.markdown
|
@ -1,134 +1,20 @@
|
||||||
# Paypal Express for Spree
|
# Official PayPal Express for Spree
|
||||||
|
|
||||||
Bridge between ActiveMerchant's Paypal Express (henceforth PPX) gateway code and Spree
|
This is the official PayPal Express extension for Spree, based on the extension by PaulCC it has been extended to support Spree's
|
||||||
|
Billing Integrations which allows users to configure the PayPal Express gateway including API login / password and signatures fields
|
||||||
|
via the Admin UI.
|
||||||
|
|
||||||
|
This extension allows the store to use PayPal Express from two locations:
|
||||||
|
|
||||||
## Setup and Customization
|
1. Checkout Payment - When configured the PayPal Express checkout button will appear alongside the standard credit card payment
|
||||||
|
options on the payment stage of the standard checkout. The selected shipping address and shipping method / costs are automatically
|
||||||
|
sent to the PayPal review page (along with detailed order information).
|
||||||
|
|
||||||
|
THIS FEATURE IS NOT YET COMPLETE
|
||||||
|
2. Cart Checkout - Presents the PayPal checkout button on the users Cart page and redirects the user to complete all shipping / addressing
|
||||||
|
information on PaypPal's site. This also supports PayPal's Instant Update feature to retrieve shipping options live from Spree when the user
|
||||||
|
selects / changes their shipping address on PayPal's site.
|
||||||
|
|
||||||
1. Start by identifying the relevant class representing your locale's paypal express gateway
|
This extension follows the documented flow for a PayPal Express Checkout, where a user is forwarded to PayPal to allow them to login and review
|
||||||
|
the order (possibly select / change shipping address and method), then the user is redirected back to Spree to confirm the order. The user
|
||||||
2. If there isn't one, then you can easily create one and patch it in. You can drop it in
|
MUST confirm the order on the Spree site before the payment is authorized / captured from PayPal (and the order is transitioned to the New state).
|
||||||
the directory +lib/active_merchant/billing/gateways/+ in an extension - probably best in your
|
|
||||||
+site+ extension - and make sure it is loaded with the following line (suitably modified) in
|
|
||||||
your extension activation code :
|
|
||||||
|
|
||||||
require File.join(SiteExtension.root, "lib", "active_merchant", "billing", "gateways", "paypal_express_narnia.rb")
|
|
||||||
|
|
||||||
See how I've handled the UK gateway customization in this extension for more info.
|
|
||||||
|
|
||||||
3. Over-ride the hook +paypal_site_options+ in the OrdersController (eg with a +class_eval+ in your
|
|
||||||
+site+ extension's activation code) so that it returns a _hash_ with at least the following
|
|
||||||
fields. The hook is sent the current order value, in case it is needed.
|
|
||||||
|
|
||||||
* +:ppx_class+ -- name of the actual gateway class
|
|
||||||
* +:login+ -- the merchant's login email address
|
|
||||||
* +:password+ -- the merchant's Paypal API Credentials Password
|
|
||||||
* +:signature+ -- the merchant's Paypal API Credentials signature string
|
|
||||||
|
|
||||||
4. You can also over-ride other PPX settings from this hook, eg the +:description+ string
|
|
||||||
attached to transactions, or the colour scheme and logo, or ... (see +lib/spree/paypal_express.rb+
|
|
||||||
for more information.
|
|
||||||
|
|
||||||
5. Over-ride the hook +paypal_variant_tax+ to calculate the tax amount for a single unit of a
|
|
||||||
variant. The hook is passed the +price+ from the containing +line_item+, plus the variant
|
|
||||||
itself. Note that the line_item price and the variant price can diverge (the former won't be
|
|
||||||
changed if the administrator changes the variant price), and Spree usually ignores the
|
|
||||||
variant price after the line_item has been created, so you probably want to calculate tax
|
|
||||||
from the line_item price. You should return a floating point number here. The hook is
|
|
||||||
located in the OrdersController.
|
|
||||||
|
|
||||||
6. Over-ride the hook +paypal_shipping_and_handling_costs+ (also in the OrdersController), to
|
|
||||||
determine a shipping and handling estimate for the order. See below for a discussion of
|
|
||||||
shipping issues and how they affect PPX.
|
|
||||||
|
|
||||||
The hook is sent the order value, and must return a _hash_ containing (at least) a
|
|
||||||
:shipping and a :handling value (both floats), which are the total costs for the order.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Interaction with Spree
|
|
||||||
|
|
||||||
The bridge code receives authorization and transaction info from PPX and converts it into the Spree
|
|
||||||
equivalent.
|
|
||||||
|
|
||||||
The payment representation isn't perfect: basically, Spree is oriented towards creditcards and some
|
|
||||||
work is needed to generalise it to other options. For now, it is a bit hacked. (See the TODO list.)
|
|
||||||
|
|
||||||
|
|
||||||
## Relationship with Active Merchant
|
|
||||||
|
|
||||||
This extension contains three files which are updates or extensions to current active merchant code. They are
|
|
||||||
loaded up when the extension is initialized, and will over-ride the existing gem files. The modifications
|
|
||||||
update the base protocol, eg allowing detailed order info to be passed, and supporting _some_ (not all)
|
|
||||||
of the new options in version 57.0.
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
Get an account for Paypal's Sandbox system first. Very good testing system!
|
|
||||||
Pity it logs you off automatically after a relatively short time period
|
|
||||||
|
|
||||||
|
|
||||||
## Status and Known issues
|
|
||||||
|
|
||||||
IMPORTANT: requires spree version 0.8.5 or later (there's a tag in the repo for earlier versions, but it needs some bug patching now)
|
|
||||||
|
|
||||||
[15Jul09] I don't know of any serious bugs or issues at present in this code, so you should be able to
|
|
||||||
start using this without serious problems - but do note the TODO list below.
|
|
||||||
|
|
||||||
Temporarily, I've had to over-ride two admin views: order/show and payments/index: this will be unpicked
|
|
||||||
once Spree is generalised to support payment types other than creditcards
|
|
||||||
|
|
||||||
WARNING: there seems to be an issue with the :shipping_discount issue which causes submitted order
|
|
||||||
info to be ignored (and not displayed - probably because the PPX addition checking doesn't tally).
|
|
||||||
See +lib/spree/paypal_express.rb+ for more info. I suggest avoiding this option unless you've
|
|
||||||
tested it carefully. The insurance options are also not tested yet.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Hooks
|
|
||||||
|
|
||||||
These were discussed in the customization section above, but for reference, they are:
|
|
||||||
|
|
||||||
* +paypal_variant_tax(sale_price, variant)+
|
|
||||||
* +paypal_site_opts(order)+
|
|
||||||
* +paypal_shipping_and_handling_costs(order)+
|
|
||||||
|
|
||||||
|
|
||||||
## Shipping Issues
|
|
||||||
|
|
||||||
It is important to note that Spree won't have selected a shipping method when the PPX process
|
|
||||||
is started. My sites only have a single shipping method, so I can get away with defaulting to
|
|
||||||
that method and using that for calculations. It also means that I've not written any code yet
|
|
||||||
for selecting from applicable methods etc etc.
|
|
||||||
|
|
||||||
Beware that this code does make some big assumptions about shipping. In particular, it AVOIDS
|
|
||||||
use of the Spree shipping calcs, effectively performing its own calcs (via the hook), but then
|
|
||||||
assigning the first shipping method at the end, just so order display will work. This stuff
|
|
||||||
is ok when there's a single shipping option defined (like me), but will need work if you have
|
|
||||||
more options.
|
|
||||||
|
|
||||||
Note that PPX allows you to capture up to 115% of the original authorized amount: this could
|
|
||||||
allow some flexibility in shipping choices, eg you could add a stage after return from PPX
|
|
||||||
which asks for a shipping choice and confirms the final amount to be captured.
|
|
||||||
|
|
||||||
It seems that PPX might have support for choosing a shipping method on its screens, but I
|
|
||||||
have not tried to use this yet.
|
|
||||||
|
|
||||||
## TODO
|
|
||||||
|
|
||||||
0. Add support for accepting PPX payment at the credit card stage (important)
|
|
||||||
|
|
||||||
1. Look at using PPX to assist in shipping method choices (or present user with a choice before
|
|
||||||
they jump to PPX interaction)
|
|
||||||
|
|
||||||
2. Improve payment tracking support in Spree (eg generalise beyond creditcard bias)
|
|
||||||
|
|
||||||
3. Add some tests
|
|
||||||
|
|
||||||
4. Get some of my code into active merchant
|
|
||||||
|
|
||||||
5. Double-check implementation of the full PPX process
|
|
||||||
|
|
||||||
6. Look at shipping method selection integration
|
|
|
@ -1,80 +0,0 @@
|
||||||
<div class='toolbar order-links'>
|
|
||||||
<%= button_link_to t("resend"), resend_admin_order_url(@order), :method => :post, :icon => 'send-email' %>
|
|
||||||
<%= event_links %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<%= render :partial => 'admin/shared/order_tabs', :locals => {:current => "Order Details"} %>
|
|
||||||
|
|
||||||
<%= render :partial => 'admin/shared/order_details', :locals => {:order => @order} -%>
|
|
||||||
|
|
||||||
<% if @order.bill_address %>
|
|
||||||
<div class='adr'>
|
|
||||||
<h4>
|
|
||||||
<%= link_to t("bill_address"), edit_admin_order_creditcard_payment_url(@order, @order.creditcard_payments.last) if @order.creditcard_payments.present? %>
|
|
||||||
<%= t("bill_address") if @order.creditcard_payments.empty? %>
|
|
||||||
</h4>
|
|
||||||
<%= render :partial => 'admin/shared/address', :locals => {:address => @order.bill_address} %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<% if (payment = @order.payments.last).class != CreditcardPayment %>
|
|
||||||
<%# look at the most recent (= up to date) payment for paypal %>
|
|
||||||
<% url = edit_admin_order_paypal_payment_url(@order) %> <%#, payment) %>
|
|
||||||
<div class='adr'>
|
|
||||||
<h4><%= link_to t("edit_paypal_info"), edit_admin_order_paypal_payment_url(@order, payment) %></h4>
|
|
||||||
(no billing address available)
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<% if @order.ship_address %>
|
|
||||||
<div class='adr'>
|
|
||||||
<h4>
|
|
||||||
<%= link_to t("ship_address"), edit_admin_order_shipment_url(@order, @order.shipments.last) if @order.shipments.present? %>
|
|
||||||
<%= t("ship_address") if @order.shipments.empty? %>
|
|
||||||
</h4>
|
|
||||||
<%= render :partial => 'admin/shared/address', :locals => {:address => @order.ship_address} %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
<table class="index">
|
|
||||||
<tr>
|
|
||||||
<th><%= t("email") %></th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><%= @order.email %></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<% unless @order.special_instructions.blank? %>
|
|
||||||
<table class="index">
|
|
||||||
<tr>
|
|
||||||
<th><%= t("shipping_instructions") %></th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><pre><%= @order.special_instructions %></pre></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<h4><%= t('history') %></h4>
|
|
||||||
|
|
||||||
<table class="index">
|
|
||||||
<tr>
|
|
||||||
<th><%= t("event") %></th>
|
|
||||||
<th><%= t("user") %></th>
|
|
||||||
<th><%= "#{t('spree.date')}/#{t('spree.time')}" %></th>
|
|
||||||
</tr>
|
|
||||||
<% @order.state_events.sort.each do |event| %>
|
|
||||||
<tr>
|
|
||||||
<td><%=t("#{event.name}") %></td>
|
|
||||||
<td><%=event.user.email if event.user %></td>
|
|
||||||
<td><%=event.created_at.to_s(:date_time24) %></td>
|
|
||||||
</tr>
|
|
||||||
<% end %>
|
|
||||||
<% if @order.state_events.empty? %>
|
|
||||||
<tr>
|
|
||||||
<td colspan="3"><%= t("none_available") %></td>
|
|
||||||
</tr>
|
|
||||||
<% end %>
|
|
||||||
</table>
|
|
|
@ -1,31 +0,0 @@
|
||||||
<div class='toolbar'>
|
|
||||||
<ul class='actions'>
|
|
||||||
<li>
|
|
||||||
<%= button_link_to t("new_credit_card_payment"), new_admin_order_creditcard_payment_url(@order), :icon => 'add' %>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<br class='clear' />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<%= render :partial => 'admin/shared/order_tabs', :locals => {:current => "Payments"} %>
|
|
||||||
|
|
||||||
<table class="index">
|
|
||||||
<tr>
|
|
||||||
<th><%= "#{t('spree.date')}/#{t('spree.time')}" %></th>
|
|
||||||
<th><%= t("amount") %></th>
|
|
||||||
<th><%= t("type") %></th>
|
|
||||||
<th></th>
|
|
||||||
</tr>
|
|
||||||
<% @payments.each do |payment| %>
|
|
||||||
<tr>
|
|
||||||
<td><%= payment.created_at.to_s(:date_time24) %></td>
|
|
||||||
<td><%= number_to_currency(payment.amount) %></td>
|
|
||||||
<td><%= payment.class.to_s %></td>
|
|
||||||
<!-- TODO: don't assume credit card, make it possible to edit other kinds of payments -->
|
|
||||||
<td>
|
|
||||||
<% url = payment.type == "CreditcardPayment" ? edit_admin_order_creditcard_payment_url(@order, payment) : edit_admin_order_paypal_payment_url(@order, payment) %>
|
|
||||||
<%= link_to_with_icon 'edit', t('edit'), url %>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<% end %>
|
|
||||||
</table>
|
|
|
@ -1,3 +1,3 @@
|
||||||
<a href="<%= paypal_checkout_order_url @checkout.order, :integration_id => integration %>" style="text-align: center;">
|
<a href="<%= paypal_checkout_orders_checkout_url @checkout.order, :integration_id => integration %>" style="text-align: center;">
|
||||||
<img src="https://www.paypal.com/en_GB/GB/i/btn/btn_xpressCheckout.gif" align="left" style="margin-right:7px;"/>
|
<img src="https://www.paypal.com/en_US/i/btn/btn_xpressCheckout.gif" align="left" style="margin-right:7px;"/>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -3,15 +3,7 @@
|
||||||
<%= t("order_not_yet_placed") %>
|
<%= t("order_not_yet_placed") %>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<%= render :partial => 'shared/order_details', :locals => {:order => @order} -%>
|
<%= render :partial => 'shared/order_details', :locals => {:order => @order} -%>
|
||||||
<div class="form-buttons">
|
<div class="form-buttons">
|
||||||
<%= button_to t('place_order'), "/orders/#{@order.number}/paypal_finish?token=#{params[:token]}&PayerID=#{params[:PayerID]}", :class => "button primary" %>
|
<%= button_to t('place_order'), paypal_finish_order_checkout_url(@checkout.order, {:token => params[:token] , :PayerID => params[:PayerID] } ), :class => "button primary" %>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
<%= @ppx_details.to_yaml %>
|
|
||||||
</pre>
|
|
|
@ -1 +0,0 @@
|
||||||
Thanks.
|
|
|
@ -1,3 +1,3 @@
|
||||||
<a href="<%= paypal_payment_order_url @checkout.order, :integration_id => integration %>" style="text-align: center;">
|
<a href="<%= paypal_payment_order_checkout_url @checkout.order, :integration_id => integration %>" style="text-align: center;">
|
||||||
<img src="https://www.paypal.com/en_GB/GB/i/btn/btn_xpressCheckout.gif" align="left" style="margin-right:7px;"/>
|
<img src="https://www.paypal.com/en_US/i/btn/btn_xpressCheckout.gif" align="left" style="margin-right:7px;"/>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
<!-- PayPal Logo --><table border="0" cellpadding="10" cellspacing="0" align="center"><tr><td align="center"></td></tr><tr><td align="center"><a href="#" onclick="javascript:window.open('https://www.paypal.com/uk/cgi-bin/webscr?cmd=xpt/Marketing/popup/OLCWhatIsPayPal-outside','olcwhatispaypal','toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, width=400, height=350');"><img src="https://www.paypal.com/en_GB/GB/i/logo/PayPal_mark_50x34.gif" border="0" alt="Acceptance Mark"></a></td></tr></table><!-- PayPal Logo -->
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
# Put your extension routes here.
|
# Put your extension routes here.
|
||||||
|
|
||||||
map.resources :orders, :member => {:paypal_checkout => :any, :paypal_payment => :any, :paypal_confirm => :any, :paypal_finish => :any}
|
map.resources :orders do |order|
|
||||||
|
order.resource :checkout, :member => {:paypal_checkout => :any, :paypal_payment => :any, :paypal_confirm => :any, :paypal_finish => :any}
|
||||||
|
end
|
||||||
|
|
||||||
map.resources :paypal_express_callbacks, :only => [:index, :show]
|
map.resources :paypal_express_callbacks, :only => [:index]
|
||||||
|
|
||||||
map.namespace :admin do |admin|
|
map.namespace :admin do |admin|
|
||||||
admin.resources :orders do |order|
|
admin.resources :orders do |order|
|
||||||
|
|
|
@ -8,41 +8,43 @@ module ActiveMerchant #:nodoc:
|
||||||
base.cattr_accessor :signature
|
base.cattr_accessor :signature
|
||||||
end
|
end
|
||||||
|
|
||||||
API_VERSION = '60.0' # TODO - check absolute adherence in this file, override in sub?
|
silence_warnings do
|
||||||
|
API_VERSION = '60.0'
|
||||||
|
|
||||||
URLS = {
|
URLS = {
|
||||||
:test => { :certificate => 'https://api.sandbox.paypal.com/2.0/',
|
:test => { :certificate => 'https://api.sandbox.paypal.com/2.0/',
|
||||||
:signature => 'https://api-3t.sandbox.paypal.com/2.0/' },
|
:signature => 'https://api-3t.sandbox.paypal.com/2.0/' },
|
||||||
:live => { :certificate => 'https://api-aa.paypal.com/2.0/',
|
:live => { :certificate => 'https://api-aa.paypal.com/2.0/',
|
||||||
:signature => 'https://api-3t.paypal.com/2.0/' }
|
:signature => 'https://api-3t.paypal.com/2.0/' }
|
||||||
}
|
}
|
||||||
|
|
||||||
PAYPAL_NAMESPACE = 'urn:ebay:api:PayPalAPI'
|
PAYPAL_NAMESPACE = 'urn:ebay:api:PayPalAPI'
|
||||||
EBAY_NAMESPACE = 'urn:ebay:apis:eBLBaseComponents'
|
EBAY_NAMESPACE = 'urn:ebay:apis:eBLBaseComponents'
|
||||||
|
|
||||||
ENVELOPE_NAMESPACES = { 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema',
|
ENVELOPE_NAMESPACES = { 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema',
|
||||||
'xmlns:env' => 'http://schemas.xmlsoap.org/soap/envelope/',
|
'xmlns:env' => 'http://schemas.xmlsoap.org/soap/envelope/',
|
||||||
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance'
|
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance'
|
||||||
}
|
}
|
||||||
CREDENTIALS_NAMESPACES = { 'xmlns' => PAYPAL_NAMESPACE,
|
CREDENTIALS_NAMESPACES = { 'xmlns' => PAYPAL_NAMESPACE,
|
||||||
'xmlns:n1' => EBAY_NAMESPACE,
|
'xmlns:n1' => EBAY_NAMESPACE,
|
||||||
'env:mustUnderstand' => '0'
|
'env:mustUnderstand' => '0'
|
||||||
}
|
}
|
||||||
|
|
||||||
AUSTRALIAN_STATES = {
|
AUSTRALIAN_STATES = {
|
||||||
'ACT' => 'Australian Capital Territory',
|
'ACT' => 'Australian Capital Territory',
|
||||||
'NSW' => 'New South Wales',
|
'NSW' => 'New South Wales',
|
||||||
'NT' => 'Northern Territory',
|
'NT' => 'Northern Territory',
|
||||||
'QLD' => 'Queensland',
|
'QLD' => 'Queensland',
|
||||||
'SA' => 'South Australia',
|
'SA' => 'South Australia',
|
||||||
'TAS' => 'Tasmania',
|
'TAS' => 'Tasmania',
|
||||||
'VIC' => 'Victoria',
|
'VIC' => 'Victoria',
|
||||||
'WA' => 'Western Australia'
|
'WA' => 'Western Australia'
|
||||||
}
|
}
|
||||||
|
|
||||||
SUCCESS_CODES = [ 'Success', 'SuccessWithWarning' ]
|
SUCCESS_CODES = [ 'Success', 'SuccessWithWarning' ]
|
||||||
|
|
||||||
FRAUD_REVIEW_CODE = "11610"
|
FRAUD_REVIEW_CODE = "11610"
|
||||||
|
end
|
||||||
|
|
||||||
# The gateway must be configured with either your PayPal PEM file
|
# The gateway must be configured with either your PayPal PEM file
|
||||||
# or your PayPal API Signature. Only one is required.
|
# or your PayPal API Signature. Only one is required.
|
||||||
|
@ -314,8 +316,6 @@ module ActiveMerchant #:nodoc:
|
||||||
xml.tag! 'n2:OrderTotal', amount(money), 'currencyID' => currency_code
|
xml.tag! 'n2:OrderTotal', amount(money), 'currencyID' => currency_code
|
||||||
|
|
||||||
# All of the values must be included together and add up to the order total
|
# All of the values must be included together and add up to the order total
|
||||||
puts "-----------#{options[:shipping]}---------------------#{amount(options[:shipping])}----------------"
|
|
||||||
|
|
||||||
if [:subtotal, :shipping, :handling, :tax].all?{ |o| options.has_key?(o) }
|
if [:subtotal, :shipping, :handling, :tax].all?{ |o| options.has_key?(o) }
|
||||||
xml.tag! 'n2:ItemTotal', amount(options[:subtotal]), 'currencyID' => currency_code
|
xml.tag! 'n2:ItemTotal', amount(options[:subtotal]), 'currencyID' => currency_code
|
||||||
xml.tag! 'n2:ShippingTotal', amount(options[:shipping]),'currencyID' => currency_code
|
xml.tag! 'n2:ShippingTotal', amount(options[:shipping]),'currencyID' => currency_code
|
||||||
|
|
|
@ -16,11 +16,7 @@ module ActiveMerchant #:nodoc:
|
||||||
def setup_authorization(money, options = {})
|
def setup_authorization(money, options = {})
|
||||||
requires!(options, :return_url, :cancel_return_url)
|
requires!(options, :return_url, :cancel_return_url)
|
||||||
|
|
||||||
req = build_setup_request('Authorization', money, options)
|
commit 'SetExpressCheckout', build_setup_request('Authorization', money, options)
|
||||||
|
|
||||||
puts req
|
|
||||||
|
|
||||||
commit 'SetExpressCheckout', req
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def setup_purchase(money, options = {})
|
def setup_purchase(money, options = {})
|
||||||
|
@ -36,11 +32,7 @@ module ActiveMerchant #:nodoc:
|
||||||
def authorize(money, options = {})
|
def authorize(money, options = {})
|
||||||
requires!(options, :token, :payer_id)
|
requires!(options, :token, :payer_id)
|
||||||
|
|
||||||
req = build_sale_or_authorization_request('Authorization', money, options)
|
commit 'DoExpressCheckoutPayment', build_sale_or_authorization_request('Authorization', money, options)
|
||||||
|
|
||||||
puts req
|
|
||||||
|
|
||||||
commit 'DoExpressCheckoutPayment', req
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def purchase(money, options = {})
|
def purchase(money, options = {})
|
||||||
|
|
|
@ -4,8 +4,9 @@ module Spree::PaypalExpress
|
||||||
include ActiveMerchant::RequiresParameters
|
include ActiveMerchant::RequiresParameters
|
||||||
|
|
||||||
def paypal_checkout
|
def paypal_checkout
|
||||||
|
load_object
|
||||||
opts = all_opts(@order, 'checkout')
|
opts = all_opts(@order, 'checkout')
|
||||||
opts.merge!(address_and_selected_shipping_options(@order))
|
opts.merge!(address_options(@order))
|
||||||
gateway = paypal_gateway
|
gateway = paypal_gateway
|
||||||
|
|
||||||
response = gateway.setup_authorization(opts[:money], opts)
|
response = gateway.setup_authorization(opts[:money], opts)
|
||||||
|
@ -19,8 +20,9 @@ module Spree::PaypalExpress
|
||||||
end
|
end
|
||||||
|
|
||||||
def paypal_payment
|
def paypal_payment
|
||||||
|
load_object
|
||||||
opts = all_opts(@order, 'payment')
|
opts = all_opts(@order, 'payment')
|
||||||
opts.merge!(address_and_selected_shipping_options(@order))
|
opts.merge!(address_options(@order))
|
||||||
gateway = paypal_gateway
|
gateway = paypal_gateway
|
||||||
|
|
||||||
response = gateway.setup_authorization(opts[:money], opts)
|
response = gateway.setup_authorization(opts[:money], opts)
|
||||||
|
@ -34,7 +36,7 @@ module Spree::PaypalExpress
|
||||||
end
|
end
|
||||||
|
|
||||||
def paypal_confirm
|
def paypal_confirm
|
||||||
@order = Order.find_by_number(params[:id])
|
load_object
|
||||||
|
|
||||||
opts = { :token => params[:token], :payer_id => params[:PayerID] }.merge all_opts(@order)
|
opts = { :token => params[:token], :payer_id => params[:PayerID] }.merge all_opts(@order)
|
||||||
gateway = paypal_gateway
|
gateway = paypal_gateway
|
||||||
|
@ -42,8 +44,6 @@ module Spree::PaypalExpress
|
||||||
@ppx_details = gateway.details_for params[:token]
|
@ppx_details = gateway.details_for params[:token]
|
||||||
gateway_error(@ppx_details) unless @ppx_details.success?
|
gateway_error(@ppx_details) unless @ppx_details.success?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# now save the updated order info
|
# now save the updated order info
|
||||||
@order.checkout.email = @ppx_details.email
|
@order.checkout.email = @ppx_details.email
|
||||||
@order.checkout.special_instructions = @ppx_details.params["note"]
|
@order.checkout.special_instructions = @ppx_details.params["note"]
|
||||||
|
@ -75,65 +75,64 @@ module Spree::PaypalExpress
|
||||||
end
|
end
|
||||||
|
|
||||||
def paypal_finish
|
def paypal_finish
|
||||||
order = Order.find_by_number(params[:id])
|
load_object
|
||||||
|
#order = Order.find_by_number(params[:id])
|
||||||
|
|
||||||
opts = { :token => params[:token], :payer_id => params[:PayerID] }.merge all_opts(@order)
|
opts = { :token => params[:token], :payer_id => params[:PayerID] }.merge all_opts(@order)
|
||||||
gateway = paypal_gateway
|
gateway = paypal_gateway
|
||||||
|
|
||||||
|
if Spree::Config[:auto_capture]
|
||||||
|
ppx_auth_response = gateway.purchase((@order.total*100).to_i, opts)
|
||||||
|
else
|
||||||
|
ppx_auth_response = gateway.authorize((@order.total*100).to_i, opts)
|
||||||
|
end
|
||||||
|
|
||||||
ppx_auth_response = gateway.authorize((order.total*100).to_i, opts)
|
|
||||||
gateway_error(ppx_auth_response) unless ppx_auth_response.success?
|
gateway_error(ppx_auth_response) unless ppx_auth_response.success?
|
||||||
puts "------------------------------------------------"
|
|
||||||
puts ppx_auth_response.to_yaml
|
|
||||||
|
|
||||||
puts "-----#{ppx_auth_response.avs_result.class}--------------------------------#{ppx_auth_response.avs_result["code"]}-----------"
|
payment = @order.paypal_payments.create(:amount => ppx_auth_response.params["gross_amount"].to_f)
|
||||||
|
|
||||||
payment = order.paypal_payments.create(:amount => ppx_auth_response.params["gross_amount"].to_f)
|
transaction = PaypalTxn.new(:paypal_payment => payment,
|
||||||
|
|
||||||
# query - need 0 in amount for an auth? see main code
|
|
||||||
transaction = PaypalTxn.new (:paypal_payment => payment,
|
|
||||||
:gross_amount => ppx_auth_response.params["gross_amount"].to_f,
|
:gross_amount => ppx_auth_response.params["gross_amount"].to_f,
|
||||||
|
:message => ppx_auth_response.params["message "],
|
||||||
:payment_status => ppx_auth_response.params["payment_status"],
|
:payment_status => ppx_auth_response.params["payment_status"],
|
||||||
:pending_reason => ppx_auth_response.params["pending_reason"],
|
:pending_reason => ppx_auth_response.params["pending_reason"],
|
||||||
:transaction_type => ppx_auth_response.params["transaction_type"],
|
:transaction_type => ppx_auth_response.params["transaction_type"],
|
||||||
:payment_type => ppx_auth_response.params["payment_type"],
|
:payment_type => ppx_auth_response.params["payment_type"],
|
||||||
:ack => ppx_auth_response.params["ack"],
|
:ack => ppx_auth_response.params["ack"],
|
||||||
:token => ppx_auth_response.params["token"])# ,
|
:token => ppx_auth_response.params["token"],
|
||||||
# :avs_code => ppx_auth_response.params["avs_result"]["code"],
|
:avs_code => ppx_auth_response.avs_result["code"],
|
||||||
# :cvv_code => ppx_auth_response.params["cvv_result"]["code"])
|
:cvv_code => ppx_auth_response.cvv_result["code"])
|
||||||
|
|
||||||
payment.paypal_txns << transaction
|
payment.paypal_txns << transaction
|
||||||
|
|
||||||
|
@order.save!
|
||||||
# save this for future reference
|
@checkout.reload
|
||||||
# order.checkout.shipment.shipping_method ||= ShippingMethod.first
|
until @checkout.state == "complete"
|
||||||
# order.checkout.shipment.save
|
@checkout.next!
|
||||||
|
end
|
||||||
order.save!
|
|
||||||
order.complete # get return of status? throw of problems??? else weak go-ahead
|
|
||||||
|
|
||||||
# todo - share code
|
# todo - share code
|
||||||
flash[:notice] = t('order_processed_successfully')
|
flash[:notice] = t('order_processed_successfully')
|
||||||
order_params = {:checkout_complete => true}
|
order_params = {:checkout_complete => true}
|
||||||
order_params[:order_token] = order.token unless order.user
|
order_params[:order_token] = @order.token unless @order.user
|
||||||
session[:order_id] = nil if order.checkout.completed_at
|
session[:order_id] = nil if @order.checkout.completed_at
|
||||||
redirect_to order_url(order, order_params)
|
redirect_to order_url(@order, order_params)
|
||||||
end
|
end
|
||||||
|
|
||||||
def do_capture(authorization)
|
# def do_capture(authorization)
|
||||||
response = paypal_gateway.capture((100 * authorization.amount).to_i, authorization.response_code)
|
# response = paypal_gateway.capture((100 * authorization.amount).to_i, authorization.response_code)
|
||||||
|
#
|
||||||
gateway_error(response) unless response.success?
|
# gateway_error(response) unless response.success?
|
||||||
|
#
|
||||||
# TODO needs to be cleaned up or recast...
|
# # TODO needs to be cleaned up or recast...
|
||||||
payment = PaypalPayment.find(authorization.creditcard_payment_id)
|
# payment = PaypalPayment.find(authorization.creditcard_payment_id)
|
||||||
|
#
|
||||||
# create a transaction to reflect the capture
|
# # create a transaction to reflect the capture
|
||||||
payment.txns << CreditcardTxn.new( :amount => authorization.amount,
|
# payment.txns << CreditcardTxn.new( :amount => authorization.amount,
|
||||||
:response_code => response.authorization,
|
# :response_code => response.authorization,
|
||||||
:txn_type => CreditcardTxn::TxnType::CAPTURE )
|
# :txn_type => CreditcardTxn::TxnType::CAPTURE )
|
||||||
payment.save
|
# payment.save
|
||||||
end
|
# end
|
||||||
|
|
||||||
private
|
private
|
||||||
def fixed_opts
|
def fixed_opts
|
||||||
|
@ -175,7 +174,7 @@ module Spree::PaypalExpress
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
opts = { :return_url => request.protocol + request.host_with_port + "/orders/#{order.number}/paypal_confirm",
|
opts = { :return_url => request.protocol + request.host_with_port + "/orders/#{order.number}/checkout/paypal_confirm",
|
||||||
:cancel_return_url => "http://" + request.host_with_port + "/orders/#{order.number}/edit",
|
:cancel_return_url => "http://" + request.host_with_port + "/orders/#{order.number}/edit",
|
||||||
:order_id => order.number,
|
:order_id => order.number,
|
||||||
:custom => order.number,
|
:custom => order.number,
|
||||||
|
@ -220,7 +219,7 @@ module Spree::PaypalExpress
|
||||||
0.0
|
0.0
|
||||||
end
|
end
|
||||||
|
|
||||||
def address_and_selected_shipping_options(order)
|
def address_options(order)
|
||||||
{
|
{
|
||||||
:no_shipping => false,
|
:no_shipping => false,
|
||||||
:address_override => true,
|
:address_override => true,
|
||||||
|
@ -288,7 +287,7 @@ module Spree::PaypalExpress
|
||||||
integration = BillingIntegration.find(params[:integration_id]) if params.key? :integration_id
|
integration = BillingIntegration.find(params[:integration_id]) if params.key? :integration_id
|
||||||
integration ||= BillingIntegration.current
|
integration ||= BillingIntegration.current
|
||||||
gw_opts = integration.options
|
gw_opts = integration.options
|
||||||
logger.debug { "-----------#{integration.provider_class}-------------------------------------" }
|
|
||||||
requires!(gw_opts, :login, :password, :signature)
|
requires!(gw_opts, :login, :password, :signature)
|
||||||
|
|
||||||
gateway = integration.provider_class.new(gw_opts)
|
gateway = integration.provider_class.new(gw_opts)
|
||||||
|
|
|
@ -8,6 +8,7 @@ class PaypalExpressExtension < Spree::Extension
|
||||||
|
|
||||||
def activate
|
def activate
|
||||||
BillingIntegration::PaypalExpress.register
|
BillingIntegration::PaypalExpress.register
|
||||||
|
BillingIntegration::PaypalExpressUk.register
|
||||||
|
|
||||||
# Load up over-rides for ActiveMerchant files
|
# Load up over-rides for ActiveMerchant files
|
||||||
# these will be submitted to ActiveMerchant some time...
|
# these will be submitted to ActiveMerchant some time...
|
||||||
|
@ -17,7 +18,7 @@ class PaypalExpressExtension < Spree::Extension
|
||||||
|
|
||||||
|
|
||||||
# inject paypal code into orders controller
|
# inject paypal code into orders controller
|
||||||
OrdersController.class_eval do
|
CheckoutsController.class_eval do
|
||||||
include Spree::PaypalExpress
|
include Spree::PaypalExpress
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue