![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/vendor/magento/module-tax-import-export/Model/Rate/ |
<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\TaxImportExport\Model\Rate; /** * Tax Rate CSV Import Handler * * @api * @since 100.0.2 */ class CsvImportHandler { /** * Collection of publicly available stores * * @var \Magento\Store\Model\ResourceModel\Store\Collection */ protected $_publicStores; /** * Region collection prototype * * The instance is used to retrieve regions based on country code * * @var \Magento\Directory\Model\ResourceModel\Region\Collection */ protected $_regionCollection; /** * Country factory * * @var \Magento\Directory\Model\CountryFactory */ protected $_countryFactory; /** * Tax rate factory * * @var \Magento\Tax\Model\Calculation\RateFactory */ protected $_taxRateFactory; /** * CSV Processor * * @var \Magento\Framework\File\Csv */ protected $csvProcessor; /** * @param \Magento\Store\Model\ResourceModel\Store\Collection $storeCollection * @param \Magento\Directory\Model\ResourceModel\Region\Collection $regionCollection * @param \Magento\Directory\Model\CountryFactory $countryFactory * @param \Magento\Tax\Model\Calculation\RateFactory $taxRateFactory * @param \Magento\Framework\File\Csv $csvProcessor */ public function __construct( \Magento\Store\Model\ResourceModel\Store\Collection $storeCollection, \Magento\Directory\Model\ResourceModel\Region\Collection $regionCollection, \Magento\Directory\Model\CountryFactory $countryFactory, \Magento\Tax\Model\Calculation\RateFactory $taxRateFactory, \Magento\Framework\File\Csv $csvProcessor ) { // prevent admin store from loading $this->_publicStores = $storeCollection->setLoadDefault(false); $this->_regionCollection = $regionCollection; $this->_countryFactory = $countryFactory; $this->_taxRateFactory = $taxRateFactory; $this->csvProcessor = $csvProcessor; } /** * Retrieve a list of fields required for CSV file (order is important!) * * @return array */ public function getRequiredCsvFields() { // indexes are specified for clarity, they are used during import return [ 0 => __('Code'), 1 => __('Country'), 2 => __('State'), 3 => __('Zip/Post Code'), 4 => __('Rate'), 5 => __('Zip/Post is Range'), 6 => __('Range From'), 7 => __('Range To') ]; } /** * Import Tax Rates from CSV file * * @param array $file file info retrieved from $_FILES array * @return void * @throws \Magento\Framework\Exception\LocalizedException */ public function importFromCsvFile($file) { if (!isset($file['tmp_name'])) { throw new \Magento\Framework\Exception\LocalizedException(__('Invalid file upload attempt.')); } $ratesRawData = $this->csvProcessor->getData($file['tmp_name']); // first row of file represents headers $fileFields = $ratesRawData[0]; $validFields = $this->_filterFileFields($fileFields); $invalidFields = array_diff_key($fileFields, $validFields); $ratesData = $this->_filterRateData($ratesRawData, $invalidFields, $validFields); // store cache array is used to quickly retrieve store ID when handling locale-specific tax rate titles $storesCache = $this->_composeStoreCache($validFields); $regionsCache = []; foreach ($ratesData as $rowIndex => $dataRow) { // skip headers if ($rowIndex == 0) { continue; } $regionsCache = $this->_importRate($dataRow, $regionsCache, $storesCache); } } /** * Filter file fields (i.e. unset invalid fields) * * @param array $fileFields * @return string[] filtered fields */ protected function _filterFileFields(array $fileFields) { $filteredFields = $this->getRequiredCsvFields(); $requiredFieldsNum = count($this->getRequiredCsvFields()); $fileFieldsNum = count($fileFields); // process title-related fields that are located right after required fields with store code as field name) for ($index = $requiredFieldsNum; $index < $fileFieldsNum; $index++) { $titleFieldName = $fileFields[$index]; if ($this->_isStoreCodeValid($titleFieldName)) { // if store is still valid, append this field to valid file fields $filteredFields[$index] = $titleFieldName; } } return $filteredFields; } /** * Filter rates data (i.e. unset all invalid fields and check consistency) * * @param array $rateRawData * @param array $invalidFields assoc array of invalid file fields * @param array $validFields assoc array of valid file fields * @return array * @throws \Magento\Framework\Exception\LocalizedException * @SuppressWarnings(PHPMD.UnusedLocalVariable) */ protected function _filterRateData(array $rateRawData, array $invalidFields, array $validFields) { $validFieldsNum = count($validFields); foreach ($rateRawData as $rowIndex => $dataRow) { // skip empty rows if (count($dataRow) <= 1) { unset($rateRawData[$rowIndex]); continue; } // unset invalid fields from data row foreach ($dataRow as $fieldIndex => $fieldValue) { if (isset($invalidFields[$fieldIndex])) { unset($rateRawData[$rowIndex][$fieldIndex]); } } // check if number of fields in row match with number of valid fields if (count($rateRawData[$rowIndex]) != $validFieldsNum) { throw new \Magento\Framework\Exception\LocalizedException(__('Invalid file format.')); } } return $rateRawData; } /** * Compose stores cache * * This cache is used to quickly retrieve store ID when handling locale-specific tax rate titles * * @param string[] $validFields list of valid CSV file fields * @return array */ protected function _composeStoreCache($validFields) { $storesCache = []; $requiredFieldsNum = count($this->getRequiredCsvFields()); $validFieldsNum = count($validFields); // title related fields located right after required fields for ($index = $requiredFieldsNum; $index < $validFieldsNum; $index++) { foreach ($this->_publicStores as $store) { $storeCode = $validFields[$index]; if ($storeCode === $store->getCode()) { $storesCache[$index] = $store->getId(); } } } return $storesCache; } /** * Check if public store with specified code still exists * * @param string $storeCode * @return boolean */ protected function _isStoreCodeValid($storeCode) { $isStoreCodeValid = false; foreach ($this->_publicStores as $store) { if ($storeCode === $store->getCode()) { $isStoreCodeValid = true; break; } } return $isStoreCodeValid; } /** * Import single rate * * @param array $rateData * @param array $regionsCache cache of regions of already used countries (is used to optimize performance) * @param array $storesCache cache of stores related to tax rate titles * @return array regions cache populated with regions related to country of imported tax rate * @throws \Magento\Framework\Exception\LocalizedException */ protected function _importRate(array $rateData, array $regionsCache, array $storesCache) { // data with index 1 must represent country code $countryCode = $rateData[1]; $country = $this->_countryFactory->create()->loadByCode($countryCode, 'iso2_code'); if (!$country->getId()) { throw new \Magento\Framework\Exception\LocalizedException(__('Country code is invalid: %1', $countryCode)); } $regionsCache = $this->_addCountryRegionsToCache($countryCode, $regionsCache); // data with index 2 must represent region code $regionCode = $rateData[2]; if (!empty($regionsCache[$countryCode][$regionCode])) { $regionId = $regionsCache[$countryCode][$regionCode] == '*' ? 0 : $regionsCache[$countryCode][$regionCode]; // data with index 3 must represent postcode $postCode = empty($rateData[3]) ? null : $rateData[3]; $modelData = [ 'code' => $rateData[0], 'tax_country_id' => $rateData[1], 'tax_region_id' => $regionId, 'tax_postcode' => $postCode, 'rate' => $rateData[4], 'zip_is_range' => $rateData[5], 'zip_from' => $rateData[6], 'zip_to' => $rateData[7], ]; // try to load existing rate /** @var $rateModel \Magento\Tax\Model\Calculation\Rate */ $rateModel = $this->_taxRateFactory->create()->loadByCode($modelData['code']); $rateModel->addData($modelData); // compose titles list $rateTitles = []; foreach ($storesCache as $fileFieldIndex => $storeId) { $rateTitles[$storeId] = $rateData[$fileFieldIndex]; } $rateModel->setTitle($rateTitles); $rateModel->save(); } return $regionsCache; } /** * Add regions of the given country to regions cache * * @param string $countryCode * @param array $regionsCache * @return array */ protected function _addCountryRegionsToCache($countryCode, array $regionsCache) { if (!isset($regionsCache[$countryCode])) { $regionsCache[$countryCode] = []; // add 'All Regions' to the list $regionsCache[$countryCode]['*'] = '*'; $regionCollection = clone $this->_regionCollection; $regionCollection->addCountryFilter($countryCode); if ($regionCollection->getSize()) { foreach ($regionCollection as $region) { $regionsCache[$countryCode][$region->getCode()] = $region->getRegionId(); } } } return $regionsCache; } }