spree_paypal_express 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -0
- data/.travis.yml +14 -0
- data/Gemfile +3 -0
- data/LICENSE +23 -0
- data/README.markdown +146 -0
- data/Rakefile +13 -0
- data/Versionfile +5 -0
- data/app/assets/images/paypal.png +0 -0
- data/app/assets/javascripts/admin/spree_paypal_express.js +0 -0
- data/app/assets/javascripts/store/spree_paypal_express.js +0 -0
- data/app/assets/stylesheets/admin/spree_paypal_express.css +0 -0
- data/app/assets/stylesheets/store/spree_paypal_express.css +0 -0
- data/app/controllers/spree/checkout_controller_decorator.rb +384 -0
- data/app/controllers/spree/paypal_express_callbacks_controller.rb +44 -0
- data/app/helpers/spree/checkout_helper_decorator.rb +7 -0
- data/app/models/spree/billing_integration/paypal_express.rb +3 -0
- data/app/models/spree/billing_integration/paypal_express_base.rb +62 -0
- data/app/models/spree/billing_integration/paypal_express_uk.rb +3 -0
- data/app/models/spree/log_entry_decorator.rb +3 -0
- data/app/models/spree/payment_decorator.rb +3 -0
- data/app/models/spree/paypal_account.rb +36 -0
- data/app/overrides/spree/shared/_order_details/add_paypal_details.html.erb.deface +16 -0
- data/app/views/spree/admin/payments/source_forms/_paypalexpress.html.erb +9 -0
- data/app/views/spree/admin/payments/source_forms/_paypalexpressuk.html.erb +9 -0
- data/app/views/spree/admin/payments/source_views/_paypalexpress.html.erb +110 -0
- data/app/views/spree/admin/payments/source_views/_paypalexpressuk.html.erb +110 -0
- data/app/views/spree/admin/paypal_payments/refund.html.erb +15 -0
- data/app/views/spree/checkout/payment/_paypalexpress.html.erb +3 -0
- data/app/views/spree/checkout/payment/_paypalexpressuk.html.erb +3 -0
- data/app/views/spree/shared/_paypal_express_checkout.html.erb +3 -0
- data/app/views/spree/shared/paypal_express_confirm.html.erb +23 -0
- data/capture-notes +28 -0
- data/config/initializers/paypal_express.rb +1 -0
- data/config/locales/en-GB.yml +30 -0
- data/config/locales/en.yml +32 -0
- data/config/routes.rb +25 -0
- data/db/migrate/20100224133156_create_paypal_accounts.rb +14 -0
- data/db/migrate/20120117182027_namespace_paypal_accounts.rb +5 -0
- data/lib/generators/spree_paypal_express/install/install_generator.rb +18 -0
- data/lib/spree/paypal_express_configuration.rb +5 -0
- data/lib/spree_paypal_express.rb +3 -0
- data/lib/spree_paypal_express/engine.rb +38 -0
- data/response-example-one +55 -0
- data/response-xml-one +137 -0
- data/spec/controllers/checkout_controller_spec.rb +323 -0
- data/spec/factories/address_factory.rb +13 -0
- data/spec/factories/order_factory.rb +11 -0
- data/spec/factories/ppx_factory.rb +5 -0
- data/spec/factories/state_factory.rb +5 -0
- data/spec/models/billing_integration/paypal_express_base_spec.rb +135 -0
- data/spec/requests/paypal_express_spec.rb +40 -0
- data/spec/spec_helper.rb +37 -0
- data/spec/support/authentication_helpers.rb +13 -0
- data/spec/support/controller_hacks.rb +33 -0
- data/spec/support/shared_connection.rb +12 -0
- data/spec/support/url_helpers.rb +7 -0
- data/spree_paypal_express.gemspec +24 -0
- metadata +224 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
module Spree
|
2
|
+
class PaypalExpressCallbacksController < Spree::BaseController
|
3
|
+
include ActiveMerchant::Billing::Integrations
|
4
|
+
skip_before_filter :verify_authenticity_token
|
5
|
+
|
6
|
+
ssl_required
|
7
|
+
|
8
|
+
def notify
|
9
|
+
retrieve_details #need to retreive details first to ensure ActiveMerchant gets configured correctly.
|
10
|
+
|
11
|
+
|
12
|
+
@notification = Paypal::Notification.new(request.raw_post)
|
13
|
+
|
14
|
+
# we only care about eChecks (for now?)
|
15
|
+
if @notification.params["payment_type"] == "echeck" && @notification.acknowledge && @payment && @order.total >= @payment.amount
|
16
|
+
@payment.started_processing!
|
17
|
+
@payment.log_entries.create(:details => @notification.to_yaml)
|
18
|
+
|
19
|
+
case @notification.params["payment_status"]
|
20
|
+
when "Denied"
|
21
|
+
@payment.failure!
|
22
|
+
|
23
|
+
when "Completed"
|
24
|
+
@payment.complete!
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
render :nothing => true
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def retrieve_details
|
34
|
+
@order = Spree::Order.find_by_number(params["invoice"])
|
35
|
+
|
36
|
+
if @order
|
37
|
+
@payment = @order.payments.where(:state => "pending", :source_type => "PaypalAccount").try(:first)
|
38
|
+
|
39
|
+
@payment.try(:payment_method).try(:provider) #configures ActiveMerchant
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
class Spree::BillingIntegration::PaypalExpressBase < Spree::BillingIntegration
|
2
|
+
preference :login, :string
|
3
|
+
preference :password, :password
|
4
|
+
preference :signature, :string
|
5
|
+
preference :review, :boolean, :default => false
|
6
|
+
preference :no_shipping, :boolean, :default => false
|
7
|
+
preference :currency, :string, :default => 'USD'
|
8
|
+
preference :allow_guest_checkout, :boolean, :default => false
|
9
|
+
|
10
|
+
attr_accessible :preferred_login, :preferred_password, :preferred_signature, :preferred_review, :preferred_no_shipping, :preferred_currency, :preferred_allow_guest_checkout, :preferred_server, :preferred_test_mode
|
11
|
+
|
12
|
+
def provider_class
|
13
|
+
ActiveMerchant::Billing::PaypalExpressGateway
|
14
|
+
end
|
15
|
+
|
16
|
+
def payment_profiles_supported?
|
17
|
+
!!preferred_review
|
18
|
+
end
|
19
|
+
|
20
|
+
def capture(payment_or_amount, account_or_response_code, gateway_options)
|
21
|
+
if payment_or_amount.is_a?(Spree::Payment)
|
22
|
+
authorization = find_authorization(payment_or_amount)
|
23
|
+
provider.capture(amount_in_cents(payment_or_amount.amount), authorization.params["transaction_id"], :currency => preferred_currency)
|
24
|
+
else
|
25
|
+
provider.capture(payment_or_amount, account_or_response_code, :currency => preferred_currency)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def credit(*args)
|
30
|
+
amount = args.shift
|
31
|
+
response_code = args.first.is_a?(String) ? args.first : args[1]
|
32
|
+
provider.credit(amount, response_code, :currency => preferred_currency)
|
33
|
+
end
|
34
|
+
|
35
|
+
def find_authorization(payment)
|
36
|
+
logs = payment.log_entries.all(:order => 'created_at DESC')
|
37
|
+
logs.each do |log|
|
38
|
+
details = YAML.load(log.details) # return the transaction details
|
39
|
+
if (details.params['payment_status'] == 'Pending' && details.params['pending_reason'] == 'authorization')
|
40
|
+
return details
|
41
|
+
end
|
42
|
+
end
|
43
|
+
return nil
|
44
|
+
end
|
45
|
+
|
46
|
+
def find_capture(payment)
|
47
|
+
#find the transaction associated with the original authorization/capture
|
48
|
+
logs = payment.log_entries.all(:order => 'created_at DESC')
|
49
|
+
logs.each do |log|
|
50
|
+
details = YAML.load(log.details) # return the transaction details
|
51
|
+
if details.params['payment_status'] == 'Completed'
|
52
|
+
return details
|
53
|
+
end
|
54
|
+
end
|
55
|
+
return nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def amount_in_cents(amount)
|
59
|
+
(100 * amount).to_i
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Spree::PaypalAccount < ActiveRecord::Base
|
2
|
+
attr_accessible :email, :payer_id, :payer_country, :payer_status
|
3
|
+
has_many :payments, :as => :source
|
4
|
+
|
5
|
+
def actions
|
6
|
+
%w{capture credit}
|
7
|
+
end
|
8
|
+
|
9
|
+
def can_capture?(payment)
|
10
|
+
!echeck?(payment) && payment.state == "pending"
|
11
|
+
end
|
12
|
+
|
13
|
+
def can_credit?(payment)
|
14
|
+
return false unless payment.state == "completed"
|
15
|
+
return false unless payment.order.payment_state == "credit_owed"
|
16
|
+
payment.credit_allowed > 0
|
17
|
+
!payment.payment_method.find_capture(payment).nil?
|
18
|
+
end
|
19
|
+
|
20
|
+
# fix for Payment#payment_profiles_supported?
|
21
|
+
def payment_gateway
|
22
|
+
false
|
23
|
+
end
|
24
|
+
|
25
|
+
def echeck?(payment)
|
26
|
+
logs = payment.log_entries.all(:order => 'created_at DESC')
|
27
|
+
logs.each do |log|
|
28
|
+
details = YAML.load(log.details) # return the transaction details
|
29
|
+
if details.params['payment_type'] == 'echeck'
|
30
|
+
return true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
return false
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<!--
|
2
|
+
insert_bottom '.payment-info'
|
3
|
+
original '9d4ef160bd508a47f906d7419c33cfc7eefc501d'
|
4
|
+
-->
|
5
|
+
<% if order.payment && order.payment.source.class.to_s == 'Spree::PaypalAccount' %>
|
6
|
+
<span class="cc-type">
|
7
|
+
<%= image_tag "paypal.png" %>
|
8
|
+
<%= order.payment.source.payer_status.to_s.capitalize %>
|
9
|
+
</span>
|
10
|
+
<br />
|
11
|
+
<span class="full-name">
|
12
|
+
<%= order.payment.source.email %>
|
13
|
+
</span>
|
14
|
+
<% end %>
|
15
|
+
|
16
|
+
|
@@ -0,0 +1,110 @@
|
|
1
|
+
<fieldset>
|
2
|
+
<legend><%= t('paypal_account') %></legend>
|
3
|
+
|
4
|
+
<table class="index">
|
5
|
+
<tr>
|
6
|
+
<th colspan="6"><%= t('account_details') %></th>
|
7
|
+
</tr>
|
8
|
+
<tr>
|
9
|
+
<td><label><%= t("email") %>:</label></td>
|
10
|
+
<td>
|
11
|
+
<%= payment.source.email %>
|
12
|
+
</td>
|
13
|
+
<td><label><%= t("payer_id") %>:</label></td>
|
14
|
+
<td>
|
15
|
+
<%= payment.source.payer_id %>
|
16
|
+
</td>
|
17
|
+
<td><label><%= t("payer_country") %>:</label></td>
|
18
|
+
<td>
|
19
|
+
<%= payment.source.payer_country %>
|
20
|
+
</td>
|
21
|
+
</tr>
|
22
|
+
<tr>
|
23
|
+
<td><label><%= t("payer_status") %>:</label></td>
|
24
|
+
<td colspan="5">
|
25
|
+
<%= payment.source.payer_status %>
|
26
|
+
</td>
|
27
|
+
</tr>
|
28
|
+
</table>
|
29
|
+
</fieldset>
|
30
|
+
|
31
|
+
<fieldset>
|
32
|
+
<legend><%= t('transactions') %></legend>
|
33
|
+
|
34
|
+
<% payment.log_entries.reverse.each do |log| %>
|
35
|
+
<% details = YAML.load(log.details) rescue "" %>
|
36
|
+
<table class="index">
|
37
|
+
|
38
|
+
<% if details.is_a? ActiveMerchant::Billing::PaypalExpressResponse %>
|
39
|
+
<tr>
|
40
|
+
<th colspan="6"><%= t('transaction') %> <%= details.params["transaction_id"] %> - <%= log.created_at.to_s(:date_time24) %></th>
|
41
|
+
</tr>
|
42
|
+
<tr>
|
43
|
+
<td width="12%;"><label><%= t('type') %>:</label></td>
|
44
|
+
<td width="20%;">
|
45
|
+
<%= details.params["transaction_type"] %>
|
46
|
+
</td>
|
47
|
+
<td width="8%;"><label><%= t("result") %>:</label></td>
|
48
|
+
<td width="20%;">
|
49
|
+
<%= details.message %>
|
50
|
+
</td>
|
51
|
+
<td width="15%;"><label><%= t("amount") %>:</label></td>
|
52
|
+
<td width="20%;">
|
53
|
+
<%= number_to_currency details.params["gross_amount"] %>
|
54
|
+
</td>
|
55
|
+
</tr>
|
56
|
+
<tr>
|
57
|
+
<td><label><%= t("comment") %>:</label></td>
|
58
|
+
<td colspan="3">
|
59
|
+
<%= details.params["message"] %>
|
60
|
+
</td>
|
61
|
+
<td><label><%= t("status") %>:</label></td>
|
62
|
+
<td>
|
63
|
+
<%= details.params["payment_status"] %>
|
64
|
+
</td>
|
65
|
+
</tr>
|
66
|
+
<% if details.params["payment_status"] == "Pending" %>
|
67
|
+
<tr>
|
68
|
+
<td><label><%= t("pending_reason") %>:</label></td>
|
69
|
+
<td colspan="5">
|
70
|
+
<%= details.params["pending_reason"] %>
|
71
|
+
</td>
|
72
|
+
</tr>
|
73
|
+
<% end %>
|
74
|
+
<% elsif details.is_a? ActiveMerchant::Billing::Integrations::Paypal::Notification %>
|
75
|
+
<tr>
|
76
|
+
<th colspan="6"><%= t('ipn_transaction') %> <%= details.params["txn_id"] %> - <%= log.created_at.to_s(:date_time24) %></th>
|
77
|
+
</tr>
|
78
|
+
<tr>
|
79
|
+
<td width="12%;"><label><%= t('type') %>:</label></td>
|
80
|
+
<td width="20%;">
|
81
|
+
<%= details.params["txn_type"] %>
|
82
|
+
</td>
|
83
|
+
<td width="8%;"><label><%= t("result") %>:</label></td>
|
84
|
+
<td width="20%;">
|
85
|
+
<%= details.params["payment_status"] %>
|
86
|
+
</td>
|
87
|
+
<td width="15%;"><label><%= t("amount") %>:</label></td>
|
88
|
+
<td width="20%;">
|
89
|
+
<%= number_to_currency details.params["mc_gross"] %>
|
90
|
+
</td>
|
91
|
+
</tr>
|
92
|
+
<tr>
|
93
|
+
<td><label><%= t("status") %>:</label></td>
|
94
|
+
<td colspan="5">
|
95
|
+
<%= details.params["payment_status"] %>
|
96
|
+
</td>
|
97
|
+
</tr>
|
98
|
+
<% else %>
|
99
|
+
<tr>
|
100
|
+
<th colspan="6"><%= t('unknown_transaction') %> - <%= log.created_at.to_s(:date_time24) %></th>
|
101
|
+
</tr>
|
102
|
+
<tr>
|
103
|
+
<td colspan="6"><pre style="overflow: hidden; width:600px;"><%= log.details %></pre></th>
|
104
|
+
</tr>
|
105
|
+
|
106
|
+
<% end %>
|
107
|
+
</table>
|
108
|
+
<% end %>
|
109
|
+
|
110
|
+
</fieldset>
|
@@ -0,0 +1,110 @@
|
|
1
|
+
<fieldset>
|
2
|
+
<legend><%= t('paypal_account') %></legend>
|
3
|
+
|
4
|
+
<table class="index">
|
5
|
+
<tr>
|
6
|
+
<th colspan="6"><%= t('account_details') %></th>
|
7
|
+
</tr>
|
8
|
+
<tr>
|
9
|
+
<td><label><%= t("email") %>:</label></td>
|
10
|
+
<td>
|
11
|
+
<%= payment.source.email %>
|
12
|
+
</td>
|
13
|
+
<td><label><%= t("payer_id") %>:</label></td>
|
14
|
+
<td>
|
15
|
+
<%= payment.source.payer_id %>
|
16
|
+
</td>
|
17
|
+
<td><label><%= t("payer_country") %>:</label></td>
|
18
|
+
<td>
|
19
|
+
<%= payment.source.payer_country %>
|
20
|
+
</td>
|
21
|
+
</tr>
|
22
|
+
<tr>
|
23
|
+
<td><label><%= t("payer_status") %>:</label></td>
|
24
|
+
<td colspan="5">
|
25
|
+
<%= payment.source.payer_status %>
|
26
|
+
</td>
|
27
|
+
</tr>
|
28
|
+
</table>
|
29
|
+
</fieldset>
|
30
|
+
|
31
|
+
<fieldset>
|
32
|
+
<legend><%= t('transactions') %></legend>
|
33
|
+
|
34
|
+
<% payment.log_entries.reverse.each do |log| %>
|
35
|
+
<% details = YAML.load(log.details) rescue "" %>
|
36
|
+
<table class="index">
|
37
|
+
|
38
|
+
<% if details.is_a? ActiveMerchant::Billing::PaypalExpressResponse %>
|
39
|
+
<tr>
|
40
|
+
<th colspan="6"><%= t('transaction') %> <%= details.params["transaction_id"] %> - <%= log.created_at.to_s(:date_time24) %></th>
|
41
|
+
</tr>
|
42
|
+
<tr>
|
43
|
+
<td width="12%;"><label><%= t('type') %>:</label></td>
|
44
|
+
<td width="20%;">
|
45
|
+
<%= details.params["transaction_type"] %>
|
46
|
+
</td>
|
47
|
+
<td width="8%;"><label><%= t("result") %>:</label></td>
|
48
|
+
<td width="20%;">
|
49
|
+
<%= details.message %>
|
50
|
+
</td>
|
51
|
+
<td width="15%;"><label><%= t("amount") %>:</label></td>
|
52
|
+
<td width="20%;">
|
53
|
+
<%= number_to_currency details.params["gross_amount"] %>
|
54
|
+
</td>
|
55
|
+
</tr>
|
56
|
+
<tr>
|
57
|
+
<td><label><%= t("comment") %>:</label></td>
|
58
|
+
<td colspan="3">
|
59
|
+
<%= details.params["message"] %>
|
60
|
+
</td>
|
61
|
+
<td><label><%= t("status") %>:</label></td>
|
62
|
+
<td>
|
63
|
+
<%= details.params["payment_status"] %>
|
64
|
+
</td>
|
65
|
+
</tr>
|
66
|
+
<% if details.params["payment_status"] == "Pending" %>
|
67
|
+
<tr>
|
68
|
+
<td><label><%= t("pending_reason") %>:</label></td>
|
69
|
+
<td colspan="5">
|
70
|
+
<%= details.params["pending_reason"] %>
|
71
|
+
</td>
|
72
|
+
</tr>
|
73
|
+
<% end %>
|
74
|
+
<% elsif details.is_a? ActiveMerchant::Billing::Integrations::Paypal::Notification %>
|
75
|
+
<tr>
|
76
|
+
<th colspan="6"><%= t('ipn_transaction') %> <%= details.params["txn_id"] %> - <%= log.created_at.to_s(:date_time24) %></th>
|
77
|
+
</tr>
|
78
|
+
<tr>
|
79
|
+
<td width="12%;"><label><%= t('type') %>:</label></td>
|
80
|
+
<td width="20%;">
|
81
|
+
<%= details.params["txn_type"] %>
|
82
|
+
</td>
|
83
|
+
<td width="8%;"><label><%= t("result") %>:</label></td>
|
84
|
+
<td width="20%;">
|
85
|
+
<%= details.params["payment_status"] %>
|
86
|
+
</td>
|
87
|
+
<td width="15%;"><label><%= t("amount") %>:</label></td>
|
88
|
+
<td width="20%;">
|
89
|
+
<%= number_to_currency details.params["mc_gross"] %>
|
90
|
+
</td>
|
91
|
+
</tr>
|
92
|
+
<tr>
|
93
|
+
<td><label><%= t("status") %>:</label></td>
|
94
|
+
<td colspan="5">
|
95
|
+
<%= details.params["payment_status"] %>
|
96
|
+
</td>
|
97
|
+
</tr>
|
98
|
+
<% else %>
|
99
|
+
<tr>
|
100
|
+
<th colspan="6"><%= t('unknown_transaction') %> - <%= log.created_at.to_s(:date_time24) %></th>
|
101
|
+
</tr>
|
102
|
+
<tr>
|
103
|
+
<td colspan="6"><pre style="overflow: hidden; width:600px;"><%= log.details %></pre></th>
|
104
|
+
</tr>
|
105
|
+
|
106
|
+
<% end %>
|
107
|
+
</table>
|
108
|
+
<% end %>
|
109
|
+
|
110
|
+
</fieldset>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<%= render :partial => 'spree/admin/shared/order_tabs', :locals => {:current => "Payments"} %>
|
2
|
+
|
3
|
+
<% form_tag do %>
|
4
|
+
|
5
|
+
<h3><%= t('refund') %></h3>
|
6
|
+
<fieldset>
|
7
|
+
<p>
|
8
|
+
<label for="amount"><%= t("amount") %></label>
|
9
|
+
<%= text_field_tag :amount, @paypal_payment.amount %>
|
10
|
+
</p>
|
11
|
+
<p class="form-buttons">
|
12
|
+
<%= button t("make_refund") %>
|
13
|
+
</p>
|
14
|
+
</fieldset>
|
15
|
+
<% end %>
|