490 lines
23 KiB
PHP
Raw Normal View History

2016-10-13 12:32:49 +02:00
<?php
// Config
if (!defined('_PS_VERSION_'))
exit;
class FluxCatalog
{
const TOMORROW = 1;
2016-10-14 15:10:45 +02:00
const CURRENT = 0;
2016-10-13 12:32:49 +02:00
const TOMORROW_FUTURE_SALES = 2;
private $_xml = null;
private $_filename = null;
private $_type = null; // type de catalogue généré (default, veoxa, criteo, idealo)
public $domain;
public $id_lang;
public $currentTime;
public $context;
public $url_additionnal_parameters = '';
2016-10-13 12:32:49 +02:00
public function __construct()
{
$this->domain = Configuration::get('PS_SHOP_DOMAIN');
$this->url_additionnal_parameters = str_replace('&', '&amp;', Configuration::get('FLUXCATALOG_TRACKING'));
2016-10-13 12:32:49 +02:00
require_once(dirname(__FILE__).'/../../../init.php');
}
/******************************************************************************************************************************
* Génère le catalog dans le dossier ./catalogs
******************************************************************************************************************************/
public function generateCatalog($type)
{
if ($type === 'arthur_media') {
$this->_filename = (new DateTime('+1 day'))->format('Ymd') . '_ventes.xml';
$this->_type = $type;
$this->context = Context::getContext();
$this->context->controller = new FrontController();
$items = $this->getSales(true);
$this->createSalesXml($items);
}
if (($handle = fopen(dirname(__FILE__).'/../catalogs/'.$this->_filename, 'w')) && $this->_xml !== null) {
fwrite($handle, $this->_xml);
}
}
/*****************************************************************
* Renvoi la liste des Ventes actives
*****************************************************************/
private function getChildren($sale)
{
$parent = Db::getInstance()->getRow('
SELECT c.`nleft`, c.`nright`
FROM ' . _DB_PREFIX_ .'category c
LEFT JOIN `'._DB_PREFIX_.'category_group` g
ON (c.`id_category` = g.`id_category`)
WHERE c.`id_category` = ' . pSQL($sale->id_category) . '
');
$maxdepth = Configuration::get('BLOCK_CATEG_MAX_DEPTH');
$range = 'AND nleft >= '.$parent['nleft'].' AND nright <= '.$parent['nright'];
$resultIds = array();
$resultParents = array();
return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
SELECT c.id_parent, c.id_category, cl.name, cl.description, cl.link_rewrite
FROM `'._DB_PREFIX_.'category` c
INNER JOIN `'._DB_PREFIX_.'category_lang` cl ON (c.`id_category` = cl.`id_category` AND cl.`id_lang` = '.(int)$this->context->language->id.Shop::addSqlRestrictionOnLang('cl').')
INNER JOIN `'._DB_PREFIX_.'category_shop` cs ON (cs.`id_category` = c.`id_category` AND cs.`id_shop` = '.(int)$this->context->shop->id.')
WHERE (c.`active` = 1 OR c.`id_category` = '.(int)Configuration::get('PS_HOME_CATEGORY').')
AND c.`id_category` != '.(int)Configuration::get('PS_ROOT_CATEGORY').'
'.((int)$maxdepth != 0 ? ' AND `level_depth` <= '.(int)$maxdepth : '').'
'.$range.'
AND c.id_category IN (
SELECT id_category
FROM `'._DB_PREFIX_.'category_group`
WHERE `id_group` IN ('.pSQL(implode(', ', Customer::getGroupsStatic((int)$this->context->customer->id))).')
)
ORDER BY `level_depth` ASC, '.(Configuration::get('BLOCK_CATEG_SORT') ? 'cl.`name`' : 'cs.`position`').' '.(Configuration::get('BLOCK_CATEG_SORT_WAY') ? 'DESC' : 'ASC'));
}
private function formatSale($sale, $future = false) {
$item = array();
$item['id_de_la_vente'] = $sale->id_privatesales;
$item['date_de_debut'] = substr($sale->date_start, 0, 10);
$item['heure_de_debut'] = substr($sale->date_start, -8);
$item['date_de_fin'] = substr($sale->date_end, 0, 10);
$item['heure_de_fin'] = substr($sale->date_end, -8);
$item['categorie_d_article'] = Db::getInstance()->getValue('
SELECT `title`
FROM `'._DB_PREFIX_.'privatesales_category_lang` a
LEFT JOIN `'._DB_PREFIX_.'privatesales_category_sales` b ON (a.`id_privatesales_category` = b.`id_privatesales_category`)
WHERE b.`id_privatesales` = '.$sale->id_privatesales.'
');
$item['nom_de_la_vente'] = $sale->title;
if ($future === false) {
$item['image_logo_marque'] = _PS_BASE_URL_.'/modules/privatesales/img/' . $sale->id_privatesales . '/logo/' . $sale->id_privatesales . '_' . Context::getContext()->language->id . '.jpg'.$this->url_additionnal_parameters;
2016-10-13 12:32:49 +02:00
}
$category = new Category($sale->id_category, (int) $this->context->cookie->id_lang);
$item['slogan'] = $sale->subtitle;
$item['sous_titre'] = $sale->subtitle;
$item['description'] = $sale->description;
$item['image_visuel_large_vente'] = _PS_BASE_URL_.'/modules/privatesales/img/'.$sale->id_privatesales.'/current/'.$sale->id_privatesales . '_' . Context::getContext()->language->id.'.jpg'.$this->url_additionnal_parameters;
$item['url_de_la_vente'] = _PS_BASE_URL_.'/'.$sale->id_category.'-'.$sale->link_rewrite.$this->url_additionnal_parameters;
2016-10-13 12:32:49 +02:00
$item['reduction'] = $sale->percent;
//BUILD MENU CATEGORIES MENU
$categories = $this->getChildren($sale);
foreach ($categories as $i => $category) {
$item['menu_'.$i.'_de_la_vente'] = $category['name'];
$item['url_menu_'.$i] = _PS_BASE_URL_ . '/' . $category['id_category'] . '-' . $category['link_rewrite'].$this->url_additionnal_parameters;
2016-10-13 12:32:49 +02:00
}
return $item;
}
public function getSales($tomorrowMode = false)
{
$diff = null;
$currentDay = date('N');
if ($currentDay === '5')
$diff = '3';
elseif ($currentDay === '6')
$diff = '2';
else
$diff = '1';
2016-10-14 15:10:45 +02:00
2016-10-13 12:32:49 +02:00
$items = array();
2016-10-14 15:10:45 +02:00
$current = $this->getSalesTomorrow($diff, self::CURRENT);
echo 'CURRENT' . PHP_EOL;
foreach ($current as $sale) {
var_dump($sale->title . ' ' . $sale->id);
2016-10-13 12:32:49 +02:00
$items[] = $this->formatSale($sale);;
}
2016-10-14 15:10:45 +02:00
$tomorrow = $this->getSalesTomorrow($diff, self::TOMORROW);
echo 'TOMORROW' . PHP_EOL;
foreach ($tomorrow as $sale) {
var_dump($sale->title . ' ' . $sale->id);
$items[] = $this->formatSale($sale);;
2016-10-13 12:32:49 +02:00
}
2016-10-14 15:10:45 +02:00
$future = $this->getSalesTomorrow($diff, self::TOMORROW_FUTURE_SALES);
echo 'FUTURE' . PHP_EOL;
foreach ($future as $sale) {
var_dump($sale->title . ' ' . $sale->id);
$items[] = $this->formatSale($sale);;
}
2016-10-13 12:32:49 +02:00
return $items;
}
2016-10-14 15:10:45 +02:00
public static function getSalesTomorrow($diff, $type = self::CURRENT){
2016-10-13 12:32:49 +02:00
$collection = new Collection('SaleCore', Context::getContext()->language->id);
2016-10-14 15:10:45 +02:00
if ($type === self::CURRENT) {
$where = ' WHERE `date_start` < "' . (new DateTime())->format('Y-m-d H:i:s') . '" AND `date_end` > "' . (new DateTime())->format('Y-m-d H:i:s') . '" AND `active` = 1';
2016-10-13 12:32:49 +02:00
}
2016-10-14 15:10:45 +02:00
elseif ($type === self::TOMORROW) {
$where = ' WHERE `date_start` BETWEEN "' . (new DateTime())->format('Y-m-d H:i:s') . '" AND "' . (new DateTime('+' . $diff . ' day'))->format('Y-m-d H:i:s') . '"';
} elseif ($type === self::TOMORROW_FUTURE_SALES) {
$where = ' WHERE `date_start` > "' . (new DateTime('+' . $diff . ' day'))->format('Y-m-d H:i:s') . '"';
2016-10-13 12:32:49 +02:00
}
2016-10-14 15:10:45 +02:00
$sql = 'SELECT `id_privatesales` FROM `ps_privatesales` ' . $where;
$id_sales = array_column(Db::getInstance()->executeS($sql), 'id_privatesales');
$sales = [];
foreach ($id_sales as $id_sale) {
$sales[] = new SaleCore($id_sale, Context::getContext()->cookie->id_lang);
2016-10-13 12:32:49 +02:00
}
2016-10-14 15:10:45 +02:00
return $sales;
2016-10-13 12:32:49 +02:00
}
/******************************************************************************************************************************
* Renvoi la liste des produits en vente aevc les informations suivantes :
******************************************************************************************************************************/
public function getProducts()
{
$return = array();
$buffer = array(); // pour éviter les doublons avec des produits appartenant à plusieurs ventes
// Fetching products ID
$context = Context::getContext();
$id_lang = $context->language->id;
$products_id = array();
$currentSales = SaleCore::getSales(SaleCore::STATE_CURRENT);
foreach ($currentSales as $privatesale) {
// On ne veut que les ventes actives (groupe 1 default)
if (isset($privatesale->id_groups[0]) && $privatesale->id_groups[0] != 1) {
continue;
}
$sale = new SaleCore($privatesale->id);
$products = $sale->getProducts();
foreach ($products as $product) {
$products_id[] = $product;
}
}
foreach ($products_id as $product_id) {
$product = new Product($product_id, false, $id_lang, null, $context);
$default_attribute_id = $this->getDefaultAttributeId($product->id);
// On filtre les produits désactivés
if (isset($product->active) && $product->active == 0)
continue;
// On esquive les doublons
if (isset($buffer[$product->id]) && $buffer[$product->id] == $product->id)
continue;
/** Correctif pour aller chercher le prix réel **/
$product->specificPrice = SpecificPrice::getByProductId((int)($product->id));
if ($product->price == 0){
$realprice = Product::getPriceStatic($product->id, true, $default_attribute_id, 2);
$product->realprice = $realprice;
$product->price_ttc = Product::getPriceStatic($product->id, true, $default_attribute_id, 2, false, false);
} else {
$realprice = Product::getPriceStatic($product->id, true, null, 2);
$product->realprice = $realprice;
$product->price_ttc = $product->price * 1.2;
}
$margin = $product->realprice - (float)$product->wholesale_price;
if ($margin < 3) $product->rentability = 5; //PAS RENTABLE
elseif ($margin < 7) $product->rentability = 4; //PEU RENTABLE
elseif ($margin < 10) $product->rentability = 3; //BREAK EVEN
elseif ($margin < 20) $product->rentability = 2; //RENTABLE
else $product->rentability = 1; //TRES RENTABLE
/** Correctif pour aller chercher la quantité réelle **/
if ( !empty($default_attribute_id) ) {
$realquantity = StockAvailable::getQuantityAvailableByProduct($product->id, $default_attribute_id);
$product->realquantity = $realquantity;
} else {
$realquantity = StockAvailable::getQuantityAvailableByProduct($product->id);
$product->realquantity = $realquantity;
}
/** on ajoute des infos sur la cover du produit **/
$images = $product->getImages($id_lang, $context);
$id_image = 0;
foreach($images as $image) {
if (isset($image['cover']) && $image['cover'] == 1) {
$id_image = $image['id_image'];
break;
}
}
if ($id_image != 0) {
$uri_path = _PS_BASE_URL_._THEME_PROD_DIR_.Image::getImgFolderStatic($id_image).$id_image;
$product->imgBig = $uri_path.'-large.jpg';
$product->imgMedium = $uri_path.'-medium.jpg';
$product->imgSmall = $uri_path.'-small.jpg';
} else {
$id_image = Language::getIsoById($id_lang).'-default';
}
/** on ajoute l'url **/
$link = new Link();
$url = $link->getProductLink($product);
$url = preg_replace('#privilegedemarque.com\.\/#', 'privilegedemarque.com/', $url);
2016-10-13 12:32:49 +02:00
$product->url = $url;
// nouveau produit
if( !isset($product->condition) || empty($product->condition) || $product->condition != 'new')
$product->new = 0;
else
$product->new = 1;
// discount
if( !isset($product->quantity_discount) || empty($product->quantity_discount) || $product->quantity_discount <=0 )
$product->discount = 0;
else
$product->discount = 1;
/** on ajoute les infos de la vente privée **/
$sale = SaleCore::getSaleByProductId($product->id);
$product->privateSaleInfo = $sale[0];
$product->manufacturer_name = $this->getManufacturerNameById($product->id_manufacturer);
$product->delivery_fee = round(Carrier::getCarrierByReference(104)->getDeliveryPriceByWeight($product->weight, 9) * 1.2, 2);
$return[] = $product;
$buffer[$product->id] = $product->id;
}
return $return;
}
/******************************************************************************************************************************
* Création du XML
******************************************************************************************************************************/
public function createSalesXml($items, $rss=false, $debug_mode=false) {
$this->_xml = '<?xml version="1.0" encoding="UTF-8" ?>';
$this->_xml .= '<catalogue>';
$this->_xml .= '<infos_boutique>';
$this->_xml .= '<logo>http://www.privilegedemarque.com/img/logo.png'.$this->url_additionnal_parameters.'</logo>';
$this->_xml .= '<nom>privilegedemarque.com</nom>';
$this->_xml .= '<url>'._PS_BASE_URL_.$this->url_additionnal_parameters.'</url>';
2016-10-13 12:32:49 +02:00
$this->_xml .= '<nb_items>'.count($items).'</nb_items>';
$this->_xml .= '</infos_boutique>';
foreach ($items as $item) {
$this->_xml .= '<vente>';
foreach ($item as $key => $value) {
$this->_xml .= '<' . $key . '>';
$this->_xml .= $value;
$this->_xml .= '</' . $key . '>';
}
$this->_xml .= '</vente>';
}
$this->_xml .= '</catalogue>';
2017-02-16 16:52:41 +01:00
$this->_xml = str_replace('&amp;', '__et__', $this->_xml);
2016-10-13 12:32:49 +02:00
$this->_xml = str_replace('&', 'et', $this->_xml);
2017-02-16 16:52:41 +01:00
$this->_xml = str_replace('__et__', '&amp;', $this->_xml);
2016-10-13 12:32:49 +02:00
// $this->_xml = htmlspecialchars($this->_xml);
}
public function createXml($items, $rss=false, $debug_mode=false)
{
$this->_xml = '<?xml version="1.0" encoding="UTF-8" ?>';
// Si on veut générer un flux RSS
if( $rss ){
$this->_xml .= '<rss version="2.0">';
$this->_xml .= ' <channel>';
$this->_xml .= ' <title>Privilege de marque</title>';
$this->_xml .= ' <description>Catalogue de produits Privilege de marque</description>';
2016-10-13 12:32:49 +02:00
$this->_xml .= ' <link>'._PS_BASE_URL_.'</link>';
$this->_xml .= ' </channel>';
foreach ($items as $item){
$this->_xml.='<item>';
$this->_xml.= '<title><![CDATA['.$item->name.']]></title>';
$this->_xml.= '<description><![CDATA['.$item->description_short.']]></description>';
$this->_xml.= '<pubDate><![CDATA['.$item->date_add.']]></pubDate>';
$this->_xml.= '<link><![CDATA['.$item->url.']]></link>';
$this->_xml.='</item>';
}
$this->_xml.='</rss>';
}
// Si on veut générer le catalogue avec détail en XML
else{
$this->_xml .= '<catalogue>';
//Infos boutique
$this->_xml .= '<infos_boutique>';
$this->_xml .= '<logo>http://www.privilegedemarque.com/img/logo.png'.$this->url_additionnal_parameters.'</logo>';
2016-10-13 12:32:49 +02:00
$this->_xml .= '<nom>'._PS_BASE_URL_.'</nom>';
$this->_xml .= '<url>'._PS_BASE_URL_.$this->url_additionnal_parameters.'</url>';
2016-10-13 12:32:49 +02:00
$this->_xml .= '<nb_items>'.count($items).'</nb_items>';
$this->_xml .= '</infos_boutique>';
// Infos Produits
foreach ($items as $item){
$this->_xml .= '<produit>';
$this->_xml .= '<id_produit>'.$item->id.'</id_produit>';
$this->_xml .= '<nom_produit><![CDATA['.$item->name.']]></nom_produit>';
$this->_xml .= '<description><![CDATA['.$this->sanitize($item->description).']]></description>';
$this->_xml .= '<prix>'.round($item->realprice,2).'</prix>';
$this->_xml .= '<url_produit><![CDATA['.$this->formatUrl($item->url, $item->name).$this->url_additionnal_parameters.']]></url_produit>';
$this->_xml .= '<url_img>'.$item->imgMedium.$this->url_additionnal_parameters.'</url_img>';
2016-10-13 12:32:49 +02:00
$this->_xml .= '<categorie>';
$this->_xml .= '<nom_categorie><![CDATA['.$item->category.']]></nom_categorie>';
$this->_xml .= '<id_categorie>'.$item->id_category_default.'</id_categorie>';
$this->_xml .= '</categorie>';
if(isset($item->ean13) && !empty($item->ean_13))
$this->_xml .= '<code_ean>'.$item->ean13.'</code_ean>';
// Infos vente privée
if( isset($item->privateSaleInfo) && !empty($item->privateSaleInfo) ){
$this->_xml .= '<vente>';
$this->_xml .= '<nom><![CDATA['.$item->privateSaleInfo->title.']]></nom>';
$this->_xml .= '<date_fin>'.$item->privateSaleInfo->date_end.'</date_fin>';
$this->_xml .= '<description><![CDATA['.$item->privateSaleInfo->description.']]></description>';
$this->_xml .= '<image>'._PS_BASE_URL_.'/modules/privatesales/img/'.(int)$item->privateSaleInfo->id_privatesales.'/current/'.(int)$item->privateSaleInfo->id_privatesales.'_2.jpg</image>';
$this->_xml .= '<url>'._PS_BASE_URL_.'/'.(int)$item->privateSaleInfo->id_category.'-'.Category::getLinkRewrite((int)$item->privateSaleInfo->id_category, 2).$this->url_additionnal_parameters.'</url>';
2016-10-13 12:32:49 +02:00
$this->_xml .= '</vente>';
}
if(isset($item->brand) && !empty($item->brand))
$this->_xml .= '<marque><![CDATA['.$item->brand.']]></marque>';
if(isset($item->price_ttc) && !empty($item->price_ttc))
$this->_xml .= '<prix_barre>'.round($item->price_ttc,2).'</prix_barre>';
if(isset($item->specificPrice[0]) && $item->specificPrice[0]['reduction'] > 0){
$this->_xml .= '<remise>';
if( $item->specificPrice[0]['reduction_type'] == 'percentage' ){
$this->_xml .= '<valeur>'.round(($item->specificPrice[0]['reduction']*100),2).'</valeur>';
$this->_xml .= '<devise>%</devise>';
} else {
$this->_xml .= '<valeur>'.round($item->specificPrice[0]['reduction'],2).'</valeur>';
$this->_xml .= '<devise>€</devise>';
}
$this->_xml .= '</remise>';
}
if(isset($item->description_short) && !empty($item->description_short))
$this->_xml .= '<description_courte><![CDATA['.$item->description_short.']]></description_courte>';
$this->_xml .= '<frais_livraison>'.$item->delivery_fee.'</frais_livraison>';
if(isset($item->additional_shipping_cost) && !empty($item->additional_shipping_cost))
$this->_xml .= '<frais_livraison_supp>'.$item->additional_shipping_cost.'</frais_livraison_supp>';
if(isset($item->realquantity)){
if((int)$item->realquantity > 0) {
$this->_xml .= '<disponible>Oui</disponible>';
$this->_xml .= '<stock>'.(int)$item->realquantity.'</stock>';
} else {
$this->_xml .= '<disponible>Non</disponible>';
}
}
$this->_xml.='</produit>';
}
$this->_xml .= '</catalogue>';
}
}
/******************************************************************************************************************************
* Renvoi l'id attribute default d'un produit
******************************************************************************************************************************/
public function getDefaultAttributeId($product_id)
{
$sql = 'SELECT p.`cache_default_attribute`
FROM `'._DB_PREFIX_.'product` p
WHERE p.`id_product` ='.$product_id;
$result = Db::getInstance()->executeS($sql);
return $result[0]['cache_default_attribute'];
}
/******************************************************************************************************************************
* Retire les caractères MAC
******************************************************************************************************************************/
public function sanitize($str)
{
$str = preg_replace_callback('#[\\xA1-\\xFF](?![\\x80-\\xBF]{2,})#',
function ($matches){return utf8_encode($matches[0]);},
$str
);
return htmlentities(str_replace('', '', $str));
}
/******************************************************************************************************************************
* Enlève les tags des URLs pour le catalogue CRITEO
******************************************************************************************************************************/
public function formatUrl($url, $name = NULL)
{
if (array_key_exists($this->_type, $this->tags)) {
$tags = $this->tags[$this->_type];
$url .= '?'.$tags['utm'];
}
return $url;
}
/******************************************************************************************************************************
* Récupère le nom d'un fabricant (sans tenir compte de la row is_active)
******************************************************************************************************************************/
public function getManufacturerNameById($m_id) {
return Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('
SELECT `name`
FROM `'._DB_PREFIX_.'manufacturer`
WHERE `id_manufacturer` = '.(int)$m_id.'
');
}
}