spree_paypal_adaptive_payment 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. data/.gitignore +22 -0
  2. data/Gemfile +34 -0
  3. data/MIT-LICENSE.txt +20 -0
  4. data/README.markdown +3 -0
  5. data/Rakefile +14 -0
  6. data/TAGS +64 -0
  7. data/Versionfile +1 -0
  8. data/app/models/billing_integration/paypal_adaptive_payment.rb +25 -0
  9. data/app/models/paypal_adaptive_payment_account.rb +99 -0
  10. data/app/views/admin/payments/source_forms/_paypal_adaptive_payments.html.erb +9 -0
  11. data/app/views/admin/payments/source_views/_paypal_adaptive_payments.html.erb +110 -0
  12. data/app/views/admin/paypal_adaptive_payments/refund.html.erb +15 -0
  13. data/app/views/checkout/_confirm.html.erb +11 -0
  14. data/app/views/checkout/_delivery.html.erb +25 -0
  15. data/app/views/checkout/_payment.html.erb +30 -0
  16. data/app/views/checkout/edit.html.erb +18 -0
  17. data/app/views/checkout/payment/_check.html.erb +0 -0
  18. data/app/views/checkout/payment/_gateway.html.erb +31 -0
  19. data/app/views/checkout/payment/_paypal_adaptive_payment.html.erb +3 -0
  20. data/app/views/checkout/payment/_paypaladaptivepayment.html.erb +3 -0
  21. data/app/views/checkout/registration.html.erb +20 -0
  22. data/app/views/shared/_paypal_adaptive_paymetns_checkout.html.erb +3 -0
  23. data/app/views/shared/paypal_adaptive_payments_confirm.html.erb +10 -0
  24. data/config/locales/en.yml +32 -0
  25. data/config/routes.rb +26 -0
  26. data/db/migrate/20100226133156_create_paypal_adaptive_payment_accounts.rb +15 -0
  27. data/doc/BillingIntegration/PaypalAdaptivePayment.html +263 -0
  28. data/doc/PaypalAdaptivePaymentAccount.html +683 -0
  29. data/doc/SpreePaypalAdaptivePayment/Engine.html +200 -0
  30. data/doc/SpreePaypalAdaptivePayment.html +106 -0
  31. data/doc/SpreePaypalAdaptivePaymentHooks.html +116 -0
  32. data/doc/_index.html +146 -0
  33. data/doc/class_list.html +47 -0
  34. data/doc/css/common.css +1 -0
  35. data/doc/css/full_list.css +53 -0
  36. data/doc/css/style.css +320 -0
  37. data/doc/file.README.html +69 -0
  38. data/doc/file_list.html +49 -0
  39. data/doc/frames.html +13 -0
  40. data/doc/index.html +69 -0
  41. data/doc/js/app.js +205 -0
  42. data/doc/js/full_list.js +150 -0
  43. data/doc/js/jquery.js +16 -0
  44. data/doc/method_list.html +134 -0
  45. data/doc/top-level-namespace.html +105 -0
  46. data/lib/spree_paypal_adaptive_payment.rb +24 -0
  47. data/lib/spree_paypal_adaptive_payment_hooks.rb +3 -0
  48. data/lib/tasks/spree_paypal_adaptive_payment.rake +26 -0
  49. data/public/images/paypal111.gif +0 -0
  50. data/spec/controllers/checkout_controller_spec.rb +278 -0
  51. data/spec/factories/address_factory.rb +13 -0
  52. data/spec/factories/order_factory.rb +11 -0
  53. data/spec/factories/state_factory.rb +5 -0
  54. data/spec/spec_helper.rb +40 -0
  55. data/spree_paypal_adaptive_payment.gemspec +17 -0
  56. metadata +111 -0
@@ -0,0 +1,134 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html>
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
+
7
+ <link rel="stylesheet" href="css/full_list.css" type="text/css" media="screen" charset="utf-8" />
8
+
9
+ <link rel="stylesheet" href="css/common.css" type="text/css" media="screen" charset="utf-8" />
10
+
11
+
12
+
13
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
14
+
15
+ <script type="text/javascript" charset="utf-8" src="js/full_list.js"></script>
16
+
17
+
18
+ <base id="base_target" target="_parent" />
19
+ </head>
20
+ <body>
21
+ <script type="text/javascript" charset="utf-8">
22
+ if (window.top.frames.main) {
23
+ document.getElementById('base_target').target = 'main';
24
+ document.body.className = 'frames';
25
+ }
26
+ </script>
27
+ <div id="content">
28
+ <h1 id="full_list_header">Method List</h1>
29
+ <div id="nav">
30
+
31
+ <a target="_self" href="class_list.html">Classes</a>
32
+
33
+ <a target="_self" href="method_list.html">Methods</a>
34
+
35
+ <a target="_self" href="file_list.html">Files</a>
36
+
37
+ </div>
38
+ <div id="search">Search: <input type="text" /></div>
39
+
40
+ <ul id="full_list" class="methods">
41
+
42
+
43
+ <li class="r1 ">
44
+ <span class='object_link'><a href="PaypalAdaptivePaymentAccount.html#actions-instance_method" title="PaypalAdaptivePaymentAccount#actions (method)">#actions</a></span>
45
+
46
+ <small>PaypalAdaptivePaymentAccount</small>
47
+
48
+ </li>
49
+
50
+
51
+ <li class="r2 ">
52
+ <span class='object_link'><a href="SpreePaypalAdaptivePayment/Engine.html#activate-class_method" title="SpreePaypalAdaptivePayment::Engine.activate (method)">activate</a></span>
53
+
54
+ <small>SpreePaypalAdaptivePayment::Engine</small>
55
+
56
+ </li>
57
+
58
+
59
+ <li class="r1 ">
60
+ <span class='object_link'><a href="PaypalAdaptivePaymentAccount.html#can_capture%3F-instance_method" title="PaypalAdaptivePaymentAccount#can_capture? (method)">#can_capture?</a></span>
61
+
62
+ <small>PaypalAdaptivePaymentAccount</small>
63
+
64
+ </li>
65
+
66
+
67
+ <li class="r2 ">
68
+ <span class='object_link'><a href="PaypalAdaptivePaymentAccount.html#can_credit%3F-instance_method" title="PaypalAdaptivePaymentAccount#can_credit? (method)">#can_credit?</a></span>
69
+
70
+ <small>PaypalAdaptivePaymentAccount</small>
71
+
72
+ </li>
73
+
74
+
75
+ <li class="r1 ">
76
+ <span class='object_link'><a href="PaypalAdaptivePaymentAccount.html#capture-instance_method" title="PaypalAdaptivePaymentAccount#capture (method)">#capture</a></span>
77
+
78
+ <small>PaypalAdaptivePaymentAccount</small>
79
+
80
+ </li>
81
+
82
+
83
+ <li class="r2 ">
84
+ <span class='object_link'><a href="PaypalAdaptivePaymentAccount.html#credit-instance_method" title="PaypalAdaptivePaymentAccount#credit (method)">#credit</a></span>
85
+
86
+ <small>PaypalAdaptivePaymentAccount</small>
87
+
88
+ </li>
89
+
90
+
91
+ <li class="r1 ">
92
+ <span class='object_link'><a href="PaypalAdaptivePaymentAccount.html#echeck%3F-instance_method" title="PaypalAdaptivePaymentAccount#echeck? (method)">#echeck?</a></span>
93
+
94
+ <small>PaypalAdaptivePaymentAccount</small>
95
+
96
+ </li>
97
+
98
+
99
+ <li class="r2 ">
100
+ <span class='object_link'><a href="PaypalAdaptivePaymentAccount.html#payment_gateway-instance_method" title="PaypalAdaptivePaymentAccount#payment_gateway (method)">#payment_gateway</a></span>
101
+
102
+ <small>PaypalAdaptivePaymentAccount</small>
103
+
104
+ </li>
105
+
106
+
107
+ <li class="r1 ">
108
+ <span class='object_link'><a href="BillingIntegration/PaypalAdaptivePayment.html#payment_profiles_supported%3F-instance_method" title="BillingIntegration::PaypalAdaptivePayment#payment_profiles_supported? (method)">#payment_profiles_supported?</a></span>
109
+
110
+ <small>BillingIntegration::PaypalAdaptivePayment</small>
111
+
112
+ </li>
113
+
114
+
115
+ <li class="r2 ">
116
+ <span class='object_link'><a href="BillingIntegration/PaypalAdaptivePayment.html#provider_class-instance_method" title="BillingIntegration::PaypalAdaptivePayment#provider_class (method)">#provider_class</a></span>
117
+
118
+ <small>BillingIntegration::PaypalAdaptivePayment</small>
119
+
120
+ </li>
121
+
122
+
123
+ <li class="r1 ">
124
+ <span class='object_link'><a href="PaypalAdaptivePaymentAccount.html#record_log-instance_method" title="PaypalAdaptivePaymentAccount#record_log (method)">#record_log</a></span>
125
+
126
+ <small>PaypalAdaptivePaymentAccount</small>
127
+
128
+ </li>
129
+
130
+
131
+ </ul>
132
+ </div>
133
+ </body>
134
+ </html>
@@ -0,0 +1,105 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
+ <title>
7
+ Top Level Namespace
8
+
9
+ &mdash; PayPal Adaptive Payments to Spree store
10
+
11
+ </title>
12
+
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" media="screen" charset="utf-8" />
14
+
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" media="screen" charset="utf-8" />
16
+
17
+ <script type="text/javascript" charset="utf-8">
18
+ relpath = '';
19
+ if (relpath != '') relpath += '/';
20
+ </script>
21
+
22
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
23
+
24
+ <script type="text/javascript" charset="utf-8" src="js/app.js"></script>
25
+
26
+
27
+ </head>
28
+ <body>
29
+ <script type="text/javascript" charset="utf-8">
30
+ if (window.top.frames.main) document.body.className = 'frames';
31
+ </script>
32
+
33
+ <div id="header">
34
+ <div id="menu">
35
+
36
+ <a href="_index.html">Index</a> &raquo;
37
+
38
+
39
+ <span class="title">Top Level Namespace</span>
40
+
41
+
42
+ <div class="noframes"><span class="title">(</span><a href="." target="_top">no frames</a><span class="title">)</span></div>
43
+ </div>
44
+
45
+ <div id="search">
46
+
47
+ <a id="class_list_link" href="#">Class List</a>
48
+
49
+ <a id="method_list_link" href="#">Method List</a>
50
+
51
+ <a id="file_list_link" href="#">File List</a>
52
+
53
+ </div>
54
+ <div class="clear"></div>
55
+ </div>
56
+
57
+ <iframe id="search_frame"></iframe>
58
+
59
+ <div id="content"><h1>Top Level Namespace
60
+
61
+
62
+
63
+ </h1>
64
+
65
+ <dl class="box">
66
+
67
+
68
+
69
+
70
+
71
+
72
+
73
+
74
+ </dl>
75
+ <div class="clear"></div>
76
+
77
+ <h2>Defined Under Namespace</h2>
78
+ <p class="children">
79
+
80
+
81
+ <strong class="modules">Modules:</strong> <span class='object_link'><a href="SpreePaypalAdaptivePayment.html" title="SpreePaypalAdaptivePayment (module)">SpreePaypalAdaptivePayment</a></span>
82
+
83
+
84
+
85
+ <strong class="classes">Classes:</strong> <span class='object_link'><a href="PaypalAdaptivePaymentAccount.html" title="PaypalAdaptivePaymentAccount (class)">PaypalAdaptivePaymentAccount</a></span>, <span class='object_link'><a href="SpreePaypalAdaptivePaymentHooks.html" title="SpreePaypalAdaptivePaymentHooks (class)">SpreePaypalAdaptivePaymentHooks</a></span>
86
+
87
+
88
+ </p>
89
+
90
+
91
+
92
+
93
+
94
+
95
+
96
+ </div>
97
+
98
+ <div id="footer">
99
+ Generated on Thu Aug 25 01:54:30 2011 by
100
+ <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
101
+ 0.7.2 (ruby-1.9.2).
102
+ </div>
103
+
104
+ </body>
105
+ </html>
@@ -0,0 +1,24 @@
1
+ require 'spree_core'
2
+ require 'spree_paypal_adaptive_payment_hooks'
3
+
4
+ module SpreePaypalAdaptivePayment
5
+ class Engine < Rails::Engine
6
+
7
+ config.autoload_paths += %W(#{config.root}/lib)
8
+
9
+ def self.activate
10
+ # workaround for
11
+ # https://github.com/Shopify/active_merchant/issuesearch?state=open&q=paypal#issue/43
12
+ require 'active_merchant'
13
+ ActiveMerchant::Billing::PaypalAdaptivePayment
14
+
15
+ Dir.glob(File.join(File.dirname(__FILE__), "../app/**/*_decorator*.rb")) do |c|
16
+ Rails.env.production? ? require(c) : load(c)
17
+ end
18
+
19
+ BillingIntegration::PaypalAdaptivePayment.register
20
+ end
21
+
22
+ config.to_prepare &method(:activate).to_proc
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ class SpreePaypalAdaptivePaymentHooks < Spree::ThemeSupport::HookListener
2
+ # custom hooks go here
3
+ end
@@ -0,0 +1,26 @@
1
+ namespace :spree_paypal_adaptive_payment do
2
+ desc "Copies all migrations and assets (NOTE: This will be obsolete with Rails 3.1)"
3
+ task :install do
4
+ Rake::Task['spree_paypal_adaptive_payment:install:migrations'].invoke
5
+ Rake::Task['spree_paypal_adaptive_payment:install:assets'].invoke
6
+ end
7
+
8
+ namespace :install do
9
+ desc "Copies all migrations (NOTE: This will be obsolete with Rails 3.1)"
10
+ task :migrations do
11
+ source = File.join(File.dirname(__FILE__), '..', '..', 'db')
12
+ destination = File.join(Rails.root, 'db')
13
+ puts "INFO: Mirroring assets from #{source} to #{destination}"
14
+ Spree::FileUtilz.mirror_files(source, destination)
15
+ end
16
+
17
+ desc "Copies all assets (NOTE: This will be obsolete with Rails 3.1)"
18
+ task :assets do
19
+ source = File.join(File.dirname(__FILE__), '..', '..', 'public')
20
+ destination = File.join(Rails.root, 'public')
21
+ puts "INFO: Mirroring assets from #{source} to #{destination}"
22
+ Spree::FileUtilz.mirror_files(source, destination)
23
+ end
24
+ end
25
+
26
+ end
Binary file
@@ -0,0 +1,278 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe CheckoutController do
4
+ let(:token) { "EC-2OPN7UJGFWK9OYFV" }
5
+ let(:order) { Factory(:ppx_order_with_totals, :state => "payment") }
6
+ let(:order_total) { (order.total * 100).to_i }
7
+ let(:gateway_provider) { mock(ActiveMerchant::Billing::PaypalExpressGateway) }
8
+ let(:paypal_gateway) { mock(BillingIntegration::PaypalExpress, :id => 123, :preferred_review => false, :preferred_no_shipping => true, :provider => gateway_provider) }
9
+
10
+ let(:details_for_response) { mock(ActiveMerchant::Billing::PaypalExpressResponse, :success? => true,
11
+ :params => {"payer" => order.user.email, "payer_id" => "FWRVKNRRZ3WUC"}, :address => {}) }
12
+
13
+ let(:purchase_response) { mock(ActiveMerchant::Billing::PaypalExpressResponse, :success? => true,
14
+ :params => {"payer" => order.user.email, "payer_id" => "FWRVKNRRZ3WUC", "gross_amount" => order_total, "payment_status" => "Completed"},
15
+ :avs_result => "F",
16
+ :to_yaml => "fake") }
17
+
18
+
19
+ before do
20
+ Spree::Auth::Config.set(:registration_step => false)
21
+ controller.stub(:current_order => order, :check_authorization => true, :current_user => order.user)
22
+ order.stub(:checkout_allowed? => true, :completed? => false)
23
+ order.update!
24
+ end
25
+
26
+ it "should understand paypal routes" do
27
+ assert_routing("/orders/#{order.number}/checkout/paypal_payment", {:controller => "checkout", :action => "paypal_payment", :order_id => order.number })
28
+ assert_routing("/orders/#{order.number}/checkout/paypal_confirm", {:controller => "checkout", :action => "paypal_confirm", :order_id => order.number })
29
+ end
30
+
31
+ context "paypal_checkout" do
32
+ #feature not implemented
33
+ end
34
+
35
+ context "paypal_payment without auto_capture" do
36
+ let(:redirect_url) { "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=#{token}&useraction=commit" }
37
+
38
+ before { Spree::Config.set(:auto_capture => false) }
39
+
40
+ it "should setup an authorize transaction and redirect to sandbox" do
41
+ PaymentMethod.should_receive(:find).at_least(1).with('123').and_return(paypal_gateway)
42
+
43
+ gateway_provider.should_receive(:redirect_url_for).with(token, {:review => false}).and_return redirect_url
44
+ paypal_gateway.provider.should_receive(:setup_authorization).with(order_total, anything()).and_return(mock(:success? => true, :token => token))
45
+
46
+ get :paypal_payment, {:order_id => order.number, :payment_method_id => "123" }
47
+
48
+ response.should redirect_to "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=#{assigns[:ppx_response].token}&useraction=commit"
49
+ end
50
+
51
+ end
52
+
53
+ context "paypal_payment with auto_capture" do
54
+ let(:redirect_url) { "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=#{token}&useraction=commit" }
55
+
56
+ before { Spree::Config.set(:auto_capture => true) }
57
+
58
+ it "should setup a purchase transaction and redirect to sandbox" do
59
+ PaymentMethod.should_receive(:find).at_least(1).with("123").and_return(paypal_gateway)
60
+
61
+ gateway_provider.should_receive(:redirect_url_for).with(token, {:review => false}).and_return redirect_url
62
+ paypal_gateway.provider.should_receive(:setup_purchase).with(order_total, anything()).and_return(mock(:success? => true, :token => token))
63
+
64
+ get :paypal_payment, {:order_id => order.number, :payment_method_id => "123" }
65
+
66
+ response.should redirect_to "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=#{assigns[:ppx_response].token}&useraction=commit"
67
+ end
68
+
69
+ end
70
+
71
+ context "paypal_confirm" do
72
+ before { PaymentMethod.should_receive(:find).at_least(1).with("123").and_return(paypal_gateway) }
73
+
74
+ context "with auto_capture and no review" do
75
+ before do
76
+ Spree::Config.set(:auto_capture => true)
77
+ paypal_gateway.stub(:preferred_review => false)
78
+ end
79
+
80
+ it "should capture payment" do
81
+ paypal_gateway.provider.should_receive(:details_for).with(token).and_return(details_for_response)
82
+
83
+ paypal_gateway.provider.should_receive(:purchase).with(order_total, anything()).and_return(purchase_response)
84
+
85
+ get :paypal_confirm, {:order_id => order.number, :payment_method_id => "123", :token => token, :PayerID => "FWRVKNRRZ3WUC" }
86
+
87
+ response.should redirect_to order_url(order)
88
+
89
+ order.reload
90
+ order.state.should == "complete"
91
+ order.payments.size.should == 1
92
+ order.payment_state.should == "paid"
93
+ end
94
+ end
95
+
96
+ context "with review" do
97
+ before { paypal_gateway.stub(:preferred_review => true) }
98
+
99
+ it "should render review" do
100
+ paypal_gateway.provider.should_receive(:details_for).with(token).and_return(details_for_response)
101
+
102
+ get :paypal_confirm, {:order_id => order.number, :payment_method_id => "123", :token => token, :PayerID => "FWRVKNRRZ3WUC" }
103
+
104
+ response.should render_template("shared/paypal_express_confirm")
105
+
106
+ end
107
+ end
108
+
109
+ context "with review and shipping update" do
110
+ before do
111
+ paypal_gateway.stub(:preferred_review => true)
112
+ paypal_gateway.stub(:preferred_no_shipping => false)
113
+
114
+ details_for_response.stub(:params => details_for_response.params.merge({'first_name' => 'Dr.', 'last_name' => 'Evil'}),
115
+ :address => {'address1' => 'Apt. 187', 'address2'=> 'Some Str.', 'city' => 'Chevy Chase', 'country' => 'US', 'zip' => '20815', 'state' => 'MD' })
116
+
117
+ end
118
+
119
+ it "should update ship_address and render review" do
120
+ paypal_gateway.provider.should_receive(:details_for).with(token).and_return(details_for_response)
121
+
122
+ get :paypal_confirm, {:order_id => order.number, :payment_method_id => "123", :token => token, :PayerID => "FWRVKNRRZ3WUC" }
123
+
124
+ order.ship_address.address1.should == "Apt. 187"
125
+ response.should render_template("shared/paypal_express_confirm")
126
+ end
127
+ end
128
+
129
+ context "with un-successful repsonse" do
130
+ before { details_for_response.stub(:success? => false) }
131
+
132
+ it "should log error and redirect to payment step" do
133
+ paypal_gateway.provider.should_receive(:details_for).with(token).and_return(details_for_response)
134
+
135
+ controller.should_receive(:gateway_error).with(details_for_response)
136
+
137
+ get :paypal_confirm, {:order_id => order.number, :payment_method_id => "123", :token => token, :PayerID => "FWRVKNRRZ3WUC" }
138
+
139
+ response.should redirect_to edit_order_checkout_url(order, :state => 'payment')
140
+ end
141
+ end
142
+
143
+ end
144
+
145
+ context "paypal_finish" do
146
+ let(:paypal_account) { stub_model(PaypalAccount, :payer_id => "FWRVKNRRZ3WUC", :email => order.email ) }
147
+ let(:authorize_response) { mock(ActiveMerchant::Billing::PaypalExpressResponse, :success? => true,
148
+ :params => {"payer" => order.user.email, "payer_id" => "FWRVKNRRZ3WUC", "gross_amount" => order_total, "payment_status" => "Pending"},
149
+ :avs_result => "F",
150
+ :to_yaml => "fake") }
151
+
152
+ before do
153
+ PaymentMethod.should_receive(:find).at_least(1).with("123").and_return(paypal_gateway)
154
+ PaypalAccount.should_receive(:find_by_payer_id).with("FWRVKNRRZ3WUC").and_return(paypal_account)
155
+ end
156
+
157
+ context "with auto_capture" do
158
+ before { Spree::Config.set(:auto_capture => true) }
159
+
160
+ it "should capture payment" do
161
+
162
+ paypal_gateway.provider.should_receive(:purchase).with(order_total, anything()).and_return(purchase_response)
163
+
164
+ get :paypal_finish, {:order_id => order.number, :payment_method_id => "123", :token => token, :PayerID => "FWRVKNRRZ3WUC" }
165
+
166
+ response.should redirect_to order_url(order)
167
+
168
+ order.reload
169
+ order.update!
170
+ order.payments.size.should == 1
171
+ order.payment_state.should == "paid"
172
+ end
173
+ end
174
+
175
+ context "with auto_capture and pending(echeck) response" do
176
+ before do
177
+ Spree::Config.set(:auto_capture => true)
178
+ purchase_response.params["payment_status"] = "pending"
179
+ end
180
+
181
+ it "should authorize payment" do
182
+
183
+ paypal_gateway.provider.should_receive(:purchase).with(order_total, anything()).and_return(purchase_response)
184
+
185
+ get :paypal_finish, {:order_id => order.number, :payment_method_id => "123", :token => token, :PayerID => "FWRVKNRRZ3WUC" }
186
+
187
+ response.should redirect_to order_url(order)
188
+
189
+ order.reload
190
+ order.update!
191
+ order.payments.size.should == 1
192
+ order.payment_state.should == "balance_due"
193
+ order.payment.state.should == "pending"
194
+ end
195
+ end
196
+
197
+ context "without auto_capture" do
198
+ before { Spree::Config.set(:auto_capture => false) }
199
+
200
+ it "should authorize payment" do
201
+
202
+ paypal_gateway.provider.should_receive(:authorize).with(order_total, anything()).and_return(authorize_response)
203
+
204
+ get :paypal_finish, {:order_id => order.number, :payment_method_id => "123", :token => token, :PayerID => "FWRVKNRRZ3WUC" }
205
+
206
+ response.should redirect_to order_url(order)
207
+
208
+ order.reload
209
+ order.update!
210
+ order.payments.size.should == 1
211
+ order.payment_state.should == "balance_due"
212
+ order.payment.state.should == "pending"
213
+ end
214
+ end
215
+
216
+ context "with un-successful repsonse" do
217
+ before do
218
+ Spree::Config.set(:auto_capture => true)
219
+ purchase_response.stub(:success? => false)
220
+ end
221
+
222
+ it "should log error and redirect to payment step" do
223
+ paypal_gateway.provider.should_receive(:purchase).with(order_total, anything()).and_return(purchase_response)
224
+
225
+ controller.should_receive(:gateway_error).with(purchase_response)
226
+
227
+ get :paypal_finish, {:order_id => order.number, :payment_method_id => "123", :token => token, :PayerID => "FWRVKNRRZ3WUC" }
228
+
229
+ response.should redirect_to edit_order_checkout_url(order, :state => 'payment')
230
+
231
+ order.reload
232
+ order.update!
233
+ order.payments.size.should == 1
234
+ order.payment_state.should == "failed"
235
+ order.payment.state.should == "failed"
236
+ end
237
+ end
238
+
239
+ end
240
+
241
+ context "order_opts" do
242
+
243
+ it "should return hash containing basic order details" do
244
+ opts = controller.send(:order_opts, order, paypal_gateway.id, 'payment')
245
+
246
+ opts.class.should == Hash
247
+ opts[:money].should == order_total
248
+ opts[:subtotal].should == (order.item_total * 100).to_i
249
+ opts[:order_id].should == order.number
250
+ opts[:custom].should == order.number
251
+ opts[:handling].should == 0
252
+ opts[:shipping].should == (order.ship_total * 100).to_i
253
+
254
+ opts[:return_url].should == paypal_confirm_order_checkout_url(order, :payment_method_id => paypal_gateway.id)
255
+ opts[:cancel_return_url].should == edit_order_url(order)
256
+
257
+ opts[:items].size.should > 0
258
+ opts[:items].size.should == order.line_items.count
259
+ end
260
+
261
+ it "should include credits in returned hash" do
262
+ order_total #need here so variable is set before credit is created.
263
+ order.adjustments.create(:label => "Credit", :amount => -1)
264
+ order.update!
265
+
266
+ opts = controller.send(:order_opts, order, paypal_gateway.id, 'payment')
267
+
268
+ opts.class.should == Hash
269
+ opts[:money].should == order_total - 100
270
+ opts[:subtotal].should == ((order.item_total * 100) + (order.adjustments.select{|c| c.amount < 0}.sum(&:amount) * 100)).to_i
271
+
272
+ opts[:items].size.should == order.line_items.count + 1
273
+ end
274
+
275
+
276
+ end
277
+ end
278
+
@@ -0,0 +1,13 @@
1
+ Factory.define :ppx_address do |f|
2
+ f.firstname 'John'
3
+ f.lastname 'Doe'
4
+ f.address1 '10 Lovely Street'
5
+ f.address2 'Northwest'
6
+ f.city "Herndon"
7
+ f.state { |state| state.association(:ppx_state) }
8
+ f.zipcode '20170'
9
+ f.country { |country| country.association(:country) }
10
+ f.phone '123-456-7890'
11
+ f.state_name "maryland"
12
+ f.alternative_phone "123-456-7899"
13
+ end
@@ -0,0 +1,11 @@
1
+ Factory.define(:ppx_order) do |record|
2
+ # associations:
3
+ record.association(:user, :factory => :user)
4
+ record.association(:bill_address, :factory => :address)
5
+ record.association(:shipping_method, :factory => :shipping_method)
6
+ record.ship_address { |ship_address| Factory(:ppx_address, :city => "Chevy Chase", :zipcode => "20815") }
7
+ end
8
+
9
+ Factory.define :ppx_order_with_totals, :parent => :order do |f|
10
+ f.after_create { |order| Factory(:line_item, :order => order) }
11
+ end
@@ -0,0 +1,5 @@
1
+ Factory.define :md_state do |f|
2
+ f.name 'Maryland'
3
+ f.abbr 'MD'
4
+ f.country { |country| country.association(:country) }
5
+ end
@@ -0,0 +1,40 @@
1
+ # This file is copied to ~/spec when you run 'ruby script/generate rspec'
2
+ # from the project root directory.
3
+ ENV["RAILS_ENV"] ||= 'test'
4
+ require File.expand_path("../test_app/config/environment", __FILE__)
5
+ require 'rspec/rails'
6
+
7
+ #include spree's factories
8
+ require 'spree_core/testing_support/factories'
9
+
10
+ # include local factories
11
+ Dir["#{File.dirname(__FILE__)}/factories/**/*.rb"].each do |f|
12
+ fp = File.expand_path(f)
13
+ require fp
14
+ end
15
+
16
+ RSpec.configure do |config|
17
+ # == Mock Framework
18
+ #
19
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
20
+ #
21
+ # config.mock_with :mocha
22
+ # config.mock_with :flexmock
23
+ # config.mock_with :rr
24
+ config.mock_with :rspec
25
+
26
+ config.fixture_path = "#{::Rails.root}/spec/fixtures"
27
+
28
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
29
+ # examples within a transaction, comment the following line or assign false
30
+ # instead of true.
31
+ config.use_transactional_fixtures = true
32
+ end
33
+
34
+ Zone.class_eval do
35
+ def self.global
36
+ find_by_name("GlobalZone") || Factory(:global_zone)
37
+ end
38
+ end
39
+
40
+ @configuration ||= AppConfiguration.find_or_create_by_name("Default configuration")
@@ -0,0 +1,17 @@
1
+ Gem::Specification.new do |s|
2
+ s.platform = Gem::Platform::RUBY
3
+ s.name = 'spree_paypal_adaptive_payment'
4
+ s.version = '0.1.0'
5
+ s.summary = 'Add PayPal Adaptive Payments to Spree store'
6
+ s.homepage = 'https://github.com/jpablobr/spree_paypal_adaptive_payment'
7
+ s.author = 'Jose Pablo Barrantes'
8
+ s.email = 'xjpalobrx@gmail.com'
9
+ s.required_ruby_version = '>= 1.8.7'
10
+
11
+ s.files = `git ls-files`.split("\n")
12
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
13
+ s.require_paths = ["lib"]
14
+ s.has_rdoc = false
15
+
16
+ s.add_dependency('spree_core', '>=0.40.3')
17
+ end