From ac44646673a6b2c8534250f5354b332bf5889829 Mon Sep 17 00:00:00 2001 From: KrasnoshchokBohdan Date: Mon, 26 May 2025 11:00:04 +0300 Subject: [PATCH 1/7] magento/magento2#37983: Place order with disabled Payment method working - prevent order placement with unavailable payment method --- .../QuoteGraphQl/Model/Cart/PlaceOrder.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php b/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php index b1a7ed3bdc5b6..ca032c7dc63da 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php @@ -58,6 +58,25 @@ public function execute(Quote $cart, string $maskedCartId, int $userId): int $cartId = (int)$cart->getId(); $paymentMethod = $this->paymentManagement->get($cartId); + // Get a list of available payment methods for the cart + $availablePaymentMethods = $this->paymentManagement->getList($cartId); + $paymentMethodCode = $cart->getPayment()->getMethod(); + $isPaymentMethodAvailable = false; + + // Check if the selected payment method is in the available methods list + if($paymentMethodCode && $availablePaymentMethods){ + foreach ($availablePaymentMethods as $availableMethod) { + if ($availableMethod->getCode() === $paymentMethodCode) { + $isPaymentMethodAvailable = true; + break; + } + } + } + + if (!$isPaymentMethodAvailable) { + throw new LocalizedException(__('The requested Payment Method is not available.')); + } + return (int)$this->cartManagement->placeOrder($cartId, $paymentMethod); } } From ff67a1db6adb8cbb6fd194243bc705eb44e2949e Mon Sep 17 00:00:00 2001 From: KrasnoshchokBohdan Date: Tue, 3 Jun 2025 12:04:47 +0300 Subject: [PATCH 2/7] magento/magento2#37983: Place order with disabled Payment method working - copyright and static test errors fix --- app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php b/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php index ca032c7dc63da..7a832fdf3aa28 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php @@ -1,7 +1,7 @@ getCode() === $paymentMethodCode) { $isPaymentMethodAvailable = true; From c646ff8d678f006bab6a59f206922d334df5d6d5 Mon Sep 17 00:00:00 2001 From: KrasnoshchokBohdan Date: Thu, 12 Jun 2025 12:16:25 +0300 Subject: [PATCH 3/7] magento/magento2#37983: Place order with disabled Payment method working Updated the code to safely handle cases where the cart's payment object might be null. This prevents potential errors when accessing the payment method code for carts without a valid payment set. --- app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php b/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php index 7a832fdf3aa28..e09b0d52f6e21 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php @@ -60,7 +60,8 @@ public function execute(Quote $cart, string $maskedCartId, int $userId): int // Get a list of available payment methods for the cart $availablePaymentMethods = $this->paymentManagement->getList($cartId); - $paymentMethodCode = $cart->getPayment()->getMethod(); + $payment = $cart->getPayment(); + $paymentMethodCode = $payment?->getMethod(); $isPaymentMethodAvailable = false; // Check if the selected payment method is in the available methods list From 8e66f2a4df18da491ee84f96014614e79f92b352 Mon Sep 17 00:00:00 2001 From: KrasnoshchokBohdan <111579196+KrasnoshchokBohdan@users.noreply.github.com> Date: Sat, 12 Jul 2025 16:22:31 +0300 Subject: [PATCH 4/7] Update app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php Co-authored-by: Abhinav Pathak <51681618+engcom-Hotel@users.noreply.github.com> --- .../Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php b/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php index e09b0d52f6e21..649976d60ff58 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php @@ -62,16 +62,12 @@ public function execute(Quote $cart, string $maskedCartId, int $userId): int $availablePaymentMethods = $this->paymentManagement->getList($cartId); $payment = $cart->getPayment(); $paymentMethodCode = $payment?->getMethod(); - $isPaymentMethodAvailable = false; - // Check if the selected payment method is in the available methods list if ($paymentMethodCode && $availablePaymentMethods) { - foreach ($availablePaymentMethods as $availableMethod) { - if ($availableMethod->getCode() === $paymentMethodCode) { - $isPaymentMethodAvailable = true; - break; - } - } + $availableCodes = array_map(fn($method) => $method->getCode(), $availablePaymentMethods); + $isPaymentMethodAvailable = in_array($paymentMethodCode, $availableCodes); + } else { + $isPaymentMethodAvailable = false; } if (!$isPaymentMethodAvailable) { From 5f3e54bd3cd53414a6d08f783b47ea6103feb7a2 Mon Sep 17 00:00:00 2001 From: KrasnoshchokBohdan Date: Sat, 12 Jul 2025 16:53:09 +0300 Subject: [PATCH 5/7] magento/magento2#37983: Place order with disabled Payment method working - Add unit tests for PlaceOrder functionality in QuoteGraphQl. --- .../Test/Unit/Model/Cart/PlaceOrderTest.php | 378 ++++++++++++++++++ 1 file changed, 378 insertions(+) create mode 100644 app/code/Magento/QuoteGraphQl/Test/Unit/Model/Cart/PlaceOrderTest.php diff --git a/app/code/Magento/QuoteGraphQl/Test/Unit/Model/Cart/PlaceOrderTest.php b/app/code/Magento/QuoteGraphQl/Test/Unit/Model/Cart/PlaceOrderTest.php new file mode 100644 index 0000000000000..ad9179741e93e --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Test/Unit/Model/Cart/PlaceOrderTest.php @@ -0,0 +1,378 @@ +paymentManagementMock = $this->createMock(PaymentMethodManagementInterface::class); + $this->cartManagementMock = $this->createMock(CartManagementInterface::class); + $this->quoteMock = $this->createMock(Quote::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->paymentInterfaceMock = $this->createMock(PaymentInterface::class); + + $this->placeOrder = new PlaceOrder( + $this->paymentManagementMock, + $this->cartManagementMock + ); + } + + /** + * Test successful order placement with available payment method + */ + public function testExecuteWithAvailablePaymentMethod(): void + { + $cartId = 123; + $maskedCartId = 'masked123'; + $userId = 456; + $paymentMethodCode = 'checkmo'; + $orderId = 789; + + $this->quoteMock->method('getId')->willReturn($cartId); + $this->quoteMock->method('getPayment')->willReturn($this->paymentMock); + + $this->paymentMock->method('getMethod')->willReturn($paymentMethodCode); + + $this->paymentManagementMock->method('get') + ->with($cartId) + ->willReturn($this->paymentInterfaceMock); + + $availableMethod1 = $this->createMock(PaymentMethodInterface::class); + $availableMethod1->method('getCode')->willReturn('paypal'); + + $availableMethod2 = $this->createMock(PaymentMethodInterface::class); + $availableMethod2->method('getCode')->willReturn($paymentMethodCode); + + $availableMethod3 = $this->createMock(PaymentMethodInterface::class); + $availableMethod3->method('getCode')->willReturn('stripe'); + + $availablePaymentMethods = [$availableMethod1, $availableMethod2, $availableMethod3]; + + $this->paymentManagementMock->method('getList') + ->with($cartId) + ->willReturn($availablePaymentMethods); + + $this->cartManagementMock->method('placeOrder') + ->with($cartId, $this->paymentInterfaceMock) + ->willReturn($orderId); + + $result = $this->placeOrder->execute($this->quoteMock, $maskedCartId, $userId); + + $this->assertEquals($orderId, $result); + } + + /** + * Test exception when payment method is not available + */ + public function testExecuteWithUnavailablePaymentMethod(): void + { + $cartId = 123; + $maskedCartId = 'masked123'; + $userId = 456; + $paymentMethodCode = 'unavailable_method'; + + $this->quoteMock->method('getId')->willReturn($cartId); + $this->quoteMock->method('getPayment')->willReturn($this->paymentMock); + + $this->paymentMock->method('getMethod')->willReturn($paymentMethodCode); + + $this->paymentManagementMock->method('get') + ->with($cartId) + ->willReturn($this->paymentInterfaceMock); + + $availableMethod1 = $this->createMock(PaymentMethodInterface::class); + $availableMethod1->method('getCode')->willReturn('paypal'); + + $availableMethod2 = $this->createMock(PaymentMethodInterface::class); + $availableMethod2->method('getCode')->willReturn('stripe'); + + $availablePaymentMethods = [$availableMethod1, $availableMethod2]; + + $this->paymentManagementMock->method('getList') + ->with($cartId) + ->willReturn($availablePaymentMethods); + + $this->expectException(LocalizedException::class); + $this->expectExceptionMessage('The requested Payment Method is not available.'); + + $this->placeOrder->execute($this->quoteMock, $maskedCartId, $userId); + } + + /** + * Test exception when no payment method is set on quote + */ + public function testExecuteWithNoPaymentMethodSet(): void + { + $cartId = 123; + $maskedCartId = 'masked123'; + $userId = 456; + + $this->quoteMock->method('getId')->willReturn($cartId); + $this->quoteMock->method('getPayment')->willReturn($this->paymentMock); + + $this->paymentMock->method('getMethod')->willReturn(null); + + $this->paymentManagementMock->method('get') + ->with($cartId) + ->willReturn($this->paymentInterfaceMock); + + $availableMethod = $this->createMock(PaymentMethodInterface::class); + $availableMethod->method('getCode')->willReturn('checkmo'); + $availablePaymentMethods = [$availableMethod]; + + $this->paymentManagementMock->method('getList') + ->with($cartId) + ->willReturn($availablePaymentMethods); + + $this->expectException(LocalizedException::class); + $this->expectExceptionMessage('The requested Payment Method is not available.'); + + $this->placeOrder->execute($this->quoteMock, $maskedCartId, $userId); + } + + /** + * Test exception when no payment methods are available + */ + public function testExecuteWithNoAvailablePaymentMethods(): void + { + $cartId = 123; + $maskedCartId = 'masked123'; + $userId = 456; + $paymentMethodCode = 'checkmo'; + + $this->quoteMock->method('getId')->willReturn($cartId); + $this->quoteMock->method('getPayment')->willReturn($this->paymentMock); + + $this->paymentMock->method('getMethod')->willReturn($paymentMethodCode); + + $this->paymentManagementMock->method('get') + ->with($cartId) + ->willReturn($this->paymentInterfaceMock); + + $this->paymentManagementMock->method('getList') + ->with($cartId) + ->willReturn([]); + + $this->expectException(LocalizedException::class); + $this->expectExceptionMessage('The requested Payment Method is not available.'); + + $this->placeOrder->execute($this->quoteMock, $maskedCartId, $userId); + } + + /** + * Test exception when available payment methods is null + */ + public function testExecuteWithNullAvailablePaymentMethods(): void + { + $cartId = 123; + $maskedCartId = 'masked123'; + $userId = 456; + $paymentMethodCode = 'checkmo'; + + $this->quoteMock->method('getId')->willReturn($cartId); + $this->quoteMock->method('getPayment')->willReturn($this->paymentMock); + + $this->paymentMock->method('getMethod')->willReturn($paymentMethodCode); + + $this->paymentManagementMock->method('get') + ->with($cartId) + ->willReturn($this->paymentInterfaceMock); + + $this->paymentManagementMock->method('getList') + ->with($cartId) + ->willReturn(null); + + $this->expectException(LocalizedException::class); + $this->expectExceptionMessage('The requested Payment Method is not available.'); + + $this->placeOrder->execute($this->quoteMock, $maskedCartId, $userId); + } + + /** + * Test exception when quote has no payment object + */ + public function testExecuteWithNoPaymentObject(): void + { + $cartId = 123; + $maskedCartId = 'masked123'; + $userId = 456; + + $this->quoteMock->method('getId')->willReturn($cartId); + $this->quoteMock->method('getPayment')->willReturn(null); + + $this->paymentManagementMock->method('get') + ->with($cartId) + ->willReturn($this->paymentInterfaceMock); + + $availableMethod = $this->createMock(PaymentMethodInterface::class); + $availableMethod->method('getCode')->willReturn('checkmo'); + $availablePaymentMethods = [$availableMethod]; + + $this->paymentManagementMock->method('getList') + ->with($cartId) + ->willReturn($availablePaymentMethods); + + $this->expectException(LocalizedException::class); + $this->expectExceptionMessage('The requested Payment Method is not available.'); + + $this->placeOrder->execute($this->quoteMock, $maskedCartId, $userId); + } + + /** + * Test that cart management exceptions are propagated + */ + public function testExecuteWithCartManagementException(): void + { + $cartId = 123; + $maskedCartId = 'masked123'; + $userId = 456; + $paymentMethodCode = 'checkmo'; + + $this->quoteMock->method('getId')->willReturn($cartId); + $this->quoteMock->method('getPayment')->willReturn($this->paymentMock); + + $this->paymentMock->method('getMethod')->willReturn($paymentMethodCode); + + $this->paymentManagementMock->method('get') + ->with($cartId) + ->willReturn($this->paymentInterfaceMock); + + $availableMethod = $this->createMock(PaymentMethodInterface::class); + $availableMethod->method('getCode')->willReturn($paymentMethodCode); + $availablePaymentMethods = [$availableMethod]; + + $this->paymentManagementMock->method('getList') + ->with($cartId) + ->willReturn($availablePaymentMethods); + + $expectedException = new NoSuchEntityException(__('Cart does not exist')); + $this->cartManagementMock->method('placeOrder') + ->with($cartId, $this->paymentInterfaceMock) + ->willThrowException($expectedException); + + $this->expectException(NoSuchEntityException::class); + $this->expectExceptionMessage('Cart does not exist'); + + $this->placeOrder->execute($this->quoteMock, $maskedCartId, $userId); + } + + /** + * Test with empty string payment method code + */ + public function testExecuteWithEmptyPaymentMethodCode(): void + { + $cartId = 123; + $maskedCartId = 'masked123'; + $userId = 456; + + $this->quoteMock->method('getId')->willReturn($cartId); + $this->quoteMock->method('getPayment')->willReturn($this->paymentMock); + + $this->paymentMock->method('getMethod')->willReturn(''); + + $this->paymentManagementMock->method('get') + ->with($cartId) + ->willReturn($this->paymentInterfaceMock); + + $availableMethod = $this->createMock(PaymentMethodInterface::class); + $availableMethod->method('getCode')->willReturn('checkmo'); + $availablePaymentMethods = [$availableMethod]; + + $this->paymentManagementMock->method('getList') + ->with($cartId) + ->willReturn($availablePaymentMethods); + + $this->expectException(LocalizedException::class); + $this->expectExceptionMessage('The requested Payment Method is not available.'); + + $this->placeOrder->execute($this->quoteMock, $maskedCartId, $userId); + } + + /** + * Test case sensitivity in payment method code comparison + */ + public function testExecuteWithCaseSensitivePaymentMethodCode(): void + { + $cartId = 123; + $maskedCartId = 'masked123'; + $userId = 456; + $paymentMethodCode = 'CheckMo'; // Different case + $orderId = 789; + + $this->quoteMock->method('getId')->willReturn($cartId); + $this->quoteMock->method('getPayment')->willReturn($this->paymentMock); + + $this->paymentMock->method('getMethod')->willReturn($paymentMethodCode); + + $this->paymentManagementMock->method('get') + ->with($cartId) + ->willReturn($this->paymentInterfaceMock); + + $availableMethod = $this->createMock(PaymentMethodInterface::class); + $availableMethod->method('getCode')->willReturn('checkmo'); // lowercase + $availablePaymentMethods = [$availableMethod]; + + $this->paymentManagementMock->method('getList') + ->with($cartId) + ->willReturn($availablePaymentMethods); + + $this->expectException(LocalizedException::class); + $this->expectExceptionMessage('The requested Payment Method is not available.'); + + $this->placeOrder->execute($this->quoteMock, $maskedCartId, $userId); + } +} From 889e4d5ed38a002191639b022e75c0f08010c746 Mon Sep 17 00:00:00 2001 From: KrasnoshchokBohdan Date: Tue, 15 Jul 2025 11:37:53 +0300 Subject: [PATCH 6/7] magento/magento2#37983: Place order with disabled Payment method working Add logging for disabled payment method attempts in PlaceOrder Extended `PlaceOrder` to log debug information when an unavailable payment method is used. This includes details like the cart ID, user ID, attempted payment method, and available methods, facilitating easier troubleshooting of order placement issues. Updated unit tests to validate the new logging behavior. --- .../QuoteGraphQl/Model/Cart/PlaceOrder.php | 27 ++++- .../Test/Unit/Model/Cart/PlaceOrderTest.php | 111 ++++++++++++++++-- 2 files changed, 126 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php b/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php index 649976d60ff58..5808535cc3b8c 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php @@ -12,6 +12,7 @@ use Magento\Quote\Api\CartManagementInterface; use Magento\Quote\Api\PaymentMethodManagementInterface; use Magento\Quote\Model\Quote; +use Psr\Log\LoggerInterface; /** * Place an order @@ -28,16 +29,24 @@ class PlaceOrder */ private $cartManagement; + /** + * @var LoggerInterface + */ + private LoggerInterface $logger; + /** * @param PaymentMethodManagementInterface $paymentManagement * @param CartManagementInterface $cartManagement + * @param LoggerInterface $logger */ public function __construct( PaymentMethodManagementInterface $paymentManagement, - CartManagementInterface $cartManagement + CartManagementInterface $cartManagement, + LoggerInterface $logger ) { $this->paymentManagement = $paymentManagement; $this->cartManagement = $cartManagement; + $this->logger = $logger; } /** @@ -71,7 +80,21 @@ public function execute(Quote $cart, string $maskedCartId, int $userId): int } if (!$isPaymentMethodAvailable) { - throw new LocalizedException(__('The requested Payment Method is not available.')); + // Log the attempt to use a disabled payment method + $this->logger->debug( + 'Attempt to place order with disabled payment method', + [ + 'payment_method' => $paymentMethodCode, + 'cart_id' => $cartId, + 'user_id' => $userId, + 'available_methods' => $availablePaymentMethods ? + array_map(fn($method) => $method->getCode(), $availablePaymentMethods) : [] + ] + ); + + throw new LocalizedException( + __('The requested Payment Method \'%1\' is not available.', $paymentMethodCode ?: 'unknown') + ); } return (int)$this->cartManagement->placeOrder($cartId, $paymentMethod); diff --git a/app/code/Magento/QuoteGraphQl/Test/Unit/Model/Cart/PlaceOrderTest.php b/app/code/Magento/QuoteGraphQl/Test/Unit/Model/Cart/PlaceOrderTest.php index ad9179741e93e..e7e9d31f6be97 100644 --- a/app/code/Magento/QuoteGraphQl/Test/Unit/Model/Cart/PlaceOrderTest.php +++ b/app/code/Magento/QuoteGraphQl/Test/Unit/Model/Cart/PlaceOrderTest.php @@ -18,6 +18,7 @@ use Magento\QuoteGraphQl\Model\Cart\PlaceOrder; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; /** * Test for PlaceOrder @@ -27,7 +28,7 @@ class PlaceOrderTest extends TestCase /** * @var PlaceOrder */ - private $placeOrder; + private $placeOrder; /** * @var PaymentMethodManagementInterface|MockObject @@ -54,6 +55,11 @@ class PlaceOrderTest extends TestCase */ private $paymentInterfaceMock; + /** + * @var LoggerInterface|MockObject + */ + private $loggerMock; + /** * Set up test environment */ @@ -64,10 +70,12 @@ protected function setUp(): void $this->quoteMock = $this->createMock(Quote::class); $this->paymentMock = $this->createMock(Payment::class); $this->paymentInterfaceMock = $this->createMock(PaymentInterface::class); + $this->loggerMock = $this->createMock(LoggerInterface::class); $this->placeOrder = new PlaceOrder( $this->paymentManagementMock, - $this->cartManagementMock + $this->cartManagementMock, + $this->loggerMock ); } @@ -146,8 +154,20 @@ public function testExecuteWithUnavailablePaymentMethod(): void ->with($cartId) ->willReturn($availablePaymentMethods); + $this->loggerMock->expects($this->once()) + ->method('debug') + ->with( + 'Attempt to place order with disabled payment method', + [ + 'payment_method' => $paymentMethodCode, + 'cart_id' => $cartId, + 'user_id' => $userId, + 'available_methods' => ['paypal', 'stripe'] + ] + ); + $this->expectException(LocalizedException::class); - $this->expectExceptionMessage('The requested Payment Method is not available.'); + $this->expectExceptionMessage("The requested Payment Method 'unavailable_method' is not available."); $this->placeOrder->execute($this->quoteMock, $maskedCartId, $userId); } @@ -178,8 +198,20 @@ public function testExecuteWithNoPaymentMethodSet(): void ->with($cartId) ->willReturn($availablePaymentMethods); + $this->loggerMock->expects($this->once()) + ->method('debug') + ->with( + 'Attempt to place order with disabled payment method', + [ + 'payment_method' => null, + 'cart_id' => $cartId, + 'user_id' => $userId, + 'available_methods' => ['checkmo'] + ] + ); + $this->expectException(LocalizedException::class); - $this->expectExceptionMessage('The requested Payment Method is not available.'); + $this->expectExceptionMessage("The requested Payment Method 'unknown' is not available."); $this->placeOrder->execute($this->quoteMock, $maskedCartId, $userId); } @@ -207,8 +239,20 @@ public function testExecuteWithNoAvailablePaymentMethods(): void ->with($cartId) ->willReturn([]); + $this->loggerMock->expects($this->once()) + ->method('debug') + ->with( + 'Attempt to place order with disabled payment method', + [ + 'payment_method' => $paymentMethodCode, + 'cart_id' => $cartId, + 'user_id' => $userId, + 'available_methods' => [] + ] + ); + $this->expectException(LocalizedException::class); - $this->expectExceptionMessage('The requested Payment Method is not available.'); + $this->expectExceptionMessage("The requested Payment Method 'checkmo' is not available."); $this->placeOrder->execute($this->quoteMock, $maskedCartId, $userId); } @@ -236,8 +280,20 @@ public function testExecuteWithNullAvailablePaymentMethods(): void ->with($cartId) ->willReturn(null); + $this->loggerMock->expects($this->once()) + ->method('debug') + ->with( + 'Attempt to place order with disabled payment method', + [ + 'payment_method' => $paymentMethodCode, + 'cart_id' => $cartId, + 'user_id' => $userId, + 'available_methods' => [] + ] + ); + $this->expectException(LocalizedException::class); - $this->expectExceptionMessage('The requested Payment Method is not available.'); + $this->expectExceptionMessage("The requested Payment Method 'checkmo' is not available."); $this->placeOrder->execute($this->quoteMock, $maskedCartId, $userId); } @@ -266,8 +322,20 @@ public function testExecuteWithNoPaymentObject(): void ->with($cartId) ->willReturn($availablePaymentMethods); + $this->loggerMock->expects($this->once()) + ->method('debug') + ->with( + 'Attempt to place order with disabled payment method', + [ + 'payment_method' => null, + 'cart_id' => $cartId, + 'user_id' => $userId, + 'available_methods' => ['checkmo'] + ] + ); + $this->expectException(LocalizedException::class); - $this->expectExceptionMessage('The requested Payment Method is not available.'); + $this->expectExceptionMessage("The requested Payment Method 'unknown' is not available."); $this->placeOrder->execute($this->quoteMock, $maskedCartId, $userId); } @@ -336,8 +404,20 @@ public function testExecuteWithEmptyPaymentMethodCode(): void ->with($cartId) ->willReturn($availablePaymentMethods); + $this->loggerMock->expects($this->once()) + ->method('debug') + ->with( + 'Attempt to place order with disabled payment method', + [ + 'payment_method' => '', + 'cart_id' => $cartId, + 'user_id' => $userId, + 'available_methods' => ['checkmo'] + ] + ); + $this->expectException(LocalizedException::class); - $this->expectExceptionMessage('The requested Payment Method is not available.'); + $this->expectExceptionMessage("The requested Payment Method 'unknown' is not available."); $this->placeOrder->execute($this->quoteMock, $maskedCartId, $userId); } @@ -351,7 +431,6 @@ public function testExecuteWithCaseSensitivePaymentMethodCode(): void $maskedCartId = 'masked123'; $userId = 456; $paymentMethodCode = 'CheckMo'; // Different case - $orderId = 789; $this->quoteMock->method('getId')->willReturn($cartId); $this->quoteMock->method('getPayment')->willReturn($this->paymentMock); @@ -370,8 +449,20 @@ public function testExecuteWithCaseSensitivePaymentMethodCode(): void ->with($cartId) ->willReturn($availablePaymentMethods); + $this->loggerMock->expects($this->once()) + ->method('debug') + ->with( + 'Attempt to place order with disabled payment method', + [ + 'payment_method' => $paymentMethodCode, + 'cart_id' => $cartId, + 'user_id' => $userId, + 'available_methods' => ['checkmo'] + ] + ); + $this->expectException(LocalizedException::class); - $this->expectExceptionMessage('The requested Payment Method is not available.'); + $this->expectExceptionMessage("The requested Payment Method 'CheckMo' is not available."); $this->placeOrder->execute($this->quoteMock, $maskedCartId, $userId); } From bd491a594c87e3bf501ea5f3b4f9d1c8cef79b69 Mon Sep 17 00:00:00 2001 From: KrasnoshchokBohdan Date: Sat, 19 Jul 2025 15:47:31 +0300 Subject: [PATCH 7/7] magento/magento2#37983: Place order with disabled Payment method working Refactor PlaceOrder to support optional logger dependency Modified the constructor to make LoggerInterface optional by defaulting to ObjectManager resolution. This improves flexibility and ensures compatibility with cases where a logger is not explicitly provided. --- app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php b/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php index 5808535cc3b8c..0aed9fe1dabde 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/PlaceOrder.php @@ -13,6 +13,7 @@ use Magento\Quote\Api\PaymentMethodManagementInterface; use Magento\Quote\Model\Quote; use Psr\Log\LoggerInterface; +use Magento\Framework\App\ObjectManager; /** * Place an order @@ -37,16 +38,17 @@ class PlaceOrder /** * @param PaymentMethodManagementInterface $paymentManagement * @param CartManagementInterface $cartManagement - * @param LoggerInterface $logger + * @param LoggerInterface|null $logger */ public function __construct( PaymentMethodManagementInterface $paymentManagement, CartManagementInterface $cartManagement, - LoggerInterface $logger + ?LoggerInterface $logger = null ) { $this->paymentManagement = $paymentManagement; $this->cartManagement = $cartManagement; - $this->logger = $logger; + $this->logger = $logger ?: ObjectManager::getInstance() + ->get(LoggerInterface::class); } /**