Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow cancelling orders that have been fully refunded #1355

Merged
merged 1 commit into from
Oct 4, 2017

Conversation

Sinetheta
Copy link
Contributor

@Sinetheta Sinetheta commented Jul 25, 2016

This fixes #1066 but I could use some feedback.

After an order is cancelled, all completed payments are also cancelled here. Each payment then tries to call cancel on it's payment method here, the implementation of which is left to the provider here.

I can't speak for the other gateways, but Braintree's cancel looks like this in solidus_gateway

def cancel(response_code)
  provider
  transaction = ::Braintree::Transaction.find(response_code)
  # "A transaction can be refunded if its status is settled or settling.
  # If the transaction has not yet begun settlement, it should be voided instead of refunded.
  if transaction.status == Braintree::Transaction::Status::SubmittedForSettlement
    provider.void(response_code)
  else
    provider.refund(response_code)
  end
end

The reason why it's sufficient to simply check whether a payment is "settled" or not, is because the Braintree provider docs say that

If you do not specify an amount to refund, the entire transaction amount will be refunded.

and

If you have already partially refunded a transaction, performing another refund without specifying the balance it will create a refund for the remaining non-refunded amount of the transaction.

but there's one more case, where a payment has already been fully refunded (through one or many refunds). In that case we get an error. This error is what causes the order cancellation to fail.

We could address this anywhere along the chain, but here are my thoughts.

  1. Not in the Braintree ruby SDK, I can understand how a failure to create any refund could be considered an error even if a partial refund is not.
  2. Not in solidus_gateway, because we don't currently pass the payment when calling cancel on the gateway and I'm not sure we should.

Any ideas how I might add a regression test for this? The behaviour seems specific to one (albeit an important) gateway.

@Sinetheta Sinetheta force-pushed the cancel-refunded-orders branch from 6beb77c to 8bf08e0 Compare July 25, 2016 23:36
@Sinetheta Sinetheta changed the title Allow cancelling orders that have been fully refunded RFC Allow cancelling orders that have been fully refunded Jul 26, 2016
@@ -145,6 +145,11 @@ def can_credit?
credit_allowed > 0
end

# @return [Boolean] true when this payment has been fully refunded
def fully_refunded?
refunds.sum(:amount) >= amount
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should == instead of >= be sufficient? If you refunded more then the amount paid there are some other issues going on IMHO.

Copy link
Contributor Author

@Sinetheta Sinetheta Aug 11, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough. I don't like when we try to catch problems tangentially, but in that case we would raise an error during a cancel, which would probably be useful. I'm cool with swicthing to ==.

@peterberkenbosch
Copy link
Contributor

This makes a lot of sense, curious why we do not have a payment#refunded state though.

@gmacdougall
Copy link
Member

I agree that this makes sense. I can't think of anywhere else I would prefer to deal with this.

👍

@seantaylor
Copy link

Also ran into this issue on a store. 👍 for getting this in. Seems reasonable to me.

@Sinetheta Sinetheta force-pushed the cancel-refunded-orders branch from 8bf08e0 to a295466 Compare August 11, 2016 17:25
@Senjai
Copy link
Contributor

Senjai commented Sep 26, 2016

👍 @jhawthorn any opinions?

@Sinetheta Sinetheta force-pushed the cancel-refunded-orders branch from a295466 to a8e4c36 Compare May 22, 2017 08:47
@Sinetheta Sinetheta changed the title RFC Allow cancelling orders that have been fully refunded Allow cancelling orders that have been fully refunded May 22, 2017
@jarednorman
Copy link
Member

@Sinetheta Thoughts on testing this?

@@ -146,6 +146,11 @@ def can_credit?
credit_allowed > 0
end

# @return [Boolean] true when this payment has been fully refunded
def fully_refunded?
refunds.sum(:amount) == amount
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can save a DB lookup here by using the in-memory refunds:

refunds.map(&:amount).sum == amount

Cancelling a payment can result in a refund, which will fail if the
payment has already been fully refunded.
@Sinetheta Sinetheta force-pushed the cancel-refunded-orders branch from 2c3d182 to 9928a9e Compare October 4, 2017 01:02
Copy link
Member

@gmacdougall gmacdougall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Contributor

@cbrunsdon cbrunsdon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We decided to take this as is, it might have been an improvement to do the check during cancel! instead of doing it in the after_cancel, but we agree this is an improvement as is.

@jhawthorn jhawthorn merged commit 9818f15 into solidusio:master Oct 4, 2017
@Sinetheta Sinetheta deleted the cancel-refunded-orders branch October 5, 2017 18:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Can't cancel an order with a refund
9 participants