Advertisement
businessdad

Aelia Currency Switcher - Add ECB provider

Nov 24th, 2022 (edited)
500
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <?php
  2. /**
  3.  * Aelia Currency Switcher - Add ECB Rates Provider from the EU VAT Assistant
  4.  * to the list of the exchange rates providers used by the Currency Switcher.
  5.  *
  6.  * IMPORTANT
  7.  * This code should only be used when the EU VAT Assistant is NOT INSTALLED.
  8.  *
  9.  * GPL DISCLAIMER
  10.  * THE USE OF THIS CODE IS AS YOUR OWN RISK.
  11.  * This code is provided free of charge and comes without any warranty, implied or explicit, to the extent permitted
  12.  * by applicable law. Except when otherwise stated in writing the copyright holders and/or other parties provide the
  13.  * program "as is" without warranty of any kind, either expressed or implied, including, but not limited to, the implied
  14.  * warranties of merchantability and fitness for a particular purpose. The entire risk as to the quality and performance
  15.  * of the program is with you. Should the program prove defective, you assume the cost of all necessary servicing, repair
  16.  * or correction.
  17.  *
  18.  * Need a consultation, or assistance to customise this code? Find us on Codeable: https://aelia.co/hire_us
  19.  */
  20. if(!class_exists('Aelia_CS_Exchange_Rates_ECB_Model') && class_exists('\Aelia\WC\ExchangeRatesModel')) {
  21.     /**
  22.      * Retrieves the exchange rates from the European Central Bank.
  23.      *
  24.      * @link https://www.ecb.europa.eu/stats/exchange/eurofxref/html/index.en.html
  25.      */
  26.     class Aelia_CS_Exchange_Rates_ECB_Model extends \Aelia\WC\ExchangeRatesModel {
  27.         // @var string The URL template to use to query ECB
  28.         private $ecb_api_rates_url = 'https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml';
  29.  
  30.         /**
  31.          * Tranforms the exchange rates received from ECB into an array of
  32.          * currency code => exchange rate pairs.
  33.          *
  34.          * @param string ecb_rates The XML received from ECB.
  35.          * @retur array
  36.          */
  37.         protected function decode_rates($ecb_rates) {
  38.             $exchange_rates = [];
  39.  
  40.             foreach($ecb_rates->Cube->Cube->Cube as $rate) {
  41.                 $exchange_rates[(string)$rate['currency']] = (float)$rate['rate'];
  42.             }
  43.             // ECB feed is based against EUR, but it doesn't contain such currency. We
  44.             // can safely add it manually, with an exchange rate of 1
  45.             $exchange_rates['EUR'] = 1;
  46.             return $exchange_rates;
  47.         }
  48.  
  49.         /**
  50.          * Fetches all exchange rates from ECB API.
  51.          *
  52.          * @return object|bool An object containing the response from Open Exchange, or
  53.          * False in case of failure.
  54.          */
  55.         private function fetch_all_rates() {
  56.             try {
  57.                 $response = \Httpful\Request::get($this->ecb_api_rates_url)
  58.                     ->expectsXml()
  59.                     ->send();
  60.  
  61.                 if($response->hasErrors()) {
  62.                     // OpenExchangeRates sends error details in response body
  63.                     if($response->hasBody()) {
  64.                         $response_data = $response->body;
  65.  
  66.                         $this->add_error(self::ERR_ERROR_RETURNED,
  67.                                                         sprintf(__('Error returned by ECB. Error code: %s. Error message: %s - %s.', 'woocommerce-aelia-currencyswitcher'),
  68.                                                                         $response_data->status,
  69.                                                                         $response_data->message,
  70.                                                                         $response_data->description));
  71.                     }
  72.                     return false;
  73.                 }
  74.                 return $response->body;
  75.             }
  76.             catch(Exception $e) {
  77.                 $this->add_error(self::ERR_EXCEPTION_OCCURRED,
  78.                                                 sprintf(__('Exception occurred while retrieving the exchange rates from ECB. Error message: %s.', 'woocommerce-aelia-currencyswitcher'),
  79.                                                                 $e->getMessage()));
  80.                 return null;
  81.             }
  82.         }
  83.  
  84.         /**
  85.          * Returns current exchange rates for the specified currency.
  86.          *
  87.          * @param string base_currency The base currency.
  88.          * @return array An array of Currency => Exchange Rate pairs.
  89.          */
  90.         private function current_rates($base_currency) {
  91.             if(empty($this->_current_rates) ||
  92.                 $this->_base_currency != $base_currency) {
  93.  
  94.                 $cache_key = md5(get_class($this)) . $base_currency;
  95.                 // Try to get the cached rates for the specified base currency, if any
  96.                 $this->_current_rates = $this->get_cached_exchange_rates($cache_key);
  97.                 if(!empty($this->_current_rates)) {
  98.                     return $this->_current_rates;
  99.                 }
  100.  
  101.                 // Fetch exchange rates
  102.                 $ecb_exchange_rates = $this->fetch_all_rates();
  103.                 if($ecb_exchange_rates === false) {
  104.                     return null;
  105.                 }
  106.  
  107.                 // ECB rates are returned as JSON representation of an array of objects.
  108.                 // We need to transform it into an array of currency => rate pairs
  109.                 $exchange_rates = $this->decode_rates($ecb_exchange_rates);
  110.                 if(!is_array($exchange_rates)) {
  111.                     $this->add_error(self::ERR_UNEXPECTED_ERROR_FETCHING_EXCHANGE_RATES,
  112.                                                     __('An unexpected error occurred while fetching exchange rates ' .
  113.                                                             'from ECB. The most common cause of this issue is the ' .
  114.                                                             'absence of PHP CURL extension. Please make sure that ' .
  115.                                                             'PHP CURL is installed and configured in your system.',
  116.                                                             'woocommerce-aelia-currencyswitcher'));
  117.                     return array();
  118.                 }
  119.  
  120.                 // Since we didn't get the exchange rates related to the base currency,
  121.                 // but in the default base currency used by OpenExchange, we need to
  122.                 // recalculate them against the base currency we would like to use
  123.                 $this->_current_rates = $this->rebase_rates($exchange_rates, $base_currency);
  124.                 $this->_base_currency = $base_currency;
  125.  
  126.                 // Cache the exchange rates
  127.                 $this->cache_exchange_rates($cache_key, $this->_current_rates);
  128.             }
  129.             return $this->_current_rates;
  130.         }
  131.  
  132.         /**
  133.          * Recaculates the exchange rates using another base currency. This method
  134.          * is invoked because the rates fetched from ECB are relative to BitCoin,
  135.          * but another currency is most likely is used by WooCommerce.
  136.          *
  137.          * @param array exchange_rates The exchange rates retrieved from ECB.
  138.          * @param string base_currency The base currency against which the rates should be recalculated.
  139.          * @return array An array of currency => exchange rate pairs.
  140.          */
  141.         private function rebase_rates(array $exchange_rates, $base_currency) {
  142.             $recalc_rate = $exchange_rates[$base_currency] ?? null;
  143.  
  144.             if(empty($recalc_rate)) {
  145.                 $this->add_error(self::ERR_BASE_CURRENCY_NOT_FOUND,
  146.                                                 sprintf(__('Could not rebase rates against base currency "%s". Currency not found in data returned by ECB.',
  147.                                                                         'woocommerce-aelia-currencyswitcher'),
  148.                                                                 $base_currency));
  149.                 return null;
  150.             }
  151.  
  152.             $result = array();
  153.             foreach($exchange_rates as $currency => $rate) {
  154.                 $result[$currency] = $rate / $recalc_rate;
  155.             }
  156.  
  157.             return $result;
  158.         }
  159.  
  160.         /**
  161.          * Returns the exchange rate of a currency in respect to a base currency.
  162.          *
  163.          * @param string base_currency The code of the base currency.
  164.          * @param string currency The code of the currency for which to find the exchange rate.
  165.          * @return float
  166.          */
  167.         protected function get_rate($base_currency, $currency) {
  168.             $current_rates = $this->current_rates($base_currency);
  169.             return get_value($currency, $current_rates);
  170.         }
  171.  
  172.         /**
  173.          * Class constructor.
  174.          *
  175.          * @param array An array of Settings that can be used to override the ones
  176.          * currently saved in the configuration.
  177.          * @return Exchange_Rates_ECB_Model.
  178.          */
  179.         public function __construct($settings = null) {
  180.             parent::__construct($settings);
  181.         }
  182.     }
  183.  
  184.  
  185.     /**
  186.      * Add the ECB model to the list of exchange rates providers available to the Currency Switcher.
  187.      *
  188.      * @param array
  189.      * @return array
  190.      */
  191.     add_filter('wc_aelia_cs_exchange_rates_models', function($exchange_rates_models): array {
  192.         // Pass the ECB Model to the Currency Switcher
  193.         $exchange_rates_models['ecb'] = (object)array(
  194.         'class_name' => 'Aelia_CS_Exchange_Rates_ECB_Model',
  195.         'label' => 'ECB - Custom',
  196.         );
  197.    
  198.         return $exchange_rates_models;
  199.     });
  200. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement