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.
@@ -1,6 +1,6 @@
1
1
  module NimbleshopPaypalwp
2
2
 
3
- # this line makes it possible to use this gem without nimbleshop_core
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
- # Since IPN can send notification multiple times check if the order has already been set to purchased status
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
- respond_to do |format|
27
- if @payment_method.update_attributes(post_params[:paypalwp])
28
- format.js {
29
- flash[:notice] = 'Paypal record was successfully updated'
30
- render js: "window.location = '/admin/payment_methods'"
31
- }
32
- else
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
- if @payment_method.destroy
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
 
@@ -9,6 +9,10 @@ module NimbleshopPaypalwp
9
9
 
10
10
  before_validation :strip_attributes
11
11
 
12
+ def test_mode?
13
+ self.mode == 'test'
14
+ end
15
+
12
16
  private
13
17
 
14
18
  def set_mode
@@ -1,32 +1,41 @@
1
- <div class='payment-method-engine-well'>
1
+ <% payment_method = NimbleshopPaypalwp::Paypalwp.first %>
2
2
 
3
- <div>
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
- <%= link_to nimbleshop_paypalwp.paypalwp_path, class: 'nimbleshop-payment-method-delete',
9
- confirm: 'Do you really want to delete Paypal payment method', method: :delete, remote: true do %>
10
- <i class='icon-remove icon-white'></i>
11
- <% end %>
12
- </div>
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
- <div class='clear'></div>
17
- </div>
15
+ <fieldset>
18
16
 
19
- <%= render partial: '/nimbleshop_paypalwp/paypalwps/form' %>
20
- </div>
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
- <script>
23
- $(function(){
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
- $('#nimbleshop-paypalwp-payment-method-edit').toggle(function(){
26
- $('#nimbleshop-paypalwp-form-well').show();
27
- }, function(){
28
- $('#nimbleshop-paypalwp-form-well').hide();
29
- });
32
+ </fieldset>
33
+
34
+ <div class="form-actions">
35
+ <%= f.submit('Submit', class: 'btn btn-primary') %>
36
+ &nbsp;
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
- @paypal_ipn = paypal_ipn(options[:raw_post])
8
- @order = Order.find_by_number!(@paypal_ipn.invoice)
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 = amount_match?
24
- record_transaction('captured', success: success)
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 = amount_match?
36
- record_transaction('authorized', success: success)
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 = amount_match?
51
- record_transaction('purchased', success: success)
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: @paypal_ipn.amount.cents,
64
- params: { ipn: @paypal_ipn.raw },
65
- transaction_gid: @paypal_ipn.transaction_id,
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
- @paypal_ipn.amount.cents == order.total_amount_in_cents
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(@paypal_ipn.params['payment_date'], "%H:%M:%S %b %d, %Y %z")
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
+
@@ -14,26 +14,23 @@ module Processor
14
14
  @order = create(:order)
15
15
  end
16
16
 
17
- test "when authorization succeeds" do
17
+ test "when purchase succeeds" do
18
18
  processor = NimbleshopPaypalwp::Processor.new(raw_post: raw_post(@order.number, @order.total_amount))
19
- playcasette('paypal/authorize-success') do
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 'authorized', transaction.operation
27
- assert_equal true, transaction.success
28
- assert_equal true, @order.authorized?
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 authorization fails" do
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.authorize
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.10
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-08-23 00:00:00.000000000 Z
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: -4510410604428150121
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: -4510410604428150121
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
- &nbsp;
32
- <%= link_to t(:cancel), nimbleshop_paypalwp.paypalwp_path, class: 'cancel btn' %>
33
- </div>
34
- <% end %>
35
-
36
- </div>