Aelia Currency Switcher - Add ECB provider
businessdad |
PRO |
01/13/23 07:53:36 AM UTC (Edited) |
0 ⭐ |
1286 👁️ |
Never ⏰ |
[ecb, currency-switcher, exchange-rates]
<?php
/**
* Aelia Currency Switcher - Add ECB Rates Provider from the EU VAT Assistant
* to the list of the exchange rates providers used by the Currency Switcher.
*
* IMPORTANT
* This code should only be used when the EU VAT Assistant is NOT INSTALLED.
*
* GPL DISCLAIMER
* THE USE OF THIS CODE IS AS YOUR OWN RISK.
* This code is provided free of charge and comes without any warranty, implied or explicit, to the extent permitted
* by applicable law. Except when otherwise stated in writing the copyright holders and/or other parties provide the
* program "as is" without warranty of any kind, either expressed or implied, including, but not limited to, the implied
* warranties of merchantability and fitness for a particular purpose. The entire risk as to the quality and performance
* of the program is with you. Should the program prove defective, you assume the cost of all necessary servicing, repair
* or correction.
*
* Need a consultation, or assistance to customise this code? Find us on Codeable: https://aelia.co/hire_us
*/
if(!class_exists('Aelia_CS_Exchange_Rates_ECB_Model') && class_exists('\Aelia\WC\ExchangeRatesModel')) {
/**
* Retrieves the exchange rates from the European Central Bank.
*
* @link https://www.ecb.europa.eu/stats/exchange/eurofxref/html/index.en.html
*/
class Aelia_CS_Exchange_Rates_ECB_Model extends \Aelia\WC\ExchangeRatesModel {
// @var string The URL template to use to query ECB
private $ecb_api_rates_url = 'https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml';
/**
* Tranforms the exchange rates received from ECB into an array of
* currency code => exchange rate pairs.
*
* @param string ecb_rates The XML received from ECB.
* @retur array
*/
protected function decode_rates($ecb_rates) {
$exchange_rates = [];
foreach($ecb_rates->Cube->Cube->Cube as $rate) {
$exchange_rates[(string)$rate['currency']] = (float)$rate['rate'];
}
// ECB feed is based against EUR, but it doesn't contain such currency. We
// can safely add it manually, with an exchange rate of 1
$exchange_rates['EUR'] = 1;
return $exchange_rates;
}
/**
* Fetches all exchange rates from ECB API.
*
* @return object|bool An object containing the response from Open Exchange, or
* False in case of failure.
*/
private function fetch_all_rates() {
try {
$response = \Httpful\Request::get($this->ecb_api_rates_url)
->expectsXml()
->send();
if($response->hasErrors()) {
// OpenExchangeRates sends error details in response body
if($response->hasBody()) {
$response_data = $response->body;
$this->add_error(self::ERR_ERROR_RETURNED,
sprintf(__('Error returned by ECB. Error code: %s. Error message: %s - %s.', 'woocommerce-aelia-currencyswitcher'),
$response_data->status,
$response_data->message,
$response_data->description));
}
return false;
}
return $response->body;
}
catch(Exception $e) {
$this->add_error(self::ERR_EXCEPTION_OCCURRED,
sprintf(__('Exception occurred while retrieving the exchange rates from ECB. Error message: %s.', 'woocommerce-aelia-currencyswitcher'),
$e->getMessage()));
return null;
}
}
/**
* Returns current exchange rates for the specified currency.
*
* @param string base_currency The base currency.
* @return array An array of Currency => Exchange Rate pairs.
*/
private function current_rates($base_currency) {
if(empty($this->_current_rates) ||
$this->_base_currency != $base_currency) {
$cache_key = md5(get_class($this)) . $base_currency;
// Try to get the cached rates for the specified base currency, if any
$this->_current_rates = $this->get_cached_exchange_rates($cache_key);
if(!empty($this->_current_rates)) {
return $this->_current_rates;
}
// Fetch exchange rates
$ecb_exchange_rates = $this->fetch_all_rates();
if($ecb_exchange_rates === false) {
return null;
}
// ECB rates are returned as JSON representation of an array of objects.
// We need to transform it into an array of currency => rate pairs
$exchange_rates = $this->decode_rates($ecb_exchange_rates);
if(!is_array($exchange_rates)) {
$this->add_error(self::ERR_UNEXPECTED_ERROR_FETCHING_EXCHANGE_RATES,
__('An unexpected error occurred while fetching exchange rates ' .
'from ECB. The most common cause of this issue is the ' .
'absence of PHP CURL extension. Please make sure that ' .
'PHP CURL is installed and configured in your system.',
'woocommerce-aelia-currencyswitcher'));
return array();
}
// Since we didn't get the exchange rates related to the base currency,
// but in the default base currency used by OpenExchange, we need to
// recalculate them against the base currency we would like to use
$this->_current_rates = $this->rebase_rates($exchange_rates, $base_currency);
$this->_base_currency = $base_currency;
// Cache the exchange rates
$this->cache_exchange_rates($cache_key, $this->_current_rates);
}
return $this->_current_rates;
}
/**
* Recaculates the exchange rates using another base currency. This method
* is invoked because the rates fetched from ECB are relative to BitCoin,
* but another currency is most likely is used by WooCommerce.
*
* @param array exchange_rates The exchange rates retrieved from ECB.
* @param string base_currency The base currency against which the rates should be recalculated.
* @return array An array of currency => exchange rate pairs.
*/
private function rebase_rates(array $exchange_rates, $base_currency) {
$recalc_rate = $exchange_rates[$base_currency] ?? null;
if(empty($recalc_rate)) {
$this->add_error(self::ERR_BASE_CURRENCY_NOT_FOUND,
sprintf(__('Could not rebase rates against base currency "%s". Currency not found in data returned by ECB.',
'woocommerce-aelia-currencyswitcher'),
$base_currency));
return null;
}
$result = array();
foreach($exchange_rates as $currency => $rate) {
$result[$currency] = $rate / $recalc_rate;
}
return $result;
}
/**
* Returns the exchange rate of a currency in respect to a base currency.
*
* @param string base_currency The code of the base currency.
* @param string currency The code of the currency for which to find the exchange rate.
* @return float
*/
protected function get_rate($base_currency, $currency) {
$current_rates = $this->current_rates($base_currency);
return get_value($currency, $current_rates);
}
/**
* Class constructor.
*
* @param array An array of Settings that can be used to override the ones
* currently saved in the configuration.
* @return Exchange_Rates_ECB_Model.
*/
public function __construct($settings = null) {
parent::__construct($settings);
}
}
/**
* Add the ECB model to the list of exchange rates providers available to the Currency Switcher.
*
* @param array
* @return array
*/
add_filter('wc_aelia_cs_exchange_rates_models', function($exchange_rates_models): array {
// Pass the ECB Model to the Currency Switcher
$exchange_rates_models['ecb'] = (object)array(
'class_name' => 'Aelia_CS_Exchange_Rates_ECB_Model',
'label' => 'ECB - Custom',
);
return $exchange_rates_models;
});
}
Comments