SetBillingAddressOnCartTest.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  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 billing address on cart mutation
  19. */
  20. class SetBillingAddressOnCartTest 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 testSetNewBillingAddressByGuest()
  51. {
  52. $maskedQuoteId = $this->getMaskedQuoteIdByReversedQuoteId('test_order_with_simple_product_without_address');
  53. $query = <<<QUERY
  54. mutation {
  55. setBillingAddressOnCart(
  56. input: {
  57. cart_id: "$maskedQuoteId"
  58. billing_address: {
  59. address: {
  60. firstname: "test firstname"
  61. lastname: "test lastname"
  62. company: "test company"
  63. street: ["test street 1", "test street 2"]
  64. city: "test city"
  65. region: "test region"
  66. postcode: "887766"
  67. country_code: "US"
  68. telephone: "88776655"
  69. save_in_address_book: false
  70. }
  71. }
  72. }
  73. ) {
  74. cart {
  75. billing_address {
  76. firstname
  77. lastname
  78. company
  79. street
  80. city
  81. postcode
  82. telephone
  83. }
  84. }
  85. }
  86. }
  87. QUERY;
  88. $response = $this->graphQlQuery($query);
  89. self::assertArrayHasKey('cart', $response['setBillingAddressOnCart']);
  90. $cartResponse = $response['setBillingAddressOnCart']['cart'];
  91. self::assertArrayHasKey('billing_address', $cartResponse);
  92. $billingAddressResponse = $cartResponse['billing_address'];
  93. $this->assertNewAddressFields($billingAddressResponse);
  94. }
  95. /**
  96. * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
  97. */
  98. public function testSetNewBillingAddressWithUseForShippingParameterByGuest()
  99. {
  100. $maskedQuoteId = $this->getMaskedQuoteIdByReversedQuoteId('test_order_with_simple_product_without_address');
  101. $query = <<<QUERY
  102. mutation {
  103. setBillingAddressOnCart(
  104. input: {
  105. cart_id: "$maskedQuoteId"
  106. billing_address: {
  107. address: {
  108. firstname: "test firstname"
  109. lastname: "test lastname"
  110. company: "test company"
  111. street: ["test street 1", "test street 2"]
  112. city: "test city"
  113. region: "test region"
  114. postcode: "887766"
  115. country_code: "US"
  116. telephone: "88776655"
  117. save_in_address_book: false
  118. }
  119. use_for_shipping: true
  120. }
  121. }
  122. ) {
  123. cart {
  124. billing_address {
  125. firstname
  126. lastname
  127. company
  128. street
  129. city
  130. postcode
  131. telephone
  132. }
  133. shipping_addresses {
  134. firstname
  135. lastname
  136. company
  137. street
  138. city
  139. postcode
  140. telephone
  141. }
  142. }
  143. }
  144. }
  145. QUERY;
  146. $response = $this->graphQlQuery($query);
  147. self::assertArrayHasKey('cart', $response['setBillingAddressOnCart']);
  148. $cartResponse = $response['setBillingAddressOnCart']['cart'];
  149. self::assertArrayHasKey('billing_address', $cartResponse);
  150. $billingAddressResponse = $cartResponse['billing_address'];
  151. self::assertArrayHasKey('shipping_addresses', $cartResponse);
  152. $shippingAddressResponse = current($cartResponse['shipping_addresses']);
  153. $this->assertNewAddressFields($billingAddressResponse);
  154. $this->assertNewAddressFields($shippingAddressResponse);
  155. }
  156. /**
  157. * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
  158. * @expectedException \Exception
  159. * @expectedExceptionMessage The current customer isn't authorized.
  160. */
  161. public function testSetBillingAddressFromAddressBookByGuest()
  162. {
  163. $maskedQuoteId = $this->getMaskedQuoteIdByReversedQuoteId('test_order_with_simple_product_without_address');
  164. $query = <<<QUERY
  165. mutation {
  166. setBillingAddressOnCart(
  167. input: {
  168. cart_id: "$maskedQuoteId"
  169. billing_address: {
  170. customer_address_id: 1
  171. }
  172. }
  173. ) {
  174. cart {
  175. billing_address {
  176. city
  177. }
  178. }
  179. }
  180. }
  181. QUERY;
  182. $this->graphQlQuery($query);
  183. }
  184. /**
  185. * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
  186. * @magentoApiDataFixture Magento/Customer/_files/customer.php
  187. */
  188. public function testSetNewBillingAddressByRegisteredCustomer()
  189. {
  190. $maskedQuoteId = $this->assignQuoteToCustomer();
  191. $query = <<<QUERY
  192. mutation {
  193. setBillingAddressOnCart(
  194. input: {
  195. cart_id: "$maskedQuoteId"
  196. billing_address: {
  197. address: {
  198. firstname: "test firstname"
  199. lastname: "test lastname"
  200. company: "test company"
  201. street: ["test street 1", "test street 2"]
  202. city: "test city"
  203. region: "test region"
  204. postcode: "887766"
  205. country_code: "US"
  206. telephone: "88776655"
  207. save_in_address_book: false
  208. }
  209. }
  210. }
  211. ) {
  212. cart {
  213. billing_address {
  214. firstname
  215. lastname
  216. company
  217. street
  218. city
  219. postcode
  220. telephone
  221. }
  222. }
  223. }
  224. }
  225. QUERY;
  226. $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap());
  227. self::assertArrayHasKey('cart', $response['setBillingAddressOnCart']);
  228. $cartResponse = $response['setBillingAddressOnCart']['cart'];
  229. self::assertArrayHasKey('billing_address', $cartResponse);
  230. $billingAddressResponse = $cartResponse['billing_address'];
  231. $this->assertNewAddressFields($billingAddressResponse);
  232. }
  233. /**
  234. * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
  235. * @magentoApiDataFixture Magento/Customer/_files/customer.php
  236. * @magentoApiDataFixture Magento/Customer/_files/customer_two_addresses.php
  237. */
  238. public function testSetBillingAddressFromAddressBookByRegisteredCustomer()
  239. {
  240. $maskedQuoteId = $this->assignQuoteToCustomer();
  241. $query = <<<QUERY
  242. mutation {
  243. setBillingAddressOnCart(
  244. input: {
  245. cart_id: "$maskedQuoteId"
  246. billing_address: {
  247. customer_address_id: 1
  248. }
  249. }
  250. ) {
  251. cart {
  252. billing_address {
  253. firstname
  254. lastname
  255. company
  256. street
  257. city
  258. postcode
  259. telephone
  260. }
  261. }
  262. }
  263. }
  264. QUERY;
  265. $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap());
  266. self::assertArrayHasKey('cart', $response['setBillingAddressOnCart']);
  267. $cartResponse = $response['setBillingAddressOnCart']['cart'];
  268. self::assertArrayHasKey('billing_address', $cartResponse);
  269. $billingAddressResponse = $cartResponse['billing_address'];
  270. $this->assertSavedBillingAddressFields($billingAddressResponse);
  271. }
  272. /**
  273. * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
  274. * @magentoApiDataFixture Magento/Customer/_files/customer.php
  275. * @expectedException \Exception
  276. * @expectedExceptionMessage Could not find a address with ID "100"
  277. */
  278. public function testSetNotExistedBillingAddressFromAddressBook()
  279. {
  280. $maskedQuoteId = $this->assignQuoteToCustomer();
  281. $query = <<<QUERY
  282. mutation {
  283. setBillingAddressOnCart(
  284. input: {
  285. cart_id: "$maskedQuoteId"
  286. billing_address: {
  287. customer_address_id: 100
  288. }
  289. }
  290. ) {
  291. cart {
  292. billing_address {
  293. city
  294. }
  295. }
  296. }
  297. }
  298. QUERY;
  299. $this->graphQlQuery($query, [], '', $this->getHeaderMap());
  300. }
  301. /**
  302. * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
  303. * @magentoApiDataFixture Magento/Customer/_files/customer.php
  304. * @magentoApiDataFixture Magento/Customer/_files/customer_two_addresses.php
  305. */
  306. public function testSetNewBillingAddressAndFromAddressBookAtSameTime()
  307. {
  308. $maskedQuoteId = $this->assignQuoteToCustomer();
  309. $query = <<<QUERY
  310. mutation {
  311. setBillingAddressOnCart(
  312. input: {
  313. cart_id: "$maskedQuoteId"
  314. billing_address: {
  315. customer_address_id: 1
  316. address: {
  317. firstname: "test firstname"
  318. lastname: "test lastname"
  319. company: "test company"
  320. street: ["test street 1", "test street 2"]
  321. city: "test city"
  322. region: "test region"
  323. postcode: "887766"
  324. country_code: "US"
  325. telephone: "88776655"
  326. save_in_address_book: false
  327. }
  328. }
  329. }
  330. ) {
  331. cart {
  332. billing_address {
  333. city
  334. }
  335. }
  336. }
  337. }
  338. QUERY;
  339. self::expectExceptionMessage(
  340. 'The billing address cannot contain "customer_address_id" and "address" at the same time.'
  341. );
  342. $this->graphQlQuery($query, [], '', $this->getHeaderMap());
  343. }
  344. /**
  345. * @magentoApiDataFixture Magento/Customer/_files/three_customers.php
  346. * @magentoApiDataFixture Magento/Customer/_files/customer_address.php
  347. * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
  348. * @expectedException \Exception
  349. * @expectedExceptionMessage The current user cannot use address with ID "1"
  350. */
  351. public function testSetBillingAddressIfCustomerIsNotOwnerOfAddress()
  352. {
  353. $maskedQuoteId = $this->getMaskedQuoteIdByReversedQuoteId('test_order_with_simple_product_without_address');
  354. $query = <<<QUERY
  355. mutation {
  356. setBillingAddressOnCart(
  357. input: {
  358. cart_id: "$maskedQuoteId"
  359. billing_address: {
  360. customer_address_id: 1
  361. }
  362. }
  363. ) {
  364. cart {
  365. billing_address {
  366. city
  367. }
  368. }
  369. }
  370. }
  371. QUERY;
  372. $this->graphQlQuery($query, [], '', $this->getHeaderMap('customer2@search.example.com'));
  373. }
  374. /**
  375. * Verify the all the whitelisted fields for a New Address Object
  376. *
  377. * @param array $billingAddressResponse
  378. */
  379. private function assertNewAddressFields(array $billingAddressResponse): void
  380. {
  381. $assertionMap = [
  382. ['response_field' => 'firstname', 'expected_value' => 'test firstname'],
  383. ['response_field' => 'lastname', 'expected_value' => 'test lastname'],
  384. ['response_field' => 'company', 'expected_value' => 'test company'],
  385. ['response_field' => 'street', 'expected_value' => [0 => 'test street 1', 1 => 'test street 2']],
  386. ['response_field' => 'city', 'expected_value' => 'test city'],
  387. ['response_field' => 'postcode', 'expected_value' => '887766'],
  388. ['response_field' => 'telephone', 'expected_value' => '88776655']
  389. ];
  390. $this->assertResponseFields($billingAddressResponse, $assertionMap);
  391. }
  392. /**
  393. * Verify the all the whitelisted fields for a Address Object
  394. *
  395. * @param array $billingAddressResponse
  396. */
  397. private function assertSavedBillingAddressFields(array $billingAddressResponse): void
  398. {
  399. $assertionMap = [
  400. ['response_field' => 'firstname', 'expected_value' => 'John'],
  401. ['response_field' => 'lastname', 'expected_value' => 'Smith'],
  402. ['response_field' => 'company', 'expected_value' => 'CompanyName'],
  403. ['response_field' => 'street', 'expected_value' => [0 => 'Green str, 67']],
  404. ['response_field' => 'city', 'expected_value' => 'CityM'],
  405. ['response_field' => 'postcode', 'expected_value' => '75477'],
  406. ['response_field' => 'telephone', 'expected_value' => '3468676']
  407. ];
  408. $this->assertResponseFields($billingAddressResponse, $assertionMap);
  409. }
  410. /**
  411. * @param string $username
  412. * @param string $password
  413. * @return array
  414. */
  415. private function getHeaderMap(string $username = 'customer@example.com', string $password = 'password'): array
  416. {
  417. $customerToken = $this->customerTokenService->createCustomerAccessToken($username, $password);
  418. $headerMap = ['Authorization' => 'Bearer ' . $customerToken];
  419. return $headerMap;
  420. }
  421. /**
  422. * @param string $reversedQuoteId
  423. * @return string
  424. */
  425. private function getMaskedQuoteIdByReversedQuoteId(string $reversedQuoteId): string
  426. {
  427. $quote = $this->quoteFactory->create();
  428. $this->quoteResource->load($quote, $reversedQuoteId, 'reserved_order_id');
  429. return $this->quoteIdToMaskedId->execute((int)$quote->getId());
  430. }
  431. /**
  432. * @param string $reversedQuoteId
  433. * @param int $customerId
  434. * @return string
  435. */
  436. private function assignQuoteToCustomer(
  437. string $reversedQuoteId = 'test_order_with_simple_product_without_address',
  438. int $customerId = 1
  439. ): string {
  440. $quote = $this->quoteFactory->create();
  441. $this->quoteResource->load($quote, $reversedQuoteId, 'reserved_order_id');
  442. $quote->setCustomerId($customerId);
  443. $this->quoteResource->save($quote);
  444. return $this->quoteIdToMaskedId->execute((int)$quote->getId());
  445. }
  446. public function tearDown()
  447. {
  448. /** @var \Magento\Config\Model\ResourceModel\Config $config */
  449. $config = ObjectManager::getInstance()->get(\Magento\Config\Model\ResourceModel\Config::class);
  450. //default state of multishipping config
  451. $config->saveConfig(
  452. Data::XML_PATH_CHECKOUT_MULTIPLE_AVAILABLE,
  453. 1,
  454. ScopeConfigInterface::SCOPE_TYPE_DEFAULT,
  455. 0
  456. );
  457. /** @var \Magento\Framework\App\Config\ReinitableConfigInterface $config */
  458. $config = ObjectManager::getInstance()->get(\Magento\Framework\App\Config\ReinitableConfigInterface::class);
  459. $config->reinit();
  460. }
  461. }