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

Payment processing state does not block double submission #4499

Closed
wants to merge 3 commits into
from

Conversation

Projects
None yet
6 participants
@shioyama
Contributor

shioyama commented Mar 27, 2014

We've been experiencing issues where two requests complete an order in rapid succession resulting in two purchase requests being sent to the gateway. This results in a success followed by a failure (double submission) which overwrites the payment state to failed, causing problems down the line.

At first I thought this was something specific to do with the payment gateway or our spree customizations, but this PR confirms that the "processing" state which should prevent this is not working, because it is set within a transaction. AFAICT this would affect any store using Spree. Although here I'm just testing that ActiveRecord::Base.connection.open_transactions is zero, I've actually tested parallel requests and confirmed that the "processing" state is not being persisted to the db at any time.

Can someone confirm that this is the case? If so I can try to push up a fix. If I'm misunderstanding something, then some clarification would be great (I'm fairly new to Spree).

Thanks!

@shioyama shioyama changed the title from Add failing test showing payment processing is set in a transaction. to Payment processing state does not block double submission Mar 27, 2014

Show outdated Hide outdated core/spec/requests/admin/orders/payments_spec.rb
@@ -99,5 +99,21 @@
end
end
describe "payment processing state" do

This comment has been minimized.

@radar

radar Mar 27, 2014

Member

@shioyama I think this test should be within core/spec/models. It's not doing any request-y stuff, so why would it need to be in spec/requests?

@radar

radar Mar 27, 2014

Member

@shioyama I think this test should be within core/spec/models. It's not doing any request-y stuff, so why would it need to be in spec/requests?

This comment has been minimized.

@shioyama

shioyama Mar 27, 2014

Contributor

See below, the fact that it is happening as a result on an order state transition is exactly why it doesn't work as expected.

@shioyama

shioyama Mar 27, 2014

Contributor

See below, the fact that it is happening as a result on an order state transition is exactly why it doesn't work as expected.

This comment has been minimized.

@shioyama

shioyama Mar 27, 2014

Contributor

But yes, I can move this to core/spec/models, you're right it's not doing anything request-y. First I'd just like to confirm that this is indeed the problem.

@shioyama

shioyama Mar 27, 2014

Contributor

But yes, I can move this to core/spec/models, you're right it's not doing anything request-y. First I'd just like to confirm that this is indeed the problem.

This comment has been minimized.

@shioyama

shioyama Mar 27, 2014

Contributor

Ok, moved this to core/spec/models/order/checkout_spec.rb. Not really sure that's the right place, but there didn't seem to be anywhere really appropriate. The existing payment specs are not testing this scenario.

@shioyama

shioyama Mar 27, 2014

Contributor

Ok, moved this to core/spec/models/order/checkout_spec.rb. Not really sure that's the right place, but there didn't seem to be anywhere really appropriate. The existing payment specs are not testing this scenario.

Show outdated Hide outdated core/spec/requests/admin/orders/payments_spec.rb
ActiveRecord::Base.connection.open_transactions.should == 0
end
order.next!

This comment has been minimized.

@radar

radar Mar 27, 2014

Member

order.next! does quite a lot. I think we could distill this test down to just work with a Payment object.

@radar

radar Mar 27, 2014

Member

order.next! does quite a lot. I think we could distill this test down to just work with a Payment object.

This comment has been minimized.

@shioyama

shioyama Mar 27, 2014

Contributor

But that's just the point. If you test on the Payment object alone, you don't see the problem. It happens precisely because the order makes a transition to the complete state, runs save as the action on that transition, then processes the payment inside the save (which is a transaction).

@shioyama

shioyama Mar 27, 2014

Contributor

But that's just the point. If you test on the Payment object alone, you don't see the problem. It happens precisely because the order makes a transition to the complete state, runs save as the action on that transition, then processes the payment inside the save (which is a transaction).

This comment has been minimized.

@shioyama

shioyama Mar 27, 2014

Contributor

And actually it's wrapped in a second transaction because the Spree::Order state machine has use_transactions set to true.

@shioyama

shioyama Mar 27, 2014

Contributor

And actually it's wrapped in a second transaction because the Spree::Order state machine has use_transactions set to true.

@@ -33,7 +33,7 @@
config.use_transactional_fixtures = false
config.before(:each) do
if example.metadata[:js]
if example.metadata[:js] || example.metadata[:truncate]

This comment has been minimized.

@radar

radar Mar 27, 2014

Member

I don't understand why this modification was made.

@radar

radar Mar 27, 2014

Member

I don't understand why this modification was made.

This comment has been minimized.

@shioyama

shioyama Mar 27, 2014

Contributor

Because otherwise the whole test itself would be run inside a transaction.

@shioyama

shioyama Mar 27, 2014

Contributor

Because otherwise the whole test itself would be run inside a transaction.

This comment has been minimized.

@Senjai

Senjai Apr 4, 2014

Contributor

Isn't that fine when we're not talking about feature specs with other processes expecting data to be in certain places?

@Senjai

Senjai Apr 4, 2014

Contributor

Isn't that fine when we're not talking about feature specs with other processes expecting data to be in certain places?

This comment has been minimized.

@huoxito

huoxito Apr 4, 2014

Member

not sure what you mean there @Senjai, I understand the modification above is necessary to actually persist the payment state on the checkout_spec.

@huoxito

huoxito Apr 4, 2014

Member

not sure what you mean there @Senjai, I understand the modification above is necessary to actually persist the payment state on the checkout_spec.

This comment has been minimized.

@shioyama

shioyama Apr 4, 2014

Contributor

@Senjai look at #4542 for background. I needed to test that something was happening outside a transaction, but the test was not a feature/request spec, so using :js => true did not seem appropriate. This was the easiest way to do it. On master in bf0aca0 I did it inline in the spec itself.

@shioyama

shioyama Apr 4, 2014

Contributor

@Senjai look at #4542 for background. I needed to test that something was happening outside a transaction, but the test was not a feature/request spec, so using :js => true did not seem appropriate. This was the easiest way to do it. On master in bf0aca0 I did it inline in the spec itself.

@shioyama

This comment has been minimized.

Show comment
Hide comment
@shioyama

shioyama Mar 28, 2014

Contributor

@radar I added a commit which fixes this problem by turning off transactions around Spree::Order state transitions. All tests pass, but I'm not sure this is safe.

In any case we need a solution and this seems important, so any advice would be much appreciated.

Contributor

shioyama commented Mar 28, 2014

@radar I added a commit which fixes this problem by turning off transactions around Spree::Order state transitions. All tests pass, but I'm not sure this is safe.

In any case we need a solution and this seems important, so any advice would be much appreciated.

@huoxito

This comment has been minimized.

Show comment
Hide comment
@huoxito

huoxito Mar 30, 2014

Member

👍 This makes a lot of sense to me. We should apply to the other branches too. Thanks a lot @shioyama

Member

huoxito commented Mar 30, 2014

👍 This makes a lot of sense to me. We should apply to the other branches too. Thanks a lot @shioyama

@shioyama

This comment has been minimized.

Show comment
Hide comment
@shioyama

shioyama Mar 31, 2014

Contributor

@huoxito Great, good to hear that. I'd be happy to make PRs for other branches, if these changes look okay.

Just one thing, I see that the default ActiveRecord integration in state machine runs transitions around validations. This PR would turn that off unless we explicitly add it back (like I did to get it to run transition callbacks around the action itself.)

No tests are failing and this doesn't look like an issue, but I just wanted to check.

Contributor

shioyama commented Mar 31, 2014

@huoxito Great, good to hear that. I'd be happy to make PRs for other branches, if these changes look okay.

Just one thing, I see that the default ActiveRecord integration in state machine runs transitions around validations. This PR would turn that off unless we explicitly add it back (like I did to get it to run transition callbacks around the action itself.)

No tests are failing and this doesn't look like an issue, but I just wanted to check.

@huoxito

This comment has been minimized.

Show comment
Hide comment
@huoxito

huoxito Apr 1, 2014

Member

yes @shioyama please submit another PR to master including a changelog entry :)

Just one thing, I see that the default ActiveRecord integration in state machine runs transitions around validations.

Sorry I'm not sure I understand that bit. Are you saying that your patch turn off validations when doing transitions? I think I misunderstood that, validations stills seem to happen with your patch applied.

thanks for looking into state_machine internals to figure this @shioyama, appreciate it

Member

huoxito commented Apr 1, 2014

yes @shioyama please submit another PR to master including a changelog entry :)

Just one thing, I see that the default ActiveRecord integration in state machine runs transitions around validations.

Sorry I'm not sure I understand that bit. Are you saying that your patch turn off validations when doing transitions? I think I misunderstood that, validations stills seem to happen with your patch applied.

thanks for looking into state_machine internals to figure this @shioyama, appreciate it

@shioyama

This comment has been minimized.

Show comment
Hide comment
@shioyama

shioyama Apr 1, 2014

Contributor

@huoxito great, will submit that asap.

Sorry I'm not sure I understand that bit. Are you saying that your patch turn off validations when doing transitions? I think I misunderstood that, validations stills seem to happen with your patch applied.

No, the other way around: the patch turns off transitions around validations. By default ActiveRecord models with state machines insert into model actions (save by default) and validations a call to StateMachine::Transition#perform, which executes any outstanding transitions as callbacks on the model:

# Runs state events around the object's validation process
def around_validation(object)
  object.class.state_machines.transitions(object, action, :after => false).perform { yield }
end

So if you save the model, it will automatically run any transitions as an around_save callback, and likewise if you call @model.valid? it will also run any transitions as an around_validation callback and then check if the model is valid. The former is important (one test failed without putting it back) but the latter seems to me unnecessary.

Incidentally, although I added back the action callback, it now fires around the action (save) rather than as an ActiveRecord callback on the model, which would run within the action (and therefore be wrapped in a transaction, which we don't want). As a result, if a transition succeeds but the action then fails, the transition will remain persisted as-is, whereas previously it would have been rolled back (except in case of a payment processing failure, see #1767).

Took me a while to get my head around this... but I believe this is basically how it works.

Contributor

shioyama commented Apr 1, 2014

@huoxito great, will submit that asap.

Sorry I'm not sure I understand that bit. Are you saying that your patch turn off validations when doing transitions? I think I misunderstood that, validations stills seem to happen with your patch applied.

No, the other way around: the patch turns off transitions around validations. By default ActiveRecord models with state machines insert into model actions (save by default) and validations a call to StateMachine::Transition#perform, which executes any outstanding transitions as callbacks on the model:

# Runs state events around the object's validation process
def around_validation(object)
  object.class.state_machines.transitions(object, action, :after => false).perform { yield }
end

So if you save the model, it will automatically run any transitions as an around_save callback, and likewise if you call @model.valid? it will also run any transitions as an around_validation callback and then check if the model is valid. The former is important (one test failed without putting it back) but the latter seems to me unnecessary.

Incidentally, although I added back the action callback, it now fires around the action (save) rather than as an ActiveRecord callback on the model, which would run within the action (and therefore be wrapped in a transaction, which we don't want). As a result, if a transition succeeds but the action then fails, the transition will remain persisted as-is, whereas previously it would have been rolled back (except in case of a payment processing failure, see #1767).

Took me a while to get my head around this... but I believe this is basically how it works.

@shioyama

This comment has been minimized.

Show comment
Hide comment
@shioyama

shioyama Apr 1, 2014

Contributor

The last part of my comment above is not quite right. The action callbacks are fired around the action by default, and only as model callbacks (within the action) for save. Using save_state as the action and aliasing that to save (see these inline notes) prevents the callbacks from being run as model callbacks, so they wrap around the action (so not wrapped in a transaction).

So, by default a save action looks like this:

# save (transaction)
  # before transition callback
  # save code
  # after transition callback
# end

By renaming the action and turning transactions off, this becomes:

# before transition callback
# save (transaction)
  # save code
# end
# after transition callback

But now if we save the model, transitions are not fired, only the other way around (i.e. making a transition between states saves the model). This test was failing because it seems to (implicitly?) rely on this behavior, so I added it back. The result is this:

# before transition callback
# save (transaction)
  # before transition callback
  # save code
  # after transition callback
# end
# after transition callback

The transitions get called outside of the transaction and inside the transaction. In the case of the failing test, something between the first (outer) and second (inner) before transition callback changes so that in the latter case, it actually transitions to complete, and the test passes. In other cases these added callbacks do not change anything.

... that's probably more than you wanted to know, but I wanted to get this down for the record, in case anybody comes back to this.

Contributor

shioyama commented Apr 1, 2014

The last part of my comment above is not quite right. The action callbacks are fired around the action by default, and only as model callbacks (within the action) for save. Using save_state as the action and aliasing that to save (see these inline notes) prevents the callbacks from being run as model callbacks, so they wrap around the action (so not wrapped in a transaction).

So, by default a save action looks like this:

# save (transaction)
  # before transition callback
  # save code
  # after transition callback
# end

By renaming the action and turning transactions off, this becomes:

# before transition callback
# save (transaction)
  # save code
# end
# after transition callback

But now if we save the model, transitions are not fired, only the other way around (i.e. making a transition between states saves the model). This test was failing because it seems to (implicitly?) rely on this behavior, so I added it back. The result is this:

# before transition callback
# save (transaction)
  # before transition callback
  # save code
  # after transition callback
# end
# after transition callback

The transitions get called outside of the transaction and inside the transaction. In the case of the failing test, something between the first (outer) and second (inner) before transition callback changes so that in the latter case, it actually transitions to complete, and the test passes. In other cases these added callbacks do not change anything.

... that's probably more than you wanted to know, but I wanted to get this down for the record, in case anybody comes back to this.

@huoxito

This comment has been minimized.

Show comment
Hide comment
@huoxito

huoxito Apr 1, 2014

Member

Thanks for the thorough explanation, great to have it documented here.

Took a while into this now but I still don't understand why that spec is failing. Maybe the set up is just wrong. Everything else seems to work perfectly for me without the around_save :perform_transitions. Definitely missing something here. Also are you saying that a before_transition transition callback, for example, would fire twice now? Doesn't seem to be happening for me.

I think ideally we should only turn off transactions when processing payments since I don't remember anywhere else on the order state_machine that relies on persisted data. But I'm not sure how to do that, if it's possible right now.

Anyway we still go with your patch just wanted to understand it better before merging. Maybe this also brings other benefits we can't see right now. Again appreciate all your investigation here @shioyama

Member

huoxito commented Apr 1, 2014

Thanks for the thorough explanation, great to have it documented here.

Took a while into this now but I still don't understand why that spec is failing. Maybe the set up is just wrong. Everything else seems to work perfectly for me without the around_save :perform_transitions. Definitely missing something here. Also are you saying that a before_transition transition callback, for example, would fire twice now? Doesn't seem to be happening for me.

I think ideally we should only turn off transactions when processing payments since I don't remember anywhere else on the order state_machine that relies on persisted data. But I'm not sure how to do that, if it's possible right now.

Anyway we still go with your patch just wanted to understand it better before merging. Maybe this also brings other benefits we can't see right now. Again appreciate all your investigation here @shioyama

@shioyama

This comment has been minimized.

Show comment
Hide comment
@shioyama

shioyama Apr 4, 2014

Contributor

@huoxito My conclusion after going deep into a stack trace is that that spec is just screwed up. Something is happening with email validation -- it shouldn't even pass because the email is not set, so the model can't be saved, but somehow it previously was (being saved) regardless of validation failing. With the change this no longer happens, but that's a good thing I think.

Can I just mark it as pending with a note that it is not actually testing what it claims to be testing? The same thing happens on master.

Contributor

shioyama commented Apr 4, 2014

@huoxito My conclusion after going deep into a stack trace is that that spec is just screwed up. Something is happening with email validation -- it shouldn't even pass because the email is not set, so the model can't be saved, but somehow it previously was (being saved) regardless of validation failing. With the change this no longer happens, but that's a good thing I think.

Can I just mark it as pending with a note that it is not actually testing what it claims to be testing? The same thing happens on master.

@shioyama

This comment has been minimized.

Show comment
Hide comment
@shioyama

shioyama Apr 4, 2014

Contributor

And: I will take out that around_save callback, which was only needed to make that test pass.

Contributor

shioyama commented Apr 4, 2014

And: I will take out that around_save callback, which was only needed to make that test pass.

@shioyama

This comment has been minimized.

Show comment
Hide comment
@shioyama

shioyama Apr 4, 2014

Contributor

Don't pull this yet, going to clean it up first.

Contributor

shioyama commented Apr 4, 2014

Don't pull this yet, going to clean it up first.

shioyama added some commits Mar 28, 2014

Mark test of subclassed order as pending.
This test is now failing but it is unclear if it was ever really
testing what it claims to be testing. An order with no email
is not valid and should not save, so the test should not pass.
@shioyama

This comment has been minimized.

Show comment
Hide comment
@shioyama

shioyama Apr 4, 2014

Contributor

Ok took out the callback and marked the failing test as pending, as I did in #4542. This should be good to go.

Contributor

shioyama commented Apr 4, 2014

Ok took out the callback and marked the failing test as pending, as I did in #4542. This should be good to go.

@shioyama

This comment has been minimized.

Show comment
Hide comment
@shioyama

shioyama Apr 7, 2014

Contributor

@huoxito Thanks for merging #4542. Can you merge this one too (or let me know if there are any issues)? This is actually the one we need 😄

Contributor

shioyama commented Apr 7, 2014

@huoxito Thanks for merging #4542. Can you merge this one too (or let me know if there are any issues)? This is actually the one we need 😄

huoxito added a commit that referenced this pull request Apr 7, 2014

Mark test of subclassed order as pending.
This test is now failing but it is unclear if it was ever really
testing what it claims to be testing. An order with no email
is not valid and should not save, so the test should not pass.

Fixes #4499
@huoxito

This comment has been minimized.

Show comment
Hide comment
@huoxito

huoxito Apr 7, 2014

Member

Merged. Thank you @shioyama :)

Member

huoxito commented Apr 7, 2014

Merged. Thank you @shioyama :)

@huoxito huoxito closed this Apr 7, 2014

@shioyama

This comment has been minimized.

Show comment
Hide comment
@shioyama

shioyama Apr 7, 2014

Contributor

Thanks!

Contributor

shioyama commented Apr 7, 2014

Thanks!

@tesserakt

This comment has been minimized.

Show comment
Hide comment
@tesserakt

tesserakt Feb 26, 2015

Just as a follow up, we turned transactions back on in our Spree site and it improved the stability A LOT.

Per the documentation here https://github.com/pluginaweek/state_machine/blob/master/lib/state_machine/integrations/active_record.rb#L286

here is the callback list

Callbacks occur in the following order. Callbacks specific to state_machine

# are bolded.  The remaining callbacks are part of ActiveRecord.
# 
# \* (-) save
# \* (-) begin transaction (if enabled)
# \* (1) _before_transition_
# \* (-) valid
# \* (2) before_validation
# \* (-) validate
# \* (3) after_validation
# \* (4) before_save
# \* (5) before_create
# \* (-) create
# \* (6) after_create
# \* (7) after_save
# \* (8) _after_transition_
# \* (-) end transaction (if enabled)
# \* (9) after_commit

Just as a follow up, we turned transactions back on in our Spree site and it improved the stability A LOT.

Per the documentation here https://github.com/pluginaweek/state_machine/blob/master/lib/state_machine/integrations/active_record.rb#L286

here is the callback list

Callbacks occur in the following order. Callbacks specific to state_machine

# are bolded.  The remaining callbacks are part of ActiveRecord.
# 
# \* (-) save
# \* (-) begin transaction (if enabled)
# \* (1) _before_transition_
# \* (-) valid
# \* (2) before_validation
# \* (-) validate
# \* (3) after_validation
# \* (4) before_save
# \* (5) before_create
# \* (-) create
# \* (6) after_create
# \* (7) after_save
# \* (8) _after_transition_
# \* (-) end transaction (if enabled)
# \* (9) after_commit
@JDutil

This comment has been minimized.

Show comment
Hide comment
@JDutil

JDutil Feb 26, 2015

Member

@tesserakt could you elaborate on the stability improvement? Should we turn them back on by default? I'm pretty sure we've even since removed the regression spec added to this.

Member

JDutil commented Feb 26, 2015

@tesserakt could you elaborate on the stability improvement? Should we turn them back on by default? I'm pretty sure we've even since removed the regression spec added to this.

@tesserakt

This comment has been minimized.

Show comment
Hide comment
@tesserakt

tesserakt Feb 26, 2015

@JDutil We only allow 1 shipment per location in our Spree Store. Without the lock, when the server got slow some customers would double submit on the address page. This created a race condition that sometimes allowed 2 identical shipments to be created for the same location, i.e. duplicates. Adding the transaction back in prevents this.

@JDutil We only allow 1 shipment per location in our Spree Store. Without the lock, when the server got slow some customers would double submit on the address page. This created a race condition that sometimes allowed 2 identical shipments to be created for the same location, i.e. duplicates. Adding the transaction back in prevents this.

@tesserakt

This comment has been minimized.

Show comment
Hide comment
@tesserakt

tesserakt Feb 26, 2015

@JDutil there were some other weird edge cases we used to see but no longer do after transactions

For example: some orders coming in without completed_at fields.

Some orders that have no shipments
Some orders where the shipments don't have a location attached.

Still looking into some of these, but they have disappeared since adding transactions.

Granted we are running a slightly modified version of 2.3, but making the change helped.

@JDutil there were some other weird edge cases we used to see but no longer do after transactions

For example: some orders coming in without completed_at fields.

Some orders that have no shipments
Some orders where the shipments don't have a location attached.

Still looking into some of these, but they have disappeared since adding transactions.

Granted we are running a slightly modified version of 2.3, but making the change helped.

@huoxito

This comment has been minimized.

Show comment
Hide comment
@huoxito

huoxito Feb 26, 2015

Member

@tesserakt I think we wanted to disable the transaction only for the payment processing which seems pretty useful to prevent double processing but I dont think it's possible not sure. We'd probably need to decouple the payment processing from state machine callbacks (this alone sounds like a nice change already)

Member

huoxito commented Feb 26, 2015

@tesserakt I think we wanted to disable the transaction only for the payment processing which seems pretty useful to prevent double processing but I dont think it's possible not sure. We'd probably need to decouple the payment processing from state machine callbacks (this alone sounds like a nice change already)

@JDutil

This comment has been minimized.

Show comment
Hide comment
@JDutil

JDutil Feb 26, 2015

Member

I've seen tons of errors related to the duplicate shipments, and it drove me nuts on 2.2+ stores. I thought we addressed it by adding the order lock version, which I believe would also have helped resolve double payment processing as well. I don't recall if we made that lock version change to 2.3 or if it wasn't until 2.4+

I think removing payments from state machine callback would be a good idea too, but not sure how best to accomplish that.

Member

JDutil commented Feb 26, 2015

I've seen tons of errors related to the duplicate shipments, and it drove me nuts on 2.2+ stores. I thought we addressed it by adding the order lock version, which I believe would also have helped resolve double payment processing as well. I don't recall if we made that lock version change to 2.3 or if it wasn't until 2.4+

I think removing payments from state machine callback would be a good idea too, but not sure how best to accomplish that.

@tesserakt

This comment has been minimized.

Show comment
Hide comment
@tesserakt

tesserakt Feb 26, 2015

@huoxito you could write a record outside of the transaction (using a separate thread) that says "Hey I'm processing payments" and then in the transaction check for that.

@huoxito you could write a record outside of the transaction (using a separate thread) that says "Hey I'm processing payments" and then in the transaction check for that.

@JDutil

This comment has been minimized.

Show comment
Hide comment
@JDutil

JDutil Feb 26, 2015

Member

Well we added it to 2-2-stable+ db52e1e

Member

JDutil commented Feb 26, 2015

Well we added it to 2-2-stable+ db52e1e

@tesserakt

This comment has been minimized.

Show comment
Hide comment
@tesserakt

tesserakt Feb 26, 2015

@JDutil we still get double shipments even with that order lock code in 2.3

@JDutil we still get double shipments even with that order lock code in 2.3

@tesserakt

This comment has been minimized.

Show comment
Hide comment
@tesserakt

tesserakt Feb 26, 2015

@JDutil @huoxito re-enabling transactions on the order requires a little finagling in the finalize method. If you get past processing the payments but then hit a snag, i.e. a random exception gets thrown somewhere in the stack; it is nice to have the finalize code catch the exception, auto void the payment, send the admin an email, then roll back the transaction and notify the user that something went wrong.

@JDutil @huoxito re-enabling transactions on the order requires a little finagling in the finalize method. If you get past processing the payments but then hit a snag, i.e. a random exception gets thrown somewhere in the stack; it is nice to have the finalize code catch the exception, auto void the payment, send the admin an email, then roll back the transaction and notify the user that something went wrong.

shioyama added a commit to shioyama/spree that referenced this pull request Nov 19, 2015

Mark test of subclassed order as pending.
This test is now failing but it is unclear if it was ever really
testing what it claims to be testing. An order with no email
is not valid and should not save, so the test should not pass.

Fixes #4499
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment