spree-contrib / better_spree_paypal_express

A better Spree PayPal Express Extension.
http://guides.spreecommerce.org
BSD 3-Clause "New" or "Revised" License
110 stars 269 forks source link

Error When Trying to Cancel Order in Dev Mode #91

Open matchapat opened 10 years ago

matchapat commented 10 years ago

I'm receiving an error when I click the "Cancel" button on a completed order, made through a Paypal sandbox account. I've tried removing gem 'spree_gateway' and gem 'activemerchant' just in case there was a weird conflict with gem 'spree_paypal_express'.

Error:

NoMethodError in Spree::Admin::OrdersController#fire
undefined method `credit' for #<PayPal::SDK::Merchant::API:0x007ff18e7eb8c8>

Gemfile:

source 'https://rubygems.org'

gem 'dotenv-rails'

gem 'rails', '4.0.4'

gem 'pg'

gem 'puma'
gem 'puma_auto_tune'

group :development do
    gem 'capistrano'
    gem 'capistrano-rails'
    gem 'capistrano3-puma', github: "seuros/capistrano-puma"
end

# Use SCSS for stylesheets
gem 'sass-rails', '~> 4.0.0'

# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'

# Use CoffeeScript for .js.coffee assets and views
gem 'coffee-rails', '~> 4.0.0'

# Use jquery as the JavaScript library
gem 'jquery-rails'

# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
gem 'turbolinks'

# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 1.2'

# gem 'unf'
gem 'asset_sync'

gem 'spree', github: 'spree/spree', branch: '2-1-stable'
gem 'spree_auth_devise', github: 'spree/spree_auth_devise', branch: '2-1-stable'
gem 'spree_gateway', :git => 'https://github.com/spree/spree_gateway.git', branch: '2-1-stable'
gem 'activemerchant'
# gem 'spree_tax_cloud', github: 'matchapat/spree_tax_cloud'
gem 'spree_paypal_express', :github => "radar/better_spree_paypal_express", :branch => "2-1-stable"
gem 'spree_bootstrap_frontend', github: '200Creative/spree_bootstrap_frontend', branch: '2-1-stable'
gem 'spree_active_shipping', :git => "git://github.com/spree/spree_active_shipping", :branch => '2-1-stable'

Trace:

/Users/Patrick/.rvm/gems/ruby-2.0.0-p247/bundler/gems/spree-c1ae67dd785a/core/app/models/spree/gateway.rb:3:in `credit'
/Users/Patrick/.rvm/gems/ruby-2.0.0-p247/bundler/gems/spree-c1ae67dd785a/core/app/models/spree/payment/processing.rb:91:in `block in credit!'
/Users/Patrick/.rvm/gems/ruby-2.0.0-p247/bundler/gems/spree-c1ae67dd785a/core/app/models/spree/payment/processing.rb:179:in `protect_from_connection_error'
/Users/Patrick/.rvm/gems/ruby-2.0.0-p247/bundler/gems/spree-c1ae67dd785a/core/app/models/spree/payment/processing.rb:81:in `credit!'
/Users/Patrick/.rvm/gems/ruby-2.0.0-p247/bundler/gems/spree-c1ae67dd785a/core/app/models/spree/order.rb:579:in `block in after_cancel'
activerecord (4.0.4) lib/active_record/relation/delegation.rb:13:in `each'
activerecord (4.0.4) lib/active_record/relation/delegation.rb:13:in `each'
/Users/Patrick/.rvm/gems/ruby-2.0.0-p247/bundler/gems/spree-c1ae67dd785a/core/app/models/spree/order.rb:579:in `after_cancel'
state_machine (1.2.0) lib/state_machine/eval_helpers.rb:58:in `evaluate_method'
state_machine (1.2.0) lib/state_machine/callback.rb:191:in `block in run_methods'
state_machine (1.2.0) lib/state_machine/callback.rb:190:in `each'
state_machine (1.2.0) lib/state_machine/callback.rb:190:in `run_methods'
state_machine (1.2.0) lib/state_machine/callback.rb:159:in `call'
state_machine (1.2.0) lib/state_machine/transition.rb:450:in `block (2 levels) in after'
state_machine (1.2.0) lib/state_machine/transition.rb:450:in `each'
state_machine (1.2.0) lib/state_machine/transition.rb:450:in `block in after'
state_machine (1.2.0) lib/state_machine/transition.rb:448:in `catch'
state_machine (1.2.0) lib/state_machine/transition.rb:448:in `after'
state_machine (1.2.0) lib/state_machine/transition.rb:251:in `run_callbacks'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:127:in `run_callbacks'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:212:in `run_callbacks'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:63:in `block (2 levels) in perform'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:63:in `catch'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:63:in `block in perform'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:186:in `within_transaction'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:62:in `perform'
state_machine (1.2.0) lib/state_machine/integrations/active_record.rb:502:in `block in around_save'
state_machine (1.2.0) lib/state_machine/integrations/active_record.rb:530:in `block in transaction'
activerecord (4.0.4) lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `block in transaction'
activerecord (4.0.4) lib/active_record/connection_adapters/abstract/database_statements.rb:221:in `within_new_transaction'
activerecord (4.0.4) lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `transaction'
activerecord (4.0.4) lib/active_record/transactions.rb:209:in `transaction'
state_machine (1.2.0) lib/state_machine/integrations/active_record.rb:529:in `transaction'
state_machine (1.2.0) lib/state_machine/integrations/active_record.rb:501:in `around_save'
state_machine (1.2.0) lib/state_machine/integrations/active_record.rb:483:in `save'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:154:in `block (2 levels) in run_actions'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:154:in `each'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:154:in `block in run_actions'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:170:in `catch_exceptions'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:148:in `run_actions'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:60:in `perform'
state_machine (1.2.0) lib/state_machine/transition.rb:219:in `perform'
state_machine (1.2.0) lib/state_machine/event.rb:172:in `fire'
state_machine (1.2.0) lib/state_machine/event.rb:247:in `block in add_actions'
state_machine (1.2.0) lib/state_machine/machine.rb:765:in `call'
state_machine (1.2.0) lib/state_machine/machine.rb:765:in `block (2 levels) in define_helper'
/Users/Patrick/.rvm/gems/ruby-2.0.0-p247/bundler/gems/spree-c1ae67dd785a/backend/app/controllers/spree/admin/orders_controller.rb:82:in `fire'
actionpack (4.0.4) lib/action_controller/metal/implicit_render.rb:4:in `send_action'
actionpack (4.0.4) lib/abstract_controller/base.rb:189:in `process_action'
actionpack (4.0.4) lib/action_controller/metal/rendering.rb:10:in `process_action'
actionpack (4.0.4) lib/abstract_controller/callbacks.rb:18:in `block in process_action'
activesupport (4.0.4) lib/active_support/callbacks.rb:483:in `_run__3626656587054556626__process_action__callbacks'
activesupport (4.0.4) lib/active_support/callbacks.rb:80:in `run_callbacks'
actionpack (4.0.4) lib/abstract_controller/callbacks.rb:17:in `process_action'
actionpack (4.0.4) lib/action_controller/metal/rescue.rb:29:in `process_action'
actionpack (4.0.4) lib/action_controller/metal/instrumentation.rb:31:in `block in process_action'
activesupport (4.0.4) lib/active_support/notifications.rb:159:in `block in instrument'
activesupport (4.0.4) lib/active_support/notifications/instrumenter.rb:20:in `instrument'
activesupport (4.0.4) lib/active_support/notifications.rb:159:in `instrument'
actionpack (4.0.4) lib/action_controller/metal/instrumentation.rb:30:in `process_action'
actionpack (4.0.4) lib/action_controller/metal/params_wrapper.rb:250:in `process_action'
activerecord (4.0.4) lib/active_record/railties/controller_runtime.rb:18:in `process_action'
actionpack (4.0.4) lib/abstract_controller/base.rb:136:in `process'
actionpack (4.0.4) lib/abstract_controller/rendering.rb:44:in `process'
actionpack (4.0.4) lib/action_controller/metal.rb:195:in `dispatch'
actionpack (4.0.4) lib/action_controller/metal/rack_delegation.rb:13:in `dispatch'
actionpack (4.0.4) lib/action_controller/metal.rb:231:in `block in action'
actionpack (4.0.4) lib/action_dispatch/routing/route_set.rb:80:in `call'
actionpack (4.0.4) lib/action_dispatch/routing/route_set.rb:80:in `dispatch'
actionpack (4.0.4) lib/action_dispatch/routing/route_set.rb:48:in `call'
actionpack (4.0.4) lib/action_dispatch/journey/router.rb:71:in `block in call'
actionpack (4.0.4) lib/action_dispatch/journey/router.rb:59:in `each'
actionpack (4.0.4) lib/action_dispatch/journey/router.rb:59:in `call'
actionpack (4.0.4) lib/action_dispatch/routing/route_set.rb:674:in `call'
railties (4.0.4) lib/rails/engine.rb:511:in `call'
railties (4.0.4) lib/rails/railtie/configurable.rb:30:in `method_missing'
actionpack (4.0.4) lib/action_dispatch/journey/router.rb:71:in `block in call'
actionpack (4.0.4) lib/action_dispatch/journey/router.rb:59:in `each'
actionpack (4.0.4) lib/action_dispatch/journey/router.rb:59:in `call'
actionpack (4.0.4) lib/action_dispatch/routing/route_set.rb:674:in `call'
warden (1.2.3) lib/warden/manager.rb:35:in `block in call'
warden (1.2.3) lib/warden/manager.rb:34:in `catch'
warden (1.2.3) lib/warden/manager.rb:34:in `call'
rack (1.5.2) lib/rack/etag.rb:23:in `call'
rack (1.5.2) lib/rack/conditionalget.rb:35:in `call'
rack (1.5.2) lib/rack/head.rb:11:in `call'
actionpack (4.0.4) lib/action_dispatch/middleware/params_parser.rb:27:in `call'
actionpack (4.0.4) lib/action_dispatch/middleware/flash.rb:241:in `call'
rack (1.5.2) lib/rack/session/abstract/id.rb:225:in `context'
rack (1.5.2) lib/rack/session/abstract/id.rb:220:in `call'
actionpack (4.0.4) lib/action_dispatch/middleware/cookies.rb:486:in `call'
activerecord (4.0.4) lib/active_record/query_cache.rb:36:in `call'
activerecord (4.0.4) lib/active_record/connection_adapters/abstract/connection_pool.rb:626:in `call'
activerecord (4.0.4) lib/active_record/migration.rb:373:in `call'
actionpack (4.0.4) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
activesupport (4.0.4) lib/active_support/callbacks.rb:373:in `_run__1807244111940971906__call__callbacks'
activesupport (4.0.4) lib/active_support/callbacks.rb:80:in `run_callbacks'
actionpack (4.0.4) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
actionpack (4.0.4) lib/action_dispatch/middleware/reloader.rb:64:in `call'
actionpack (4.0.4) lib/action_dispatch/middleware/remote_ip.rb:76:in `call'
actionpack (4.0.4) lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call'
actionpack (4.0.4) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
railties (4.0.4) lib/rails/rack/logger.rb:38:in `call_app'
railties (4.0.4) lib/rails/rack/logger.rb:20:in `block in call'
activesupport (4.0.4) lib/active_support/tagged_logging.rb:68:in `block in tagged'
activesupport (4.0.4) lib/active_support/tagged_logging.rb:26:in `tagged'
activesupport (4.0.4) lib/active_support/tagged_logging.rb:68:in `tagged'
railties (4.0.4) lib/rails/rack/logger.rb:20:in `call'
actionpack (4.0.4) lib/action_dispatch/middleware/request_id.rb:21:in `call'
rack (1.5.2) lib/rack/methodoverride.rb:21:in `call'
rack (1.5.2) lib/rack/runtime.rb:17:in `call'
activesupport (4.0.4) lib/active_support/cache/strategy/local_cache.rb:83:in `call'
rack (1.5.2) lib/rack/lock.rb:17:in `call'
actionpack (4.0.4) lib/action_dispatch/middleware/static.rb:64:in `call'
rack (1.5.2) lib/rack/sendfile.rb:112:in `call'
railties (4.0.4) lib/rails/engine.rb:511:in `call'
railties (4.0.4) lib/rails/application.rb:97:in `call'
rack (1.5.2) lib/rack/content_length.rb:14:in `call'
puma (2.8.2) lib/puma/server.rb:490:in `handle_request'
puma (2.8.2) lib/puma/server.rb:361:in `process_client'
puma (2.8.2) lib/puma/server.rb:254:in `block in run'
puma (2.8.2) lib/puma/thread_pool.rb:92:in `call'
puma (2.8.2) lib/puma/thread_pool.rb:92:in `block in spawn_thread'
adlersantos commented 10 years ago

Getting the same error as well. The issue is in Spree::Payment::Processing#credit! method:

if payment_method.payment_profiles_supported?
  response = payment_method.credit(credit_cents, source, response_code, gateway_options)
else
  response = payment_method.credit(credit_cents, response_code, gateway_options)
end

From here on I'm confused on how to add a customized credit method to Paypal::SDK::Merchant::API (see https://github.com/paypal/merchant-sdk-ruby/blob/master/lib/paypal-sdk/merchant/api.rb)

radar commented 10 years ago

There's already a method on the gateway called refund which should do this.

We should probably alias the credit method to refund for this gateway, at a guess. I am not certain if that would absolutely fix the problem, but it's worth investigating.

jonmast commented 9 years ago

It appears this issue was never fixed. Due to updates in spree it now raises a NotImplementedError for cancel. I couldn't find where the refund method is actually used. Could we just rework it into a cancel method?

DriesS commented 9 years ago

:+1:

jungbunzlav commented 9 years ago

We would appreciate a fix for this issue because canceling orders paid via PayPal is impossible like this :-(

philbattos commented 9 years ago

:+1:

imme5150 commented 9 years ago

+1

The site I'm running into this issue w/ is pretty low volume and PayPal is our only PaymentMethod, so I just modified the controller to display an error telling the user to cancel the payment manually in PayPal and added an empty credit method on Spree::Gateway::PayPalExpress

Part of the problem is that PayPalExpress stores the transaction ID in the payment.source and the response code is nil on the payment. I can fix this, but don't have the time right now unless someone wanted to hire me for an hour or 2.

My hack: paypal_express_hack.rb

Spree::Gateway::PayPalExpress.class_eval do
  def credit(credit_cents, response_code, gateway_options)
    # TODO: this should use the `refund` method, but it needs some work.
    # Doing nothing for now to prevent an error and allow orders to be cancelled.
    OpenStruct.new(success?:true,warning:'PayPal credit method not implemented, make sure payments are cancelled manually')
  end
end

orders_controller_decorator.rb

Spree::Admin::OrdersController.class_eval do
  def cancel
    @order.cancel!
    flash[:error] = 'Order cancelled - You must cancel the payment in PayPal manually!'
    redirect_to :back
  end
end
vcavallo commented 8 years ago

As it appears this still hasn't been fixed I'm taking a stab at my own implementation. I'll update if it works. if seeing this post revitalized reminds anyone of a proper fix for this that they've seen in the interim, please post it here.

rsmithlal commented 8 years ago

Thanks @imme5150, your solution was exactly what I needed to address my use case!