<?php
/**
  \licence GPL 2005-2011  The osCSS developers - osCSS Open Source E-commerce
  \portion code Copyright (c) 2002 osCommerce
  \package osCSS-2 <www http://www.oscss.org>
  \version 2.1.0
  \date  25/01/11, 11:33
  \author oscim <mail aurelien@oscim.fr> <www http://www.oscim.fr>
  			ORDONEZ Olivier <mail info@olivier-ordonez.fr> <www http://www.olivier-ordonez.fr>
  \encode UTF-8
  \class  price
  \dir common/classes/
  \brief Gestion des prix

  			Voir la page price

  \page price
  \section Utilisation Utilisation class price

   \p class price \n

   \p Terminologie des fonctions :
    \li - view_* 	  => final pour affichage : fonction usel , utilise
    \li - get_*     => Récupération d'une variable brute pour calcul...
    \li - display_* => Simple traitement de données brutes...
    \li  - print_*   => Calcul et récupération de donnée et traitement en vue de leur affichage... (en Gal get + display)
    \li  - is_*      => Questionnement retour booléen obligatoire


    \p Découpage de la class :
    \li  - Fonctions de gestion du prix général
    \li  - Fonctions de gestion des promotions
    \li  - Fonctions de gestion des taxes
    \li  - Fonctions de gestion des monnaies
    \li  - Fonctions utile pour SPPC
    \li  N.B. 1: La gestion de la partie SPPC est intégrée dans l'ensemble de ces fonctions mais quelques fonctions spécifiques sont séparée
    \li  N.B. 2: La gestion de AttributeManager ????
	\
TODO:

  Gestion des valeur d'arrondis \n
    Si dans process = 4 \n
    Si pour view valeur = decimal_places \n


*/


class price {

  public $currencies;

  public $customer;

  public static $currency =array();
  /**
    @p array tableau de cache des prix deja calculé
  */
  public static $PriceCache=array();
  /**
    @p array cache des prix promo (special)
  */
  public static $_spe_Cache=array();

  /**
    Cache
  */
  private static $_taxrate_Cache=array();
  private static $_taxdesc_Cache=array();
  private static $_taxtitle_Cache=array();

  /**
    Gabarit prix normal
  */
  protected static $modele = array( 'price_model' => array( 'text'=>'%pprice', // Modèle Brut
							    'html'=>'<span class="price">%pprice</span>', // Modèle HTML
							    'rss'=>'      <price>%pprice</price>' // Modèle rss
							  ),
				    'special_model'=> array( 'text'=>'%sprice', // Modèle Brut
							    'html'=>'<del>%pprice</del>&nbsp;<span class="productSpecialPrice">%sprice</span>',// Modèle HTML
							    'rss'=>"      <price>%pprice</price> \n       <specialprice>%sprice</specialprice>" // Modèle rss
							  ),
				      );

  /**
    Gabarit one usage
  */
  protected static $getmodele=array();




  public function __construct() {

    $this->currencies = array();
    $currencies_query = tep_db_query("select code, title, symbol_left, symbol_right, decimal_point, thousands_point, decimal_places, value from " . TABLE_CURRENCIES);
    while ($currencies = tep_db_fetch_array($currencies_query)) {
      $this->currencies[$currencies['code']] = array('title' => $currencies['title'],
                                                     'symbol_left' => $currencies['symbol_left'],
                                                     'symbol_right' => $currencies['symbol_right'],
                                                     'decimal_point' => $currencies['decimal_point'],
                                                     'thousands_point' => $currencies['thousands_point'],
                                                     'decimal_places' => $currencies['decimal_places'],
                                                     'value' => $currencies['value']);
    }
    self::$currency=$this->currencies ;
  }


  /**
   * \fn get_product_sell_price(int id_du_produit [, int id_groupe_du_client])
   * \brief Récupère le prix final d'un produit en fonction du groupe et des promos
   * @param $products_id
   * @param $customers_group_id
   * @return float
   */
  private function get_product_sell_price($products_id, $customers_group_id='NaN') {
    if ($customers_group_id == 'NaN') $customers_group_id = $this->get_customer_group_id();

    $products_price = $this->get_db_products_price($products_id, $customers_group_id);

    if (($products_special_price=$this->get_db_products_special_price($products_id, $customers_group_id)) && $products_special_price < $products_price)
      return $products_special_price;
    else
       return $products_price;
  }


// -- Price methods --
  /**
   * \fn get_db_products_price($products_id, $customers_group_id='NaN')
   * \brief Récupère le prix d'origine d'un produit en fonction du groupe
   * @param $products_id
   * @param $customers_group_id
   * @return float
   */
  private function get_db_products_price($products_id, $customers_group_id='NaN') {
    if ($customers_group_id == 'NaN') $customers_group_id = $this->get_customer_group_id();

    $pid = tep_get_prid($products_id);

    if ($customers_group_id > 0) { // recup prix spécifiqu au groupe
      $price_query = tep_db_query("select customers_group_price as products_price from " . TABLE_PRODUCTS_GROUPS . " where products_id = '" .$pid. "' and customers_group_id =  '" . $customers_group_id  . "'");
      if (tep_db_num_rows($price_query)) $products_price = (float)tep_db_fetch_array($price_query);
    }
    if (!isset($products_price['products_price'])) { // si pas de prix pour le groupe, recup prix général
      $product_obj=product::get_item($pid);
      if(!$product_obj) return 0;
      $products_price['products_price']=(float) $product_obj->products_price;
    }

    $products_price['products_price'] += (float)$this->get_attributes_price($products_id, tep_get_prid_array($products_id));

    return $products_price['products_price'];
  }

  private function get_attributes_price($products_id, $attributes=array()) {
    return product::get_product_attribut_price($products_id, $attributes);
  }

// -- EOF Price methods --

// -- Special methods --

  /**
   * \fn get_db_products_special_price($products_id, $customers_group_id='NaN')
   * \brief  Récupère le prix promotionnel d'un produit en fonction du groupe
   * @param $products_id
   * @param $customers_group_id
   */
  private function get_db_products_special_price($products_id, $customers_group_id='NaN') {

    if ($customers_group_id == 'NaN') $customers_group_id = $this->get_customer_group_id();
    $pid = tep_get_prid($products_id);

    if(!isset(self::$_spe_Cache[$pid])){
      $product_query = tep_db_query("select specials_new_products_price from " . TABLE_SPECIALS . " where products_id = '" . (int)$pid . "' and customers_group_id= '" . (int)$customers_group_id . "' and status='1' ");
      $product = tep_db_fetch_array($product_query);
      self::$_spe_Cache[$pid]=(isset($product['specials_new_products_price'])? $product['specials_new_products_price'] : 0);

    } else {
      $product['specials_new_products_price'] = self::$_spe_Cache[$pid];
    }
    return $product['specials_new_products_price'];
  }


// -- Tax methods --



  /**
    \brief  Precise si tarif avec/ hors taxe
    @param $style string
  */
  private function display_tax_symbol($style='html') {
    $tax_symbol = '&nbsp;';

    if (self::is_SPPC_show_tax()) $tax_symbol .= TAX_SYMBOL;
    else $tax_symbol .= NOTAX_SYMBOL;

    if ($style=='html')
      return '<span class="tax_symbol">'.$tax_symbol.'</span>';
    else
      return $tax_symbol;
  }

  /**
   * \brief  Récupération du taux de la taxe d'un produit à partir de l'identifiant produit
   * @param $products_id
   * @param $country_id
   * @param $zone_id
   */
  private function get_tax_rates_from_pid($products_id, $country_id = -1, $zone_id = -1) {
    $pid = tep_get_prid($products_id);
    $product_obj=product::get_item($pid);
    if(!$product_obj)return false;
    return $this->get_tax_rate($product_obj->products_tax_class_id, $country_id, $zone_id);
  }


  /**
   *
   * @param $number
   * @param $calculate_currency_value boolean
   * @param $currency_type
   * @param $currency_value
   * @param $round  boolean round  in process = false
   */
  private function currency_format($number, $calculate_currency_value = true, $currency_type = '', $currency_value = '', $round=false) {
    global $currency;
    $euro_string = '';

    if (empty($currency_type))
       $currency_type = (!empty($currency) ? $currency : (_cst_bool('USE_DEFAULT_LANGUAGE_CURRENCY') ? LANGUAGE_CURRENCY : DEFAULT_CURRENCY) ) ;

    if ($calculate_currency_value == true) {
      $number *= tep_not_null($currency_value) ? $currency_value : $this->get_currency_value();
      // if the selected currency is in the european euro-conversion and the default currency is euro, the currency will displayed in the national currency and euro currency
      if ( (DEFAULT_CURRENCY == 'EUR') && in_array($currency_type, array('DEM','BEF','LUF','ESP','FRF','IEP','ITL','NLG','ATS','PTE','FIM','GRD')) )
        $euro_string = ' <small>[' . $this->currency_format($number, true, 'EUR') . ']</small>';
    }

    return $this->currencies[$currency_type]['symbol_left'] . number_format(tep_round($number, $this->get_round($round) ), $this->get_currency_decimal_places(), $this->currencies[$currency_type]['decimal_point'], $this->currencies[$currency_type]['thousands_point']) . $this->currencies[$currency_type]['symbol_right'] . $euro_string;
  }

  /**
   *
   * @param $code string
   */
  private function is_currency_set($code) { // alias trouvé tep_currency_exists <> retour $code au lieu de true
    if (isset($this->currencies[$code]) && tep_not_null($this->currencies[$code])) {
      return true;
    } else {
      return false;
    }
  }

  /**
   *
   * @param $code string
   */
  private function get_currency_value($code=DEFAULT_CURRENCY) {
    return $this->currencies[$code]['value'];
  }

  /**
   *
   * @param $code string
   */
  private function get_currency_decimal_places($code=DEFAULT_CURRENCY) {
    return $this->currencies[$code]['decimal_places'];
  }


 // -- SPPC methods --
  private static function is_SPPC_show_tax() {
    if (!isset($_SESSION['sppc_customer_group_show_tax']) || ( isset($_SESSION['sppc_customer_group_show_tax']) &&  $_SESSION['sppc_customer_group_show_tax']=='1'))
      return true ;
    else
      return false;
  }

  private static function get_SPPC_sql_specific_tax_exemption() {
    if (isset($_SESSION['sppc_customer_specific_taxes_exempt']) && tep_not_null($_SESSION['sppc_customer_specific_taxes_exempt']))
      return  "AND tax_rates_id NOT IN ( ". $_SESSION['sppc_customer_specific_taxes_exempt'] ." )";
    else
      return '';
  }

  private static function is_SPPC_tax_exempt() {
    if (isset($_SESSION['sppc_customer_group_tax_exempt']) && $_SESSION['sppc_customer_group_tax_exempt'] == '1')
      return true;
    else
      return false;
  }

  private function get_customer_group_id() {
    global $page;

    if (!isset($this->customer['customers_group_id'])) {
      $page->new_class('customer');
      $this->customer = $page->_call('customer','the_customer');
    }
    if(!isset($this->customer['customers_group_id'])) self::is_SPPC_grp();

    return $this->customer['customers_group_id'];
  }

  /**
   *
   * @param $price float
   */
  private static function get_SPPC_discount($price){
    if(isset($_SESSION['sppc_group_discount']) && $_SESSION['sppc_group_discount']>0)  return ($price - ($price*($_SESSION['sppc_group_discount']/100)) );
    return $price;
  }

  /**
    \brief Recup element groupe 0 si user not connected
  */
  private static function is_SPPC_grp(){
    $DB=Database::getInstance();
    $res_o=$DB->query("select * from ".TABLE_CUSTOMERS_GROUPS." where customers_group_id='0' ");
    $res=$res_o->fetchAssoc();

    $_SESSION['sppc_customer_group_tax_exempt']=$res['customers_group_tax_exempt'];
    $_SESSION['sppc_customer_specific_taxes_exempt']=$res['group_specific_taxes_exempt'];
    $_SESSION['sppc_customer_group_show_tax']=$res['customers_group_show_tax'];
    $_SESSION['sppc_group_discount']=$res['group_discount'];
  }

  /**
   * \brief FrontOffice
   * \note     Utilisation modele
    			Uniquement appelé par  display_products_price
   * @param $products_id int
   * @param $type string
   * @param $style string
   */
  private static function getModele($products_id,$type='price_model', $style='html'){

    if(isset(self::$getmodele[$products_id][$type][$style])){
      $res= self::$getmodele[$products_id][$type][$style];
    }
    else $res= self::$modele[$type][$style];

    return $res;
  }


  /**
   * \fn  calcul_price($products_id,$products_price, $products_tax_rate = 0, $specials_products_price = 0, $qty=1,$tax_force=false)
   * \brief frontoffice function
   * \note     Update price , by module , special , group , discount
			    Prend en charge le calcul du prix produit, special, total line, en HT et TTC
   * @param $products_id int/string pid or prid
   * @param $products_price
   * @param $products_tax_rate
   * @param $specials_products_price
   * @param $qty
   * @param $tax_force
   * @return array prices products
   */
  private function calcul_price($products_id,$products_price, $products_tax_rate = 0, $specials_products_price = 0, $qty=1,$tax_force=false){

    if(isset(self::$PriceCache[$products_id.'_'.$qty])) return self::$PriceCache[$products_id.'_'.$qty];

    //! discount SPPC
    $products_price=self::get_SPPC_discount($products_price);
    $specials_products_price=self::get_SPPC_discount($specials_products_price);

    //! add taxes
    $res_price = $this->display_with_tax($products_price, $products_tax_rate, $tax_force);
    $res_spe_price =$this->display_with_tax($specials_products_price, $products_tax_rate, $tax_force);

    //! qty
    $total_line=( (($specials_products_price>0 && $specials_products_price !=$products_price)? $specials_products_price :$products_price) * $qty);
    $total_line_ttc=( (($res_spe_price>0 && $res_spe_price !=$res_price)? $res_spe_price :$res_price) * $qty);

    /**
      Inclusion des modules intervant sur les prix, flag price
    */
    $array_res=product::get_adjust_price(array('products_id'=>$products_id,
					      'final_price_ht'=> $products_price,
					      'final_price_ttc'=> $res_price,
					      'final_sprice_ht'=> $specials_products_price,
					      'final_sprice_ttc'=> $res_spe_price,
					      'total_line'=> $total_line,
					      'total_line_ttc'=> $total_line_ttc,
					      'products_quantity'=>$qty)
					      );

    //
    $_products_price=( (is_float($array_res['final_price_ht']) )? $array_res['final_price_ht'] : $products_price );

    if(/*$_products_price != $products_price &&*/ $array_res['final_price_ttc']=='')
      $_res_price=$this->display_with_tax($_products_price, $products_tax_rate, $tax_force);
    else
      $_res_price=( (is_float($array_res['final_price_ttc']) )? $array_res['final_price_ttc'] : $res_price );

    $_specials_products_price=( (is_float($array_res['final_sprice_ht']) )? $array_res['final_sprice_ht'] : $specials_products_price );
    $_res_spe_price=( (is_float($array_res['final_sprice_ttc']) )? $array_res['final_sprice_ttc'] : $res_spe_price );
    $total_line=( (is_float($array_res['total_line']) )? $array_res['total_line'] : $total_line );
    $total_line_ttc=( (is_float($array_res['total_line_ttc']) )? $array_res['total_line_ttc'] : $total_line_ttc );

    //! qty apres adjust price
    if(!is_float($array_res['total_line']) ||($_products_price !=$products_price) || ($_specials_products_price !=$specials_products_price ) )
      $total_line=( (($_specials_products_price>0 && $_specials_products_price !=$_products_price)? $_specials_products_price :$_products_price) * $qty);
    if(!is_float($array_res['total_line_ttc']) ||($_res_spe_price !=$res_spe_price) || ($_res_price !=$res_price ) )
      $total_line_ttc=( (($_res_spe_price>0 && $_res_spe_price !=$_res_price)? $_res_spe_price :$_res_price) * $qty);

    return self::$PriceCache[$products_id.'_'.$qty]=array('price_ht'=>$_products_price,
						  'price_ttc'=>$_res_price,
						  'sprice_ht'=>$_specials_products_price,
						  'sprice_ttc'=>$_res_spe_price,
						  'total_line'=>$total_line,
						  'total_line_ttc'=>$total_line_ttc,
						  );
  }

  /**
    Fonction public
  */


  /**
   * \brief value round
   * @param $process bool
   */
  public function get_round($process){
    return ((bool)$process)
	    ? $this->get_currency_decimal_places()
	    : 6 ;
  }

  /**
   * \brief Fonction de convertion de valeur ,
   *
   * @param $number
   * @param $in_currency
   * @param $to_currency
   */
  public static function convert_in_currency($number, $in_currency, $to_currency = DEFAULT_CURRENCY){
    $in_currency = (!empty($in_currency) ? $in_currency : (_cst_bool('USE_DEFAULT_LANGUAGE_CURRENCY') ? LANGUAGE_CURRENCY : DEFAULT_CURRENCY) ) ;
    return  (($number / self::$currency[$in_currency]['value'])  * self::$currency[$to_currency]['value']);
  }

  /**
   *
   * @param $code string
   */
  public function get_decimal_places($code=DEFAULT_CURRENCY){
    return $this->get_currency_decimal_places($code);
  }

  /**
   *
   * @param  $code string
   */
  public function is_set($code) {
    if (isset($this->currencies[$code]) && tep_not_null($this->currencies[$code])) return true;
    else  return false;
  }

  /**
   *
   * @param $code string
   */
  public function get_value($code) {
    return $this->currencies[$code]['value'];
  }


  /**
   * \brief Vue du prix total produits
   * @param $price float
   * @param $tax_id int
   * @param $currency
   * @param $currency_v float
   * @param $qty int
   */
  public function view_price_with_tax($price,$tax_id, $currency='',$currency_v='', $qty=1){
    return $this->currency_format(
	    tep_round(
	      ($this->display_with_tax($price, $tax_id, true, true) *$qty)
	      , $this->get_currency_decimal_places())
	    , false , $currency, $currency_v);
  }

  /**
   * \fn display_tax_value($value, $padding = TAX_DECIMAL_PLACES)
   * \brief  Ajout de zero après la virgule si besoin
   * @param $value float
   * @param $padding
   * @return string
   */
  public function display_tax_value($value, $padding = TAX_DECIMAL_PLACES) {
    if (strpos($value, '.')) {
      while (substr($value, -1) == '0') $value = substr($value, 0, -1);
      if (substr($value, -1) == '.') $value = substr($value, 0, -1);
    }
    if ($padding > 0) {
      if ($decimal_pos = strpos($value, '.')) {
        $decimals = strlen(substr($value, ($decimal_pos+1)));
        for ($i=$decimals; $i<$padding; $i++) $value .= '0';
      } else {
        $value .= '.';
        for ($i=0; $i<$padding; $i++) $value .= '0';
      }
    }
    return $value;
  }


  /**
   * \brief Alias  currency_format pour display
   * @param  $number
   * @param  $calculate_currency_value bool
   * @param  $currency_type
   * @param  $currency_value
   */
  public function format($number, $calculate_currency_value = true, $currency_type = '', $currency_value = '') {
    return $this->currency_format($number, $calculate_currency_value, $currency_type, $currency_value, true);
  }

  /**
    Récupération du taux de la taxe d'un produit à partir de l'identifiant de la taxe
  */
  public function get_tax_rate($class_id, $country_id = -1, $zone_id = -1) {
    global $customer_zone_id, $customer_country_id;

    // Gestion de l'exemption totale de taxe
    if (self::is_SPPC_tax_exempt()) return 0;;

    // Geolocalisation
    if ( ($country_id == -1) && ($zone_id == -1) ) {
      if (!tep_session_is_registered('customer_id')) {
        $country_id = STORE_COUNTRY;
        $zone_id = STORE_ZONE;
      } else {
        $country_id = $customer_country_id;
        $zone_id = $customer_zone_id;
      }
    }
    if(isset(self::$_taxrate_Cache[(int)$country_id .'_'.(int)$zone_id .'_'.(int)$class_id])) return self::$_taxrate_Cache[(int)$country_id .'_'.(int)$zone_id .'_'.(int)$class_id];

    $tax_query = tep_db_query("select sum(tax_rate) as tax_rate from " . TABLE_TAX_RATES . " tr left join " . TABLE_ZONES_TO_GEO_ZONES . " za on (tr.tax_zone_id = za.geo_zone_id) left join " . TABLE_GEO_ZONES . " tz on (tz.geo_zone_id = tr.tax_zone_id) where (za.zone_country_id is null or za.zone_country_id = '0' or za.zone_country_id = '" . (int)$country_id . "') and (za.zone_id is null or za.zone_id = '0' or za.zone_id = '" . (int)$zone_id . "') and tr.tax_class_id = '" . (int)$class_id . "' " . self::get_SPPC_sql_specific_tax_exemption() . " group by tr.tax_priority");

    if (!tep_db_num_rows($tax_query)) return self::$_taxrate_Cache[(int)$country_id .'_'.(int)$zone_id .'_'.(int)$class_id] = 0;

    $tax_multiplier = 1.0;
    while ($tax = tep_db_fetch_array($tax_query)) {
      $tax_multiplier *= 1.0 + ($tax['tax_rate'] / 100);
    }

    return self::$_taxrate_Cache[(int)$country_id .'_'.(int)$zone_id .'_'.(int)$class_id] = ($tax_multiplier - 1.0) * 100;
  }


  /**
   * \fn display_with_tax(float prix_produit, float taux_de_tva [,bool force_le_calcul [, bool pas_arrondir_taxe]] )
   * \brief Ajout de la taxe au prix en vue de l'affichage
   * @param $products_price
   * @param $tax
   * @param $force boolean
   * @param $strict boolean $strict  in process = false
   * @return float
   */
  public function display_with_tax($products_price, $tax, $force=false, $strict=false) { //tep_add_tax //$this->add_tax

    $customer_group_show_tax = self::is_SPPC_show_tax();

    if ( $force || ($tax > 0 && $customer_group_show_tax))
      return (!$strict)
		? tep_round((float)$products_price, $this->get_round($strict) ) + $this->get_tax_amount((float)$products_price, $tax ,$strict )
		: (float)$products_price + $this->get_tax_amount((float)$products_price, $tax ,false );
    else
      return $products_price;
  }


  /**
    \brief Mise en forme pour l'affichage d'un prix de produit à partir de son identifiant
    Prend en compte :
    \li- l'existance ou non d'une promotion
    \li- l'affichage des taxes
    \li- Le module SPPC (prix, taxes et promo)


    @param $products_id int|string product_id | prid
    @param $style  string format sortie
    @return string
  */
  public function print_products_price($products_id, $style='html'){
    return $this->display_products_price($products_id,$this->get_db_products_price($products_id), $this->get_tax_rates_from_pid($products_id), $this->get_db_products_special_price($products_id), $style);
  }

  /**
   * \fn get_products_price($products_id,$qty=1, $mode='',$tax_force=false)
   * \brief Recup prix produit, tableau ou detail
   * @param $products_id string/int $products_id pid or prid
   * @param $qty int
   * @param $mode string
   * @param $tax_force bool
   * @return array/string
  */
  public function get_products_price($products_id,$qty=1, $mode='',$tax_force=false){
    $res_array=$this->calcul_price($products_id,$this->get_db_products_price($products_id), $this->get_tax_rates_from_pid($products_id), $this->get_db_products_special_price($products_id), $qty,$tax_force);

    if(!empty($mode) && isset($res_array[$mode])) return $res_array[$mode];
    return $res_array;
  }


  /**
   * \fn  display_products_price($products_id,$products_price, $products_tax_rate = 0, $specials_products_price = 0, $style='html', $tax_sym=true, $tax_force=false)
   * \brief Génération du html pour l'affichage du prix d'un produit
   * @param $products_id
   * @param $products_price
   * @param $products_tax_rate
   * @param $specials_products_price
   * @param $style string
   * @param $tax_sym
   * @param $tax_force bool
   * @return string
   */
  public function display_products_price($products_id,$products_price, $products_tax_rate = 0, $specials_products_price = 0, $style='html', $tax_sym=true, $tax_force=false) {

    $res_array=$this->calcul_price($products_id,$products_price, $products_tax_rate, $specials_products_price ,1, $tax_force);

    $style = strtolower($style);

    $output_price = $this->currency_format($res_array['price_ttc']).($tax_sym?$this->display_tax_symbol($style):'');
    $output_special = $this->currency_format($res_array['sprice_ttc']).($tax_sym?$this->display_tax_symbol($style):'');
    $output = '';

    if ((int)$res_array['sprice_ttc'] && $res_array['sprice_ttc'] != $res_array['price_ttc'])
      $output = str_replace('%pprice', $output_price, str_replace('%sprice', $output_special, self::getModele($products_id,'special_model',$style) /*self::$special_model[$style]*/));
    elseif($products_price)
      $output = str_replace('%pprice', $output_price,self::getModele($products_id,'price_model',$style) /*self::$price_model[$style]*/);

    return $output;
  }


  /**
    \brief re-definiton d'un modele de sortie de prix
    \note cf  $price_model | $special_model
    @param $format string
    @param $type string
    @param $style string
  */
  public static function define_modele($format,$type='price_model', $style='html'){
    if(isset(self::$modele[$type][$style]))  self::$modele[$type][$style]=$format;
  }


  /**
   * \brief re-definiton d'un modele de sortie de prix usage ponctuel
   * \note cf $price_model | $special_model
   * @param $products_id int
   * @param $format
   * @param $type string
   * @param $style string
   */
  public static function define_OneModele($products_id,$format,$type='price_model', $style='html'){
    self::$getmodele[$products_id][$type][$style]=$format;
  }


  /**
   * \brief Recupère le nom des taxes
   * @param $class_id
   * @param $country_id
   * @param $zone_id
   */
  public function get_tax_description($class_id, $country_id, $zone_id) {
   // Gestion de l'exemption totale de taxe
    if (self::is_SPPC_tax_exempt()) return '';


    if(isset(self::$_taxdesc_Cache[(int)$country_id .'_'.(int)$zone_id .'_'.(int)$class_id]) ) return self::$_taxdesc_Cache[(int)$country_id .'_'.(int)$zone_id .'_'.(int)$class_id];

    $tax_query = tep_db_query("select tax_description from " . TABLE_TAX_RATES . " tr left join " . TABLE_ZONES_TO_GEO_ZONES . " za on (tr.tax_zone_id = za.geo_zone_id) left join " . TABLE_GEO_ZONES . " tz on (tz.geo_zone_id = tr.tax_zone_id) where (za.zone_country_id is null or za.zone_country_id = '0' or za.zone_country_id = '" . (int)$country_id . "') and (za.zone_id is null or za.zone_id = '0' or za.zone_id = '" . (int)$zone_id . "') and tr.tax_class_id = '" . (int)$class_id . "' " . self::get_SPPC_sql_specific_tax_exemption() . " order by tr.tax_priority");

    if (!tep_db_num_rows($tax_query)) return self::$_taxdesc_Cache[(int)$country_id .'_'.(int)$zone_id .'_'.(int)$class_id] = TEXT_UNKNOWN_TAX_RATE;

    $tax_description = '';
    while ($tax = tep_db_fetch_array($tax_query)) {
      $tax_description .= $tax['tax_description'] . ' + ';
    }
    $tax_description = substr($tax_description, 0, -3);

    return self::$_taxdesc_Cache[(int)$country_id .'_'.(int)$zone_id .'_'.(int)$class_id] = $tax_description;
  }


  /**
   * \brief Recup title class
   * @param $tax_class_id
   */
  public function tep_get_tax_class_title($tax_class_id) {
    if ($tax_class_id == '0')  return TEXT_NONE;
    else {
      if(isset(self::$_taxtitle_Cache[(int)$tax_class_id])) return self::$_taxtitle_Cache[(int)$tax_class_id];
      $classes_query = tep_db_query("select tax_class_title from " . TABLE_TAX_CLASS . " where tax_class_id = '" . (int)$tax_class_id . "'");
      $classes = tep_db_fetch_array($classes_query);
      return self::$_taxtitle_Cache[(int)$tax_class_id] = $classes['tax_class_title'];
    }
  }

  /**
    \brief Calcule le montant de la taxe
    @param $products_price
    @param $tax
    @param $round boolean round  in process = false
  */
  public function get_tax_amount($products_price, $tax,$round=false) { //tep_calculate_tax //$this->calculate_tax

    if(!$round)return tep_round((float)$products_price * $tax / 100, $this->get_round($round));
    else return ($products_price * $tax / 100);
  }

  public function display_price($products_price, $products_tax, $quantity = 1) {
    return $this->currency_format(tep_add_tax($products_price, $products_tax) * $quantity);
  }

  /** obsolete
  function display_currencied_price($products_price, $products_tax, $quantity = 1) {
    return $this->display_products_price($products_price*$quantity, $products_tax, 0);
  }
  */



}
?>