businessdad icon

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 |

7.57 KB

|

None

|

0 👍

/

0 👎

<?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