RowParser.php 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV;
  7. use Magento\Framework\Phrase;
  8. use Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\LocationDirectory;
  9. /**
  10. * Row parser.
  11. */
  12. class RowParser
  13. {
  14. /**
  15. * @var LocationDirectory
  16. */
  17. private $locationDirectory;
  18. /**
  19. * RowParser constructor.
  20. * @param LocationDirectory $locationDirectory
  21. */
  22. public function __construct(LocationDirectory $locationDirectory)
  23. {
  24. $this->locationDirectory = $locationDirectory;
  25. }
  26. /**
  27. * Retrieve columns.
  28. *
  29. * @return array
  30. */
  31. public function getColumns()
  32. {
  33. return [
  34. 'website_id',
  35. 'dest_country_id',
  36. 'dest_region_id',
  37. 'dest_zip',
  38. 'condition_name',
  39. 'condition_value',
  40. 'price',
  41. ];
  42. }
  43. /**
  44. * Parse provided row data.
  45. *
  46. * @param array $rowData
  47. * @param int $rowNumber
  48. * @param int $websiteId
  49. * @param string $conditionShortName
  50. * @param string $conditionFullName
  51. * @param ColumnResolver $columnResolver
  52. * @return array
  53. * @throws ColumnNotFoundException
  54. * @throws RowException
  55. */
  56. public function parse(
  57. array $rowData,
  58. $rowNumber,
  59. $websiteId,
  60. $conditionShortName,
  61. $conditionFullName,
  62. ColumnResolver $columnResolver
  63. ) {
  64. // validate row
  65. if (count($rowData) < 5) {
  66. throw new RowException(
  67. __(
  68. 'The Table Rates File Format is incorrect in row number "%1". Verify the format and try again.',
  69. $rowNumber
  70. )
  71. );
  72. }
  73. $countryId = $this->getCountryId($rowData, $rowNumber, $columnResolver);
  74. $regionIds = $this->getRegionIds($rowData, $rowNumber, $columnResolver, $countryId);
  75. $zipCode = $this->getZipCode($rowData, $columnResolver);
  76. $conditionValue = $this->getConditionValue($rowData, $rowNumber, $conditionFullName, $columnResolver);
  77. $price = $this->getPrice($rowData, $rowNumber, $columnResolver);
  78. $rates = [];
  79. foreach ($regionIds as $regionId) {
  80. $rates[] = [
  81. 'website_id' => $websiteId,
  82. 'dest_country_id' => $countryId,
  83. 'dest_region_id' => $regionId,
  84. 'dest_zip' => $zipCode,
  85. 'condition_name' => $conditionShortName,
  86. 'condition_value' => $conditionValue,
  87. 'price' => $price,
  88. ];
  89. }
  90. return $rates;
  91. }
  92. /**
  93. * Get country id from provided row data.
  94. *
  95. * @param array $rowData
  96. * @param int $rowNumber
  97. * @param ColumnResolver $columnResolver
  98. * @return null|string
  99. * @throws ColumnNotFoundException
  100. * @throws RowException
  101. */
  102. private function getCountryId(array $rowData, $rowNumber, ColumnResolver $columnResolver)
  103. {
  104. $countryCode = $columnResolver->getColumnValue(ColumnResolver::COLUMN_COUNTRY, $rowData);
  105. // validate country
  106. if ($this->locationDirectory->hasCountryId($countryCode)) {
  107. $countryId = $this->locationDirectory->getCountryId($countryCode);
  108. } elseif ($countryCode === '*' || $countryCode === '') {
  109. $countryId = '0';
  110. } else {
  111. throw new RowException(
  112. __(
  113. 'The "%1" country in row number "%2" is incorrect. Verify the country and try again.',
  114. $countryCode,
  115. $rowNumber
  116. )
  117. );
  118. }
  119. return $countryId;
  120. }
  121. /**
  122. * Retrieve region id from provided row data.
  123. *
  124. * @param array $rowData
  125. * @param int $rowNumber
  126. * @param ColumnResolver $columnResolver
  127. * @param int $countryId
  128. * @return array
  129. * @throws ColumnNotFoundException
  130. * @throws RowException
  131. */
  132. private function getRegionIds(array $rowData, $rowNumber, ColumnResolver $columnResolver, $countryId)
  133. {
  134. $regionCode = $columnResolver->getColumnValue(ColumnResolver::COLUMN_REGION, $rowData);
  135. if ($countryId !== '0' && $this->locationDirectory->hasRegionId($countryId, $regionCode)) {
  136. $regionIds = $this->locationDirectory->getRegionIds($countryId, $regionCode);
  137. } elseif ($regionCode === '*' || $regionCode === '') {
  138. $regionIds = [0];
  139. } else {
  140. throw new RowException(
  141. __(
  142. 'The "%1" region or state in row number "%2" is incorrect. '
  143. . 'Verify the region or state and try again.',
  144. $regionCode,
  145. $rowNumber
  146. )
  147. );
  148. }
  149. return $regionIds;
  150. }
  151. /**
  152. * Retrieve zip code from provided row data.
  153. *
  154. * @param array $rowData
  155. * @param ColumnResolver $columnResolver
  156. * @return float|int|null|string
  157. * @throws ColumnNotFoundException
  158. */
  159. private function getZipCode(array $rowData, ColumnResolver $columnResolver)
  160. {
  161. $zipCode = $columnResolver->getColumnValue(ColumnResolver::COLUMN_ZIP, $rowData);
  162. if ($zipCode === '') {
  163. $zipCode = '*';
  164. }
  165. return $zipCode;
  166. }
  167. /**
  168. * Get condition value form provided row data.
  169. *
  170. * @param array $rowData
  171. * @param int $rowNumber
  172. * @param string $conditionFullName
  173. * @param ColumnResolver $columnResolver
  174. * @return bool|float
  175. * @throws ColumnNotFoundException
  176. * @throws RowException
  177. */
  178. private function getConditionValue(array $rowData, $rowNumber, $conditionFullName, ColumnResolver $columnResolver)
  179. {
  180. // validate condition value
  181. $conditionValue = $columnResolver->getColumnValue($conditionFullName, $rowData);
  182. $value = $this->_parseDecimalValue($conditionValue);
  183. if ($value === false) {
  184. throw new RowException(
  185. __(
  186. 'Please correct %1 "%2" in the Row #%3.',
  187. $conditionFullName,
  188. $conditionValue,
  189. $rowNumber
  190. )
  191. );
  192. }
  193. return $value;
  194. }
  195. /**
  196. * Retrieve price from provided row data.
  197. *
  198. * @param array $rowData
  199. * @param int $rowNumber
  200. * @param ColumnResolver $columnResolver
  201. * @return bool|float
  202. * @throws ColumnNotFoundException
  203. * @throws RowException
  204. */
  205. private function getPrice(array $rowData, $rowNumber, ColumnResolver $columnResolver)
  206. {
  207. $priceValue = $columnResolver->getColumnValue(ColumnResolver::COLUMN_PRICE, $rowData);
  208. $price = $this->_parseDecimalValue($priceValue);
  209. if ($price === false) {
  210. throw new RowException(
  211. __(
  212. 'The "%1" shipping price in row number "%2" is incorrect. Verify the shipping price and try again.',
  213. $priceValue,
  214. $rowNumber
  215. )
  216. );
  217. }
  218. return $price;
  219. }
  220. /**
  221. * Parse and validate positive decimal value
  222. *
  223. * Return false if value is not decimal or is not positive
  224. *
  225. * @param string $value
  226. * @return bool|float
  227. */
  228. private function _parseDecimalValue($value)
  229. {
  230. $result = false;
  231. if (is_numeric($value)) {
  232. $value = (double)sprintf('%.4F', $value);
  233. if ($value >= 0.0000) {
  234. $result = $value;
  235. }
  236. }
  237. return $result;
  238. }
  239. }