33 'FORMAT_STRING' =>
'#',
35 'THOUSANDS_SEP' =>
' ',
45 private static string $region;
67 return (!(defined(
'ADMIN_SECTION') &&
ADMIN_SECTION ===
true) && self::$useHideZero >= 0);
74 $getErrors = ($getErrors ===
true);
89 if (
$currency ===
false || $language ===
false)
92 $errorMessages =
array();
107 '~THOUSANDS_VARIANT',
112 $clearFields[] =
'CREATED_BY';
113 $clearFields[] =
'CURRENCY';
114 $clearFields[] =
'LID';
117 foreach ($clearFields as $fieldName)
119 if (isset(
$fields[$fieldName]))
122 unset($fieldName, $clearFields);
132 if (empty(
$fields[
'FORMAT_STRING']))
134 $errorMessages[] =
array(
135 'id' =>
'FORMAT_STRING',
'text' => Loc::getMessage(
'BT_CUR_LANG_ERR_FORMAT_STRING_IS_EMPTY',
array(
'#LANG#' => $language))
139 if (empty($errorMessages))
146 if (empty($errorMessages))
148 if (isset(
$fields[
'FORMAT_STRING']) && empty(
$fields[
'FORMAT_STRING']))
150 $errorMessages[] =
array(
151 'id' =>
'FORMAT_STRING',
'text' => Loc::getMessage(
'BT_CUR_LANG_ERR_FORMAT_STRING_IS_EMPTY',
array(
'#LANG#' => $language))
154 if (isset(
$fields[
'DECIMALS']))
158 $fields[
'DECIMALS'] = self::$arDefaultValues[
'DECIMALS'];
160 $validateCustomSeparator =
false;
161 if (isset(
$fields[
'THOUSANDS_VARIANT']))
163 if (empty(
$fields[
'THOUSANDS_VARIANT']) || !isset(self::$arSeparators[
$fields[
'THOUSANDS_VARIANT']]))
165 $fields[
'THOUSANDS_VARIANT'] =
false;
166 $validateCustomSeparator =
true;
170 $fields[
'THOUSANDS_SEP'] = self::$arSeparators[
$fields[
'THOUSANDS_VARIANT']];
175 if (isset(
$fields[
'THOUSANDS_SEP']))
176 $validateCustomSeparator =
true;
179 if ($validateCustomSeparator)
181 if (!isset(
$fields[
'THOUSANDS_SEP']) ||
$fields[
'THOUSANDS_SEP'] ==
'')
183 $errorMessages[] =
array(
184 'id' =>
'THOUSANDS_SEP',
185 'text' => Loc::getMessage(
186 'BT_CUR_LANG_ERR_THOUSANDS_SEP_IS_EMPTY',
187 array(
'#LANG#' => $language)
193 if (!preg_match(
'/^&(#[x]?[0-9a-zA-Z]+|[a-zA-Z]+);$/',
$fields[
'THOUSANDS_SEP']))
195 $errorMessages[] =
array(
196 'id' =>
'THOUSANDS_SEP',
197 'text' => Loc::getMessage(
198 'BT_CUR_LANG_ERR_THOUSANDS_SEP_IS_NOT_VALID',
199 array(
'#LANG#' => $language)
205 unset($validateCustomSeparator);
207 if (isset(
$fields[
'HIDE_ZERO']))
213 $intUserID = (int)
$USER->GetID();
214 $strDateFunction =
$DB->GetNowFunction();
215 $fields[
'~TIMESTAMP_X'] = $strDateFunction;
218 if (!isset(
$fields[
'MODIFIED_BY']))
219 $fields[
'MODIFIED_BY'] = $intUserID;
221 if (
$fields[
'MODIFIED_BY'] <= 0)
222 $fields[
'MODIFIED_BY'] = $intUserID;
226 $fields[
'~DATE_CREATE'] = $strDateFunction;
230 $fields[
'CREATED_BY'] = $intUserID;
232 if (
$fields[
'CREATED_BY'] <= 0)
233 $fields[
'CREATED_BY'] = $intUserID;
237 if (empty($errorMessages))
241 if (!empty(
$fields[
'THOUSANDS_VARIANT']) && isset(self::$arSeparators[
$fields[
'THOUSANDS_VARIANT']]))
243 if (
$fields[
'DEC_POINT'] == self::$arSeparators[
$fields[
'THOUSANDS_VARIANT']])
245 $errorMessages[] =
array(
247 'text' => Loc::getMessage(
248 'BT_CUR_LANG_ERR_DEC_POINT_EQUAL_THOUSANDS_SEP',
249 array(
'#LANG#' => $language)
259 || (isset(
$fields[
'THOUSANDS_VARIANT']) && isset(self::$arSeparators[
$fields[
'THOUSANDS_VARIANT']]))
264 if (!isset($copyFields[
'DEC_POINT']))
265 $needFields[] =
'DEC_POINT';
266 if (!isset($copyFields[
'THOUSANDS_VARIANT']))
267 $needFields[] =
'THOUSANDS_VARIANT';
269 if (!empty($needFields))
272 'select' => $needFields,
273 'filter' => [
'=CURRENCY' =>
$currency,
'=LID' => $language]
277 $copyFields = array_merge($copyFields, $row);
284 && (!empty($copyFields[
'THOUSANDS_VARIANT']) && isset(self::$arSeparators[$copyFields[
'THOUSANDS_VARIANT']]))
285 && ($copyFields[
'DEC_POINT'] == self::$arSeparators[$copyFields[
'THOUSANDS_VARIANT']])
288 $errorMessages[] =
array(
290 'text' => Loc::getMessage(
291 'BT_CUR_LANG_ERR_DEC_POINT_EQUAL_THOUSANDS_SEP',
292 array(
'#LANG#' => $language)
296 unset($needFields, $copyFields);
301 if (!empty($errorMessages))
304 return $errorMessages;
318 if (!self::checkFields(
'ADD',
$arFields))
321 $arInsert =
$DB->PrepareInsert(
"b_catalog_currency_lang",
$arFields);
323 $strSql =
"insert into b_catalog_currency_lang(".$arInsert[0].
") values(".$arInsert[1].
")";
344 $strUpdate =
$DB->PrepareUpdate(
"b_catalog_currency_lang",
$arFields);
345 if (!empty($strUpdate))
347 $strSql =
"update b_catalog_currency_lang set ".$strUpdate.
" where CURRENCY = '".
$DB->ForSql(
$currency).
"' and LID='".
$DB->ForSql(
$lang).
"'";
369 $strSql =
"delete from b_catalog_currency_lang where CURRENCY = '".$DB->ForSql(
$currency).
"' and LID = '".
$DB->ForSql(
$lang).
"'";
384 $strSql =
"select * from b_catalog_currency_lang where CURRENCY = '".$DB->ForSql(
$currency).
"' and LID = '".
$DB->ForSql(
$lang).
"'";
396 global $stackCacheManager;
398 if (defined(
"CURRENCY_SKIP_CACHE") && CURRENCY_SKIP_CACHE)
405 if (defined(
"CURRENCY_CACHE_TIME"))
406 $cacheTime = (int)CURRENCY_CACHE_TIME;
410 $stackCacheManager->SetLength(
"currency_currency_lang", 20);
411 $stackCacheManager->SetTTL(
"currency_currency_lang", $cacheTime);
412 if ($stackCacheManager->Exist(
"currency_currency_lang", $strCacheKey))
414 $arCurrencyLang = $stackCacheManager->Get(
"currency_currency_lang", $strCacheKey);
419 $stackCacheManager->Set(
"currency_currency_lang", $strCacheKey, $arCurrencyLang);
423 return $arCurrencyLang;
430 $strSql =
"select CURL.* from b_catalog_currency_lang CURL ";
433 $strSql .=
"where CURL.CURRENCY = '".$DB->ForSql(
$currency, 3).
"' ";
435 if (strtolower($by) ==
"currency") $strSqlOrder =
" order by CURL.CURRENCY ";
436 elseif (strtolower($by) ==
"name") $strSqlOrder =
" order by CURL.FULL_NAME ";
439 $strSqlOrder =
" order BY CURL.LID ";
443 $strSqlOrder .=
" desc ";
445 $strSql .= $strSqlOrder;
447 return $DB->Query($strSql);
452 return self::$arDefaultValues;
457 return self::$arSeparators;
462 $boolFull = (
true == $boolFull);
487 'TEXT' =>
'$1.234,10',
494 'TEXT' =>
'$1 234,10',
501 'TEXT' =>
'1.234,10 USD',
508 'TEXT' =>
'1 234,10 USD',
515 'TEXT' =>
'€2.345,20',
516 'FORMAT' =>
'€#',
522 'TEXT' =>
'€2 345,20',
523 'FORMAT' =>
'€#',
529 'TEXT' =>
'2.345,20 EUR',
536 'TEXT' =>
'2 345,20 EUR',
543 if (in_array(
'RUB', $installCurrencies))
545 $rubTitle = Loc::getMessage(
'BT_CUR_LANG_CURRENCY_RUBLE');
547 'TEXT' =>
'3.456,70 '.$rubTitle,
548 'FORMAT' =>
'# '.$rubTitle,
554 'TEXT' =>
'3 456,70 '.$rubTitle,
555 'FORMAT' =>
'# '.$rubTitle,
568 Main\Context::getCurrent()->getRequest()->isAdminSection()
573 if (!isset(self::$arCurrencyFormat[
$currency]))
585 $arCurFormat[
'DECIMALS'] = self::$arDefaultValues[
'DECIMALS'];
590 $arCurFormat[
'DEC_POINT'] = self::$arDefaultValues[
'DEC_POINT'];
594 && isset(self::$arSeparators[
$arCurFormat[
'THOUSANDS_VARIANT']])
601 $arCurFormat[
'THOUSANDS_SEP'] = self::$arDefaultValues[
'THOUSANDS_SEP'];
605 $arCurFormat[
'FORMAT_STRING'] = self::$arDefaultValues[
'FORMAT_STRING'];
608 $sanitizer = new \CBXSanitizer();
610 $sanitizer->ApplyDoubleEncode(
false);
616 $arCurFormat[
"FORMAT_STRING"] = strip_tags(preg_replace(
617 '#<script[^>]*?>.*?</script[^>]*?>#is',
624 $arCurFormat[
'HIDE_ZERO'] = self::$arDefaultValues[
'HIDE_ZERO'];
635 $parts = static::explodeFormatTemplate(
$arCurFormat[
'FORMAT_STRING']);
639 $arCurFormat[
'TEMPLATE'][
'VALUE_INDEX'] = (int)array_search(
'#', $parts);
657 static $eventExists =
null;
659 $useTemplate = (bool)$useTemplate;
662 if ($eventExists ===
true || $eventExists ===
null)
664 foreach (
GetModuleEvents(
'currency',
'CurrencyFormat',
true) as $arEvent)
673 if ($eventExists ===
null)
675 $eventExists =
false;
680 if (!isset($price) || $price ===
'')
691 $format = self::$arCurrencyFormat[
$currency] ?? self::GetFormatDescription(
$currency);
693 return static::formatValue($price, $format, $useTemplate);
698 if (!isset(self::$region))
703 $format[
'DECIMALS'] = (int)($format[
'DECIMALS'] ?? self::$arDefaultValues[
'DECIMALS']);
704 $format[
'HIDE_ZERO'] ??= self::$arDefaultValues[
'HIDE_ZERO'];
705 $format[
'DEC_POINT'] = (string)($format[
'DEC_POINT'] ?? self::$arDefaultValues[
'DEC_POINT']);
706 $format[
'THOUSANDS_SEP'] = (string)($format[
'THOUSANDS_SEP'] ?? self::$arDefaultValues[
'THOUSANDS_SEP']);
707 $format[
'FORMAT_STRING'] = (string)($format[
'FORMAT_STRING'] ?? self::$arDefaultValues[
'FORMAT_STRING']);
708 $format[
'CURRENCY'] = $format[
'CURRENCY'] ??
null;
710 if (is_string($value))
712 $value = str_replace(
',',
'.', $value);
716 $format[
'CURRENCY'] ===
'INR'
717 && (self::$region ===
'hi' || self::$region ===
'in')
720 if (self::useSimpleFormat($value, $format[
'DECIMALS']))
722 $value = round((
float)$value, $format[
'DECIMALS']);
724 $result = self::extendedInrFormatValue((
string)$value, $format);
728 if (self::useSimpleFormat($value, $format[
'DECIMALS']))
730 $result = self::simpleFormatValue((
float)$value, $format);
734 $result = self::extendedFormatValue((
string)$value, $format);
740 ? static::applyTemplate(
$result, $format[
'FORMAT_STRING'])
747 $format[
'THOUSANDS_VARIANT'] = (string)($format[
'THOUSANDS_VARIANT'] ?? self::$arDefaultValues[
'THOUSANDS_VARIANT']);
748 $format[
'THOUSANDS_SEP'] = (string)($format[
'THOUSANDS_SEP'] ?? self::$arDefaultValues[
'THOUSANDS_SEP']);
758 return static::formatValue($value, $format,
false);
763 return (
string)preg_replace(
'/(^|[^&])#/',
'${1}'.$value, (
string)
$template);
780 if (
$currency ===
false || $language ===
false)
784 $query =
"select LID from b_catalog_currency_lang where CURRENCY = '".$DB->ForSql(
$currency).
"' and LID = '".
$DB->ForSql($language).
"'";
786 $result = $searchIterator->Fetch();
787 unset($searchIterator);
796 return $result[
'TEMPLATE'][
'PARTS'];
801 $result = preg_split(
'/(?<!&)(#)/',
$template, -1, PREG_SPLIT_DELIM_CAPTURE);
807 if ($resultCount > 1)
818 if (
$result[$resultCount-1] ==
'')
827 unset(
$count, $offset, $needSlice);
844 $format = static::getParsedCurrencyFormat(
$currency);
849 $index = array_search(
'#', $format);
850 if ($index ===
false)
856 return implode(
'', $format);
861 return ($value !==
null);
868 return static::unFormatValue($formattedValue, (
string)$format[
'THOUSANDS_SEP'], (
string)$format[
'DEC_POINT']);
871 protected static function unFormatValue(
string $formattedValue,
string $thousandsSeparator,
string $decPoint): string
875 if($thousandsSeparator !==
'')
880 if($decPoint !==
'.' && $decPoint !==
'')
888 private static function useSimpleFormat(
string|
float|
int|
null $value,
int $decimals): bool
890 static $floatPrecision =
null;
891 if ($floatPrecision ===
null)
893 $floatPrecision = (int)ini_get(
'precision');
895 if (is_int($value) || is_float($value))
899 if ($value ===
'' || $value ===
null || $value ===
'0')
904 if ($value !== (
string)((
float)$value))
909 $parsedValue = Currency\Helpers\Editor::parseValue($value);
910 if ($parsedValue ===
null)
915 $flatValue = ($parsedValue[2] ===
'' ?
'0' : $parsedValue[2]);
916 $parsedValue[3] ??=
'';
917 if ($parsedValue[3] !==
'' && $parsedValue[3] !==
'.')
919 $fraction = str_pad($parsedValue[3], $decimals + 1,
'0', STR_PAD_RIGHT);
920 if ($fraction !==
'.')
922 $flatValue .= $fraction;
927 return (strlen($flatValue) + 2) < $floatPrecision;
930 private static function simpleFormatValue(
float $value,
array $format): string
932 $decimals = $format[
'DECIMALS'];
933 if (static::isAllowUseHideZero() && $format[
'HIDE_ZERO'] ===
'Y')
935 if (round($value, $format[
'DECIMALS']) === round($value, 0))
941 return number_format($value, $decimals, $format[
'DEC_POINT'], $format[
'THOUSANDS_SEP']);
944 private static function extendedFormatValue(
string $value,
array $format): string
946 $triadSep = $format[
'THOUSANDS_SEP'];
948 $value = str_replace(
',',
'.', $value);
949 $parcedValue = explode(
'.', $value, 2);
950 $wholePart = $parcedValue[0] ??
'';
951 $fraction = $parcedValue[1] ??
'';
954 if ($wholePart[0] ===
'-')
957 $wholePart = substr($wholePart, 1);
960 $normalizedFraction = self::normalizeFraction($fraction, $format);
961 $fraction = $normalizedFraction[
'FRACTION'];
962 if ($normalizedFraction[
'FIX_UP'] !==
'')
964 $wholePart = self::roundWholePart($wholePart, $normalizedFraction[
'FIX_UP']);
966 unset($normalizedFraction[
'FIX_UP']);
968 $leadLen = strlen($wholePart) % 3;
974 $lead = substr($wholePart, 0, $leadLen);
975 $triads = substr($wholePart, $leadLen);
979 ? $lead . preg_replace(
'/(\\d{3})/', $triadSep.
'\\1', $triads)
980 : ($lead !==
'' ? $lead :
'0')
983 if ($fraction !==
'')
985 $result .= $format[
'DEC_POINT'] . $fraction;
991 private static function extendedInrFormatValue(
string $value,
array $format): string
993 $blockSep = $format[
'THOUSANDS_SEP'];
995 $value = str_replace(
',',
'.', $value);
996 $parcedValue = explode(
'.', $value, 2);
997 $wholePart = $parcedValue[0] ??
'';
998 $fraction = $parcedValue[1] ??
'';
1001 if ($wholePart[0] ===
'-')
1004 $wholePart = substr($wholePart, 1);
1007 $normalizedFraction = self::normalizeFraction($fraction, $format);
1008 $fraction = $normalizedFraction[
'FRACTION'];
1009 if ($normalizedFraction[
'FIX_UP'] !==
'')
1011 $wholePart = self::roundWholePart($wholePart, $normalizedFraction[
'FIX_UP']);
1013 unset($normalizedFraction[
'FIX_UP']);
1015 if (strlen($wholePart) <= 3)
1021 $rightTriad = substr($wholePart, -3);
1022 $wholePart = substr($wholePart, 0, -3);
1024 $leadLen = strlen($wholePart) % 2;
1030 $lead = substr($wholePart, 0, $leadLen);
1031 $blocks = substr($wholePart, $leadLen);
1035 ? $lead . preg_replace(
'/(\\d{2})/', $blockSep.
'\\1', $blocks)
1036 : ($lead !==
'' ? $lead :
'')
1039 $result .= $blockSep . $rightTriad;
1042 if ($fraction !==
'')
1044 $result .= $format[
'DEC_POINT'] . $fraction;
1050 private static function normalizeFraction(
string $fraction,
array $format): ?
array
1052 $decimals = $format[
'DECIMALS'];
1053 if (static::isAllowUseHideZero() && $format[
'HIDE_ZERO'] ===
'Y')
1055 if ($fraction ===
'')
1062 if (preg_match(
'/^0+$/', $fraction, $prepared))
1075 if ($fraction ===
'')
1077 $result[
'FRACTION'] = $decimals > 0 ? str_repeat(
'0', $decimals) :
'';
1082 $fractionLength = strlen($fraction);
1083 if ($fractionLength > $decimals)
1086 for (
$i = $fractionLength - 1;
$i >=$decimals;
$i--)
1088 $value = (int)$fraction[
$i] + $carry;
1095 $roundFraction =
'';
1096 for (
$i = $decimals - 1;
$i >= 0;
$i--)
1098 $value = (int)$fraction[
$i] + $carry;
1107 $roundFraction =
$value . $roundFraction;
1109 $result[
'FRACTION'] = $roundFraction;
1115 elseif ($fractionLength < $decimals)
1117 $result[
'FRACTION'] = str_pad($fraction, $decimals,
'0', STR_PAD_RIGHT);
1121 $result[
'FRACTION'] = $fraction;
1127 private static function roundWholePart(
string $wholePart,
string $fixUp): string
1129 $length = strlen($wholePart);
1132 $value = (int)$wholePart[$length - 1] + (
int)$fixUp;
1140 for (
$i = $length - 2;
$i >= 0;
$i--)
1142 $value = (int)$wholePart[
$i] + $carry;
const DECIMAL_POINT_COMMA
static clearCurrencyCache($language='')
static checkLanguage($language)
static getInstalledCurrencies()
static checkCurrencyID($currency)
static isModuleInstalled($moduleName)
static getList(array $parameters=array())
static array $arSeparators
static checkFields($action, &$fields, $currency='', $language='', $getErrors=false)
static Update($currency, $lang, $arFields)
static array $arDefaultValues
static unFormatValue(string $formattedValue, string $thousandsSeparator, string $decPoint)
static formatEditValue(int|float|string|null $value, array $format)
static applyTemplate($value, $template)
static explodeFormatTemplate(string $template)
static GetSeparatorTypes($boolFull=false)
static GetFormatTemplates()
static getUnFormattedValue(string $formattedValue, string $currency, string $lang=LANGUAGE_ID)
static GetByID($currency, $lang)
static isExistCurrencyLanguage($currency, $language)
static Delete($currency, $lang)
static isAllowUseHideZero()
static formatValue($value, array $format, $useTemplate=true)
static GetFormatDescription($currency)
static getPriceControl(string $control, string $currency)
static checkLanguage($language)
static CurrencyFormat($price, $currency, $useTemplate=true)
static array $arCurrencyFormat
static GetCurrencyFormat($currency, $lang=LANGUAGE_ID)
static GetList($by='lang', $order='asc', $currency='')
static enableUseHideZero()
static GetDefaultValues()
static clearFields($value)
static disableUseHideZero()
static getParsedCurrencyFormat(string $currency)
const CURRENCY_CACHE_DEFAULT_TIME
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
if(!defined('SITE_ID')) $lang
ExecuteModuleEventEx($arEvent, $arParams=[])
GetModuleEvents($MODULE_ID, $MESSAGE_ID, $bReturnArray=false)
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"