* @copyright Since 2007 PrestaShop SA and Contributors * @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) */ use PrestaShop\PrestaShop\Core\Localization\CLDR\LocaleRepository; class CurrencyCore extends ObjectModel { public $id; /** * Currency's name for the current language. * * @var string|string[] */ public $name; /** * Localized names of the currency * * @var string[] */ protected $localizedNames; /** * Alphabetic ISO 4217 code of this currency. * * @var string */ public $iso_code; /** * Numeric ISO 4217 code of this currency * * @var string */ public $iso_code_num; /** * Numeric ISO 4217 code of this currency. * * @var string|null */ public $numeric_iso_code; /** * Exchange rate from default currency. * * @var float */ public $conversion_rate; /** * Is this currency deleted ? * If currency is deleted, it stays in database. This is just a state (soft delete). * * @var bool */ public $deleted = false; /** * Is this currency unofficial ? * * @var int|bool unofficial */ public $unofficial; /** * Is this currency modified ? * * @var int|bool modified */ public $modified; /** * Is this currency active ? * * @var int|bool active */ public $active; /** * Currency's symbol * * @deprecated Use $symbol * * @var string */ public $sign; /** * Currency's symbol for the current language. * * @var string|string[] */ public $symbol; /** * Localized Currency's symbol. * * @var string[] */ private $localizedSymbols; /** * CLDR price formatting pattern * e.g.: In french (fr-FR), price formatting pattern is : #,##0.00 ยค. * * @var string */ public $format; /** * @var int */ public $blank; /** * Use decimals when displaying a price in this currency * * @deprecated since 1.7.0 * * @var int */ public $decimals; /** * Number of decimal digits to use when displaying a price in this currency. * * @var int */ public $precision; /** * CLDR price pattern * * @var string|string[] */ public $pattern; /** * CLDR price patterns, the array is indexed by language id * * @var string[] */ private $localizedPatterns; /** * @see ObjectModel::$definition */ public static $definition = [ 'table' => 'currency', 'primary' => 'id_currency', 'multilang' => true, 'fields' => [ 'iso_code' => ['type' => self::TYPE_STRING, 'validate' => 'isLanguageIsoCode', 'required' => true, 'size' => 3], 'numeric_iso_code' => ['type' => self::TYPE_STRING, 'allow_null' => true, 'validate' => 'isNumericIsoCode', 'size' => 3], 'precision' => ['type' => self::TYPE_INT, 'validate' => 'isInt'], 'conversion_rate' => ['type' => self::TYPE_FLOAT, 'validate' => 'isUnsignedFloat', 'required' => true, 'shop' => true], 'deleted' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'], 'active' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'], 'unofficial' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'], 'modified' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'], /* Lang fields */ 'name' => ['type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'size' => 255], 'symbol' => ['type' => self::TYPE_STRING, 'lang' => true, 'size' => 255], 'pattern' => ['type' => self::TYPE_STRING, 'lang' => true, 'size' => 255], ], ]; /** @var array Currency cache */ protected static $currencies = []; protected static $countActiveCurrencies = []; protected $webserviceParameters = [ 'objectsNodeName' => 'currencies', 'fields' => [ 'names' => [ 'getter' => 'getLocalizedNames', 'i18n' => true, ], 'name' => [ 'getter' => 'getName', 'modifier' => [ 'http_method' => WebserviceRequest::HTTP_POST | WebserviceRequest::HTTP_PUT | WebserviceRequest::HTTP_PATCH, 'modifier' => 'setNameForWebservice', ], ], 'symbol' => [ 'getter' => 'getLocalizedSymbols', ], 'iso_code' => [ 'modifier' => [ 'http_method' => WebserviceRequest::HTTP_POST | WebserviceRequest::HTTP_PUT | WebserviceRequest::HTTP_PATCH, 'modifier' => 'setIsoCodeForWebService', ], ], ], ]; /** * 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; /** * CurrencyCore constructor. * * @param int|null $id * @param int|false|null $idLang if null or false, default language will be used * @param int|null $idShop */ public function __construct($id = null, $idLang = null, $idShop = null) { parent::__construct($id, $idLang, $idShop); if ($this->iso_code) { // As the CLDR used to return a string even if in multi shop / lang, // We force only one string to be returned if (empty($idLang)) { $idLang = Context::getContext()->language->id; } /* * Both fields used to be string, but they were turned into translatable * fields so now they are arrays (indexed by language id). But to avoid BC breaks * the field is turned into a string in the constructor (using either the specified * language or the default one). * Since we want to keep the original array we store it in another field before setting * the field as a string. */ if (is_array($this->symbol)) { $this->localizedSymbols = $this->symbol; $this->sign = $this->symbol = $this->symbol[$idLang]; } else { $this->localizedSymbols = [$idLang => $this->symbol]; $this->sign = $this->symbol; } if (is_array($this->name)) { $this->localizedNames = $this->name; $this->name = Tools::ucfirst($this->name[$idLang]); } else { $this->localizedNames = [$idLang => $this->name]; $this->name = Tools::ucfirst($this->name); } if (is_array($this->pattern)) { $this->localizedPatterns = $this->pattern; } else { $this->localizedPatterns = [$idLang => $this->pattern]; } $this->iso_code_num = $this->numeric_iso_code; $this->blank = 1; $this->decimals = 1; } if (!$this->conversion_rate) { $this->conversion_rate = 1; } } /** * @param string|null $ws_params_attribute_name * * @return array */ public function getWebserviceParameters($ws_params_attribute_name = null) { $parameters = parent::getWebserviceParameters($ws_params_attribute_name); // name is an i18n field but is casted to single string in the constructor // so we need to force the webservice to consider this field as non-i18n. $parameters['fields']['name']['i18n'] = false; $parameters['fields']['name']['required'] = true; return $parameters; } /** * If the field 'names' (localized names) is sent, * it should be use instead of the field 'name' (non-localized). * LocalizedNames is also updated to reflect the new information. */ public function setNameForWebservice() { if (!empty($this->names)) { $this->name = $this->names; if (is_array($this->names)) { $this->localizedNames = $this->names; } else { foreach ($this->localizedNames as $lang => $name) { $this->localizedNames[$lang] = $this->names; } } } else { foreach ($this->localizedNames as $lang => $localizedName) { $this->localizedNames[$lang] = $this->name; } } } /** * In 1.7.6, new fields have been introduced. To keep it backward compatible, * we need to populate those fields with default values and they are all available * using the ISO code through CLDR data. */ public function setIsoCodeForWebService() { $container = Context::getContext()->container; /** @var LocaleRepository $localeCldr */ $localeCldr = $container->get('prestashop.core.localization.cldr.locale_repository'); /** @var Configuration $configuration */ $configuration = $container->get('prestashop.adapter.legacy.configuration'); $languages = Language::getIDs(); $defaultLanguage = new Language((int) $configuration->get('PS_LANG_DEFAULT')); $locale = $localeCldr->getLocale($defaultLanguage->getLocale()); $currency = $locale->getCurrency($this->iso_code); if (!empty($currency)) { if (empty($this->numeric_iso_code)) { $this->numeric_iso_code = $currency->getNumericIsoCode(); $this->iso_code_num = $this->numeric_iso_code; } if (empty($this->precision)) { $this->precision = (int) $currency->getDecimalDigits(); } } if (empty($this->symbol)) { $name = $this->name; $this->refreshLocalizedCurrencyData($languages, $localeCldr); $this->name = $name; } if (is_array($this->symbol)) { $this->localizedSymbols = $this->symbol; } else { foreach ($this->localizedSymbols as $lang => $symbol) { $this->localizedSymbols[$lang] = $this->symbol; } } } /** * reset static cache (eg unit testing purpose). */ public static function resetStaticCache() { parent::resetStaticCache(); static::$currencies = []; static::$countActiveCurrencies = []; Cache::clean('Currency::*'); } /** * 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. * * @param bool $autoDate Automatically set `date_upd` and `date_add` columns * @param bool $nullValues Whether we want to use NULL values instead of empty quotes values * * @return bool Indicates whether the Currency has been successfully added */ public function add($autoDate = true, $nullValues = false) { if ((float) $this->conversion_rate <= 0) { return false; } return Currency::exists($this->iso_code) ? false : parent::add($autoDate, $nullValues); } /** * Updates the current object in the database. * * @param bool $nullValues Whether we want to use NULL values instead of empty quotes values * * @return bool Indicates whether the CartRule has been successfully updated * * @throws PrestaShopDatabaseException * @throws PrestaShopException */ public function update($nullValues = false) { if ((float) $this->conversion_rate <= 0) { return false; } return parent::update($nullValues); } /** * Check if a Currency already exists. * * @param int|string $isoCode int for iso code number string for iso code * @param int $idShop Shop ID * * @return bool Indicates whether the Currency already exists */ public static function exists($isoCode, $idShop = 0) { $idCurrencyExists = Currency::getIdByIsoCode($isoCode, (int) $idShop); return (bool) $idCurrencyExists; } /** * Delete given Currencies. * * @param array $selection Currencies * * @return bool Indicates whether the selected Currencies have been succesfully deleted */ public function deleteSelection($selection) { if (!is_array($selection)) { return false; } $res = []; foreach ($selection as $id) { $obj = new Currency((int) $id); $res[$id] = $obj->delete(); } foreach ($res as $value) { if (!$value) { return false; } } return true; } /** * Deletes current object from database. * * @return bool True if delete was successful * * @throws PrestaShopException */ public function delete() { if ($this->id == Currency::getDefaultCurrencyId()) { $result = Db::getInstance()->getRow('SELECT `id_currency` FROM ' . _DB_PREFIX_ . 'currency WHERE `id_currency` != ' . (int) $this->id . ' AND `deleted` = 0'); if (empty($result['id_currency'])) { return false; } Configuration::updateValue('PS_CURRENCY_DEFAULT', $result['id_currency']); } // Remove currency restrictions $res = Db::getInstance()->delete('module_currency', 'id_currency = ' . (int) $this->id); return $res && $this->softDelete(); } /** * Return formatted sign. * * @param string $side left or right * * @return string formated sign */ public function getSign($side = null) { return $this->sign; } /** * Is this currency installed for a given shop ? * (current shop by default). * * @param int|null $currencyId * The currency to look for ( * @param int|null $shopId * The given shop's id * * @return bool * True if this currency is installed for the given shop */ public function isInstalled($currencyId = null, $shopId = null) { $currencyId = $currencyId ?: $this->id; $shopId = $shopId ?: Context::getContext()->shop->id; $sql = (new DbQuery()) ->select('1') ->from('currency', 'c') ->innerJoin('currency_shop', 'cs', 'c.`id_currency` = cs.`id_currency`') ->where('c.`id_currency` = ' . (int) $currencyId) ->where('cs.`id_shop` = ' . (int) $shopId) ->where('c.`deleted` = 0') ->where('c.`active` = 1'); return (bool) Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($sql); } /** * Returns the name of the currency (using the translated name base on the id_lang * provided on creation). This method is useful when $this->name contains an array * but you still need to get its name as a string. * * @return string */ public function getName() { if (is_string($this->name)) { return $this->name; } $id_lang = $this->id_lang; if ($id_lang === null) { $id_lang = Configuration::get('PS_LANG_DEFAULT'); } return Tools::ucfirst($this->name[$id_lang]); } /** * @return string */ public function getSymbol() { if (is_string($this->symbol)) { return $this->symbol; } $id_lang = $this->id_lang; if (null === $id_lang) { $id_lang = Configuration::get('PS_LANG_DEFAULT'); } if (!isset($this->symbol[$id_lang])) { return ''; } return Tools::ucfirst($this->symbol[$id_lang]); } /** * Names indexed by language id * * @return string[] */ public function getLocalizedNames() { return $this->localizedNames; } /** * This setter updates the name field because it is used when you want to update * the database (legacy core feature). But to be consistent the names field also * needs to be updated. * * @param string[] $localizedNames list of currency names, the array needs to be indexed by language id * * @return $this */ public function setLocalizedNames(array $localizedNames) { $this->localizedNames = $this->name = $localizedNames; return $this; } /** * Symbols indexed by language id * * @return string[] */ public function getLocalizedSymbols() { return $this->localizedSymbols; } /** * This setter updates the symbol field because it is used when you want to update * the database (legacy core feature). But to be consistent the symbols field also * needs to be updated. * * @param string[] $localizedSymbols list of currency symbols, the array needs to be indexed by language id * * @return CurrencyCore */ public function setLocalizedSymbols(array $localizedSymbols) { $this->localizedSymbols = $this->symbol = $localizedSymbols; return $this; } /** * @return string */ public function getPattern($idLang) { return $this->localizedPatterns[$idLang] ?? ''; } /** * Patterns indexed by language id * * @return string[] */ public function getLocalizedPatterns() { return $this->localizedPatterns; } /** * This setter updates the pattern field because it is used when you want to update * the database (legacy core feature). But to be consistent the patterns field also * needs to be updated. * * @param string[] $localizedPatterns list of currency patterns, the array needs to be indexed by language id * * @return CurrencyCore */ public function setLocalizedPatterns(array $localizedPatterns) { $this->localizedPatterns = $this->pattern = $localizedPatterns; return $this; } /** * Return available currencies. * * @param bool $object * @param bool $active * @param bool $groupBy * * @return array Currencies */ public static function getCurrencies($object = false, $active = true, $groupBy = false) { return static::addCldrDatasToCurrency( static::findAll($active, $groupBy), $object ); } /** * Retrieve all currencies data from the database. * * @param bool $active If true only active are returned * @param bool $groupBy Group by id_currency * @param bool $currentShopOnly If true returns only currencies associated to current shop * * @return array Currency data from database * * @throws PrestaShopDatabaseException */ public static function findAll($active = true, $groupBy = false, $currentShopOnly = true) { $currencies = Db::getInstance()->executeS(' SELECT * FROM `' . _DB_PREFIX_ . 'currency` c ' . ($currentShopOnly ? Shop::addSqlAssociation('currency', 'c') : '') . ' WHERE c.`deleted` = 0' . ($active ? ' AND c.`active` = 1' : '') . ($groupBy ? ' GROUP BY c.`id_currency`' : '') . ' ORDER BY `iso_code` ASC'); return $currencies; } /** * Retrieve all currencies data from the database. * * @return array Currency data from database * * @throws PrestaShopDatabaseException */ public static function findAllInstalled() { $currencies = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS( 'SELECT * FROM `' . _DB_PREFIX_ . 'currency` c ORDER BY `iso_code` ASC' ); return $currencies; } /** * @param int|null $shopId * * @return array */ public function getInstalledCurrencies($shopId = null) { $shopId = $shopId ?: Context::getContext()->shop->id; $sql = (new DbQuery()) ->select('c.*, cl.*') ->from('currency', 'c') ->innerJoin('currency_lang', 'cl', 'c.`id_currency` = cl.`id_currency`') ->innerJoin('currency_shop', 'cs', 'c.`id_currency` = cs.`id_currency`') ->where('cs.`id_shop` = ' . (int) $shopId) ->where('c.`deleted` = 0') ->where('c.`active` = 1'); return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql); } /** * Get Currencies by Shop ID. * * @param int $idShop Shop ID * * @return array|Currency */ public static function getCurrenciesByIdShop($idShop = 0) { $currencies = Db::getInstance()->executeS(' SELECT * FROM `' . _DB_PREFIX_ . 'currency` c LEFT JOIN `' . _DB_PREFIX_ . 'currency_shop` cs ON (cs.`id_currency` = c.`id_currency`) ' . ($idShop ? ' WHERE cs.`id_shop` = ' . (int) $idShop : '') . ' ORDER BY `iso_code` ASC'); return self::addCldrDatasToCurrency($currencies); } /** * Add Cldr datas to result query or signe object/array. * * @param array|object $currencies * @param bool $isObject * * @return mixed object|array */ protected static function addCldrDatasToCurrency($currencies, $isObject = false) { if (is_array($currencies)) { foreach ($currencies as $k => $c) { $currencies[$k] = Currency::getCurrencyInstance($c['id_currency']); if (!$isObject) { $currencies[$k] = (array) $currencies[$k]; $currencies[$k]['id_currency'] = $currencies[$k]['id']; } } } else { $currencies = Currency::getCurrencyInstance($currencies['id_currency']); if (!$isObject) { $currencies = (array) $currencies; $currencies['id_currency'] = $currencies['id']; } } return $currencies; } /** * @param int $idModule * @param int|null $idShop * * @return array */ public static function getPaymentCurrenciesSpecial($idModule, $idShop = null) { if (null === $idShop) { $idShop = Context::getContext()->shop->id; } $sql = 'SELECT * FROM ' . _DB_PREFIX_ . 'module_currency WHERE id_module = ' . (int) $idModule . ' AND id_shop =' . (int) $idShop; return Db::getInstance()->getRow($sql); } /** * Get payment Currencies. * * @param int $idModule Module ID * @param int|null $idShop Shop ID * * @return array|false|mysqli_result|PDOStatement|resource|null */ public static function getPaymentCurrencies($idModule, $idShop = null) { if (null === $idShop) { $idShop = 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) $idModule . ' AND c.`active` = 1 AND mc.id_shop = ' . (int) $idShop . ' ORDER BY c.`iso_code` ASC'; return Db::getInstance()->executeS($sql); } /** * Check payment Currencies. * * @param int $idModule Module ID * @param int|null $idShop Shop ID * * @return array|PDOStatement|resource|null */ public static function checkPaymentCurrencies($idModule, $idShop = null) { if (empty($idModule)) { return []; } if (null === $idShop) { $idShop = Context::getContext()->shop->id; } $sql = new DbQuery(); $sql->select('mc.*'); $sql->from('module_currency', 'mc'); $sql->where('mc.`id_module` = ' . (int) $idModule); $sql->where('mc.`id_shop` = ' . (int) $idShop); $currencies = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql); return $currencies ? $currencies : []; } /** * Get Currency. * * @param int $idCurrency Currency ID * * @return array|bool|object|null */ public static function getCurrency($idCurrency) { $sql = new DbQuery(); $sql->select('c.*'); $sql->from('currency', 'c'); $sql->where('`deleted` = 0'); $sql->where('`id_currency` = ' . (int) $idCurrency); return Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow($sql); } /** * Get Currency ID by ISO code. * * @param string $isoCode ISO code * @param int $idShop Shop ID * @param bool $forceRefreshCache [default=false] Set to TRUE to forcefully refresh any currently cached results * @param bool $includeDeleted [default=false] Set to TRUE to get result even for soft deleted currency * * @return int Currency ID */ public static function getIdByIsoCode($isoCode, $idShop = 0, $forceRefreshCache = false, $includeDeleted = false) { $cacheId = 'Currency::getIdByIsoCode_' . pSQL($isoCode) . '-' . (int) $idShop . ($includeDeleted ? '-deleted' : ''); if ($forceRefreshCache || !Cache::isStored($cacheId)) { $query = Currency::getIdByQuery($idShop, $includeDeleted); $query->where('iso_code = \'' . pSQL($isoCode) . '\''); $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($query->build()); if (empty($result)) { return 0; } Cache::store($cacheId, $result); return (int) $result; } return (int) Cache::retrieve($cacheId); } /** * Get Currency ISO Code by ID * * @param int $id * @param bool $forceRefreshCache * * @return string */ public static function getIsoCodeById(int $id, bool $forceRefreshCache = false) { $cacheId = 'Currency::getIsoCodeById' . pSQL((string) $id); if ($forceRefreshCache || !Cache::isStored($cacheId)) { $resultIsoCode = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('SELECT `iso_code` FROM ' . _DB_PREFIX_ . 'currency WHERE `id_currency` = ' . (int) $id); Cache::store($cacheId, $resultIsoCode); return $resultIsoCode; } return Cache::retrieve($cacheId); } /** * Get Currency ID by numeric ISO code. * * @param int $numericIsoCode ISO code * @param int $idShop Shop ID * * @return int Currency ID */ public static function getIdByNumericIsoCode($numericIsoCode, $idShop = 0) { $cacheId = 'Currency::getIdByNumericIsoCode_' . pSQL((string) $numericIsoCode) . '-' . (int) $idShop; if (!Cache::isStored($cacheId)) { $query = Currency::getIdByQuery($idShop); $query->where('numeric_iso_code = \'' . pSQL((string) $numericIsoCode) . '\''); $result = (int) Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($query->build()); Cache::store($cacheId, $result); return $result; } return Cache::retrieve($cacheId); } /** * Get Currency ID query. * * @param int $idShop Shop ID * @param bool $includeDeleted [default=false] Set to TRUE to get result even for soft deleted currency * * @return DbQuery */ public static function getIdByQuery($idShop = 0, $includeDeleted = false) { $query = new DbQuery(); $query->select('c.id_currency'); $query->from('currency', 'c'); if (!$includeDeleted) { $query->where('deleted = 0'); } if (Shop::isFeatureActive() && $idShop > 0) { $query->leftJoin('currency_shop', 'cs', 'cs.id_currency = c.id_currency'); $query->where('id_shop = ' . (int) $idShop); } 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 $exchangeRate = 1; $tmp = $this->conversion_rate; if ($defaultCurrency->iso_code != $isoCodeSource) { foreach ($data->currency as $currency) { if ($currency['iso_code'] == $defaultCurrency->iso_code) { $exchangeRate = 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->currency as $obj) { if ($this->iso_code == (string) ($obj['iso_code'])) { $rate = (float) $obj['rate']; break; } } } if (isset($rate)) { $this->conversion_rate = round($rate / $exchangeRate, 6); } } if ($tmp != $this->conversion_rate) { $this->update(); } } /** * Get default Currency. * * @return bool|Currency */ public static function getDefaultCurrency() { $idCurrency = Currency::getDefaultCurrencyId(); if ($idCurrency == 0) { return false; } return new Currency($idCurrency); } /** * Get default currency Id. * * @return int */ public static function getDefaultCurrencyId(): int { return (int) Configuration::get('PS_CURRENCY_DEFAULT'); } /** * Refresh Currencies. * * @return string Error message */ public static function refreshCurrencies() { // Parse if (!$feed = Tools::simplexml_load_file(_PS_CURRENCY_FEED_URL_)) { return Context::getContext()->getTranslator()->trans('Cannot parse feed.', [], 'Admin.Notifications.Error'); } // Default feed currency (EUR) $isoCodeSource = (string) ($feed->source['iso_code']); if (!$defaultCurrency = Currency::getDefaultCurrency()) { return Context::getContext()->getTranslator()->trans('No default currency', [], 'Admin.Notifications.Error'); } $currencies = Currency::getCurrencies(true, false, true); foreach ($currencies as $currency) { /** @var Currency $currency */ if ($currency->id != $defaultCurrency->id) { $currency->refreshCurrency($feed->list, $isoCodeSource, $defaultCurrency); } } return ''; } /** * Get Currency instance. * * @param int $id Currency ID * * @return Currency */ public static function getCurrencyInstance($id) { if (!isset(self::$currencies[$id])) { self::$currencies[(int) ($id)] = new Currency($id); } return self::$currencies[(int) ($id)]; } /** * Get conversion rate. * * @return int|string * * @deprecated 1.7.2.0, use Currency::getConversionRate() instead */ public function getConversationRate() { Tools::displayAsDeprecated('Use Currency::getConversionRate() instead'); return $this->getConversionRate(); } /** * Get conversion rate. * * @return int|string */ public function getConversionRate() { return ($this->id != static::getDefaultCurrencyId()) ? $this->conversion_rate : 1; } /** * Count active Currencies. * * @param int|null $idShop Shop ID * * @return mixed Amount of active Currencies * `false` if none found */ public static function countActiveCurrencies($idShop = null) { if ($idShop === null) { $idShop = (int) Context::getContext()->shop->id; } if (!isset(self::$countActiveCurrencies[$idShop])) { self::$countActiveCurrencies[$idShop] = 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) $idShop . ') WHERE c.`active` = 1 AND c.`deleted` = 0 '); } return self::$countActiveCurrencies[$idShop]; } /** * Is multi Currency activated? * * @param int|null $idShop Shop ID * * @return bool Indicates whether multi Currency is actived */ public static function isMultiCurrencyActivated($idShop = null) { return Currency::countActiveCurrencies($idShop) > 1; } /** * This method aims to update localized data in currency from CLDR reference. * * @param array $languages * @param LocaleRepository $localeRepoCLDR * * @throws PrestaShopDatabaseException * @throws PrestaShopException * @throws \PrestaShop\PrestaShop\Core\Localization\Exception\LocalizationException */ public function refreshLocalizedCurrencyData(array $languages, LocaleRepository $localeRepoCLDR) { $this->modified = false; $originalNames = $this->localizedNames; $originalSymbols = $this->localizedSymbols; $symbolsByLang = $namesByLang = []; foreach ($languages as $languageData) { $language = new Language($languageData['id_lang']); // CLDR locale give us the CLDR reference specification $cldrLocale = $localeRepoCLDR->getLocale($language->getLocale()); // CLDR currency gives data from CLDR reference, for the given language $cldrCurrency = $cldrLocale->getCurrency($this->iso_code); if (empty($cldrCurrency)) { // The currency may not be declared in the locale, eg with unofficial iso code // Check if data is present in case it's not available for all languages $namesByLang[$language->id] = !empty($originalNames[$language->id]) ? $originalNames[$language->id] : $this->iso_code; $symbolsByLang[$language->id] = !empty($originalSymbols[$language->id]) ? $originalSymbols[$language->id] : $this->iso_code; $this->modified = true; continue; } // Symbol is localized, we check if it was manually modified $symbol = (string) $cldrCurrency->getSymbol() ?: $this->iso_code; if (!empty($symbol) && !empty($originalSymbols[$language->id]) && $symbol !== $originalSymbols[$language->id]) { $symbol = $originalSymbols[$language->id]; $this->modified = true; } $symbolsByLang[$language->id] = $symbol; // Name is localized, we check if it was manually modified $name = $cldrCurrency->getDisplayName(); if (!empty($originalNames[$language->id]) && $name !== $originalNames[$language->id]) { $name = $originalNames[$language->id]; $this->modified = true; } $namesByLang[$language->id] = $name; } $this->setLocalizedNames($namesByLang); $this->setLocalizedSymbols($symbolsByLang); } }