Jump to content

PrestaShop exchange rates not updating after moving webhosting


Recommended Posts

My shop was configured and running fine for a few months until I moved my web hosting provider 10 days ago. I have three currencies: USD, CHF and EUR. I had a CronJob that ran on the "old" host every 12 hours and I could see the exchange rates change every 12 hours.

 

Since moving 10 days ago to a "new" host and setting up an identical CronJob, the CronJob runs normally with the same confirmation email, but my exchange rates have not changed in 10 days. In fact, they seem to be "stuck" at their current level, even if I manually click on Update Currency Rates. By this, I mean, that if I manually change the rates to another value, then either 1.) run the CronJob or 2.) manually Update Currency Rates, the rates are visibly returned to the values they were at before.

 

I see only two possibilities for this outcome:

 

1.) PrestaShop is not updating the currency exchange rates data and has not done so since I moved (this would be a big coincidence), or

 

2.) The secure key that I had in my shop on the "old" host is no longer the same at my "new" host (although this is the secure key that still shows in my back office today).

 

Under LOCALIZATION ¦ CURRENCIES, the following link is still displayed today as it was before the move: http://www.hopelingerie.ch/adminxxxxyyyy/cron_currency_rates.php?secure_key=8919146b3ed6e9785a12f4d7fbe5399f

 

 

My base currency is the CHF. The exchange rates that are displayed (stuck?) are 0.915332 for EUR and 1.006682 for USD.

 

Does anyone have an idea what is wrong here?

 

Thanks and regards,

Rick

Edited by ricklarsen_ch (see edit history)
Link to comment
Share on other sites

You are just modifying the data feed location in the file from prestashop (not updated feed) to European Central Bank Feed (couple of lines of code) no need for new module or spending any $$$.

Works better than before as it retrieves a daily updated data feed.

Mine stopped working (prestashop feed) end of August.

 

If you need the code I cut and paste to the currency.php I can add here

Let me know.

Edited by markaussie (see edit history)
Link to comment
Share on other sites

I would like to supplement my original posting with a closely related questions:

 

QUESTIONS:

 

1. How is the unique "Secure Key" used in the currency rate CronJob generated?

2. Is this key somehow specific to installation-specific information, or a combination of various pieces of information, at the time PrestaShop was installed (for example, the IP address, the website name, server-specific IP or MAC addresses, etc.)? 

 

In explicit terms, I would like to know if the key that was generated at the time of installation on a specific server at one hosting service, at one fixed IP address, would be transportable to a different fixed IP address, on a different server, at a different host?

 

My specific secure_key is ​<removed>

 

Is there any relation between this secure_key and the token that appears in the address bar of my browser when I go to this page in Back Office, because the two are not the same? ...AdminCurrencies&token=<removed>

 

Thanks in advance,

Rick

Link to comment
Share on other sites

I removed the secure keys from your post.

 

The cron job secure key is the md5 hash of your _COOKIE_KEY_ in config/settings.inc.php followed by your shop name:

md5(_COOKIE_KEY_.Configuration::get('PS_SHOP_NAME'))

It is different to the token in the address bar, which is based on the tab class name and employee ID:

        return Tools::getAdminToken($tab.(int)Tab::getIdFromClassName($tab).(int)$context->employee->id);
Link to comment
Share on other sites

Thank you very much for this information, but I am not sure how I can apply it to solve my problem.

 

QUESTIONS:

 

1. Is it possible that the old key does not work on the new site at the new host and that this is the source of my problem?

2. Do I need to generate a new secure key for the new site at the new host? If yes, how can I generate this key?

 

Regards,

Rick

Link to comment
Share on other sites

ricklarsen_ch

 

Data feed is from https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml

 

Suggest creating an override as it will stay when you update minor versions of prestashop.

Copy and paste classes/Currency.php to override/classes/Currency.php and clear cache.

 

This is the complete code mod I used (easy just complete cut old out of Currency.php and paste all of this below).

(again well done and thanks to [email protected] and mattf10

Clear cache when finished and update currency rates via back office.

Make sure your cron is correct as displayed of currency page.

 
<?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.or...ses/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.or...ses/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('https://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

Dear nethercott solutions,

 

 

 

Are you sure the problem isn't just that PrestaShop hasn't been updating the rates since you've changed host?

 

No, I am not sure. I did not read any chatter from other users of this feature in the internet or on this forum about PrestaShop stopping to update the file that (presumably) many users are using, but I have nonetheless no ruled out that my move and their stopping updating are a coincidence.

 

I have also -- and partially for this reason -- been trying to eliminate any other remaining possibility. All the while I have been doing so, I am slowly arriving at the conclusion that this in one of, if not the only, logical explanation.

Link to comment
Share on other sites

Dear markaussie,

 

First, thank you for sharing this with me! I will investigate implementing it as early as today. I just need to find someone to help me because I am a simple businessman, not a technical person.

 

Second, ...

 

 

Suggest creating an override as it will stay when you update minor versions of prestashop.

Copy and paste classes/Currency.php to override/classes/Currency.php and clear cache.

 

Would you mind telling me, for the reason already invoked in the first point above, where I can read/learn about how to create "...an override..."?

 

Thanks and best regards,

Rick Larsen

Link to comment
Share on other sites

Files in the override folder don't get replaced/updated when you run prestashop 1 click upgrade.

If you don't create the modified files in the override folder no big deal it just means you will have to modify the original files you have changed every time you upgrade prestashop with your relevant fixes.

You may have many fixes/mods, I keep a list of all changes so when I upgrade prestashop or theme its easy to reference and modify files if needed.

 

To test it just backup your classes/Currency.php file 

Modify it clear cache and test.

You can restore original Currency.php if needed and re-sync old currency values.

 

The more you use prestashop the more technical and flexible you will become :D to fix little annoyances like currency feed not updating...........

Just remember to backup as you go and implement/test an easy way to restore if needed.

Link to comment
Share on other sites

Hello,

 

When I created a new Currency.php file in the /override/classes/ directory (renaming the old one), my site would no longer load.

 

I thought I followed the directions very carefully, but it was not clear to me if I had to place the new file in BOTH the /override/classes/ and the /classes/ directories. Could you please clarify?

 

Thanks in advance,

Rick

Link to comment
Share on other sites

As of yesterday, October 25th, 2016, currency rates are updating again with CronJobs. I did not check the rates last Thursday or Friday, so it is possible the rates were updating as early as that.

 

The only logical explanation is that someone at PrestaShop did something, because I did nothing except try to solve the problem.

 

Regards,

Link to comment
Share on other sites

The other logical explanation is you successfully applied the fix I mentioned and it's working from the recently run cron job on the 25Oct2016.

Well done.

 

To confirm just search your Currency.php files for this below (normal location or override location where to may have changed it ;) )

Tools::simplexml_load_file 

and it should show next to it the euro data feed as mentioned below.

('https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml')
Link to comment
Share on other sites

I checked the Currency.php file currently in my /classes/ directory and it does not have the ecb XML data feed mentioned above. 

 

I also checked the small 22-line Currency.php file in my /override/classes/ directory and it does not have this feed.

 

When I tried to use the code you sent me, by copying it into a Currency.php script in the /override/classes/ directory on October 24th, my website would not load. Users received an error message saying that the website was not available. As soon as I renamed the new script to new_Currency.php and put the short 22-line script back that had been there, the site was available again.

 

Since asking for some further precision the same day (above), I have not tried again. I also have 999 other things that I have to do.

 

Although the currency rates are again updating (at the moment), they seem to be in error. For example, my base currency is the Swiss franc. This morning the exchange rate with euros is exactly 1, something that is practically impossible. It is even more unlikely considering that the night before this same exchange rate was 0.921574. Even manually updating exchange rate this morning had no effect on the 1-1 exchange rate.

 

Regards,

Link to comment
Share on other sites

Hello,

 

I have no idea what the 22-line Currency.php is or where it came from, but the contents follow. I did not make any changes to the original file, nor did I authorize anyone to do so on my behalf. I have changed its name for the moment. Thank you for the suggestion about my admin.

 

---Currency.php contents---

<?php
include_once(_PS_MODULE_DIR_.'hardevelmulticurrency/hardevelmulticurrency.php');
class Currency extends CurrencyCore{
    /*
    * module: hardevelmulticurrency
    * date: 2016-07-27 15:25:59
    * version: 1.0.10
    */
    public function update($autodate = true, $nullValues = false)
    {
    
        $result = parent::update($autodate,$nullValues);
        if($result){
            
            include_once(_PS_MODULE_DIR_.'hardevelmulticurrency/hardevelmulticurrency.php');
            
            $hardevelmulticurrency = new hardevelmulticurrency();
            $hardevelmulticurrency->updatePrices(array(),$this->id);
        }
        return $result;
    }
}
Link to comment
Share on other sites

That's seems like a module enabled have a look in modules and disable it or configure it maybe = hardevelmulticurrency (test for dramas)

Suggest put shop in maintenance when playing.

Backup suspected module Currency.php if you havn't already then create the Currency.php I mentioned before in the override/classes

Clear cache and try manual sync of currencies.

Feels like your getting closer (999 things to do only 998 soon).

 

Can still see your external link in the first post

Edited by markaussie (see edit history)
Link to comment
Share on other sites

I have a multi-currency module that manages my back office purchase (cost) prices in US$. This is the module it is referring to.

 

Understanding now what it is, I have changed its name back to the original name in this directory.

 

Considering that the rates have (at least started) updating, I would like to see if they will keep updating and doing so correctly before trying to figure out how to make the code you suggested work in a file in the same directory with the same name. (I'm not sure how to combine the two scripts in the same file.)

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...