Skip to content

Commit 591f16e

Browse files
committed
MAGETWO-47492: [GitHub] Currency rates import service is loading all rate for activated currencies. #2757
- added a new currency converter service fixer.io - fixed errors procession in webservices - added unit test
1 parent 0d2000c commit 591f16e

File tree

5 files changed

+261
-15
lines changed

5 files changed

+261
-15
lines changed

app/code/Magento/Directory/Model/Currency/Import/AbstractImport.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public function fetchRates()
9494
$data = [];
9595
$currencies = $this->_getCurrencyCodes();
9696
$defaultCurrencies = $this->_getDefaultCurrencyCodes();
97-
@set_time_limit(0);
97+
set_time_limit(0);
9898
foreach ($defaultCurrencies as $currencyFrom) {
9999
if (!isset($data[$currencyFrom])) {
100100
$data[$currencyFrom] = [];
@@ -111,6 +111,7 @@ public function fetchRates()
111111
}
112112
ksort($data[$currencyFrom]);
113113
}
114+
ini_restore('max_execution_time');
114115

115116
return $data;
116117
}
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
<?php
2+
/**
3+
* Copyright © 2015 Magento. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\Directory\Model\Currency\Import;
8+
9+
/**
10+
* Currency rate import model (From http://fixer.io/)
11+
*/
12+
class FixerIo extends \Magento\Directory\Model\Currency\Import\AbstractImport
13+
{
14+
/**
15+
* @var string
16+
*/
17+
const CURRENCY_CONVERTER_URL = 'http://api.fixer.io/latest?base={{CURRENCY_FROM}}&symbols={{CURRENCY_TO}}';
18+
19+
/**
20+
* Http Client Factory
21+
*
22+
* @var \Magento\Framework\HTTP\ZendClientFactory
23+
*/
24+
protected $httpClientFactory;
25+
26+
/**
27+
* Core scope config
28+
*
29+
* @var \Magento\Framework\App\Config\ScopeConfigInterface
30+
*/
31+
private $scopeConfig;
32+
33+
/**
34+
* Initialize dependencies
35+
*
36+
* @param \Magento\Directory\Model\CurrencyFactory $currencyFactory
37+
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
38+
* @param \Magento\Framework\HTTP\ZendClientFactory $httpClientFactory
39+
*/
40+
public function __construct(
41+
\Magento\Directory\Model\CurrencyFactory $currencyFactory,
42+
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
43+
\Magento\Framework\HTTP\ZendClientFactory $httpClientFactory
44+
) {
45+
parent::__construct($currencyFactory);
46+
$this->scopeConfig = $scopeConfig;
47+
$this->httpClientFactory = $httpClientFactory;
48+
}
49+
50+
/**
51+
* {@inheritdoc}
52+
*/
53+
public function fetchRates()
54+
{
55+
$data = [];
56+
$currencies = $this->_getCurrencyCodes();
57+
$defaultCurrencies = $this->_getDefaultCurrencyCodes();
58+
59+
foreach ($defaultCurrencies as $currencyFrom) {
60+
if (!isset($data[$currencyFrom])) {
61+
$data[$currencyFrom] = [];
62+
}
63+
$data = $this->convertBatch($data, $currencyFrom, $currencies);
64+
ksort($data[$currencyFrom]);
65+
}
66+
return $data;
67+
}
68+
69+
70+
/**
71+
* Return currencies convert rates in batch mode
72+
*
73+
* @param array $data
74+
* @param string $currencyFrom
75+
* @param array $currenciesTo
76+
* @return array
77+
*/
78+
private function convertBatch($data, $currencyFrom, $currenciesTo)
79+
{
80+
$currenciesStr = implode(',', $currenciesTo);
81+
$url = str_replace('{{CURRENCY_FROM}}', $currencyFrom, self::CURRENCY_CONVERTER_URL);
82+
$url = str_replace('{{CURRENCY_TO}}', $currenciesStr, $url);
83+
84+
set_time_limit(0);
85+
$response = $this->getServiceResponse($url);
86+
ini_restore('max_execution_time');
87+
88+
foreach ($currenciesTo as $currencyTo) {
89+
if ($currencyFrom == $currencyTo) {
90+
$data[$currencyFrom][$currencyTo] = $this->_numberFormat(1);
91+
} else {
92+
if (empty($response['rates'][$currencyTo])) {
93+
$this->_messages[] = __('We can\'t retrieve a rate from %1 for %2.', $url, $currencyTo);
94+
$data[$currencyFrom][$currencyTo] = null;
95+
} else {
96+
$data[$currencyFrom][$currencyTo] = $this->_numberFormat(
97+
(double)$response['rates'][$currencyTo]
98+
);
99+
}
100+
}
101+
}
102+
return $data;
103+
}
104+
105+
/**
106+
* Get Fixer.io service response
107+
*
108+
* @param string $url
109+
* @param int $retry
110+
* @return array
111+
*/
112+
private function getServiceResponse($url, $retry = 0)
113+
{
114+
/** @var \Magento\Framework\HTTP\ZendClient $httpClient */
115+
$httpClient = $this->httpClientFactory->create();
116+
$response = [];
117+
118+
try {
119+
$jsonResponse = $httpClient->setUri(
120+
$url
121+
)->setConfig(
122+
[
123+
'timeout' => $this->scopeConfig->getValue(
124+
'currency/fixerio/timeout',
125+
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
126+
),
127+
]
128+
)->request(
129+
'GET'
130+
)->getBody();
131+
132+
$response = json_decode($jsonResponse, true);
133+
} catch (\Exception $e) {
134+
if ($retry == 0) {
135+
$response = $this->getServiceResponse($url, 1);
136+
}
137+
}
138+
return $response;
139+
}
140+
141+
/**
142+
* {@inheritdoc}
143+
*/
144+
protected function _convert($currencyFrom, $currencyTo)
145+
{
146+
}
147+
}

app/code/Magento/Directory/Model/Currency/Import/Webservicex.php

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,45 +4,46 @@
44
* See COPYING.txt for license details.
55
*/
66

7-
// @codingStandardsIgnoreFile
7+
namespace Magento\Directory\Model\Currency\Import;
88

99
/**
1010
* Currency rate import model (From www.webservicex.net)
1111
*/
12-
namespace Magento\Directory\Model\Currency\Import;
13-
1412
class Webservicex extends \Magento\Directory\Model\Currency\Import\AbstractImport
1513
{
1614
/**
1715
* @var string
1816
*/
19-
const CURRENCY_CONVERTER_URL = 'http://www.webservicex.net/CurrencyConvertor.asmx/ConversionRate?FromCurrency={{CURRENCY_FROM}}&ToCurrency={{CURRENCY_TO}}';
17+
const CURRENCY_CONVERTER_URL = 'http://www.webservicex.net/CurrencyConvertor.asmx/ConversionRate?' .
18+
'FromCurrency={{CURRENCY_FROM}}&ToCurrency={{CURRENCY_TO}}';
2019

2120
/**
22-
* HTTP client
21+
* Http Client Factory
2322
*
24-
* @var \Magento\Framework\HTTP\ZendClient
23+
* @var \Magento\Framework\HTTP\ZendClientFactory
2524
*/
26-
protected $_httpClient;
25+
protected $httpClientFactory;
2726

2827
/**
29-
* Core store config
28+
* Core scope config
3029
*
3130
* @var \Magento\Framework\App\Config\ScopeConfigInterface
3231
*/
33-
protected $_scopeConfig;
32+
private $scopeConfig;
3433

3534
/**
3635
* @param \Magento\Directory\Model\CurrencyFactory $currencyFactory
3736
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
37+
* @param \Magento\Framework\HTTP\ZendClientFactory $httpClientFactory
3838
*/
3939
public function __construct(
4040
\Magento\Directory\Model\CurrencyFactory $currencyFactory,
41-
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
41+
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
42+
\Magento\Framework\HTTP\ZendClientFactory $httpClientFactory
4243
) {
4344
parent::__construct($currencyFactory);
44-
$this->_scopeConfig = $scopeConfig;
45-
$this->_httpClient = new \Magento\Framework\HTTP\ZendClient();
45+
$this->scopeConfig = $scopeConfig;
46+
$this->httpClientFactory = $httpClientFactory;
4647
}
4748

4849
/**
@@ -55,13 +56,15 @@ protected function _convert($currencyFrom, $currencyTo, $retry = 0)
5556
{
5657
$url = str_replace('{{CURRENCY_FROM}}', $currencyFrom, self::CURRENCY_CONVERTER_URL);
5758
$url = str_replace('{{CURRENCY_TO}}', $currencyTo, $url);
59+
/** @var \Magento\Framework\HTTP\ZendClient $httpClient */
60+
$httpClient = $this->httpClientFactory->create();
5861

5962
try {
60-
$response = $this->_httpClient->setUri(
63+
$response = $httpClient->setUri(
6164
$url
6265
)->setConfig(
6366
[
64-
'timeout' => $this->_scopeConfig->getValue(
67+
'timeout' => $this->scopeConfig->getValue(
6568
'currency/webservicex/timeout',
6669
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
6770
),
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
/**
3+
* Copyright © 2015 Magento. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\Directory\Test\Unit\Model\Currency\Import;
8+
9+
class FixerIoTest extends \PHPUnit_Framework_TestCase
10+
{
11+
/**
12+
* @var \Magento\Directory\Model\Currency\Import\FixerIo
13+
*/
14+
private $model;
15+
16+
/**
17+
* @var \Magento\Directory\Model\CurrencyFactory|\PHPUnit_Framework_MockObject_MockObject
18+
*/
19+
private $currencyFactoryMock;
20+
21+
/**
22+
* @var \Magento\Framework\HTTP\ZendClientFactory|\PHPUnit_Framework_MockObject_MockObject
23+
*/
24+
private $httpClientFactoryMock;
25+
26+
protected function setUp()
27+
{
28+
$objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
29+
30+
$this->currencyFactoryMock = $this->getMockBuilder('Magento\Directory\Model\CurrencyFactory')
31+
->disableOriginalConstructor()
32+
->setMethods([])
33+
->getMock();
34+
$this->httpClientFactoryMock = $this->getMockBuilder('Magento\Framework\HTTP\ZendClientFactory')
35+
->disableOriginalConstructor()
36+
->setMethods(['create'])
37+
->getMock();
38+
$scopeMock = $this->getMockBuilder('Magento\Framework\App\Config\ScopeConfigInterface')
39+
->disableOriginalConstructor()
40+
->setMethods([])
41+
->getMock();
42+
43+
$this->model = $objectManagerHelper->getObject(
44+
'Magento\Directory\Model\Currency\Import\FixerIo',
45+
[
46+
'currencyFactory' => $this->currencyFactoryMock,
47+
'scopeConfig' => $scopeMock,
48+
'httpClientFactory' => $this->httpClientFactoryMock
49+
]
50+
);
51+
}
52+
53+
public function testFetchRates()
54+
{
55+
$currencyFromList = ['USD'];
56+
$currencyToList = ['EUR', 'UAH'];
57+
$responseBody = '{"base":"USD","date":"2015-10-07","rates":{"EUR":0.9022}}';
58+
$expectedCurrencyRateList = ['USD' => ['EUR' => 0.9022, 'UAH' => null]];
59+
$message = "We can't retrieve a rate from http://api.fixer.io/latest?base=USD&symbols=EUR,UAH for UAH.";
60+
61+
/** @var \Magento\Directory\Model\Currency|\PHPUnit_Framework_MockObject_MockObject $currencyMock */
62+
$currencyMock = $this->getMockBuilder('Magento\Directory\Model\Currency')
63+
->disableOriginalConstructor()
64+
->setMethods([])
65+
->getMock();
66+
/** @var \Magento\Framework\HTTP\ZendClient|\PHPUnit_Framework_MockObject_MockObject $currencyMock */
67+
$httpClientMock = $this->getMockBuilder('Magento\Framework\HTTP\ZendClient')
68+
->disableOriginalConstructor()
69+
->setMethods([])
70+
->getMock();
71+
/** @var \Zend_Http_Response|\PHPUnit_Framework_MockObject_MockObject $currencyMock */
72+
$httpResponseMock = $this->getMockBuilder('Zend_Http_Response')
73+
->disableOriginalConstructor()
74+
->setMethods([])
75+
->getMock();
76+
$this->currencyFactoryMock->expects($this->any())->method('create')->willReturn($currencyMock);
77+
$currencyMock->expects($this->once())->method('getConfigBaseCurrencies')->willReturn($currencyFromList);
78+
$currencyMock->expects($this->once())->method('getConfigAllowCurrencies')->willReturn($currencyToList);
79+
$this->httpClientFactoryMock->expects($this->any())->method('create')->willReturn($httpClientMock);
80+
$httpClientMock->expects($this->atLeastOnce())->method('setUri')->willReturnSelf();
81+
$httpClientMock->expects($this->atLeastOnce())->method('setConfig')->willReturnSelf();
82+
$httpClientMock->expects($this->atLeastOnce())->method('request')->willReturn($httpResponseMock);
83+
$httpResponseMock->expects($this->any())->method('getBody')->willReturn($responseBody);
84+
85+
$this->assertEquals($expectedCurrencyRateList, $this->model->fetchRates());
86+
$messages = $this->model->getMessages();
87+
$this->assertNotEmpty($messages);
88+
$this->assertTrue(is_array($messages));
89+
$this->assertEquals($message, (string)$messages[0]);
90+
}
91+
}

app/code/Magento/Directory/etc/di.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
<item name="label" xsi:type="string">Webservicex</item>
1414
<item name="class" xsi:type="string">Magento\Directory\Model\Currency\Import\Webservicex</item>
1515
</item>
16+
<item name="fixerio" xsi:type="array">
17+
<item name="label" xsi:type="string">Fixer.io</item>
18+
<item name="class" xsi:type="string">Magento\Directory\Model\Currency\Import\FixerIo</item>
19+
</item>
1620
</argument>
1721
</arguments>
1822
</type>

0 commit comments

Comments
 (0)