diff --git a/app/code/Magento/Directory/Model/Currency/Import/CurrencyConverterApi.php b/app/code/Magento/Directory/Model/Currency/Import/CurrencyConverterApi.php
index f52886a14264d..2547974774953 100644
--- a/app/code/Magento/Directory/Model/Currency/Import/CurrencyConverterApi.php
+++ b/app/code/Magento/Directory/Model/Currency/Import/CurrencyConverterApi.php
@@ -7,30 +7,30 @@
namespace Magento\Directory\Model\Currency\Import;
+use Magento\Store\Model\ScopeInterface;
+
class CurrencyConverterApi extends AbstractImport
{
/**
* @var string
*/
- const CURRENCY_CONVERTER_URL = 'http://free.currencyconverterapi.com/api/v3/convert?q={{CURRENCY_FROM}}_{{CURRENCY_TO}}&compact=ultra'; //@codingStandardsIgnoreLine
+ const CURRENCY_CONVERTER_URL = 'https://free.currencyconverterapi.com/api/v6/convert?q={{CURRENCY_FROM}}_{{CURRENCY_TO}}'
+ . '&compact=ultra&apiKey={{ACCESS_KEY}}'; //@codingStandardsIgnoreLine
/**
* Http Client Factory
- *
* @var \Magento\Framework\HTTP\ZendClientFactory
*/
private $httpClientFactory;
/**
* Core scope config
- *
* @var \Magento\Framework\App\Config\ScopeConfigInterface
*/
private $scopeConfig;
/**
* Initialize dependencies
- *
* @param \Magento\Directory\Model\CurrencyFactory $currencyFactory
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
* @param \Magento\Framework\HTTP\ZendClientFactory $httpClientFactory
@@ -51,6 +51,14 @@ public function __construct(
public function fetchRates()
{
$data = [];
+ $accessKey = $this->scopeConfig->getValue(
+ 'currency/currencyconverterapi/api_key',
+ ScopeInterface::SCOPE_STORE
+ );
+ if (empty($accessKey)) {
+ $this->_messages[] = __('No API Key was specified or an invalid API Key was specified.');
+ return $data;
+ }
$currencies = $this->_getCurrencyCodes();
$defaultCurrencies = $this->_getDefaultCurrencyCodes();
@@ -58,7 +66,7 @@ public function fetchRates()
if (!isset($data[$currencyFrom])) {
$data[$currencyFrom] = [];
}
- $data = $this->convertBatch($data, $currencyFrom, $currencies);
+ $data = $this->convertBatch($data, $currencyFrom, $currencies, $accessKey);
ksort($data[$currencyFrom]);
}
return $data;
@@ -67,19 +75,31 @@ public function fetchRates()
/**
* Return currencies convert rates in batch mode
*
+ * @param string $accessKey
* @param array $data
* @param string $currencyFrom
* @param array $currenciesTo
* @return array
*/
- private function convertBatch($data, $currencyFrom, $currenciesTo)
+ private function convertBatch($data, $currencyFrom, $currenciesTo, $accessKey)
{
foreach ($currenciesTo as $to) {
set_time_limit(0);
try {
- $url = str_replace('{{CURRENCY_FROM}}', $currencyFrom, self::CURRENCY_CONVERTER_URL);
- $url = str_replace('{{CURRENCY_TO}}', $to, $url);
+ $url = str_replace(
+ ['{{ACCESS_KEY}}', '{{CURRENCY_FROM}}', '{{CURRENCY_TO}}'],
+ [$accessKey, $currencyFrom, $to],
+ self::CURRENCY_CONVERTER_URL
+ );
+
$response = $this->getServiceResponse($url);
+
+ if (!$this->validateResponse($response, $currencyFrom, $to)) {
+ $data[$currencyFrom][$to] = null;
+
+ return $data;
+ }
+
if ($currencyFrom == $to) {
$data[$currencyFrom][$to] = $this->_numberFormat(1);
} else {
@@ -143,4 +163,27 @@ protected function _convert($currencyFrom, $currencyTo)
{
return 1;
}
+
+ /**
+ * Validates rates response.
+ * @param array $response
+ * @param string $currencyFrom
+ * @param string $currenciesTo
+ * @return bool
+ */
+ private function validateResponse(array $response, string $currencyFrom, string $currenciesTo): bool
+ {
+ if (isset($response['error'])) {
+ $this->_messages[] = $response['error'];
+
+ return false;
+ }
+ if (empty($response[$currencyFrom . '_' . $currenciesTo])) {
+ $this->_messages[] = __('We can\'t retrieve a rate for %1.', $currenciesTo);
+
+ return false;
+ }
+
+ return true;
+ }
}
diff --git a/app/code/Magento/Directory/Test/Unit/Model/Currency/Import/CurrencyConverterApiTest.php b/app/code/Magento/Directory/Test/Unit/Model/Currency/Import/CurrencyConverterApiTest.php
new file mode 100644
index 0000000000000..00e0a20eba844
--- /dev/null
+++ b/app/code/Magento/Directory/Test/Unit/Model/Currency/Import/CurrencyConverterApiTest.php
@@ -0,0 +1,124 @@
+currencyFactory = $this->getMockBuilder(CurrencyFactory::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['create'])
+ ->getMock();
+ $this->httpClientFactory = $this->getMockBuilder(ZendClientFactory::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['create'])
+ ->getMock();
+ $this->scopeConfig = $this->getMockBuilder(ScopeConfigInterface::class)
+ ->disableOriginalConstructor()
+ ->setMethods([])
+ ->getMock();
+
+ $this->model = new CurrencyConverterApi($this->currencyFactory, $this->scopeConfig, $this->httpClientFactory);
+ }
+
+ /**
+ * Test Fetch Rates
+ *
+ * @return void
+ */
+ public function testFetchRates(): void
+ {
+ $currencyFromList = ['USD'];
+ $currencyToList = ['EUR', 'UAH'];
+ $responseBody = '{"USD_EUR":0.879215}';
+ $expectedRateList = ['USD' => ['EUR' => 0.879215, 'UAH' => null]];
+ $message = "We can't retrieve a rate for UAH.";
+
+ $this->scopeConfig->method('getValue')
+ ->withConsecutive(
+ ['currency/currencyconverterapi/api_key', 'store'],
+ ['currency/currencyconverterapi/timeout', 'store']
+ )
+ ->willReturnOnConsecutiveCalls('api_key', 100);
+
+ /** @var Currency|MockObject $currency */
+ $currency = $this->getMockBuilder(Currency::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ /** @var ZendClient|MockObject $httpClient */
+ $httpClient = $this->getMockBuilder(ZendClient::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ /** @var DataObject|MockObject $currencyMock */
+ $httpResponse = $this->getMockBuilder(DataObject::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getBody'])
+ ->getMock();
+
+ $this->currencyFactory->method('create')
+ ->willReturn($currency);
+ $currency->method('getConfigBaseCurrencies')
+ ->willReturn($currencyFromList);
+ $currency->method('getConfigAllowCurrencies')
+ ->willReturn($currencyToList);
+
+ $this->httpClientFactory->method('create')
+ ->willReturn($httpClient);
+ $httpClient->method('setUri')
+ ->willReturnSelf();
+ $httpClient->method('setConfig')
+ ->willReturnSelf();
+ $httpClient->method('request')
+ ->willReturn($httpResponse);
+ $httpResponse->method('getBody')
+ ->willReturn($responseBody);
+
+ self::assertEquals($expectedRateList, $this->model->fetchRates());
+
+ $messages = $this->model->getMessages();
+ self::assertNotEmpty($messages);
+ self::assertTrue(is_array($messages));
+ self::assertEquals($message, (string)$messages[0]);
+ }
+}
diff --git a/app/code/Magento/Directory/etc/adminhtml/system.xml b/app/code/Magento/Directory/etc/adminhtml/system.xml
index ec5fa35b6a152..eb3f2a0e9ef2b 100644
--- a/app/code/Magento/Directory/etc/adminhtml/system.xml
+++ b/app/code/Magento/Directory/etc/adminhtml/system.xml
@@ -47,7 +47,12 @@
-
+
+
+ currency/currencyconverterapi/api_key
+ Magento\Config\Model\Config\Backend\Encrypted
+
+
diff --git a/app/code/Magento/Directory/etc/config.xml b/app/code/Magento/Directory/etc/config.xml
index 276d7088cc2ea..c18c4f29d5822 100644
--- a/app/code/Magento/Directory/etc/config.xml
+++ b/app/code/Magento/Directory/etc/config.xml
@@ -24,6 +24,7 @@
100
+
0