bb-legacy/app/Tools.php line 1568

Open in your IDE?
  1. <?php
  2. /** @noinspection PhpUndefinedFieldInspection */
  3. use App\Application\Service\Customer\CustomerExpeditionTimeService;
  4. use App\Application\Service\Helper\DatetimeHelper;
  5. use App\Application\Service\Helper\ShippingDateService;
  6. use App\Application\Service\Session\SessionService;
  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.      * @param string $date La fecha a convertir
  220.      * @param bool $full Si el formato de la fecha debe retornar horas o no
  221.      * @param string $format Formato de la fecha personalizado
  222.      *
  223.      * @return string La fecha convertida
  224.      */
  225.     public static function displayDate($date$full false$date_format false$plus_gmt_offset true)
  226.     {
  227.         if (!$date || !($time strtotime($date))) {
  228.             return $date;
  229.         }
  230.         if ($date == '0000-00-00 00:00:00' || $date == '0000-00-00') {
  231.             return '';
  232.         }
  233.         if (!Validate::isDate($date) || !Validate::isBool($full)) {
  234.             Tools::addError('Invalid date');
  235.         }
  236.         if (!$date_format) {
  237.             $date_format = ($full Session::get('date_format_full') : Session::get('date_format_lite'));
  238.         }
  239.         if ($plus_gmt_offset) {
  240.             return date($date_format$time Session::get('gmt_offset'));
  241.         } else {
  242.             return date($date_format$time);
  243.         }
  244.     }
  245.     /**
  246.      * Retorna una fecha con formato compatible con Mysql
  247.      *
  248.      * @param type $date Fecha a convertir
  249.      * @param type $dateFormat Formato para Mysql
  250.      *
  251.      * @return type Fecha formateada
  252.      */
  253.     public static function displayDateMysql($date$dateFormat 'Y-m-d H:i:s')
  254.     {
  255.         $date str_replace('/''.'$date);
  256.         $dateMysql date($dateFormatstrtotime($date));
  257.         return $dateMysql;
  258.     }
  259.     public static function getWeekDays()
  260.     {
  261.         return [
  262.             self::l('Domingo''Tools'),
  263.             self::l('Lunes''Tools'),
  264.             self::l('Martes''Tools'),
  265.             self::l('Miércoles''Tools'),
  266.             self::l('Jueves''Tools'),
  267.             self::l('Viernes''Tools'),
  268.             self::l('Sábado''Tools'),
  269.         ];
  270.     }
  271.     public static function getMonths()
  272.     {
  273.         return [
  274.             self::l('Enero''Tools'),
  275.             self::l('Febrero''Tools'),
  276.             self::l('Marzo''Tools'),
  277.             self::l('Abril''Tools'),
  278.             self::l('Mayo''Tools'),
  279.             self::l('Junio''Tools'),
  280.             self::l('Julio''Tools'),
  281.             self::l('Agosto''Tools'),
  282.             self::l('Septiembre''Tools'),
  283.             self::l('Octubre''Tools'),
  284.             self::l('Noviembre''Tools'),
  285.             self::l('Diciembre''Tools'),
  286.         ];
  287.     }
  288.     public static function displayTextDate($date)
  289.     {
  290.         $year date('Y'$date);
  291.         $month = (int)date('m'$date);
  292.         $day date('d'$date);
  293.         $week_day date('w'$date);
  294.         $week_days Tools::getWeekDays();
  295.         $months Tools::getMonths();
  296.         return $week_days[$week_day].', '.$day.' de '.$months[$month].' de '.$year;
  297.     }
  298.     public static function displayTextMonth($monthsNumber)
  299.     {
  300.         $months Tools::getMonths();
  301.         return $months[$monthsNumber 1];
  302.     }
  303.     /**
  304.      * Return price with currency sign for a given product
  305.      *
  306.      * @param float $price Product price
  307.      *
  308.      * @return string Price correctly formated (sign, decimal separator...)
  309.      */
  310.     public static function displayPrice($price$show_currency true$decimal 2$no_utf8 false)
  311.     {
  312.         if (!is_numeric($price)) {
  313.             return $price;
  314.         }
  315.         $c_char '';
  316.         $blank '';
  317.         if ($show_currency) {
  318.             $c_char '€';
  319.             $blank ' ';
  320.         }
  321.         $c_format Session::get('currency_format');
  322.         $c_decimals $decimal;
  323.         $ret 0;
  324.         if ($is_negative = ($price 0)) {
  325.             $price *= -1;
  326.         }
  327.         $price Tools::ps_round($price$c_decimals);
  328.         switch ($c_format) {
  329.             /* 0.000,00 X */
  330.             case 1:
  331.                 $ret number_format($price$c_decimals',''.').$blank.$c_char;
  332.                 break;
  333.                 /* X 0,000.00 X */
  334.             case 2:
  335.                 $ret $c_char.number_format($price$c_decimals'.'',');
  336.                 break;
  337.         }
  338.         if ($is_negative) {
  339.             $ret '-'.$ret;
  340.         }
  341.         if ($no_utf8) {
  342.             return str_replace('€'chr(128), $ret);
  343.         }
  344.         return $ret;
  345.     }
  346.     /**
  347.      * Return price with currency sign for a given product
  348.      *
  349.      * @param float $price Product price
  350.      *
  351.      * @return string Price correctly formated (sign, decimal separator...)
  352.      */
  353.     public static function displayNumber($number$decimal 2)
  354.     {
  355.         if (!is_numeric($number)) {
  356.             return $number;
  357.         }
  358.         $c_format Session::get('currency_format');
  359.         $c_decimals $decimal;
  360.         $ret 0;
  361.         if ($is_negative = ($number 0)) {
  362.             $number *= -1;
  363.         }
  364.         $number Tools::ps_round($number$c_decimals);
  365.         switch ($c_format) {
  366.             /* 0.000,00 */
  367.             case 1:
  368.                 $ret number_format($number$c_decimals',''.');
  369.                 break;
  370.                 /* 0,000.00 */
  371.             case 2:
  372.                 $ret number_format($number$c_decimals'.'',');
  373.                 break;
  374.         }
  375.         if ($is_negative) {
  376.             $ret '-'.$ret;
  377.         }
  378.         return $ret;
  379.     }
  380.     public static function strtolower($str)
  381.     {
  382.         if (is_array($str)) {
  383.             return false;
  384.         }
  385.         if (function_exists('mb_strtolower')) {
  386.             return mb_strtolower($str'utf-8');
  387.         }
  388.         return strtolower($str);
  389.     }
  390.     public static function substr($str$start$length false$encoding 'utf-8')
  391.     {
  392.         if (is_array($str)) {
  393.             return false;
  394.         }
  395.         if (function_exists('mb_substr')) {
  396.             return mb_substr($str, (int)$start$length === false Tools::strlen($str) : (int)$length$encoding);
  397.         }
  398.         return substr($str$start$length === false Tools::strlen($str) : (int)$length);
  399.     }
  400.     /**
  401.      * Comprobamos un VAT Number
  402.      *
  403.      * @param string $vatid VAT Number a validar
  404.      * @param string $cc codigo ISO del pais
  405.      * @param int $idCustomer Identificador del usuario
  406.      *
  407.      * @return bool
  408.      * @deprecated use TaxService::isValidVies() instead
  409.      */
  410.     public static function checkVATNumber($vatid$cc$idCustomer)
  411.     {
  412.         if (!$vatid || !$cc) {
  413.             return false;
  414.         }
  415.         $taxService self::getSfService(TaxService::class);
  416.         return $taxService->isValidVies($idCustomer$vatid$cc);
  417.     }
  418.     /**
  419.      * returns the rounded value of $value to specified precision, according to your configuration;
  420.      *
  421.      * @note : PHP 5.3.0 introduce a 3rd parameter mode in round function
  422.      *
  423.      * @param float $value
  424.      * @param int $precision
  425.      *
  426.      * @return float
  427.      *
  428.      * @deprecated use round() instead
  429.      */
  430.     public static function ps_round($value$precision 0)
  431.     {
  432.         return round($value$precision);
  433.     }
  434.     public static function getBreadcrumbData($taxonomyId$addSections = [], $idLang null)
  435.     {
  436.         if (!$idLang) {
  437.             $idLang Session::get('id_lang');
  438.         }
  439.         $parentTaxonomies Taxonomy::getParentsTaxonomy($taxonomyId$idLang);
  440.         if (!$parentTaxonomies) {
  441.             return [];
  442.         }
  443.         $sections = [];
  444.         $taxonomy array_shift($parentTaxonomies);
  445.         $link Link::getTaxonomyLink($taxonomy->getId(), $idLang); // str_replace(".html", "/", $taxonomy->getLink());
  446.         $name Taxonomy::getTaxonomyName($taxonomy->getId(), $idLang);
  447.         $sections[] = ['link' => $link'name' => $name];
  448.         foreach ($parentTaxonomies as $parentTaxonomy) {
  449.             $link Link::getTaxonomyLink($parentTaxonomy->getId(), $idLang);
  450.             $name Taxonomy::getTaxonomyName($parentTaxonomy->getId(), $idLang);
  451.             $sections[] = ['link' => $link'name' => $name];
  452.         }
  453.         if (count($addSections) > 0) {
  454.             foreach ($addSections as $section) {
  455.                 $sections[] = $section;
  456.             }
  457.         }
  458.         return $sections;
  459.     }
  460.     public static function getRealIP()
  461.     {
  462.         if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
  463.             return $_SERVER['HTTP_CLIENT_IP'];
  464.         }
  465.         // TODO quitar este if y descomentar las líneas
  466.         if (!empty($_SERVER['REMOTE_ADDR'])) {
  467.             return $_SERVER['REMOTE_ADDR'];
  468.         }
  469.         // if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
  470.         return $_SERVER['HTTP_X_FORWARDED_FOR'];
  471.         // return $_SERVER['REMOTE_ADDR'];
  472.     }
  473.     public static function getCoordsIP()
  474.     {
  475.         // Obtenemos localización del usuario por su ip
  476.         $ip Tools::getRealIP();
  477.         // $ip = '88.0.57.88';
  478.         $url 'http://www.geoplugin.net/php.gp?ip='.$ip// echo $url;
  479.         $datos = @unserialize(file_get_contents($url));
  480.         $resp = [];
  481.         if ($datos) {
  482.             // $iso_code = $datos['geoplugin_countryCode'];
  483.             // $city = $datos['geoplugin_city'];
  484.             $resp['latitud'] = (isset($datos['geoplugin_latitude'])) ? $datos['geoplugin_latitude'] : '';
  485.             $resp['longitud'] = (isset($datos['geoplugin_longitude'])) ? $datos['geoplugin_longitude'] : '';
  486.             $resp['country_code'] = (isset($datos['geoplugin_countryCode'])) ? $datos['geoplugin_countryCode'] : '';
  487.             $resp['geoplugin_request'] = (isset($datos['geoplugin_request'])) ? $datos['geoplugin_request'] : '';
  488.         } else {
  489.             $resp['latitud'] = '';
  490.             $resp['longitud'] = '';
  491.             $resp['country_code'] = '';
  492.             $resp['geoplugin_request'] = '';
  493.         }
  494.         return $resp;
  495.     }
  496.     /**
  497.      * Modifies a string to remove all non ASCII characters and spaces.
  498.      */
  499.     public static function slugify($text)
  500.     {
  501.         // replace non letter or digits by -
  502.         $text preg_replace('~[^\\pL\d]+~u''-'$text);
  503.         // trim
  504.         $text trim($text'-');
  505.         // transliterate
  506.         if (function_exists('iconv')) {
  507.             $text iconv('utf-8''us-ascii//TRANSLIT'$text);
  508.         }
  509.         // lowercase
  510.         $text strtolower($text);
  511.         // remove unwanted characters
  512.         $text preg_replace('~[^-\w]+~'''$text);
  513.         if (empty($text)) {
  514.             return 'n-a';
  515.         }
  516.         return $text;
  517.     }
  518.     public static function httpPost($url$params$return_http_code false$follow false$sslVerification true)
  519.     {
  520.         $postData '';
  521.         if (!empty($params)) {
  522.             $postData http_build_query($params);
  523.         }
  524.         $ch curl_init();
  525.         curl_setopt($chCURLOPT_URL$url);
  526.         curl_setopt($chCURLOPT_RETURNTRANSFERtrue);
  527.         curl_setopt($chCURLOPT_HEADERfalse);
  528.         // NO VERIFICAR SSL SI ESTAMOS EN MODO DESARROLLO
  529.         if (Tools::getSfService(\App\Service\EnvironmentService::class)->isDev() || !$sslVerification) {
  530.             curl_setopt($chCURLOPT_SSL_VERIFYHOSTfalse);
  531.             curl_setopt($chCURLOPT_SSL_VERIFYPEERfalse);
  532.         }
  533.         if (!empty($params)) {
  534.             curl_setopt($chCURLOPT_POSTis_array($postData) && count($postData) ? true false);
  535.             curl_setopt($chCURLOPT_POSTFIELDS$postData);
  536.         }
  537.         if ($follow) {
  538.             curl_setopt($chCURLOPT_FOLLOWLOCATIONtrue);
  539.         }
  540.         //        DESCOMENTAR PARA DEPURAR LLAMADAS CURL DESDE NETBEANS
  541.         //        curl_setopt($ch, CURLOPT_COOKIE,"XDEBUG_SESSION=netbeans-xdebug");
  542.         $output curl_exec($ch);
  543.         if ($output == false) {
  544.             $output curl_error($ch);
  545.         }
  546.         // DEVOLVEMOS EL CODIGO HTTP (404, 500, 200...)
  547.         if ($return_http_code) {
  548.             $output curl_getinfo($chCURLINFO_HTTP_CODE);
  549.         }
  550.         curl_close($ch);
  551.         return $output;
  552.     }
  553.     /**
  554.      * Truncate strings
  555.      *
  556.      * @param string $str
  557.      * @param int $max_length Max length
  558.      * @param string $suffix Suffix optional
  559.      *
  560.      * @return string $str truncated
  561.      */
  562.     /* CAUTION : Use it only on module hookEvents.
  563.      * * For other purposes use the smarty function instead */
  564.     public static function truncate($str$max_length$suffix '...')
  565.     {
  566.         if (Tools::strlen($str) <= $max_length) {
  567.             return $str;
  568.         }
  569.         $str utf8_decode($str);
  570.         return utf8_encode(substr($str0$max_length Tools::strlen($suffix)).$suffix);
  571.     }
  572.     public static function getDefaultIndexContent()
  573.     {
  574.         return '<?php
  575. /*
  576. * BLOQUEAR ACCESO A LAS CARPETAS
  577. */
  578. header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
  579. header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
  580. header("Cache-Control: no-store, no-cache, must-revalidate");
  581. header("Cache-Control: post-check=0, pre-check=0", false);
  582. header("Pragma: no-cache");
  583. header("Location: ../");
  584. exit;
  585. ';
  586.     }
  587.     public static function isMobile()
  588.     {// return true;
  589.         if (defined('IS_MOBILE')) {
  590.             return IS_MOBILE;
  591.         }
  592.         return false;
  593.     }
  594.     public static function getPassword()
  595.     {
  596.         // Se define una cadena de caractares. Te recomiendo que uses esta.
  597.         $cadena 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
  598.         // Obtenemos la longitud de la cadena de caracteres
  599.         $longitudCadena strlen($cadena);
  600.         // Se define la variable que va a contener la contraseña
  601.         $pass '';
  602.         // Se define la longitud de la contraseña, en mi caso 10, pero puedes poner la longitud que quieras
  603.         $longitudPass 10;
  604.         // Creamos la contraseña
  605.         for ($i 1$i <= $longitudPass$i++) {
  606.             // Definimos numero aleatorio entre 0 y la longitud de la cadena de caracteres-1
  607.             $pos rand(0$longitudCadena 1);
  608.             // 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.
  609.             $pass .= substr($cadena$pos1);
  610.         }
  611.         return $pass;
  612.     }
  613.     public static function getNombreMes($mes)
  614.     {
  615.         setlocale(LC_TIMESession::get('lang'));
  616.         $nombre strftime('%B'mktime(000$mes12000));
  617.         return strtoupper(substr($nombre03));
  618.     }
  619.     public static function generarCodigo($longitud)
  620.     {
  621.         $key '';
  622.         $pattern '1234567890abcdefghijklmnopqrstuvwxyz';
  623.         $max strlen($pattern) - 1;
  624.         for ($i 0$i $longitud$i++) {
  625.             $key .= $pattern[mt_rand(0$max)];
  626.         }
  627.         return $key;
  628.     }
  629.     public static function array_orderby()
  630.     {
  631.         $args func_get_args();
  632.         $data array_shift($args);
  633.         foreach ($args as $n => $field) {
  634.             if (is_string($field)) {
  635.                 $tmp = [];
  636.                 foreach ($data as $key => $row) {
  637.                     $tmp[$key] = $row[$field];
  638.                 }
  639.                 $args[$n] = $tmp;
  640.             }
  641.         }
  642.         $args[] = &$data;
  643.         call_user_func_array('array_multisort'$args);
  644.         return array_pop($args);
  645.     }
  646.     public static function dropAccents($incoming_string)
  647.     {
  648.         $tofind 'ÀÁÂÄÅàáâäÒÓÔÖòóôöÈÉÊËèéêëÇçÌÍÎÏìíîïÙÚÛÜùúûüÿÑñ';
  649.         $replac 'AAAAAaaaaOOOOooooEEEEeeeeCcIIIIiiiiUUUUuuuuyNn';
  650.         return utf8_encode(strtr(utf8_decode($incoming_string), utf8_decode($tofind), $replac));
  651.     }
  652.     public static function addPeriodToDate($frecuency$time$period)
  653.     {
  654.         $date = new DateTime($time);
  655.         $monthOld $date->format('m');
  656.         $date->modify('+'.$frecuency.' '.$period);
  657.         $monthActually $date->format('m');
  658.         if ($monthActually $monthOld) {
  659.             $monthActually += 12;
  660.         }
  661.         if ($monthActually $monthOld $frecuency) {
  662.             $date->modify('last day of -1 Month');
  663.         }
  664.         return $date->format('Y-m-d');
  665.     }
  666.     public static function calculateDaysTransit($days$productId null$extern false)
  667.     {
  668.         $syncronisedException = ($extern) ? Product::isSincronisedSendException($productId) : false;
  669.         if ($days <= 2) {
  670.             return [
  671.                 'days' => 1,
  672.                 'text_product' => self::l('%s uds.''Tools'),
  673.                 'text_cart' => (!$syncronisedException) ? self::l('Envío inmediato''Tools') : self::l('24/48h''Tools'),
  674.             ];
  675.         }
  676.         $tmpDays = (int)ceil($days 5);
  677.         switch ($tmpDays) {
  678.             case 0:
  679.             case 1:
  680.                 $days_range '2/5';
  681.                 $tmpDays 1;
  682.                 break;
  683.             case 2:
  684.                 $days_range '5/10';
  685.                 break;
  686.             case 3:
  687.                 $days_range '10/15';
  688.                 break;
  689.             case 4:
  690.                 $days_range '15/20';
  691.                 break;
  692.             default:
  693.                 $days_range '20/30';
  694.         }
  695.         return [
  696.             'days' => $tmpDays 5,
  697.             'text_product' => sprintf(self::l('%s uds. envío %s días''Tools'), '%s'$days_range),
  698.             'text_cart' => sprintf(self::l('%s días''Tools'), $days_range),
  699.         ];
  700.     }
  701.     public static function divideString($name$separador '<br />'$num_lines 2)
  702.     {
  703.         $blank_spaces ceil(substr_count($name' ') / $num_lines);
  704.         $nameEnd '';
  705.         $count_spaces 0;
  706.         $nameTmp str_split($name);
  707.         $br false;
  708.         foreach ($nameTmp as $c) {
  709.             if ($c == ' ') {
  710.                 $count_spaces++;
  711.             }
  712.             if ($count_spaces == $blank_spaces && $blank_spaces && !$br) {
  713.                 $nameEnd .= $separador;
  714.                 $br true;
  715.             } else {
  716.                 $nameEnd .= $c;
  717.             }
  718.         }
  719.         return $nameEnd;
  720.     }
  721.     public static function replaceAutomatedLinks($string_to_replace)
  722.     {
  723.         return preg_replace_callback('/##(CMS|CAT|TAXONOMY)\_(.[0-9]*)##/', function ($matches) {
  724.             switch ($matches[1]) {
  725.                 case 'CMS':
  726.                     $cms = new Cms($matches[2]);
  727.                     // RECUPERAMOS LOS DATOS QUE NECESITAMOS PARA EL LINK
  728.                     $link_rewrite = (!empty($cms->link_rewrite[Session::get('id_lang')])) ? $cms->link_rewrite[Session::get('id_lang')] : '';
  729.                     return Link::getActionLink($link_rewrite);
  730.                     break;
  731.                 case 'CAT':
  732.                     return Link::getCategoryLink($matches[2]);
  733.                 case 'TAXONOMY':
  734.                     return Link::getTaxonomyLink($matches[2]);
  735.                     break;
  736.             }
  737.         }, $string_to_replace);
  738.     }
  739.     public static function convertTable($txt$titulo '')
  740.     {
  741.         $_convertTable = [
  742.         '&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', ];
  743.         if ($txt == '') {
  744.             $txt $titulo;
  745.         }
  746.         $temp =  strtr($txt$_convertTable);
  747.         $urlKey preg_replace('#[^0-9a-z]+#i''-'$temp);
  748.         $urlKey strtolower($urlKey);
  749.         $urlKey trim($urlKey'-');
  750.         return $urlKey;
  751.     }
  752.     // Recibimos los parámetros que debemos aplicar para definir los filtros Javascript de las categorías
  753.     public static function createCategoryFilters($params)
  754.     {
  755.         /*
  756.          * Estructura
  757.          *  key => array(valor predeterminado, is_string)
  758.          */
  759.         $filters = [
  760.             'categoryId' => [''true],
  761.             'entityId' => [0false],
  762.             'categoryOffset' =>  [ViewService::MAX_CATEGORY_PRODUCTS],
  763.             'categoryLimit' =>  [ViewService::MAX_CATEGORY_PRODUCTS],
  764.             'categoryMaxPrice' => [0false],
  765.             'categoryMaxStock' => [0false],
  766.             'categoryMinStock' => [0false],
  767.             'catLink' => [''true],
  768.             'filterMobile' => [0false],
  769.             'sliderFilterInit' => [0false],
  770.             'sliderFilterEnd' => [0false],
  771.             'sliderFilterStockInit' => [0false],
  772.             'sliderFilterStockEnd' => [0false],
  773.             'urlListProducts' => [''true],
  774.         ];
  775.         $jsCode '';
  776.         foreach ($filters as $key => $value) {
  777.             $valorFinal = (empty($params[$key])) ? $value[0] : $params[$key];
  778.             if (!isset($value[1]) || $value[1] == true) {
  779.                 $jsCode .= 'var '.$key."='".$valorFinal."';";
  780.             } else {
  781.                 $jsCode .= 'var '.$key.'='.$valorFinal.';';
  782.             }
  783.         }
  784.         return $jsCode;
  785.     }
  786.     /*
  787.      * ELIMINAMOS LOS FILTROS PARA MOVIL
  788.      */
  789.     public static function remove_filters()
  790.     {
  791.         Session::delete('filters');
  792.     }
  793.     public static function convertDateToEpoch($date)
  794.     {
  795.         $tmp explode(' '$date);
  796.         $dateArray explode('-'$tmp[0]);
  797.         $hourArray explode(':'$tmp[1]);
  798.         if (empty($dateArray[1]) || empty($hourArray[2]) || empty($hourArray[1]) || empty($hourArray[2])) {
  799.             return 0;
  800.         }
  801.         $epoch mktime($hourArray[0], $hourArray[1], $hourArray[2], $dateArray[1], $dateArray[2], $dateArray[0]);
  802.         return $epoch;
  803.     }
  804.     public static function addShowRecentProduct($id_product)
  805.     {
  806.         $maxNumProductsViews Configuration::get('MAX_NUM_PRODUCTS_VIEWS'true);
  807.         $recentProductList Session::get('view_recent_products');
  808.         if (!$recentProductList) {
  809.             $recentProductList = [];
  810.             $recentProductList[$id_product] = date('Y-m-d H:i:s');
  811.             Session::set('view_recent_products'$recentProductList);
  812.             return;
  813.         }
  814.         $recentProductList[$id_product] = date('Y-m-d H:i:s');
  815.         if (count($recentProductList) > $maxNumProductsViews) {
  816.             arsort($recentProductList);
  817.             array_pop($recentProductList);
  818.         }
  819.         Session::set('view_recent_products'$recentProductList);
  820.     }
  821.     /**
  822.      * Comprobamos si el usuario tiene precio de coste para los productos
  823.      *
  824.      * @param $idCustomer Identificador del cliente
  825.      *
  826.      * @return bool|mixed Retornamos el porcentaje de descuento al precio de coste o false
  827.      */
  828.     public static function getCustomerCostPrice($customerId)
  829.     {
  830.         //TODO no borrar esta función. Aunque Nine tenga un 0% debemos aplicar ese porcentaje al precio
  831.         $customerCostList Tools::jsonDecode(Configuration::get('CUSTOMER_COST_PRICE'true), true);
  832.         if (!$customerCostList) {
  833.             return null;
  834.         }
  835.         if (!isset($customerCostList[$customerId])) {
  836.             return null;
  837.         }
  838.         return $customerCostList[$customerId];
  839.     }
  840.     /**
  841.      * Añadimos la cookie de la secure Key del carriro
  842.      */
  843.     public static function processCookieSecureKey()
  844.     {
  845.         if (empty($_COOKIE['secure_key'])) {
  846.             $secureKey uniqid(rand(09).rand(09).rand(09), true);
  847.             setcookie('secure_key'$secureKeytime() + (60 60 24 7), '/');
  848.             Session::set('secure_key'$secureKey);
  849.         }
  850.     }
  851.     /**
  852.      * @deprecated migrated to App\Service\FiscalPositionService
  853.      *
  854.      * Comprobamos si se produce una excepción para determinados paises de la UE
  855.      */
  856.     public static function reviewExceptions(string $isoCodestring $postCode): bool
  857.     {
  858.         return self::getSfService(\App\Service\FiscalPositionService::class)->reviewExceptions($isoCode$postCode);
  859.     }
  860.     public static function getCustomerName($idCustomer)
  861.     {
  862.         $customer = new Account($idCustomer);
  863.         if (!$customer->getId()) {
  864.             return '';
  865.         }
  866.         return $customer->getName().' '.$customer->getSurnames();
  867.     }
  868.     public static function getLinkAcademy($type)
  869.     {
  870.         switch ($type) {
  871.             case 'invoice':
  872.                 $text Tools::getLinkAcademyInvoice();
  873.                 break;
  874.             case 'lock_refuse':
  875.                 $text Tools::getLinkLockRefuse();
  876.                 break;
  877.             default:
  878.                 $text '';
  879.                 break;
  880.         }
  881.         return $text;
  882.     }
  883.     public static function getLinkAcademyInvoice()
  884.     {
  885.         switch (Session::get('lang')) {
  886.             case 'es':
  887.                 $link 'http://www.bigbuy.eu/academy/es/crear-una-factura-exportaciones-la-union-europea/';
  888.                 break;
  889.             case 'fr':
  890.                 $link 'http://www.bigbuy.eu/academy/fr/comment-creer-facture-exportations-dehors-lunion-europeenne/';
  891.                 break;
  892.             case 'de':
  893.                 $link 'http://www.bigbuy.eu/academy/de/so-erstellen-rechnung-exporte-ausserhalb-europaeischen-union/';
  894.                 break;
  895.             case 'it':
  896.                 $link 'http://www.bigbuy.eu/academy/it/come-emettere-fattura-esportazioni-fuori-unione-europea/';
  897.                 break;
  898.             default:
  899.                 $link 'http://www.bigbuy.eu/academy/en/how-create-invoice-exports-outside-european-union/';
  900.                 break;
  901.         }
  902.         return $link;
  903.     }
  904.     public static function getLinkLockRefuse()
  905.     {
  906.         switch (Session::get('lang')) {
  907.             case 'es':
  908.                 $link 'http://www.bigbuy.eu/academy/es/bloqueo-stock-bigbuy-como-funciona/';
  909.                 break;
  910.             case 'fr':
  911.                 $link 'http://www.bigbuy.eu/academy/fr/blocage-stock-ce-cest-et-comment-cela-fonctionne/';
  912.                 break;
  913.             case 'de':
  914.                 $link 'http://www.bigbuy.eu/academy/de/lagerbestandssperre-was-ist-und-wie-funktioniert/';
  915.                 break;
  916.             case 'it':
  917.                 $link 'http://www.bigbuy.eu/academy/it/bloccaggio-dello-stock-bigbuy-cose-e-come-funziona/';
  918.                 break;
  919.             default:
  920.                 $link 'http://www.bigbuy.eu/academy/en/stock-blocking-what-it-is-and-how-it-works/';
  921.                 break;
  922.         }
  923.         return $link;
  924.     }
  925.     /**
  926.      * @param $timestamp
  927.      * @param $supplierId
  928.      *
  929.      * @return int
  930.      */
  931.     public static function getClosestNonHolidayTimestampInFuture($timestamp$supplierId$additionalDaysToSkip 0): int
  932.     {
  933.         $dateTimeHelper = new DatetimeHelper();
  934.         $dateTime $dateTimeHelper->getDatetimeFromTimestamp($timestamp);
  935.         $weekendDays = [DatetimeHelper::SATURDAYDatetimeHelper::SUNDAY];
  936.         $dateHolidays Tools::jsonDecode(Configuration::get('HOLIDAYS'true), true);
  937.         if ($supplierId) {
  938.             /** @var SupplierHolidaysManager $supplierHolidayManager */
  939.             $supplierHolidayManager Tools::getSfService(SupplierHolidaysManager::class);
  940.             $supplierHoliday $supplierHolidayManager->findOneById((int)$supplierId);
  941.             $dateSupplierHolidays = ($supplierHoliday) ? json_decode($supplierHoliday->getHolidays(), true) : [];
  942.         }
  943.         while (true) {
  944.             $isHoliday = isset($dateHolidays[$dateTime->format('Y-m-d')]);
  945.             $isWeekend in_array($dateTime->format('w'), $weekendDays);
  946.             if ($supplierId) {
  947.                 $isHolidaySuplier in_array($dateTime->format('Y-m-d'), $dateSupplierHolidays);
  948.                 if (!$isHoliday && !$isWeekend && !$isHolidaySuplier) {
  949.                     if ($additionalDaysToSkip === 0) {
  950.                         return $dateTime->getTimestamp();
  951.                     } else {
  952.                         $additionalDaysToSkip--;
  953.                     }
  954.                 }
  955.             } else {
  956.                 if (!$isHoliday && !$isWeekend) {
  957.                     if ($additionalDaysToSkip === 0) {
  958.                         return $dateTime->getTimestamp();
  959.                     } else {
  960.                         $additionalDaysToSkip--;
  961.                     }
  962.                 }
  963.             }
  964.             $dateTime->modify('+1 day');
  965.         }
  966.     }
  967.     public static function removeTimeToStrtotime($date$time$period)
  968.     {
  969.         $newDate strtotime('-'.$time.' '.$period$date);
  970.         return $newDate;
  971.     }
  972.     /**
  973.      * @return int
  974.      *
  975.      * @throws Exception
  976.      *
  977.      * @var
  978.      */
  979.     public static function getExpeditionTimestampByDefault($supplierId): int
  980.     {
  981.         $availableStockExpeditionConfig self::jsonDecode(Configuration::get('EXPEDITION_DEFAULT_DATA'true), true);
  982.         $cutTimeString $availableStockExpeditionConfig['expedition_message_time'];
  983.         return self::calculateExpeditionTimestamp($cutTimeString$supplierId00false);
  984.     }
  985.     /**
  986.      * @param int $idSupplier
  987.      * @param int|null $timestampToCompare
  988.      *
  989.      * @return int
  990.      *
  991.      * @throws Exception
  992.      */
  993.     public static function getExpeditionTimestampBySupplier(int $idSupplier, ?int $timestampToComparebool $stock_3_5): int
  994.     {
  995.         $supplierExpeditionConfig plazo_aprovisionamiento_proveedor::getExpeditionInformation($idSupplier);
  996.         $cutTimeString $supplierExpeditionConfig['expedition_message_time'];
  997.         $expeditionAdditionalDaysDelay = (int)$supplierExpeditionConfig['expedition_days'];
  998.         if ($stock_3_5) {
  999.             $expeditionAdditionalDaysDelay = (int)$supplierExpeditionConfig['expedition_days_3_5'];
  1000.         }
  1001.         return self::calculateExpeditionTimestamp($cutTimeString$idSupplier$expeditionAdditionalDaysDelay$timestampToComparetrue);
  1002.     }
  1003.     /**
  1004.      * @param array $product
  1005.      *
  1006.      * @return int
  1007.      *
  1008.      * @throws Exception
  1009.      */
  1010.     public static function getExpeditionTimestampForFutureStock(array $product): int
  1011.     {
  1012.         $daysUntilStockWillBeHere = \stock_venideros::calculateDaysTransit($product['id_product'], $product['id_product_attribute']);
  1013.         if (!$daysUntilStockWillBeHere) {
  1014.             $daysUntilStockWillBeHere = (int)self::jsonDecode(Configuration::get('STOCK_VENIDERO_DIAS_CORTESIA'), true);
  1015.         }
  1016.         $transitDaysData self::calculateDaysTransit($daysUntilStockWillBeHere$product['id_product']);
  1017.         $datetimeHelper = new DatetimeHelper();
  1018.         $tmpExpeditionTimestamp $datetimeHelper->getCurrentTimestamp();
  1019.         // Add
  1020.         $tmpExpeditionTimestamp += $transitDaysData['days'] * DatetimeHelper::SECONDS_A_DAY;
  1021.         return self::getClosestNonHolidayTimestampInFuture($tmpExpeditionTimestampnull);
  1022.     }
  1023.     /**
  1024.      * @param string $cutTimeString
  1025.      * @param int $supplierId
  1026.      * @param int $supplierAdditionalDaysDelay
  1027.      * @param int|null $timestampToCompare
  1028.      *
  1029.      * @return int
  1030.      *
  1031.      * @throws Exception Calculates expedition timestamp taking into account:
  1032.      *                   1. Customer specific delays (Ex: Workhuman 3 hour delay)
  1033.      *                   2. Whether cut time has passed or not
  1034.      *                   3. Supplier specific delays
  1035.      *                   4. Skip holidays and weekends
  1036.      *
  1037.      * Accepts a $timestampToCompare argument that will be returned if its greater than the value calculated by the function
  1038.      */
  1039.     private static function calculateExpeditionTimestamp(
  1040.         string $cutTimeString,
  1041.         int $supplierId,
  1042.         int $supplierAdditionalDaysDelay,
  1043.         ?int $timestampToCompare,
  1044.         bool $includeSupplierHolidays
  1045.     ): int {
  1046.         $datetimeHelper = new DatetimeHelper();
  1047.         $currentTimestamp $datetimeHelper->getCurrentTimestamp();
  1048.         // Init to current timestamp
  1049.         $tmpExpeditionTimestamp $currentTimestamp;
  1050.         // If customer specific delay exists, add to the timestamp (Ex: 3 hours for Workhuman)
  1051.         /** @var CustomerExpeditionTimeService */
  1052.         $customerExpeditionTimeService self::getSfService(CustomerExpeditionTimeService::class);
  1053.         $customerExpeditionDelayInHours $customerExpeditionTimeService->getCustomCustomerExpeditionTimeDelayInHours(Session::get('id_customer'));
  1054.         if ($customerExpeditionDelayInHours 0) {
  1055.             $tmpExpeditionTimestamp $tmpExpeditionTimestamp + ($customerExpeditionDelayInHours DatetimeHelper::SECONDS_AN_HOUR);
  1056.         }
  1057.         // If the temporary expedition timestamp exceeds the cut time, add a day
  1058.         if (self::timestampExceedsCutTime($tmpExpeditionTimestamp$cutTimeString)) {
  1059.             $tmpExpeditionTimestamp $tmpExpeditionTimestamp DatetimeHelper::SECONDS_A_DAY;
  1060.         }
  1061.         // if $tmpExpeditionTimestamp is not a working day, get closest one
  1062.         $closestNonHolidayTimestampInFuture Tools::getClosestNonHolidayTimestampInFuture($tmpExpeditionTimestamp$includeSupplierHolidays $supplierId null0);
  1063.         // Add as many more days as 'expedition_days' value and get closest working day again
  1064.         if ($supplierAdditionalDaysDelay 0) {
  1065.             $closestNonHolidayTimestampInFuture Tools::getClosestNonHolidayTimestampInFuture($tmpExpeditionTimestamp$includeSupplierHolidays $supplierId null$supplierAdditionalDaysDelay);
  1066.         }
  1067.         if ($timestampToCompare $closestNonHolidayTimestampInFuture) {
  1068.             return $timestampToCompare;
  1069.         }
  1070.         return $closestNonHolidayTimestampInFuture;
  1071.     }
  1072.     public static function replaceByAbsoluteURL($matches)
  1073.     {
  1074.         if (array_key_exists(1$matches) && array_key_exists(2$matches)) {
  1075.             if (!preg_match('/^(?:https?:)?\/\//iUs'$matches[2])) {
  1076.                 return $matches[1].BASE_URL.'public/css/'.$matches[2];
  1077.             }
  1078.             return $matches[0];
  1079.         }
  1080.         return false;
  1081.     }
  1082.     /**
  1083.      * @param int $tmpExpeditionTimestamp
  1084.      * @param string $cutTimeString
  1085.      *
  1086.      * @return bool
  1087.      */
  1088.     private static function timestampExceedsCutTime(int $tmpExpeditionTimestampstring $cutTimeString): bool
  1089.     {
  1090.         $datetimeHelper = new DatetimeHelper();
  1091.         $tmpDatetime $datetimeHelper->getDatetimeFromTimestamp($tmpExpeditionTimestamp);
  1092.         $cutTimeComponents explode(':'$cutTimeString);
  1093.         $cutTimeHours = (int)trim($cutTimeComponents[0]);
  1094.         $cutTimeMinutes = (int)trim($cutTimeComponents[1]);
  1095.         $cutTimeSeconds = (int)trim($cutTimeComponents[2]);
  1096.         $cutDatetime $datetimeHelper->getCurrentDateTime()->setTime($cutTimeHours$cutTimeMinutes$cutTimeSeconds);
  1097.         return $tmpDatetime $cutDatetime;
  1098.     }
  1099.     /**
  1100.      * Recuperamos los indentificadores de las tiendas disponibles para contratar
  1101.      *
  1102.      * @return array Listado de tiendas de servicios
  1103.      */
  1104.     public static function getProductsShopsList()
  1105.     {
  1106.         $shops360 Tools::jsonDecode(Configuration::get('SHOP_360_LIST'true), true);
  1107.         $shopsShopify Tools::jsonDecode(Configuration::get('SHOPIFY_360_LIST'true), true);
  1108.         return array_merge($shops360$shopsShopify);
  1109.     }
  1110.     /**
  1111.      * Retorna la lista de identificadores de los conectores
  1112.      *
  1113.      * @return array Listado de identificadores conectores
  1114.      */
  1115.     public static function getProductsConectorsList()
  1116.     {
  1117.         $serviceIds = [];
  1118.         $availableServices = \App\Entity\System\ServiceProduct::MIP_ADDITIONAL_SERVICE_DATA_INDEXED_BY_NAME;
  1119.         foreach ($availableServices as $availableService) {
  1120.             $serviceIds[] = $availableService['id'];
  1121.         }
  1122.         return $serviceIds;
  1123.     }
  1124.     /**
  1125.      * Retornamos un array con la lista de todos los productos tienda disponibles
  1126.      *
  1127.      * @return array Listado de productos tienda
  1128.      */
  1129.     public static function getProductShopListArray()
  1130.     {
  1131.         $shopifyList Tools::jsonDecode(Configuration::get('SHOPIFY_360_LIST'), true);
  1132.         $prestashopList explode(','Configuration::get('ID_SHOPS'));
  1133.         return array_merge($shopifyList$prestashopList);
  1134.     }
  1135.     public static function getPayPalSpecificError($idPayPalError, ?bool $urlPassVirtual)
  1136.     {
  1137.         $url Link::getFrontLink('cart/checkout');
  1138.         if ($urlPassVirtual) {
  1139.             $url Link::getFrontLink('subscription/checkout');
  1140.         }
  1141.         $defaultMessage sprintf(
  1142.             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'),
  1143.             '<a href="'.$url.'" class="link color-blue">',
  1144.             '</a>'
  1145.         ).'<br><br>'.
  1146.             self::l('Si el fallo persiste, no dude en contactarnos para que podamos ayudarle.''Tools');
  1147.         $messageErrorTmp = [
  1148.             '10417' => self::l('Ha habido un fallo de pago. A continuación, le indicamos posibles soluciones, revíselas:''Tools').
  1149.                 '<ul class="orderMsg-text">'.
  1150.                 '<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>'.
  1151.                 '<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>'.
  1152.                 '<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>'.
  1153.                 '<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>'.
  1154.                 '<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>'.
  1155.                 '<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>'.
  1156.                 '<li>'.self::l('Si con estas indicaciones sigue teniendo problemas para realizar el pago, no dude en contactarnos para que podamos ayudarle.''Tools').'</li>'.
  1157.                 '</ul>',
  1158.             '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'),
  1159.             '10486' => self::l('Ha habido un fallo de pago. A continuación, le indicamos posibles soluciones, revíselas:''Tools').
  1160.                 '<ul class="orderMsg-text">'.
  1161.                 '<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>'.
  1162.                 '<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>'.
  1163.                 '<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>'.
  1164.                 '<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>'.
  1165.                 '<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>'.
  1166.                 '<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>'.
  1167.                 '<li>'.self::l('Si con estas indicaciones sigue teniendo problemas para realizar el pago, no dude en contactarnos para que podamos ayudarle.''Tools').'</li>'.
  1168.                 '</ul>',
  1169.             '10411' => self::l('La sesión ha expirado. Haga de nuevo la compra haciendo clic aquí.''Tools'),
  1170.         ];
  1171.         $msgIdPayPalError '<p class="orderMsg-text"><strong>Id PayPal error: </strong>'.$idPayPalError.'</p>';
  1172.         if (empty($messageErrorTmp[$idPayPalError])) {
  1173.             return $defaultMessage.$msgIdPayPalError;
  1174.         }
  1175.         return $messageErrorTmp[$idPayPalError].$msgIdPayPalError;
  1176.     }
  1177.     public static function getPackName($packName$subscriptionName '')
  1178.     {
  1179.         if ($packName == $subscriptionName) {
  1180.             return $subscriptionName;
  1181.         }
  1182.         return $packName.' '.$subscriptionName;
  1183.     }
  1184.     public static function getDateExpeditionTime($productList)
  1185.     {
  1186.         $dateTmp 0;
  1187.         foreach ($productList as $product) {
  1188.             $dateExpeditionTmp Tools::getExpeditionTimestampBySupplier($product['id_supplier'], $dateTmp, (int)$product['quantity_stock_supplier_3_5'] === 1);
  1189.             if ($dateExpeditionTmp $dateTmp) {
  1190.                 $dateTmp $dateExpeditionTmp;
  1191.             }
  1192.         }
  1193.         return $dateTmp;
  1194.     }
  1195.     public static function getGenericServerError($errorCode)
  1196.     {
  1197.         return sprintf(
  1198.             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'),
  1199.             '<a href="'.Link::getFrontLink('contact#tabpanel3').'" class="link color-blue">',
  1200.             '</a>',
  1201.             $errorCode
  1202.         );
  1203.     }
  1204.     /**
  1205.      * Clean Url of <script> tags
  1206.      * This method use HTMLPurifier lib from composer
  1207.      *
  1208.      * @param string $url
  1209.      */
  1210.     public static function htmlPurifier($url): string
  1211.     {
  1212.         $config HTMLPurifier_Config::createDefault();
  1213.         $config->set('Cache.DefinitionImpl'null);
  1214.         $purifier = new HTMLPurifier($config);
  1215.         $newParam $purifier->purify($url); // this convert
  1216.         $searchParams = ['&lt;script&gt;''&lt;/script&gt;'];
  1217.         $replaceParams '';
  1218.         $newParam str_ireplace($searchParams$replaceParams$newParam);
  1219.         $newParam trim($newParam);
  1220.         return $newParam;
  1221.     }
  1222.     public static function getPriceToCheckout($productId)
  1223.     {
  1224.         $product = new Product($productId);
  1225.         return (int)$product->getWholesale_price();
  1226.     }
  1227.     /**
  1228.      * @param $resOrderSync
  1229.      *
  1230.      * @return string|string[]
  1231.      */
  1232.     public static function formatResOrderSync($resOrderSync)
  1233.     {
  1234.         /**
  1235.          * TODO Aparece el caracter ZWNBSP y rompe la codificación
  1236.          * Al pasarle esa cadena a pack() da error
  1237.          *       Warning: pack(): Type H: illegal hex digit Z
  1238.          */
  1239.         // Remove BOM special chars
  1240.         $bom pack('H*''EFBBBF');
  1241.         $resOrderSync preg_replace("/^$bom/"''$resOrderSync);
  1242.         // $resOrderSync = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $resOrderSync);
  1243.         $resOrderSync str_replace('<\\/''</'$resOrderSync);
  1244.         return $resOrderSync;
  1245.     }
  1246.     public static function getResultsElasticSearch($lang$init$limit$ajax$filters$isWholeSaler$searchText null)
  1247.     {
  1248.         $customerId Session::get('id_customer');
  1249.         $filters['catalogs'] = Session::get(SessionService::ALLOWED_CATALOGS_KEY);
  1250.         if (empty($customerId)) {
  1251.             $customerId null;
  1252.         }
  1253.         if (isset($filters['rangeStock']) && is_array($filters['rangeStock'])) {
  1254.             $minStock $filters['rangeStock'][0] ?? 0;
  1255.             if (!\is_numeric($minStock)) {
  1256.                 $minStock 0;
  1257.             }
  1258.             $maxStock $filters['rangeStock'][1] ?? $minStock 1000;
  1259.             if (!\is_numeric($maxStock)) {
  1260.                 $maxStock $minStock 1000;
  1261.             }
  1262.             $filters['minStock'] = $minStock;
  1263.             $filters['maxStock'] = $maxStock;
  1264.         }
  1265.         if (isset($filters['category']) && is_array($filters['category'])) {
  1266.             $filters['taxonomy'] = [];
  1267.             foreach ($filters['category'] as $categoryId) {
  1268.                 $filters['taxonomy'][] = $categoryId;
  1269.             }
  1270.             unset($filters['category']);
  1271.         }
  1272.         // TODO comprobar si esta definida la sesion
  1273.         if (empty(Session::get('list_products_rand_seed'))) {
  1274.             $randSeed rand(1MAX_RANDOM_SEED);
  1275.             Session::set('list_products_rand_seed'$randSeed);
  1276.         }
  1277.         $randOrderingSeed null;
  1278.         if (isset($filters['order'])) {
  1279.             if ((\is_array($filters['order']) && (int)$filters['order'][0] === 6)
  1280.                 || (int)$filters['order'] === 6) {
  1281.                 if (!isset($filters['randOrderingSeed'])) {
  1282.                     // If user selected "Selección BigBuy" we use a fixed seed so pagination won't repeat results
  1283.                     $randOrderingSeed Session::get('list_products_rand_seed');
  1284.                 } else {
  1285.                     // True randomness
  1286.                     $randOrderingSeed $filters['randOrderingSeed'];
  1287.                 }
  1288.             }
  1289.         }
  1290.         $factory self::getSfService(\App\Factory\Search\FindProductsRequestFactory::class);
  1291.         $findProductsRequest $factory->buildFromWebProductListsCriteria(
  1292.             $customerId,
  1293.             $lang,
  1294.             $init,
  1295.             $limit,
  1296.             $ajax,
  1297.             $filters,
  1298.             (bool)$isWholeSaler,
  1299.             self::getRealIP(),
  1300.             $searchText,
  1301.             $randOrderingSeed
  1302.         );
  1303.         $productRepositoryAdapter self::getSfService(ProductRepositoryAdapter::class);
  1304.         return  $productRepositoryAdapter->search($findProductsRequest);
  1305.     }
  1306.     /**
  1307.      * @template T
  1308.      *
  1309.      * @param class-string<T> $serviceFqn
  1310.      *
  1311.      * @return T
  1312.      */
  1313.     public static function getSfService(string $serviceFqn)
  1314.     {
  1315.         /** @var ContainerInterface $container */
  1316.         $container $GLOBALS['kernel']->getContainer();
  1317.         return $container->get($serviceFqn);
  1318.     }
  1319.     public static function getSfParameter(string $parameterName)
  1320.     {
  1321.         /** @var ContainerInterface $container */
  1322.         $container $GLOBALS['kernel']->getContainer();
  1323.         return $container->getParameter($parameterName);
  1324.     }
  1325.     /**
  1326.      * @param $supplierId
  1327.      *
  1328.      * @return string
  1329.      *
  1330.      * @throws Exception
  1331.      */
  1332.     public static function getExpeditionDateTextForAvailableStock($supplierId): string
  1333.     {
  1334.         $expeditionTimestamp self::getExpeditionTimestampByDefault($supplierId);
  1335.         /** @var \App\Application\Service\Helper\ShippingDateService $shippingDateService */
  1336.         $shippingDateService self::getSfService(ShippingDateService::class);
  1337.         return $shippingDateService->getBuyItNowAndWeSendItOnDateText($expeditionTimestamp);
  1338.     }
  1339.     /**
  1340.      * @param $idSupplier
  1341.      *
  1342.      * @return string
  1343.      *
  1344.      * @throws Exception
  1345.      */
  1346.     public static function getExpeditionDateTextForSupplierStock($idSupplier$dateToCompare$stockSupplier_3_5): string
  1347.     {
  1348.         $expeditionTimestamp self::getExpeditionTimestampBySupplier($idSupplier$dateToCompare$stockSupplier_3_5);
  1349.         $shippingDateService self::getSfService(ShippingDateService::class);
  1350.         return $shippingDateService->getBuyItNowAndWeSendItOnDateText($expeditionTimestamp);
  1351.     }
  1352.     /**
  1353.      * @param string $data
  1354.      *
  1355.      * @return string|null
  1356.      */
  1357.     public static function cleanNonPrintableCharacters(string $data): ?string
  1358.     {
  1359.         return preg_replace('/[[:^print:]]/'''$data);
  1360.     }
  1361.     /**
  1362.      * @deprecated use Symfony translator instead
  1363.      */
  1364.     public static function trans(string $key, ?array $parameters = [], ?string $domain 'messages'): ?string
  1365.     {
  1366.         return Tools::getSfService('translator')->trans($key$parameters$domain);
  1367.     }
  1368.     public static function getDaysBetweenTwoDates(?string $initialDateStringstring $finalDateString): int
  1369.     {
  1370.         $initialDate date($initialDateString);
  1371.         $finalDate date($finalDateString);
  1372.         $initialSeconds strtotime($initialDate);
  1373.         $finalSeconds strtotime($finalDate);
  1374.         return ($finalSeconds $initialSeconds) / self::SECONDS_BY_DAY;
  1375.     }
  1376.     public static function displayIban(string $iban)
  1377.     {
  1378.         return self::substr($iban04).' ****** '.self::substr($iban, -44);
  1379.     }
  1380. }