SetShippingAddressOnCartTest.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. declare(strict_types=1);
  7. namespace Magento\GraphQl\Quote;
  8. use Magento\Framework\App\Config\ScopeConfigInterface;
  9. use Magento\Integration\Api\CustomerTokenServiceInterface;
  10. use Magento\Multishipping\Helper\Data;
  11. use Magento\Quote\Model\QuoteFactory;
  12. use Magento\Quote\Model\QuoteIdToMaskedQuoteIdInterface;
  13. use Magento\Quote\Model\ResourceModel\Quote as QuoteResource;
  14. use Magento\TestFramework\Helper\Bootstrap;
  15. use Magento\TestFramework\TestCase\GraphQlAbstract;
  16. use Magento\TestFramework\ObjectManager;
  17. /**
  18. * Test for set shipping addresses on cart mutation
  19. */
  20. class SetShippingAddressOnCartTest extends GraphQlAbstract
  21. {
  22. /**
  23. * @var QuoteResource
  24. */
  25. private $quoteResource;
  26. /**
  27. * @var QuoteFactory
  28. */
  29. private $quoteFactory;
  30. /**
  31. * @var QuoteIdToMaskedQuoteIdInterface
  32. */
  33. private $quoteIdToMaskedId;
  34. /**
  35. * @var CustomerTokenServiceInterface
  36. */
  37. private $customerTokenService;
  38. protected function setUp()
  39. {
  40. $this->markTestIncomplete('https://github.com/magento/graphql-ce/issues/434');
  41. $objectManager = Bootstrap::getObjectManager();
  42. $this->quoteResource = $objectManager->get(QuoteResource::class);
  43. $this->quoteFactory = $objectManager->get(QuoteFactory::class);
  44. $this->quoteIdToMaskedId = $objectManager->get(QuoteIdToMaskedQuoteIdInterface::class);
  45. $this->customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class);
  46. }
  47. /**
  48. * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
  49. */
  50. public function testSetNewShippingAddressByGuest()
  51. {
  52. $maskedQuoteId = $this->getMaskedQuoteIdByReversedQuoteId('test_order_with_simple_product_without_address');
  53. $query = <<<QUERY
  54. mutation {
  55. setShippingAddressesOnCart(
  56. input: {
  57. cart_id: "$maskedQuoteId"
  58. shipping_addresses: [
  59. {
  60. address: {
  61. firstname: "test firstname"
  62. lastname: "test lastname"
  63. company: "test company"
  64. street: ["test street 1", "test street 2"]
  65. city: "test city"
  66. region: "test region"
  67. postcode: "887766"
  68. country_code: "US"
  69. telephone: "88776655"
  70. save_in_address_book: false
  71. }
  72. }
  73. ]
  74. }
  75. ) {
  76. cart {
  77. shipping_addresses {
  78. firstname
  79. lastname
  80. company
  81. street
  82. city
  83. postcode
  84. telephone
  85. }
  86. }
  87. }
  88. }
  89. QUERY;
  90. $response = $this->graphQlQuery($query);
  91. self::assertArrayHasKey('cart', $response['setShippingAddressesOnCart']);
  92. $cartResponse = $response['setShippingAddressesOnCart']['cart'];
  93. self::assertArrayHasKey('shipping_addresses', $cartResponse);
  94. $shippingAddressResponse = current($cartResponse['shipping_addresses']);
  95. $this->assertNewShippingAddressFields($shippingAddressResponse);
  96. }
  97. /**
  98. * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
  99. * @expectedException \Exception
  100. * @expectedExceptionMessage The current customer isn't authorized.
  101. */
  102. public function testSetShippingAddressFromAddressBookByGuest()
  103. {
  104. $maskedQuoteId = $this->getMaskedQuoteIdByReversedQuoteId('test_order_with_simple_product_without_address');
  105. $query = <<<QUERY
  106. mutation {
  107. setShippingAddressesOnCart(
  108. input: {
  109. cart_id: "$maskedQuoteId"
  110. shipping_addresses: [
  111. {
  112. customer_address_id: 1
  113. }
  114. ]
  115. }
  116. ) {
  117. cart {
  118. shipping_addresses {
  119. city
  120. }
  121. }
  122. }
  123. }
  124. QUERY;
  125. $this->graphQlQuery($query);
  126. }
  127. /**
  128. * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
  129. * @magentoApiDataFixture Magento/Customer/_files/customer.php
  130. */
  131. public function testSetNewShippingAddressByRegisteredCustomer()
  132. {
  133. $maskedQuoteId = $this->assignQuoteToCustomer();
  134. $query = <<<QUERY
  135. mutation {
  136. setShippingAddressesOnCart(
  137. input: {
  138. cart_id: "$maskedQuoteId"
  139. shipping_addresses: [
  140. {
  141. address: {
  142. firstname: "test firstname"
  143. lastname: "test lastname"
  144. company: "test company"
  145. street: ["test street 1", "test street 2"]
  146. city: "test city"
  147. region: "test region"
  148. postcode: "887766"
  149. country_code: "US"
  150. telephone: "88776655"
  151. save_in_address_book: false
  152. }
  153. }
  154. ]
  155. }
  156. ) {
  157. cart {
  158. shipping_addresses {
  159. firstname
  160. lastname
  161. company
  162. street
  163. city
  164. postcode
  165. telephone
  166. }
  167. }
  168. }
  169. }
  170. QUERY;
  171. $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap());
  172. self::assertArrayHasKey('cart', $response['setShippingAddressesOnCart']);
  173. $cartResponse = $response['setShippingAddressesOnCart']['cart'];
  174. self::assertArrayHasKey('shipping_addresses', $cartResponse);
  175. $shippingAddressResponse = current($cartResponse['shipping_addresses']);
  176. $this->assertNewShippingAddressFields($shippingAddressResponse);
  177. }
  178. /**
  179. * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
  180. * @magentoApiDataFixture Magento/Customer/_files/customer.php
  181. * @magentoApiDataFixture Magento/Customer/_files/customer_two_addresses.php
  182. */
  183. public function testSetShippingAddressFromAddressBookByRegisteredCustomer()
  184. {
  185. $maskedQuoteId = $this->assignQuoteToCustomer();
  186. $query = <<<QUERY
  187. mutation {
  188. setShippingAddressesOnCart(
  189. input: {
  190. cart_id: "$maskedQuoteId"
  191. shipping_addresses: [
  192. {
  193. customer_address_id: 1
  194. }
  195. ]
  196. }
  197. ) {
  198. cart {
  199. shipping_addresses {
  200. firstname
  201. lastname
  202. company
  203. street
  204. city
  205. postcode
  206. telephone
  207. }
  208. }
  209. }
  210. }
  211. QUERY;
  212. $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap());
  213. self::assertArrayHasKey('cart', $response['setShippingAddressesOnCart']);
  214. $cartResponse = $response['setShippingAddressesOnCart']['cart'];
  215. self::assertArrayHasKey('shipping_addresses', $cartResponse);
  216. $shippingAddressResponse = current($cartResponse['shipping_addresses']);
  217. $this->assertSavedShippingAddressFields($shippingAddressResponse);
  218. }
  219. /**
  220. * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
  221. * @magentoApiDataFixture Magento/Customer/_files/customer.php
  222. * @expectedException \Exception
  223. * @expectedExceptionMessage Could not find a address with ID "100"
  224. */
  225. public function testSetNotExistedShippingAddressFromAddressBook()
  226. {
  227. $maskedQuoteId = $this->assignQuoteToCustomer();
  228. $query = <<<QUERY
  229. mutation {
  230. setShippingAddressesOnCart(
  231. input: {
  232. cart_id: "$maskedQuoteId"
  233. shipping_addresses: [
  234. {
  235. customer_address_id: 100
  236. }
  237. ]
  238. }
  239. ) {
  240. cart {
  241. shipping_addresses {
  242. city
  243. }
  244. }
  245. }
  246. }
  247. QUERY;
  248. $this->graphQlQuery($query, [], '', $this->getHeaderMap());
  249. }
  250. /**
  251. * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
  252. * @expectedException \Exception
  253. * @expectedExceptionMessage The shipping address must contain either "customer_address_id" or "address".
  254. */
  255. public function testSetShippingAddressWithoutAddresses()
  256. {
  257. $maskedQuoteId = $this->getMaskedQuoteIdByReversedQuoteId('test_order_with_simple_product_without_address');
  258. $query = <<<QUERY
  259. mutation {
  260. setShippingAddressesOnCart(
  261. input: {
  262. cart_id: "$maskedQuoteId"
  263. shipping_addresses: [
  264. {}
  265. ]
  266. }
  267. ) {
  268. cart {
  269. shipping_addresses {
  270. city
  271. }
  272. }
  273. }
  274. }
  275. QUERY;
  276. $this->graphQlQuery($query);
  277. }
  278. /**
  279. * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
  280. * @magentoApiDataFixture Magento/Customer/_files/customer.php
  281. * @magentoApiDataFixture Magento/Customer/_files/customer_two_addresses.php
  282. */
  283. public function testSetNewShippingAddressAndFromAddressBookAtSameTime()
  284. {
  285. $maskedQuoteId = $this->assignQuoteToCustomer();
  286. $query = <<<QUERY
  287. mutation {
  288. setShippingAddressesOnCart(
  289. input: {
  290. cart_id: "$maskedQuoteId"
  291. shipping_addresses: [
  292. {
  293. customer_address_id: 1,
  294. address: {
  295. firstname: "test firstname"
  296. lastname: "test lastname"
  297. company: "test company"
  298. street: ["test street 1", "test street 2"]
  299. city: "test city"
  300. region: "test region"
  301. postcode: "887766"
  302. country_code: "US"
  303. telephone: "88776655"
  304. save_in_address_book: false
  305. }
  306. }
  307. ]
  308. }
  309. ) {
  310. cart {
  311. shipping_addresses {
  312. city
  313. }
  314. }
  315. }
  316. }
  317. QUERY;
  318. self::expectExceptionMessage(
  319. 'The shipping address cannot contain "customer_address_id" and "address" at the same time.'
  320. );
  321. $this->graphQlQuery($query, [], '', $this->getHeaderMap());
  322. }
  323. /**
  324. * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
  325. * @expectedException \Exception
  326. * @expectedExceptionMessage You cannot specify multiple shipping addresses.
  327. */
  328. public function testSetMultipleNewShippingAddresses()
  329. {
  330. $maskedQuoteId = $this->getMaskedQuoteIdByReversedQuoteId('test_order_with_simple_product_without_address');
  331. $query = <<<QUERY
  332. mutation {
  333. setShippingAddressesOnCart(
  334. input: {
  335. cart_id: "$maskedQuoteId"
  336. shipping_addresses: [
  337. {
  338. address: {
  339. firstname: "test firstname"
  340. lastname: "test lastname"
  341. company: "test company"
  342. street: ["test street 1", "test street 2"]
  343. city: "test city"
  344. region: "test region"
  345. postcode: "887766"
  346. country_code: "US"
  347. telephone: "88776655"
  348. save_in_address_book: false
  349. }
  350. },
  351. {
  352. address: {
  353. firstname: "test firstname 2"
  354. lastname: "test lastname 2"
  355. company: "test company 2"
  356. street: ["test street 1", "test street 2"]
  357. city: "test city"
  358. region: "test region"
  359. postcode: "887766"
  360. country_code: "US"
  361. telephone: "88776655"
  362. save_in_address_book: false
  363. }
  364. }
  365. ]
  366. }
  367. ) {
  368. cart {
  369. shipping_addresses {
  370. city
  371. }
  372. }
  373. }
  374. }
  375. QUERY;
  376. /** @var \Magento\Config\Model\ResourceModel\Config $config */
  377. $config = ObjectManager::getInstance()->get(\Magento\Config\Model\ResourceModel\Config::class);
  378. $config->saveConfig(
  379. Data::XML_PATH_CHECKOUT_MULTIPLE_AVAILABLE,
  380. null,
  381. ScopeConfigInterface::SCOPE_TYPE_DEFAULT,
  382. 0
  383. );
  384. /** @var \Magento\Framework\App\Config\ReinitableConfigInterface $config */
  385. $config = ObjectManager::getInstance()->get(\Magento\Framework\App\Config\ReinitableConfigInterface::class);
  386. $config->reinit();
  387. $this->graphQlQuery($query);
  388. }
  389. /**
  390. * @magentoApiDataFixture Magento/Customer/_files/three_customers.php
  391. * @magentoApiDataFixture Magento/Customer/_files/customer_address.php
  392. * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
  393. * @expectedException \Exception
  394. * @expectedExceptionMessage The current user cannot use address with ID "1"
  395. */
  396. public function testSetShippingAddressIfCustomerIsNotOwnerOfAddress()
  397. {
  398. $maskedQuoteId = $this->getMaskedQuoteIdByReversedQuoteId('test_order_with_simple_product_without_address');
  399. $query = <<<QUERY
  400. mutation {
  401. setShippingAddressesOnCart(
  402. input: {
  403. cart_id: "$maskedQuoteId"
  404. shipping_addresses: [
  405. {
  406. customer_address_id: 1
  407. }
  408. ]
  409. }
  410. ) {
  411. cart {
  412. shipping_addresses {
  413. postcode
  414. }
  415. }
  416. }
  417. }
  418. QUERY;
  419. $this->graphQlQuery($query, [], '', $this->getHeaderMap('customer2@search.example.com'));
  420. }
  421. /**
  422. * Verify the all the whitelisted fields for a New Address Object
  423. *
  424. * @param array $shippingAddressResponse
  425. */
  426. private function assertNewShippingAddressFields(array $shippingAddressResponse): void
  427. {
  428. $assertionMap = [
  429. ['response_field' => 'firstname', 'expected_value' => 'test firstname'],
  430. ['response_field' => 'lastname', 'expected_value' => 'test lastname'],
  431. ['response_field' => 'company', 'expected_value' => 'test company'],
  432. ['response_field' => 'street', 'expected_value' => [0 => 'test street 1', 1 => 'test street 2']],
  433. ['response_field' => 'city', 'expected_value' => 'test city'],
  434. ['response_field' => 'postcode', 'expected_value' => '887766'],
  435. ['response_field' => 'telephone', 'expected_value' => '88776655']
  436. ];
  437. $this->assertResponseFields($shippingAddressResponse, $assertionMap);
  438. }
  439. /**
  440. * Verify the all the whitelisted fields for a Address Object
  441. *
  442. * @param array $shippingAddressResponse
  443. */
  444. private function assertSavedShippingAddressFields(array $shippingAddressResponse): void
  445. {
  446. $assertionMap = [
  447. ['response_field' => 'firstname', 'expected_value' => 'John'],
  448. ['response_field' => 'lastname', 'expected_value' => 'Smith'],
  449. ['response_field' => 'company', 'expected_value' => 'CompanyName'],
  450. ['response_field' => 'street', 'expected_value' => [0 => 'Green str, 67']],
  451. ['response_field' => 'city', 'expected_value' => 'CityM'],
  452. ['response_field' => 'postcode', 'expected_value' => '75477'],
  453. ['response_field' => 'telephone', 'expected_value' => '3468676']
  454. ];
  455. $this->assertResponseFields($shippingAddressResponse, $assertionMap);
  456. }
  457. /**
  458. * @param string $username
  459. * @param string $password
  460. * @return array
  461. */
  462. private function getHeaderMap(string $username = 'customer@example.com', string $password = 'password'): array
  463. {
  464. $customerToken = $this->customerTokenService->createCustomerAccessToken($username, $password);
  465. $headerMap = ['Authorization' => 'Bearer ' . $customerToken];
  466. return $headerMap;
  467. }
  468. /**
  469. * @param string $reversedQuoteId
  470. * @return string
  471. */
  472. private function getMaskedQuoteIdByReversedQuoteId(string $reversedQuoteId): string
  473. {
  474. $quote = $this->quoteFactory->create();
  475. $this->quoteResource->load($quote, $reversedQuoteId, 'reserved_order_id');
  476. return $this->quoteIdToMaskedId->execute((int)$quote->getId());
  477. }
  478. /**
  479. * @param string $reversedQuoteId
  480. * @param int $customerId
  481. * @return string
  482. */
  483. private function assignQuoteToCustomer(
  484. string $reversedQuoteId = 'test_order_with_simple_product_without_address',
  485. int $customerId = 1
  486. ): string {
  487. $quote = $this->quoteFactory->create();
  488. $this->quoteResource->load($quote, $reversedQuoteId, 'reserved_order_id');
  489. $quote->setCustomerId($customerId);
  490. $this->quoteResource->save($quote);
  491. return $this->quoteIdToMaskedId->execute((int)$quote->getId());
  492. }
  493. public function tearDown()
  494. {
  495. /** @var \Magento\Config\Model\ResourceModel\Config $config */
  496. $config = ObjectManager::getInstance()->get(\Magento\Config\Model\ResourceModel\Config::class);
  497. //default state of multishipping config
  498. $config->saveConfig(
  499. Data::XML_PATH_CHECKOUT_MULTIPLE_AVAILABLE,
  500. 1,
  501. ScopeConfigInterface::SCOPE_TYPE_DEFAULT,
  502. 0
  503. );
  504. /** @var \Magento\Framework\App\Config\ReinitableConfigInterface $config */
  505. $config = ObjectManager::getInstance()->get(\Magento\Framework\App\Config\ReinitableConfigInterface::class);
  506. $config->reinit();
  507. }
  508. }