DataTest.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Catalog\Helper;
  7. use Magento\Store\Model\ScopeInterface;
  8. use Magento\Tax\Model\ClassModel;
  9. use Magento\Tax\Model\Config;
  10. use Magento\Tax\Model\TaxRuleFixtureFactory;
  11. /**
  12. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  13. */
  14. class DataTest extends \PHPUnit\Framework\TestCase
  15. {
  16. /**
  17. * Tax helper
  18. *
  19. * @var \Magento\Catalog\Helper\Data
  20. */
  21. private $helper;
  22. /**
  23. * Object Manager
  24. *
  25. * @var \Magento\Framework\ObjectManagerInterface
  26. */
  27. private $objectManager;
  28. /**
  29. * Array of default tax classes ids
  30. *
  31. * Key is class name
  32. *
  33. * @var int[]
  34. */
  35. private $taxClasses;
  36. /**
  37. * Array of default tax rates ids.
  38. *
  39. * Key is rate percentage as string.
  40. *
  41. * @var int[]
  42. */
  43. private $taxRates;
  44. /**
  45. * Array of default tax rules ids.
  46. *
  47. * Key is rule code.
  48. *
  49. * @var int[]
  50. */
  51. private $taxRules;
  52. /**
  53. * Helps in creating required tax rules.
  54. *
  55. * @var TaxRuleFixtureFactory
  56. */
  57. private $taxRuleFixtureFactory;
  58. /**
  59. * @var \Magento\Framework\App\MutableScopeConfig
  60. */
  61. private $scopeConfig;
  62. protected function setUp()
  63. {
  64. $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
  65. $this->helper = $this->objectManager->get(\Magento\Catalog\Helper\Data::class);
  66. $this->taxRuleFixtureFactory = new TaxRuleFixtureFactory();
  67. $this->scopeConfig = $this->objectManager->get(\Magento\Framework\App\MutableScopeConfig::class);
  68. }
  69. protected function tearDown()
  70. {
  71. $this->tearDownDefaultRules();
  72. }
  73. /**
  74. * @magentoDataFixture Magento/Catalog/_files/categories.php
  75. * @magentoDbIsolation enabled
  76. * @magentoAppIsolation enabled
  77. */
  78. public function testGetBreadcrumbPath()
  79. {
  80. $category = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
  81. \Magento\Catalog\Model\Category::class
  82. );
  83. $category->load(5);
  84. /** @var $objectManager \Magento\TestFramework\ObjectManager */
  85. $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
  86. $objectManager->get(\Magento\Framework\Registry::class)->register('current_category', $category);
  87. try {
  88. $path = $this->helper->getBreadcrumbPath();
  89. $this->assertInternalType('array', $path);
  90. $this->assertEquals(['category3', 'category4', 'category5'], array_keys($path));
  91. $this->assertArrayHasKey('label', $path['category3']);
  92. $this->assertArrayHasKey('link', $path['category3']);
  93. $objectManager->get(\Magento\Framework\Registry::class)->unregister('current_category');
  94. } catch (\Exception $e) {
  95. $objectManager->get(\Magento\Framework\Registry::class)->unregister('current_category');
  96. throw $e;
  97. }
  98. }
  99. public function testGetCategory()
  100. {
  101. $category = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
  102. \Magento\Catalog\Model\Category::class
  103. );
  104. /** @var $objectManager \Magento\TestFramework\ObjectManager */
  105. $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
  106. $objectManager->get(\Magento\Framework\Registry::class)->register('current_category', $category);
  107. try {
  108. $this->assertSame($category, $this->helper->getCategory());
  109. $objectManager->get(\Magento\Framework\Registry::class)->unregister('current_category');
  110. } catch (\Exception $e) {
  111. $objectManager->get(\Magento\Framework\Registry::class)->unregister('current_category');
  112. throw $e;
  113. }
  114. }
  115. public function testGetProduct()
  116. {
  117. $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
  118. \Magento\Catalog\Model\Product::class
  119. );
  120. /** @var $objectManager \Magento\TestFramework\ObjectManager */
  121. $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
  122. $objectManager->get(\Magento\Framework\Registry::class)->register('current_product', $product);
  123. try {
  124. $this->assertSame($product, $this->helper->getProduct());
  125. $objectManager->get(\Magento\Framework\Registry::class)->unregister('current_product');
  126. } catch (\Exception $e) {
  127. $objectManager->get(\Magento\Framework\Registry::class)->unregister('current_product');
  128. throw $e;
  129. }
  130. }
  131. public function testSplitSku()
  132. {
  133. $sku = 'one-two-three';
  134. $this->assertEquals(['on', 'e-', 'tw', 'o-', 'th', 're', 'e'], $this->helper->splitSku($sku, 2));
  135. }
  136. public function testGetAttributeHiddenFields()
  137. {
  138. $this->assertEquals([], $this->helper->getAttributeHiddenFields());
  139. /** @var $objectManager \Magento\TestFramework\ObjectManager */
  140. $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
  141. $objectManager->get(\Magento\Framework\Registry::class)->register('attribute_type_hidden_fields', 'test');
  142. try {
  143. $this->assertEquals('test', $this->helper->getAttributeHiddenFields());
  144. $objectManager->get(\Magento\Framework\Registry::class)->unregister('attribute_type_hidden_fields');
  145. } catch (\Exception $e) {
  146. $objectManager->get(\Magento\Framework\Registry::class)->unregister('attribute_type_hidden_fields');
  147. throw $e;
  148. }
  149. }
  150. public function testGetPriceScopeDefault()
  151. {
  152. // $this->assertEquals(\Magento\Store\Model\Store::PRICE_SCOPE_GLOBAL, $this->helper->getPriceScope());
  153. $this->assertNull($this->helper->getPriceScope());
  154. }
  155. /**
  156. * @magentoConfigFixture current_store catalog/price/scope 1
  157. */
  158. public function testGetPriceScope()
  159. {
  160. $this->assertEquals(\Magento\Store\Model\Store::PRICE_SCOPE_WEBSITE, $this->helper->getPriceScope());
  161. }
  162. public function testIsPriceGlobalDefault()
  163. {
  164. $this->assertTrue($this->helper->isPriceGlobal());
  165. }
  166. /**
  167. * @magentoConfigFixture current_store catalog/price/scope 1
  168. */
  169. public function testIsPriceGlobal()
  170. {
  171. $this->assertFalse($this->helper->isPriceGlobal());
  172. }
  173. public function testIsUsingStaticUrlsAllowedDefault()
  174. {
  175. $this->assertFalse($this->helper->isUsingStaticUrlsAllowed());
  176. }
  177. /**
  178. * isUsingStaticUrlsAllowed()
  179. * setStoreId()
  180. * @magentoConfigFixture current_store cms/wysiwyg/use_static_urls_in_catalog 1
  181. */
  182. public function testIsUsingStaticUrlsAllowed()
  183. {
  184. $this->assertTrue($this->helper->isUsingStaticUrlsAllowed());
  185. $this->helper->setStoreId(
  186. \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
  187. \Magento\Store\Model\StoreManagerInterface::class
  188. )->getStore()->getId()
  189. );
  190. $this->assertTrue($this->helper->isUsingStaticUrlsAllowed());
  191. }
  192. public function testIsUrlDirectivesParsingAllowedDefault()
  193. {
  194. $this->assertTrue($this->helper->isUrlDirectivesParsingAllowed());
  195. }
  196. /**
  197. * isUrlDirectivesParsingAllowed()
  198. * setStoreId()
  199. * @magentoConfigFixture current_store catalog/frontend/parse_url_directives 0
  200. */
  201. public function testIsUrlDirectivesParsingAllowed()
  202. {
  203. $this->assertFalse($this->helper->isUrlDirectivesParsingAllowed());
  204. $this->helper->setStoreId(
  205. \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
  206. \Magento\Store\Model\StoreManagerInterface::class
  207. )->getStore()->getId()
  208. );
  209. $this->assertFalse($this->helper->isUrlDirectivesParsingAllowed());
  210. }
  211. public function testGetPageTemplateProcessor()
  212. {
  213. $this->assertInstanceOf(\Magento\Framework\Filter\Template::class, $this->helper->getPageTemplateProcessor());
  214. }
  215. /**
  216. * @param \Magento\Framework\DataObject $input
  217. * @param float $expectOutputPrice
  218. * @param string[] $configs
  219. * @param string $productClassName
  220. *
  221. * @magentoDataFixture Magento/Catalog/_files/products.php
  222. * @magentoDataFixture Magento/Customer/_files/customer.php
  223. * @magentoDataFixture Magento/Customer/_files/customer_address.php
  224. * @magentoDbIsolation enabled
  225. * @magentoAppIsolation enabled
  226. * @dataProvider getTaxPriceDataProvider
  227. */
  228. public function testGetTaxPrice(
  229. $input,
  230. $expectOutputPrice,
  231. $configs = [],
  232. $productClassName = 'DefaultProductClass'
  233. ) {
  234. $this->setUpDefaultRules();
  235. /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
  236. $productRepository = $this->objectManager->get(\Magento\Catalog\Api\ProductRepositoryInterface::class);
  237. /** @var \Magento\Catalog\Model\Product $product */
  238. $product = $productRepository->get('simple');
  239. $product->setTaxClassId($this->taxClasses[$productClassName]);
  240. $shippingAddress = $this->getCustomerAddress();
  241. $billingAddress = $shippingAddress;
  242. foreach ($configs as $config) {
  243. $this->scopeConfig->setValue($config['path'], $config['value'], ScopeInterface::SCOPE_STORE, 'default');
  244. }
  245. $price = $this->helper->getTaxPrice(
  246. $product,
  247. $input->getPrice(),
  248. $input->getIncludingTax(),
  249. $shippingAddress,
  250. $billingAddress,
  251. $this->taxClasses['DefaultCustomerClass'],
  252. $input->getStore(),
  253. $input->getPriceIncludesTax(),
  254. $input->getRoundPrice()
  255. );
  256. if ($input->getNotEqual()) {
  257. $this->assertNotEquals($expectOutputPrice, $price);
  258. } else {
  259. $this->assertEquals($expectOutputPrice, $price);
  260. }
  261. }
  262. /**
  263. * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
  264. */
  265. public function getTaxPriceDataProvider()
  266. {
  267. return [
  268. 'price is 0' => [
  269. (new \Magento\Framework\DataObject())->setPrice(0),
  270. 0,
  271. ],
  272. 'no price conversion, round' => [
  273. (new \Magento\Framework\DataObject())->setPrice(3.256)->setRoundPrice(true),
  274. '3.26',
  275. ],
  276. 'no price conversion, no round' => [
  277. (new \Magento\Framework\DataObject())->setPrice(3.256),
  278. '3.256',
  279. ],
  280. 'price conversion, display including tax, round' => [
  281. (new \Magento\Framework\DataObject())->setPrice(3.256)->setRoundPrice(true),
  282. '3.5',
  283. [
  284. [
  285. 'path' => Config::CONFIG_XML_PATH_PRICE_INCLUDES_TAX,
  286. 'value' => '0',
  287. ],
  288. [
  289. 'path' => Config::CONFIG_XML_PATH_PRICE_DISPLAY_TYPE,
  290. 'value' => Config::DISPLAY_TYPE_INCLUDING_TAX,
  291. ],
  292. ],
  293. ],
  294. 'price conversion, display including tax, no round' => [
  295. (new \Magento\Framework\DataObject())->setPrice(3.256)->setNotEqual(true),
  296. '3.5', // should be not equal to rounded value (eg, 3.5045009999999999)
  297. [
  298. [
  299. 'path' => Config::CONFIG_XML_PATH_PRICE_INCLUDES_TAX,
  300. 'value' => '0',
  301. ],
  302. [
  303. 'path' => Config::CONFIG_XML_PATH_PRICE_DISPLAY_TYPE,
  304. 'value' => Config::DISPLAY_TYPE_INCLUDING_TAX,
  305. ],
  306. ],
  307. ],
  308. 'price conversion, display including tax, high rate product tax class, cross boarder trade, round' => [
  309. (new \Magento\Framework\DataObject())->setPrice(3.256)->setRoundPrice(true),
  310. '3.98', // rounding issue: old code expects 3.97
  311. [
  312. [
  313. 'path' => Config::CONFIG_XML_PATH_PRICE_INCLUDES_TAX,
  314. 'value' => '0',
  315. ],
  316. [
  317. 'path' => Config::CONFIG_XML_PATH_PRICE_DISPLAY_TYPE,
  318. 'value' => Config::DISPLAY_TYPE_INCLUDING_TAX,
  319. ],
  320. [
  321. 'path' => Config::CONFIG_XML_PATH_CROSS_BORDER_TRADE_ENABLED,
  322. 'value' => '1',
  323. ],
  324. ],
  325. 'HigherProductClass',
  326. ],
  327. 'price include tax, display including tax, round' => [
  328. (new \Magento\Framework\DataObject())->setPrice(3.256)->setRoundPrice(true),
  329. '3.26',
  330. [
  331. [
  332. 'path' => Config::CONFIG_XML_PATH_PRICE_INCLUDES_TAX,
  333. 'value' => '1',
  334. ],
  335. [
  336. 'path' => Config::CONFIG_XML_PATH_PRICE_DISPLAY_TYPE,
  337. 'value' => Config::DISPLAY_TYPE_INCLUDING_TAX,
  338. ],
  339. ],
  340. ],
  341. 'price include tax, display excluding tax, round' => [
  342. (new \Magento\Framework\DataObject())->setPrice(3.256)->setRoundPrice(true),
  343. '3.03',
  344. [
  345. [
  346. 'path' => Config::CONFIG_XML_PATH_PRICE_INCLUDES_TAX,
  347. 'value' => '1',
  348. ],
  349. [
  350. 'path' => Config::CONFIG_XML_PATH_PRICE_DISPLAY_TYPE,
  351. 'value' => Config::DISPLAY_TYPE_EXCLUDING_TAX,
  352. ],
  353. ],
  354. ],
  355. 'price include tax, display excluding tax, request including tax, round' => [
  356. (new \Magento\Framework\DataObject())->setPrice(3.256)
  357. ->setRoundPrice(true)
  358. ->setIncludingTax(true),
  359. '3.26',
  360. [
  361. [
  362. 'path' => Config::CONFIG_XML_PATH_PRICE_INCLUDES_TAX,
  363. 'value' => '1',
  364. ],
  365. [
  366. 'path' => Config::CONFIG_XML_PATH_PRICE_DISPLAY_TYPE,
  367. 'value' => Config::DISPLAY_TYPE_EXCLUDING_TAX,
  368. ],
  369. ],
  370. ],
  371. 'price include tax, display excluding tax, high rate product tax class, round' => [
  372. (new \Magento\Framework\DataObject())->setPrice(3.256)->setRoundPrice(true),
  373. '2.97',
  374. [
  375. [
  376. 'path' => Config::CONFIG_XML_PATH_PRICE_INCLUDES_TAX,
  377. 'value' => '1',
  378. ],
  379. [
  380. 'path' => Config::CONFIG_XML_PATH_PRICE_DISPLAY_TYPE,
  381. 'value' => Config::DISPLAY_TYPE_EXCLUDING_TAX,
  382. ],
  383. ],
  384. 'HigherProductClass',
  385. ],
  386. 'price include tax, display excluding tax, high rate product tax class, cross boarder trade, round' => [
  387. (new \Magento\Framework\DataObject())->setPrice(3.256)->setRoundPrice(true),
  388. '2.67',
  389. [
  390. [
  391. 'path' => Config::CONFIG_XML_PATH_PRICE_INCLUDES_TAX,
  392. 'value' => '1',
  393. ],
  394. [
  395. 'path' => Config::CONFIG_XML_PATH_PRICE_DISPLAY_TYPE,
  396. 'value' => Config::DISPLAY_TYPE_EXCLUDING_TAX,
  397. ],
  398. [
  399. 'path' => Config::CONFIG_XML_PATH_CROSS_BORDER_TRADE_ENABLED,
  400. 'value' => '1',
  401. ],
  402. ],
  403. 'HigherProductClass',
  404. ],
  405. ];
  406. }
  407. /**
  408. * Helper function that sets up some default rules
  409. */
  410. private function setUpDefaultRules()
  411. {
  412. $this->taxClasses = $this->taxRuleFixtureFactory->createTaxClasses([
  413. ['name' => 'DefaultCustomerClass', 'type' => ClassModel::TAX_CLASS_TYPE_CUSTOMER],
  414. ['name' => 'DefaultProductClass', 'type' => ClassModel::TAX_CLASS_TYPE_PRODUCT],
  415. ['name' => 'HigherProductClass', 'type' => ClassModel::TAX_CLASS_TYPE_PRODUCT],
  416. ]);
  417. $this->taxRates = $this->taxRuleFixtureFactory->createTaxRates([
  418. ['percentage' => 7.5, 'country' => 'US', 'region' => 42],
  419. ['percentage' => 7.5, 'country' => 'US', 'region' => 12], // Default store rate
  420. ]);
  421. $higherRates = $this->taxRuleFixtureFactory->createTaxRates([
  422. ['percentage' => 22, 'country' => 'US', 'region' => 42],
  423. ['percentage' => 10, 'country' => 'US', 'region' => 12], // Default store rate
  424. ]);
  425. $this->taxRules = $this->taxRuleFixtureFactory->createTaxRules([
  426. [
  427. 'code' => 'Default Rule',
  428. 'customer_tax_class_ids' => [$this->taxClasses['DefaultCustomerClass'], 3],
  429. 'product_tax_class_ids' => [$this->taxClasses['DefaultProductClass']],
  430. 'tax_rate_ids' => array_values($this->taxRates),
  431. 'sort_order' => 0,
  432. 'priority' => 0,
  433. ],
  434. [
  435. 'code' => 'Higher Rate Rule',
  436. 'customer_tax_class_ids' => [$this->taxClasses['DefaultCustomerClass'], 3],
  437. 'product_tax_class_ids' => [$this->taxClasses['HigherProductClass']],
  438. 'tax_rate_ids' => array_values($higherRates),
  439. 'sort_order' => 0,
  440. 'priority' => 0,
  441. ],
  442. ]);
  443. // For cleanup
  444. $this->taxRates = array_merge($this->taxRates, $higherRates);
  445. }
  446. /**
  447. * Get fixture customer address
  448. *
  449. * @return \Magento\Customer\Model\Address
  450. */
  451. private function getCustomerAddress()
  452. {
  453. $fixtureCustomerId = 1;
  454. $customerAddress = $this->objectManager->create(
  455. \Magento\Customer\Model\Address::class
  456. )->load($fixtureCustomerId);
  457. /** Set data which corresponds tax class fixture */
  458. $customerAddress->setCountryId('US')->setRegionId(42)->save();
  459. return $customerAddress;
  460. }
  461. /**
  462. * Helper function that tears down some default rules
  463. */
  464. private function tearDownDefaultRules()
  465. {
  466. if ($this->taxRules) {
  467. $this->taxRuleFixtureFactory->deleteTaxRules(array_values($this->taxRules));
  468. }
  469. if ($this->taxRates) {
  470. $this->taxRuleFixtureFactory->deleteTaxRates(array_values($this->taxRates));
  471. }
  472. if ($this->taxClasses) {
  473. $this->taxRuleFixtureFactory->deleteTaxClasses(array_values($this->taxClasses));
  474. }
  475. }
  476. }