diff --git a/changelog/_unreleased/2025-02-07-add-additiona-transition.md b/changelog/_unreleased/2025-02-07-add-additiona-transition.md new file mode 100644 index 00000000000..06a0faf50e0 --- /dev/null +++ b/changelog/_unreleased/2025-02-07-add-additiona-transition.md @@ -0,0 +1,15 @@ +# Changelog Entry for Migration 1738955309 + +**Summary:** +Added additional transitions for the "paid" status in the Order Transaction State Machine to resolve an inconsistency. According to the documentation, the action "paid" should be used to mark an order as fully paid. However, only the legacy action "pay" was available. This migration adds the following transitions without removing the legacy "pay" transition: + +- Transition from `reminded` to `paid_partially` using action "paid_partially". +- Transition from `reminded` to `paid` using action "paid". +- Transition from `paid_partially` to `paid` using action "paid". + +**Reason:** +This change ensures that the documented action "paid" is available for transitioning orders to a fully paid state, improving consistency across the platform while maintaining backward compatibility. + +**Impact:** +The migration does not remove any existing transitions; it only adds new ones if they are not already present. All environments will receive this update automatically during the migration process. + diff --git a/src/Core/Migration/V6_6/Migration1738955309AddAdditionalPaidTransition.php b/src/Core/Migration/V6_6/Migration1738955309AddAdditionalPaidTransition.php new file mode 100644 index 00000000000..3b71f08253e --- /dev/null +++ b/src/Core/Migration/V6_6/Migration1738955309AddAdditionalPaidTransition.php @@ -0,0 +1,137 @@ +fetchOne( + 'SELECT `id` FROM `state_machine` + WHERE `technical_name` = :technical_name LIMIT 1', + ['technical_name' => OrderTransactionStates::STATE_MACHINE] + ); + + $statePaidPartiallyId = (string) $connection->fetchOne( + 'SELECT `id` FROM `state_machine_state` + WHERE `state_machine_id` = :stateMachineId + AND `technical_name` = :technicalName + LIMIT 1', + [ + 'stateMachineId' => $stateMachineId, + 'technicalName' => 'paid_partially', + ] + ); + + $statePaidId = (string) $connection->fetchOne( + 'SELECT `id` FROM `state_machine_state` + WHERE `state_machine_id` = :stateMachineId + AND `technical_name` = :technicalName + LIMIT 1', + [ + 'stateMachineId' => $stateMachineId, + 'technicalName' => 'paid', + ] + ); + + $remindedId = (string) $connection->fetchOne( + 'SELECT `id` FROM `state_machine_state` + WHERE `state_machine_id` = :stateMachineId + AND `technical_name` = :technicalName + LIMIT 1', + [ + 'stateMachineId' => $stateMachineId, + 'technicalName' => 'reminded', + ] + ); + + $existingTransition1 = $connection->fetchOne( + 'SELECT COUNT(*) FROM `state_machine_transition` + WHERE `state_machine_id` = :stateMachineId + AND `from_state_id` = :fromStateId + AND `to_state_id` = :toStateId + AND `action_name` = :actionName', + [ + 'stateMachineId' => $stateMachineId, + 'fromStateId' => $remindedId, + 'toStateId' => $statePaidPartiallyId, + 'actionName' => 'paid_partially', + ] + ); + if ((int)$existingTransition1 === 0) { + $connection->insert('state_machine_transition', [ + 'id' => Uuid::randomBytes(), + 'state_machine_id' => $stateMachineId, + 'action_name' => 'paid_partially', + 'from_state_id' => $remindedId, + 'to_state_id' => $statePaidPartiallyId, + 'created_at' => (new \DateTime())->format(Defaults::STORAGE_DATE_TIME_FORMAT), + ]); + } + + $existingTransition2 = $connection->fetchOne( + 'SELECT COUNT(*) FROM `state_machine_transition` + WHERE `state_machine_id` = :stateMachineId + AND `from_state_id` = :fromStateId + AND `to_state_id` = :toStateId + AND `action_name` = :actionName', + [ + 'stateMachineId' => $stateMachineId, + 'fromStateId' => $remindedId, + 'toStateId' => $statePaidId, + 'actionName' => 'paid', + ] + ); + if ((int)$existingTransition2 === 0) { + $connection->insert('state_machine_transition', [ + 'id' => Uuid::randomBytes(), + 'state_machine_id' => $stateMachineId, + 'action_name' => 'paid', + 'from_state_id' => $remindedId, + 'to_state_id' => $statePaidId, + 'created_at' => (new \DateTime())->format(Defaults::STORAGE_DATE_TIME_FORMAT), + ]); + } + + $existingTransition3 = $connection->fetchOne( + 'SELECT COUNT(*) FROM `state_machine_transition` + WHERE `state_machine_id` = :stateMachineId + AND `from_state_id` = :fromStateId + AND `to_state_id` = :toStateId + AND `action_name` = :actionName', + [ + 'stateMachineId' => $stateMachineId, + 'fromStateId' => $statePaidPartiallyId, + 'toStateId' => $statePaidId, + 'actionName' => 'paid', + ] + ); + if ((int)$existingTransition3 === 0) { + $connection->insert('state_machine_transition', [ + 'id' => Uuid::randomBytes(), + 'state_machine_id' => $stateMachineId, + 'action_name' => 'paid', + 'from_state_id' => $statePaidPartiallyId, + 'to_state_id' => $statePaidId, + 'created_at' => (new \DateTime())->format(Defaults::STORAGE_DATE_TIME_FORMAT), + ]); + } + } + + public function updateDestructive(Connection $connection): void + { + } +} diff --git a/tests/migration/Core/V6_6/Migration1738955309AddAdditionalPaidTransitionTest.php b/tests/migration/Core/V6_6/Migration1738955309AddAdditionalPaidTransitionTest.php new file mode 100644 index 00000000000..814c1e30dd2 --- /dev/null +++ b/tests/migration/Core/V6_6/Migration1738955309AddAdditionalPaidTransitionTest.php @@ -0,0 +1,99 @@ +getContainer()->get(Connection::class); + + $stateMachineId = (string)$connection->fetchOne( + 'SELECT `id` FROM `state_machine` WHERE `technical_name` = "order_transaction.state" LIMIT 1' + ); + + $remindedId = (string)$connection->fetchOne( + 'SELECT `id` FROM `state_machine_state` + WHERE `state_machine_id` = :stateMachineId AND `technical_name` = "reminded" LIMIT 1', + ['stateMachineId' => $stateMachineId] + ); + + $statePaidPartiallyId = (string)$connection->fetchOne( + 'SELECT `id` FROM `state_machine_state` + WHERE `state_machine_id` = :stateMachineId AND `technical_name` = "paid_partially" LIMIT 1', + ['stateMachineId' => $stateMachineId] + ); + + $statePaidId = (string)$connection->fetchOne( + 'SELECT `id` FROM `state_machine_state` + WHERE `state_machine_id` = :stateMachineId AND `technical_name` = "paid" LIMIT 1', + ['stateMachineId' => $stateMachineId] + ); + + $connection->executeUpdate( + 'DELETE FROM state_machine_transition + WHERE state_machine_id = :stateMachineId + AND action_name IN ("paid_partially", "paid") + AND ((from_state_id = :remindedId AND to_state_id IN (:statePaidPartiallyId, :statePaidId)) + OR (from_state_id = :statePaidPartiallyId AND to_state_id = :statePaidId))', + [ + 'stateMachineId' => $stateMachineId, + 'remindedId' => $remindedId, + 'statePaidPartiallyId'=> $statePaidPartiallyId, + 'statePaidId' => $statePaidId, + ] + ); + + $migration = new Migration1738955309AddAdditionalPaidTransition(); + $migration->update($connection); + + $countCase1 = (int)$connection->fetchOne( + 'SELECT COUNT(*) FROM state_machine_transition + WHERE state_machine_id = :stateMachineId + AND action_name = "paid_partially" + AND from_state_id = :remindedId + AND to_state_id = :statePaidPartiallyId', + [ + 'stateMachineId' => $stateMachineId, + 'remindedId' => $remindedId, + 'statePaidPartiallyId'=> $statePaidPartiallyId, + ] + ); + $this->assertGreaterThanOrEqual(1, $countCase1, 'Expected a transition from reminded to paid_partially with action "paid_partially" to be added.'); + + $countCase2 = (int)$connection->fetchOne( + 'SELECT COUNT(*) FROM state_machine_transition + WHERE state_machine_id = :stateMachineId + AND action_name = "paid" + AND from_state_id = :remindedId + AND to_state_id = :statePaidId', + [ + 'stateMachineId' => $stateMachineId, + 'remindedId' => $remindedId, + 'statePaidId' => $statePaidId, + ] + ); + $this->assertGreaterThanOrEqual(1, $countCase2, 'Expected a transition from reminded to paid with action "paid" to be added.'); + + $countCase3 = (int)$connection->fetchOne( + 'SELECT COUNT(*) FROM state_machine_transition + WHERE state_machine_id = :stateMachineId + AND action_name = "paid" + AND from_state_id = :statePaidPartiallyId + AND to_state_id = :statePaidId', + [ + 'stateMachineId' => $stateMachineId, + 'statePaidPartiallyId'=> $statePaidPartiallyId, + 'statePaidId' => $statePaidId, + ] + ); + $this->assertGreaterThanOrEqual(1, $countCase3, 'Expected a transition from paid_partially to paid with action "paid" to be added.'); + } +}