-
-
Notifications
You must be signed in to change notification settings - Fork 724
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
Handle credit validation errors #5780
Handle credit validation errors #5780
Conversation
aba9a79
to
e619080
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice, go! 🚀
68903e7
to
899c498
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome, this is good to go.
I left some comments, the main one is about the code comment, basically I think the "chain of validations" is not related to the skip_source_validation attribute but to the invalidate_old_payments, so the comment about that would need to go there?
@luisramos0 I addressed your comments plus a commit that handles |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
perfect 👌
app/models/spree/payment.rb
Outdated
def invalidate_old_payments | ||
order.payments.with_state('checkout').where("id != ?", id).each(&:invalidate!) | ||
order.payments.with_state('checkout').where("id != ?", id).each do |payment| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can start using #not
in Rails 4 for these "where not equals" AR scopes. Not blocking, just mentioning it...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wooow! I totally forgot Rails 4.0 introduced #not!
As expected, changing from The issue is that since we now skip validations and callbacks the |
I thought this would take days but I think I managed to solve it. I also addressed your comment @Matt-Yorkley . ProTip: You need a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm it's test ready I think
Hi @sauloperez and @luisramos0, The PR introduces an error 500 on Please see: |
Got it. The migration https://github.com/openfoodfoundation/openfoodnetwork/blob/master/db/migrate/20200616162646_move_all_calculators_outside_the_spree_namespace.rb was applied in that DB but this branch's code still has the calculators within the Spree namespace. |
After that, we can TDD a second one that also handles validation errors.
This basically catches ActiveRecord::RecordInvalid caused by an invalid credit record, for instance, but also other situations we haven't forseen.
Given the importance of this code, it doesn't bring me much confidence. Apparently, this specs where using a non-existent state by mistake and this went unnoticed because the payment creation was failing silently in payment/processing.rb. This unearthed the fact that our `#ensure_correct_adjustment` needs the order to be persisted to succeed.
No reason to use a callback when custom validation methods can be defined.
The original payment may not be valid because its credit card may be expired. Stripe gives this as a valid scenario returning a success and we should do too. When creating the credit payment we end up validating all sources in a chain as follows. ``` Payment being persisted -> source payment -> original credit card. ``` The source payment was valid when created (It would not be persisted otherwise) but its source card may now be expired, and that's legit. There was also an issue with the `#invalidate_old_payments` callback. It was causing the original payment to be validated again and thus the credit payment failed to be persisted due to the original credit card being expired. Switching this callback to use `#update_column` skips validations and so we don't validate the source payment. We only care about the state there, so it should be fine.
Switching from `#invalidate` to `#update_column` skipped both validations and callbacks and thus, `#ensure_correct_adjustments` was no longer called for older payments.
8b30858
to
97f551a
Compare
I forced push to get the latest changes of #5806. This should put both FR staging's DB and the calculators' code in sync |
@filipefurtad0 it's solved now. https://staging.openfoodfrance.org/admin/enterprises/fricando-hub/edit works. |
Hey @sauloperez , I've reversed the order, and numbered the test cases: i) Place regular orders, as a consumer There is quite a lot going on here, so let's go, vaya vayita! :-) Set different enterprise fees, shipping fees, transaction fees. The shop charges GST. Placed 6 orders, with different payment methods in the shopfront. All payment methods have the same transaction fee. i) Placing 6 orders, with these payment methods:
The value of the orders should be and is the same, as checked on confirmation e-mails and under /orders. ii) Placing the same 6 orders, on the backoffice:
Issue “Backoffice orders: "Balance due" state after payments with a transaction fee #5574” was observed; Used the described workaround and obtained the same values as those obtained in shopfront orders. iii) Issue a partial credit with each supported payment gateway Removed 5 items and recalculated fees. Proceeded to Payments:
Refund appears correctly in Stripe Dashboard:
iv) Issue a void operation with each supported payment gateway:
On Stripe dashboard it can be seen, that a partially refunded order goes from this state: Into:
v) Issue a capture operation with each supported payment gateway I am not 100% sure about this operation @sauloperez . Do you mean this (below) the tick, under /orders? I thought this was only possible for cash payments...
So in summary:
I would say this is ready to go, but I'm especially grateful for feedback here. This is quite extensive and touches many corners. Moving to ready to go, but adding the feedback label. Thank you! |
Hey @filipefurtad0 thanks a lot for the testing. I think you tried to void the refund and then void the original payment of an order with a partial refund. I think it's good it failed. After you issue a partial refund, foer example, payed 100 and refunded 50, none of these two movements should be voided. I think all the user can do after this is to issue another partial refund, or collect another payment. I think what also needs to be tested here are the checkout retrial scenarios. I will have a look at #5816 and #5818 so we can continue the conversation there. So, I will merge this PR now and look at #5816 and #5818 with and without this PR to see if anything has changed 👍 |
Hey @luisramos0, Yes, the partial refund works well for both Stripe methods. The subsequent full refund fails for Stripe-SCA (test cases iv) 3 and 4) but works nicely for Stripe-Connect (see test case iv) 5). If not allowing for a full refund after a partial one is the expected behavior than all is good think, as eventually Stripe-Connect will be discontinued. I checked anyway for this difference between the two payment methods and it is not introduced by this PR and it does not seem to relate to transaction fees. |
oh, nice finding. I didnt know that would work in StripeConnect. That's basically lost functionality from StripeConnect to StripeSCA. We should create a specific issue for it and then decide what to do. The functitonality is "full refund after partial refund", and I think you mean the user presses VOID on the original payment, right? |
Hi @luisramos0 ,
Yes, that's it.
Voiding partial refunds do not work in neither Stripe-Connect or -SCA: opened issue #5830 |
Hello Filipe! Thanks for confirming that 👍 |
Thanks a lot for this in-depth testing @filipefurtad0 ! We are now in a much better position to fix these things 💪 |
What? Why?
Closes #5449
Note this is based on #5806.
I'm not particularly happy about having to come down to the
attr_accessor
trick to skip a callback but this prevents this fix from growing exponentially on LOCs and avoids the risk of making the wrong assumptions. What I like about it is thatskip_source_validation
is explicit enough to pave the way for extracting specific per use-case service objects in the future.What should we test?
We need to cover all payment scenarios:
When performing these actions as admin, the payment total should be accurate, taking into account any payment fees.
Release notes
Handle credit and other payment actions whose credit card is now expired. Stripe kept track of them and we weren't
Changelog Category: Fixed