We use state_machine in Commerce and have configured two transitions that go from fulfillment -> complete. One is intended to also trigger some payments logic in event subscribers, the other leaves the order unpaid. Currently, state machine determines the transition to apply by searching the workflow. In this case, that matches the first applicable transition, which may not be the one clicked in the transition form.

This patch stores information about the intended transition in the StateItem instance, much like is already one with StateItem::$originalValue. If a specific transition is not passed (e.g., the state is set using primitive setters on the item) then the current logic is retained.

Not using PHP 7 null coalesce because State Machine does not (yet) specify a PHP 7 requirement.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

bradjones1 created an issue. See original summary.

Neograph734’s picture

Status: Needs review » Reviewed & tested by the community

For hours I have been renaming my events trying to figure out why my second transition event would not fire. Thanks for reporting and providing a solution.

+++ b/src/Plugin/Field/FieldType/StateItem.php
@@ -342,7 +350,9 @@ class StateItem extends FieldItemBase implements StateItemInterface, OptionsProv
+    $transition = $this->appliedTransition
+      ? $this->appliedTransition
+      : $workflow->findTransition($this->originalValue, $this->value);

Could be replaced with a Null coalescing operator:

  $transition = $this->appliedTransition ?? $workflow->findTransition($this->originalValue, $this->value);
jsacksick’s picture

Status: Reviewed & tested by the community » Needs review

Renamed appliedTransition to transitionToApply, and used the Null coalescing operator.

Also added a comment so we know why this is there :).

jsacksick’s picture

Better with the patch no? :p

bradjones1’s picture

Status: Needs review » Reviewed & tested by the community
Neograph734’s picture

Should we add or update a test for this?

If there are 2 transitions with the same 'from' and 'to' states, the code would previously always select the first one.
Triggering the second transition and then checking it should fail for the current code and pass with the patched code.

Neograph734’s picture

I guess it would look something like this?

Neograph734’s picture

Oh, forgot to add the newly created configurations :(

Neograph734’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
10.25 KB

Great, the test works (test only patch selected completed1 instead of completed2). It only failed on a stupid copy/paste error.
No test_only anymore as that point is already proven in #8.

  • jsacksick committed f22f994 on 8.x-1.x authored by Neograph734
    Issue #3083407 by Neograph734, bradjones1, jsacksick: Fire intended...
jsacksick’s picture

Status: Needs review » Fixed

Thanks everyone! Committed!

bradjones1’s picture

Awesome. Think this is worth tagging a new minor?

jsacksick’s picture

@bradjones1: Sure, but I'd love to get #3051503: Implement a confirmation form before the transition in as well in the next release.

As soon as this is done, I'll tag a release.

jsacksick’s picture

Status: Fixed » Needs work

I believe this introduced a regression as reported in #2912849: Require confirmation for state transitions.

Before applying the transition... We're not checking whether it is allowed... As a consequence, "canceled" shipments are marked as "shipped"... although the previous behavior was changing the state, but then skipping the transition.

jsacksick’s picture

Hm.... With the previous code, the state would still be changed, it's just the event that wouldn't be fired (because no transition would be found by dispatchTransitionEvent())... So unsure what to do here...

Either applyTransition() should first check if the transition is allowed... Or code calling it should check that the transition is allowed...

Neograph734’s picture

I think that relates to #3052752: When calling applyTransition directly (as commerce does) the guards are never invoked?
Both options have been proposed there.

jsacksick’s picture

Status: Needs work » Fixed

Setting the status back to "fixed" as I believe the problem is not coming from this code but code applying transition without checking if the transition is allowed before.

Also, if a fix needs to implemented in State machine itself, it should happen in #3052752: When calling applyTransition directly (as commerce does) the guards are never invoked.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.