Jump to content

[SOLVED]Currency update


Recommended Posts

OK, i'v asked my server company to look at this.

I found this code in \Classes\currency.php

static public function refreshCurrencies()
{
if (!$feed = @simplexml_load_file('http://www.prestashop.com/xml/currencies.xml'))
return Tools::displayError('Cannot parse feed!');
if (!$defaultCurrency = intval(Configuration::get('PS_CURRENCY_DEFAULT')))
return Tools::displayError('No default currency!');
$isoCodeSource = strval($feed->source['iso_code']);
$currencies = self::getCurrencies(true);
$defaultCurrency = self::refreshCurrenciesGetDefault($feed->list, $isoCodeSource, $defaultCurrency);
foreach ($currencies as $currency)
if ($currency->iso_code != $defaultCurrency->iso_code)
$currency->refreshCurrency($feed->list, $isoCodeSource, $defaultCurrency);
}
}

?>

Does ths look right, can you compare whit your file? is this file supose to be 777?

Link to comment
Share on other sites

That's the same as my file. The problem is that your server is returning false when @simplexml_load_file('http://www.prestashop.com/xml/currencies.xml') in executed, whereas it is returning the feed on my server.

Link to comment
Share on other sites

I get a question from my server admin, (What is required for the service to work? In what way is the XML feeds retrieved through "PrestaShop"?

What do i answer. Can i show them the classes/currency.php file?

Link to comment
Share on other sites

The server admin replayed this:

Seems as if this is fopen, which is not permitted on our servers. Tip is that you us a curl script to first get home this locally and then see if it works to read it.

Link to comment
Share on other sites

It looks like you'll need to change to a server that uses fopen or rewrite PrestaShop's code to use cURL. I did a Google search and found this site which has cURL code. You could try using code similar to it. Unfortunately, I'm not familiar with cURL, so I can't help any more.

Link to comment
Share on other sites

Replace the refreshCurrencies() function on lines 217-229 of classes/Currency.php (in PrestaShop v1.3):

static public function refreshCurrencies()
{
   if (!$feed = @simplexml_load_file('http://www.prestashop.com/xml/currencies.xml'))
       return Tools::displayError('Cannot parse feed!');
   if (!$defaultCurrency = intval(Configuration::get('PS_CURRENCY_DEFAULT')))
       return Tools::displayError('No default currency!');
   $isoCodeSource = strval($feed->source['iso_code']);
   $currencies = self::getCurrencies(true);
   $defaultCurrency = self::refreshCurrenciesGetDefault($feed->list, $isoCodeSource, $defaultCurrency);
   foreach ($currencies as $currency)
       if ($currency->iso_code != $defaultCurrency->iso_code)
           $currency->refreshCurrency($feed->list, $isoCodeSource, $defaultCurrency);
}



with the following two functions:

static public function file_get_url_contents($url) {
   if (preg_match('/^([a-z]+):\/\/([a-z0-9-.]+)(\/.*$)/i', $url, $matches)) {
       $protocol = strtolower($matches[1]);
       $host = $matches[2];
       $path = $matches[3];
   } else {
       // Bad url-format
       return FALSE;
   }

   if ($protocol == "http") {
       $socket = fsockopen($host, 80);
   } else {
       // Bad protocol
       return FALSE;
   }

   if (!socket) {
       // Error creating socket
       return FALSE;
   }

   $request = "GET $path HTTP/1.0\r\nHost: $host\r\n\r\n";
   $len_written = fwrite($socket, $request);

   if ($len_written === FALSE || $len_written != strlen($request)) {
       // Error sending request
       return FALSE;
   }

   $response = "";
   while (!feof($socket) && ($buf = fread($socket, 4096)) !== FALSE) {
       $response .= $buf;
   }

   if ($buf === FALSE) {
       // Error reading response
       return FALSE;
   }

   $end_of_header = strpos($response, "\r\n\r\n");
   return substr($response, $end_of_header + 4);
}

static public function refreshCurrencies()
{
   $url = "http://www.prestashop.com/xml/currencies.xml";
   $res = self::file_get_url_contents($url);
   if ($res === FALSE)
       return Tools::displayError("Error fetching $url");
   else
   {
       if (!$feed = @simplexml_load_string($res))
           return Tools::displayError('Cannot parse feed!');
       if (!$defaultCurrency = intval(Configuration::get('PS_CURRENCY_DEFAULT')))
           return Tools::displayError('No default currency!');
       $isoCodeSource = strval($feed->source['iso_code']);
       $currencies = self::getCurrencies(true);
       $defaultCurrency = self::refreshCurrenciesGetDefault($feed->list, $isoCodeSource, $defaultCurrency);
       foreach ($currencies as $currency)
           if ($currency->iso_code != $defaultCurrency->iso_code)
               $currency->refreshCurrency($feed->list, $isoCodeSource, $defaultCurrency);
   }
}

Link to comment
Share on other sites

Don't work for me. I get an blank page. Can you post this code in a file, maybe i get error for that i clip and paste. And how a bout the file i got from ny server admin, do i yous dhat on to?

Link to comment
Share on other sites

  • 2 months later...

Forgive my ignorance but I'm not sure I understand, the currency xml feed seems to be working when it is set to Euro as the conversions to pound and dollar show fine and these depend on the xml feed being imported succesfully.

I can't see how this is solely a server issue if this is the case.

I thought it was because the application is not set up to parse the feed properly when the currency is changed hence whatever you have set to the base currency is treated as a Euro as well as a Euro being treated as a Euro?
In other words there is nothing in the application classes to reparse the xml in a different order to compensate for the change.

Thanks,

Pedro.

Link to comment
Share on other sites

  • 2 weeks later...

Hi,

can anybody tell me how often is prestashop's currencies.xml updated? And what's the feed for currencies rate? European Central Bank? I only need one conversion PLN <-> EUR and tha rate 3,95 is not accurate enough... i'd rather have x,xxxx format. Is that possible?

Link to comment
Share on other sites

  • 2 months later...
  • 1 month later...

Hi there,

Does anyone knows where is Prestashop getting the information to the http://www.prestashop.com/xml/currencies.xml
For example the rate from EUR to USD from prestashop.com is 1.29 and from oanda.com is 1.35 and in the European Central Bank it was 1.36. I thing this is a huge difference.

Why doesn't Prestashop use this link from the European Central Bank:
http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml

So the question remains: where does Prestashop are getting the information rates?

Thanks.

  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...
  • 1 year later...
  • 4 years later...

Hi there,

 

Does anyone knows where is Prestashop getting the information to the http://www.prestashop.com/xml/currencies.xml

For example the rate from EUR to USD from prestashop.com is 1.29 and from oanda.com is 1.35 and in the European Central Bank it was 1.36. I thing this is a huge difference.

 

Why doesn't Prestashop use this link from the European Central Bank:

http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml

 

So the question remains: where does Prestashop are getting the information rates?

 

Thanks.

I think others also have the problem right now. Once they get the currencies.xml file to intergrate into the shop and either the manual or automatic upgrade works ( you have to have a second cron job which also deletes the cache then) those notice with some bitterness that the contents of the xml file are at least several weeks old and ar not updated at all. No one ever was doubting the provided currency rates, a simple calcuator reveals them as rubbish!

I am not sure if Prestashop is aware of the potential consequences for a webshop, if they knowingly provide the wrong currency rates. Even if they say the rate is provided as is, this can be no disclaimer for providing a wrong rate and knowing this for sure. As the issue is already several weeks old, no action has been taken so far.

Is this something a developer did wrong or simply a hardware problem, currently your whole software is invalidated as USELESS dear Prestashop team.

It reminds me of famous Microsoft errors as the Excel calculation bug, and MS Project statistical printout error (WYSIWYMG). Guys that is just poor. No matter where the problem is, all Shops can close now for a while! Our French friends are on holidays, Bonne vacance!

Link to comment
Share on other sites

Right now I have solved it by a new currency.php in classes directory, for Prestashop 1.6.

It takes its rates from ECB bank. And it just works!

 

here is the code:

--------------------------------

<?php
/*
* 2007-2016 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to [email protected] so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
*  @author PrestaShop SA <[email protected]>
*  @copyright  2007-2016 PrestaShop SA
*  @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
*  International Registered Trademark & Property of PrestaShop SA
*/

class CurrencyCore extends ObjectModel
{
    public $id;

    /** @var string Name */
    public $name;

    /** @var string Iso code */
    public $iso_code;

    /** @var string Iso code numeric */
    public $iso_code_num;

    /** @var string Symbol for short display */
    public $sign;

    /** @var int bool used for displaying blank between sign and price */
    public $blank;

    /** @var string exchange rate from euros */
    public $conversion_rate;

    /** @var bool True if currency has been deleted (staying in database as deleted) */
    public $deleted = 0;

    /** @var int ID used for displaying prices */
    public $format;

    /** @var int bool Display decimals on prices */
    public $decimals;

    /** @var int bool active */
    public $active;

    /**
     * @see ObjectModel::$definition
     */
    public static $definition = array(
        'table' => 'currency',
        'primary' => 'id_currency',
        'multilang_shop' => true,
        'fields' => array(
            'name' =>            array('type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'required' => true, 'size' => 32),
            'iso_code' =>        array('type' => self::TYPE_STRING, 'validate' => 'isLanguageIsoCode', 'required' => true, 'size' => 3),
            'iso_code_num' =>    array('type' => self::TYPE_STRING, 'validate' => 'isNumericIsoCode', 'size' => 3),
            'blank' =>            array('type' => self::TYPE_INT, 'validate' => 'isInt'),
            'sign' =>            array('type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'required' => true, 'size' => 8),
            'format' =>        array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
            'decimals' =>        array('type' => self::TYPE_BOOL, 'validate' => 'isBool', 'required' => true),
            'conversion_rate' =>array('type' => self::TYPE_FLOAT, 'validate' => 'isUnsignedFloat', 'required' => true, 'shop' => true),
            'deleted' =>        array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
            'active' =>        array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
        ),
    );

    /** @var array Currency cache */
    protected static $currencies = array();
    protected static $countActiveCurrencies = array();

    protected $webserviceParameters = array(
        'objectsNodeName' => 'currencies',
    );

    /**
     * contains the sign to display before price, according to its format
     * @var string
     */
    public $prefix = null;
    /**
     * contains the sign to display after price, according to its format
     * @var string
     */
    public $suffix = null;

    public function __construct($id = null, $id_lang = null, $id_shop = null)
    {
        parent::__construct($id, $id_lang, $id_shop);
        // prefix and suffix are convenient shortcut for displaying
        // price sign before or after the price number
        $this->prefix =    $this->format % 2 != 0 ? $this->sign.' ' : '';
        $this->suffix =    $this->format % 2 == 0 ? ' '.$this->sign : '';
        if (!$this->conversion_rate) {
            $this->conversion_rate = 1;
        }
    }
    /**
     * Overriding check if currency rate is not empty and if currency with the same iso code already exists.
     * If it's true, currency is not added.
     *
     * @see ObjectModelCore::add()
     */
    public function add($autodate = true, $nullValues = false)
    {
        if ((float)$this->conversion_rate <= 0) {
            return false;
        }
        return Currency::exists($this->iso_code, $this->iso_code_num) ? false : parent::add($autodate, $nullValues);
    }

    public function update($autodate = true, $nullValues = false)
    {
        if ((float)$this->conversion_rate <= 0) {
            return false;
        }
        return parent::update($autodate, $nullValues);
    }

    /**
     * Check if a curency already exists.
     *
     * @param int|string $iso_code int for iso code number string for iso code
     * @return bool
     */
    public static function exists($iso_code, $iso_code_num, $id_shop = 0)
    {
        if (is_int($iso_code)) {
            $id_currency_exists = Currency::getIdByIsoCodeNum((int)$iso_code_num, (int)$id_shop);
        } else {
            $id_currency_exists = Currency::getIdByIsoCode($iso_code, (int)$id_shop);
        }

        if ($id_currency_exists) {
            return true;
        } else {
            return false;
        }
    }

    public function deleteSelection($selection)
    {
        if (!is_array($selection)) {
            return false;
        }

        $res = array();
        foreach ($selection as $id) {
            $obj = new Currency((int)$id);
            $res[$id] = $obj->delete();
        }

        foreach ($res as $value) {
            if (!$value) {
                return false;
            }
        }
        return true;
    }

    public function delete()
    {
        if ($this->id == Configuration::get('PS_CURRENCY_DEFAULT')) {
            $result = Db::getInstance()->getRow('SELECT `id_currency` FROM '._DB_PREFIX_.'currency WHERE `id_currency` != '.(int)($this->id).' AND `deleted` = 0');
            if (!$result['id_currency']) {
                return false;
            }
            Configuration::updateValue('PS_CURRENCY_DEFAULT', $result['id_currency']);
        }
        $this->deleted = 1;
        return $this->update();
    }

    /**
     * Return formated sign
     *
     * @param string $side left or right
     * @return string formated sign
     */
    public function getSign($side = null)
    {
        if (!$side) {
            return $this->sign;
        }
        $formated_strings = array(
            'left' => $this->sign.' ',
            'right' => ' '.$this->sign
        );

        $formats = array(
            1 => array('left' => &$formated_strings['left'], 'right' => ''),
            2 => array('left' => '', 'right' => &$formated_strings['right']),
            3 => array('left' => &$formated_strings['left'], 'right' => ''),
            4 => array('left' => '', 'right' => &$formated_strings['right']),
            5 => array('left' => '', 'right' => &$formated_strings['right'])
        );
        if (isset($formats[$this->format][$side])) {
            return ($formats[$this->format][$side]);
        }
        return $this->sign;
    }

    /**
     * Return available currencies
     *
     * @return array Currencies
     */
    public static function getCurrencies($object = false, $active = true, $group_by = false)
    {
        $tab = Db::getInstance()->executeS('
        SELECT *
        FROM `'._DB_PREFIX_.'currency` c
        '.Shop::addSqlAssociation('currency', 'c').
        ' WHERE `deleted` = 0'.
        ($active ? ' AND c.`active` = 1' : '').
        ($group_by ? ' GROUP BY c.`id_currency`' : '').
        ' ORDER BY `name` ASC');
        if ($object) {
            foreach ($tab as $key => $currency) {
                $tab[$key] = Currency::getCurrencyInstance($currency['id_currency']);
            }
        }
        return $tab;
    }

    public static function getCurrenciesByIdShop($id_shop = 0)
    {
        return Db::getInstance()->executeS('
        SELECT *
        FROM `'._DB_PREFIX_.'currency` c
        LEFT JOIN `'._DB_PREFIX_.'currency_shop` cs ON (cs.`id_currency` = c.`id_currency`)
        '.($id_shop ? ' WHERE cs.`id_shop` = '.(int)$id_shop : '').'
        ORDER BY `name` ASC');
    }


    public static function getPaymentCurrenciesSpecial($id_module, $id_shop = null)
    {
        if (is_null($id_shop)) {
            $id_shop = Context::getContext()->shop->id;
        }

        $sql = 'SELECT *
                FROM '._DB_PREFIX_.'module_currency
                WHERE id_module = '.(int)$id_module.'
                    AND id_shop ='.(int)$id_shop;
        return Db::getInstance()->getRow($sql);
    }

    public static function getPaymentCurrencies($id_module, $id_shop = null)
    {
        if (is_null($id_shop)) {
            $id_shop = Context::getContext()->shop->id;
        }

        $sql = 'SELECT c.*
                FROM `'._DB_PREFIX_.'module_currency` mc
                LEFT JOIN `'._DB_PREFIX_.'currency` c ON c.`id_currency` = mc.`id_currency`
                WHERE c.`deleted` = 0
                    AND mc.`id_module` = '.(int)$id_module.'
                    AND c.`active` = 1
                    AND mc.id_shop = '.(int)$id_shop.'
                ORDER BY c.`name` ASC';
        return Db::getInstance()->executeS($sql);
    }

    public static function checkPaymentCurrencies($id_module, $id_shop = null)
    {
        if (empty($id_module)) {
            return false;
        }

        if (is_null($id_shop)) {
            $id_shop = Context::getContext()->shop->id;
        }

        $sql = 'SELECT *
                FROM `'._DB_PREFIX_.'module_currency`
                WHERE `id_module` = '.(int)$id_module.'
                    AND `id_shop` = '.(int)$id_shop;
        return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql);
    }

    public static function getCurrency($id_currency)
    {
        return Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow('
        SELECT *
        FROM `'._DB_PREFIX_.'currency`
        WHERE `deleted` = 0
        AND `id_currency` = '.(int)($id_currency));
    }

    /**
     * @param $iso_code
     * @param int $id_shop
     * @return int
     */
    public static function getIdByIsoCode($iso_code, $id_shop = 0)
    {
        $cache_id = 'Currency::getIdByIsoCode_'.pSQL($iso_code).'-'.(int)$id_shop;
        if (!Cache::isStored($cache_id)) {
            $query = Currency::getIdByQuery($id_shop);
            $query->where('iso_code = \''.pSQL($iso_code).'\'');

            $result = (int)Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($query->build());
            Cache::store($cache_id, $result);
            return $result;
        }
        return Cache::retrieve($cache_id);
    }

    /**
     * @param $iso_code_num
     * @param int $id_shop
     * @return int
     */
    public static function getIdByIsoCodeNum($iso_code_num, $id_shop = 0)
    {
        $query = Currency::getIdByQuery($id_shop);
        $query->where('iso_code_num = \''.pSQL($iso_code_num).'\'');

        return (int)Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($query->build());
    }

    /**
     * @param int $id_shop
     * @return DbQuery
     */
    public static function getIdByQuery($id_shop = 0)
    {
        $query = new DbQuery();
        $query->select('c.id_currency');
        $query->from('currency', 'c');
        $query->where('deleted = 0');

        if (Shop::isFeatureActive() && $id_shop > 0) {
            $query->leftJoin('currency_shop', 'cs', 'cs.id_currency = c.id_currency');
            $query->where('id_shop = '.(int)$id_shop);
        }
        return $query;
    }

    /**
     * Refresh the currency exchange rate
     * The XML file define exchange rate for each from a default currency ($isoCodeSource).
     *
     * @param SimpleXMLElement $data XML content which contains all the exchange rates
     * @param string $isoCodeSource The default currency used in the XML file
     * @param Currency $defaultCurrency The default currency object
     */
    public function refreshCurrency($data, $isoCodeSource, $defaultCurrency)
    {
        // fetch the exchange rate of the default currency
        $exchange_rate = 1;
        $tmp = $this->conversion_rate;
        if ($defaultCurrency->iso_code != $isoCodeSource) {
            foreach ($data->Cube->Cube->Cube as $currency) {
                if ($currency['currency'] == $defaultCurrency->iso_code) {
                    $exchange_rate = round((float)$currency['rate'], 6);
                    break;
                }
            }
        }

        if ($defaultCurrency->iso_code == $this->iso_code) {
            $this->conversion_rate = 1;
        } else {
            if ($this->iso_code == $isoCodeSource) {
                $rate = 1;
            } else {
                foreach ($data->Cube->Cube->Cube as $obj) {
                    if ($this->iso_code == strval($obj['currency'])) {
                        $rate = (float)$obj['rate'];
                        break;
                    }
                }
            }

            if (isset($rate)) {
                $this->conversion_rate = round($rate / $exchange_rate, 6);
            }
        }

        if ($tmp != $this->conversion_rate) {
            $this->update();
        }
    }

    public static function getDefaultCurrency()
    {
        $id_currency = (int)Configuration::get('PS_CURRENCY_DEFAULT');
        if ($id_currency == 0) {
            return false;
        }

        return new Currency($id_currency);
    }

    public static function refreshCurrencies()
    {
        // Parse
        if (!$feed = Tools::simplexml_load_file('http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml')) {
            return Tools::displayError('Cannot parse feed.');
        }

 
        // Default feed currency (EUR)
        $isoCodeSource = 'EUR';

        if (!$default_currency = Currency::getDefaultCurrency()) {
            return Tools::displayError('No default currency');
        }

        $currencies = Currency::getCurrencies(true, false, true);
        foreach ($currencies as $currency) {
            /** @var Currency $currency */
            if ($currency->id != $default_currency->id) {
                $currency->refreshCurrency($feed, $isoCodeSource, $default_currency);
            }
        }
    }

    /**
     * Get current currency
     *
     * @deprecated as of 1.5 use $context->currency instead
     * @return Currency
     */
    public static function getCurrent()
    {
        Tools::displayAsDeprecated();
        return Context::getContext()->currency;
    }

    public static function getCurrencyInstance($id)
    {
        if (!isset(self::$currencies[$id])) {
            self::$currencies[(int)($id)] = new Currency($id);
        }
        return self::$currencies[(int)($id)];
    }

    public function getConversationRate()
    {
        return $this->id != (int)Configuration::get('PS_CURRENCY_DEFAULT') ? $this->conversion_rate : 1;
    }

    public static function countActiveCurrencies($id_shop = null)
    {
        if ($id_shop === null) {
            $id_shop = (int)Context::getContext()->shop->id;
        }

        if (!isset(self::$countActiveCurrencies[$id_shop])) {
            self::$countActiveCurrencies[$id_shop] = Db::getInstance()->getValue('
                SELECT COUNT(DISTINCT c.id_currency) FROM `'._DB_PREFIX_.'currency` c
                LEFT JOIN '._DB_PREFIX_.'currency_shop cs ON (cs.id_currency = c.id_currency AND cs.id_shop = '.(int)$id_shop.')
                WHERE c.`active` = 1
            ');
        }
        return self::$countActiveCurrencies[$id_shop];
    }

    public static function isMultiCurrencyActivated($id_shop = null)
    {
        return (Currency::countActiveCurrencies($id_shop) > 1);
    }
}
 

Link to comment
Share on other sites

×
×
  • Create New...