bb-legacy/app/Tools.php line 1568

Open in your IDE?
  1. <?php
  2. /** @noinspection PhpUndefinedFieldInspection */
  3. use App\Application\Service\Helper\DatetimeHelper;
  4. use App\Application\Service\Helper\ShippingDateService;
  5. use App\Application\Service\Session\SessionService;
  6. use App\Manager\System\CustomerManager;
  7. use App\Service\Search\Adapter\ProductRepositoryAdapter;
  8. use App\ViewManager\Landing\ViewService;
  9. use Symfony\Component\DependencyInjection\ContainerInterface;
  10. use App\Manager\System\SupplierHolidaysManager;
  11. use App\Service\TaxService;
  12. class Tools extends AllowTranslation
  13. {
  14.     public const COOKIE_TAPFILIATE 'ref_tapfiliate';
  15.     public const KEY_TAPFILIATE 'tapfiliate';
  16.     public const COOKIE_ID_CUSTOMER_STASH 'bbidm';
  17.     public const HOST_BIGBUY 'bigbuy.eu';
  18.     public const ERROR_LIST = [
  19.         'SUBS01' => 'SUBS01',   // No se ha podido crear el pedido.
  20.         'SUBS02' => 'SUBS02',   // No se ha podido crear carrito de pack
  21.         'SUBS03' => 'SUBS03',   // No se ha podido crear carrito de servicios
  22.         'ORD01' => 'ORD01',     // No se ha podido recuperar el carrito asociado al pedido
  23.         'ORD02' => 'ORD02',     // No se han podido recuperar los costes de envío
  24.         'ORD03' => 'ORD03',     // No se ha podido guardar el pedido
  25.         'ORD04' => 'ORD04',     // Cache de carrito bloqueada
  26.     ];
  27.     public const MAX_LIST_PRODUCTS 9984;
  28.     public const SECONDS_BY_DAY 86400;
  29.     public static function getValue($key$default_value false$stripSlashes true)
  30.     {
  31.         if (!isset($key) || empty($key) || !is_string($key)) {
  32.             return false;
  33.         }
  34.         $ret = (isset($_POST[$key]) ? $_POST[$key] : (isset($_GET[$key]) ? $_GET[$key] : $default_value));
  35.         if (is_string($ret) === true) {
  36.             $ret urldecode(preg_replace('/((\%5C0+)|(\%00+))/i'''urlencode($ret)));
  37.         }
  38.         if (!is_string($ret)) {
  39.             return $ret;
  40.         } else {
  41.             return $stripSlashes stripslashes($ret) : $ret;
  42.         }
  43.     }
  44.     /**
  45.      * Sanitize data which will be injected into SQL query
  46.      *
  47.      * @param string $string SQL data which will be injected into SQL query
  48.      * @param bool $htmlOK Does data contain HTML code ? (optional)
  49.      *
  50.      * @return string Sanitized data
  51.      */
  52.     public static function pSQL($string$htmlOK false)
  53.     {
  54.         return self::escape($string$htmlOK);
  55.     }
  56.     /**
  57.      * Sanitize data which will be injected into SQL query
  58.      *
  59.      * @param string $string SQL data which will be injected into SQL query
  60.      * @param bool $html_ok Does data contain HTML code ? (optional)
  61.      *
  62.      * @return string Sanitized data
  63.      */
  64.     public static function escape($string$html_ok false)
  65.     {
  66.         $string addslashes($string);
  67.         if (!is_numeric($string)) {
  68.             if (!$html_ok) {
  69.                 $string strip_tags(Tools::nl2br($string));
  70.             }
  71.         }
  72.         return $string;
  73.     }
  74.     /**
  75.      * Convert \n and \r\n and \r to <br />
  76.      *
  77.      * @param string $string String to transform
  78.      *
  79.      * @return string New string
  80.      */
  81.     public static function nl2br($str)
  82.     {
  83.         return str_replace(["\r\n""\r""\n"], '<br />'$str);
  84.     }
  85.     /**
  86.      * Delete unicode class from regular expression patterns
  87.      *
  88.      * @param string $pattern
  89.      *
  90.      * @return pattern
  91.      */
  92.     public static function cleanNonUnicodeSupport($pattern)
  93.     {
  94.         if (!defined('PREG_BAD_UTF8_OFFSET')) {
  95.             return $pattern;
  96.         }
  97.         return preg_replace('/\\\[px]\{[a-z]\}{1,2}|(\/[a-z]*)u([a-z]*)$/i''$1$2'$pattern);
  98.     }
  99.     /**
  100.      * Redirect user to another page
  101.      *
  102.      * @param string $url Desired URL
  103.      * @param string $baseUri Base URI (optional)
  104.      * @param string|array $headers A list of headers to send before redirection
  105.      */
  106.     public static function redirect($url$base_uri BASE_URL$redirect_301 false)
  107.     {
  108.         if (strpos($url'http://') === false && strpos($url'https://') === false) {
  109.             if (strpos($url$base_uri) === 0) {
  110.                 $url substr($urlstrlen($base_uri));
  111.             }
  112.             // SE CONCATENA LA URI BASE JUNTO CON LA URL SOLICITADA
  113.             $url $base_uri.$url;
  114.         }
  115.         ob_clean();
  116.         if ($redirect_301) {
  117.             header('HTTP/1.1 301 Moved Permanently');
  118.         }
  119.         header('Location: '.$url);
  120.         exit;
  121.     }
  122.     public static function addError($message)
  123.     {
  124.         Session::add('error'$message);
  125.     }
  126.     public static function addNamedError($name_input$message)
  127.     {
  128.         Session::add_flashdata_byId('error'$name_input$message);
  129.     }
  130.     public static function getError()
  131.     {
  132.         return Session::get('error'falsetrue);
  133.     }
  134.     public static function hasError()
  135.     {
  136.         return Session::get('error');
  137.     }
  138.     public static function getErrors()
  139.     {
  140.         $errors false;
  141.         if (Tools::hasError()) {
  142.             $errors Tools::getError();
  143.         }
  144.         return $errors;
  145.     }
  146.     public static function addNamedNotice($name_input$message)
  147.     {
  148.         Session::add_flashdata_byId('notice'$name_input$message);
  149.     }
  150.     public static function hasNotice()
  151.     {
  152.         return Session::get('notice');
  153.     }
  154.     public static function getNotice()
  155.     {
  156.         return Session::get('notice'falsetrue);
  157.     }
  158.     public static function getNotices()
  159.     {
  160.         $notices false;
  161.         if (Tools::hasNotice()) {
  162.             $notices Tools::getNotice();
  163.         }
  164.         return $notices;
  165.     }
  166.     public static function strlen($str$encoding 'UTF-8')
  167.     {
  168.         if (is_array($str)) {
  169.             return false;
  170.         }
  171.         $str html_entity_decode($strENT_COMPAT'UTF-8');
  172.         if (function_exists('mb_strlen')) {
  173.             return mb_strlen($str$encoding);
  174.         }
  175.         return strlen($str);
  176.     }
  177.     /**
  178.      * Encrypt password
  179.      *
  180.      * @param string $passwd String to encrypt
  181.      */
  182.     public static function encrypt($passwd)
  183.     {
  184.         return md5($passwd);
  185.     }
  186.     /**
  187.      * jsonDecode convert json string to php array / object
  188.      *
  189.      * @param string $json
  190.      * @param bool $assoc (since 1.4.2.4) if true, convert to associativ array
  191.      *
  192.      * @return array
  193.      *
  194.      * @deprecated use json_decode instead
  195.      */
  196.     public static function jsonDecode($json$assoc false)
  197.     {
  198.         return json_decode($json$assoc);
  199.     }
  200.     /**
  201.      * Convert an array to json string
  202.      *
  203.      * @param array $data
  204.      *
  205.      * @return string json
  206.      * @deprecated use json_encode instead
  207.      *
  208.      */
  209.     public static function jsonEncode($data$unescape false)
  210.     {
  211.         if (!$unescape) {
  212.             return json_encode($data);
  213.         }
  214.         return json_encode($dataJSON_UNESCAPED_SLASHES);
  215.     }
  216.     /**
  217.      * Retorna una fecha según las preferencias del lenguaje
  218.      *
  219.      * @deprecated use displayDate from ToolsService instead
  220.      *
  221.      * @param string $date La fecha a convertir
  222.      * @param bool $full Si el formato de la fecha debe retornar horas o no
  223.      * @param string $format Formato de la fecha personalizado
  224.      *
  225.      * @return string La fecha convertida
  226.      */
  227.     public static function displayDate($date$full false$date_format false$plus_gmt_offset true)
  228.     {
  229.         if (!$date || !($time strtotime($date))) {
  230.             return $date;
  231.         }
  232.         if ($date == '0000-00-00 00:00:00' || $date == '0000-00-00') {
  233.             return '';
  234.         }
  235.         if (!Validate::isDate($date) || !Validate::isBool($full)) {
  236.             Tools::addError('Invalid date');
  237.         }
  238.         if (!$date_format) {
  239.             $date_format = ($full Session::get('date_format_full') : Session::get('date_format_lite'));
  240.         }
  241.         if ($plus_gmt_offset) {
  242.             return date($date_format$time Session::get('gmt_offset'));
  243.         } else {
  244.             return date($date_format$time);
  245.         }
  246.     }
  247.     /**
  248.      * Retorna una fecha con formato compatible con Mysql
  249.      *
  250.      * @param type $date Fecha a convertir
  251.      * @param type $dateFormat Formato para Mysql
  252.      *
  253.      * @return type Fecha formateada
  254.      */
  255.     public static function displayDateMysql($date$dateFormat 'Y-m-d H:i:s')
  256.     {
  257.         $date str_replace('/''.'$date);
  258.         $dateMysql date($dateFormatstrtotime($date));
  259.         return $dateMysql;
  260.     }
  261.     public static function getWeekDays()
  262.     {
  263.         return [
  264.             self::l('Domingo''Tools'),
  265.             self::l('Lunes''Tools'),
  266.             self::l('Martes''Tools'),
  267.             self::l('Miércoles''Tools'),
  268.             self::l('Jueves''Tools'),
  269.             self::l('Viernes''Tools'),
  270.             self::l('Sábado''Tools'),
  271.         ];
  272.     }
  273.     public static function getMonths()
  274.     {
  275.         return [
  276.             self::l('Enero''Tools'),
  277.             self::l('Febrero''Tools'),
  278.             self::l('Marzo''Tools'),
  279.             self::l('Abril''Tools'),
  280.             self::l('Mayo''Tools'),
  281.             self::l('Junio''Tools'),
  282.             self::l('Julio''Tools'),
  283.             self::l('Agosto''Tools'),
  284.             self::l('Septiembre''Tools'),
  285.             self::l('Octubre''Tools'),
  286.             self::l('Noviembre''Tools'),
  287.             self::l('Diciembre''Tools'),
  288.         ];
  289.     }
  290.     public static function displayTextDate($date)
  291.     {
  292.         $year date('Y'$date);
  293.         $month = (int)date('m'$date);
  294.         $day date('d'$date);
  295.         $week_day date('w'$date);
  296.         $week_days Tools::getWeekDays();
  297.         $months Tools::getMonths();
  298.         return $week_days[$week_day].', '.$day.' de '.$months[$month].' de '.$year;
  299.     }
  300.     public static function displayTextMonth($monthsNumber)
  301.     {
  302.         $months Tools::getMonths();
  303.         return $months[$monthsNumber 1];
  304.     }
  305.     /**
  306.      * Return price with currency sign for a given product
  307.      *
  308.      * @deprecated use displayPrice from ToolsService instead
  309.      *
  310.      * @param float $price Product price
  311.      *
  312.      * @return string Price correctly formated (sign, decimal separator...)
  313.      */
  314.     public static function displayPrice($price$show_currency true$decimal 2$no_utf8 false)
  315.     {
  316.         if (!is_numeric($price)) {
  317.             return $price;
  318.         }
  319.         $c_char '';
  320.         $blank '';
  321.         if ($show_currency) {
  322.             $c_char '€';
  323.             $blank ' ';
  324.         }
  325.         $c_format Session::get('currency_format');
  326.         $c_decimals $decimal;
  327.         $ret 0;
  328.         if ($is_negative = ($price 0)) {
  329.             $price *= -1;
  330.         }
  331.         $price Tools::ps_round($price$c_decimals);
  332.         switch ($c_format) {
  333.             /* 0.000,00 X */
  334.             case 1:
  335.                 $ret number_format($price$c_decimals',''.').$blank.$c_char;
  336.                 break;
  337.                 /* X 0,000.00 X */
  338.             case 2:
  339.                 $ret $c_char.number_format($price$c_decimals'.'',');
  340.                 break;
  341.         }
  342.         if ($is_negative) {
  343.             $ret '-'.$ret;
  344.         }
  345.         if ($no_utf8) {
  346.             return str_replace('€'chr(128), $ret);
  347.         }
  348.         return $ret;
  349.     }
  350.     /**
  351.      * Return price with currency sign for a given product
  352.      *
  353.      * @deprecated use displayNumber from ToolsService instead
  354.      *
  355.      * @param float $price Product price
  356.      *
  357.      * @return string Price correctly formated (sign, decimal separator...)
  358.      */
  359.     public static function displayNumber($number$decimal 2)
  360.     {
  361.         if (!is_numeric($number)) {
  362.             return $number;
  363.         }
  364.         $c_format Session::get('currency_format');
  365.         $c_decimals $decimal;
  366.         $ret 0;
  367.         if ($is_negative = ($number 0)) {
  368.             $number *= -1;
  369.         }
  370.         $number Tools::ps_round($number$c_decimals);
  371.         switch ($c_format) {
  372.             /* 0.000,00 */
  373.             case 1:
  374.                 $ret number_format($number$c_decimals',''.');
  375.                 break;
  376.                 /* 0,000.00 */
  377.             case 2:
  378.                 $ret number_format($number$c_decimals'.'',');
  379.                 break;
  380.         }
  381.         if ($is_negative) {
  382.             $ret '-'.$ret;
  383.         }
  384.         return $ret;
  385.     }
  386.     public static function strtolower($str)
  387.     {
  388.         if (is_array($str)) {
  389.             return false;
  390.         }
  391.         if (function_exists('mb_strtolower')) {
  392.             return mb_strtolower($str'utf-8');
  393.         }
  394.         return strtolower($str);
  395.     }
  396.     public static function substr($str$start$length false$encoding 'utf-8')
  397.     {
  398.         if (is_array($str)) {
  399.             return false;
  400.         }
  401.         if (function_exists('mb_substr')) {
  402.             return mb_substr($str, (int)$start$length === false Tools::strlen($str) : (int)$length$encoding);
  403.         }
  404.         return substr($str$start$length === false Tools::strlen($str) : (int)$length);
  405.     }
  406.     /**
  407.      * Comprobamos un VAT Number
  408.      *
  409.      * @param string $vatid VAT Number a validar
  410.      * @param string $cc codigo ISO del pais
  411.      * @param int $idCustomer Identificador del usuario
  412.      *
  413.      * @return bool
  414.      * @deprecated use TaxService::isValidVies() instead
  415.      */
  416.     public static function checkVATNumber($vatid$cc$idCustomer)
  417.     {
  418.         if (!$vatid || !$cc) {
  419.             return false;
  420.         }
  421.         $taxService self::getSfService(TaxService::class);
  422.         return $taxService->isValidVies($idCustomer$vatid$cc);
  423.     }
  424.     /**
  425.      * returns the rounded value of $value to specified precision, according to your configuration;
  426.      *
  427.      * @note : PHP 5.3.0 introduce a 3rd parameter mode in round function
  428.      *
  429.      * @param float $value
  430.      * @param int $precision
  431.      *
  432.      * @return float
  433.      *
  434.      * @deprecated use round() instead
  435.      */
  436.     public static function ps_round($value$precision 0)
  437.     {
  438.         return round($value$precision);
  439.     }
  440.     public static function getBreadcrumbData($taxonomyId$addSections = [], $idLang null)
  441.     {
  442.         if (!$idLang) {
  443.             $idLang Session::get('id_lang');
  444.         }
  445.         $parentTaxonomies Taxonomy::getParentsTaxonomy($taxonomyId$idLang);
  446.         if (!$parentTaxonomies) {
  447.             return [];
  448.         }
  449.         $sections = [];
  450.         $taxonomy array_shift($parentTaxonomies);
  451.         $link Link::getTaxonomyLink($taxonomy->getId(), $idLang); // str_replace(".html", "/", $taxonomy->getLink());
  452.         $name Taxonomy::getTaxonomyName($taxonomy->getId(), $idLang);
  453.         $sections[] = ['link' => $link'name' => $name];
  454.         foreach ($parentTaxonomies as $parentTaxonomy) {
  455.             $link Link::getTaxonomyLink($parentTaxonomy->getId(), $idLang);
  456.             $name Taxonomy::getTaxonomyName($parentTaxonomy->getId(), $idLang);
  457.             $sections[] = ['link' => $link'name' => $name];
  458.         }
  459.         if (count($addSections) > 0) {
  460.             foreach ($addSections as $section) {
  461.                 $sections[] = $section;
  462.             }
  463.         }
  464.         return $sections;
  465.     }
  466.     public static function getRealIP()
  467.     {
  468.         if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
  469.             return $_SERVER['HTTP_CLIENT_IP'];
  470.         }
  471.         // TODO quitar este if y descomentar las líneas
  472.         if (!empty($_SERVER['REMOTE_ADDR'])) {
  473.             return $_SERVER['REMOTE_ADDR'];
  474.         }
  475.         // if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
  476.         return $_SERVER['HTTP_X_FORWARDED_FOR'];
  477.         // return $_SERVER['REMOTE_ADDR'];
  478.     }
  479.     public static function getCoordsIP()
  480.     {
  481.         // Obtenemos localización del usuario por su ip
  482.         $ip Tools::getRealIP();
  483.         // $ip = '88.0.57.88';
  484.         $url 'http://www.geoplugin.net/php.gp?ip='.$ip// echo $url;
  485.         $datos = @unserialize(file_get_contents($url));
  486.         $resp = [];
  487.         if ($datos) {
  488.             // $iso_code = $datos['geoplugin_countryCode'];
  489.             // $city = $datos['geoplugin_city'];
  490.             $resp['latitud'] = (isset($datos['geoplugin_latitude'])) ? $datos['geoplugin_latitude'] : '';
  491.             $resp['longitud'] = (isset($datos['geoplugin_longitude'])) ? $datos['geoplugin_longitude'] : '';
  492.             $resp['country_code'] = (isset($datos['geoplugin_countryCode'])) ? $datos['geoplugin_countryCode'] : '';
  493.             $resp['geoplugin_request'] = (isset($datos['geoplugin_request'])) ? $datos['geoplugin_request'] : '';
  494.         } else {
  495.             $resp['latitud'] = '';
  496.             $resp['longitud'] = '';
  497.             $resp['country_code'] = '';
  498.             $resp['geoplugin_request'] = '';
  499.         }
  500.         return $resp;
  501.     }
  502.     /**
  503.      * Modifies a string to remove all non ASCII characters and spaces.
  504.      */
  505.     public static function slugify($text)
  506.     {
  507.         // replace non letter or digits by -
  508.         $text preg_replace('~[^\\pL\d]+~u''-'$text);
  509.         // trim
  510.         $text trim($text'-');
  511.         // transliterate
  512.         if (function_exists('iconv')) {
  513.             $text iconv('utf-8''us-ascii//TRANSLIT'$text);
  514.         }
  515.         // lowercase
  516.         $text strtolower($text);
  517.         // remove unwanted characters
  518.         $text preg_replace('~[^-\w]+~'''$text);
  519.         if (empty($text)) {
  520.             return 'n-a';
  521.         }
  522.         return $text;
  523.     }
  524.     /**
  525.      * @deprecated use guzzle instead
  526.      */
  527.     public static function httpPost($url$params$return_http_code false$follow false$sslVerification true)
  528.     {
  529.         $postData '';
  530.         if (!empty($params)) {
  531.             $postData http_build_query($params);
  532.         }
  533.         $ch curl_init();
  534.         curl_setopt($chCURLOPT_URL$url);
  535.         curl_setopt($chCURLOPT_RETURNTRANSFERtrue);
  536.         curl_setopt($chCURLOPT_HEADERfalse);
  537.         // NO VERIFICAR SSL SI ESTAMOS EN MODO DESARROLLO
  538.         if (Tools::getSfService(\App\Service\EnvironmentService::class)->isDev() || !$sslVerification) {
  539.             curl_setopt($chCURLOPT_SSL_VERIFYHOSTfalse);
  540.             curl_setopt($chCURLOPT_SSL_VERIFYPEERfalse);
  541.         }
  542.         if (!empty($params)) {
  543.             curl_setopt($chCURLOPT_POSTis_array($postData) && count($postData) ? true false);
  544.             curl_setopt($chCURLOPT_POSTFIELDS$postData);
  545.         }
  546.         if ($follow) {
  547.             curl_setopt($chCURLOPT_FOLLOWLOCATIONtrue);
  548.         }
  549.         //        DESCOMENTAR PARA DEPURAR LLAMADAS CURL DESDE NETBEANS
  550.         //        curl_setopt($ch, CURLOPT_COOKIE,"XDEBUG_SESSION=netbeans-xdebug");
  551.         $output curl_exec($ch);
  552.         if ($output == false) {
  553.             $output curl_error($ch);
  554.         }
  555.         // DEVOLVEMOS EL CODIGO HTTP (404, 500, 200...)
  556.         if ($return_http_code) {
  557.             $output curl_getinfo($chCURLINFO_HTTP_CODE);
  558.         }
  559.         curl_close($ch);
  560.         return $output;
  561.     }
  562.     /**
  563.      * Truncate strings
  564.      *
  565.      * @param string $str
  566.      * @param int $max_length Max length
  567.      * @param string $suffix Suffix optional
  568.      *
  569.      * @return string $str truncated
  570.      */
  571.     /* CAUTION : Use it only on module hookEvents.
  572.      * * For other purposes use the smarty function instead */
  573.     public static function truncate($str$max_length$suffix '...')
  574.     {
  575.         if (Tools::strlen($str) <= $max_length) {
  576.             return $str;
  577.         }
  578.         $str utf8_decode($str);
  579.         return utf8_encode(substr($str0$max_length Tools::strlen($suffix)).$suffix);
  580.     }
  581.     public static function getDefaultIndexContent()
  582.     {
  583.         return '<?php
  584. /*
  585. * BLOQUEAR ACCESO A LAS CARPETAS
  586. */
  587. header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
  588. header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
  589. header("Cache-Control: no-store, no-cache, must-revalidate");
  590. header("Cache-Control: post-check=0, pre-check=0", false);
  591. header("Pragma: no-cache");
  592. header("Location: ../");
  593. exit;
  594. ';
  595.     }
  596.     public static function isMobile()
  597.     {// return true;
  598.         if (defined('IS_MOBILE')) {
  599.             return IS_MOBILE;
  600.         }
  601.         return false;
  602.     }
  603.     public static function getPassword()
  604.     {
  605.         // Se define una cadena de caractares. Te recomiendo que uses esta.
  606.         $cadena 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
  607.         // Obtenemos la longitud de la cadena de caracteres
  608.         $longitudCadena strlen($cadena);
  609.         // Se define la variable que va a contener la contraseña
  610.         $pass '';
  611.         // Se define la longitud de la contraseña, en mi caso 10, pero puedes poner la longitud que quieras
  612.         $longitudPass 10;
  613.         // Creamos la contraseña
  614.         for ($i 1$i <= $longitudPass$i++) {
  615.             // Definimos numero aleatorio entre 0 y la longitud de la cadena de caracteres-1
  616.             $pos rand(0$longitudCadena 1);
  617.             // Vamos formando la contraseña en cada iteraccion del bucle, añadiendo a la cadena $pass la letra correspondiente a la posicion $pos en la cadena de caracteres definida.
  618.             $pass .= substr($cadena$pos1);
  619.         }
  620.         return $pass;
  621.     }
  622.     public static function getNombreMes($mes)
  623.     {
  624.         setlocale(LC_TIMESession::get('lang'));
  625.         $nombre strftime('%B'mktime(000$mes12000));
  626.         return strtoupper(substr($nombre03));
  627.     }
  628.     public static function generarCodigo($longitud)
  629.     {
  630.         $key '';
  631.         $pattern '1234567890abcdefghijklmnopqrstuvwxyz';
  632.         $max strlen($pattern) - 1;
  633.         for ($i 0$i $longitud$i++) {
  634.             $key .= $pattern[mt_rand(0$max)];
  635.         }
  636.         return $key;
  637.     }
  638.     public static function array_orderby()
  639.     {
  640.         $args func_get_args();
  641.         $data array_shift($args);
  642.         foreach ($args as $n => $field) {
  643.             if (is_string($field)) {
  644.                 $tmp = [];
  645.                 foreach ($data as $key => $row) {
  646.                     $tmp[$key] = $row[$field];
  647.                 }
  648.                 $args[$n] = $tmp;
  649.             }
  650.         }
  651.         $args[] = &$data;
  652.         call_user_func_array('array_multisort'$args);
  653.         return array_pop($args);
  654.     }
  655.     public static function dropAccents($incoming_string)
  656.     {
  657.         $tofind 'ÀÁÂÄÅàáâäÒÓÔÖòóôöÈÉÊËèéêëÇçÌÍÎÏìíîïÙÚÛÜùúûüÿÑñ';
  658.         $replac 'AAAAAaaaaOOOOooooEEEEeeeeCcIIIIiiiiUUUUuuuuyNn';
  659.         return utf8_encode(strtr(utf8_decode($incoming_string), utf8_decode($tofind), $replac));
  660.     }
  661.     public static function addPeriodToDate($frecuency$time$period)
  662.     {
  663.         $date = new DateTime($time);
  664.         $monthOld $date->format('m');
  665.         $date->modify('+'.$frecuency.' '.$period);
  666.         $monthActually $date->format('m');
  667.         if ($monthActually $monthOld) {
  668.             $monthActually += 12;
  669.         }
  670.         if ($monthActually $monthOld $frecuency) {
  671.             $date->modify('last day of -1 Month');
  672.         }
  673.         return $date->format('Y-m-d');
  674.     }
  675.     public static function calculateDaysTransit($days$productId null$extern false)
  676.     {
  677.         $syncronisedException = ($extern) ? Product::isSincronisedSendException($productId) : false;
  678.         if ($days <= 2) {
  679.             return [
  680.                 'days' => 1,
  681.                 'text_product' => self::l('%s uds.''Tools'),
  682.                 'text_cart' => (!$syncronisedException) ? self::l('Envío inmediato''Tools') : self::l('24/48h''Tools'),
  683.             ];
  684.         }
  685.         $tmpDays = (int)ceil($days 5);
  686.         switch ($tmpDays) {
  687.             case 0:
  688.             case 1:
  689.                 $days_range '2/5';
  690.                 $tmpDays 1;
  691.                 break;
  692.             case 2:
  693.                 $days_range '5/10';
  694.                 break;
  695.             case 3:
  696.                 $days_range '10/15';
  697.                 break;
  698.             case 4:
  699.                 $days_range '15/20';
  700.                 break;
  701.             default:
  702.                 $days_range '20/30';
  703.         }
  704.         return [
  705.             'days' => $tmpDays 5,
  706.             'text_product' => sprintf(self::l('%s uds. envío %s días''Tools'), '%s'$days_range),
  707.             'text_cart' => sprintf(self::l('%s días''Tools'), $days_range),
  708.         ];
  709.     }
  710.     public static function divideString($name$separador '<br />'$num_lines 2)
  711.     {
  712.         $blank_spaces ceil(substr_count($name' ') / $num_lines);
  713.         $nameEnd '';
  714.         $count_spaces 0;
  715.         $nameTmp str_split($name);
  716.         $br false;
  717.         foreach ($nameTmp as $c) {
  718.             if ($c == ' ') {
  719.                 $count_spaces++;
  720.             }
  721.             if ($count_spaces == $blank_spaces && $blank_spaces && !$br) {
  722.                 $nameEnd .= $separador;
  723.                 $br true;
  724.             } else {
  725.                 $nameEnd .= $c;
  726.             }
  727.         }
  728.         return $nameEnd;
  729.     }
  730.     public static function replaceAutomatedLinks($string_to_replace)
  731.     {
  732.         return preg_replace_callback('/##(CMS|CAT|TAXONOMY)\_(.[0-9]*)##/', function ($matches) {
  733.             switch ($matches[1]) {
  734.                 case 'CMS':
  735.                     $cms = new Cms($matches[2]);
  736.                     // RECUPERAMOS LOS DATOS QUE NECESITAMOS PARA EL LINK
  737.                     $link_rewrite = (!empty($cms->link_rewrite[Session::get('id_lang')])) ? $cms->link_rewrite[Session::get('id_lang')] : '';
  738.                     return Link::getActionLink($link_rewrite);
  739.                     break;
  740.                 case 'CAT':
  741.                     return Link::getCategoryLink($matches[2]);
  742.                 case 'TAXONOMY':
  743.                     return Link::getTaxonomyLink($matches[2]);
  744.                     break;
  745.             }
  746.         }, $string_to_replace);
  747.     }
  748.     public static function convertTable($txt$titulo '')
  749.     {
  750.         $_convertTable = [
  751.         '&amp;' => 'and''@' => 'at''©' => 'c''®' => 'r''À' => 'a''Á' => 'a''Â' => 'a''Ä' => 'a''Å' => 'a''Æ' => 'ae''Ç' => 'c''È' => 'e''É' => 'e''Ë' => 'e''Ì' => 'i''Í' => 'i''Î' => 'i''Ï' => 'i''Ò' => 'o''Ó' => 'o''Ô' => 'o''Õ' => 'o''Ö' => 'o''Ø' => 'o''Ù' => 'u''Ú' => 'u''Û' => 'u''Ü' => 'u''Ý' => 'y''ß' => 'ss''à' => 'a''á' => 'a''â' => 'a''ä' => 'a''å' => 'a''æ' => 'ae''ç' => 'c''è' => 'e''é' => 'e''ê' => 'e''ë' => 'e''ì' => 'i''í' => 'i''î' => 'i''ï' => 'i''ò' => 'o''ó' => 'o''ô' => 'o''õ' => 'o''ö' => 'o''ø' => 'o''ù' => 'u''ú' => 'u''û' => 'u''ü' => 'u''ý' => 'y''þ' => 'p''ÿ' => 'y''Ā' => 'a''ā' => 'a''Ă' => 'a''ă' => 'a''Ą' => 'a''ą' => 'a''Ć' => 'c''ć' => 'c''Ĉ' => 'c''ĉ' => 'c''Ċ' => 'c''ċ' => 'c''Č' => 'c''č' => 'c''Ď' => 'd''ď' => 'd''Đ' => 'd''đ' => 'd''Ē' => 'e''ē' => 'e''Ĕ' => 'e''ĕ' => 'e''Ė' => 'e''ė' => 'e''Ę' => 'e''ę' => 'e''Ě' => 'e''ě' => 'e''Ĝ' => 'g''ĝ' => 'g''Ğ' => 'g''ğ' => 'g''Ġ' => 'g''ġ' => 'g''Ģ' => 'g''ģ' => 'g''Ĥ' => 'h''ĥ' => 'h''Ħ' => 'h''ħ' => 'h''Ĩ' => 'i''ĩ' => 'i''Ī' => 'i''ī' => 'i''Ĭ' => 'i''ĭ' => 'i''Į' => 'i''į' => 'i''İ' => 'i''ı' => 'i''IJ' => 'ij''ij' => 'ij''Ĵ' => 'j''ĵ' => 'j''Ķ' => 'k''ķ' => 'k''ĸ' => 'k''Ĺ' => 'l''ĺ' => 'l''Ļ' => 'l''ļ' => 'l''Ľ' => 'l''ľ' => 'l''Ŀ' => 'l''ŀ' => 'l''Ł' => 'l''ł' => 'l''Ń' => 'n''ń' => 'n''Ņ' => 'n''ņ' => 'n''Ň' => 'n''ň' => 'n''ʼn' => 'n''Ŋ' => 'n''ŋ' => 'n''Ō' => 'o''ō' => 'o''Ŏ' => 'o''ŏ' => 'o''Ő' => 'o''ő' => 'o''Œ' => 'oe''œ' => 'oe''Ŕ' => 'r''ŕ' => 'r''Ŗ' => 'r''ŗ' => 'r''Ř' => 'r''ř' => 'r''Ś' => 's''ś' => 's''Ŝ' => 's''ŝ' => 's''Ş' => 's''ş' => 's''Š' => 's''š' => 's''Ţ' => 't''ţ' => 't''Ť' => 't''ť' => 't''Ŧ' => 't''ŧ' => 't''Ũ' => 'u''ũ' => 'u''Ū' => 'u''ū' => 'u''Ŭ' => 'u''ŭ' => 'u''Ů' => 'u''ů' => 'u''Ű' => 'u''ű' => 'u''Ų' => 'u''ų' => 'u''Ŵ' => 'w''ŵ' => 'w''Ŷ' => 'y''ŷ' => 'y''Ÿ' => 'y''Ź' => 'z''ź' => 'z''Ż' => 'z''ż' => 'z''Ž' => 'z''ž' => 'z''ſ' => 'z''Ə' => 'e''ƒ' => 'f''Ơ' => 'o''ơ' => 'o''Ư' => 'u''ư' => 'u''Ǎ' => 'a''ǎ' => 'a''Ǐ' => 'i''ǐ' => 'i''Ǒ' => 'o''ǒ' => 'o''Ǔ' => 'u''ǔ' => 'u''Ǖ' => 'u''ǖ' => 'u''Ǘ' => 'u''ǘ' => 'u''Ǚ' => 'u''ǚ' => 'u''Ǜ' => 'u''ǜ' => 'u''Ǻ' => 'a''ǻ' => 'a''Ǽ' => 'ae''ǽ' => 'ae''Ǿ' => 'o''ǿ' => 'o''ə' => 'e''Ё' => 'jo''Є' => 'e''І' => 'i''Ї' => 'i''А' => 'a''Б' => 'b''В' => 'v''Г' => 'g''Д' => 'd''Е' => 'e''Ж' => 'zh''З' => 'z''И' => 'i''Й' => 'j''К' => 'k''Л' => 'l''М' => 'm''Н' => 'n''О' => 'o''П' => 'p''Р' => 'r''С' => 's''Т' => 't''У' => 'u''Ф' => 'f''Х' => 'h''Ц' => 'c''Ч' => 'ch''Ш' => 'sh''Щ' => 'sch''Ъ' => '-''Ы' => 'y''Ь' => '-''Э' => 'je''Ю' => 'ju''Я' => 'ja''а' => 'a''б' => 'b''в' => 'v''г' => 'g''д' => 'd''е' => 'e''ж' => 'zh''з' => 'z''и' => 'i''й' => 'j''к' => 'k''л' => 'l''м' => 'm''н' => 'n''о' => 'o''п' => 'p''р' => 'r''с' => 's''т' => 't''у' => 'u''ф' => 'f''х' => 'h''ц' => 'c''ч' => 'ch''ш' => 'sh''щ' => 'sch''ъ' => '-''ы' => 'y''ь' => '-''э' => 'je''ю' => 'ju''я' => 'ja''ё' => 'jo''є' => 'e''і' => 'i''ї' => 'i''Ґ' => 'g''ґ' => 'g''א' => 'a''ב' => 'b''ג' => 'g''ד' => 'd''ה' => 'h''ו' => 'v''ז' => 'z''ח' => 'h''ט' => 't''י' => 'i''ך' => 'k''כ' => 'k''ל' => 'l''ם' => 'm''מ' => 'm''ן' => 'n''נ' => 'n''ס' => 's''ע' => 'e''ף' => 'p''פ' => 'p''ץ' => 'C''צ' => 'c''ק' => 'q''ר' => 'r''ש' => 'w''ת' => 't''™' => 'tm''Α' => 'a''α' => 'a''Β' => 'v''β' => 'v''Γ' => 'g''γ' => 'g''Δ' => 'd''δ' => 'd''Ε' => 'e''ε' => 'e''Ζ' => 'z''ζ' => 'z''Η' => 'i''η' => 'i''Θ' => 'th''θ' => 'th''Ι' => 'i''ι' => 'i''Κ'    => 'k''κ'    => 'k''Λ'    => 'l''λ'    => 'l''Μ'    => 'm',    'μ'    => 'm''Ν'    => 'n',    'ν'    => 'n''Ξ'    => 'ks''ξ' => 'ks''Ο' => 'o''ο' => 'o''Π' => 'p''π' => 'p''Ρ' => 'r''ρ' => 'r''Σ' => 's''σ' => 's''ς' => 's''Τ' => 't''τ' => 't''Υ' => 'u''υ' => 'u''Φ' => 'ph''φ' => 'ph''Χ' => 'x''χ' => 'x''Ψ' => 'ps''ψ'    => 'ps''Ω' => 'o''ω' => 'o',    'Ά' => 'a''ά' => 'a''Έ' => 'e''έ' => 'e''Ή' => 'i''ή' => 'i''Ί' => 'i''ί' => 'i''Ό' => 'o''ό' => 'o''Ώ' => 'o''ώ' => 'o''Ύ' => 'u''ύ' => 'u', ];
  752.         if ($txt == '') {
  753.             $txt $titulo;
  754.         }
  755.         $temp =  strtr($txt$_convertTable);
  756.         $urlKey preg_replace('#[^0-9a-z]+#i''-'$temp);
  757.         $urlKey strtolower($urlKey);
  758.         $urlKey trim($urlKey'-');
  759.         return $urlKey;
  760.     }
  761.     // Recibimos los parámetros que debemos aplicar para definir los filtros Javascript de las categorías
  762.     public static function createCategoryFilters($params)
  763.     {
  764.         /*
  765.          * Estructura
  766.          *  key => array(valor predeterminado, is_string)
  767.          */
  768.         $filters = [
  769.             'categoryId' => [''true],
  770.             'entityId' => [0false],
  771.             'categoryOffset' =>  [ViewService::MAX_CATEGORY_PRODUCTS],
  772.             'categoryLimit' =>  [ViewService::MAX_CATEGORY_PRODUCTS],
  773.             'categoryMaxPrice' => [0false],
  774.             'categoryMaxStock' => [0false],
  775.             'categoryMinStock' => [0false],
  776.             'catLink' => [''true],
  777.             'filterMobile' => [0false],
  778.             'sliderFilterInit' => [0false],
  779.             'sliderFilterEnd' => [0false],
  780.             'sliderFilterStockInit' => [0false],
  781.             'sliderFilterStockEnd' => [0false],
  782.             'urlListProducts' => [''true],
  783.         ];
  784.         $jsCode '';
  785.         foreach ($filters as $key => $value) {
  786.             $valorFinal = (empty($params[$key])) ? $value[0] : $params[$key];
  787.             if (!isset($value[1]) || $value[1] == true) {
  788.                 $jsCode .= 'var '.$key."='".$valorFinal."';";
  789.             } else {
  790.                 $jsCode .= 'var '.$key.'='.$valorFinal.';';
  791.             }
  792.         }
  793.         return $jsCode;
  794.     }
  795.     /*
  796.      * ELIMINAMOS LOS FILTROS PARA MOVIL
  797.      */
  798.     public static function remove_filters()
  799.     {
  800.         Session::delete('filters');
  801.     }
  802.     public static function convertDateToEpoch($date)
  803.     {
  804.         $tmp explode(' '$date);
  805.         $dateArray explode('-'$tmp[0]);
  806.         $hourArray explode(':'$tmp[1]);
  807.         if (empty($dateArray[1]) || empty($hourArray[2]) || empty($hourArray[1]) || empty($hourArray[2])) {
  808.             return 0;
  809.         }
  810.         $epoch mktime($hourArray[0], $hourArray[1], $hourArray[2], $dateArray[1], $dateArray[2], $dateArray[0]);
  811.         return $epoch;
  812.     }
  813.     public static function addShowRecentProduct($id_product)
  814.     {
  815.         $maxNumProductsViews Configuration::get('MAX_NUM_PRODUCTS_VIEWS'true);
  816.         $recentProductList Session::get('view_recent_products');
  817.         if (!$recentProductList) {
  818.             $recentProductList = [];
  819.             $recentProductList[$id_product] = date('Y-m-d H:i:s');
  820.             Session::set('view_recent_products'$recentProductList);
  821.             return;
  822.         }
  823.         $recentProductList[$id_product] = date('Y-m-d H:i:s');
  824.         if (count($recentProductList) > $maxNumProductsViews) {
  825.             arsort($recentProductList);
  826.             array_pop($recentProductList);
  827.         }
  828.         Session::set('view_recent_products'$recentProductList);
  829.     }
  830.     /**
  831.      * Añadimos la cookie de la secure Key del carriro
  832.      */
  833.     public static function processCookieSecureKey()
  834.     {
  835.         if (empty($_COOKIE['secure_key'])) {
  836.             $secureKey uniqid(rand(09).rand(09).rand(09), true);
  837.             setcookie('secure_key'$secureKeytime() + (60 60 24 7), '/');
  838.             Session::set('secure_key'$secureKey);
  839.         }
  840.     }
  841.     /**
  842.      * @deprecated migrated to App\Service\FiscalPositionService
  843.      *
  844.      * Comprobamos si se produce una excepción para determinados paises de la UE
  845.      */
  846.     public static function reviewExceptions(string $isoCodestring $postCode): bool
  847.     {
  848.         return self::getSfService(\App\Service\FiscalPositionService::class)->reviewExceptions($isoCode$postCode);
  849.     }
  850.     public static function getLinkAcademyInvoice()
  851.     {
  852.         switch (Session::get('lang')) {
  853.             case 'es':
  854.                 $link 'http://www.bigbuy.eu/academy/es/crear-una-factura-exportaciones-la-union-europea/';
  855.                 break;
  856.             case 'fr':
  857.                 $link 'http://www.bigbuy.eu/academy/fr/comment-creer-facture-exportations-dehors-lunion-europeenne/';
  858.                 break;
  859.             case 'de':
  860.                 $link 'http://www.bigbuy.eu/academy/de/so-erstellen-rechnung-exporte-ausserhalb-europaeischen-union/';
  861.                 break;
  862.             case 'it':
  863.                 $link 'http://www.bigbuy.eu/academy/it/come-emettere-fattura-esportazioni-fuori-unione-europea/';
  864.                 break;
  865.             default:
  866.                 $link 'http://www.bigbuy.eu/academy/en/how-create-invoice-exports-outside-european-union/';
  867.                 break;
  868.         }
  869.         return $link;
  870.     }
  871.     public static function getLinkLockRefuse()
  872.     {
  873.         switch (Session::get('lang')) {
  874.             case 'es':
  875.                 $link 'http://www.bigbuy.eu/academy/es/bloqueo-stock-bigbuy-como-funciona/';
  876.                 break;
  877.             case 'fr':
  878.                 $link 'http://www.bigbuy.eu/academy/fr/blocage-stock-ce-cest-et-comment-cela-fonctionne/';
  879.                 break;
  880.             case 'de':
  881.                 $link 'http://www.bigbuy.eu/academy/de/lagerbestandssperre-was-ist-und-wie-funktioniert/';
  882.                 break;
  883.             case 'it':
  884.                 $link 'http://www.bigbuy.eu/academy/it/bloccaggio-dello-stock-bigbuy-cose-e-come-funziona/';
  885.                 break;
  886.             default:
  887.                 $link 'http://www.bigbuy.eu/academy/en/stock-blocking-what-it-is-and-how-it-works/';
  888.                 break;
  889.         }
  890.         return $link;
  891.     }
  892.     /**
  893.      * @param $timestamp
  894.      * @param $supplierId
  895.      *
  896.      * @return int
  897.      */
  898.     public static function getClosestNonHolidayTimestampInFuture($timestamp$supplierId$additionalDaysToSkip 0): int
  899.     {
  900.         $dateTimeHelper = new DatetimeHelper();
  901.         $dateTime $dateTimeHelper->getDatetimeFromTimestamp($timestamp);
  902.         $weekendDays = [DatetimeHelper::SATURDAYDatetimeHelper::SUNDAY];
  903.         $dateHolidays Tools::jsonDecode(Configuration::get('HOLIDAYS'true), true);
  904.         if ($supplierId) {
  905.             /** @var SupplierHolidaysManager $supplierHolidayManager */
  906.             $supplierHolidayManager Tools::getSfService(SupplierHolidaysManager::class);
  907.             $supplierHoliday $supplierHolidayManager->findOneById((int)$supplierId);
  908.             $dateSupplierHolidays = ($supplierHoliday) ? json_decode($supplierHoliday->getHolidays(), true) : [];
  909.         }
  910.         while (true) {
  911.             $isHoliday = isset($dateHolidays[$dateTime->format('Y-m-d')]);
  912.             $isWeekend in_array($dateTime->format('w'), $weekendDays);
  913.             if ($supplierId) {
  914.                 $isHolidaySuplier in_array($dateTime->format('Y-m-d'), $dateSupplierHolidays);
  915.                 if (!$isHoliday && !$isWeekend && !$isHolidaySuplier) {
  916.                     if ($additionalDaysToSkip === 0) {
  917.                         return $dateTime->getTimestamp();
  918.                     } else {
  919.                         $additionalDaysToSkip--;
  920.                     }
  921.                 }
  922.             } else {
  923.                 if (!$isHoliday && !$isWeekend) {
  924.                     if ($additionalDaysToSkip === 0) {
  925.                         return $dateTime->getTimestamp();
  926.                     } else {
  927.                         $additionalDaysToSkip--;
  928.                     }
  929.                 }
  930.             }
  931.             $dateTime->modify('+1 day');
  932.         }
  933.     }
  934.     public static function removeTimeToStrtotime($date$time$period)
  935.     {
  936.         $newDate strtotime('-'.$time.' '.$period$date);
  937.         return $newDate;
  938.     }
  939.     /**
  940.      * @return int
  941.      *
  942.      * @throws Exception
  943.      *
  944.      * @var
  945.      */
  946.     public static function getExpeditionTimestampByDefault(?int $customerId$supplierId): int
  947.     {
  948.         return self::calculateExpeditionTimestamp($customerIdShippingDateService::DEFAULT_EXPEDITION_MESSAGE_TIME$supplierId00false);
  949.     }
  950.     /**
  951.      * @param int $idSupplier
  952.      * @param int|null $timestampToCompare
  953.      *
  954.      * @return int
  955.      *
  956.      * @throws Exception
  957.      */
  958.     public static function getExpeditionTimestampBySupplier(?int $customerIdint $idSupplier, ?int $timestampToComparebool $stock_3_5): int
  959.     {
  960.         $supplierExpeditionConfig plazo_aprovisionamiento_proveedor::getExpeditionInformation($idSupplier);
  961.         $cutTimeString $supplierExpeditionConfig['expedition_message_time'];
  962.         $expeditionAdditionalDaysDelay = (int)$supplierExpeditionConfig['expedition_days'];
  963.         if ($stock_3_5) {
  964.             $expeditionAdditionalDaysDelay = (int)$supplierExpeditionConfig['expedition_days_3_5'];
  965.         }
  966.         return self::calculateExpeditionTimestamp($customerId$cutTimeString$idSupplier$expeditionAdditionalDaysDelay$timestampToComparetrue);
  967.     }
  968.     /**
  969.      * @param array $product
  970.      *
  971.      * @return int
  972.      *
  973.      * @throws Exception
  974.      */
  975.     public static function getExpeditionTimestampForFutureStock(array $product): int
  976.     {
  977.         $daysUntilStockWillBeHere = \stock_venideros::calculateDaysTransit($product['id_product'], $product['id_product_attribute']);
  978.         if (!$daysUntilStockWillBeHere) {
  979.             $daysUntilStockWillBeHere = (int)self::jsonDecode(Configuration::get('STOCK_VENIDERO_DIAS_CORTESIA'), true);
  980.         }
  981.         $transitDaysData self::calculateDaysTransit($daysUntilStockWillBeHere$product['id_product']);
  982.         $datetimeHelper = new DatetimeHelper();
  983.         $tmpExpeditionTimestamp $datetimeHelper->getCurrentTimestamp();
  984.         // Add
  985.         $tmpExpeditionTimestamp += $transitDaysData['days'] * DatetimeHelper::SECONDS_A_DAY;
  986.         return self::getClosestNonHolidayTimestampInFuture($tmpExpeditionTimestampnull);
  987.     }
  988.     /**
  989.      * @param string $cutTimeString
  990.      * @param int $supplierId
  991.      * @param int $supplierAdditionalDaysDelay
  992.      * @param int|null $timestampToCompare
  993.      *
  994.      * @return int
  995.      *
  996.      * @throws Exception Calculates expedition timestamp taking into account:
  997.      *                   1. Customer specific delays (Ex: Workhuman 3 hour delay)
  998.      *                   2. Whether cut time has passed or not
  999.      *                   3. Supplier specific delays
  1000.      *                   4. Skip holidays and weekends
  1001.      *
  1002.      * Accepts a $timestampToCompare argument that will be returned if its greater than the value calculated by the function
  1003.      */
  1004.     private static function calculateExpeditionTimestamp(
  1005.         ?int $customerId,
  1006.         string $cutTimeString,
  1007.         int $supplierId,
  1008.         int $supplierAdditionalDaysDelay,
  1009.         ?int $timestampToCompare,
  1010.         bool $includeSupplierHolidays
  1011.     ): int {
  1012.         $datetimeHelper = new DatetimeHelper();
  1013.         $currentTimestamp $datetimeHelper->getCurrentTimestamp();
  1014.         // Init to current timestamp
  1015.         $tmpExpeditionTimestamp $currentTimestamp;
  1016.         // Apply customer-defined delay
  1017.         if (!empty($customerId)) {
  1018.             $tmpExpeditionTimestamp self::addCustomerSpecificDelay($tmpExpeditionTimestamp$customerId);
  1019.         }
  1020.         // If the temporary expedition timestamp exceeds the cut time, add a day
  1021.         if (self::timestampExceedsCutTime($tmpExpeditionTimestamp$cutTimeString)) {
  1022.             $tmpExpeditionTimestamp $tmpExpeditionTimestamp DatetimeHelper::SECONDS_A_DAY;
  1023.         }
  1024.         // if $tmpExpeditionTimestamp is not a working day, get closest one
  1025.         $closestNonHolidayTimestampInFuture Tools::getClosestNonHolidayTimestampInFuture($tmpExpeditionTimestamp$includeSupplierHolidays $supplierId null0);
  1026.         // Add as many more days as 'expedition_days' value and get closest working day again
  1027.         if ($supplierAdditionalDaysDelay 0) {
  1028.             $closestNonHolidayTimestampInFuture Tools::getClosestNonHolidayTimestampInFuture($tmpExpeditionTimestamp$includeSupplierHolidays $supplierId null$supplierAdditionalDaysDelay);
  1029.         }
  1030.         if ($timestampToCompare $closestNonHolidayTimestampInFuture) {
  1031.             return $timestampToCompare;
  1032.         }
  1033.         return $closestNonHolidayTimestampInFuture;
  1034.     }
  1035.     public static function replaceByAbsoluteURL($matches)
  1036.     {
  1037.         if (array_key_exists(1$matches) && array_key_exists(2$matches)) {
  1038.             if (!preg_match('/^(?:https?:)?\/\//iUs'$matches[2])) {
  1039.                 return $matches[1].BASE_URL.'public/css/'.$matches[2];
  1040.             }
  1041.             return $matches[0];
  1042.         }
  1043.         return false;
  1044.     }
  1045.     /**
  1046.      * @param int $tmpExpeditionTimestamp
  1047.      * @param string $cutTimeString
  1048.      *
  1049.      * @return bool
  1050.      */
  1051.     private static function timestampExceedsCutTime(int $tmpExpeditionTimestampstring $cutTimeString): bool
  1052.     {
  1053.         $datetimeHelper = new DatetimeHelper();
  1054.         $tmpDatetime $datetimeHelper->getDatetimeFromTimestamp($tmpExpeditionTimestamp);
  1055.         $cutTimeComponents explode(':'$cutTimeString);
  1056.         $cutTimeHours = (int)trim($cutTimeComponents[0]);
  1057.         $cutTimeMinutes = (int)trim($cutTimeComponents[1]);
  1058.         $cutTimeSeconds = (int)trim($cutTimeComponents[2]);
  1059.         $cutDatetime $datetimeHelper->getCurrentDateTime()->setTime($cutTimeHours$cutTimeMinutes$cutTimeSeconds);
  1060.         return $tmpDatetime $cutDatetime;
  1061.     }
  1062.     /**
  1063.      * Recuperamos los indentificadores de las tiendas disponibles para contratar
  1064.      *
  1065.      * @return array Listado de tiendas de servicios
  1066.      */
  1067.     public static function getProductsShopsList()
  1068.     {
  1069.         return array_merge(\App\Entity\System\Product::SHOP_360_PRODUCTS, \App\Entity\System\Product::SHOPIFY_PRODUCTS);
  1070.     }
  1071.     /**
  1072.      * Retorna la lista de identificadores de los conectores
  1073.      *
  1074.      * @return array Listado de identificadores conectores
  1075.      */
  1076.     public static function getProductsConectorsList()
  1077.     {
  1078.         $serviceIds = [];
  1079.         $availableServices = \App\Entity\System\ServiceProduct::MIP_ADDITIONAL_SERVICE_DATA_INDEXED_BY_NAME;
  1080.         foreach ($availableServices as $availableService) {
  1081.             $serviceIds[] = $availableService['id'];
  1082.         }
  1083.         return $serviceIds;
  1084.     }
  1085.     /**
  1086.      * Retornamos un array con la lista de todos los productos tienda disponibles
  1087.      *
  1088.      * @return array Listado de productos tienda
  1089.      */
  1090.     public static function getProductShopListArray()
  1091.     {
  1092.         $prestashopList explode(','Configuration::get('ID_SHOPS'));
  1093.         return array_merge(\App\Entity\System\Product::SHOPIFY_PRODUCTS$prestashopList);
  1094.     }
  1095.     public static function getPayPalSpecificError($idPayPalError, ?bool $urlPassVirtual)
  1096.     {
  1097.         $url Link::getFrontLink('cart/checkout');
  1098.         if ($urlPassVirtual) {
  1099.             $url Link::getFrontLink('subscription/checkout');
  1100.         }
  1101.         $defaultMessage sprintf(
  1102.             self::l('Ha habido un fallo en la transacción. Inténtelo de nuevo haciendo clic %saquí%s o bien elija un método de pago alternativo.''Tools'),
  1103.             '<a href="'.$url.'" class="link color-blue">',
  1104.             '</a>'
  1105.         ).'<br><br>'.
  1106.             self::l('Si el fallo persiste, no dude en contactarnos para que podamos ayudarle.''Tools');
  1107.         $messageErrorTmp = [
  1108.             '10417' => self::l('Ha habido un fallo de pago. A continuación, le indicamos posibles soluciones, revíselas:''Tools').
  1109.                 '<ul class="orderMsg-text">'.
  1110.                 '<li>'.self::l('Si tiene asociada una tarjeta de crédito a PayPal como fuente de financiación, revise si ha caducado. Si es el caso, renuévela.''Tools').'</li>'.
  1111.                 '<li>'.self::l('El cargo que intenta realizar con PayPal es posible que supere el límite de su tarjeta de crédito. Si es así, amplíe ese límite.''Tools').'</li>'.
  1112.                 '<li>'.self::l('Si está realizando la compra de un pack más servicios adicionales, intente realizar la compra en 2 pasos. Primero active el pack y una vez tenga el pack activo vuelva a comprar los servicios adicionales.''Tools').'</li>'.
  1113.                 '<li>'.self::l('Para evitar problemas con su tarjeta de crédito, puede asociar una cuenta bancaria como fuente de financiación de PayPal.''Tools').'</li>'.
  1114.                 '<li>'.sprintf(self::l('Si tiene problemas con su tarjeta de crédito o para asociar un nuevo método de pago, contacte con PayPal aquí.''Tools'), '<a href="http://www.paypal.com/contactus" target="_blank" class="link color-blue">''</a>').'</li>'.
  1115.                 '<li>'.self::l('Si no ha conseguido solucionar los problemas con su cuenta de PayPal, puede utilizar un método de pago alternativo. Vuelva a hacer la compra.''Tools').'</li>'.
  1116.                 '<li>'.self::l('Si con estas indicaciones sigue teniendo problemas para realizar el pago, no dude en contactarnos para que podamos ayudarle.''Tools').'</li>'.
  1117.                 '</ul>',
  1118.             '10474' => self::l('El método de pago PayPal no está disponible en el país de envío. Elija un método de pago alternativo para finalizar la compra.''Tools'),
  1119.             '10486' => self::l('Ha habido un fallo de pago. A continuación, le indicamos posibles soluciones, revíselas:''Tools').
  1120.                 '<ul class="orderMsg-text">'.
  1121.                 '<li>'.self::l('Si tiene asociada una tarjeta de crédito a PayPal como fuente de financiación, revise si ha caducado. Si es el caso, renuévela.''Tools').'</li>'.
  1122.                 '<li>'.self::l('El cargo que intenta realizar con PayPal es posible que supere el límite de su tarjeta de crédito. Si es así, amplíe ese límite.''Tools').'</li>'.
  1123.                 '<li>'.self::l('Si está realizando la compra de un pack más servicios adicionales, intente realizar la compra en 2 pasos. Primero active el pack y una vez tenga el pack activo vuelva a comprar los servicios adicionales.''Tools').'</li>'.
  1124.                 '<li>'.self::l('Para evitar problemas con su tarjeta de crédito, puede asociar una cuenta bancaria como fuente de financiación de PayPal.''Tools').'</li>'.
  1125.                 '<li>'.sprintf(self::l('Si tiene problemas con su tarjeta de crédito o para asociar un nuevo método de pago, contacte con PayPal aquí.''Tools'), '<a href="http://www.paypal.com/contactus" target="_blank" class="link color-blue">''</a>').'</li>'.
  1126.                 '<li>'.self::l('Si no ha conseguido solucionar los problemas con su cuenta de PayPal, puede utilizar un método de pago alternativo. Vuelva a hacer la compra.''Tools').'</li>'.
  1127.                 '<li>'.self::l('Si con estas indicaciones sigue teniendo problemas para realizar el pago, no dude en contactarnos para que podamos ayudarle.''Tools').'</li>'.
  1128.                 '</ul>',
  1129.             '10411' => self::l('La sesión ha expirado. Haga de nuevo la compra haciendo clic aquí.''Tools'),
  1130.         ];
  1131.         $msgIdPayPalError '<p class="orderMsg-text"><strong>Id PayPal error: </strong>'.$idPayPalError.'</p>';
  1132.         if (empty($messageErrorTmp[$idPayPalError])) {
  1133.             return $defaultMessage.$msgIdPayPalError;
  1134.         }
  1135.         return $messageErrorTmp[$idPayPalError].$msgIdPayPalError;
  1136.     }
  1137.     public static function getPackName($packName$subscriptionName '')
  1138.     {
  1139.         if ($packName == $subscriptionName) {
  1140.             return $subscriptionName;
  1141.         }
  1142.         return $packName.' '.$subscriptionName;
  1143.     }
  1144.     public static function getDateExpeditionTime(int $customerId$productList)
  1145.     {
  1146.         $dateTmp 0;
  1147.         foreach ($productList as $product) {
  1148.             $dateExpeditionTmp Tools::getExpeditionTimestampBySupplier($customerId$product['id_supplier'], $dateTmp, (int)$product['quantity_stock_supplier_3_5'] === 1);
  1149.             if ($dateExpeditionTmp $dateTmp) {
  1150.                 $dateTmp $dateExpeditionTmp;
  1151.             }
  1152.         }
  1153.         return $dateTmp;
  1154.     }
  1155.     public static function getGenericServerError($errorCode)
  1156.     {
  1157.         return sprintf(
  1158.             self::l('Ha habido una incidencia y no ha podido completarse su pedido. Vaya a la sección %sContacto > Soporte técnico%s, seleccione Web BigBuy e indíquenos el código de la incidencia %s para poder ayudarle.''subscriptionController'),
  1159.             '<a href="'.Link::getFrontLink('contact#tabpanel3').'" class="link color-blue">',
  1160.             '</a>',
  1161.             $errorCode
  1162.         );
  1163.     }
  1164.     /**
  1165.      * Clean Url of <script> tags
  1166.      * This method use HTMLPurifier lib from composer
  1167.      *
  1168.      * @param string $url
  1169.      */
  1170.     public static function htmlPurifier($url): string
  1171.     {
  1172.         $config HTMLPurifier_Config::createDefault();
  1173.         $config->set('Cache.DefinitionImpl'null);
  1174.         $purifier = new HTMLPurifier($config);
  1175.         $newParam $purifier->purify($url); // this convert
  1176.         $searchParams = ['&lt;script&gt;''&lt;/script&gt;'];
  1177.         $replaceParams '';
  1178.         $newParam str_ireplace($searchParams$replaceParams$newParam);
  1179.         $newParam trim($newParam);
  1180.         return $newParam;
  1181.     }
  1182.     public static function getPriceToCheckout($productId)
  1183.     {
  1184.         $product = new Product($productId);
  1185.         return (int)$product->getWholesale_price();
  1186.     }
  1187.     public static function getResultsElasticSearch($lang$init$limit$ajax$filters$isWholeSaler$searchText null)
  1188.     {
  1189.         $customerId Session::get('id_customer');
  1190.         $filters['catalogs'] = Session::get(SessionService::ALLOWED_CATALOGS_KEY);
  1191.         if (empty($customerId)) {
  1192.             $customerId null;
  1193.         }
  1194.         if (isset($filters['rangeStock']) && is_array($filters['rangeStock'])) {
  1195.             $minStock $filters['rangeStock'][0] ?? 0;
  1196.             if (!\is_numeric($minStock)) {
  1197.                 $minStock 0;
  1198.             }
  1199.             $maxStock $filters['rangeStock'][1] ?? $minStock 1000;
  1200.             if (!\is_numeric($maxStock)) {
  1201.                 $maxStock $minStock 1000;
  1202.             }
  1203.             $filters['minStock'] = $minStock;
  1204.             $filters['maxStock'] = $maxStock;
  1205.         }
  1206.         if (isset($filters['category']) && is_array($filters['category'])) {
  1207.             $filters['taxonomy'] = [];
  1208.             foreach ($filters['category'] as $categoryId) {
  1209.                 $filters['taxonomy'][] = $categoryId;
  1210.             }
  1211.             unset($filters['category']);
  1212.         }
  1213.         // TODO comprobar si esta definida la sesion
  1214.         if (empty(Session::get('list_products_rand_seed'))) {
  1215.             $randSeed rand(1MAX_RANDOM_SEED);
  1216.             Session::set('list_products_rand_seed'$randSeed);
  1217.         }
  1218.         $randOrderingSeed null;
  1219.         if (isset($filters['order'])) {
  1220.             if ((\is_array($filters['order']) && (int)$filters['order'][0] === 6)
  1221.                 || (int)$filters['order'] === 6) {
  1222.                 if (!isset($filters['randOrderingSeed'])) {
  1223.                     // If user selected "Selección BigBuy" we use a fixed seed so pagination won't repeat results
  1224.                     $randOrderingSeed Session::get('list_products_rand_seed');
  1225.                 } else {
  1226.                     // True randomness
  1227.                     $randOrderingSeed $filters['randOrderingSeed'];
  1228.                 }
  1229.             }
  1230.         }
  1231.         $factory self::getSfService(\App\Factory\Search\FindProductsRequestFactory::class);
  1232.         $findProductsRequest $factory->buildFromWebProductListsCriteria(
  1233.             $customerId,
  1234.             $lang,
  1235.             $init,
  1236.             $limit,
  1237.             $ajax,
  1238.             $filters,
  1239.             (bool)$isWholeSaler,
  1240.             self::getRealIP(),
  1241.             $searchText,
  1242.             $randOrderingSeed
  1243.         );
  1244.         $productRepositoryAdapter self::getSfService(ProductRepositoryAdapter::class);
  1245.         return  $productRepositoryAdapter->search($findProductsRequest);
  1246.     }
  1247.     /**
  1248.      * @template T
  1249.      *
  1250.      * @param class-string<T> $serviceFqn
  1251.      *
  1252.      * @return T
  1253.      */
  1254.     public static function getSfService(string $serviceFqn)
  1255.     {
  1256.         /** @var ContainerInterface $container */
  1257.         $container $GLOBALS['kernel']->getContainer();
  1258.         return $container->get($serviceFqn);
  1259.     }
  1260.     public static function getSfParameter(string $parameterName)
  1261.     {
  1262.         /** @var ContainerInterface $container */
  1263.         $container $GLOBALS['kernel']->getContainer();
  1264.         return $container->getParameter($parameterName);
  1265.     }
  1266.     /**
  1267.      * @throws Exception
  1268.      */
  1269.     public static function getExpeditionDateTextForAvailableStock(?int $customerId$supplierId$languageId): string
  1270.     {
  1271.         $expeditionTimestamp self::getExpeditionTimestampByDefault($customerId$supplierId);
  1272.         /** @var \App\Application\Service\Helper\ShippingDateService $shippingDateService */
  1273.         $shippingDateService self::getSfService(ShippingDateService::class);
  1274.         return $shippingDateService->getBuyItNowAndWeSendItOnDateText($expeditionTimestampfalse$languageId);
  1275.     }
  1276.     /**
  1277.      * @throws Exception
  1278.      */
  1279.     public static function getExpeditionDateTextForSupplierStock($customerId$idSupplier$dateToCompare$stockSupplier_3_5$languageId): string
  1280.     {
  1281.         $expeditionTimestamp self::getExpeditionTimestampBySupplier($customerId$idSupplier$dateToCompare$stockSupplier_3_5);
  1282.         $shippingDateService self::getSfService(ShippingDateService::class);
  1283.         return $shippingDateService->getBuyItNowAndWeSendItOnDateText($expeditionTimestampfalse$languageId);
  1284.     }
  1285.     /**
  1286.      * @param string $data
  1287.      *
  1288.      * @return string|null
  1289.      */
  1290.     public static function cleanNonPrintableCharacters(string $data): ?string
  1291.     {
  1292.         return preg_replace('/[[:^print:]]/'''$data);
  1293.     }
  1294.     /**
  1295.      * @deprecated use Symfony translator instead
  1296.      */
  1297.     public static function trans(string $key, ?array $parameters = [], ?string $domain 'messages'): ?string
  1298.     {
  1299.         return Tools::getSfService('translator')->trans($key$parameters$domain);
  1300.     }
  1301.     public static function getDaysBetweenTwoDates(?string $initialDateStringstring $finalDateString): int
  1302.     {
  1303.         $initialDate date($initialDateString);
  1304.         $finalDate date($finalDateString);
  1305.         $initialSeconds strtotime($initialDate);
  1306.         $finalSeconds strtotime($finalDate);
  1307.         return ($finalSeconds $initialSeconds) / self::SECONDS_BY_DAY;
  1308.     }
  1309.     public static function displayIban(string $iban)
  1310.     {
  1311.         return self::substr($iban04).' ****** '.self::substr($iban, -44);
  1312.     }
  1313.     /**
  1314.      * @param int $tmpExpeditionTimestamp
  1315.      * @param int $customerId
  1316.      * @return float|int
  1317.      */
  1318.     protected static function addCustomerSpecificDelay(int $tmpExpeditionTimestampint $customerId): int
  1319.     {
  1320.         // If customer order confirmation delay exists, add to the timestamp
  1321.         $customerManager self::getSfService(CustomerManager::class);
  1322.         $customer $customerManager->findOneById($customerId);
  1323.         if (!empty($customer->getOrderConfirmationDelay())) {
  1324.             $tmpExpeditionTimestamp $tmpExpeditionTimestamp + ($customer->getOrderConfirmationDelay() * DatetimeHelper::SECONDS_AN_HOUR);
  1325.         }
  1326.         return $tmpExpeditionTimestamp;
  1327.     }
  1328. }