RateRepository.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. <?php
  2. /**
  3. *
  4. * Copyright © Magento, Inc. All rights reserved.
  5. * See COPYING.txt for license details.
  6. */
  7. namespace Magento\Tax\Model\Calculation;
  8. use Magento\Directory\Model\CountryFactory;
  9. use Magento\Directory\Model\RegionFactory;
  10. use Magento\Framework\Api\Search\FilterGroup;
  11. use Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface;
  12. use Magento\Framework\Exception\InputException;
  13. use Magento\Framework\Exception\LocalizedException;
  14. use Magento\Tax\Model\Calculation\Rate\Converter;
  15. use Magento\Tax\Model\ResourceModel\Calculation\Rate\Collection;
  16. /**
  17. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  18. */
  19. class RateRepository implements \Magento\Tax\Api\TaxRateRepositoryInterface
  20. {
  21. const MESSAGE_TAX_RATE_ID_IS_NOT_ALLOWED = 'id is not expected for this request.';
  22. /**
  23. * Tax rate model and tax rate data object converter
  24. *
  25. * @var Converter
  26. */
  27. protected $converter;
  28. /**
  29. * Tax rate registry
  30. *
  31. * @var RateRegistry
  32. */
  33. protected $rateRegistry;
  34. /**
  35. * @var \Magento\Tax\Api\Data\TaxRuleSearchResultsInterfaceFactory
  36. */
  37. private $taxRateSearchResultsFactory;
  38. /**
  39. * @var RateFactory
  40. */
  41. private $rateFactory;
  42. /**
  43. * @var \Magento\Directory\Model\CountryFactory
  44. */
  45. protected $countryFactory;
  46. /**
  47. * @var \Magento\Directory\Model\RegionFactory
  48. */
  49. protected $regionFactory;
  50. /**
  51. * @var \Magento\Tax\Model\ResourceModel\Calculation\Rate
  52. */
  53. protected $resourceModel;
  54. /**
  55. * @var \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface
  56. */
  57. protected $joinProcessor;
  58. /**
  59. * @var \Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface
  60. */
  61. private $collectionProcessor;
  62. /**
  63. * @param Converter $converter
  64. * @param RateRegistry $rateRegistry
  65. * @param \Magento\Tax\Api\Data\TaxRuleSearchResultsInterfaceFactory $taxRateSearchResultsFactory
  66. * @param RateFactory $rateFactory
  67. * @param CountryFactory $countryFactory
  68. * @param RegionFactory $regionFactory
  69. * @param \Magento\Tax\Model\ResourceModel\Calculation\Rate $rateResource
  70. * @param \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $joinProcessor
  71. * @param CollectionProcessorInterface $collectionProcessor
  72. */
  73. public function __construct(
  74. Converter $converter,
  75. RateRegistry $rateRegistry,
  76. \Magento\Tax\Api\Data\TaxRuleSearchResultsInterfaceFactory $taxRateSearchResultsFactory,
  77. RateFactory $rateFactory,
  78. CountryFactory $countryFactory,
  79. RegionFactory $regionFactory,
  80. \Magento\Tax\Model\ResourceModel\Calculation\Rate $rateResource,
  81. \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $joinProcessor,
  82. CollectionProcessorInterface $collectionProcessor = null
  83. ) {
  84. $this->converter = $converter;
  85. $this->rateRegistry = $rateRegistry;
  86. $this->taxRateSearchResultsFactory = $taxRateSearchResultsFactory;
  87. $this->rateFactory = $rateFactory;
  88. $this->countryFactory = $countryFactory;
  89. $this->regionFactory = $regionFactory;
  90. $this->resourceModel = $rateResource;
  91. $this->joinProcessor = $joinProcessor;
  92. $this->collectionProcessor = $collectionProcessor ?: $this->getCollectionProcessor();
  93. }
  94. /**
  95. * {@inheritdoc}
  96. */
  97. public function save(\Magento\Tax\Api\Data\TaxRateInterface $taxRate)
  98. {
  99. if ($taxRate->getId()) {
  100. $this->rateRegistry->retrieveTaxRate($taxRate->getId());
  101. }
  102. $this->validate($taxRate);
  103. $taxRateTitles = $this->converter->createTitleArrayFromServiceObject($taxRate);
  104. try {
  105. $this->resourceModel->save($taxRate);
  106. $taxRate->saveTitles($taxRateTitles);
  107. } catch (LocalizedException $e) {
  108. throw $e;
  109. }
  110. $this->rateRegistry->registerTaxRate($taxRate);
  111. return $taxRate;
  112. }
  113. /**
  114. * {@inheritdoc}
  115. */
  116. public function get($rateId)
  117. {
  118. return $this->rateRegistry->retrieveTaxRate($rateId);
  119. }
  120. /**
  121. * {@inheritdoc}
  122. */
  123. public function delete(\Magento\Tax\Api\Data\TaxRateInterface $taxRate)
  124. {
  125. return $this->resourceModel->delete($taxRate);
  126. }
  127. /**
  128. * {@inheritdoc}
  129. */
  130. public function deleteById($rateId)
  131. {
  132. $rateModel = $this->rateRegistry->retrieveTaxRate($rateId);
  133. $this->delete($rateModel);
  134. $this->rateRegistry->removeTaxRate($rateId);
  135. return true;
  136. }
  137. /**
  138. * {@inheritdoc}
  139. */
  140. public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCriteria)
  141. {
  142. /** @var \Magento\Tax\Model\ResourceModel\Calculation\Rate\Collection $collection */
  143. $collection = $this->rateFactory->create()->getCollection();
  144. $this->joinProcessor->process($collection);
  145. $collection->joinRegionTable();
  146. $this->collectionProcessor->process($searchCriteria, $collection);
  147. $taxRate = [];
  148. /** @var \Magento\Tax\Model\Calculation\Rate $taxRateModel */
  149. foreach ($collection as $taxRateModel) {
  150. $taxRate[] = $taxRateModel;
  151. }
  152. return $this->taxRateSearchResultsFactory->create()
  153. ->setItems($taxRate)
  154. ->setTotalCount($collection->getSize())
  155. ->setSearchCriteria($searchCriteria);
  156. }
  157. /**
  158. * Helper function that adds a FilterGroup to the collection.
  159. *
  160. * @param FilterGroup $filterGroup
  161. * @param Collection $collection
  162. * @return void
  163. * @deprecated 100.2.0
  164. * @throws \Magento\Framework\Exception\InputException
  165. */
  166. protected function addFilterGroupToCollection(FilterGroup $filterGroup, Collection $collection)
  167. {
  168. $fields = [];
  169. $conditions = [];
  170. foreach ($filterGroup->getFilters() as $filter) {
  171. $condition = $filter->getConditionType() ? $filter->getConditionType() : 'eq';
  172. $fields[] = $this->translateField($filter->getField());
  173. $conditions[] = [$condition => $filter->getValue()];
  174. }
  175. if ($fields) {
  176. $collection->addFieldToFilter($fields, $conditions);
  177. }
  178. }
  179. /**
  180. * Translates a field name to a DB column name for use in collection queries.
  181. *
  182. * @deprecated 100.2.0
  183. * @param string $field a field name that should be translated to a DB column name.
  184. * @return string
  185. */
  186. protected function translateField($field)
  187. {
  188. switch ($field) {
  189. case Rate::KEY_REGION_NAME:
  190. return 'region_table.code';
  191. default:
  192. return "main_table." . $field;
  193. }
  194. }
  195. /**
  196. * Validate tax rate
  197. *
  198. * @param \Magento\Tax\Api\Data\TaxRateInterface $taxRate
  199. * @throws InputException
  200. * @return void
  201. *
  202. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  203. * @SuppressWarnings(PHPMD.NPathComplexity)
  204. */
  205. private function validate(\Magento\Tax\Api\Data\TaxRateInterface $taxRate)
  206. {
  207. $exception = new InputException();
  208. $countryCode = $taxRate->getTaxCountryId();
  209. if (!\Zend_Validate::is($countryCode, 'NotEmpty')) {
  210. $exception->addError(__('"%fieldName" is required. Enter and try again.', ['fieldName' => 'country_id']));
  211. } elseif (!\Zend_Validate::is(
  212. $this->countryFactory->create()->loadByCode($countryCode)->getId(),
  213. 'NotEmpty'
  214. )) {
  215. $exception->addError(
  216. __(
  217. 'Invalid value of "%value" provided for the %fieldName field.',
  218. [
  219. 'fieldName' => 'country_id',
  220. 'value' => $countryCode
  221. ]
  222. )
  223. );
  224. }
  225. $regionCode = $taxRate->getTaxRegionId();
  226. // if regionCode eq 0 (all regions *), do not validate with existing region list
  227. if (\Zend_Validate::is($regionCode, 'NotEmpty') &&
  228. $regionCode != "0" && !\Zend_Validate::is(
  229. $this->regionFactory->create()->load($regionCode)->getId(),
  230. 'NotEmpty'
  231. )
  232. ) {
  233. $exception->addError(
  234. __(
  235. 'Invalid value of "%value" provided for the %fieldName field.',
  236. ['fieldName' => 'region_id', 'value' => $regionCode]
  237. )
  238. );
  239. }
  240. if (!is_numeric($taxRate->getRate()) || $taxRate->getRate() < 0) {
  241. $exception->addError(
  242. __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'percentage_rate'])
  243. );
  244. }
  245. if (!\Zend_Validate::is(trim($taxRate->getCode()), 'NotEmpty')) {
  246. $exception->addError(__('"%fieldName" is required. Enter and try again.', ['fieldName' => 'code']));
  247. }
  248. if ($taxRate->getZipIsRange()) {
  249. $zipRangeFromTo = [
  250. 'zip_from' => $taxRate->getZipFrom(),
  251. 'zip_to' => $taxRate->getZipTo(),
  252. ];
  253. foreach ($zipRangeFromTo as $key => $value) {
  254. if (!is_numeric($value) || $value < 0) {
  255. $exception->addError(
  256. __(
  257. 'Invalid value of "%value" provided for the %fieldName field.',
  258. ['fieldName' => $key, 'value' => $value]
  259. )
  260. );
  261. }
  262. }
  263. if ($zipRangeFromTo['zip_from'] > $zipRangeFromTo['zip_to']) {
  264. $exception->addError(__('Range To should be equal or greater than Range From.'));
  265. }
  266. } else {
  267. if (!\Zend_Validate::is(trim($taxRate->getTaxPostcode()), 'NotEmpty')) {
  268. $exception->addError(__('"%fieldName" is required. Enter and try again.', ['fieldName' => 'postcode']));
  269. }
  270. }
  271. if ($exception->wasErrorAdded()) {
  272. throw $exception;
  273. }
  274. }
  275. /**
  276. * Retrieve collection processor
  277. *
  278. * @deprecated 100.2.0
  279. * @return CollectionProcessorInterface
  280. */
  281. private function getCollectionProcessor()
  282. {
  283. if (!$this->collectionProcessor) {
  284. $this->collectionProcessor = \Magento\Framework\App\ObjectManager::getInstance()->get(
  285. 'Magento\Tax\Model\Api\SearchCriteria\TaxRateCollectionProcessor'
  286. );
  287. }
  288. return $this->collectionProcessor;
  289. }
  290. }