From 93b08f65d88270af1c7d92d4ab9ae99be9cfd45b Mon Sep 17 00:00:00 2001 From: Patrick McLain Date: Fri, 22 Feb 2019 23:15:28 -0500 Subject: [PATCH 01/17] Prototype BraintreeGraphQl Payments --- .../Model/BraintreeDataProvider.php | 32 +++++++++++++++++++ .../Model/BraintreeVaultDataProvider.php | 32 +++++++++++++++++++ app/code/Magento/BraintreeGraphQl/README.md | 4 +++ .../Magento/BraintreeGraphQl/composer.json | 24 ++++++++++++++ .../BraintreeGraphQl/etc/graphql/di.xml | 17 ++++++++++ .../Magento/BraintreeGraphQl/etc/module.xml | 10 ++++++ .../BraintreeGraphQl/etc/schema.graphqls | 18 +++++++++++ .../Magento/BraintreeGraphQl/registration.php | 10 ++++++ .../AdditionalDataProviderInterface.php | 16 ++++++++++ .../Payment/AdditionalDataProviderPool.php | 31 ++++++++++++++++++ .../Model/Resolver/SetPaymentMethodOnCart.php | 16 ++++++++-- 11 files changed, 208 insertions(+), 2 deletions(-) create mode 100644 app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php create mode 100644 app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php create mode 100644 app/code/Magento/BraintreeGraphQl/README.md create mode 100644 app/code/Magento/BraintreeGraphQl/composer.json create mode 100644 app/code/Magento/BraintreeGraphQl/etc/graphql/di.xml create mode 100644 app/code/Magento/BraintreeGraphQl/etc/module.xml create mode 100644 app/code/Magento/BraintreeGraphQl/etc/schema.graphqls create mode 100644 app/code/Magento/BraintreeGraphQl/registration.php create mode 100644 app/code/Magento/QuoteGraphQl/Model/Cart/Payment/AdditionalDataProviderInterface.php create mode 100644 app/code/Magento/QuoteGraphQl/Model/Cart/Payment/AdditionalDataProviderPool.php diff --git a/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php b/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php new file mode 100644 index 000000000000..96da041532b0 --- /dev/null +++ b/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php @@ -0,0 +1,32 @@ +arrayManager = $arrayManager; + } + + public function getData(array $args): array + { + return $this->arrayManager->get(static::PATH_ADDITIONAL_DATA, $args) ?? []; + } +} diff --git a/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php b/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php new file mode 100644 index 000000000000..6fbff368eed0 --- /dev/null +++ b/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php @@ -0,0 +1,32 @@ +arrayManager = $arrayManager; + } + + public function getData(array $args): array + { + return $this->arrayManager->get(static::PATH_ADDITIONAL_DATA, $args) ?? []; + } +} diff --git a/app/code/Magento/BraintreeGraphQl/README.md b/app/code/Magento/BraintreeGraphQl/README.md new file mode 100644 index 000000000000..f6740e4d250e --- /dev/null +++ b/app/code/Magento/BraintreeGraphQl/README.md @@ -0,0 +1,4 @@ +# BraintreeGraphQl + +**BraintreeGraphQl** provides type and resolver for method additional +information. \ No newline at end of file diff --git a/app/code/Magento/BraintreeGraphQl/composer.json b/app/code/Magento/BraintreeGraphQl/composer.json new file mode 100644 index 000000000000..a322db9d257d --- /dev/null +++ b/app/code/Magento/BraintreeGraphQl/composer.json @@ -0,0 +1,24 @@ +{ + "name": "magento/module-braintree-graph-ql", + "description": "N/A", + "type": "magento2-module", + "require": { + "php": "~7.1.3||~7.2.0", + "magento/framework": "*" + }, + "suggest": { + "magento/module-graph-ql": "*" + }, + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\BraintreeGraphQl\\": "" + } + } +} diff --git a/app/code/Magento/BraintreeGraphQl/etc/graphql/di.xml b/app/code/Magento/BraintreeGraphQl/etc/graphql/di.xml new file mode 100644 index 000000000000..d4b7266fa752 --- /dev/null +++ b/app/code/Magento/BraintreeGraphQl/etc/graphql/di.xml @@ -0,0 +1,17 @@ + + + + + + + Magento\BraintreeGraphQl\Model\BraintreeDataProvider + Magento\BraintreeGraphQl\Model\BraintreeVaultDataProvider + + + + diff --git a/app/code/Magento/BraintreeGraphQl/etc/module.xml b/app/code/Magento/BraintreeGraphQl/etc/module.xml new file mode 100644 index 000000000000..2133e95a6910 --- /dev/null +++ b/app/code/Magento/BraintreeGraphQl/etc/module.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/code/Magento/BraintreeGraphQl/etc/schema.graphqls b/app/code/Magento/BraintreeGraphQl/etc/schema.graphqls new file mode 100644 index 000000000000..538780516cc7 --- /dev/null +++ b/app/code/Magento/BraintreeGraphQl/etc/schema.graphqls @@ -0,0 +1,18 @@ +# Copyright © Magento, Inc. All rights reserved. +# See COPYING.txt for license details. + +input PaymentMethodAdditionalDataInput { + braintree: BraintreeInput + braintree_vault: BraintreeVaultInput +} + +input BraintreeInput { + payment_method_nonce: String! + is_active_payment_token_enabler: Boolean! +} + +input BraintreeVaultInput { + payment_method_nonce: String! + public_hash: String! + is_active_payment_token_enabler: Boolean! +} diff --git a/app/code/Magento/BraintreeGraphQl/registration.php b/app/code/Magento/BraintreeGraphQl/registration.php new file mode 100644 index 000000000000..37f7ef30864c --- /dev/null +++ b/app/code/Magento/BraintreeGraphQl/registration.php @@ -0,0 +1,10 @@ +dataProviders = $dataProviders; + } + + public function getData(string $methodCode, array $args): array + { + $additionalData = []; + if (isset($this->dataProviders[$methodCode])) { + $additionalData = $this->dataProviders[$methodCode]->getData($args); + } + + return $additionalData; + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/SetPaymentMethodOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/SetPaymentMethodOnCart.php index 82709de03b9b..05574a07143c 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/SetPaymentMethodOnCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/SetPaymentMethodOnCart.php @@ -17,6 +17,7 @@ use Magento\QuoteGraphQl\Model\Cart\GetCartForUser; use Magento\Quote\Api\Data\PaymentInterfaceFactory; use Magento\Quote\Api\PaymentMethodManagementInterface; +use Magento\QuoteGraphQl\Model\Cart\Payment\AdditionalDataProviderPool; /** * Mutation resolver for setting payment method for shopping cart @@ -43,22 +44,30 @@ class SetPaymentMethodOnCart implements ResolverInterface */ private $paymentFactory; + /** + * @var AdditionalDataProviderPool + */ + private $additionalDataProviderPool; + /** * @param GetCartForUser $getCartForUser * @param ArrayManager $arrayManager * @param PaymentMethodManagementInterface $paymentMethodManagement * @param PaymentInterfaceFactory $paymentFactory + * @param AdditionalDataProviderPool $additionalDataProviderPool */ public function __construct( GetCartForUser $getCartForUser, ArrayManager $arrayManager, PaymentMethodManagementInterface $paymentMethodManagement, - PaymentInterfaceFactory $paymentFactory + PaymentInterfaceFactory $paymentFactory, + AdditionalDataProviderPool $additionalDataProviderPool ) { $this->getCartForUser = $getCartForUser; $this->arrayManager = $arrayManager; $this->paymentMethodManagement = $paymentMethodManagement; $this->paymentFactory = $paymentFactory; + $this->additionalDataProviderPool = $additionalDataProviderPool; } /** @@ -91,7 +100,10 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value 'data' => [ PaymentInterface::KEY_METHOD => $paymentMethodCode, PaymentInterface::KEY_PO_NUMBER => $poNumber, - PaymentInterface::KEY_ADDITIONAL_DATA => [], + PaymentInterface::KEY_ADDITIONAL_DATA => $this->additionalDataProviderPool->getData( + $paymentMethodCode, + $args + ), ] ]); From a59a919e768d36421c0b7cd9991810767ef5a186 Mon Sep 17 00:00:00 2001 From: Patrick McLain Date: Tue, 21 May 2019 08:14:39 -0400 Subject: [PATCH 02/17] Braintree CC and Vault Support and Tests --- .../Model/BraintreeVaultDataProvider.php | 2 +- .../BraintreeGraphQl/etc/graphql/di.xml | 2 +- .../BraintreeGraphQl/etc/schema.graphqls | 6 +- .../Magento/QuoteGraphQl/etc/schema.graphqls | 4 + .../api-functional/phpunit_graphql.xml.dist | 4 + .../Customer/SetPaymentMethodTest.php | 353 ++++++++++++++++++ .../Braintree/Guest/SetPaymentMethodTest.php | 178 +++++++++ .../_files/add_simple_product_qty_one.php | 28 ++ .../_files/add_simple_product_qty_three.php | 28 ++ .../GraphQl/Braintree/_files/payments.php | 36 ++ .../GraphQl/Braintree/_files/token.php | 54 +++ 11 files changed, 691 insertions(+), 4 deletions(-) create mode 100644 dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php create mode 100644 dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Guest/SetPaymentMethodTest.php create mode 100644 dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/add_simple_product_qty_one.php create mode 100644 dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/add_simple_product_qty_three.php create mode 100644 dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/payments.php create mode 100644 dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/token.php diff --git a/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php b/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php index 6fbff368eed0..95c7b4839ded 100644 --- a/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php +++ b/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php @@ -12,7 +12,7 @@ class BraintreeVaultDataProvider implements AdditionalDataProviderInterface { - private const PATH_ADDITIONAL_DATA = 'input/payment_method/additional_data/braintree_vault'; + private const PATH_ADDITIONAL_DATA = 'input/payment_method/additional_data/braintree_cc_vault'; /** * @var ArrayManager diff --git a/app/code/Magento/BraintreeGraphQl/etc/graphql/di.xml b/app/code/Magento/BraintreeGraphQl/etc/graphql/di.xml index d4b7266fa752..1f3ee1a1eeda 100644 --- a/app/code/Magento/BraintreeGraphQl/etc/graphql/di.xml +++ b/app/code/Magento/BraintreeGraphQl/etc/graphql/di.xml @@ -10,7 +10,7 @@ Magento\BraintreeGraphQl\Model\BraintreeDataProvider - Magento\BraintreeGraphQl\Model\BraintreeVaultDataProvider + Magento\BraintreeGraphQl\Model\BraintreeVaultDataProvider diff --git a/app/code/Magento/BraintreeGraphQl/etc/schema.graphqls b/app/code/Magento/BraintreeGraphQl/etc/schema.graphqls index 538780516cc7..c1cf93bf9f93 100644 --- a/app/code/Magento/BraintreeGraphQl/etc/schema.graphqls +++ b/app/code/Magento/BraintreeGraphQl/etc/schema.graphqls @@ -3,16 +3,18 @@ input PaymentMethodAdditionalDataInput { braintree: BraintreeInput - braintree_vault: BraintreeVaultInput + braintree_cc_vault: BraintreeCcVaultInput } input BraintreeInput { payment_method_nonce: String! is_active_payment_token_enabler: Boolean! + device_data: String } -input BraintreeVaultInput { +input BraintreeCcVaultInput { payment_method_nonce: String! public_hash: String! is_active_payment_token_enabler: Boolean! + device_data: String } diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index 9e9c83b35820..feda505dfe9f 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -131,6 +131,10 @@ input SetPaymentMethodOnCartInput { input PaymentMethodInput { code: String! @doc(description:"Payment method code") purchase_order_number: String @doc(description:"Purchase order number") + additional_data: PaymentMethodAdditionalDataInput +} + +input PaymentMethodAdditionalDataInput { } input SetGuestEmailOnCartInput { diff --git a/dev/tests/api-functional/phpunit_graphql.xml.dist b/dev/tests/api-functional/phpunit_graphql.xml.dist index aa1899d88f48..f8e075390adb 100644 --- a/dev/tests/api-functional/phpunit_graphql.xml.dist +++ b/dev/tests/api-functional/phpunit_graphql.xml.dist @@ -47,6 +47,10 @@ + + + + diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php new file mode 100644 index 000000000000..2cfcd9c11ec5 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php @@ -0,0 +1,353 @@ +markTestSkipped('Braintree sandbox credentials must be defined in phpunit_graphql.xml.dist'); + } + } + + $objectManager = Bootstrap::getObjectManager(); + $this->getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class); + $this->customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class); + $this->orderCollectionFactory = $objectManager->get(CollectionFactory::class); + $this->orderRepository = $objectManager->get(OrderRepositoryInterface::class); + $this->registry = Bootstrap::getObjectManager()->get(Registry::class); + $this->tokenCollectionFactory = Bootstrap::getObjectManager()->get(TokenCollectionFactory::class); + $this->tokenResource = Bootstrap::getObjectManager()->get(PaymentToken::class); + $this->getNonceCommand = Bootstrap::getObjectManager()->get(GetPaymentNonceCommand::class); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php + * @magentoApiDataFixture Magento/Graphql/Braintree/_files/payments.php + */ + public function testPlaceOrder() + { + $reservedOrderId = 'test_quote'; + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId); + + $setPaymentQuery = $this->getSetPaymentBraintreeQuery($maskedQuoteId); + $setPaymentResponse = $this->graphQlMutation($setPaymentQuery, [], '', $this->getHeaderMap()); + + $this->assertSetPaymentMethodResponse($setPaymentResponse, 'braintree'); + + $placeOrderQuery = $this->getPlaceOrderQuery($maskedQuoteId); + $placeOrderResponse = $this->graphQlMutation($placeOrderQuery, [], '', $this->getHeaderMap()); + + $this->assertPlaceOrderResponse($placeOrderResponse, $reservedOrderId); + + $tokenQueryResult = $this->graphQlQuery($this->getPaymentTokenQuery(), [], '', $this->getHeaderMap()); + + self::assertArrayHasKey('customerPaymentTokens', $tokenQueryResult); + self::assertArrayHasKey('items', $tokenQueryResult['customerPaymentTokens']); + self::assertCount(0, $tokenQueryResult['customerPaymentTokens']['items']); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/add_simple_product_qty_one.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php + * @magentoApiDataFixture Magento/Graphql/Braintree/_files/payments.php + */ + public function testPlaceOrderSaveInVault() + { + $reservedOrderId = 'test_quote'; + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId); + + $setPaymentQuery = $this->getSetPaymentBraintreeQuery($maskedQuoteId, true); + $setPaymentResponse = $this->graphQlMutation($setPaymentQuery, [], '', $this->getHeaderMap()); + + $this->assertSetPaymentMethodResponse($setPaymentResponse, 'braintree'); + + $placeOrderQuery = $this->getPlaceOrderQuery($maskedQuoteId); + $placeOrderResponse = $this->graphQlMutation($placeOrderQuery, [], '', $this->getHeaderMap()); + + $this->assertPlaceOrderResponse($placeOrderResponse, $reservedOrderId); + + $tokenQueryResult = $this->graphQlQuery($this->getPaymentTokenQuery(), [], '', $this->getHeaderMap()); + + self::assertArrayHasKey('customerPaymentTokens', $tokenQueryResult); + self::assertArrayHasKey('items', $tokenQueryResult['customerPaymentTokens']); + self::assertCount(1, $tokenQueryResult['customerPaymentTokens']['items']); + $token = current($tokenQueryResult['customerPaymentTokens']['items']); + self::assertArrayHasKey('payment_method_code', $token); + self::assertEquals('braintree', $token['payment_method_code']); + self::assertArrayHasKey('type', $token); + self::assertEquals('card', $token['type']); + self::assertArrayHasKey('details', $token); + self::assertArrayHasKey('public_hash', $token); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/add_simple_product_qty_three.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php + * @magentoApiDataFixture Magento/Graphql/Braintree/_files/payments.php + * @magentoApiDataFixture Magento/Graphql/Braintree/_files/token.php + */ + public function testPlaceOrderWithVault() + { + $reservedOrderId = 'test_quote'; + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId); + + $nonceResult = $this->getNonceCommand->execute([ + 'customer_id' => 1, + 'public_hash' => 'braintree_public_hash', + ]); + $nonce = $nonceResult->get()['paymentMethodNonce']; + + $setPaymentQuery = $this->getSetPaymentBraintreeVaultQuery($maskedQuoteId, 'braintree_public_hash', $nonce, true); + $setPaymentResponse = $this->graphQlMutation($setPaymentQuery, [], '', $this->getHeaderMap()); + + $this->assertSetPaymentMethodResponse($setPaymentResponse, 'braintree_cc_vault'); + + $placeOrderQuery = $this->getPlaceOrderQuery($maskedQuoteId); + $placeOrderResponse = $this->graphQlMutation($placeOrderQuery, [], '', $this->getHeaderMap()); + + $this->assertPlaceOrderResponse($placeOrderResponse, $reservedOrderId); + } + + private function assertPlaceOrderResponse(array $response, string $reservedOrderId): void + { + self::assertArrayHasKey('placeOrder', $response); + self::assertArrayHasKey('order', $response['placeOrder']); + self::assertArrayHasKey('order_id', $response['placeOrder']['order']); + self::assertEquals($reservedOrderId, $response['placeOrder']['order']['order_id']); + } + + private function assertSetPaymentMethodResponse(array $response, string $methodCode): void + { + self::assertArrayHasKey('setPaymentMethodOnCart', $response); + self::assertArrayHasKey('cart', $response['setPaymentMethodOnCart']); + self::assertArrayHasKey('selected_payment_method', $response['setPaymentMethodOnCart']['cart']); + self::assertArrayHasKey('code', $response['setPaymentMethodOnCart']['cart']['selected_payment_method']); + self::assertEquals($methodCode, $response['setPaymentMethodOnCart']['cart']['selected_payment_method']['code']); + } + + /** + * @param string $maskedQuoteId + * @param bool $saveInVault + * @return string + */ + private function getSetPaymentBraintreeQuery(string $maskedQuoteId, bool $saveInVault = false): string + { + $saveInVault = json_encode($saveInVault); + return <<customerTokenService->createCustomerAccessToken($username, $password); + $headerMap = ['Authorization' => 'Bearer ' . $customerToken]; + return $headerMap; + } + + /** + * @inheritdoc + */ + public function tearDown() + { + $this->registry->unregister('isSecureArea'); + $this->registry->register('isSecureArea', true); + + $orderCollection = $this->orderCollectionFactory->create(); + foreach ($orderCollection as $order) { + $this->orderRepository->delete($order); + } + + $tokenCollection = $this->tokenCollectionFactory->create(); + foreach ($tokenCollection as $token) { + $this->tokenResource->delete($token); + } + $this->registry->unregister('isSecureArea'); + $this->registry->register('isSecureArea', false); + + parent::tearDown(); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Guest/SetPaymentMethodTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Guest/SetPaymentMethodTest.php new file mode 100644 index 000000000000..75f8e58c48a6 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Guest/SetPaymentMethodTest.php @@ -0,0 +1,178 @@ +markTestSkipped('Braintree sandbox credentials must be defined in phpunit_graphql.xml.dist'); + } + } + + $objectManager = Bootstrap::getObjectManager(); + $this->getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class); + $this->customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class); + $this->orderCollectionFactory = $objectManager->get(CollectionFactory::class); + $this->orderRepository = $objectManager->get(OrderRepositoryInterface::class); + $this->registry = Bootstrap::getObjectManager()->get(Registry::class); + } + + /** + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/set_guest_email.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php + * @magentoApiDataFixture Magento/Graphql/Braintree/_files/payments.php + */ + public function testPlaceOrder() + { + $reservedOrderId = 'test_quote'; + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId); + + $setPaymentQuery = $this->getSetPaymentBraintreeQuery($maskedQuoteId); + $setPaymentResponse = $this->graphQlMutation($setPaymentQuery); + + $this->assertSetPaymentMethodResponse($setPaymentResponse, 'braintree'); + + $placeOrderQuery = $this->getPlaceOrderQuery($maskedQuoteId); + $placeOrderResponse = $this->graphQlMutation($placeOrderQuery); + + $this->assertPlaceOrderResponse($placeOrderResponse, $reservedOrderId); + } + + private function assertPlaceOrderResponse(array $response, string $reservedOrderId): void + { + self::assertArrayHasKey('placeOrder', $response); + self::assertArrayHasKey('order', $response['placeOrder']); + self::assertArrayHasKey('order_id', $response['placeOrder']['order']); + self::assertEquals($reservedOrderId, $response['placeOrder']['order']['order_id']); + } + + private function assertSetPaymentMethodResponse(array $response, string $methodCode): void + { + self::assertArrayHasKey('setPaymentMethodOnCart', $response); + self::assertArrayHasKey('cart', $response['setPaymentMethodOnCart']); + self::assertArrayHasKey('selected_payment_method', $response['setPaymentMethodOnCart']['cart']); + self::assertArrayHasKey('code', $response['setPaymentMethodOnCart']['cart']['selected_payment_method']); + self::assertEquals($methodCode, $response['setPaymentMethodOnCart']['cart']['selected_payment_method']['code']); + } + + /** + * @param string $maskedQuoteId + * @return string + */ + private function getSetPaymentBraintreeQuery(string $maskedQuoteId): string + { + return <<registry->unregister('isSecureArea'); + $this->registry->register('isSecureArea', true); + + $orderCollection = $this->orderCollectionFactory->create(); + foreach ($orderCollection as $order) { + $this->orderRepository->delete($order); + } + $this->registry->unregister('isSecureArea'); + $this->registry->register('isSecureArea', false); + + parent::tearDown(); + } +} diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/add_simple_product_qty_one.php b/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/add_simple_product_qty_one.php new file mode 100644 index 000000000000..52e9f61730cd --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/add_simple_product_qty_one.php @@ -0,0 +1,28 @@ +get(ProductRepositoryInterface::class); +/** @var QuoteFactory $quoteFactory */ +$quoteFactory = Bootstrap::getObjectManager()->get(QuoteFactory::class); +/** @var QuoteResource $quoteResource */ +$quoteResource = Bootstrap::getObjectManager()->get(QuoteResource::class); +/** @var CartRepositoryInterface $cartRepository */ +$cartRepository = Bootstrap::getObjectManager()->get(CartRepositoryInterface::class); + +$product = $productRepository->get('simple_product'); + +$quote = $quoteFactory->create(); +$quoteResource->load($quote, 'test_quote', 'reserved_order_id'); +$quote->addProduct($product, 1); +$cartRepository->save($quote); diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/add_simple_product_qty_three.php b/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/add_simple_product_qty_three.php new file mode 100644 index 000000000000..e85e95f5beb7 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/add_simple_product_qty_three.php @@ -0,0 +1,28 @@ +get(ProductRepositoryInterface::class); +/** @var QuoteFactory $quoteFactory */ +$quoteFactory = Bootstrap::getObjectManager()->get(QuoteFactory::class); +/** @var QuoteResource $quoteResource */ +$quoteResource = Bootstrap::getObjectManager()->get(QuoteResource::class); +/** @var CartRepositoryInterface $cartRepository */ +$cartRepository = Bootstrap::getObjectManager()->get(CartRepositoryInterface::class); + +$product = $productRepository->get('simple_product'); + +$quote = $quoteFactory->create(); +$quoteResource->load($quote, 'test_quote', 'reserved_order_id'); +$quote->addProduct($product, 3); +$cartRepository->save($quote); diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/payments.php b/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/payments.php new file mode 100644 index 000000000000..b8c3456905b4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/payments.php @@ -0,0 +1,36 @@ +get(EncryptorInterface::class); + +$processConfigData = function (Config $config, array $data) { + foreach ($data as $key => $value) { + $config->setDataByPath($key, $value); + $config->save(); + } +}; + +// save payment configuration for the default scope +$configData = [ + 'payment/braintree/merchant_id' => defined('TESTS_BRAINTREE_MERCHANT_ID') ? TESTS_BRAINTREE_MERCHANT_ID : 'def_merchant_id', + 'payment/braintree/public_key' => $encryptor->encrypt(defined('TESTS_BRAINTREE_PUBLIC_KEY') ? TESTS_BRAINTREE_PUBLIC_KEY : 'def_public_key'), + 'payment/braintree/private_key' => $encryptor->encrypt(defined('TESTS_BRAINTREE_PRIVATE_KEY') ? TESTS_BRAINTREE_PRIVATE_KEY : 'def_private_key'), + 'payment/' . ConfigProvider::CODE . '/active' => '1', + 'payment/' . ConfigProvider::CC_VAULT_CODE . '/active' => '1', + 'payment/' . ConfigProvider::CODE . '/environment' => 'sandbox', +]; +/** @var Config $defConfig */ +$defConfig = $objectManager->create(Config::class); +$defConfig->setScope(ScopeConfigInterface::SCOPE_TYPE_DEFAULT); +$processConfigData($defConfig, $configData); diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/token.php b/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/token.php new file mode 100644 index 000000000000..bdfd9902f070 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/token.php @@ -0,0 +1,54 @@ +get(\Magento\Braintree\Model\Adapter\BraintreeAdapterFactory::class); +$adapter = $adapterFactory->create(); + +$result = $adapter->sale([ + 'amount' => '0.01', + 'customer' => [ + 'email' => 'customer@example.com', + 'firstName' => 'John', + 'lastName' => 'Smith' + ], + 'options' => ['storeInVaultOnSuccess' => true], + 'paymentMethodNonce' => 'fake-valid-nonce', +]); + +$braintreeToken = $result->transaction->creditCardDetails->token; + +/** @var PaymentToken $token */ +$token = $objectManager->create(PaymentToken::class); + +$token->setGatewayToken($braintreeToken) + ->setPublicHash('braintree_public_hash') + ->setPaymentMethodCode('braintree_vault') + ->setType('card') + ->setExpiresAt(strtotime('+1 year')) + ->setIsVisible(true) + ->setIsActive(true) + ->setCustomerId(1); + +/** @var PaymentTokenRepository $tokenRepository */ +$tokenRepository = $objectManager->create(PaymentTokenRepository::class); +$token = $tokenRepository->save($token); From a784526f87e655676fcd68d766d6a85ac14586f5 Mon Sep 17 00:00:00 2001 From: Patrick McLain Date: Sun, 16 Jun 2019 19:29:27 -0400 Subject: [PATCH 03/17] Add braintree mock for testing --- .../Model/Adapter/BraintreeAdapter.php | 70 ++++++++++ .../Model/MockResponseDataProvider.php | 128 ++++++++++++++++++ .../Magento/TestModuleBraintree/etc/di.xml | 10 ++ .../TestModuleBraintree/etc/module.xml | 10 ++ .../TestModuleBraintree/registration.php | 11 ++ .../api-functional/phpunit_graphql.xml.dist | 4 - .../Customer/SetPaymentMethodTest.php | 4 +- .../_files/add_simple_product_qty_one.php | 28 ---- .../_files/add_simple_product_qty_three.php | 28 ---- 9 files changed, 231 insertions(+), 62 deletions(-) create mode 100644 dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/Adapter/BraintreeAdapter.php create mode 100644 dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/MockResponseDataProvider.php create mode 100644 dev/tests/api-functional/_files/Magento/TestModuleBraintree/etc/di.xml create mode 100644 dev/tests/api-functional/_files/Magento/TestModuleBraintree/etc/module.xml create mode 100644 dev/tests/api-functional/_files/Magento/TestModuleBraintree/registration.php delete mode 100644 dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/add_simple_product_qty_one.php delete mode 100644 dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/add_simple_product_qty_three.php diff --git a/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/Adapter/BraintreeAdapter.php b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/Adapter/BraintreeAdapter.php new file mode 100644 index 000000000000..b6f855f5c2f1 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/Adapter/BraintreeAdapter.php @@ -0,0 +1,70 @@ +mockResponseDataProvider = $mockResponseDataProvider; + } + + /** + * @param string $token + * @return \Braintree\Result\Successful|\Braintree\Result\Error + */ + public function createNonce($token) + { + return $this->mockResponseDataProvider->generateMockNonceResponse(); + } + + /** + * @param array $attributes + * @return \Braintree\Result\Successful|\Braintree\Result\Error + */ + public function sale(array $attributes) + { + return $this->mockResponseDataProvider->generateMockSaleResponse($attributes); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/MockResponseDataProvider.php b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/MockResponseDataProvider.php new file mode 100644 index 000000000000..7355fa3d97f6 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/MockResponseDataProvider.php @@ -0,0 +1,128 @@ +random = $random; + } + + /** + * Create mock sale response for testing + * + * @param array $attributes + * @return \Braintree\Instance + */ + public function generateMockSaleResponse(array $attributes): \Braintree\Instance + { + $transaction = $this->createTransaction($attributes); + + return new \Braintree\Result\Successful([$transaction]); + } + + /** + * Create mock nonce response for testing + * + * @return \Braintree\Instance + */ + public function generateMockNonceResponse(): \Braintree\Instance + { + $nonce = $this->createNonce(); + + return new \Braintree\Result\Successful($nonce, 'paymentMethodNonce'); + } + + /** + * Create Braintree transaction from provided request attributes + * + * @param array $attributes + * @return \Braintree\Transaction + * @throws \Magento\Framework\Exception\LocalizedException + */ + private function createTransaction(array $attributes): \Braintree\Transaction + { + $creditCardInfo = $this->generateCardDetails(); + return \Braintree\Transaction::factory([ + 'amount' => $attributes['amount'], + 'billing' => $attributes['billing'] ?? null, + 'creditCard' => $creditCardInfo, + 'cardDetails' => new \Braintree\Transaction\CreditCardDetails($creditCardInfo), + 'currencyIsoCode' => 'USD', + 'customer' => $attributes['customer'], + 'cvvResponseCode' => 'M', + 'id' => $this->random->getRandomString(8), + 'options' => $attributes['options'] ?? null, + 'shipping' => $attributes['shipping'] ?? null, + 'paymentMethodNonce' => $attributes['paymentMethodNonce'], + 'status' => 'authorized', + 'type' => 'sale', + ]); + } + + /** + * Generate fake Braintree card details + * + * @return array + * @throws \Magento\Framework\Exception\LocalizedException + */ + private function generateCardDetails(): array + { + return [ + 'bin' => $this->random->getRandomString(6), + 'cardType' => 'Visa', + 'expirationMonth' => '12', + 'expirationYear' => '2020', //TODO: make dynamic + 'last4' => (string) random_int(1000, 9999), + 'token' => $this->random->getRandomString(6), + 'uniqueNumberIdentifier' => $this->random->getRandomString(32), + ]; + } + + /** + * Create fake Braintree nonce + * + * @return \Braintree\PaymentMethodNonce + * @throws \Magento\Framework\Exception\LocalizedException + */ + private function createNonce(): \Braintree\PaymentMethodNonce + { + $lastFour = (string) random_int(1000, 9999); + $lastTwo = substr($lastFour, -2); + return \Braintree\PaymentMethodNonce::factory([ + 'consumed' => false, + 'default' => true, + 'description' => 'ending in ' . $lastTwo, + 'details' => [ + 'bin' => $this->random->getRandomString(6), + 'cardType' => 'Visa', + 'lastFour' => $lastFour, + 'lastTwo' => $lastTwo, + ], + 'hasSubscription' => false, + 'isLocked' => false, + 'nonce' => $this->random->getRandomString(36), + 'type' => 'CreditCard' + ]); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModuleBraintree/etc/di.xml b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/etc/di.xml new file mode 100644 index 000000000000..db5c13684068 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/etc/di.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/dev/tests/api-functional/_files/Magento/TestModuleBraintree/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/etc/module.xml new file mode 100644 index 000000000000..22df4e5fe7ea --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/etc/module.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/dev/tests/api-functional/_files/Magento/TestModuleBraintree/registration.php b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/registration.php new file mode 100644 index 000000000000..c95e68f3f48f --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/registration.php @@ -0,0 +1,11 @@ +getPath(ComponentRegistrar::MODULE, 'Magento_TestModuleBraintree') === null) { + ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magento_TestModuleBraintree', __DIR__); +} diff --git a/dev/tests/api-functional/phpunit_graphql.xml.dist b/dev/tests/api-functional/phpunit_graphql.xml.dist index f8e075390adb..aa1899d88f48 100644 --- a/dev/tests/api-functional/phpunit_graphql.xml.dist +++ b/dev/tests/api-functional/phpunit_graphql.xml.dist @@ -47,10 +47,6 @@ - - - - diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php index 2cfcd9c11ec5..39efff59d94c 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php @@ -126,7 +126,7 @@ public function testPlaceOrder() * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php - * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/add_simple_product_qty_one.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php @@ -166,7 +166,7 @@ public function testPlaceOrderSaveInVault() * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php - * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/add_simple_product_qty_three.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/add_simple_product_qty_one.php b/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/add_simple_product_qty_one.php deleted file mode 100644 index 52e9f61730cd..000000000000 --- a/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/add_simple_product_qty_one.php +++ /dev/null @@ -1,28 +0,0 @@ -get(ProductRepositoryInterface::class); -/** @var QuoteFactory $quoteFactory */ -$quoteFactory = Bootstrap::getObjectManager()->get(QuoteFactory::class); -/** @var QuoteResource $quoteResource */ -$quoteResource = Bootstrap::getObjectManager()->get(QuoteResource::class); -/** @var CartRepositoryInterface $cartRepository */ -$cartRepository = Bootstrap::getObjectManager()->get(CartRepositoryInterface::class); - -$product = $productRepository->get('simple_product'); - -$quote = $quoteFactory->create(); -$quoteResource->load($quote, 'test_quote', 'reserved_order_id'); -$quote->addProduct($product, 1); -$cartRepository->save($quote); diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/add_simple_product_qty_three.php b/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/add_simple_product_qty_three.php deleted file mode 100644 index e85e95f5beb7..000000000000 --- a/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/add_simple_product_qty_three.php +++ /dev/null @@ -1,28 +0,0 @@ -get(ProductRepositoryInterface::class); -/** @var QuoteFactory $quoteFactory */ -$quoteFactory = Bootstrap::getObjectManager()->get(QuoteFactory::class); -/** @var QuoteResource $quoteResource */ -$quoteResource = Bootstrap::getObjectManager()->get(QuoteResource::class); -/** @var CartRepositoryInterface $cartRepository */ -$cartRepository = Bootstrap::getObjectManager()->get(CartRepositoryInterface::class); - -$product = $productRepository->get('simple_product'); - -$quote = $quoteFactory->create(); -$quoteResource->load($quote, 'test_quote', 'reserved_order_id'); -$quote->addProduct($product, 3); -$cartRepository->save($quote); From 5f25fddd40dd9d0c4b2bc8fdf2044a67dec425f1 Mon Sep 17 00:00:00 2001 From: Patrick McLain Date: Tue, 18 Jun 2019 19:06:18 -0400 Subject: [PATCH 04/17] fix static test failures --- .../Model/BraintreeDataProvider.php | 12 +++ .../Model/BraintreeVaultDataProvider.php | 12 +++ .../Magento/BraintreeGraphQl/composer.json | 3 +- composer.json | 1 + composer.lock | 4 +- .../Model/Adapter/BraintreeAdapter.php | 7 +- .../Model/MockResponseDataProvider.php | 73 ++++++++++--------- .../Customer/SetPaymentMethodTest.php | 40 +++++----- .../Braintree/Guest/SetPaymentMethodTest.php | 3 + .../GraphQl/Braintree/_files/payments.php | 6 +- .../GraphQl/Braintree/_files/token.php | 22 +++--- .../GraphQl/Query/QueryProcessor.php | 2 +- 12 files changed, 110 insertions(+), 75 deletions(-) diff --git a/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php b/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php index 96da041532b0..bc4dd8a47896 100644 --- a/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php +++ b/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php @@ -10,6 +10,9 @@ use Magento\QuoteGraphQl\Model\Cart\Payment\AdditionalDataProviderInterface; use Magento\Framework\Stdlib\ArrayManager; +/** + * Format Braintree input into value expected when setting payment method + */ class BraintreeDataProvider implements AdditionalDataProviderInterface { private const PATH_ADDITIONAL_DATA = 'input/payment_method/additional_data/braintree'; @@ -19,12 +22,21 @@ class BraintreeDataProvider implements AdditionalDataProviderInterface */ private $arrayManager; + /** + * @param ArrayManager $arrayManager + */ public function __construct( ArrayManager $arrayManager ) { $this->arrayManager = $arrayManager; } + /** + * Format Braintree input into value expected when setting payment method + * + * @param array $args + * @return array + */ public function getData(array $args): array { return $this->arrayManager->get(static::PATH_ADDITIONAL_DATA, $args) ?? []; diff --git a/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php b/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php index 95c7b4839ded..7fc65ad5da46 100644 --- a/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php +++ b/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php @@ -10,6 +10,9 @@ use Magento\QuoteGraphQl\Model\Cart\Payment\AdditionalDataProviderInterface; use Magento\Framework\Stdlib\ArrayManager; +/** + * Format Braintree input into value expected when setting payment method + */ class BraintreeVaultDataProvider implements AdditionalDataProviderInterface { private const PATH_ADDITIONAL_DATA = 'input/payment_method/additional_data/braintree_cc_vault'; @@ -19,12 +22,21 @@ class BraintreeVaultDataProvider implements AdditionalDataProviderInterface */ private $arrayManager; + /** + * @param ArrayManager $arrayManager + */ public function __construct( ArrayManager $arrayManager ) { $this->arrayManager = $arrayManager; } + /** + * Format Braintree input into value expected when setting payment method + * + * @param array $args + * @return array + */ public function getData(array $args): array { return $this->arrayManager->get(static::PATH_ADDITIONAL_DATA, $args) ?? []; diff --git a/app/code/Magento/BraintreeGraphQl/composer.json b/app/code/Magento/BraintreeGraphQl/composer.json index a322db9d257d..27537598052c 100644 --- a/app/code/Magento/BraintreeGraphQl/composer.json +++ b/app/code/Magento/BraintreeGraphQl/composer.json @@ -4,7 +4,8 @@ "type": "magento2-module", "require": { "php": "~7.1.3||~7.2.0", - "magento/framework": "*" + "magento/framework": "*", + "magento/module-quote-graph-ql": "*" }, "suggest": { "magento/module-graph-ql": "*" diff --git a/composer.json b/composer.json index a1323796ed4d..5d3a47b0ec31 100644 --- a/composer.json +++ b/composer.json @@ -112,6 +112,7 @@ "magento/module-backend": "*", "magento/module-backup": "*", "magento/module-braintree": "*", + "magento/module-braintree-graph-ql": "*", "magento/module-bundle": "*", "magento/module-bundle-graph-ql": "*", "magento/module-bundle-import-export": "*", diff --git a/composer.lock b/composer.lock index 5454994ca82d..017cd0e67001 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "912e04a44c38c8918799bd01b828fba0", + "content-hash": "462d9da112f33e2cb9f9e26faa0fe233", "packages": [ { "name": "braintree/braintree_php", @@ -2169,7 +2169,7 @@ }, { "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" + "email": "backendtea@gmail.com" } ], "description": "Symfony polyfill for ctype functions", diff --git a/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/Adapter/BraintreeAdapter.php b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/Adapter/BraintreeAdapter.php index b6f855f5c2f1..5895cf929a58 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/Adapter/BraintreeAdapter.php +++ b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/Adapter/BraintreeAdapter.php @@ -22,11 +22,6 @@ */ class BraintreeAdapter extends \Magento\Braintree\Model\Adapter\BraintreeAdapter { - /** - * @var Config - */ - private $config; - /** * @var MockResponseDataProvider */ @@ -56,7 +51,7 @@ public function __construct( */ public function createNonce($token) { - return $this->mockResponseDataProvider->generateMockNonceResponse(); + return $this->mockResponseDataProvider->generateMockNonceResponse($token); } /** diff --git a/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/MockResponseDataProvider.php b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/MockResponseDataProvider.php index 7355fa3d97f6..9598f9d0415c 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/MockResponseDataProvider.php +++ b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/MockResponseDataProvider.php @@ -44,11 +44,12 @@ public function generateMockSaleResponse(array $attributes): \Braintree\Instance /** * Create mock nonce response for testing * + * @param string $token * @return \Braintree\Instance */ - public function generateMockNonceResponse(): \Braintree\Instance + public function generateMockNonceResponse(string $token): \Braintree\Instance { - $nonce = $this->createNonce(); + $nonce = $this->createNonce($token); return new \Braintree\Result\Successful($nonce, 'paymentMethodNonce'); } @@ -63,21 +64,23 @@ public function generateMockNonceResponse(): \Braintree\Instance private function createTransaction(array $attributes): \Braintree\Transaction { $creditCardInfo = $this->generateCardDetails(); - return \Braintree\Transaction::factory([ - 'amount' => $attributes['amount'], - 'billing' => $attributes['billing'] ?? null, - 'creditCard' => $creditCardInfo, - 'cardDetails' => new \Braintree\Transaction\CreditCardDetails($creditCardInfo), - 'currencyIsoCode' => 'USD', - 'customer' => $attributes['customer'], - 'cvvResponseCode' => 'M', - 'id' => $this->random->getRandomString(8), - 'options' => $attributes['options'] ?? null, - 'shipping' => $attributes['shipping'] ?? null, - 'paymentMethodNonce' => $attributes['paymentMethodNonce'], - 'status' => 'authorized', - 'type' => 'sale', - ]); + return \Braintree\Transaction::factory( + [ + 'amount' => $attributes['amount'], + 'billing' => $attributes['billing'] ?? null, + 'creditCard' => $creditCardInfo, + 'cardDetails' => new \Braintree\Transaction\CreditCardDetails($creditCardInfo), + 'currencyIsoCode' => 'USD', + 'customer' => $attributes['customer'], + 'cvvResponseCode' => 'M', + 'id' => $this->random->getRandomString(8), + 'options' => $attributes['options'] ?? null, + 'shipping' => $attributes['shipping'] ?? null, + 'paymentMethodNonce' => $attributes['paymentMethodNonce'], + 'status' => 'authorized', + 'type' => 'sale', + ] + ); } /** @@ -102,27 +105,31 @@ private function generateCardDetails(): array /** * Create fake Braintree nonce * + * @param string $token * @return \Braintree\PaymentMethodNonce * @throws \Magento\Framework\Exception\LocalizedException */ - private function createNonce(): \Braintree\PaymentMethodNonce + private function createNonce(string $token): \Braintree\PaymentMethodNonce { $lastFour = (string) random_int(1000, 9999); $lastTwo = substr($lastFour, -2); - return \Braintree\PaymentMethodNonce::factory([ - 'consumed' => false, - 'default' => true, - 'description' => 'ending in ' . $lastTwo, - 'details' => [ - 'bin' => $this->random->getRandomString(6), - 'cardType' => 'Visa', - 'lastFour' => $lastFour, - 'lastTwo' => $lastTwo, - ], - 'hasSubscription' => false, - 'isLocked' => false, - 'nonce' => $this->random->getRandomString(36), - 'type' => 'CreditCard' - ]); + return \Braintree\PaymentMethodNonce::factory( + [ + 'bin' => $token, + 'consumed' => false, + 'default' => true, + 'description' => 'ending in ' . $lastTwo, + 'details' => [ + 'bin' => $this->random->getRandomString(6), + 'cardType' => 'Visa', + 'lastFour' => $lastFour, + 'lastTwo' => $lastTwo, + ], + 'hasSubscription' => false, + 'isLocked' => false, + 'nonce' => $this->random->getRandomString(36), + 'type' => 'CreditCard' + ] + ); } } diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php index 39efff59d94c..5ce2df305f50 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php @@ -18,14 +18,11 @@ use Magento\Vault\Model\ResourceModel\PaymentToken; use Magento\Vault\Model\ResourceModel\PaymentToken\CollectionFactory as TokenCollectionFactory; +/** + * Test setting payment method and placing order with Braintree + */ class SetPaymentMethodTest extends GraphQlAbstract { - private const REQUIRED_CONSTS = [ - 'TESTS_BRAINTREE_MERCHANT_ID', - 'TESTS_BRAINTREE_PUBLIC_KEY', - 'TESTS_BRAINTREE_PRIVATE_KEY', - ]; - /** * @var CustomerTokenServiceInterface */ @@ -71,12 +68,6 @@ class SetPaymentMethodTest extends GraphQlAbstract */ protected function setUp() { - foreach (static::REQUIRED_CONSTS as $const) { - if (!defined($const)) { - $this->markTestSkipped('Braintree sandbox credentials must be defined in phpunit_graphql.xml.dist'); - } - } - $objectManager = Bootstrap::getObjectManager(); $this->getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class); $this->customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class); @@ -178,13 +169,20 @@ public function testPlaceOrderWithVault() $reservedOrderId = 'test_quote'; $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId); - $nonceResult = $this->getNonceCommand->execute([ - 'customer_id' => 1, - 'public_hash' => 'braintree_public_hash', - ]); + $nonceResult = $this->getNonceCommand->execute( + [ + 'customer_id' => 1, + 'public_hash' => 'braintree_public_hash', + ] + ); $nonce = $nonceResult->get()['paymentMethodNonce']; - $setPaymentQuery = $this->getSetPaymentBraintreeVaultQuery($maskedQuoteId, 'braintree_public_hash', $nonce, true); + $setPaymentQuery = $this->getSetPaymentBraintreeVaultQuery( + $maskedQuoteId, + 'braintree_public_hash', + $nonce, + true + ); $setPaymentResponse = $this->graphQlMutation($setPaymentQuery, [], '', $this->getHeaderMap()); $this->assertSetPaymentMethodResponse($setPaymentResponse, 'braintree_cc_vault'); @@ -251,8 +249,12 @@ private function getSetPaymentBraintreeQuery(string $maskedQuoteId, bool $saveIn * @param bool $saveInVault * @return string */ - private function getSetPaymentBraintreeVaultQuery(string $maskedQuoteId, string $publicHash, string $nonce, bool $saveInVault = false): string - { + private function getSetPaymentBraintreeVaultQuery( + string $maskedQuoteId, + string $publicHash, + string $nonce, + bool $saveInVault = false + ): string { $saveInVault = json_encode($saveInVault); return << defined('TESTS_BRAINTREE_MERCHANT_ID') ? TESTS_BRAINTREE_MERCHANT_ID : 'def_merchant_id', - 'payment/braintree/public_key' => $encryptor->encrypt(defined('TESTS_BRAINTREE_PUBLIC_KEY') ? TESTS_BRAINTREE_PUBLIC_KEY : 'def_public_key'), - 'payment/braintree/private_key' => $encryptor->encrypt(defined('TESTS_BRAINTREE_PRIVATE_KEY') ? TESTS_BRAINTREE_PRIVATE_KEY : 'def_private_key'), + 'payment/braintree/merchant_id' => 'def_merchant_id', + 'payment/braintree/public_key' => $encryptor->encrypt('def_public_key'), + 'payment/braintree/private_key' => $encryptor->encrypt('def_private_key'), 'payment/' . ConfigProvider::CODE . '/active' => '1', 'payment/' . ConfigProvider::CC_VAULT_CODE . '/active' => '1', 'payment/' . ConfigProvider::CODE . '/environment' => 'sandbox', diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/token.php b/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/token.php index bdfd9902f070..4694ddf99fad 100644 --- a/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/token.php +++ b/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/token.php @@ -24,16 +24,18 @@ $adapterFactory = $objectManager->get(\Magento\Braintree\Model\Adapter\BraintreeAdapterFactory::class); $adapter = $adapterFactory->create(); -$result = $adapter->sale([ - 'amount' => '0.01', - 'customer' => [ - 'email' => 'customer@example.com', - 'firstName' => 'John', - 'lastName' => 'Smith' - ], - 'options' => ['storeInVaultOnSuccess' => true], - 'paymentMethodNonce' => 'fake-valid-nonce', -]); +$result = $adapter->sale( + [ + 'amount' => '0.01', + 'customer' => [ + 'email' => 'customer@example.com', + 'firstName' => 'John', + 'lastName' => 'Smith' + ], + 'options' => ['storeInVaultOnSuccess' => true], + 'paymentMethodNonce' => 'fake-valid-nonce', + ] +); $braintreeToken = $result->transaction->creditCardDetails->token; diff --git a/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php b/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php index 0a0dba36ef0e..a797a1c0e7dd 100644 --- a/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php +++ b/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php @@ -69,7 +69,7 @@ public function process( $operationName )->toArray( $this->exceptionFormatter->shouldShowDetail() ? - \GraphQL\Error\Debug::INCLUDE_DEBUG_MESSAGE : false + \GraphQL\Error\Debug::INCLUDE_DEBUG_MESSAGE : true ); } } From 05632a8c477e9987cd51623e50bd4de9b9e829f2 Mon Sep 17 00:00:00 2001 From: Patrick McLain Date: Thu, 27 Jun 2019 21:57:04 -0400 Subject: [PATCH 05/17] Move Method Specific input into PaymentMethodInput --- .../Model/BraintreeDataProvider.php | 2 +- .../Model/BraintreeVaultDataProvider.php | 2 +- .../BraintreeGraphQl/etc/schema.graphqls | 2 +- .../Model/Cart/SetPaymentMethodOnCart.php | 15 ++++---- .../Customer/SetPaymentMethodTest.php | 26 ++++++-------- .../Braintree/Guest/SetPaymentMethodTest.php | 22 +++--------- .../_files/enable_braintree_payment.php | 35 ++++++++++++++++++ .../enable_braintree_payment_rollback.php | 31 ++++++++++++++++ .../GraphQl/Braintree/_files/payments.php | 36 ------------------- .../GraphQl/Braintree/_files/token.php | 11 ------ 10 files changed, 90 insertions(+), 92 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/enable_braintree_payment.php create mode 100644 dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/enable_braintree_payment_rollback.php delete mode 100644 dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/payments.php diff --git a/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php b/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php index bc4dd8a47896..9227d7877da2 100644 --- a/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php +++ b/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php @@ -15,7 +15,7 @@ */ class BraintreeDataProvider implements AdditionalDataProviderInterface { - private const PATH_ADDITIONAL_DATA = 'input/payment_method/additional_data/braintree'; + private const PATH_ADDITIONAL_DATA = 'braintree'; /** * @var ArrayManager diff --git a/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php b/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php index 7fc65ad5da46..0b7a0965b086 100644 --- a/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php +++ b/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php @@ -15,7 +15,7 @@ */ class BraintreeVaultDataProvider implements AdditionalDataProviderInterface { - private const PATH_ADDITIONAL_DATA = 'input/payment_method/additional_data/braintree_cc_vault'; + private const PATH_ADDITIONAL_DATA = 'braintree_cc_vault'; /** * @var ArrayManager diff --git a/app/code/Magento/BraintreeGraphQl/etc/schema.graphqls b/app/code/Magento/BraintreeGraphQl/etc/schema.graphqls index c1cf93bf9f93..f00fff7f19d8 100644 --- a/app/code/Magento/BraintreeGraphQl/etc/schema.graphqls +++ b/app/code/Magento/BraintreeGraphQl/etc/schema.graphqls @@ -1,7 +1,7 @@ # Copyright © Magento, Inc. All rights reserved. # See COPYING.txt for license details. -input PaymentMethodAdditionalDataInput { +input PaymentMethodInput { braintree: BraintreeInput braintree_cc_vault: BraintreeCcVaultInput } diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/SetPaymentMethodOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Cart/SetPaymentMethodOnCart.php index ceaebf19e0e0..4deb794761ef 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/SetPaymentMethodOnCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/SetPaymentMethodOnCart.php @@ -68,18 +68,15 @@ public function execute(Quote $cart, array $paymentData): void $paymentMethodCode = $paymentData['code']; $poNumber = $paymentData['purchase_order_number'] ?? null; - $additionalData = isset($paymentData['additional_data']) - ? $this->additionalDataProviderPool->getData($paymentMethodCode, $paymentData['additional_data']) - : []; + $additionalData = $this->additionalDataProviderPool->getData($paymentMethodCode, $paymentData); $payment = $this->paymentFactory->create( [ - 'data' => - [ - PaymentInterface::KEY_METHOD => $paymentMethodCode, - PaymentInterface::KEY_PO_NUMBER => $poNumber, - PaymentInterface::KEY_ADDITIONAL_DATA => $additionalData, - ], + 'data' => [ + PaymentInterface::KEY_METHOD => $paymentMethodCode, + PaymentInterface::KEY_PO_NUMBER => $poNumber, + PaymentInterface::KEY_ADDITIONAL_DATA => $additionalData, + ], ] ); diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php index 5ce2df305f50..e9cca64c9650 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php @@ -88,7 +88,7 @@ protected function setUp() * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php - * @magentoApiDataFixture Magento/Graphql/Braintree/_files/payments.php + * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/enable_braintree_payment.php */ public function testPlaceOrder() { @@ -121,7 +121,7 @@ public function testPlaceOrder() * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php - * @magentoApiDataFixture Magento/Graphql/Braintree/_files/payments.php + * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/enable_braintree_payment.php */ public function testPlaceOrderSaveInVault() { @@ -161,8 +161,8 @@ public function testPlaceOrderSaveInVault() * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php - * @magentoApiDataFixture Magento/Graphql/Braintree/_files/payments.php - * @magentoApiDataFixture Magento/Graphql/Braintree/_files/token.php + * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/enable_braintree_payment.php + * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/token.php */ public function testPlaceOrderWithVault() { @@ -224,11 +224,9 @@ private function getSetPaymentBraintreeQuery(string $maskedQuoteId, bool $saveIn cart_id:"{$maskedQuoteId}" payment_method:{ code:"braintree" - additional_data:{ - braintree:{ - is_active_payment_token_enabler:{$saveInVault} - payment_method_nonce:"fake-valid-nonce" - } + braintree:{ + is_active_payment_token_enabler:{$saveInVault} + payment_method_nonce:"fake-valid-nonce" } } }) { @@ -262,12 +260,10 @@ private function getSetPaymentBraintreeVaultQuery( cart_id:"{$maskedQuoteId}" payment_method:{ code:"braintree_cc_vault" - additional_data:{ - braintree_cc_vault:{ - is_active_payment_token_enabler:{$saveInVault} - payment_method_nonce:"{$nonce}" - public_hash:"{$publicHash}" - } + braintree_cc_vault:{ + is_active_payment_token_enabler:{$saveInVault} + payment_method_nonce:"{$nonce}" + public_hash:"{$publicHash}" } } }) { diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Guest/SetPaymentMethodTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Guest/SetPaymentMethodTest.php index 9302ed237b3f..2c6ed205cbea 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Guest/SetPaymentMethodTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Guest/SetPaymentMethodTest.php @@ -20,12 +20,6 @@ */ class SetPaymentMethodTest extends GraphQlAbstract { - private const REQUIRED_CONSTS = [ - 'TESTS_BRAINTREE_MERCHANT_ID', - 'TESTS_BRAINTREE_PUBLIC_KEY', - 'TESTS_BRAINTREE_PRIVATE_KEY', - ]; - /** * @var CustomerTokenServiceInterface */ @@ -56,12 +50,6 @@ class SetPaymentMethodTest extends GraphQlAbstract */ protected function setUp() { - foreach (static::REQUIRED_CONSTS as $const) { - if (!defined($const)) { - $this->markTestSkipped('Braintree sandbox credentials must be defined in phpunit_graphql.xml.dist'); - } - } - $objectManager = Bootstrap::getObjectManager(); $this->getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class); $this->customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class); @@ -79,7 +67,7 @@ protected function setUp() * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php - * @magentoApiDataFixture Magento/Graphql/Braintree/_files/payments.php + * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/enable_braintree_payment.php */ public function testPlaceOrder() { @@ -126,11 +114,9 @@ private function getSetPaymentBraintreeQuery(string $maskedQuoteId): string cart_id:"{$maskedQuoteId}" payment_method:{ code:"braintree" - additional_data:{ - braintree:{ - is_active_payment_token_enabler:false - payment_method_nonce:"fake-valid-nonce" - } + braintree:{ + is_active_payment_token_enabler:false + payment_method_nonce:"fake-valid-nonce" } } }) { diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/enable_braintree_payment.php b/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/enable_braintree_payment.php new file mode 100644 index 000000000000..b91259376bed --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/enable_braintree_payment.php @@ -0,0 +1,35 @@ +get(WriterInterface::class); +/** @var EncryptorInterface $encryptor */ +$encryptor = $objectManager->get(EncryptorInterface::class); + +/** @var $mutableScopeConfig */ +$mutableScopeConfig = $objectManager->get( + \Magento\Framework\App\Config\MutableScopeConfigInterface::class +); + +$configWriter->save('payment/' . ConfigProvider::CODE . '/merchant_id', 'def_merchant_id'); +$configWriter->save('payment/' . ConfigProvider::CODE . '/public_key', $encryptor->encrypt('def_public_key')); +$configWriter->save('payment/' . ConfigProvider::CODE . '/private_key', $encryptor->encrypt('def_private_key')); +$configWriter->save('payment/' . ConfigProvider::CODE . '/active', '1'); +$configWriter->save('payment/' . ConfigProvider::CODE . '/environment', 'sandbox'); +$configWriter->save('payment/' . ConfigProvider::CC_VAULT_CODE . '/active', '1'); + +$scopeConfig = $objectManager->get(ScopeConfigInterface::class); +$scopeConfig->clean(); diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/enable_braintree_payment_rollback.php b/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/enable_braintree_payment_rollback.php new file mode 100644 index 000000000000..7b4e187c6717 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/enable_braintree_payment_rollback.php @@ -0,0 +1,31 @@ +get(WriterInterface::class); +/** @var EncryptorInterface $encryptor */ +$encryptor = $objectManager->get(EncryptorInterface::class); + +/** @var $mutableScopeConfig */ +$mutableScopeConfig = $objectManager->get( + \Magento\Framework\App\Config\MutableScopeConfigInterface::class +); + +$configWriter->delete('payment/' . ConfigProvider::CODE . '/merchant_id'); +$configWriter->delete('payment/' . ConfigProvider::CODE . '/public_key'); +$configWriter->delete('payment/' . ConfigProvider::CODE . '/private_key'); +$configWriter->delete('payment/' . ConfigProvider::CODE . '/active'); +$configWriter->delete('payment/' . ConfigProvider::CODE . '/environment'); +$configWriter->delete('payment/' . ConfigProvider::CC_VAULT_CODE . '/active'); diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/payments.php b/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/payments.php deleted file mode 100644 index b66332e714f4..000000000000 --- a/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/payments.php +++ /dev/null @@ -1,36 +0,0 @@ -get(EncryptorInterface::class); - -$processConfigData = function (Config $config, array $data) { - foreach ($data as $key => $value) { - $config->setDataByPath($key, $value); - $config->save(); - } -}; - -// save payment configuration for the default scope -$configData = [ - 'payment/braintree/merchant_id' => 'def_merchant_id', - 'payment/braintree/public_key' => $encryptor->encrypt('def_public_key'), - 'payment/braintree/private_key' => $encryptor->encrypt('def_private_key'), - 'payment/' . ConfigProvider::CODE . '/active' => '1', - 'payment/' . ConfigProvider::CC_VAULT_CODE . '/active' => '1', - 'payment/' . ConfigProvider::CODE . '/environment' => 'sandbox', -]; -/** @var Config $defConfig */ -$defConfig = $objectManager->create(Config::class); -$defConfig->setScope(ScopeConfigInterface::SCOPE_TYPE_DEFAULT); -$processConfigData($defConfig, $configData); diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/token.php b/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/token.php index 4694ddf99fad..8164e6d33e24 100644 --- a/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/token.php +++ b/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/token.php @@ -8,17 +8,6 @@ use Magento\Vault\Model\PaymentToken; use Magento\Vault\Model\PaymentTokenRepository; -$requiredConst = [ - 'TESTS_BRAINTREE_MERCHANT_ID', - 'TESTS_BRAINTREE_PUBLIC_KEY', - 'TESTS_BRAINTREE_PRIVATE_KEY', -]; -foreach ($requiredConst as $const) { - if (!defined($const)) { - return; - } -} - $objectManager = Bootstrap::getObjectManager(); $adapterFactory = $objectManager->get(\Magento\Braintree\Model\Adapter\BraintreeAdapterFactory::class); From 3720ec0ba2daec0c6ed777deb80b7b670b94b231 Mon Sep 17 00:00:00 2001 From: Patrick McLain Date: Mon, 8 Jul 2019 12:53:24 -0400 Subject: [PATCH 06/17] Revert error reporting change committed by mistake --- lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php b/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php index a797a1c0e7dd..0a0dba36ef0e 100644 --- a/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php +++ b/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php @@ -69,7 +69,7 @@ public function process( $operationName )->toArray( $this->exceptionFormatter->shouldShowDetail() ? - \GraphQL\Error\Debug::INCLUDE_DEBUG_MESSAGE : true + \GraphQL\Error\Debug::INCLUDE_DEBUG_MESSAGE : false ); } } From a6e32e8f7475f3e375e137da1378a4743ef6aedc Mon Sep 17 00:00:00 2001 From: Patrick McLain Date: Tue, 9 Jul 2019 15:05:15 -0400 Subject: [PATCH 07/17] Mutation for creating braintree client token This token is required by the sdk when creating nonces client-side --- .../Resolver/CreateBraintreeClientToken.php | 78 +++++++++++++++++++ .../BraintreeGraphQl/etc/schema.graphqls | 4 + .../Model/Adapter/BraintreeAdapter.php | 9 +++ .../Model/MockResponseDataProvider.php | 10 +++ .../CreateBraintreeClientTokenTest.php | 49 ++++++++++++ 5 files changed, 150 insertions(+) create mode 100644 app/code/Magento/BraintreeGraphQl/Model/Resolver/CreateBraintreeClientToken.php create mode 100644 dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/CreateBraintreeClientTokenTest.php diff --git a/app/code/Magento/BraintreeGraphQl/Model/Resolver/CreateBraintreeClientToken.php b/app/code/Magento/BraintreeGraphQl/Model/Resolver/CreateBraintreeClientToken.php new file mode 100644 index 000000000000..d13dc91d6482 --- /dev/null +++ b/app/code/Magento/BraintreeGraphQl/Model/Resolver/CreateBraintreeClientToken.php @@ -0,0 +1,78 @@ +storeManager = $storeManager; + $this->config = $config; + $this->adapterFactory = $adapterFactory; + } + + /** + * @inheritdoc + */ + public function resolve( + Field $field, + $context, + ResolveInfo $info, + array $value = null, + array $args = null + ) { + $storeId = $this->storeManager->getStore()->getId(); + + if (!$this->config->isActive($storeId)) { + throw new GraphQlInputException(__('The Braintree payment method is not active.')); + } + + $params = []; + $merchantAccountId = $this->config->getMerchantAccountId($storeId); + if (!empty($merchantAccountId)) { + $params[PaymentDataBuilder::MERCHANT_ACCOUNT_ID] = $merchantAccountId; + } + + return $this->adapterFactory->create($storeId)->generate($params); + } +} diff --git a/app/code/Magento/BraintreeGraphQl/etc/schema.graphqls b/app/code/Magento/BraintreeGraphQl/etc/schema.graphqls index f00fff7f19d8..fc24211ec0bc 100644 --- a/app/code/Magento/BraintreeGraphQl/etc/schema.graphqls +++ b/app/code/Magento/BraintreeGraphQl/etc/schema.graphqls @@ -1,6 +1,10 @@ # Copyright © Magento, Inc. All rights reserved. # See COPYING.txt for license details. +type Mutation { + createBraintreeClientToken: String! @resolver(class: "\\Magento\\BraintreeGraphQl\\Model\\Resolver\\CreateBraintreeClientToken") @doc(description:"Creates Braintree Client Token for creating client-side nonce.") +} + input PaymentMethodInput { braintree: BraintreeInput braintree_cc_vault: BraintreeCcVaultInput diff --git a/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/Adapter/BraintreeAdapter.php b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/Adapter/BraintreeAdapter.php index 5895cf929a58..d8f5c8627960 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/Adapter/BraintreeAdapter.php +++ b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/Adapter/BraintreeAdapter.php @@ -62,4 +62,13 @@ public function sale(array $attributes) { return $this->mockResponseDataProvider->generateMockSaleResponse($attributes); } + + /** + * @param array $params + * @return string|\Braintree\Result\Error + */ + public function generate(array $params = []) + { + return $this->mockResponseDataProvider->generateMockClientToken(); + } } diff --git a/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/MockResponseDataProvider.php b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/MockResponseDataProvider.php index 9598f9d0415c..9149d9ac637d 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/MockResponseDataProvider.php +++ b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/MockResponseDataProvider.php @@ -54,6 +54,16 @@ public function generateMockNonceResponse(string $token): \Braintree\Instance return new \Braintree\Result\Successful($nonce, 'paymentMethodNonce'); } + /** + * Create mock client token + * + * @return string + */ + public function generateMockClientToken(): string + { + return $this->random->getRandomString(32); + } + /** * Create Braintree transaction from provided request attributes * diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/CreateBraintreeClientTokenTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/CreateBraintreeClientTokenTest.php new file mode 100644 index 000000000000..b83041e31b14 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/CreateBraintreeClientTokenTest.php @@ -0,0 +1,49 @@ +graphQlMutation($this->getMutation()); + + self::assertArrayHasKey('createBraintreeClientToken', $response); + self::assertNotEmpty($response['createBraintreeClientToken']); + } + + /** + * Test creating Braintree client token when method is disabled + * + * @expectedException \Exception + * @expectedExceptionMessage payment method is not active + */ + public function testCreateBraintreeClientTokenNotActive() + { + $this->graphQlMutation($this->getMutation()); + } + + private function getMutation(): string + { + return << Date: Tue, 9 Jul 2019 17:26:32 -0400 Subject: [PATCH 08/17] Generate nonce from public hash server-side This simplifies the implementation requirements when setting the payment method to Braintree Vault. In the current frontend implementation the nonce is created server-side, but using an ajax request when the place order button is activated. The current storefront flow executes: 1. User selects vault method and places order 2. Ajax request with public hash is made to server returning the nonce 3. Nonce is submitted with order placement request in payment details The second step is uncessecary and is removed from the graphql flow with this commit. --- .../Plugin/SetVaultPaymentNonce.php | 76 +++++++++++++++++++ .../Magento/BraintreeGraphQl/composer.json | 3 + .../BraintreeGraphQl/etc/graphql/di.xml | 3 + .../BraintreeGraphQl/etc/schema.graphqls | 2 - .../Model/Adapter/BraintreeAdapter.php | 1 + .../Model/MockResponseDataProvider.php | 20 ++++- .../Customer/SetPaymentMethodTest.php | 21 +---- 7 files changed, 103 insertions(+), 23 deletions(-) create mode 100644 app/code/Magento/BraintreeGraphQl/Plugin/SetVaultPaymentNonce.php diff --git a/app/code/Magento/BraintreeGraphQl/Plugin/SetVaultPaymentNonce.php b/app/code/Magento/BraintreeGraphQl/Plugin/SetVaultPaymentNonce.php new file mode 100644 index 000000000000..b8294f1a1352 --- /dev/null +++ b/app/code/Magento/BraintreeGraphQl/Plugin/SetVaultPaymentNonce.php @@ -0,0 +1,76 @@ +command = $command; + $this->logger = $logger; + } + + /** + * Set Braintree nonce from public hash + * + * @param \Magento\QuoteGraphQl\Model\Cart\SetPaymentMethodOnCart $subject + * @param \Magento\Quote\Model\Quote $quote + * @param array $paymentData + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function beforeExecute( + \Magento\QuoteGraphQl\Model\Cart\SetPaymentMethodOnCart $subject, + \Magento\Quote\Model\Quote $quote, + array $paymentData + ): array { + if ($paymentData['code'] !== ConfigProvider::CC_VAULT_CODE) { + return [$quote, $paymentData]; + } + + $subject = [ + 'public_hash' => $paymentData[ConfigProvider::CC_VAULT_CODE]['public_hash'], + 'customer_id' => $quote->getCustomerId(), + 'store_id' => $quote->getStoreId(), + ]; + + try { + $result = $this->command->execute($subject)->get(); + $paymentData[ConfigProvider::CC_VAULT_CODE]['payment_method_nonce'] = $result['paymentMethodNonce']; + } catch (\Exception $e) { + $this->logger->critical($e); + throw new GraphQlInputException(__('Sorry, but something went wrong')); + } + + return [$quote, $paymentData]; + } +} diff --git a/app/code/Magento/BraintreeGraphQl/composer.json b/app/code/Magento/BraintreeGraphQl/composer.json index 27537598052c..7f06b34353be 100644 --- a/app/code/Magento/BraintreeGraphQl/composer.json +++ b/app/code/Magento/BraintreeGraphQl/composer.json @@ -5,6 +5,9 @@ "require": { "php": "~7.1.3||~7.2.0", "magento/framework": "*", + "magento/module-braintree": "*", + "magento/module-store": "*", + "magento/module-quote": "*", "magento/module-quote-graph-ql": "*" }, "suggest": { diff --git a/app/code/Magento/BraintreeGraphQl/etc/graphql/di.xml b/app/code/Magento/BraintreeGraphQl/etc/graphql/di.xml index 1f3ee1a1eeda..a31066316377 100644 --- a/app/code/Magento/BraintreeGraphQl/etc/graphql/di.xml +++ b/app/code/Magento/BraintreeGraphQl/etc/graphql/di.xml @@ -14,4 +14,7 @@ + + + diff --git a/app/code/Magento/BraintreeGraphQl/etc/schema.graphqls b/app/code/Magento/BraintreeGraphQl/etc/schema.graphqls index fc24211ec0bc..0492f8aaf989 100644 --- a/app/code/Magento/BraintreeGraphQl/etc/schema.graphqls +++ b/app/code/Magento/BraintreeGraphQl/etc/schema.graphqls @@ -17,8 +17,6 @@ input BraintreeInput { } input BraintreeCcVaultInput { - payment_method_nonce: String! public_hash: String! - is_active_payment_token_enabler: Boolean! device_data: String } diff --git a/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/Adapter/BraintreeAdapter.php b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/Adapter/BraintreeAdapter.php index d8f5c8627960..a4bc29270cc1 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/Adapter/BraintreeAdapter.php +++ b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/Adapter/BraintreeAdapter.php @@ -66,6 +66,7 @@ public function sale(array $attributes) /** * @param array $params * @return string|\Braintree\Result\Error + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function generate(array $params = []) { diff --git a/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/MockResponseDataProvider.php b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/MockResponseDataProvider.php index 9149d9ac637d..ab86109c6f91 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/MockResponseDataProvider.php +++ b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/MockResponseDataProvider.php @@ -32,10 +32,26 @@ public function __construct( * Create mock sale response for testing * * @param array $attributes - * @return \Braintree\Instance + * @return \Braintree\Result\Error|\Braintree\Result\Successful */ - public function generateMockSaleResponse(array $attributes): \Braintree\Instance + public function generateMockSaleResponse(array $attributes) { + if (empty($attributes['paymentMethodNonce'])) { + return new \Braintree\Result\Error( + [ + 'errors' => [ + [ + 'errorData' => [ + 'code' => 2019, + 'message' => 'Your transaction has been declined.' + ] + ] + ], + 'transaction' => $this->createTransaction($attributes)->jsonSerialize(), + ] + ); + } + $transaction = $this->createTransaction($attributes); return new \Braintree\Result\Successful([$transaction]); diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php index e9cca64c9650..8baf7c6386b3 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php @@ -169,19 +169,9 @@ public function testPlaceOrderWithVault() $reservedOrderId = 'test_quote'; $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId); - $nonceResult = $this->getNonceCommand->execute( - [ - 'customer_id' => 1, - 'public_hash' => 'braintree_public_hash', - ] - ); - $nonce = $nonceResult->get()['paymentMethodNonce']; - $setPaymentQuery = $this->getSetPaymentBraintreeVaultQuery( $maskedQuoteId, - 'braintree_public_hash', - $nonce, - true + 'braintree_public_hash' ); $setPaymentResponse = $this->graphQlMutation($setPaymentQuery, [], '', $this->getHeaderMap()); @@ -243,17 +233,12 @@ private function getSetPaymentBraintreeQuery(string $maskedQuoteId, bool $saveIn /** * @param string $maskedQuoteId * @param string $publicHash - * @param string $nonce - * @param bool $saveInVault * @return string */ private function getSetPaymentBraintreeVaultQuery( string $maskedQuoteId, - string $publicHash, - string $nonce, - bool $saveInVault = false + string $publicHash ): string { - $saveInVault = json_encode($saveInVault); return << Date: Sun, 14 Jul 2019 09:32:25 -0400 Subject: [PATCH 09/17] Validate additional input is present for associated payment method --- .../Model/BraintreeDataProvider.php | 25 +++---- .../Model/BraintreeVaultDataProvider.php | 24 +++---- .../Plugin/SetVaultPaymentNonce.php | 4 +- .../Customer/SetPaymentMethodTest.php | 60 +++++++++++++++++ .../Braintree/Guest/SetPaymentMethodTest.php | 66 ++++++++++++++++++- 5 files changed, 143 insertions(+), 36 deletions(-) diff --git a/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php b/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php index 9227d7877da2..8afc738dbdf8 100644 --- a/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php +++ b/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php @@ -7,8 +7,8 @@ namespace Magento\BraintreeGraphQl\Model; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\QuoteGraphQl\Model\Cart\Payment\AdditionalDataProviderInterface; -use Magento\Framework\Stdlib\ArrayManager; /** * Format Braintree input into value expected when setting payment method @@ -17,28 +17,21 @@ class BraintreeDataProvider implements AdditionalDataProviderInterface { private const PATH_ADDITIONAL_DATA = 'braintree'; - /** - * @var ArrayManager - */ - private $arrayManager; - - /** - * @param ArrayManager $arrayManager - */ - public function __construct( - ArrayManager $arrayManager - ) { - $this->arrayManager = $arrayManager; - } - /** * Format Braintree input into value expected when setting payment method * * @param array $args * @return array + * @throws GraphQlInputException */ public function getData(array $args): array { - return $this->arrayManager->get(static::PATH_ADDITIONAL_DATA, $args) ?? []; + if (!isset($args[static::PATH_ADDITIONAL_DATA])) { + throw new GraphQlInputException( + __('Required parameter "braintree" for "payment_method" is missing.') + ); + } + + return $args[static::PATH_ADDITIONAL_DATA]; } } diff --git a/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php b/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php index 0b7a0965b086..fcbea6d91ddb 100644 --- a/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php +++ b/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php @@ -7,8 +7,8 @@ namespace Magento\BraintreeGraphQl\Model; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\QuoteGraphQl\Model\Cart\Payment\AdditionalDataProviderInterface; -use Magento\Framework\Stdlib\ArrayManager; /** * Format Braintree input into value expected when setting payment method @@ -17,20 +17,6 @@ class BraintreeVaultDataProvider implements AdditionalDataProviderInterface { private const PATH_ADDITIONAL_DATA = 'braintree_cc_vault'; - /** - * @var ArrayManager - */ - private $arrayManager; - - /** - * @param ArrayManager $arrayManager - */ - public function __construct( - ArrayManager $arrayManager - ) { - $this->arrayManager = $arrayManager; - } - /** * Format Braintree input into value expected when setting payment method * @@ -39,6 +25,12 @@ public function __construct( */ public function getData(array $args): array { - return $this->arrayManager->get(static::PATH_ADDITIONAL_DATA, $args) ?? []; + if (!isset($args[static::PATH_ADDITIONAL_DATA])) { + throw new GraphQlInputException( + __('Required parameter "braintree_cc_vault" for "payment_method" is missing.') + ); + } + + return $args[static::PATH_ADDITIONAL_DATA]; } } diff --git a/app/code/Magento/BraintreeGraphQl/Plugin/SetVaultPaymentNonce.php b/app/code/Magento/BraintreeGraphQl/Plugin/SetVaultPaymentNonce.php index b8294f1a1352..10b1d5826835 100644 --- a/app/code/Magento/BraintreeGraphQl/Plugin/SetVaultPaymentNonce.php +++ b/app/code/Magento/BraintreeGraphQl/Plugin/SetVaultPaymentNonce.php @@ -53,7 +53,9 @@ public function beforeExecute( \Magento\Quote\Model\Quote $quote, array $paymentData ): array { - if ($paymentData['code'] !== ConfigProvider::CC_VAULT_CODE) { + if ($paymentData['code'] !== ConfigProvider::CC_VAULT_CODE + || !isset($paymentData[ConfigProvider::CC_VAULT_CODE]) + ) { return [$quote, $paymentData]; } diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php index 8baf7c6386b3..805b2825299f 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php @@ -183,6 +183,41 @@ public function testPlaceOrderWithVault() $this->assertPlaceOrderResponse($placeOrderResponse, $reservedOrderId); } + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php + * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/enable_braintree_payment.php + * @dataProvider dataProviderTestSetPaymentMethodInvalidInput + * @expectedException \Exception + * @param string $methodCode + */ + public function testSetPaymentMethodInvalidInput(string $methodCode) + { + $reservedOrderId = 'test_quote'; + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId); + + $setPaymentQuery = $this->getSetPaymentBraintreeQueryInvalidInput( + $maskedQuoteId, + $methodCode + ); + $this->expectExceptionMessage("Required parameter \"$methodCode\" for \"payment_method\" is missing."); + $this->graphQlMutation($setPaymentQuery, [], '', $this->getHeaderMap()); + } + + public function dataProviderTestSetPaymentMethodInvalidInput(): array + { + return [ + ['braintree'], + ['braintree_cc_vault'], + ]; + } + private function assertPlaceOrderResponse(array $response, string $reservedOrderId): void { self::assertArrayHasKey('placeOrder', $response); @@ -260,6 +295,31 @@ private function getSetPaymentBraintreeVaultQuery( QUERY; } + /** + * @param string $maskedQuoteId + * @param string $methodCode + * @return string + */ + private function getSetPaymentBraintreeQueryInvalidInput(string $maskedQuoteId, string $methodCode): string + { + return <<getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId); - $setPaymentQuery = $this->getSetPaymentBraintreeQuery($maskedQuoteId); + $setPaymentQuery = $this->getSetPaymentBraintreeQuery($maskedQuoteId, $nonce); $setPaymentResponse = $this->graphQlMutation($setPaymentQuery); $this->assertSetPaymentMethodResponse($setPaymentResponse, 'braintree'); @@ -85,6 +86,41 @@ public function testPlaceOrder() $this->assertPlaceOrderResponse($placeOrderResponse, $reservedOrderId); } + /** + * Data provider for testPlaceOrder + * + * @return array + */ + public function dataProviderTestPlaceOrder(): array + { + return [ + ['fake-valid-nonce'], + ['fake-apple-pay-visa-nonce'], + ]; + } + + /** + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/set_guest_email.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php + * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/enable_braintree_payment.php + * @expectedException \Exception + */ + public function testSetPaymentMethodInvalidInput() + { + $reservedOrderId = 'test_quote'; + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId); + + $setPaymentQuery = $this->getSetPaymentBraintreeQueryInvalidInput($maskedQuoteId); + $this->expectExceptionMessage("Required parameter \"braintree\" for \"payment_method\" is missing."); + $this->graphQlMutation($setPaymentQuery); + } + private function assertPlaceOrderResponse(array $response, string $reservedOrderId): void { self::assertArrayHasKey('placeOrder', $response); @@ -106,7 +142,7 @@ private function assertSetPaymentMethodResponse(array $response, string $methodC * @param string $maskedQuoteId * @return string */ - private function getSetPaymentBraintreeQuery(string $maskedQuoteId): string + private function getSetPaymentBraintreeQuery(string $maskedQuoteId, string $nonce): string { return << Date: Tue, 23 Jul 2019 20:10:15 -0400 Subject: [PATCH 10/17] Add validation for additonal data input --- .../Model/BraintreeDataProvider.php | 12 +++++ .../Model/BraintreeVaultDataProvider.php | 6 +++ .../Plugin/SetVaultPaymentNonce.php | 1 + .../Customer/SetPaymentMethodTest.php | 53 +++++++++++++++++++ .../Braintree/Guest/SetPaymentMethodTest.php | 49 ++++++++++++++++- 5 files changed, 120 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php b/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php index 8afc738dbdf8..ee97b329f135 100644 --- a/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php +++ b/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php @@ -32,6 +32,18 @@ public function getData(array $args): array ); } + if (!isset($args[static::PATH_ADDITIONAL_DATA]['payment_method_nonce'])) { + throw new GraphQlInputException( + __('Required parameter "payment_method_nonce" for "braintree" is missing.') + ); + } + + if (!isset($args[static::PATH_ADDITIONAL_DATA]['is_active_payment_token_enabler'])) { + throw new GraphQlInputException( + __('Required parameter "is_active_payment_token_enabler" for "braintree" is missing.') + ); + } + return $args[static::PATH_ADDITIONAL_DATA]; } } diff --git a/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php b/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php index fcbea6d91ddb..d619645fbea0 100644 --- a/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php +++ b/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php @@ -31,6 +31,12 @@ public function getData(array $args): array ); } + if (!isset($args[static::PATH_ADDITIONAL_DATA]['public_hash'])) { + throw new GraphQlInputException( + __('Required parameter "public_hash" for "braintree_cc_vault" is missing.') + ); + } + return $args[static::PATH_ADDITIONAL_DATA]; } } diff --git a/app/code/Magento/BraintreeGraphQl/Plugin/SetVaultPaymentNonce.php b/app/code/Magento/BraintreeGraphQl/Plugin/SetVaultPaymentNonce.php index 10b1d5826835..1dea9992c630 100644 --- a/app/code/Magento/BraintreeGraphQl/Plugin/SetVaultPaymentNonce.php +++ b/app/code/Magento/BraintreeGraphQl/Plugin/SetVaultPaymentNonce.php @@ -55,6 +55,7 @@ public function beforeExecute( ): array { if ($paymentData['code'] !== ConfigProvider::CC_VAULT_CODE || !isset($paymentData[ConfigProvider::CC_VAULT_CODE]) + || !isset($paymentData[ConfigProvider::CC_VAULT_CODE]['public_hash']) ) { return [$quote, $paymentData]; } diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php index 805b2825299f..420e1b80d74c 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php @@ -210,6 +210,33 @@ public function testSetPaymentMethodInvalidInput(string $methodCode) $this->graphQlMutation($setPaymentQuery, [], '', $this->getHeaderMap()); } + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php + * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/enable_braintree_payment.php + * @dataProvider dataProviderTestSetPaymentMethodInvalidInput + * @expectedException \Exception + * @param string $methodCode + */ + public function testSetPaymentMethodInvalidMethodInput(string $methodCode) + { + $reservedOrderId = 'test_quote'; + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId); + + $setPaymentQuery = $this->getSetPaymentBraintreeQueryInvalidMethodInput( + $maskedQuoteId, + $methodCode + ); + $this->expectExceptionMessage("for \"$methodCode\" is missing."); + $this->graphQlMutation($setPaymentQuery, [], '', $this->getHeaderMap()); + } + public function dataProviderTestSetPaymentMethodInvalidInput(): array { return [ @@ -320,6 +347,32 @@ private function getSetPaymentBraintreeQueryInvalidInput(string $maskedQuoteId, QUERY; } + /** + * @param string $maskedQuoteId + * @param string $methodCode + * @return string + */ + private function getSetPaymentBraintreeQueryInvalidMethodInput(string $maskedQuoteId, string $methodCode): string + { + return <<graphQlMutation($setPaymentQuery); } + /** + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/set_guest_email.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php + * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/enable_braintree_payment.php + * @expectedException \Exception + */ + public function testSetPaymentMethodInvalidMethodInput() + { + $reservedOrderId = 'test_quote'; + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId); + + $setPaymentQuery = $this->getSetPaymentBraintreeQueryInvalidMethodInput($maskedQuoteId); + $this->expectExceptionMessage("for \"braintree\" is missing."); + $this->graphQlMutation($setPaymentQuery); + } + private function assertPlaceOrderResponse(array $response, string $reservedOrderId): void { self::assertArrayHasKey('placeOrder', $response); @@ -152,7 +174,7 @@ private function getSetPaymentBraintreeQuery(string $maskedQuoteId, string $nonc code:"braintree" braintree:{ is_active_payment_token_enabler:false - payment_method_nonce:"fake-valid-nonce" + payment_method_nonce:"{$nonce}" } } }) { @@ -190,6 +212,31 @@ private function getSetPaymentBraintreeQueryInvalidInput(string $maskedQuoteId): QUERY; } + /** + * @param string $maskedQuoteId + * @return string + */ + private function getSetPaymentBraintreeQueryInvalidMethodInput(string $maskedQuoteId): string + { + return << Date: Sat, 27 Jul 2019 08:25:26 -0400 Subject: [PATCH 11/17] Add parent-compatible typehint to constructor docblock --- .../Model/Adapter/BraintreeAdapter.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/Adapter/BraintreeAdapter.php b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/Adapter/BraintreeAdapter.php index a4bc29270cc1..58932e7e8ea8 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/Adapter/BraintreeAdapter.php +++ b/dev/tests/api-functional/_files/Magento/TestModuleBraintree/Model/Adapter/BraintreeAdapter.php @@ -28,10 +28,10 @@ class BraintreeAdapter extends \Magento\Braintree\Model\Adapter\BraintreeAdapter private $mockResponseDataProvider; /** - * @param $merchantId - * @param $publicKey - * @param $privateKey - * @param $environment + * @param string $merchantId + * @param string $publicKey + * @param string $privateKey + * @param string $environment * @param MockResponseDataProvider $mockResponseDataProvider */ public function __construct( From 169ac1bd0182e86c359502f72d2edaac4c97d476 Mon Sep 17 00:00:00 2001 From: Patrick McLain Date: Tue, 30 Jul 2019 16:29:16 -0400 Subject: [PATCH 12/17] Get storeId from resolver context --- .../Model/Resolver/CreateBraintreeClientToken.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/app/code/Magento/BraintreeGraphQl/Model/Resolver/CreateBraintreeClientToken.php b/app/code/Magento/BraintreeGraphQl/Model/Resolver/CreateBraintreeClientToken.php index d13dc91d6482..82c1196f0e68 100644 --- a/app/code/Magento/BraintreeGraphQl/Model/Resolver/CreateBraintreeClientToken.php +++ b/app/code/Magento/BraintreeGraphQl/Model/Resolver/CreateBraintreeClientToken.php @@ -21,11 +21,6 @@ */ class CreateBraintreeClientToken implements ResolverInterface { - /** - * @var StoreManagerInterface - */ - private $storeManager; - /** * @var Config */ @@ -37,16 +32,13 @@ class CreateBraintreeClientToken implements ResolverInterface private $adapterFactory; /** - * @param StoreManagerInterface $storeManager * @param Config $config * @param BraintreeAdapterFactory $adapterFactory */ public function __construct( - StoreManagerInterface $storeManager, Config $config, BraintreeAdapterFactory $adapterFactory ) { - $this->storeManager = $storeManager; $this->config = $config; $this->adapterFactory = $adapterFactory; } @@ -61,7 +53,7 @@ public function resolve( array $value = null, array $args = null ) { - $storeId = $this->storeManager->getStore()->getId(); + $storeId = (int)$context->getExtensionAttributes()->getStore()->getId(); if (!$this->config->isActive($storeId)) { throw new GraphQlInputException(__('The Braintree payment method is not active.')); From f69b080b695af447d783185fda1ee5abc2522c75 Mon Sep 17 00:00:00 2001 From: Patrick McLain Date: Tue, 30 Jul 2019 16:33:07 -0400 Subject: [PATCH 13/17] Add composer deps to module sequence --- app/code/Magento/BraintreeGraphQl/etc/module.xml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/BraintreeGraphQl/etc/module.xml b/app/code/Magento/BraintreeGraphQl/etc/module.xml index 2133e95a6910..dd12c0638b7b 100644 --- a/app/code/Magento/BraintreeGraphQl/etc/module.xml +++ b/app/code/Magento/BraintreeGraphQl/etc/module.xml @@ -6,5 +6,12 @@ */ --> - + + + + + + + + From ec719be155a11b75f5194b76e34353194e6acef0 Mon Sep 17 00:00:00 2001 From: Patrick McLain Date: Tue, 30 Jul 2019 17:21:19 -0400 Subject: [PATCH 14/17] Update php reqs in BraintreeGraphQl composer.json --- app/code/Magento/BraintreeGraphQl/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/BraintreeGraphQl/composer.json b/app/code/Magento/BraintreeGraphQl/composer.json index 7f06b34353be..7790a4ac031d 100644 --- a/app/code/Magento/BraintreeGraphQl/composer.json +++ b/app/code/Magento/BraintreeGraphQl/composer.json @@ -3,7 +3,7 @@ "description": "N/A", "type": "magento2-module", "require": { - "php": "~7.1.3||~7.2.0", + "php": "~7.1.3||~7.2.0||~7.3.0", "magento/framework": "*", "magento/module-braintree": "*", "magento/module-store": "*", From d757fb5b6732978c11eef254225b5908697e3f86 Mon Sep 17 00:00:00 2001 From: Patrick McLain Date: Tue, 30 Jul 2019 16:49:23 -0400 Subject: [PATCH 15/17] Update tests to use @magentoConfigFixture Deletes configuration data fixtures no longer in use --- .../CreateBraintreeClientTokenTest.php | 6 ++- .../Customer/SetPaymentMethodTest.php | 44 ++++++++++++++----- .../Braintree/Guest/SetPaymentMethodTest.php | 24 +++++++--- .../_files/enable_braintree_payment.php | 35 --------------- .../enable_braintree_payment_rollback.php | 31 ------------- 5 files changed, 57 insertions(+), 83 deletions(-) delete mode 100644 dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/enable_braintree_payment.php delete mode 100644 dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/enable_braintree_payment_rollback.php diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/CreateBraintreeClientTokenTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/CreateBraintreeClientTokenTest.php index b83041e31b14..1564d00fa599 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/CreateBraintreeClientTokenTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/CreateBraintreeClientTokenTest.php @@ -17,7 +17,11 @@ class CreateBraintreeClientTokenTest extends GraphQlAbstract /** * Test creating Braintree client token * - * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/enable_braintree_payment.php + * @magentoConfigFixture default_store payment/braintree/active 1 + * @magentoConfigFixture default_store payment/braintree/environment sandbox + * @magentoConfigFixture default_store payment/braintree/merchant_id def_merchant_id + * @magentoConfigFixture default_store payment/braintree/public_key def_public_key + * @magentoConfigFixture default_store payment/braintree/private_key def_private_key */ public function testCreateBraintreeClientToken() { diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php index 420e1b80d74c..84a639af30b0 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Customer/SetPaymentMethodTest.php @@ -80,15 +80,19 @@ protected function setUp() } /** + * @magentoConfigFixture default_store carriers/flatrate/active 1 + * @magentoConfigFixture default_store payment/braintree/active 1 + * @magentoConfigFixture default_store payment/braintree/environment sandbox + * @magentoConfigFixture default_store payment/braintree/merchant_id def_merchant_id + * @magentoConfigFixture default_store payment/braintree/public_key def_public_key + * @magentoConfigFixture default_store payment/braintree/private_key def_private_key * @magentoApiDataFixture Magento/Customer/_files/customer.php * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php - * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php - * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/enable_braintree_payment.php */ public function testPlaceOrder() { @@ -113,15 +117,20 @@ public function testPlaceOrder() } /** + * @magentoConfigFixture default_store carriers/flatrate/active 1 + * @magentoConfigFixture default_store payment/braintree/active 1 + * @magentoConfigFixture default_store payment/braintree_cc_vault/active 1 + * @magentoConfigFixture default_store payment/braintree/environment sandbox + * @magentoConfigFixture default_store payment/braintree/merchant_id def_merchant_id + * @magentoConfigFixture default_store payment/braintree/public_key def_public_key + * @magentoConfigFixture default_store payment/braintree/private_key def_private_key * @magentoApiDataFixture Magento/Customer/_files/customer.php * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php - * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php - * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/enable_braintree_payment.php */ public function testPlaceOrderSaveInVault() { @@ -153,15 +162,20 @@ public function testPlaceOrderSaveInVault() } /** + * @magentoConfigFixture default_store carriers/flatrate/active 1 + * @magentoConfigFixture default_store payment/braintree/active 1 + * @magentoConfigFixture default_store payment/braintree_cc_vault/active 1 + * @magentoConfigFixture default_store payment/braintree/environment sandbox + * @magentoConfigFixture default_store payment/braintree/merchant_id def_merchant_id + * @magentoConfigFixture default_store payment/braintree/public_key def_public_key + * @magentoConfigFixture default_store payment/braintree/private_key def_private_key * @magentoApiDataFixture Magento/Customer/_files/customer.php * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php - * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php - * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/enable_braintree_payment.php * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/token.php */ public function testPlaceOrderWithVault() @@ -184,15 +198,20 @@ public function testPlaceOrderWithVault() } /** + * @magentoConfigFixture default_store carriers/flatrate/active 1 + * @magentoConfigFixture default_store payment/braintree/active 1 + * @magentoConfigFixture default_store payment/braintree_cc_vault/active 1 + * @magentoConfigFixture default_store payment/braintree/environment sandbox + * @magentoConfigFixture default_store payment/braintree/merchant_id def_merchant_id + * @magentoConfigFixture default_store payment/braintree/public_key def_public_key + * @magentoConfigFixture default_store payment/braintree/private_key def_private_key * @magentoApiDataFixture Magento/Customer/_files/customer.php * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php - * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php - * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/enable_braintree_payment.php * @dataProvider dataProviderTestSetPaymentMethodInvalidInput * @expectedException \Exception * @param string $methodCode @@ -211,15 +230,20 @@ public function testSetPaymentMethodInvalidInput(string $methodCode) } /** + * @magentoConfigFixture default_store carriers/flatrate/active 1 + * @magentoConfigFixture default_store payment/braintree/active 1 + * @magentoConfigFixture default_store payment/braintree_cc_vault/active 1 + * @magentoConfigFixture default_store payment/braintree/environment sandbox + * @magentoConfigFixture default_store payment/braintree/merchant_id def_merchant_id + * @magentoConfigFixture default_store payment/braintree/public_key def_public_key + * @magentoConfigFixture default_store payment/braintree/private_key def_private_key * @magentoApiDataFixture Magento/Customer/_files/customer.php * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php - * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php - * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/enable_braintree_payment.php * @dataProvider dataProviderTestSetPaymentMethodInvalidInput * @expectedException \Exception * @param string $methodCode diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Guest/SetPaymentMethodTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Guest/SetPaymentMethodTest.php index 832b5e130b0f..1d48c5253fe8 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Guest/SetPaymentMethodTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Braintree/Guest/SetPaymentMethodTest.php @@ -59,15 +59,19 @@ protected function setUp() } /** + * @magentoConfigFixture default_store carriers/flatrate/active 1 + * @magentoConfigFixture default_store payment/braintree/active 1 + * @magentoConfigFixture default_store payment/braintree/environment sandbox + * @magentoConfigFixture default_store payment/braintree/merchant_id def_merchant_id + * @magentoConfigFixture default_store payment/braintree/public_key def_public_key + * @magentoConfigFixture default_store payment/braintree/private_key def_private_key * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php - * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/set_guest_email.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php - * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/enable_braintree_payment.php * @dataProvider dataProviderTestPlaceOrder */ public function testPlaceOrder(string $nonce) @@ -100,15 +104,19 @@ public function dataProviderTestPlaceOrder(): array } /** + * @magentoConfigFixture default_store carriers/flatrate/active 1 + * @magentoConfigFixture default_store payment/braintree/active 1 + * @magentoConfigFixture default_store payment/braintree/environment sandbox + * @magentoConfigFixture default_store payment/braintree/merchant_id def_merchant_id + * @magentoConfigFixture default_store payment/braintree/public_key def_public_key + * @magentoConfigFixture default_store payment/braintree/private_key def_private_key * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php - * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/set_guest_email.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php - * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/enable_braintree_payment.php * @expectedException \Exception */ public function testSetPaymentMethodInvalidInput() @@ -122,15 +130,19 @@ public function testSetPaymentMethodInvalidInput() } /** + * @magentoConfigFixture default_store carriers/flatrate/active 1 + * @magentoConfigFixture default_store payment/braintree/active 1 + * @magentoConfigFixture default_store payment/braintree/environment sandbox + * @magentoConfigFixture default_store payment/braintree/merchant_id def_merchant_id + * @magentoConfigFixture default_store payment/braintree/public_key def_public_key + * @magentoConfigFixture default_store payment/braintree/private_key def_private_key * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php - * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/set_guest_email.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php - * @magentoApiDataFixture Magento/GraphQl/Braintree/_files/enable_braintree_payment.php * @expectedException \Exception */ public function testSetPaymentMethodInvalidMethodInput() diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/enable_braintree_payment.php b/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/enable_braintree_payment.php deleted file mode 100644 index b91259376bed..000000000000 --- a/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/enable_braintree_payment.php +++ /dev/null @@ -1,35 +0,0 @@ -get(WriterInterface::class); -/** @var EncryptorInterface $encryptor */ -$encryptor = $objectManager->get(EncryptorInterface::class); - -/** @var $mutableScopeConfig */ -$mutableScopeConfig = $objectManager->get( - \Magento\Framework\App\Config\MutableScopeConfigInterface::class -); - -$configWriter->save('payment/' . ConfigProvider::CODE . '/merchant_id', 'def_merchant_id'); -$configWriter->save('payment/' . ConfigProvider::CODE . '/public_key', $encryptor->encrypt('def_public_key')); -$configWriter->save('payment/' . ConfigProvider::CODE . '/private_key', $encryptor->encrypt('def_private_key')); -$configWriter->save('payment/' . ConfigProvider::CODE . '/active', '1'); -$configWriter->save('payment/' . ConfigProvider::CODE . '/environment', 'sandbox'); -$configWriter->save('payment/' . ConfigProvider::CC_VAULT_CODE . '/active', '1'); - -$scopeConfig = $objectManager->get(ScopeConfigInterface::class); -$scopeConfig->clean(); diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/enable_braintree_payment_rollback.php b/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/enable_braintree_payment_rollback.php deleted file mode 100644 index 7b4e187c6717..000000000000 --- a/dev/tests/integration/testsuite/Magento/GraphQl/Braintree/_files/enable_braintree_payment_rollback.php +++ /dev/null @@ -1,31 +0,0 @@ -get(WriterInterface::class); -/** @var EncryptorInterface $encryptor */ -$encryptor = $objectManager->get(EncryptorInterface::class); - -/** @var $mutableScopeConfig */ -$mutableScopeConfig = $objectManager->get( - \Magento\Framework\App\Config\MutableScopeConfigInterface::class -); - -$configWriter->delete('payment/' . ConfigProvider::CODE . '/merchant_id'); -$configWriter->delete('payment/' . ConfigProvider::CODE . '/public_key'); -$configWriter->delete('payment/' . ConfigProvider::CODE . '/private_key'); -$configWriter->delete('payment/' . ConfigProvider::CODE . '/active'); -$configWriter->delete('payment/' . ConfigProvider::CODE . '/environment'); -$configWriter->delete('payment/' . ConfigProvider::CC_VAULT_CODE . '/active'); From 1132a47ad8090470b1d6ce3cdec75f05ffe3d86b Mon Sep 17 00:00:00 2001 From: Patrick McLain Date: Tue, 30 Jul 2019 20:18:09 -0400 Subject: [PATCH 16/17] Replace static with self --- .../BraintreeGraphQl/Model/BraintreeDataProvider.php | 8 ++++---- .../BraintreeGraphQl/Model/BraintreeVaultDataProvider.php | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php b/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php index ee97b329f135..23ca1d88e362 100644 --- a/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php +++ b/app/code/Magento/BraintreeGraphQl/Model/BraintreeDataProvider.php @@ -26,24 +26,24 @@ class BraintreeDataProvider implements AdditionalDataProviderInterface */ public function getData(array $args): array { - if (!isset($args[static::PATH_ADDITIONAL_DATA])) { + if (!isset($args[self::PATH_ADDITIONAL_DATA])) { throw new GraphQlInputException( __('Required parameter "braintree" for "payment_method" is missing.') ); } - if (!isset($args[static::PATH_ADDITIONAL_DATA]['payment_method_nonce'])) { + if (!isset($args[self::PATH_ADDITIONAL_DATA]['payment_method_nonce'])) { throw new GraphQlInputException( __('Required parameter "payment_method_nonce" for "braintree" is missing.') ); } - if (!isset($args[static::PATH_ADDITIONAL_DATA]['is_active_payment_token_enabler'])) { + if (!isset($args[self::PATH_ADDITIONAL_DATA]['is_active_payment_token_enabler'])) { throw new GraphQlInputException( __('Required parameter "is_active_payment_token_enabler" for "braintree" is missing.') ); } - return $args[static::PATH_ADDITIONAL_DATA]; + return $args[self::PATH_ADDITIONAL_DATA]; } } diff --git a/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php b/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php index d619645fbea0..4635e4e317bc 100644 --- a/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php +++ b/app/code/Magento/BraintreeGraphQl/Model/BraintreeVaultDataProvider.php @@ -25,18 +25,18 @@ class BraintreeVaultDataProvider implements AdditionalDataProviderInterface */ public function getData(array $args): array { - if (!isset($args[static::PATH_ADDITIONAL_DATA])) { + if (!isset($args[self::PATH_ADDITIONAL_DATA])) { throw new GraphQlInputException( __('Required parameter "braintree_cc_vault" for "payment_method" is missing.') ); } - if (!isset($args[static::PATH_ADDITIONAL_DATA]['public_hash'])) { + if (!isset($args[self::PATH_ADDITIONAL_DATA]['public_hash'])) { throw new GraphQlInputException( __('Required parameter "public_hash" for "braintree_cc_vault" is missing.') ); } - return $args[static::PATH_ADDITIONAL_DATA]; + return $args[self::PATH_ADDITIONAL_DATA]; } } From 00002f4b4dd3a43209a2312fd79f798e4262cf6b Mon Sep 17 00:00:00 2001 From: Valerii Naida Date: Sun, 4 Aug 2019 15:09:53 -0500 Subject: [PATCH 17/17] magento/graphql-ce#644: [Checkout] Support of "Braintree" payment method --- composer.lock | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/composer.lock b/composer.lock index 591e51c62e83..f67eb5067531 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f6c85e01a374b22a185f11a0c51e08fb", + "content-hash": "a4299e3f4f0d4dd4915f37a5dde8e2ed", "packages": [ { "name": "braintree/braintree_php", @@ -1552,28 +1552,28 @@ "authors": [ { "name": "Jim Wigginton", - "email": "terrafrost@php.net", - "role": "Lead Developer" + "role": "Lead Developer", + "email": "terrafrost@php.net" }, { "name": "Patrick Monnerat", - "email": "pm@datasphere.ch", - "role": "Developer" + "role": "Developer", + "email": "pm@datasphere.ch" }, { "name": "Andreas Fischer", - "email": "bantu@phpbb.com", - "role": "Developer" + "role": "Developer", + "email": "bantu@phpbb.com" }, { "name": "Hans-Jürgen Petrich", - "email": "petrich@tronic-media.com", - "role": "Developer" + "role": "Developer", + "email": "petrich@tronic-media.com" }, { "name": "Graham Campbell", - "email": "graham@alt-three.com", - "role": "Developer" + "role": "Developer", + "email": "graham@alt-three.com" } ], "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",