nimbleshop_paypalwp 0.0.10 → 0.0.11
Sign up to get free protection for your applications and to get access to all the features.
- data/app/controllers/nimbleshop_paypalwp/paypalwps_controller.rb +11 -28
- data/app/helpers/nimbleshop_paypalwp/exposed_helper.rb +3 -0
- data/app/models/nimbleshop_paypalwp/paypalwp.rb +4 -0
- data/app/views/nimbleshop_paypalwp/paypalwps/_edit.html.erb +33 -24
- data/lib/nimbleshop_paypalwp/processor.rb +49 -30
- data/test/functional/paypalwps_controller_test.rb +67 -0
- data/test/unit/processor_test.rb +7 -10
- metadata +6 -5
- data/app/views/nimbleshop_paypalwp/paypalwps/_form.html.erb +0 -36
@@ -1,6 +1,6 @@
|
|
1
1
|
module NimbleshopPaypalwp
|
2
2
|
|
3
|
-
#
|
3
|
+
# Following line makes it possible to use this gem without nimbleshop_core
|
4
4
|
klass = defined?(::Admin::PaymentMethodsController) ? ::Admin::PaymentMethodsController : ActionController::Base
|
5
5
|
|
6
6
|
class PaypalwpsController < klass
|
@@ -13,40 +13,23 @@ module NimbleshopPaypalwp
|
|
13
13
|
processor = NimbleshopPaypalwp::Processor.new(raw_post: request.raw_post)
|
14
14
|
order = processor.order
|
15
15
|
|
16
|
-
#
|
17
|
-
unless order.purchased?
|
18
|
-
processor.order.update_attributes(payment_method: NimbleshopPaypalwp::Paypalwp.first)
|
19
|
-
processor.purchase
|
20
|
-
end
|
16
|
+
# order is already in purchased state. Seems like IPN is sending duplicate notification
|
17
|
+
processor.purchase unless order.purchased?
|
21
18
|
|
22
19
|
render nothing: true
|
23
20
|
end
|
24
21
|
|
25
22
|
def update
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
msg = @payment_method.errors.full_messages.first
|
34
|
-
error = %Q[alert("#{msg}")]
|
35
|
-
format.js { render js: error }
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
23
|
+
alert_msg = if @payment_method.update_attributes(post_params[:paypalwp])
|
24
|
+
msg = "Record has been updated"
|
25
|
+
%Q[alert("#{msg}")]
|
26
|
+
else
|
27
|
+
msg = @payment_method.errors.full_messages.first
|
28
|
+
%Q[alert("#{msg}")]
|
29
|
+
end
|
39
30
|
|
40
|
-
def destroy
|
41
31
|
respond_to do |format|
|
42
|
-
|
43
|
-
format.js {
|
44
|
-
flash[:notice] = 'Paypal record was successfully deleted'
|
45
|
-
render js: "window.location = '/admin/payment_methods'"
|
46
|
-
}
|
47
|
-
else
|
48
|
-
format.js { render js: 'Paypal record could not be deleted. Please try again later.' }
|
49
|
-
end
|
32
|
+
format.js { render js: alert_msg }
|
50
33
|
end
|
51
34
|
end
|
52
35
|
|
@@ -39,6 +39,8 @@ module NimbleshopPaypalwp
|
|
39
39
|
service.notify_url nimbleshop_paypalwp_notify_url
|
40
40
|
service.return_url nimbleshop_paypalwp_return_url(order)
|
41
41
|
service.cancel_return_url nimbleshop_paypalwp_cancel_url(order)
|
42
|
+
|
43
|
+
Rails.logger.debug "service attributes: #{service.inspect}"
|
42
44
|
end
|
43
45
|
|
44
46
|
def nimbleshop_paypalwp_crud_form
|
@@ -65,6 +67,7 @@ module NimbleshopPaypalwp
|
|
65
67
|
end
|
66
68
|
|
67
69
|
def nimbleshop_paypalwp_protocol
|
70
|
+
# TODO do not hardcode decision based on env
|
68
71
|
NimbleshopPaypalwp::Paypalwp.first.mode == 'production' ? 'https' : 'http'
|
69
72
|
end
|
70
73
|
|
@@ -1,32 +1,41 @@
|
|
1
|
-
|
1
|
+
<% payment_method = NimbleshopPaypalwp::Paypalwp.first %>
|
2
2
|
|
3
|
-
|
4
|
-
<h2>Paypal websites payment standard</h2>
|
5
|
-
<div class="edit_link">
|
6
|
-
<%= link_to 'Edit', '#', class: 'nimbleshop-payment-method-edit', id: 'nimbleshop-paypalwp-payment-method-edit' %>
|
3
|
+
<%= content_tag :div, style: 'display:none', data: { behavior: "payment-method-form-#{payment_method.permalink}" } do %>
|
7
4
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
5
|
+
<div style="width:100px;margin-left:50px;"> <%= nimbleshop_paypalwp_picture_on_admin_payment_methods %> </div>
|
6
|
+
<br />
|
7
|
+
|
8
|
+
<%= form_for payment_method, url: '/nimbleshop_paypalwp/paypalwp',
|
9
|
+
remote: true,
|
10
|
+
html: { method: 'put',
|
11
|
+
id: 'nimbleshop-paypalwp-form',
|
12
|
+
class: 'nimbleshop-payment-method-form form-horizontal'} do |f| %>
|
13
13
|
|
14
|
-
<%= nimbleshop_paypalwp_picture_on_admin_payment_methods %>
|
15
14
|
|
16
|
-
<
|
17
|
-
</div>
|
15
|
+
<fieldset>
|
18
16
|
|
19
|
-
|
20
|
-
|
17
|
+
<div class="control-group">
|
18
|
+
<%= f.label :merchant_email, nil, class: 'control-label' %>
|
19
|
+
<div class="controls">
|
20
|
+
<%= f.text_field :merchant_email, class: 'span6' %>
|
21
|
+
</div>
|
22
|
+
</div>
|
21
23
|
|
22
|
-
<
|
23
|
-
|
24
|
+
<div class="control-group">
|
25
|
+
<div class="controls">
|
26
|
+
<label class='checkbox'>
|
27
|
+
<%= f.check_box :mode, {}, 'test', 'production' %> Enable sandbox mode
|
28
|
+
</label>
|
29
|
+
</div>
|
30
|
+
</div>
|
24
31
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
32
|
+
</fieldset>
|
33
|
+
|
34
|
+
<div class="form-actions">
|
35
|
+
<%= f.submit('Submit', class: 'btn btn-primary') %>
|
36
|
+
|
37
|
+
<%= link_to 'Disable', main_app.disable_admin_payment_method_path(payment_method), class: 'disable-payment-method-link', method: :put %>
|
38
|
+
</div>
|
39
|
+
<% end %>
|
30
40
|
|
31
|
-
|
32
|
-
</script>
|
41
|
+
<% end %>
|
@@ -1,29 +1,23 @@
|
|
1
1
|
module NimbleshopPaypalwp
|
2
2
|
class Processor < Processor::Base
|
3
3
|
|
4
|
-
attr_reader :order, :payment_method
|
4
|
+
attr_reader :order, :payment_method, :notify
|
5
5
|
|
6
6
|
def initialize(options = {})
|
7
|
-
|
8
|
-
|
7
|
+
options.symbolize_keys!
|
8
|
+
options.assert_valid_keys :raw_post
|
9
|
+
raw_post = options.fetch :raw_post
|
10
|
+
|
11
|
+
@notify = ActiveMerchant::Billing::Integrations::Paypal::Notification.new raw_post
|
12
|
+
@order = Order.find_by_number! notify.invoice
|
9
13
|
@payment_method = NimbleshopPaypalwp::Paypalwp.first
|
10
14
|
end
|
11
15
|
|
12
16
|
private
|
13
17
|
|
14
|
-
def paypal_ipn(raw_post)
|
15
|
-
# ActiveMerchant::Billing::Integrations::Paypal::Notification is a subclass of
|
16
|
-
# ActiveMerchant::Billing::Integrations::Notification
|
17
|
-
#
|
18
|
-
# And ActiveMerchant::Billing::Integrations::Notification dependds on money gem
|
19
|
-
ActiveMerchant::Billing::Integrations::Paypal::Notification.new(raw_post)
|
20
|
-
end
|
21
|
-
|
22
18
|
def do_capture(options = {})
|
23
|
-
success =
|
24
|
-
|
25
|
-
|
26
|
-
if success
|
19
|
+
if success = ipn_from_paypal?
|
20
|
+
record_transaction 'captured'
|
27
21
|
order.update_attributes(purchased_at: purchased_at, payment_method: payment_method)
|
28
22
|
order.kapture
|
29
23
|
end
|
@@ -32,10 +26,8 @@ module NimbleshopPaypalwp
|
|
32
26
|
end
|
33
27
|
|
34
28
|
def do_authorize(options = {})
|
35
|
-
success =
|
36
|
-
|
37
|
-
|
38
|
-
if success
|
29
|
+
if success = ipn_from_paypal?
|
30
|
+
record_transaction 'authorized'
|
39
31
|
order.update_attributes(purchased_at: purchased_at, payment_method: payment_method)
|
40
32
|
order.authorize
|
41
33
|
end
|
@@ -47,32 +39,59 @@ module NimbleshopPaypalwp
|
|
47
39
|
end
|
48
40
|
|
49
41
|
def do_purchase(options = {})
|
50
|
-
success =
|
51
|
-
|
52
|
-
|
53
|
-
if success
|
54
|
-
order.update_attributes(purchased_at: @paypal_ipn.received_at, payment_method: payment_method)
|
42
|
+
if success = ipn_from_paypal?
|
43
|
+
record_transaction 'purchased'
|
44
|
+
order.update_attributes(purchased_at: notify.received_at, payment_method: payment_method)
|
55
45
|
order.purchase
|
56
46
|
end
|
57
47
|
|
58
48
|
success
|
59
49
|
end
|
60
50
|
|
61
|
-
|
62
51
|
def record_transaction(operation, options = {})
|
63
|
-
order.payment_transactions.create(options.merge(amount:
|
64
|
-
params: { ipn:
|
65
|
-
transaction_gid:
|
52
|
+
order.payment_transactions.create(options.merge(amount: notify.amount.cents,
|
53
|
+
params: { ipn: notify.raw },
|
54
|
+
transaction_gid: notify.transaction_id,
|
66
55
|
operation: operation))
|
56
|
+
end
|
57
|
+
|
58
|
+
def ipn_from_paypal?
|
59
|
+
# this is needed because the intergration mode was being reset in development
|
60
|
+
ActiveMerchant::Billing::Base.integration_mode = payment_method.mode.intern
|
61
|
+
|
62
|
+
result = amount_match? && notify_complete && business_email_match? && notify_acknowledge
|
63
|
+
Rails.logger.debug "ipn_from_paypal? : #{result}"
|
64
|
+
result
|
65
|
+
end
|
66
|
+
|
67
|
+
def notify_complete
|
68
|
+
result = notify.complete?
|
69
|
+
Rails.logger.debug "notify.complete? : #{result}"
|
70
|
+
result
|
71
|
+
end
|
72
|
+
|
73
|
+
def notify_acknowledge
|
74
|
+
result = Rails.env.test? ? true : notify.acknowledge
|
75
|
+
Rails.logger.debug "notify_acknowledge : #{result}"
|
76
|
+
result
|
77
|
+
end
|
78
|
+
|
79
|
+
def business_email_match?
|
80
|
+
return true if Rails.env.test?
|
67
81
|
|
82
|
+
result = notify.account == payment_method.merchant_email
|
83
|
+
Rails.logger.debug "business_email_match? : #{result}"
|
84
|
+
result
|
68
85
|
end
|
69
86
|
|
70
87
|
def amount_match?
|
71
|
-
|
88
|
+
result = notify.amount.cents == order.total_amount_in_cents
|
89
|
+
Rails.logger.debug "amount_match? : #{result}"
|
90
|
+
result
|
72
91
|
end
|
73
92
|
|
74
93
|
def purchased_at
|
75
|
-
Time.strptime(
|
94
|
+
Time.strptime(notify.params['payment_date'], "%H:%M:%S %b %d, %Y %z")
|
76
95
|
end
|
77
96
|
end
|
78
97
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class PaypalwpsControllerTest < ActionController::TestCase
|
4
|
+
|
5
|
+
setup do
|
6
|
+
@controller = NimbleshopPaypalwp::PaypalwpsController.new
|
7
|
+
NimbleshopPaypalwp::Paypalwp.create!(name: 'Paypalwp', merchant_email: 'seller_1323037155_biz@bigbinary.com', description: 'this is description')
|
8
|
+
@order = create :order_paid_using_paypalwp
|
9
|
+
end
|
10
|
+
|
11
|
+
test "should accept notification request" do
|
12
|
+
|
13
|
+
hash = { "mc_gross" => "2.99",
|
14
|
+
"invoice"=> @order.number,
|
15
|
+
"item_mpn1"=>"",
|
16
|
+
"protection_eligibility"=>"Ineligible",
|
17
|
+
"item_count_unit1"=>"0",
|
18
|
+
"item_number1"=>"",
|
19
|
+
"tax"=>"0.04",
|
20
|
+
"payer_id"=>"8NMFURHRJBP94",
|
21
|
+
"payment_date"=>"05:50:35 Sep 27, 2012 PDT",
|
22
|
+
"item_tax_rate1"=>"0",
|
23
|
+
"payment_status"=>"Completed",
|
24
|
+
"charset"=>"windows-1252",
|
25
|
+
"mc_shipping"=>"0.00",
|
26
|
+
"item_tax_rate_double1"=>"0.00",
|
27
|
+
"mc_handling"=>"10.00",
|
28
|
+
"first_name"=>"Rashmi",
|
29
|
+
"mc_fee"=>"0.68",
|
30
|
+
"notify_version"=>"3.7",
|
31
|
+
"custom"=>"4",
|
32
|
+
"payer_status"=>"unverified",
|
33
|
+
"business"=>"seller_1323037155_biz@bigbinary.com",
|
34
|
+
"num_cart_items"=>"1",
|
35
|
+
"mc_handling1"=>"0.00",
|
36
|
+
"verify_sign"=>"A52WYOWQ5f6.ZWIwRWkmVwieCw2gAWuLNstA178r02lkMvIe5mnmEib8",
|
37
|
+
"payer_email"=>"hello@bigbinary.com",
|
38
|
+
"mc_shipping1"=>"0.00",
|
39
|
+
"item_style_number1"=>"",
|
40
|
+
"tax1"=>"0.00",
|
41
|
+
"item_plu1"=>"",
|
42
|
+
"txn_id"=>"90U719813N3473230",
|
43
|
+
"payment_type"=>"instant",
|
44
|
+
"last_name"=>"Singh",
|
45
|
+
"item_name1"=>"Hard wood case for iphone",
|
46
|
+
"receiver_email"=>"neeraj@bigbinary.com",
|
47
|
+
"item_isbn1"=>"",
|
48
|
+
"payment_fee"=>"0.68",
|
49
|
+
"quantity1"=>"1",
|
50
|
+
"receiver_id"=>"DS94AKELVSP6U",
|
51
|
+
"txn_type"=>"cart",
|
52
|
+
"item_model_number1"=>"",
|
53
|
+
"mc_gross_1"=>"3.00",
|
54
|
+
"mc_currency"=>"USD",
|
55
|
+
"item_taxable1"=>"N",
|
56
|
+
"residence_country"=>"US",
|
57
|
+
"transaction_subject"=>"4",
|
58
|
+
"payment_gross"=>"13.04",
|
59
|
+
"ipn_track_id"=>"841618d367692"}
|
60
|
+
|
61
|
+
post :notify, { use_route: :nimbleshop_paypalwp }.merge(hash)
|
62
|
+
@order.reload
|
63
|
+
assert @order.purchased?, "payment status is #{@order.payment_status}"
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
data/test/unit/processor_test.rb
CHANGED
@@ -14,26 +14,23 @@ module Processor
|
|
14
14
|
@order = create(:order)
|
15
15
|
end
|
16
16
|
|
17
|
-
test "when
|
17
|
+
test "when purchase succeeds" do
|
18
18
|
processor = NimbleshopPaypalwp::Processor.new(raw_post: raw_post(@order.number, @order.total_amount))
|
19
|
-
|
20
|
-
assert_equal true, processor.authorize
|
21
|
-
end
|
19
|
+
assert_equal true, processor.purchase
|
22
20
|
|
23
21
|
@order.reload
|
24
22
|
|
25
23
|
transaction = @order.payment_transactions.last
|
26
|
-
assert_equal '
|
27
|
-
assert_equal true,
|
28
|
-
|
29
|
-
assert_equal "April 01, 2012 at 08:46 pm", @order.purchased_at.to_s(:long)
|
24
|
+
assert_equal 'purchased', transaction.operation
|
25
|
+
assert_equal true, @order.purchased?
|
26
|
+
assert_match /April 01, 2012/, @order.purchased_at.to_s(:long)
|
30
27
|
assert_equal NimbleshopPaypalwp::Paypalwp.first, @order.payment_method
|
31
28
|
assert_equal transaction.amount, @order.total_amount_in_cents
|
32
29
|
end
|
33
30
|
|
34
|
-
test "when
|
31
|
+
test "when purchase fails" do
|
35
32
|
processor = NimbleshopPaypalwp::Processor.new(raw_post: raw_post(@order.number, 10.48))
|
36
|
-
assert_equal false, processor.
|
33
|
+
assert_equal false, processor.purchase
|
37
34
|
assert_nil @order.payment_method
|
38
35
|
end
|
39
36
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nimbleshop_paypalwp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.11
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-11-12 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activemerchant
|
@@ -75,7 +75,6 @@ files:
|
|
75
75
|
- app/views/nimbleshop_paypalwp/payments/_new.html.erb
|
76
76
|
- app/views/nimbleshop_paypalwp/payments/_order_show_extra_info.html.erb
|
77
77
|
- app/views/nimbleshop_paypalwp/paypalwps/_edit.html.erb
|
78
|
-
- app/views/nimbleshop_paypalwp/paypalwps/_form.html.erb
|
79
78
|
- config/routes.rb
|
80
79
|
- lib/nimbleshop_paypalwp/active_merchant/billing/integrations/paypal/helper.rb
|
81
80
|
- lib/nimbleshop_paypalwp/engine.rb
|
@@ -84,6 +83,7 @@ files:
|
|
84
83
|
- lib/tasks/nimbleshop_paypalwp_mock_ipn_callback.rake
|
85
84
|
- lib/tasks/nimbleshop_paypalwp_tasks.rake
|
86
85
|
- README.md
|
86
|
+
- test/functional/paypalwps_controller_test.rb
|
87
87
|
- test/test_helper.rb
|
88
88
|
- test/unit/payment_method_test.rb
|
89
89
|
- test/unit/processor_test.rb
|
@@ -101,7 +101,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
101
101
|
version: '0'
|
102
102
|
segments:
|
103
103
|
- 0
|
104
|
-
hash: -
|
104
|
+
hash: -3466410436082107566
|
105
105
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
106
|
none: false
|
107
107
|
requirements:
|
@@ -110,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
110
110
|
version: '0'
|
111
111
|
segments:
|
112
112
|
- 0
|
113
|
-
hash: -
|
113
|
+
hash: -3466410436082107566
|
114
114
|
requirements: []
|
115
115
|
rubyforge_project:
|
116
116
|
rubygems_version: 1.8.24
|
@@ -118,6 +118,7 @@ signing_key:
|
|
118
118
|
specification_version: 3
|
119
119
|
summary: Paypal WPS extension for nimbleshop
|
120
120
|
test_files:
|
121
|
+
- test/functional/paypalwps_controller_test.rb
|
121
122
|
- test/test_helper.rb
|
122
123
|
- test/unit/payment_method_test.rb
|
123
124
|
- test/unit/processor_test.rb
|
@@ -1,36 +0,0 @@
|
|
1
|
-
<div class='well nimbleshop-payment-method-form-well' id='nimbleshop-paypalwp-form-well', style='display:none;'>
|
2
|
-
|
3
|
-
<%= form_for NimbleshopPaypalwp::Paypalwp.first, url: '/nimbleshop_paypalwp/paypalwp',
|
4
|
-
remote: true,
|
5
|
-
html: { method: 'put',
|
6
|
-
id: 'nimbleshop-paypalwp-form',
|
7
|
-
class: 'nimbleshop-payment-method-form form-horizontal'} do |f| %>
|
8
|
-
|
9
|
-
|
10
|
-
<fieldset>
|
11
|
-
|
12
|
-
<div class="control-group">
|
13
|
-
<%= f.label :merchant_email, nil, class: 'control-label' %>
|
14
|
-
<div class="controls">
|
15
|
-
<%= f.text_field :merchant_email, class: 'span6' %>
|
16
|
-
</div>
|
17
|
-
</div>
|
18
|
-
|
19
|
-
<div class="control-group">
|
20
|
-
<div class="controls">
|
21
|
-
<label class='checkbox'>
|
22
|
-
<%= f.check_box :mode, {}, 'test', 'production' %> Enable sandbox mode
|
23
|
-
</label>
|
24
|
-
</div>
|
25
|
-
</div>
|
26
|
-
|
27
|
-
</fieldset>
|
28
|
-
|
29
|
-
<div class="form-actions">
|
30
|
-
<%= f.submit('Submit', class: 'btn btn-primary') %>
|
31
|
-
|
32
|
-
<%= link_to t(:cancel), nimbleshop_paypalwp.paypalwp_path, class: 'cancel btn' %>
|
33
|
-
</div>
|
34
|
-
<% end %>
|
35
|
-
|
36
|
-
</div>
|