Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
TaxRateRepositoryTest.php
Go to the documentation of this file.
1 <?php
7 namespace Magento\Tax\Api;
8 
16 
21 {
22  const SERVICE_NAME = "taxTaxRateRepositoryV1";
23  const SERVICE_VERSION = "V1";
24  const RESOURCE_PATH = "/V1/taxRates";
25 
27  private $fixtureTaxRates;
28 
30  private $fixtureTaxClasses;
31 
33  private $fixtureTaxRules;
34 
38  private $taxRateService;
39 
41  private $filterBuilder;
42 
44  private $searchCriteriaBuilder;
45 
47  private $sortOrderBuilder;
48 
54  private $otherRates = [];
55 
59  public function setUp()
60  {
62  $this->taxRateService = $objectManager->get(\Magento\Tax\Api\TaxRateRepositoryInterface::class);
63  $this->searchCriteriaBuilder = $objectManager->create(
64  \Magento\Framework\Api\SearchCriteriaBuilder::class
65  );
66  $this->filterBuilder = $objectManager->create(
67  \Magento\Framework\Api\FilterBuilder::class
68  );
69  $this->sortOrderBuilder = $objectManager->create(
70  \Magento\Framework\Api\SortOrderBuilder::class
71  );
73  $this->getFixtureTaxRates();
74  $this->getFixtureTaxClasses();
75  $this->getFixtureTaxRules();
76  }
77 
78  public function tearDown()
79  {
80  $taxRules = $this->getFixtureTaxRules();
81  if (count($taxRules)) {
82  $taxRates = $this->getFixtureTaxRates();
83  $taxClasses = $this->getFixtureTaxClasses();
84  foreach ($taxRules as $taxRule) {
85  $taxRule->delete();
86  }
87  foreach ($taxRates as $taxRate) {
88  $taxRate->delete();
89  }
90  foreach ($taxClasses as $taxClass) {
91  $taxClass->delete();
92  }
93  }
94  if (count($this->otherRates)) {
95  foreach ($this->otherRates as $taxRate) {
96  $taxRate->delete();
97  }
98  }
99  }
100 
102  {
103  $expectedMessage = '%1 already exists.';
104  $data = [
105  'tax_rate' => [
106  'tax_country_id' => 'US',
107  'tax_region_id' => 12,
108  'tax_postcode' => '*',
109  'code' => 'US-CA-*-Rate 1',
110  'rate' => '8.2501',
111  ],
112  ];
113 
114  $serviceInfo = [
115  'rest' => [
116  'resourcePath' => self::RESOURCE_PATH,
118  ],
119  'soap' => [
120  'service' => self::SERVICE_NAME,
121  'serviceVersion' => self::SERVICE_VERSION,
122  'operation' => self::SERVICE_NAME . 'Save',
123  ],
124  ];
125  try {
126  $this->_webApiCall($serviceInfo, $data);
127  $this->fail('Expected exception was not raised');
128  } catch (\SoapFault $e) {
129  $this->assertContains(
130  $expectedMessage,
131  $e->getMessage(),
132  'SoapFault does not contain expected message.'
133  );
134  } catch (\Exception $e) {
135  $errorObj = $this->processRestExceptionResult($e);
136  $this->assertEquals($expectedMessage, $errorObj['message']);
137  $this->assertEquals(['Code'], $errorObj['parameters']);
138  }
139  }
140 
142  {
143  $data = [
144  'tax_rate' => [
145  'tax_country_id' => 'US',
146  'tax_region_id' => 12,
147  'tax_postcode' => '*',
148  'code' => 'US-CA-*-Rate 1',
149  ],
150  ];
151 
152  $serviceInfo = [
153  'rest' => [
154  'resourcePath' => self::RESOURCE_PATH,
156  ],
157  'soap' => [
158  'service' => self::SERVICE_NAME,
159  'serviceVersion' => self::SERVICE_VERSION,
160  'operation' => self::SERVICE_NAME . 'Save',
161  ],
162  ];
163  try {
164  $this->_webApiCall($serviceInfo, $data);
165  $this->fail('Expected exception was not raised');
166  } catch (\SoapFault $e) {
167  $this->assertContains(
168  'SOAP-ERROR: Encoding: object has no \'rate\' property',
169  $e->getMessage(),
170  'SoapFault does not contain expected message.'
171  );
172  } catch (\Exception $e) {
173  $errorObj = $this->processRestExceptionResult($e);
174  $this->assertEquals('"%fieldName" is required. Enter and try again.', $errorObj['message']);
175  $this->assertEquals(['fieldName' => 'percentage_rate'], $errorObj['parameters']);
176  }
177  }
178 
179  public function testCreateTaxRate()
180  {
181  $data = [
182  'tax_rate' => [
183  'tax_country_id' => 'US',
184  'tax_region_id' => 12,
185  'tax_postcode' => '*',
186  'code' => 'Test Tax Rate ' . microtime(),
187  'rate' => '8.2501',
188  ],
189  ];
190 
191  $serviceInfo = [
192  'rest' => [
193  'resourcePath' => self::RESOURCE_PATH,
195  ],
196  'soap' => [
197  'service' => self::SERVICE_NAME,
198  'serviceVersion' => self::SERVICE_VERSION,
199  'operation' => self::SERVICE_NAME . 'Save',
200  ],
201  ];
202  $result = $this->_webApiCall($serviceInfo, $data);
203  $this->assertArrayHasKey('id', $result);
204  $taxRateId = $result['id'];
207  $taxRate = Bootstrap::getObjectManager()->create(\Magento\Tax\Model\Calculation\Rate::class);
208  $this->assertEquals($taxRateId, $taxRate->load($taxRateId)->getId(), 'Tax rate was not created in DB.');
209  $taxRate->delete();
210  }
211 
212  public function testCreateTaxRateWithZipRange()
213  {
214  $data = [
215  'tax_rate' => [
216  'tax_country_id' => 'US',
217  'tax_region_id' => 12,
218  'code' => 'Test Tax Rate ' . microtime(),
219  'rate' => '8.2501',
220  'zip_is_range' => 1,
221  'zip_from' => 17,
222  'zip_to' => 25,
223  ],
224  ];
225 
226  $serviceInfo = [
227  'rest' => [
228  'resourcePath' => self::RESOURCE_PATH,
230  ],
231  'soap' => [
232  'service' => self::SERVICE_NAME,
233  'serviceVersion' => self::SERVICE_VERSION,
234  'operation' => self::SERVICE_NAME . 'Save',
235  ],
236  ];
237  $result = $this->_webApiCall($serviceInfo, $data);
238  $this->assertArrayHasKey('id', $result);
239  $taxRateId = $result['id'];
242  $taxRate = Bootstrap::getObjectManager()->create(\Magento\Tax\Model\Calculation\Rate::class);
243  $this->assertEquals($taxRateId, $taxRate->load($taxRateId)->getId(), 'Tax rate was not created in DB.');
244  $this->assertEquals('17-25', $taxRate->getTaxPostcode(), 'Zip range is not saved in DB.');
245  $taxRate->delete();
246  }
247 
248  public function testCreateTaxRateWithZeroValue()
249  {
250  $data = [
251  'tax_rate' => [
252  'tax_country_id' => 'US',
253  'tax_region_id' => 12,
254  'tax_postcode' => '*',
255  'code' => 'Test Tax Rate ' . microtime(),
256  'rate' => '0.0',
257  ],
258  ];
259 
260  $serviceInfo = [
261  'rest' => [
262  'resourcePath' => self::RESOURCE_PATH,
264  ],
265  'soap' => [
266  'service' => self::SERVICE_NAME,
267  'serviceVersion' => self::SERVICE_VERSION,
268  'operation' => self::SERVICE_NAME . 'Save',
269  ],
270  ];
271  $result = $this->_webApiCall($serviceInfo, $data);
272  $this->assertArrayHasKey('id', $result);
273  $taxRateId = $result['id'];
276  $taxRate = Bootstrap::getObjectManager()->create(\Magento\Tax\Model\Calculation\Rate::class);
277  $taxModel = $taxRate->load($taxRateId);
278  $this->assertEquals($taxRateId, $taxModel->getId(), 'Tax rate was not created in DB.');
279  $this->assertEquals(0, $taxModel->getRate(), 'Tax rate value is wrong.');
280  $taxRate->delete();
281  }
282 
286  public function testUpdateTaxRate()
287  {
288  $fixtureRate = $this->getFixtureTaxRates()[0];
289 
290  $data = [
291  'tax_rate' => [
292  'id' => $fixtureRate->getId(),
293  'tax_region_id' => 43,
294  'tax_country_id' => 'US',
295  'tax_postcode' => '07400',
296  'code' => 'Test Tax Rate ' . microtime(),
297  'rate' => 3.456,
298  ],
299  ];
300 
301  $serviceInfo = [
302  'rest' => [
303  'resourcePath' => self::RESOURCE_PATH,
305  ],
306  'soap' => [
307  'service' => self::SERVICE_NAME,
308  'serviceVersion' => self::SERVICE_VERSION,
309  'operation' => self::SERVICE_NAME . 'Save',
310  ],
311  ];
312  $this->_webApiCall($serviceInfo, $data);
313  $expectedRateData = $data['tax_rate'];
316  $taxRate = Bootstrap::getObjectManager()->create(\Magento\Tax\Model\Calculation\Rate::class);
317  $taxRateModel = $taxRate->load($fixtureRate->getId());
318  $this->assertEquals($expectedRateData['id'], $taxRateModel->getId(), 'Tax rate was not updated in DB.');
319  $this->assertEquals(
320  $expectedRateData['tax_region_id'],
321  $taxRateModel->getTaxRegionId(),
322  'Tax rate was not updated in DB.'
323  );
324  $this->assertEquals(
325  $expectedRateData['tax_country_id'],
326  $taxRateModel->getTaxCountryId(),
327  'Tax rate was not updated in DB.'
328  );
329  $this->assertEquals(
330  $expectedRateData['tax_postcode'],
331  $taxRateModel->getTaxPostcode(),
332  'Tax rate was not updated in DB.'
333  );
334  $this->assertEquals($expectedRateData['code'], $taxRateModel->getCode(), 'Tax rate was not updated in DB.');
335  $this->assertEquals(
336  $expectedRateData['rate'],
337  $taxRateModel->getRate(),
338  'Tax rate was not updated in DB.'
339  );
340  }
341 
343  {
344  $data = [
345  'tax_rate' => [
346  'id' => 555,
347  'tax_region_id' => 43,
348  'tax_country_id' => 'US',
349  'tax_postcode' => '07400',
350  'code' => 'Test Tax Rate ' . microtime(),
351  'rate' => 3.456,
352  ],
353  ];
354 
355  $serviceInfo = [
356  'rest' => [
357  'resourcePath' => self::RESOURCE_PATH,
359  ],
360  'soap' => [
361  'service' => self::SERVICE_NAME,
362  'serviceVersion' => self::SERVICE_VERSION,
363  'operation' => self::SERVICE_NAME . 'Save',
364  ],
365  ];
366  try {
367  $this->_webApiCall($serviceInfo, $data);
368  $this->fail('Expected exception was not raised');
369  } catch (\Exception $e) {
370  $expectedMessage = 'No such entity with %fieldName = %fieldValue';
371 
372  $this->assertContains(
373  $expectedMessage,
374  $e->getMessage(),
375  "Exception does not contain expected message."
376  );
377  }
378  }
379 
380  public function testGetTaxRate()
381  {
382  $taxRateId = 2;
383  $serviceInfo = [
384  'rest' => [
385  'resourcePath' => self::RESOURCE_PATH . "/$taxRateId",
387  ],
388  'soap' => [
389  'service' => self::SERVICE_NAME,
390  'serviceVersion' => self::SERVICE_VERSION,
391  'operation' => self::SERVICE_NAME . 'Get',
392  ],
393  ];
394 
395  $result = $this->_webApiCall($serviceInfo, ['rateId' => $taxRateId]);
396  $expectedRateData = [
397  'id' => 2,
398  'tax_country_id' => 'US',
399  'tax_region_id' => 43,
400  'tax_postcode' => '*',
401  'code' => 'US-NY-*-Rate 1',
402  'rate' => 8.375,
403  'titles' => [],
404  'region_name' => 'NY',
405  ];
406  $this->assertEquals($expectedRateData, $result);
407  }
408 
409  public function testGetTaxRateNotExist()
410  {
411  $taxRateId = 37865;
412  $serviceInfo = [
413  'rest' => [
414  'resourcePath' => self::RESOURCE_PATH . "/$taxRateId",
416  ],
417  'soap' => [
418  'service' => self::SERVICE_NAME,
419  'serviceVersion' => self::SERVICE_VERSION,
420  'operation' => self::SERVICE_NAME . 'Get',
421  ],
422  ];
423  try {
424  $this->_webApiCall($serviceInfo, ['rateId' => $taxRateId]);
425  $this->fail('Expected exception was not raised');
426  } catch (\Exception $e) {
427  $expectedMessage = 'No such entity with %fieldName = %fieldValue';
428 
429  $this->assertContains(
430  $expectedMessage,
431  $e->getMessage(),
432  "Exception does not contain expected message."
433  );
434  }
435  }
436 
440  public function testDeleteTaxRate()
441  {
443  $taxRules = $this->getFixtureTaxRules();
444  foreach ($taxRules as $taxRule) {
445  $taxRule->delete();
446  }
447 
448  $fixtureRate = $this->getFixtureTaxRates()[0];
449  $taxRateId = $fixtureRate->getId();
450  $serviceInfo = [
451  'rest' => [
452  'resourcePath' => self::RESOURCE_PATH . "/$taxRateId",
454  ],
455  'soap' => [
456  'service' => self::SERVICE_NAME,
457  'serviceVersion' => self::SERVICE_VERSION,
458  'operation' => self::SERVICE_NAME . 'DeleteById',
459  ],
460  ];
461 
462  $result = $this->_webApiCall($serviceInfo, ['rateId' => $taxRateId]);
463  $this->assertTrue($result);
466  $taxRate = Bootstrap::getObjectManager()->create(\Magento\Tax\Model\Calculation\Rate::class);
467  $this->assertNull($taxRate->load($taxRateId)->getId(), 'Tax rate was not deleted from DB.');
468  }
469 
475  public function testCannotDeleteTaxRate()
476  {
477  $fixtureRate = $this->getFixtureTaxRates()[0];
478  $taxRateId = $fixtureRate->getId();
479  $serviceInfo = [
480  'rest' => [
481  'resourcePath' => self::RESOURCE_PATH . "/$taxRateId",
483  ],
484  'soap' => [
485  'service' => self::SERVICE_NAME,
486  'serviceVersion' => self::SERVICE_VERSION,
487  'operation' => self::SERVICE_NAME . 'DeleteById',
488  ],
489  ];
490  try {
491  $this->_webApiCall($serviceInfo, ['rateId' => $taxRateId]);
492  $this->fail('Expected exception was not raised');
493  } catch (\Exception $e) {
494  $expectedMessage = "The tax rate can't be removed because it exists in a tax rule.";
495 
496  $this->assertContains(
497  $expectedMessage,
498  $e->getMessage(),
499  "Exception does not contain expected message."
500  );
501  }
502  }
503 
504  public function testSearchTaxRates()
505  {
506  $rates = $this->setupTaxRatesForSearch();
507 
508  // Find rates whose code is 'codeUs12'
509  $filter = $this->filterBuilder->setField(Rate::KEY_CODE)
510  ->setValue('codeUs12')
511  ->create();
512 
513  $this->searchCriteriaBuilder->addFilters([$filter]);
514 
515  $searchData = $this->searchCriteriaBuilder->create()->__toArray();
516  $requestData = ['searchCriteria' => $searchData];
517  $serviceInfo = [
518  'rest' => [
519  'resourcePath' => self::RESOURCE_PATH . '/search' . '?' . http_build_query($requestData),
521  ],
522  'soap' => [
523  'service' => self::SERVICE_NAME,
524  'serviceVersion' => self::SERVICE_VERSION,
525  'operation' => self::SERVICE_NAME . 'GetList',
526  ],
527  ];
528 
530  $searchResults = $this->_webApiCall($serviceInfo, $requestData);
531 
532  $this->assertEquals(1, $searchResults['total_count']);
533 
534  $expectedRuleData = [
535  [
536  'id' => (int)$rates['codeUs12']->getId(),
537  'tax_country_id' => $rates['codeUs12']->getTaxCountryId(),
538  'tax_region_id' => (int)$rates['codeUs12']->getTaxRegionId(),
539  'region_name' => 'CA',
540  'tax_postcode' => $rates['codeUs12']->getTaxPostcode(),
541  'code' => $rates['codeUs12']->getCode(),
542  'rate' => ((float) $rates['codeUs12']->getRate()),
543  'titles' => [],
544  ],
545  ];
546  $this->assertEquals($expectedRuleData, $searchResults['items']);
547  }
548 
549  public function testSearchTaxRatesCz()
550  {
551  // TODO: This test fails in SOAP, a generic bug searching in SOAP
552  $this->_markTestAsRestOnly();
553  $rates = $this->setupTaxRatesForSearch();
554 
555  $filterBR = $this->filterBuilder->setField(Rate::KEY_COUNTRY_ID)
556  ->setValue('BR')
557  ->create();
558  $filterUS = $this->filterBuilder->setField(Rate::KEY_COUNTRY_ID)
559  ->setValue('US')
560  ->create();
561  // Find rates which country id 'CZ'
562  $filterCZ = $this->filterBuilder->setField(Rate::KEY_COUNTRY_ID)
563  ->setValue('CZ')
564  ->create();
565  $sortOrder = $this->sortOrderBuilder
566  ->setField(Rate::KEY_POSTCODE)
567  ->setDirection(SortOrder::SORT_DESC)
568  ->create();
569  $filterRate = $this->filterBuilder->setField(Rate::KEY_PERCENTAGE_RATE)
570  ->setValue('2.2000')
571  ->create();
572  $this->searchCriteriaBuilder->addFilters([$filterBR, $filterUS, $filterCZ]);
573  // Order them by descending postcode (not the default order)
574  $this->searchCriteriaBuilder->addFilters([$filterCZ, $filterRate])
575  ->addSortOrder($sortOrder);
576  $searchData = $this->searchCriteriaBuilder->create()->__toArray();
577  $requestData = ['searchCriteria' => $searchData];
578  $serviceInfo = [
579  'rest' => [
580  'resourcePath' => self::RESOURCE_PATH . '/search' . '?' . http_build_query($requestData),
582  ],
583  'soap' => [
584  'service' => self::SERVICE_NAME,
585  'serviceVersion' => self::SERVICE_VERSION,
586  'operation' => self::SERVICE_NAME . 'GetList',
587  ],
588  ];
589 
591  $searchResults = $this->_webApiCall($serviceInfo, $requestData);
592 
593  $this->assertEquals(2, $searchResults['total_count']);
594 
595  $expectedRuleData = [
596  [
597  'id' => (int)$rates['codeCz2']->getId(),
598  'tax_country_id' => $rates['codeCz2']->getTaxCountryId(),
599  'tax_postcode' => $rates['codeCz2']->getTaxPostcode(),
600  'code' => $rates['codeCz2']->getCode(),
601  'rate' => ((float) $rates['codeCz2']->getRate()),
602  'tax_region_id' => 0,
603  'titles' => [],
604  ],
605  [
606  'id' => (int)$rates['codeCz1']->getId(),
607  'tax_country_id' => $rates['codeCz1']->getTaxCountryId(),
608  'tax_postcode' => $rates['codeCz1']->getTaxPostcode(),
609  'code' => $rates['codeCz1']->getCode(),
610  'rate' => ((float) $rates['codeCz1']->getRate()),
611  'tax_region_id' => 0,
612  'titles' => [],
613  ],
614  ];
615  $this->assertEquals($expectedRuleData, $searchResults['items']);
616  }
617 
623  private function getFixtureTaxRates()
624  {
625  if ($this->fixtureTaxRates === null) {
626  $this->fixtureTaxRates = [];
627  if ($this->getFixtureTaxRules()) {
628  $taxRateIds = (array)$this->getFixtureTaxRules()[0]->getRates();
629  foreach ($taxRateIds as $taxRateId) {
631  $taxRate = Bootstrap::getObjectManager()->create(\Magento\Tax\Model\Calculation\Rate::class);
632  $this->fixtureTaxRates[] = $taxRate->load($taxRateId);
633  }
634  }
635  }
636  return $this->fixtureTaxRates;
637  }
638 
644  private function getFixtureTaxClasses()
645  {
646  if ($this->fixtureTaxClasses === null) {
647  $this->fixtureTaxClasses = [];
648  if ($this->getFixtureTaxRules()) {
649  $taxClassIds = array_merge(
650  (array)$this->getFixtureTaxRules()[0]->getCustomerTaxClasses(),
651  (array)$this->getFixtureTaxRules()[0]->getProductTaxClasses()
652  );
653  foreach ($taxClassIds as $taxClassId) {
655  $taxClass = Bootstrap::getObjectManager()->create(\Magento\Tax\Model\ClassModel::class);
656  $this->fixtureTaxClasses[] = $taxClass->load($taxClassId);
657  }
658  }
659  }
660  return $this->fixtureTaxClasses;
661  }
662 
668  private function getFixtureTaxRules()
669  {
670  if ($this->fixtureTaxRules === null) {
671  $this->fixtureTaxRules = [];
672  $taxRuleCodes = ['Test Rule Duplicate', 'Test Rule'];
673  foreach ($taxRuleCodes as $taxRuleCode) {
675  $taxRule = Bootstrap::getObjectManager()->create(\Magento\Tax\Model\Calculation\Rule::class);
676  $taxRule->load($taxRuleCode, 'code');
677  if ($taxRule->getId()) {
678  $this->fixtureTaxRules[] = $taxRule;
679  }
680  }
681  }
682  return $this->fixtureTaxRules;
683  }
684 
690  private function setupTaxRatesForSearch()
691  {
693 
694  $taxRateUs12 = [
695  'tax_country_id' => 'US',
696  'tax_region_id' => 12,
697  'tax_postcode' => '*',
698  'code' => 'codeUs12',
699  'rate' => 22,
700  'region_name' => 'CA',
701  ];
702  $rates['codeUs12'] = $objectManager->create(\Magento\Tax\Model\Calculation\Rate::class)
703  ->setData($taxRateUs12)
704  ->save();
705 
706  $taxRateUs14 = [
707  'tax_country_id' => 'US',
708  'tax_region_id' => 14,
709  'tax_postcode' => '*',
710  'code' => 'codeUs14',
711  'rate' => 22,
712  ];
713  $rates['codeUs14'] = $objectManager->create(\Magento\Tax\Model\Calculation\Rate::class)
714  ->setData($taxRateUs14)
715  ->save();
716  $taxRateBr13 = [
717  'tax_country_id' => 'BR',
718  'tax_region_id' => 13,
719  'tax_postcode' => '*',
720  'code' => 'codeBr13',
721  'rate' => 7.5,
722  ];
723  $rates['codeBr13'] = $objectManager->create(\Magento\Tax\Model\Calculation\Rate::class)
724  ->setData($taxRateBr13)
725  ->save();
726 
727  $taxRateCz1 = [
728  'tax_country_id' => 'CZ',
729  'tax_postcode' => '110 00',
730  'code' => 'codeCz1',
731  'rate' => 1.1,
732  ];
733  $rates['codeCz1'] = $objectManager->create(\Magento\Tax\Model\Calculation\Rate::class)
734  ->setData($taxRateCz1)
735  ->save();
736  $taxRateCz2 = [
737  'tax_country_id' => 'CZ',
738  'tax_postcode' => '250 00',
739  'code' => 'codeCz2',
740  'rate' => 2.2,
741  ];
742  $rates['codeCz2'] = $objectManager->create(\Magento\Tax\Model\Calculation\Rate::class)
743  ->setData($taxRateCz2)
744  ->save();
745 
746  // Set class variable so rates will be deleted on tearDown()
747  $this->otherRates = $rates;
748  return $rates;
749  }
750 }
$objectManager
Definition: bootstrap.php:17
_webApiCall( $serviceInfo, $arguments=[], $webApiAdapterCode=null, $storeCode=null, $integration=null)
$rates
Definition: tax.phtml:35
$taxRule
Definition: tax_rule.php:35
$taxRate
Definition: tax_rule.php:12