RateRepositoryTest.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Tax\Test\Unit\Model\Calculation;
  7. use Magento\Framework\Exception\AlreadyExistsException;
  8. use Magento\Framework\Exception\LocalizedException;
  9. use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
  10. use Magento\Tax\Model\Calculation\RateRepository;
  11. /**
  12. * Class RateRepositoryTest
  13. * @package Magento\Tax\Test\Unit\Model\Calculation
  14. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  15. */
  16. class RateRepositoryTest extends \PHPUnit\Framework\TestCase
  17. {
  18. /**
  19. * @var RateRepository
  20. */
  21. private $model;
  22. /**
  23. * @var \PHPUnit_Framework_MockObject_MockObject
  24. */
  25. private $rateConverterMock;
  26. /**
  27. * @var \PHPUnit_Framework_MockObject_MockObject
  28. */
  29. private $rateRegistryMock;
  30. /**
  31. * @var \PHPUnit_Framework_MockObject_MockObject
  32. */
  33. private $searchResultFactory;
  34. /**
  35. * @var \PHPUnit_Framework_MockObject_MockObject
  36. */
  37. private $searchResultMock;
  38. /**
  39. * @var \PHPUnit_Framework_MockObject_MockObject
  40. */
  41. private $rateFactoryMock;
  42. /**
  43. * @var \PHPUnit_Framework_MockObject_MockObject
  44. */
  45. private $countryFactoryMock;
  46. /**
  47. * @var \PHPUnit_Framework_MockObject_MockObject
  48. */
  49. private $regionFactoryMock;
  50. /**
  51. * @var \PHPUnit_Framework_MockObject_MockObject
  52. */
  53. private $rateResourceMock;
  54. /**
  55. * @var \PHPUnit_Framework_MockObject_MockObject
  56. */
  57. private $joinProcessorMock;
  58. /**
  59. * @var \PHPUnit_Framework_MockObject_MockObject
  60. */
  61. private $collectionProcessor;
  62. protected function setUp()
  63. {
  64. $this->rateConverterMock = $this->createMock(\Magento\Tax\Model\Calculation\Rate\Converter::class);
  65. $this->rateRegistryMock = $this->createMock(\Magento\Tax\Model\Calculation\RateRegistry::class);
  66. $this->searchResultFactory = $this->createPartialMock(
  67. \Magento\Tax\Api\Data\TaxRuleSearchResultsInterfaceFactory::class,
  68. ['create']
  69. );
  70. $this->searchResultMock = $this->createMock(\Magento\Tax\Api\Data\TaxRuleSearchResultsInterface::class);
  71. $this->rateFactoryMock = $this->createPartialMock(
  72. \Magento\Tax\Model\Calculation\RateFactory::class,
  73. ['create']
  74. );
  75. $this->countryFactoryMock = $this->createPartialMock(
  76. \Magento\Directory\Model\CountryFactory::class,
  77. ['create']
  78. );
  79. $this->regionFactoryMock = $this->createPartialMock(\Magento\Directory\Model\RegionFactory::class, ['create']);
  80. $this->rateResourceMock = $this->createMock(\Magento\Tax\Model\ResourceModel\Calculation\Rate::class);
  81. $this->joinProcessorMock = $this->createMock(
  82. \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface::class
  83. );
  84. $this->collectionProcessor = $this->createMock(
  85. \Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface::class
  86. );
  87. $this->model = new RateRepository(
  88. $this->rateConverterMock,
  89. $this->rateRegistryMock,
  90. $this->searchResultFactory,
  91. $this->rateFactoryMock,
  92. $this->countryFactoryMock,
  93. $this->regionFactoryMock,
  94. $this->rateResourceMock,
  95. $this->joinProcessorMock,
  96. $this->collectionProcessor
  97. );
  98. }
  99. public function testSave()
  100. {
  101. $countryCode = 'US';
  102. $countryMock = $this->createMock(\Magento\Directory\Model\Country::class);
  103. $countryMock->expects($this->any())->method('getId')->will($this->returnValue(1));
  104. $countryMock->expects($this->any())->method('loadByCode')->with($countryCode)->will($this->returnSelf());
  105. $this->countryFactoryMock->expects($this->once())->method('create')->will($this->returnValue($countryMock));
  106. $regionId = 2;
  107. $regionMock = $this->createMock(\Magento\Directory\Model\Region::class);
  108. $regionMock->expects($this->any())->method('getId')->will($this->returnValue($regionId));
  109. $regionMock->expects($this->any())->method('load')->with($regionId)->will($this->returnSelf());
  110. $this->regionFactoryMock->expects($this->once())->method('create')->will($this->returnValue($regionMock));
  111. $rateTitles = [
  112. 'Label 1',
  113. 'Label 2',
  114. ];
  115. $rateMock = $this->getTaxRateMock([
  116. 'id' => null,
  117. 'tax_country_id' => $countryCode,
  118. 'tax_region_id' => $regionId,
  119. 'region_name' => null,
  120. 'tax_postcode' => null,
  121. 'zip_is_range' => true,
  122. 'zip_from' => 90000,
  123. 'zip_to' => 90005,
  124. 'rate' => 7.5,
  125. 'code' => 'Tax Rate Code',
  126. 'titles' => $rateTitles,
  127. ]);
  128. $this->rateConverterMock->expects($this->once())->method('createTitleArrayFromServiceObject')
  129. ->with($rateMock)->will($this->returnValue($rateTitles));
  130. $this->rateResourceMock->expects($this->once())->method('save')->with($rateMock);
  131. $rateMock->expects($this->once())->method('saveTitles')->with($rateTitles);
  132. $this->rateRegistryMock->expects($this->once())->method('registerTaxRate')->with($rateMock);
  133. $this->model->save($rateMock);
  134. }
  135. /**
  136. * @expectedException \Exception
  137. * @expectedExceptionMessage No such entity with id 9999
  138. */
  139. public function testSaveThrowsExceptionIfTargetTaxRateDoesNotExist()
  140. {
  141. $rateTitles = [
  142. 'Label 1',
  143. 'Label 2',
  144. ];
  145. $rateId = 9999;
  146. $rateMock = $this->getTaxRateMock([
  147. 'id' => $rateId,
  148. 'tax_country_id' => 'US',
  149. 'tax_region_id' => 1,
  150. 'region_name' => null,
  151. 'tax_postcode' => null,
  152. 'zip_is_range' => true,
  153. 'zip_from' => 90000,
  154. 'zip_to' => 90005,
  155. 'rate' => 7.5,
  156. 'code' => 'Tax Rate Code',
  157. 'titles' => $rateTitles,
  158. ]);
  159. $this->rateRegistryMock->expects($this->once())->method('retrieveTaxRate')->with($rateId)
  160. ->willThrowException(new \Exception('No such entity with id ' . $rateId));
  161. $this->rateResourceMock->expects($this->never())->method('save')->with($rateMock);
  162. $this->rateRegistryMock->expects($this->never())->method('registerTaxRate')->with($rateMock);
  163. $this->model->save($rateMock);
  164. }
  165. public function testGet()
  166. {
  167. $rateId = 1;
  168. $this->rateRegistryMock->expects($this->once())->method('retrieveTaxRate')->with($rateId);
  169. $this->model->get($rateId);
  170. }
  171. public function testDelete()
  172. {
  173. $rateMock = $this->getTaxRateMock(['id' => 1]);
  174. $this->rateResourceMock->expects($this->once())->method('delete')->with($rateMock);
  175. $this->model->delete($rateMock);
  176. }
  177. public function testDeleteById()
  178. {
  179. $rateId = 1;
  180. $rateMock = $this->getTaxRateMock(['id' => $rateId]);
  181. $this->rateRegistryMock->expects($this->once())->method('retrieveTaxRate')->with($rateId)
  182. ->will($this->returnValue($rateMock));
  183. $this->rateResourceMock->expects($this->once())->method('delete')->with($rateMock);
  184. $this->model->deleteById($rateId);
  185. }
  186. public function testGetList()
  187. {
  188. $searchCriteriaMock = $this->createMock(\Magento\Framework\Api\SearchCriteriaInterface::class);
  189. $searchCriteriaMock = $this->createMock(\Magento\Framework\Api\SearchCriteriaInterface::class);
  190. $rateMock = $this->getTaxRateMock([]);
  191. $objectManager = new ObjectManager($this);
  192. $items = [$rateMock];
  193. $collectionMock = $objectManager->getCollectionMock(
  194. \Magento\Tax\Model\ResourceModel\Calculation\Rate\Collection::class,
  195. $items
  196. );
  197. $collectionMock->expects($this->once())->method('joinRegionTable');
  198. $collectionMock->expects($this->once())->method('getSize')->will($this->returnValue(count($items)));
  199. $this->rateFactoryMock->expects($this->once())->method('create')->will($this->returnValue($rateMock));
  200. $rateMock->expects($this->any())->method('getCollection')->will($this->returnValue($collectionMock));
  201. $this->searchResultMock->expects($this->once())->method('setItems')->with($items)->willReturnSelf();
  202. $this->searchResultMock->expects($this->once())->method('setTotalCount')->with(count($items))
  203. ->willReturnSelf();
  204. $this->searchResultMock->expects($this->once())->method('setSearchCriteria')->with($searchCriteriaMock)
  205. ->willReturnSelf();
  206. $this->collectionProcessor->expects($this->once())
  207. ->method('process')
  208. ->with($searchCriteriaMock, $collectionMock);
  209. $this->searchResultFactory->expects($this->once())->method('create')->willReturn($this->searchResultMock);
  210. $this->joinProcessorMock->expects($this->once())->method('process')->with($collectionMock);
  211. $this->model->getList($searchCriteriaMock);
  212. }
  213. /**
  214. * Retrieve tax rate mock
  215. *
  216. * @param array $taxRateData
  217. * @return \PHPUnit_Framework_MockObject_MockObject
  218. */
  219. private function getTaxRateMock(array $taxRateData)
  220. {
  221. $taxRateMock = $this->createMock(\Magento\Tax\Model\Calculation\Rate::class);
  222. foreach ($taxRateData as $key => $value) {
  223. // convert key from snake case to upper case
  224. $taxRateMock->expects($this->any())
  225. ->method('get' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key))))
  226. ->will($this->returnValue($value));
  227. }
  228. return $taxRateMock;
  229. }
  230. /**
  231. * @dataProvider saveThrowsExceptionIfCannotSaveTitlesDataProvider
  232. * @param LocalizedException $expectedException
  233. * @param string $exceptionType
  234. * @param string $exceptionMessage
  235. * @throws LocalizedException
  236. * @throws \Exception
  237. * @throws \Magento\Framework\Exception\AlreadyExistsException
  238. */
  239. public function testSaveThrowsExceptionIfCannotSaveTitles($expectedException, $exceptionType, $exceptionMessage)
  240. {
  241. $countryCode = 'US';
  242. $countryMock = $this->createMock(\Magento\Directory\Model\Country::class);
  243. $countryMock->expects($this->any())->method('getId')->will($this->returnValue(1));
  244. $countryMock->expects($this->any())->method('loadByCode')->with($countryCode)->will($this->returnSelf());
  245. $this->countryFactoryMock->expects($this->once())->method('create')->will($this->returnValue($countryMock));
  246. $regionId = 2;
  247. $regionMock = $this->createMock(\Magento\Directory\Model\Region::class);
  248. $regionMock->expects($this->any())->method('getId')->will($this->returnValue($regionId));
  249. $regionMock->expects($this->any())->method('load')->with($regionId)->will($this->returnSelf());
  250. $this->regionFactoryMock->expects($this->once())->method('create')->will($this->returnValue($regionMock));
  251. $rateTitles = ['Label 1', 'Label 2'];
  252. $rateMock = $this->getTaxRateMock(
  253. [
  254. 'id' => null,
  255. 'tax_country_id' => $countryCode,
  256. 'tax_region_id' => $regionId,
  257. 'region_name' => null,
  258. 'tax_postcode' => null,
  259. 'zip_is_range' => true,
  260. 'zip_from' => 90000,
  261. 'zip_to' => 90005,
  262. 'rate' => 7.5,
  263. 'code' => 'Tax Rate Code',
  264. 'titles' => $rateTitles,
  265. ]
  266. );
  267. $this->rateConverterMock->expects($this->once())->method('createTitleArrayFromServiceObject')
  268. ->with($rateMock)->will($this->returnValue($rateTitles));
  269. $this->rateResourceMock->expects($this->once())->method('save')->with($rateMock);
  270. $rateMock
  271. ->expects($this->once())
  272. ->method('saveTitles')
  273. ->with($rateTitles)
  274. ->willThrowException($expectedException);
  275. $this->rateRegistryMock->expects($this->never())->method('registerTaxRate')->with($rateMock);
  276. $this->expectException($exceptionType);
  277. $this->expectExceptionMessage($exceptionMessage);
  278. $this->model->save($rateMock);
  279. }
  280. /**
  281. * @return array
  282. */
  283. public function saveThrowsExceptionIfCannotSaveTitlesDataProvider()
  284. {
  285. return [
  286. 'entity_already_exists' => [
  287. new AlreadyExistsException(__('Entity already exists')),
  288. AlreadyExistsException::class,
  289. 'Entity already exists'
  290. ],
  291. 'cannot_save_title' => [
  292. new LocalizedException(__('Cannot save titles')),
  293. LocalizedException::class,
  294. 'Cannot save titles'
  295. ]
  296. ];
  297. }
  298. public function testGetListWhenFilterGroupExists()
  299. {
  300. $searchCriteriaMock = $this->createMock(\Magento\Framework\Api\SearchCriteriaInterface::class);
  301. $objectManager = new ObjectManager($this);
  302. $rateMock = $this->getTaxRateMock([]);
  303. $items = [$rateMock];
  304. $collectionMock = $objectManager->getCollectionMock(
  305. \Magento\Tax\Model\ResourceModel\Calculation\Rate\Collection::class,
  306. $items
  307. );
  308. $rateMock = $this->getTaxRateMock([]);
  309. $this->collectionProcessor->expects($this->once())
  310. ->method('process')
  311. ->with($searchCriteriaMock, $collectionMock);
  312. $collectionMock->expects($this->once())->method('joinRegionTable');
  313. $collectionMock->expects($this->once())->method('getSize')->will($this->returnValue(count($items)));
  314. $this->rateFactoryMock->expects($this->once())->method('create')->will($this->returnValue($rateMock));
  315. $rateMock->expects($this->any())->method('getCollection')->will($this->returnValue($collectionMock));
  316. $this->searchResultMock->expects($this->once())->method('setItems')->with($items)->willReturnSelf();
  317. $this->searchResultMock->expects($this->once())->method('setTotalCount')->with(count($items))
  318. ->willReturnSelf();
  319. $this->searchResultMock->expects($this->once())->method('setSearchCriteria')->with($searchCriteriaMock)
  320. ->willReturnSelf();
  321. $this->searchResultFactory->expects($this->once())->method('create')->willReturn($this->searchResultMock);
  322. $this->joinProcessorMock->expects($this->once())->method('process')->with($collectionMock);
  323. $this->model->getList($searchCriteriaMock);
  324. }
  325. /**
  326. * @expectedException \Magento\Framework\Exception\InputException
  327. * @expectedExceptionMessage One or more input exceptions have occurred.
  328. */
  329. public function testValidate()
  330. {
  331. $regionId = 2;
  332. $rateTitles = ['Label 1', 'Label 2'];
  333. $regionMock = $this->createMock(\Magento\Directory\Model\Region::class);
  334. $regionMock->expects($this->any())->method('getId')->will($this->returnValue(''));
  335. $regionMock->expects($this->any())->method('load')->with($regionId)->will($this->returnSelf());
  336. $this->regionFactoryMock->expects($this->once())->method('create')->will($this->returnValue($regionMock));
  337. $rateMock = $this->getTaxRateMock(
  338. [
  339. 'id' => null,
  340. 'tax_country_id' => '',
  341. 'tax_region_id' => $regionId,
  342. 'region_name' => null,
  343. 'tax_postcode' => null,
  344. 'zip_is_range' => true,
  345. 'zip_from' => -90000,
  346. 'zip_to' => '',
  347. 'rate' => '',
  348. 'code' => '',
  349. 'titles' => $rateTitles,
  350. ]
  351. );
  352. $this->model->save($rateMock);
  353. }
  354. /**
  355. * @expectedException \Magento\Framework\Exception\InputException
  356. * @expectedExceptionMessage "percentage_rate" is required. Enter and try again.
  357. */
  358. public function testValidateWithNoRate()
  359. {
  360. $rateTitles = ['Label 1', 'Label 2'];
  361. $countryCode = 'US';
  362. $countryMock = $this->createMock(\Magento\Directory\Model\Country::class);
  363. $countryMock->expects($this->any())->method('getId')->will($this->returnValue(1));
  364. $countryMock->expects($this->any())->method('loadByCode')->with($countryCode)->will($this->returnSelf());
  365. $this->countryFactoryMock->expects($this->once())->method('create')->will($this->returnValue($countryMock));
  366. $regionId = 2;
  367. $regionMock = $this->createMock(\Magento\Directory\Model\Region::class);
  368. $regionMock->expects($this->any())->method('getId')->will($this->returnValue($regionId));
  369. $regionMock->expects($this->any())->method('load')->with($regionId)->will($this->returnSelf());
  370. $this->regionFactoryMock->expects($this->once())->method('create')->will($this->returnValue($regionMock));
  371. $rateMock = $this->getTaxRateMock(
  372. [
  373. 'id' => null,
  374. 'tax_country_id' => $countryCode,
  375. 'tax_region_id' => $regionId,
  376. 'region_name' => null,
  377. 'tax_postcode' => null,
  378. 'zip_is_range' => true,
  379. 'zip_from' => 90000,
  380. 'zip_to' => 90005,
  381. 'rate' => '',
  382. 'code' => 'Tax Rate Code',
  383. 'titles' => $rateTitles,
  384. ]
  385. );
  386. $this->model->save($rateMock);
  387. }
  388. /**
  389. * @expectedException \Magento\Framework\Exception\InputException
  390. * @expectedExceptionMessage "percentage_rate" is required. Enter and try again.
  391. */
  392. public function testValidateWithWrongRate()
  393. {
  394. $rateTitles = ['Label 1', 'Label 2'];
  395. $countryCode = 'US';
  396. $countryMock = $this->createMock(\Magento\Directory\Model\Country::class);
  397. $countryMock->expects($this->any())->method('getId')->will($this->returnValue(1));
  398. $countryMock->expects($this->any())->method('loadByCode')->with($countryCode)->will($this->returnSelf());
  399. $this->countryFactoryMock->expects($this->once())->method('create')->will($this->returnValue($countryMock));
  400. $regionId = 2;
  401. $regionMock = $this->createMock(\Magento\Directory\Model\Region::class);
  402. $regionMock->expects($this->any())->method('getId')->will($this->returnValue($regionId));
  403. $regionMock->expects($this->any())->method('load')->with($regionId)->will($this->returnSelf());
  404. $this->regionFactoryMock->expects($this->once())->method('create')->will($this->returnValue($regionMock));
  405. $rateMock = $this->getTaxRateMock(
  406. [
  407. 'id' => null,
  408. 'tax_country_id' => $countryCode,
  409. 'tax_region_id' => $regionId,
  410. 'region_name' => null,
  411. 'tax_postcode' => null,
  412. 'zip_is_range' => true,
  413. 'zip_from' => 90000,
  414. 'zip_to' => 90005,
  415. 'rate' => '7,9',
  416. 'code' => 'Tax Rate Code',
  417. 'titles' => $rateTitles,
  418. ]
  419. );
  420. $this->model->save($rateMock);
  421. }
  422. }