· 9 years ago · Oct 04, 2016, 01:36 PM
1<?php
2/*
3Licensed to the Apache Software Foundation (ASF) under one
4or more contributor license agreements. See the NOTICE file
5distributed with this work for additional information
6regarding copyright ownership. The ASF licenses this file
7to you under the Apache License, Version 2.0 (the
8"License"); you may not use this file except in compliance
9with the License. You may obtain a copy of the License at
10
11http://www.apache.org/licenses/LICENSE-2.0
12
13Unless required by applicable law or agreed to in writing,
14software distributed under the License is distributed on an
15"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16KIND, either express or implied. See the License for the
17specific language governing permissions and limitations
18under the License.
19*/
20
21require(dirname(__FILE__).'/gcategories.class.php');
22require(dirname(__FILE__).'/glangandcurrency.class.php');
23
24class GShoppingFlux extends Module
25{
26 private $_html = '';
27 private $user_groups;
28
29 const CHARSET = 'UTF-8';
30 const REPLACE_FLAGS = ENT_COMPAT;
31
32 public function __construct()
33 {
34 $this->name = 'gshoppingflux';
35 $this->tab = 'smart_shopping';
36 $this->version = '1.6.4';
37 $this->author = 'Dim00z';
38
39 $this->bootstrap = true;
40 parent::__construct();
41
42 $this->page = basename(__FILE__, '.php');
43 $this->displayName = $this->l('Google Shopping Flux');
44 $this->description = $this->l('Export your products to Google Merchant Center, easily.');
45
46 $this->need_instance = 0;
47 $this->ps_versions_compliancy = array('min' => '1.5.0.0', 'max' => _PS_VERSION_);
48 $this->uri = ToolsCore::getCurrentUrlProtocolPrefix().$this->context->shop->domain_ssl.$this->context->shop->physical_uri;
49 if(empty($this->context->shop->domain_ssl))
50 $this->uri = ToolsCore::getCurrentUrlProtocolPrefix().$this->context->shop->domain.$this->context->shop->physical_uri;
51 $this->categories_values = array();
52
53 }
54
55 public function install($delete_params = true)
56 {
57 if (!parent::install()
58 || !$this->registerHook('actionObjectCategoryAddAfter')
59 || !$this->registerHook('actionObjectCategoryDeleteAfter')
60 || !$this->registerHook('actionShopDataDuplication')
61 || !$this->installDb())
62 return false;
63
64 $shops = Shop::getShops(true, null, true);
65 foreach ($shops as $shop_id) {
66 $shop_group_id = Shop::getGroupFromShop($shop_id);
67
68 if (!$this->initDb((int)$shop_id))
69 return false;
70
71 if ($delete_params)
72 if (!Configuration::updateValue('GS_PRODUCT_TYPE', '', true, (int)$shop_group_id, (int)$shop_id)
73 || !Configuration::updateValue('GS_DESCRIPTION', 'short', false, (int)$shop_group_id, (int)$shop_id)
74 || !Configuration::updateValue('GS_SHIPPING_PRICE', '0.00', false, (int)$shop_group_id, (int)$shop_id)
75 || !Configuration::updateValue('GS_SHIPPING_COUNTRY', 'UK', false, (int)$shop_group_id, (int)$shop_id)
76 || !Configuration::updateValue('GS_IMG_TYPE', 'large_default', false, (int)$shop_group_id, (int)$shop_id)
77 || !Configuration::updateValue('GS_MPN_TYPE', 'reference', false, (int)$shop_group_id, (int)$shop_id)
78 || !Configuration::updateValue('GS_GENDER', '', false, (int)$shop_group_id, (int)$shop_id)
79 || !Configuration::updateValue('GS_AGE_GROUP', '', false, (int)$shop_group_id, (int)$shop_id)
80 || !Configuration::updateValue('GS_ATTRIBUTES', '0', false, (int)$shop_group_id, (int)$shop_id)
81 || !Configuration::updateValue('GS_COLOR', '', false, (int)$shop_group_id, (int)$shop_id)
82 || !Configuration::updateValue('GS_MATERIAL', '', false, (int)$shop_group_id, (int)$shop_id)
83 || !Configuration::updateValue('GS_PATTERN', '', false, (int)$shop_group_id, (int)$shop_id)
84 || !Configuration::updateValue('GS_SIZE', '', false, (int)$shop_group_id, (int)$shop_id)
85 || !Configuration::updateValue('GS_EXPORT_MIN_PRICE', '0.00', false, (int)$shop_group_id, (int)$shop_id)
86 || !Configuration::updateValue('GS_NO_GTIN', '1', false, (int)$shop_group_id, (int)$shop_id)
87 || !Configuration::updateValue('GS_NO_BRAND', '1', false, (int)$shop_group_id, (int)$shop_id)
88 || !Configuration::updateValue('GS_ID_EXISTS_TAG', '1', false, (int)$shop_group_id, (int)$shop_id)
89 || !Configuration::updateValue('GS_EXPORT_NAP', '0', false, (int)$shop_group_id, (int)$shop_id)
90 || !Configuration::updateValue('GS_QUANTITY', '1', false, (int)$shop_group_id, (int)$shop_id)
91 || !Configuration::updateValue('GS_FEATURED_PRODUCTS', '1', false, (int)$shop_group_id, (int)$shop_id)
92 || !Configuration::updateValue('GS_GEN_FILE_IN_ROOT', '1', false, (int)$shop_group_id, (int)$shop_id))
93 return false;
94 }
95
96 // Get generation file route
97 if (!is_dir(dirname(__FILE__).'/export'))
98 @mkdir(dirname(__FILE__).'/export', 0755, true);
99
100 @chmod(dirname(__FILE__).'/export', 0755);
101
102 return true;
103 }
104
105 public function installDb()
106 {
107 return (Db::getInstance()->execute('
108 CREATE TABLE IF NOT EXISTS `'._DB_PREFIX_.'gshoppingflux` (
109 `id_gcategory` INT(11) UNSIGNED NOT NULL,
110 `export` INT(11) UNSIGNED NOT NULL,
111 `condition` VARCHAR( 12 ) NOT NULL,
112 `availability` VARCHAR( 12 ) NOT NULL,
113 `gender` VARCHAR( 8 ) NOT NULL,
114 `age_group` VARCHAR( 8 ) NOT NULL,
115 `color` VARCHAR( 64 ) NOT NULL,
116 `material` VARCHAR( 64 ) NOT NULL,
117 `pattern` VARCHAR( 64 ) NOT NULL,
118 `size` VARCHAR( 64 ) NOT NULL,
119 `id_shop` INT(11) UNSIGNED NOT NULL,
120 INDEX (`id_gcategory`, `id_shop`)
121 ) ENGINE = '._MYSQL_ENGINE_.' CHARACTER SET utf8 COLLATE utf8_general_ci;')
122
123 && Db::getInstance()->execute('
124 CREATE TABLE IF NOT EXISTS `'._DB_PREFIX_.'gshoppingflux_lc` (
125 `id_glang` INT(11) UNSIGNED NOT NULL,
126 `id_currency` VARCHAR(255) NOT NULL,
127 `tax_included` TINYINT(1) NOT NULL,
128 `id_shop` INT(11) UNSIGNED NOT NULL,
129 INDEX (`id_glang`, `id_shop`)
130 ) ENGINE = '._MYSQL_ENGINE_.' CHARACTER SET utf8 COLLATE utf8_general_ci;')
131
132 && Db::getInstance()->execute('
133 CREATE TABLE IF NOT EXISTS `'._DB_PREFIX_.'gshoppingflux_lang` (
134 `id_gcategory` INT(11) UNSIGNED NOT NULL,
135 `id_lang` INT(11) UNSIGNED NOT NULL,
136 `id_shop` INT(11) UNSIGNED NOT NULL,
137 `gcategory` VARCHAR( 255 ) NOT NULL,
138 INDEX (`id_gcategory`, `id_lang`, `id_shop`)
139 ) ENGINE = '._MYSQL_ENGINE_.' CHARACTER SET utf8 COLLATE utf8_general_ci;'));
140 }
141
142 public function initDb($id_shop)
143 {
144 $languages = $this->context->controller->getLanguages();
145 $id_lang = $this->context->language->id;
146 $str = array();
147
148 $shop = new Shop($id_shop);
149 $root = Category::getRootCategory($id_lang, $shop);
150
151 $categs = Db::getInstance()->executeS('
152 SELECT c.id_category, c.id_parent, c.active
153 FROM '._DB_PREFIX_.'category c
154 INNER JOIN `'._DB_PREFIX_.'category_shop` cs ON (cs.id_category=c.id_category AND cs.id_shop='.(int)$id_shop.')
155 ORDER BY c.id_category ASC, c.level_depth ASC, cs.position ASC;'
156 );
157
158 foreach ($categs as $kc => $cat) {
159
160 foreach ($languages as $key => $lang){
161 $str[$lang['id_lang']] = '';
162 }
163
164 $condition = '';
165 $availability = '';
166 $gender = '';
167 $age_group = '';
168 $color = '';
169 $material = '';
170 $pattern = '';
171 $size = '';
172
173 $cat_exists = GCategories::get($cat['id_category'], $id_lang, $id_shop);
174 if ((!count($cat_exists) || $cat_exists===false) && ($cat['id_category'] > 0)) {
175
176 if ($root->id_category == $cat['id_category']) {
177 foreach ($languages as $key => $lang)
178 $str[$lang['id_lang']] = $this->l('Google Category Example > Google Sub-Category Example');
179
180 $condition = 'new';
181 $availability = 'in stock';
182 }
183 GCategories::add($cat['id_category'], $str, $cat['active'], $condition, $availability, $gender, $age_group, $color, $material, $pattern, $size, $id_shop);
184 }
185 }
186
187 foreach($languages as $lang){
188 if(!count(GLangAndCurrency::getLangCurrencies($lang['id_lang'], $id_shop)))
189 GLangAndCurrency::add($lang['id_lang'], $this->context->currency->id, 1, $id_shop);
190 }
191
192 return true;
193 }
194
195 public function uninstall($delete_params = true)
196 {
197 if (!parent::uninstall())
198 return false;
199
200 if ($delete_params)
201 if (!$this->uninstallDB() || !Configuration::deleteByName('GS_PRODUCT_TYPE') || !Configuration::deleteByName('GS_DESCRIPTION') || !Configuration::deleteByName('GS_SHIPPING_PRICE') || !Configuration::deleteByName('GS_SHIPPING_COUNTRY') || !Configuration::deleteByName('GS_IMG_TYPE') || !Configuration::deleteByName('GS_MPN_TYPE') || !Configuration::deleteByName('GS_GENDER') || !Configuration::deleteByName('GS_AGE_GROUP') || !Configuration::deleteByName('GS_ATTRIBUTES') || !Configuration::deleteByName('GS_COLOR') || !Configuration::deleteByName('GS_MATERIAL') || !Configuration::deleteByName('GS_PATTERN') || !Configuration::deleteByName('GS_SIZE') || !Configuration::deleteByName('GS_EXPORT_MIN_PRICE') || !Configuration::deleteByName('GS_NO_GTIN') || !Configuration::deleteByName('GS_NO_BRAND') || !Configuration::deleteByName('GS_ID_EXISTS_TAG') || !Configuration::deleteByName('GS_EXPORT_NAP') || !Configuration::deleteByName('GS_QUANTITY') || !Configuration::deleteByName('GS_FEATURED_PRODUCTS') || !Configuration::deleteByName('GS_GEN_FILE_IN_ROOT'))
202 return false;
203
204 return true;
205 }
206
207 private function uninstallDb()
208 {
209 Db::getInstance()->execute('DROP TABLE `'._DB_PREFIX_.'gshoppingflux`');
210 Db::getInstance()->execute('DROP TABLE `'._DB_PREFIX_.'gshoppingflux_lc`');
211 Db::getInstance()->execute('DROP TABLE `'._DB_PREFIX_.'gshoppingflux_lang`');
212 return true;
213 }
214
215 public function reset()
216 {
217 if (!$this->uninstall(false))
218 return false;
219 if (!$this->install(false))
220 return false;
221
222 return true;
223 }
224
225 public function hookActionObjectCategoryAddAfter($params)
226 {
227 $shops = Shop::getShops(true, null, true);
228 foreach ($shops as $id_shop)
229 $this->initDb($id_shop);
230 }
231
232 public function hookActionObjectCategoryDeleteAfter($params)
233 {
234 $shops = Shop::getShops(true, null, true);
235 foreach ($shops as $id_shop)
236 $this->initDb($id_shop);
237 }
238
239 public function hookActionShopDataDuplication($params)
240 {
241 $gcategories = Db::getInstance()->executeS('
242 SELECT *
243 FROM '._DB_PREFIX_.'gshoppingflux
244 WHERE id_shop = '.(int)$params['old_id_shop']
245 );
246
247 foreach ($gcategories as $id => $gcateg) {
248 Db::getInstance()->insert('gshoppingflux', array(
249 'id_gcategory' => null,
250 'id_shop' => (int)$params['new_id_shop'],
251 ));
252
253 $gcategories[$id]['new_id_gcategory'] = Db::getInstance()->Insert_ID();
254 }
255
256 foreach ($gcategories as $id => $gcateg) {
257 $lang = Db::getInstance()->executeS('
258 SELECT id_lang, '.(int)$params['new_id_shop'].', gcategory
259 FROM '._DB_PREFIX_.'gshoppingflux_lang
260 WHERE id_gcategory = '.(int)$gcateg['id_gcategory'].' AND id_shop = '.(int)$params['old_id_shop']);
261
262 foreach ($lang as $l)
263 Db::getInstance()->insert('gshoppingflux_lang', array(
264 'id_gcategory' => (int)$gcateg['new_id_gcategory'],
265 'id_lang' => (int)$l['id_lang'],
266 'id_shop' => (int)$params['new_id_shop'],
267 'gcategory' => (int)$l['gcategory'],
268 ));
269 }
270 }
271
272 public function getContent()
273 {
274 $id_lang = $this->context->language->id;
275 $languages = $this->context->controller->getLanguages();
276 $shops = Shop::getShops(true, null, true);
277 $shop_id = $this->context->shop->id;
278 $shop_group_id = Shop::getGroupFromShop($shop_id);
279
280 $gcategories = Tools::getValue('gcategory') ? array_filter(Tools::getValue('gcategory'), 'strlen') : array();
281
282 if (count($shops) > 1 && !isset($shop_id)) {
283 $this->_html .= $this->getWarningMultishopHtml();
284 return $this->_html;
285 }
286
287 if (Shop::isFeatureActive())
288 $this->_html .= $this->getCurrentShopInfoMsg();
289
290 if (Tools::isSubmit('submitFluxOptions')) {
291 $errors_update_shops = array();
292 $updated = true;
293 $product_type_lang = Tools::getValue('product_type');
294 foreach ($languages as $k => $lang)
295 $product_type[$lang['id_lang']] = $product_type_lang[$k];
296
297 $updated &= Configuration::updateValue('GS_PRODUCT_TYPE', $product_type, false, (int)$shop_group_id, (int)$shop_id);
298 $updated &= Configuration::updateValue('GS_DESCRIPTION', Tools::getValue('description'), false, (int)$shop_group_id, (int)$shop_id);
299 $updated &= Configuration::updateValue('GS_SHIPPING_PRICE', (float)Tools::getValue('shipping_price'), false, (int)$shop_group_id, (int)$shop_id);
300 $updated &= Configuration::updateValue('GS_SHIPPING_COUNTRY', Tools::getValue('shipping_country'), false, (int)$shop_group_id, (int)$shop_id);
301 $updated &= Configuration::updateValue('GS_IMG_TYPE', Tools::getValue('img_type'), false, (int)$shop_group_id, (int)$shop_id);
302 $updated &= Configuration::updateValue('GS_MPN_TYPE', Tools::getValue('mpn_type'), false, (int)$shop_group_id, (int)$shop_id);
303 $updated &= Configuration::updateValue('GS_GENDER', Tools::getValue('gender'), false, (int)$shop_group_id, (int)$shop_id);
304 $updated &= Configuration::updateValue('GS_AGE_GROUP', Tools::getValue('age_group'), false, (int)$shop_group_id, (int)$shop_id);
305 $updated &= Configuration::updateValue('GS_ATTRIBUTES', Tools::getValue('export_attributes'), false, (int)$shop_group_id, (int)$shop_id);
306 $updated &= Configuration::updateValue('GS_COLOR', implode(';', Tools::getValue('color')), false, (int)$shop_group_id, (int)$shop_id);
307 $updated &= Configuration::updateValue('GS_MATERIAL', implode(';', Tools::getValue('material')), false, (int)$shop_group_id, (int)$shop_id);
308 $updated &= Configuration::updateValue('GS_PATTERN', implode(';', Tools::getValue('pattern')), false, (int)$shop_group_id, (int)$shop_id);
309 $updated &= Configuration::updateValue('GS_SIZE', implode(';', Tools::getValue('size')), false, (int)$shop_group_id, (int)$shop_id);
310 $updated &= Configuration::updateValue('GS_EXPORT_MIN_PRICE', (float)Tools::getValue('export_min_price'), false, (int)$shop_group_id, (int)$shop_id);
311 $updated &= Configuration::updateValue('GS_NO_GTIN', (bool)Tools::getValue('no_gtin'), false, (int)$shop_group_id, (int)$shop_id);
312 $updated &= Configuration::updateValue('GS_NO_BRAND', (bool)Tools::getValue('no_brand'), false, (int)$shop_group_id, (int)$shop_id);
313 $updated &= Configuration::updateValue('GS_ID_EXISTS_TAG', (bool)Tools::getValue('id_exists_tag'), false, (int)$shop_group_id, (int)$shop_id);
314 $updated &= Configuration::updateValue('GS_EXPORT_NAP', (bool)Tools::getValue('export_nap'), false, (int)$shop_group_id, (int)$shop_id);
315 $updated &= Configuration::updateValue('GS_QUANTITY', (bool)Tools::getValue('quantity'), false, (int)$shop_group_id, (int)$shop_id);
316 $updated &= Configuration::updateValue('GS_FEATURED_PRODUCTS', (bool)Tools::getValue('featured_products'), false, (int)$shop_group_id, (int)$shop_id);
317 $updated &= Configuration::updateValue('GS_GEN_FILE_IN_ROOT', (bool)Tools::getValue('gen_file_in_root'), false, (int)$shop_group_id, (int)$shop_id);
318
319 if (!$updated) {
320 $shop = new Shop($shop_id);
321 $errors_update_shops[] = $shop->name;
322 }
323
324 if (!count($errors_update_shops)) {
325 $this->confirm = $this->l('The settings have been updated.');
326 $this->generateXMLFiles(0, $shop_id, $shop_group_id);
327 }else{
328 $this->_html .= $this->displayError(sprintf($this->l('Unable to update settings for the following shop: %s'), implode(', ', $errors_update_shops)));
329 }
330 }
331
332 elseif (Tools::isSubmit('updateCategory')) {
333 $id_gcategory = (int)Tools::getValue('id_gcategory', 0);
334 $export = (int)Tools::getValue('export', 0);
335 $condition = Tools::getValue('condition');
336 $availability = Tools::getValue('availability');
337 $gender = Tools::getValue('gender');
338 $age_group = Tools::getValue('age_group');
339 $color = implode(";", Tools::getValue('color'));
340 $material = implode(";", Tools::getValue('material'));
341 $pattern = implode(";", Tools::getValue('pattern'));
342 $size = implode(";", Tools::getValue('size'));
343 $id_shop = (int)Shop::getContextShopID();
344
345 if (Tools::isSubmit('updatecateg')) {
346 $gcateg = array();
347 foreach (Language::getLanguages(false) as $lang) {
348 $gcateg[$lang['id_lang']] = Tools::getValue('gcategory_'.(int)$lang['id_lang']);
349 }
350
351 GCategories::update($id_gcategory, $gcateg, $export, $condition, $availability, $gender, $age_group, $color, $material, $pattern, $size, $id_shop);
352 $this->confirm = $this->l('Google category has been updated.');
353 }
354 $this->generateXMLFiles(0, $shop_id, $shop_group_id);
355 }
356
357 elseif (Tools::isSubmit('updateLanguage')) {
358 $id_glang = (int)Tools::getValue('id_glang', 0);
359 $currencies = implode(";", Tools::getValue('currencies'));
360 $tax_included = (int)Tools::getValue('tax_included', 0);
361 $export = (int)Tools::getValue('active', 0);
362 if (Tools::isSubmit('updatelang')) {
363 GLangAndCurrency::update($id_glang, $currencies, $tax_included, (int)Shop::getContextShopID());
364 if(count(Tools::getValue('currencies'))>1)
365 $this->confirm = $this->l('Selected currencies for this language have been saved.');
366 else
367 $this->confirm = $this->l('Selected currency for this language has been saved.');
368 }
369 if ($export) $this->generateXMLFiles($id_glang, $shop_id, $shop_group_id);
370 else $this->_html .= $this->displayConfirmation(html_entity_decode($this->confirm));
371 }
372
373 $gcategories = GCategories::gets((int)$id_lang, null, (int)$shop_id);
374 if (!count($gcategories))
375 return $this->_html;
376
377 if ((Tools::getIsset('updategshoppingflux') || Tools::getIsset('statusgshoppingflux')) && !Tools::getValue('updategshoppingflux')){
378 $this->_html .= $this->renderCategForm();
379 $this->_html .= $this->renderCategList();
380 } else if ((Tools::getIsset('updategshoppingflux_lc') || Tools::getIsset('statusgshoppingflux_lc')) && !Tools::getValue('updategshoppingflux_lc')){
381 $this->_html .= $this->renderLangForm();
382 $this->_html .= $this->renderLangList();
383 } else {
384 $this->_html .= $this->renderForm();
385 $this->_html .= $this->renderCategList();
386 $this->_html .= $this->renderLangList();
387 $this->_html .= $this->renderInfo();
388 }
389
390 return $this->_html;
391 }
392
393 private function generateXMLFiles($lang_id=0, $shop_id, $shop_group_id)
394 {
395 if(isset($lang_id) && $lang_id!=0){
396 $count = $this->generateLangFileList($lang_id, $shop_id);
397 $languages = GLangAndCurrency::getLangCurrencies($lang_id, $shop_id);
398 }else{
399 $count = $this->generateShopFileList($shop_id);
400 $languages = GLangAndCurrency::getAllLangCurrencies(1);
401 }
402
403 foreach ($languages as $i => $lang) {
404 $currencies = explode(";",$lang['id_currency']);
405 foreach($currencies as $curr){
406 $currency = new Currency($curr);
407 if (Configuration::get('GS_GEN_FILE_IN_ROOT', 0, $shop_group_id, $shop_id) == 1)
408 $get_file_url = $this->uri.$this->_getOutputFileName($lang['iso_code'], $currency->iso_code, $shop_id);
409 else
410 $get_file_url = $this->uri.'modules/'.$this->name.'/export/'.$this->_getOutputFileName($lang['iso_code'], $currency->iso_code, $shop_id);
411
412 $this->confirm .= '<br /> <a href="'.$get_file_url.'" target="_blank">'.$get_file_url.'</a> : '.($count[$i]['nb_products'] - $count[$i]['nb_combinations']).' '.$this->l('products exported');
413
414 if ($count[$i]['nb_combinations'] > 0) {
415 $this->confirm .= ': '.$count[$i]['nb_prod_w_attr'].' '.$this->l('products with attributes');
416 $this->confirm .= ', '.$count[$i]['nb_combinations'].' '.$this->l('attributes combinations');
417 $this->confirm .= '.<br/> '.$this->l('Total').': '.($count[$i]['nb_products']).' '.$this->l('exported products');
418
419 if ($count[$i]['non_exported_products'] > 0)
420 $this->confirm .= ', '.$this->l('and').' '.$count[$i]['non_exported_products'].' '.$this->l('not-exported products (non-available)');
421 $this->confirm .= '.';
422 }
423
424 else
425 $this->confirm .= '.';
426 }
427 }
428 $this->_html .= $this->displayConfirmation(html_entity_decode($this->confirm));
429 return;
430 }
431
432 private function getWarningMultishopHtml()
433 {
434 return '<p class="alert alert-warning">'.$this->l('You cannot manage Google categories from a "All Shops" or a "Group Shop" context, select directly the shop you want to edit').'</p>';
435 }
436
437 private function getCurrentShopInfoMsg()
438 {
439 $shop_info = null;
440
441 if (Shop::getContext() == Shop::CONTEXT_SHOP)
442 $shop_info = sprintf($this->l('The modifications will be applied to shop: %s'), $this->context->shop->name);
443 else if (Shop::getContext() == Shop::CONTEXT_GROUP)
444 $shop_info = sprintf($this->l('The modifications will be applied to this group: %s'), Shop::getContextShopGroup()->name);
445 else
446 $shop_info = $this->l('The modifications will be applied to all shops');
447
448 return '<div class="alert alert-info">'.$shop_info.'</div>';
449 }
450
451 public function getShopFeatures($id_lang, $id_shop)
452 {
453 return Db::getInstance()->executeS('
454 SELECT fl.* FROM '._DB_PREFIX_.'feature f
455 LEFT JOIN '._DB_PREFIX_.'feature_lang fl ON (fl.id_feature = f.id_feature)
456 LEFT JOIN '._DB_PREFIX_.'feature_shop fs ON (fs.id_feature = f.id_feature)
457 WHERE fl.id_lang = '.(int)$id_lang.' AND fs.id_shop = '.(int)$id_shop.'
458 ORDER BY f.id_feature ASC'
459 );
460 }
461
462 public function getShopAttributes($id_lang, $id_shop)
463 {
464 return Db::getInstance()->executeS('
465 SELECT agl.* FROM '._DB_PREFIX_.'attribute_group_lang agl
466 LEFT JOIN '._DB_PREFIX_.'attribute_group_shop ags ON (ags.id_attribute_group = agl.id_attribute_group)
467 WHERE agl.id_lang = '.(int)$id_lang.' AND ags.id_shop = '.(int)$id_shop.'
468 ORDER BY ags.id_attribute_group ASC'
469 );
470 }
471
472 public function getProductFeatures($id_product, $id_lang, $id_shop)
473 {
474 return Db::getInstance()->executeS('
475 SELECT fl.*, fv.value FROM '._DB_PREFIX_.'feature_product fp
476 LEFT JOIN '._DB_PREFIX_.'feature_lang fl ON (fl.id_feature = fp.id_feature)
477 LEFT JOIN '._DB_PREFIX_.'feature_shop fs ON (fs.id_feature = fp.id_feature)
478 LEFT JOIN '._DB_PREFIX_.'feature_value_lang fv ON (fv.id_feature_value = fp.id_feature_value AND fv.id_lang = fl.id_lang)
479 WHERE fp.id_product = '.(int)$id_product.' AND fl.id_lang = '.(int)$id_lang.' AND fs.id_shop = '.(int)$id_shop.'
480 ORDER BY fp.id_feature ASC'
481 );
482 }
483
484 public function renderForm()
485 {
486 $helper = new HelperForm();
487 $helper->show_toolbar = false;
488 $helper->table = $this->table;
489
490 $lang = new Language((int)Configuration::get('PS_LANG_DEFAULT'));
491 $helper->default_form_language = $lang->id;
492 $helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') ? Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') : 0;
493 $this->fields_form = array();
494 $helper->module = $this;
495 $helper->identifier = $this->identifier;
496 $helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false).'&configure='.$this->name.'&tab_module='.$this->tab.'&module_name='.$this->name;
497 $helper->token = Tools::getAdminTokenLite('AdminModules');
498 $helper->tpl_vars = array(
499 'fields_value' => $this->getConfigFieldsValues($this->context->shop->id),
500 'id_language' => $this->context->language->id,
501 'languages' => $this->context->controller->getLanguages()
502 );
503
504 $id_lang = $this->context->language->id;
505 $id_shop = $this->context->shop->id;
506 $img_types = ImageType::getImagesTypes('products');
507
508 $features = array(
509 array(
510 'id_feature' => '',
511 'name' => $this->l('Product feature doesn\'t exist')
512 )
513 );
514 $features = array_merge($features, $this->getShopFeatures($id_lang, $id_shop));
515 $descriptions = array(
516 array(
517 'id_desc' => 'short',
518 'name' => $this->l('Short description')
519 ),
520 array(
521 'id_desc' => 'long',
522 'name' => $this->l('Long description')
523 ),
524 array(
525 'id_desc' => 'meta',
526 'name' => $this->l('Meta description')
527 )
528 );
529 $mpn_types = array(
530 array(
531 'id_mpn' => 'reference',
532 'name' => $this->l('Reference')
533 ),
534 array(
535 'id_mpn' => 'supplier_reference',
536 'name' => $this->l('Supplier reference')
537 )
538 );
539 $form_desc = html_entity_decode($this->l('Please visit and read the <a href="http://support.google.com/merchants/answer/188494" target="_blank">Google Shopping Products Feed Specification</a> if you don\'t know how to configure these options. <br/> If all your shop products match the same Google Shopping category, you can attach it to your home category in the table below, sub-categories will automatically get the same setting. No need to fill each Google category field. <br/> Products in categories with no Google category specified are exported in the Google Shopping category linked to the nearest parent.'));
540
541 $fields_form = array(
542 'form' => array(
543 'legend' => array(
544 'title' => $this->l('Parameters'),
545 'icon' => 'icon-cogs'
546 ),
547 'input' => array(
548 array(
549 'type' => 'text',
550 'label' => $this->l('Default product type'),
551 'name' => 'product_type[]',
552 //'class' => 'fixed-width-xl',
553 'lang' => true,
554 'desc' => $this->l('Your shop\'s default product type, ie: if you sell pants and shirts, and your main categories are "Men", "Women", "Kids", enter "Clothing" here. That will be exported as your shop main category. This setting is optional and can be left empty. Besides the module requires that at least main category of your shop is correctly linked to a Google product category.')
555 ),
556 array(
557 'type' => 'select',
558 'label' => $this->l('Description type'),
559 'name' => 'description',
560 'default_value' => $helper->tpl_vars['fields_value']['description'],
561 'options' => array(
562 //'default' => array('value' => 0, 'label' => $this->l('Choose description type')),
563 'query' => $descriptions,
564 'id' => 'id_desc',
565 'name' => 'name'
566 )
567 ),
568 array(
569 'type' => 'text',
570 'label' => $this->l('Shipping price'),
571 'name' => 'shipping_price',
572 'class' => 'fixed-width-xs',
573 'prefix' => $this->context->currency->sign
574 ),
575 array(
576 'type' => 'text',
577 'label' => $this->l('Shipping country'),
578 'name' => 'shipping_country',
579 'class' => 'fixed-width-xs'
580 //'suffix' => strtoupper($this->context->language->iso_code),
581 ),
582 array(
583 'type' => 'select',
584 'label' => $this->l('Images type'),
585 'name' => 'img_type',
586 'default_value' => $helper->tpl_vars['fields_value']['img_type'],
587 'options' => array(
588 //'default' => array('value' => 0, 'label' => $this->l('Choose image type')),
589 'query' => $img_types,
590 'id' => 'name',
591 'name' => 'name'
592 )
593 ),
594 array(
595 'type' => 'select',
596 'label' => $this->l('Manufacturers References type (MPN)'),
597 'name' => 'mpn_type',
598 'default_value' => $helper->tpl_vars['fields_value']['mpn_type'],
599 'options' => array(
600 'query' => $mpn_types,
601 'id' => 'id_mpn',
602 'name' => 'name'
603 )
604 ),
605 array(
606 'type' => 'text',
607 'label' => $this->l('Minimum product price'),
608 'name' => 'export_min_price',
609 'class' => 'fixed-width-xs',
610 'prefix' => $this->context->currency->sign,
611 'desc' => $this->l('Products at lower price are not exported. Enter 0.00 for no use.'),
612 'required' => true
613 ),
614 array(
615 'type' => 'select',
616 'label' => $this->l('Products gender feature'),
617 'name' => 'gender',
618 'default_value' => $helper->tpl_vars['fields_value']['gender'],
619 'options' => array(
620 'query' => $features,
621 'id' => 'id_feature',
622 'name' => 'name'
623 )
624 ),
625 array(
626 'type' => 'select',
627 'label' => $this->l('Products age group feature'),
628 'name' => 'age_group',
629 'default_value' => $helper->tpl_vars['fields_value']['age_group'],
630 'options' => array(
631 'query' => $features,
632 'id' => 'id_feature',
633 'name' => 'name'
634 )
635 ),
636 array(
637 'type' => 'select',
638 'multiple' => true,
639 'label' => $this->l('Products color feature'),
640 'name' => 'color[]',
641 'default_value' => $helper->tpl_vars['fields_value']['color[]'],
642 'options' => array(
643 'query' => $features,
644 'id' => 'id_feature',
645 'name' => 'name'
646 ),
647 'desc' => $this->l('Hold [Ctrl] key pressed to select multiple color features.')
648 ),
649 array(
650 'type' => 'select',
651 'multiple' => true,
652 'label' => $this->l('Products material feature'),
653 'name' => 'material[]',
654 'default_value' => $helper->tpl_vars['fields_value']['material[]'],
655 'options' => array(
656 'query' => $features,
657 'id' => 'id_feature',
658 'name' => 'name'
659 ),
660 'desc' => $this->l('Hold [Ctrl] key pressed to select multiple material features.')
661 ),
662 array(
663 'type' => 'select',
664 'multiple' => true,
665 'label' => $this->l('Products pattern feature'),
666 'name' => 'pattern[]',
667 'default_value' => $helper->tpl_vars['fields_value']['pattern[]'],
668 'options' => array(
669 'query' => $features,
670 'id' => 'id_feature',
671 'name' => 'name'
672 ),
673 'desc' => $this->l('Hold [Ctrl] key pressed to select multiple pattern features.')
674 ),
675 array(
676 'type' => 'select',
677 'multiple' => true,
678 'label' => $this->l('Products size feature'),
679 'name' => 'size[]',
680 'default_value' => $helper->tpl_vars['fields_value']['size[]'],
681 'options' => array(
682 'query' => $features,
683 'id' => 'id_feature',
684 'name' => 'name'
685 ),
686 'desc' => $this->l('Hold [Ctrl] key pressed to select multiple size features.')
687 ),
688 array(
689 'type' => 'switch',
690 'label' => $this->l('Export attributes combinations'),
691 'name' => 'export_attributes',
692 'is_bool' => true,
693 'values' => array(
694 array(
695 'id' => 'active_on',
696 'value' => 1,
697 'label' => $this->l('Enabled')
698 ),
699 array(
700 'id' => 'active_off',
701 'value' => 0,
702 'label' => $this->l('Disabled')
703 )
704 ),
705 'desc' => $this->l('If checked, one product is exported for each attributes combination. Products should have at least one attribute filled in order to be exported as combinations.')
706 ),
707 array(
708 'type' => 'switch',
709 'label' => $this->l('Export products with no GTIN code'),
710 'name' => 'no_gtin',
711 'is_bool' => true,
712 'values' => array(
713 array(
714 'id' => 'active_on',
715 'value' => 1,
716 'label' => $this->l('Enabled')
717 ),
718 array(
719 'id' => 'active_off',
720 'value' => 0,
721 'label' => $this->l('Disabled')
722 )
723 )
724 ),
725 array(
726 'type' => 'switch',
727 'label' => $this->l('Export products with no brand'),
728 'name' => 'no_brand',
729 'is_bool' => true,
730 'values' => array(
731 array(
732 'id' => 'active_on',
733 'value' => 1,
734 'label' => $this->l('Enabled')
735 ),
736 array(
737 'id' => 'active_off',
738 'value' => 0,
739 'label' => $this->l('Disabled')
740 )
741 )
742 ),
743 array(
744 'type' => 'switch',
745 'label' => $this->l('Set <identifier_exists> tag to FALSE'),
746 'name' => 'id_exists_tag',
747 'is_bool' => true,
748 'values' => array(
749 array(
750 'id' => 'active_on',
751 'value' => 1,
752 'label' => $this->l('Enabled')
753 ),
754 array(
755 'id' => 'active_off',
756 'value' => 0,
757 'label' => $this->l('Disabled')
758 )
759 )
760 ),
761 array(
762 'type' => 'switch',
763 'label' => $this->l('Export non-available products'),
764 'name' => 'export_nap',
765 'is_bool' => true,
766 'values' => array(
767 array(
768 'id' => 'active_on',
769 'value' => 1,
770 'label' => $this->l('Enabled')
771 ),
772 array(
773 'id' => 'active_off',
774 'value' => 0,
775 'label' => $this->l('Disabled')
776 )
777 )
778 ),
779 array(
780 'type' => 'switch',
781 'label' => $this->l('Export product quantity'),
782 'name' => 'quantity',
783 'is_bool' => true,
784 'values' => array(
785 array(
786 'id' => 'active_on',
787 'value' => 1,
788 'label' => $this->l('Enabled')
789 ),
790 array(
791 'id' => 'active_off',
792 'value' => 0,
793 'label' => $this->l('Disabled')
794 )
795 )
796 ),
797 array(
798 'type' => 'switch',
799 'label' => $this->l('Export "On Sale" indication'),
800 'name' => 'featured_products',
801 'is_bool' => true,
802 'values' => array(
803 array(
804 'id' => 'active_on',
805 'value' => 1,
806 'label' => $this->l('Enabled')
807 ),
808 array(
809 'id' => 'active_off',
810 'value' => 0,
811 'label' => $this->l('Disabled')
812 )
813 )
814 ),
815 array(
816 'type' => 'switch',
817 'label' => $this->l('Generate the files to the root of the site'),
818 'name' => 'gen_file_in_root',
819 'is_bool' => true,
820 'values' => array(
821 array(
822 'id' => 'active_on',
823 'value' => 1,
824 'label' => $this->l('Enabled')
825 ),
826 array(
827 'id' => 'active_off',
828 'value' => 0,
829 'label' => $this->l('Disabled')
830 )
831 )
832 )
833 ),
834 'description' => $form_desc,
835 'submit' => array(
836 'name' => 'submitFluxOptions',
837 'title' => $this->l('Save & Export')
838 )
839 )
840 );
841
842 return $helper->generateForm(array(
843 $fields_form
844 ));
845 }
846
847 public function getConfigFieldsValues($shop_id)
848 {
849 $shop_group_id = Shop::getGroupFromShop($shop_id);
850 $product_type = array();
851 $description = 'short';
852 $shipping_price = 0;
853 $shipping_country = 'UK';
854 $img_type = 'large_default';
855 $mpn_type = '';
856 $gender = '';
857 $age_group = '';
858 $export_attributes = '';
859 $color = array();
860 $material = array();
861 $pattern = array();
862 $size = array();
863 $export_min_price = 0;
864 $no_gtin = true;
865 $no_brand = true;
866 $id_exists_tag = true;
867 $export_nap = true;
868 $quantity = true;
869 $featured_products = true;
870 $gen_file_in_root = true;
871
872 foreach (Language::getLanguages(false) as $lang)
873 $product_type[$lang['id_lang']] = Configuration::get('GS_PRODUCT_TYPE', $lang['id_lang'], $shop_group_id, $shop_id);
874
875 $description = Configuration::get('GS_DESCRIPTION', 0, $shop_group_id, $shop_id);
876 $shipping_price = (float)Configuration::get('GS_SHIPPING_PRICE', 0, $shop_group_id, $shop_id);
877 $shipping_country = Configuration::get('GS_SHIPPING_COUNTRY', 0, $shop_group_id, $shop_id);
878 $img_type = Configuration::get('GS_IMG_TYPE', 0, $shop_group_id, $shop_id);
879 $mpn_type = Configuration::get('GS_MPN_TYPE', 0, $shop_group_id, $shop_id);
880 $gender = Configuration::get('GS_GENDER', 0, $shop_group_id, $shop_id);
881 $age_group = Configuration::get('GS_AGE_GROUP', 0, $shop_group_id, $shop_id);
882 $export_attributes = Configuration::get('GS_ATTRIBUTES', 0, $shop_group_id, $shop_id);
883 $color = explode(";", Configuration::get('GS_COLOR', 0, $shop_group_id, $shop_id));
884 $material = explode(";", Configuration::get('GS_MATERIAL', 0, $shop_group_id, $shop_id));
885 $pattern = explode(";", Configuration::get('GS_PATTERN', 0, $shop_group_id, $shop_id));
886 $size = explode(";", Configuration::get('GS_SIZE', 0, $shop_group_id, $shop_id));
887 $export_min_price = (float)Configuration::get('GS_EXPORT_MIN_PRICE', 0, $shop_group_id, $shop_id);
888 $no_gtin &= (bool)Configuration::get('GS_NO_GTIN', 0, $shop_group_id, $shop_id);
889 $no_brand &= (bool)Configuration::get('GS_NO_BRAND', 0, $shop_group_id, $shop_id);
890 $id_exists_tag &= (bool)Configuration::get('GS_ID_EXISTS_TAG', 0, $shop_group_id, $shop_id);
891 $export_nap &= (bool)Configuration::get('GS_EXPORT_NAP', 0, $shop_group_id, $shop_id);
892 $quantity &= (bool)Configuration::get('GS_QUANTITY', 0, $shop_group_id, $shop_id);
893 $featured_products &= (bool)Configuration::get('GS_FEATURED_PRODUCTS', 0, $shop_group_id, $shop_id);
894 $gen_file_in_root &= (bool)Configuration::get('GS_GEN_FILE_IN_ROOT', 0, $shop_group_id, $shop_id);
895
896 return array(
897 'product_type[]' => $product_type,
898 'description' => $description,
899 'shipping_price' => (float)$shipping_price,
900 'shipping_country' => $shipping_country,
901 'img_type' => $img_type,
902 'mpn_type' => $mpn_type,
903 'gender' => $gender,
904 'age_group' => $age_group,
905 'export_attributes' => (int)$export_attributes,
906 'color[]' => $color,
907 'material[]' => $material,
908 'pattern[]' => $pattern,
909 'size[]' => $size,
910 'export_min_price' => (float)$export_min_price,
911 'no_gtin' => (int)$no_gtin,
912 'no_brand' => (int)$no_brand,
913 'id_exists_tag' => (int)$id_exists_tag,
914 'export_nap' => (int)$export_nap,
915 'quantity' => (int)$quantity,
916 'featured_products' => (int)$featured_products,
917 'gen_file_in_root' => (int)$gen_file_in_root
918 );
919 }
920
921 public function renderCategForm()
922 {
923 $helper = new HelperForm();
924 $helper->show_toolbar = false;
925 $helper->module = $this;
926 $helper->table = $this->table;
927 $helper->default_form_language = (int)$this->context->language->id;
928 $helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') ? Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') : 0;
929 $this->fields_form = array();
930 $helper->identifier = $this->identifier;
931 $helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false).'&configure='.$this->name.'&tab_module='.$this->tab.'&module_name='.$this->name;
932 $helper->token = Tools::getAdminTokenLite('AdminModules');
933 $back_url = $helper->currentIndex.'&token='.$helper->token;
934 $helper->fields_value = $this->getGCategFieldsValues();
935 $helper->languages = $this->context->controller->getLanguages();
936 $helper->tpl_vars = array(
937 'back_url' => $back_url,
938 'show_cancel_button' => true
939 );
940 $id_lang = $this->context->language->id;
941 $id_shop = $this->context->shop->id;
942
943 $conditions = array(
944 array(
945 'id_cond' => '',
946 'name' => $this->l('Default')
947 ),
948 array(
949 'id_cond' => 'new',
950 'name' => $this->l('Category\'s products are new')
951 ),
952 array(
953 'id_cond' => 'used',
954 'name' => $this->l('Category\'s products are used')
955 ),
956 array(
957 'id_cond' => 'refurbished',
958 'name' => $this->l('Category\'s products are refurbished')
959 )
960 );
961 $avail_modes = array(
962 array(
963 'id_mode' => '',
964 'name' => $this->l('Default')
965 ),
966 array(
967 'id_mode' => 'in stock',
968 'name' => $this->l('Category\'s products are in stock')
969 ),
970 array(
971 'id_mode' => 'preorder',
972 'name' => $this->l('Category\'s products avail. on preorder')
973 )
974 );
975 $gender_modes = array(
976 array(
977 'id' => '',
978 'name' => $this->l('Default')
979 ),
980 array(
981 'id' => 'male',
982 'name' => $this->l('Category\'s products are for men')
983 ),
984 array(
985 'id' => 'female',
986 'name' => $this->l('Category\'s products are for women')
987 ),
988 array(
989 'id' => 'unisex',
990 'name' => $this->l('Category\'s products are unisex')
991 )
992 );
993 $age_modes = array(
994 array(
995 'id' => '',
996 'name' => $this->l('Default')
997 ),
998 array(
999 'id' => 'newborn',
1000 'name' => $this->l('Newborn')
1001 ),
1002 array(
1003 'id' => 'infant',
1004 'name' => $this->l('Infant')
1005 ),
1006 array(
1007 'id' => 'toddler',
1008 'name' => $this->l('Toddler')
1009 ),
1010 array(
1011 'id' => 'kids',
1012 'name' => $this->l('Kids')
1013 ),
1014 array(
1015 'id' => 'adult',
1016 'name' => $this->l('Adult')
1017 )
1018 );
1019 $attributes = array(
1020 array(
1021 'id_attribute_group' => '',
1022 'name' => $this->l('Products attribute doesn\'t exist')
1023 )
1024 );
1025 $attributes = array_merge($attributes, $this->getShopAttributes($id_lang, $id_shop));
1026 $gcat_desc = '<a href="http://www.google.com/support/merchants/bin/answer.py?answer=160081&query=product_type" target="_blank">'.$this->l('See Google Categories').'</a> ';
1027 $form_desc = html_entity_decode($this->l('Default: System tries to get the value of the product attribute. If not found, system tries to get the category\'s attribute value. <br> If not found, it tries to get the parent category\'s attribute, and so till the root category. At last, if empty, value is not exported.'));
1028
1029 $fields_form = array(
1030 'form' => array(
1031 'legend' => array(
1032 'title' => ((Tools::getIsset('updategshoppingflux') || Tools::getIsset('statusgshoppingflux')) && !Tools::getValue('updategshoppingflux')) ? $this->l('Update the matching Google category') : $this->l('Add a new Google category'),
1033 'icon' => 'icon-link'
1034 ),
1035 'input' => array(
1036 array(
1037 'type' => 'free',
1038 'label' => $this->l('Category'),
1039 'name' => 'breadcrumb'
1040 ),
1041 array(
1042 'type' => 'text',
1043 'label' => $this->l('Matching Google category'),
1044 'name' => 'gcategory',
1045 'lang' => true,
1046 'desc' => $gcat_desc
1047 ),
1048 array(
1049 'type' => 'switch',
1050 'name' => 'export',
1051 'label' => $this->l('Export products from this category'),
1052 'values' => array(
1053 array(
1054 'id' => 'active_on',
1055 'value' => 1,
1056 'label' => $this->l('Enabled')
1057 ),
1058 array(
1059 'id' => 'active_off',
1060 'value' => 0,
1061 'label' => $this->l('Disabled')
1062 )
1063 )
1064 ),
1065 array(
1066 'type' => 'select',
1067 'label' => $this->l('Condition'),
1068 'name' => 'condition',
1069 'default_value' => $helper->fields_value['condition'],
1070 'options' => array(
1071 'query' => $conditions,
1072 'id' => 'id_cond',
1073 'name' => 'name'
1074 )
1075 ),
1076 array(
1077 'type' => 'select',
1078 'label' => $this->l('Products\' availability'),
1079 'name' => 'availability',
1080 'default_value' => $helper->fields_value['availability'],
1081 'options' => array(
1082 'query' => $avail_modes,
1083 'id' => 'id_mode',
1084 'name' => 'name'
1085 )
1086 ),
1087 array(
1088 'type' => 'select',
1089 'label' => $this->l('Gender attribute'),
1090 'name' => 'gender',
1091 'default_value' => $helper->fields_value['gender'],
1092 'options' => array(
1093 'query' => $gender_modes,
1094 'id' => 'id',
1095 'name' => 'name'
1096 )
1097 ),
1098 array(
1099 'type' => 'select',
1100 'label' => $this->l('Age group'),
1101 'name' => 'age_group',
1102 'default_value' => $helper->fields_value['age_group'],
1103 'options' => array(
1104 'query' => $age_modes,
1105 'id' => 'id',
1106 'name' => 'name'
1107 )
1108 ),
1109 array(
1110 'type' => 'select',
1111 'multiple' => true,
1112 'label' => $this->l('Products color attribute'),
1113 'name' => 'color[]',
1114 'default_value' => $helper->fields_value['color[]'],
1115 'options' => array(
1116 'query' => $attributes,
1117 'id' => 'id_attribute_group',
1118 'name' => 'name'
1119 ),
1120 'desc' => $this->l('Hold [Ctrl] key pressed to select multiple color attributes.')
1121 ),
1122 array(
1123 'type' => 'select',
1124 'multiple' => true,
1125 'label' => $this->l('Products material attribute'),
1126 'name' => 'material[]',
1127 'default_value' => $helper->fields_value['material[]'],
1128 'options' => array(
1129 'query' => $attributes,
1130 'id' => 'id_attribute_group',
1131 'name' => 'name'
1132 ),
1133 'desc' => $this->l('Hold [Ctrl] key pressed to select multiple material attributes.')
1134 ),
1135 array(
1136 'type' => 'select',
1137 'multiple' => true,
1138 'label' => $this->l('Products pattern attribute'),
1139 'name' => 'pattern[]',
1140 'default_value' => $helper->fields_value['pattern[]'],
1141 'options' => array(
1142 'query' => $attributes,
1143 'id' => 'id_attribute_group',
1144 'name' => 'name'
1145 ),
1146 'desc' => $this->l('Hold [Ctrl] key pressed to select multiple pattern attributes.')
1147 ),
1148 array(
1149 'type' => 'select',
1150 'multiple' => true,
1151 'label' => $this->l('Products size attribute'),
1152 'name' => 'size[]',
1153 'default_value' => $helper->fields_value['size[]'],
1154 'options' => array(
1155 'query' => $attributes,
1156 'id' => 'id_attribute_group',
1157 'name' => 'name'
1158 ),
1159 'desc' => $this->l('Hold [Ctrl] key pressed to select multiple size attributes.')
1160 )
1161 ),
1162 'description' => $form_desc,
1163 'submit' => array(
1164 'name' => 'submitCategory',
1165 'title' => $this->l('Save')
1166 )
1167 )
1168 );
1169
1170 if ((Tools::getIsset('updategshoppingflux') || Tools::getIsset('statusgshoppingflux')) && !Tools::getValue('updategshoppingflux'))
1171 $fields_form['form']['submit'] = array(
1172 'name' => 'updateCategory',
1173 'title' => $this->l('Update')
1174 );
1175
1176 if (Tools::isSubmit('updategshoppingflux') || Tools::isSubmit('statusgshoppingflux')) {
1177 $fields_form['form']['input'][] = array(
1178 'type' => 'hidden',
1179 'name' => 'updatecateg'
1180 );
1181 $fields_form['form']['input'][] = array(
1182 'type' => 'hidden',
1183 'name' => 'id_gcategory'
1184 );
1185 $helper->fields_value['updatecateg'] = '';
1186 }
1187
1188 return $helper->generateForm(
1189 array(
1190 $fields_form
1191 )
1192 );
1193 }
1194
1195 public function getGCategFieldsValues()
1196 {
1197 $gcatexport_active = '';
1198 $gcatcondition_edit = '';
1199 $gcatavail_edit = '';
1200 $gcatgender_edit = '';
1201 $gcatage_edit = '';
1202 $gcatcolor_edit = '';
1203 $gcatmaterial_edit = '';
1204 $gcatpattern_edit = '';
1205 $gcatsize_edit = '';
1206 $gcategory_edit = '';
1207 $gcatlabel_edit = '';
1208
1209 if (Tools::isSubmit('updategshoppingflux') || Tools::isSubmit('statusgshoppingflux')) {
1210 $id_lang= $this->context->cookie->id_lang;
1211 $gcateg = GCategories::getCategLang(Tools::getValue('id_gcategory'), (int)Shop::getContextShopID(), $id_lang);
1212
1213 foreach ($gcateg['gcategory'] as $key => $categ)
1214 $gcateg['gcategory'][$key] = Tools::htmlentitiesDecodeUTF8($categ);
1215
1216 $gcatexport_active = $gcateg['export'];
1217 $gcatcondition_edit = $gcateg['condition'];
1218 $gcatavail_edit = $gcateg['availability'];
1219 $gcatgender_edit = $gcateg['gender'];
1220 $gcatage_edit = $gcateg['age_group'];
1221 $gcatcolor_edit = $gcateg['color'];
1222 $gcatmaterial_edit = $gcateg['material'];
1223 $gcatpattern_edit = $gcateg['pattern'];
1224 $gcatsize_edit = $gcateg['size'];
1225 $gcategory_edit = $gcateg['gcategory'];
1226 $gcatlabel_edit = $gcateg['breadcrumb'];
1227 }
1228
1229 $fields_values = array(
1230 'id_gcategory' => Tools::getValue('id_gcategory'),
1231 'breadcrumb' => (isset($gcatlabel_edit) ? $gcatlabel_edit : ''),
1232 'export' => Tools::getValue('export', isset($gcatexport_active) ? $gcatexport_active : ''),
1233 'condition' => Tools::getValue('condition', isset($gcatcondition_edit) ? $gcatcondition_edit : ''),
1234 'availability' => Tools::getValue('availability', isset($gcatavail_edit) ? $gcatavail_edit : ''),
1235 'gender' => Tools::getValue('gender', isset($gcatgender_edit) ? $gcatgender_edit : ''),
1236 'age_group' => Tools::getValue('age_group', isset($gcatage_edit) ? $gcatage_edit : ''),
1237 'color[]' => explode(';', Tools::getValue('color[]', isset($gcatcolor_edit) ? $gcatcolor_edit : '')),
1238 'material[]' => explode(';', Tools::getValue('material[]', isset($gcatmaterial_edit) ? $gcatmaterial_edit : '')),
1239 'pattern[]' => explode(';', Tools::getValue('pattern[]', isset($gcatpattern_edit) ? $gcatpattern_edit : '')),
1240 'size[]' => explode(';', Tools::getValue('size[]', isset($gcatsize_edit) ? $gcatsize_edit : ''))
1241 );
1242
1243 if (Tools::getValue('submitAddmodule')) {
1244 foreach (Language::getLanguages(false) as $lang) {
1245 $fields_values['gcategory'][$lang['id_lang']] = '';
1246 }
1247 }
1248
1249 else
1250 foreach (Language::getLanguages(false) as $lang) {
1251 $fields_values['gcategory'][$lang['id_lang']] = Tools::getValue('gcategory_'.(int)$lang['id_lang'], isset($gcategory_edit[$lang['id_lang']]) ? html_entity_decode($gcategory_edit[$lang['id_lang']]) : '');
1252 }
1253
1254 return $fields_values;
1255 }
1256 public function getGLangFieldsValues()
1257 {
1258 $glangcurrency_edit = '';
1259 $glangexport_active = '';
1260
1261 if (Tools::isSubmit('updategshoppingflux_lc') || Tools::isSubmit('statusgshoppingflux_lc')) {
1262 $glang = GLangAndCurrency::getLangCurrencies(Tools::getValue('id_glang'), (int)Shop::getContextShopID());
1263 $glangcurrency_edit = explode(";",$glang[0]['id_currency']);
1264 $glangtax_included = $glang[0]['tax_included'];
1265 $glangexport_active = $glang[0]['active'];
1266 }
1267 $language = Language::getLanguage(Tools::getValue('id_glang'));
1268 $fields_values = array(
1269 'id_glang' => Tools::getValue('id_glang'),
1270 'name' => $language['name'],
1271 'iso_code' => $language['iso_code'],
1272 'language_code' => $language['language_code'],
1273 'currencies[]' => Tools::getValue('currencies[]', $glangcurrency_edit),
1274 'tax_included' => Tools::getValue('tax_included', $glangtax_included),
1275 'active' => Tools::getValue('active', $glangexport_active)
1276 );
1277
1278 return $fields_values;
1279 }
1280
1281 public function renderLangForm()
1282 {
1283 $this->fields_form = array();
1284 $helper = new HelperForm();
1285 $helper->show_toolbar = false;
1286 $helper->module = $this;
1287 $helper->table = 'gshoppingflux_lc';
1288 $helper->default_form_language = (int)$this->context->language->id;
1289 $helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') ? Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') : 0;
1290 $helper->identifier = $this->identifier;
1291 $helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false).'&configure='.$this->name.'&tab_module='.$this->tab.'&module_name='.$this->name;
1292 $helper->token = Tools::getAdminTokenLite('AdminModules');
1293 $back_url = $helper->currentIndex.'&token='.$helper->token;
1294 $helper->fields_value = $this->getGLangFieldsValues();
1295 $helper->tpl_vars = array(
1296 'back_url' => $back_url,
1297 'show_cancel_button' => true
1298 );
1299 $currencies = Currency::getCurrencies();
1300
1301 $form_desc = html_entity_decode($this->l('Select currency to export with this language.'));
1302
1303 $fields_form = array(
1304 'form' => array(
1305 'legend' => array(
1306 'title' => $this->l('Language export settings'),
1307 'icon' => 'icon-globe'
1308 ),
1309 'input' => array(
1310 array(
1311 'type' => 'free',
1312 'label' => $this->l('Language'),
1313 'name' => 'name'
1314 ),
1315 array(
1316 'type' => 'free',
1317 'label' => $this->l('Language code'),
1318 'name' => 'language_code'
1319 ),
1320 array(
1321 'type' => 'switch',
1322 'label' => $this->l('Enabled'),
1323 'name' => 'active',
1324 'is_bool' => true,
1325 'disabled' => true,
1326 'values' => array(
1327 array(
1328 'id' => 'active_on',
1329 'value' => 1,
1330 'label' => $this->l('Enabled')
1331 ),
1332 array(
1333 'id' => 'active_off',
1334 'value' => 0,
1335 'label' => $this->l('Disabled')
1336 )
1337 )
1338 ),
1339 array(
1340 'type' => 'select',
1341 'multiple' => true,
1342 'label' => $this->l('Currencies'),
1343 'name' => 'currencies[]',
1344 'default_value' => $helper->fields_value['currencies[]'],
1345 'options' => array(
1346 'query' => $currencies,
1347 'id' => 'id_currency',
1348 'name' => 'name'
1349 ),
1350 'desc' => $this->l('Hold [Ctrl] key pressed to select multiple currencies.')
1351 ),
1352 array(
1353 'type' => 'switch',
1354 'label' => $this->l('Prices exported tax included'),
1355 'name' => 'tax_included',
1356 'is_bool' => true,
1357 'values' => array(
1358 array(
1359 'id' => 'inc_tax',
1360 'value' => 1,
1361 'label' => $this->l('Enabled')
1362 ),
1363 array(
1364 'id' => 'ex_tax',
1365 'value' => 0,
1366 'label' => $this->l('Disabled')
1367 )
1368 ),
1369 'desc' => $this->l('If disabled, prices are exported ex tax.')
1370 )
1371 ),
1372 'description' => $form_desc,
1373 'submit' => array(
1374 'name' => 'submitCategory',
1375 'title' => $this->l('Save')
1376 )
1377 )
1378 );
1379
1380 if ((Tools::getIsset('updategshoppingflux_lc') || Tools::getIsset('statusgshoppingflux_lc')) && !Tools::getValue('updategshoppingflux_lc'))
1381 $fields_form['form']['submit'] = array(
1382 'name' => 'updateLanguage',
1383 'title' => $this->l('Update')
1384 );
1385
1386 if (Tools::isSubmit('updategshoppingflux_lc') || Tools::isSubmit('statusgshoppingflux_lc')) {
1387 $fields_form['form']['input'][] = array(
1388 'type' => 'hidden',
1389 'name' => 'updatelang'
1390 );
1391 $fields_form['form']['input'][] = array(
1392 'type' => 'hidden',
1393 'name' => 'id_glang'
1394 );
1395 $helper->fields_value['updatelang'] = '';
1396 }
1397
1398 return $helper->generateForm(
1399 array(
1400 $fields_form
1401 )
1402 );
1403 }
1404
1405 public function renderLangList()
1406 {
1407 $fields_list = array(
1408 'id_glang' => array(
1409 'title' => $this->l('ID')
1410 ),
1411 'flag' => array(
1412 'title' => $this->l('Flag'),
1413 'image' => 'l',
1414 ),
1415 'name' => array(
1416 'title' => $this->l('Language')
1417 ),
1418 'language_code' => array(
1419 'title' => $this->l('Language code'),
1420 'align' => 'center',
1421 'class' => 'fixed-width-xs'
1422 ),
1423 'currency' => array(
1424 'title' => $this->l('Currency'),
1425 ),
1426 'tax_included' => array(
1427 'title' => $this->l('Tax'),
1428 ),
1429 'active' => array(
1430 'title' => $this->l('Enabled'),
1431 'align' => 'center',
1432 'active' => 'status',
1433 'type' => 'bool',
1434 'class' => 'fixed-width-sm'
1435 )
1436 );
1437
1438 if (Configuration::get('PS_MULTISHOP_FEATURE_ACTIVE') && count(Shop::getShops(true, null, true)) > 1)
1439 $fields_list = array_merge($fields_list, array(
1440 'shop_name' => array(
1441 'title' => $this->l('Shop name'),
1442 'width' => '15%'
1443 )
1444 ));
1445
1446 $form_desc = "Export currencies you need with the language you want.";
1447
1448 $helper = new HelperList();
1449 $helper->shopLinkType = '';
1450 $helper->show_toolbar = false;
1451 $helper->simple_header = true;
1452 $helper->identifier = 'id_glang';
1453 $helper->imageType = "jpg";
1454 $helper->table = 'gshoppingflux_lc';
1455 $helper->actions = array(
1456 'edit'
1457 );
1458 $helper->title = $this->l('Export languages and currencies');
1459 $helper->token = Tools::getAdminTokenLite('AdminModules');
1460 $helper->currentIndex = AdminController::$currentIndex.'&configure='.$this->name;
1461 $helper->tpl_vars = array(
1462 'languages' => $this->context->controller->getLanguages()
1463 );
1464 $glangflux = GLangAndCurrency::getAllLangCurrencies(0);
1465
1466 foreach($glangflux as $k => $v){
1467 $currencies = explode(";",$glangflux[$k]['id_currency']);
1468 $arrCurr = array();
1469 foreach($currencies as $idc){
1470 $currency = new Currency($idc);
1471 $arrCurr[] = $currency->iso_code;
1472 }
1473 $glangflux[$k]['currency'] = implode(" - ",$arrCurr);
1474 if($glangflux[$k]['tax_included']==1) $glangflux[$k]['tax_included']= $this->l('Inc Tax ');
1475 else $glangflux[$k]['tax_included']= $this->l('Ex Tax');
1476 }
1477
1478 return $helper->generateList($glangflux, $fields_list);
1479 }
1480
1481 public function renderCategList()
1482 {
1483 $gcategories = $this->makeCatTree();
1484
1485 $fields_list = array(
1486 'id_gcategory' => array(
1487 'title' => $this->l('ID')
1488 )
1489 );
1490
1491 if (Configuration::get('PS_MULTISHOP_FEATURE_ACTIVE') && count(Shop::getShops(true, null, true)) > 1)
1492 $fields_list = array_merge($fields_list, array(
1493 'shop_name' => array(
1494 'title' => $this->l('Shop name'),
1495 'width' => '15%'
1496 )
1497 ));
1498
1499 $form_desc = "If all your products match the same Google category, you can attach it to your home category, sub-categories will automatically get the same setting. Products in categories with no Google category specified are exported in the same place than the one from parent categories.";
1500
1501 $fields_list = array_merge($fields_list, array(
1502 'gcat_name' => array(
1503 'title' => $this->l('Category'),
1504 'width' => '30%'
1505 ),
1506 'gcategory' => array(
1507 'title' => $this->l('Matching Google category'),
1508 'width' => '70%'
1509 ),
1510 'condition' => array(
1511 'title' => $this->l('Condit.')
1512 ),
1513 'availability' => array(
1514 'title' => $this->l('Avail.')
1515 ),
1516 'gender' => array(
1517 'title' => $this->l('Gender')
1518 ),
1519 'age_group' => array(
1520 'title' => $this->l('Age')
1521 ),
1522 'gid_colors' => array(
1523 'title' => $this->l('Color')
1524 ),
1525 'gid_materials' => array(
1526 'title' => $this->l('Material')
1527 ),
1528 'gid_patterns' => array(
1529 'title' => $this->l('Pattern')
1530 ),
1531 'gid_sizes' => array(
1532 'title' => $this->l('Size')
1533 ),
1534 'export' => array(
1535 'title' => $this->l('Export'),
1536 'align' => 'center',
1537 'is_bool' => true,
1538 'active' => 'status'
1539 )
1540 ));
1541
1542 $helper = new HelperList();
1543 $helper->shopLinkType = '';
1544 $helper->simple_header = true;
1545 $helper->identifier = 'id_gcategory';
1546 $helper->table = 'gshoppingflux';
1547 $helper->actions = array(
1548 'edit'
1549 );
1550 $helper->show_toolbar = false;
1551 $helper->module = $this;
1552 $helper->title = $this->l('Google categories');
1553 $helper->token = Tools::getAdminTokenLite('AdminModules');
1554 $helper->currentIndex = AdminController::$currentIndex.'&configure='.$this->name;
1555
1556 return $helper->generateList($gcategories, $fields_list);
1557 }
1558
1559 public function renderInfo()
1560 {
1561 $helper = new HelperForm();
1562 $helper->show_toolbar = false;
1563 $helper->table = $this->table;
1564 $helper->languages = $this->context->controller->getLanguages();
1565 $helper->default_form_language = (int)$this->context->language->id;
1566 $helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') ? Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') : 0;
1567 $this->fields_form = array();
1568 $helper->identifier = $this->identifier;
1569 $helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false).'&configure='.$this->name.'&tab_module='.$this->tab.'&module_name='.$this->name;
1570 $helper->token = Tools::getAdminTokenLite('AdminModules');
1571
1572 // Get active langs on shop
1573 $languages = GLangAndCurrency::getAllLangCurrencies(1);
1574 $shops = Shop::getShops(true, null, true);
1575 $output = '';
1576
1577 foreach ($languages as $lang) {
1578 $currencies = explode(";",$lang['id_currency']);
1579 foreach($currencies as $curr){
1580 $currency = new Currency($curr);
1581 if (Configuration::get('GS_GEN_FILE_IN_ROOT', 0, $this->context->shop->id_shop_group, $this->context->shop->id) == 1) {
1582 $get_file_url = $this->uri.$this->_getOutputFileName($lang['iso_code'], $currency->iso_code, $this->context->shop->id);
1583 } else {
1584 $get_file_url = $this->uri.'modules/'.$this->name.'/export/'.$this->_getOutputFileName($lang['iso_code'], $currency->iso_code, $this->context->shop->id);
1585 }
1586 $output .= '<a href="'.$get_file_url.'">'.$get_file_url.'</a> <br /> ';
1587 }
1588 }
1589 $info_cron = '<a href="'.$this->uri.'modules/'.$this->name.'/cron.php" target="_blank">'.$this->uri.'modules/'.$this->name.'/cron.php</a>';
1590
1591 if (count($languages) > 1)
1592 $files_desc = $this->l('Configure these URLs in your Google Merchant Center account.');
1593
1594 else
1595 $files_desc = $this->l('Configure this URL in your Google Merchant Center account.');
1596
1597 $cron_desc = $this->l('Install a CRON task to update the feed frequently.');
1598
1599 if (count($shops) > 1)
1600 $cron_desc .= ' '.$this->l('Please note that as multishop feature is active, you\'ll have to install several CRON tasks, one for each shop.');
1601
1602 $form_desc = $this->l('Report bugs and find help on forum: <a href="http://www.prestashop.com/forums/topic/381026-free-module-google-shopping-flux/" target="_blank">http://www.prestashop.com/forums/topic/381026-free-module-google-shopping-flux/</a>');
1603 $helper->fields_value = array(
1604 'info_files' => $output,
1605 'info_cron' => $info_cron
1606 );
1607
1608 $fields_form = array(
1609 'form' => array(
1610 'legend' => array(
1611 'title' => $this->l('Files information'),
1612 'icon' => 'icon-info'
1613 ),
1614 'input' => array(
1615 array(
1616 'type' => 'free',
1617 'label' => $this->l('Generated files links:'),
1618 'name' => 'info_files',
1619 'desc' => $files_desc
1620 ),
1621 array(
1622 'type' => 'free',
1623 'label' => $this->l('Automatic files generation:'),
1624 'name' => 'info_cron',
1625 'desc' => $cron_desc
1626 )
1627 ),
1628 'description' => html_entity_decode($form_desc, self::REPLACE_FLAGS, self::CHARSET)
1629 )
1630 );
1631
1632 return $helper->generateForm(array(
1633 $fields_form
1634 ));
1635 }
1636
1637 public function customGetNestedCategories($shop_id, $root_category = null, $id_lang = false, $active = true, $groups = null, $use_shop_restriction = true, $sql_filter = '', $sql_sort = '', $sql_limit = '')
1638 {
1639 if (isset($root_category) && !Validate::isInt($root_category))
1640 die(Tools::displayError());
1641
1642 if (!Validate::isBool($active))
1643 die(Tools::displayError());
1644
1645 if (isset($groups) && Group::isFeatureActive() && !is_array($groups))
1646 $groups = (array)$groups;
1647
1648 $cache_id = 'Category::getNestedCategories_'.md5((int)$shop_id.(int)$root_category.(int)$id_lang.(int)$active.(int)$active.(isset($groups) && Group::isFeatureActive() ? implode('', $groups) : ''));
1649
1650 if (!Cache::isStored($cache_id)) {
1651 $result = Db::getInstance()->executeS('
1652 SELECT c.*, cl.`name` as gcat_name, g.*, gl.*, s.name as shop_name
1653 FROM `'._DB_PREFIX_.'category` c
1654 INNER JOIN `'._DB_PREFIX_.'category_shop` cs ON (cs.`id_category` = c.`id_category` AND cs.`id_shop` = "'.(int)$shop_id.'")
1655 LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON c.`id_category` = cl.`id_category` AND cl.`id_shop` = "'.(int)$shop_id.'"
1656 LEFT JOIN `'._DB_PREFIX_.'gshoppingflux` g ON g.`id_gcategory` = c.`id_category` AND g.`id_shop` = "'.(int)$shop_id.'"
1657 LEFT JOIN `'._DB_PREFIX_.'gshoppingflux_lang` gl ON gl.`id_gcategory` = c.`id_category` AND gl.`id_shop` = "'.(int)$shop_id.'"
1658 LEFT JOIN '._DB_PREFIX_.'shop s ON s.`id_shop` = "'.(int)$shop_id.'"
1659 WHERE 1 '.$sql_filter.' '.($id_lang ? 'AND cl.`id_lang` = '.(int)$id_lang.' AND gl.`id_lang` = '.(int)$id_lang : '')
1660 .($active ? ' AND c.`active` = 1' : '')
1661 .(isset($groups) && Group::isFeatureActive() ? ' AND cg.`id_group` IN ('.implode(',', $groups).')' : '')
1662 .(!$id_lang || (isset($groups) && Group::isFeatureActive()) ? ' GROUP BY c.`id_category`' : '')
1663 .($sql_sort != '' ? $sql_sort : ' ORDER BY c.`level_depth` ASC')
1664 .($sql_sort == '' && $use_shop_restriction ? ', cs.`position` ASC' : '')
1665 .($sql_limit != '' ? $sql_limit : ' LIMIT 1;')
1666 );
1667
1668 $attributes = $this->getShopAttributes($this->context->language->id, $this->context->shop->id);
1669
1670 foreach ($result as $k => $cat) {
1671 $result[$k]['gcategory'] = html_entity_decode($result[$k]['gcategory']);
1672 $gid_colors = array();
1673 $gid_materials = array();
1674 $gid_patterns = array();
1675 $gid_sizes = array();
1676
1677 if ($result[$k]['level_depth'] > 0) {
1678 $tree = " > ";
1679 $str = '';
1680 for ($i = 0; $i < $result[$k]['level_depth'] - 1; $i++) {
1681 $str .= $tree;
1682 }
1683
1684 $result[$k]['gcat_name'] = $str.' '.$result[$k]['gcat_name'];
1685 $shop_group_id = Shop::getGroupFromShop($shop_id);
1686
1687 $result[$k]['color'] = explode(";", $result[$k]['color']);
1688 foreach ($result[$k]['color'] as $a => $v) {
1689 if(isset($attributes[$v - 1]))$gid_colors[] = $attributes[$v - 1]['name'];
1690 }
1691
1692 $result[$k]['material'] = explode(";", $result[$k]['material']);
1693 foreach ($result[$k]['material'] as $a => $v) {
1694 if(isset($attributes[$v - 1]))$gid_materials[] = $attributes[$v - 1]['name'];
1695 }
1696
1697 $result[$k]['pattern'] = explode(";", $result[$k]['pattern']);
1698 foreach ($result[$k]['pattern'] as $a => $v) {
1699 if(isset($attributes[$v - 1]))$gid_patterns[] = $attributes[$v - 1]['name'];
1700 }
1701
1702 $result[$k]['size'] = explode(";", $result[$k]['size']);
1703 foreach ($result[$k]['size'] as $a => $v) {
1704 if(isset($attributes[$v - 1]))$gid_sizes[] = $attributes[$v - 1]['name'];
1705 }
1706
1707 $result[$k]['gid_colors'] = implode(" ; ", $gid_colors);
1708 $result[$k]['gid_materials'] = implode(" ; ", $gid_materials);
1709 $result[$k]['gid_patterns'] = implode(" ; ", $gid_patterns);
1710 $result[$k]['gid_sizes'] = implode(" ; ", $gid_sizes);
1711
1712 }
1713 }
1714
1715 $categories = array();
1716 $buff = array();
1717
1718 if (!isset($root_category))
1719 $root_category = 1;
1720
1721 foreach ($result as $row) {
1722 $current =& $buff[$row['id_category']];
1723 $current = $row;
1724
1725 if ($row['id_category'] == $root_category)
1726 $categories[$row['id_category']] =& $current;
1727 else
1728 $buff[$row['id_parent']]['children'][$row['id_category']] =& $current;
1729 }
1730
1731 Cache::store($cache_id, $categories);
1732 }
1733
1734 return Cache::retrieve($cache_id);
1735 }
1736
1737 private function makeCatTree($id_cat = 0, $catlist = 0)
1738 {
1739 $id_lang = (int)$this->context->language->id;
1740 $id_shop = (int)Shop::getContextShopID();
1741 $sql_filter = '';
1742 $sql_sort = '';
1743 $sql_limit = '';
1744
1745 if ($id_cat == 0 && $catlist == 0) {
1746 $catlist = array();
1747 $shop = new Shop($id_shop);
1748 $id_cat = Category::getRootCategory($id_lang, $shop);
1749 $id_cat = $id_cat->id_category;
1750 $sql_limit = ';';
1751 }
1752
1753 $category = new Category((int)$id_cat, (int)$id_lang);
1754
1755 if (Validate::isLoadedObject($category)) {
1756 $tabcat = $this->customGetNestedCategories($id_shop, $id_cat, $id_lang, true, $this->user_groups, true, $sql_filter, $sql_sort, $sql_limit);
1757 $catlist = array_merge($catlist, $tabcat);
1758 }
1759
1760 foreach ($tabcat as $k => $c)
1761 if (!empty($c['children']))
1762 foreach ($c['children'] as $j)
1763 $catlist = $this->makeCatTree($j['id_category'], $catlist);
1764
1765 return $catlist;
1766 }
1767
1768 public function getGCategValues($id_lang, $id_shop)
1769 {
1770 // Get categories' export values, or it's parents ones :
1771 // Matching Google category, condition, availability, gender, age_group...
1772 $sql = 'SELECT k.*, g.*, gl.*
1773 FROM '._DB_PREFIX_.'category k
1774 LEFT JOIN '._DB_PREFIX_.'gshoppingflux g ON (g.id_gcategory=k.id_category AND g.id_shop='.$id_shop.')
1775 LEFT JOIN '._DB_PREFIX_.'gshoppingflux_lang gl ON (gl.id_gcategory=k.id_category AND gl.id_lang = '.(int)$id_lang.' AND gl.id_shop='.(int)$id_shop.')
1776 WHERE g.id_shop = '.(int)$id_shop;
1777
1778 $ret = Db::getInstance()->executeS($sql);
1779 $shop = new Shop($id_shop);
1780 $root = Category::getRootCategory($id_lang, $shop);
1781
1782 foreach ($ret as $cat) {
1783 $parent_id = $cat['id_category'];
1784 $gcategory = $cat['gcategory'];
1785 $condition = $cat['condition'];
1786 $availability = $cat['availability'];
1787 $gender = $cat['gender'];
1788 $age_group = $cat['age_group'];
1789 $color = $cat['color'];
1790 $material = $cat['material'];
1791 $pattern = $cat['pattern'];
1792 $size = $cat['size'];
1793
1794 while ((empty($gcategory) || empty($condition) || empty($availability) || empty($gender) || empty($age_group) || empty($color) || empty($material) || empty($pattern) || empty($size)) && $parent_id >= $root->id_category) {
1795 $parentsql = $sql.' AND k.id_category = '.$parent_id.';';
1796 $parentret = Db::getInstance()->executeS($parentsql);
1797
1798 if (!count($parentret))
1799 break;
1800
1801 foreach ($parentret as $parentcat) {
1802 $parent_id = $parentcat['id_parent'];
1803 if (empty($gcategory))
1804 $gcategory = $parentcat['gcategory'];
1805 if (empty($condition))
1806 $condition = $parentcat['condition'];
1807 if (empty($availability))
1808 $availability = $parentcat['availability'];
1809 if (empty($gender))
1810 $gender = $parentcat['gender'];
1811 if (empty($age_group))
1812 $age_group = $parentcat['age_group'];
1813 if (empty($color))
1814 $color = $parentcat['color'];
1815 if (empty($material))
1816 $material = $parentcat['material'];
1817 if (empty($pattern))
1818 $pattern = $parentcat['pattern'];
1819 if (empty($size))
1820 $size = $parentcat['size'];
1821 }
1822 }
1823
1824 if (!$color && !empty($this->module_conf['color']))
1825 $color = $this->module_conf['color'];
1826 if (!$material && !empty($this->module_conf['material']))
1827 $material = $this->module_conf['material'];
1828 if (!$pattern && !empty($this->module_conf['pattern']))
1829 $pattern = $this->module_conf['pattern'];
1830 if (!$size && !empty($this->module_conf['size']))
1831 $size = $this->module_conf['size'];
1832
1833 $this->categories_values[$cat['id_category']]['gcategory'] = html_entity_decode($gcategory);
1834 $this->categories_values[$cat['id_category']]['gcat_condition'] = $condition;
1835 $this->categories_values[$cat['id_category']]['gcat_avail'] = $availability;
1836 $this->categories_values[$cat['id_category']]['gcat_gender'] = $gender;
1837 $this->categories_values[$cat['id_category']]['gcat_age_group'] = $age_group;
1838 $this->categories_values[$cat['id_category']]['gcat_color[]'] = explode(";", $color);
1839 $this->categories_values[$cat['id_category']]['gcat_material[]'] = explode(";", $material);
1840 $this->categories_values[$cat['id_category']]['gcat_pattern[]'] = explode(";", $pattern);
1841 $this->categories_values[$cat['id_category']]['gcat_size[]'] = explode(";", $size);
1842 }
1843 }
1844
1845 private function rip_tags($string)
1846 {
1847 // ----- remove HTML TAGs -----
1848 $string = preg_replace('/<[^>]*>/', ' ', $string);
1849
1850 // ----- remove control characters -----
1851 $string = str_replace("\r", '', $string); // --- replace with empty space
1852 $string = str_replace("\n", ' ', $string); // --- replace with space
1853 $string = str_replace("\t", ' ', $string); // --- replace with space
1854
1855 // ----- remove multiple spaces -----
1856 $string = trim(preg_replace('/ {2,}/', ' ', $string));
1857 return $string;
1858 }
1859
1860 private function _getOutputFileName($lang, $curr, $shop)
1861 {
1862 return 'googleshopping-s'.$shop.'-'.$lang.'-'.$curr.'.xml';
1863 }
1864
1865 public function getShopDescription($id_lang, $id_shop)
1866 {
1867 $ret = Db::getInstance()->executeS('
1868 SELECT ml.description
1869 FROM '._DB_PREFIX_.'meta_lang ml
1870 LEFT JOIN '._DB_PREFIX_.'meta m ON (m.id_meta = ml.id_meta)
1871 WHERE m.page="index"
1872 AND ml.id_shop = '.(int)$id_shop.'
1873 AND ml.id_lang = '.(int)$id_lang);
1874 return $ret[0]['description'];
1875 }
1876
1877 public function generateAllShopsFileList()
1878 {
1879 // Get all shops
1880 $shops = Shop::getShops(true, null, true);
1881 foreach ($shops as $i => $shop)
1882 $ret[$i] = $this->generateShopFileList($shop);
1883
1884 return $ret;
1885 }
1886
1887 public function generateShopFileList($id_shop)
1888 {
1889 // Get all shop languages
1890 $languages = GLangAndCurrency::getAllLangCurrencies(1);
1891 foreach ($languages as $i => $lang){
1892 $currencies = explode(";",$lang['id_currency']);
1893 foreach($currencies as $id_curr)
1894 $ret[] = $this->generateFile($lang, $id_curr, $id_shop);
1895 }
1896
1897 return $ret;
1898 }
1899
1900 public function generateLangFileList($id_lang, $id_shop)
1901 {
1902 // Get all shop languages
1903 $languages = GLangAndCurrency::getLangCurrencies($id_lang, $id_shop);
1904 foreach ($languages as $i => $lang){
1905 $currencies = explode(";",$lang['id_currency']);
1906 foreach($currencies as $id_curr)
1907 $ret[] = $this->generateFile($lang, $id_curr, $id_shop);
1908 }
1909
1910 return $ret;
1911 }
1912
1913 private function generateFile($lang, $id_curr, $id_shop)
1914 {
1915 $id_lang = (int)$lang['id_lang'];
1916 $curr = new Currency($id_curr);
1917 $this->shop = new Shop($id_shop);
1918 $root = Category::getRootCategory($id_lang, $this->shop);
1919 $this->id_root = $root->id_category;
1920
1921 // Get module configuration for this shop
1922 $this->module_conf = $this->getConfigFieldsValues($id_shop);
1923
1924 // Init categories special attributes :
1925 // Google's matching category, gender, age_group, color_group, material, pattern, size...
1926 $this->getGCategValues($id_lang, $id_shop);
1927
1928 // Init file_path value
1929 if ($this->module_conf['gen_file_in_root'])
1930 $generate_file_path = dirname(__FILE__).'/../../'.$this->_getOutputFileName($lang['iso_code'], $curr->iso_code, $id_shop);
1931
1932 else
1933 $generate_file_path = dirname(__FILE__).'/export/'.$this->_getOutputFileName($lang['iso_code'], $curr->iso_code, $id_shop);
1934
1935 if ($this->shop->name == 'Prestashop') {
1936 $this->shop->name = Configuration::get('PS_SHOP_NAME');
1937 }
1938
1939 // Google Shopping XML
1940 $xml = '<?xml version="1.0" encoding="'.self::CHARSET.'" ?>'."\n";
1941 $xml .= '<rss version="2.0" xmlns:g="http://base.google.com/ns/1.0">'."\n\n";
1942 $xml .= '<channel>'."\n";
1943 // Shop name
1944 $xml .= '<title><![CDATA['.$this->shop->name.']]></title>'."\n";
1945 // Shop description
1946 $xml .= '<description><![CDATA['.$this->getShopDescription($id_lang, $id_shop).']]></description>'."\n";
1947 $xml .= '<link href="'.htmlspecialchars($this->uri, self::REPLACE_FLAGS, self::CHARSET, false).'" rel="alternate" type="text/html"/>'."\n";
1948 $xml .= '<image>'."\n";
1949 $xml .= '<url>'.htmlspecialchars($this->context->link->getMediaLink(_PS_IMG_.Configuration::get('PS_LOGO')), self::REPLACE_FLAGS, self::CHARSET, false).'</url>'."\n";
1950 $xml .= '<link>'.htmlspecialchars($this->uri, self::REPLACE_FLAGS, self::CHARSET, false).'</link>'."\n";
1951 $xml .= '</image>'."\n";
1952 $xml .= '<modified>'.date('Y-m-d').' T01:01:01Z</modified>'."\n";
1953 $xml .= '<author>'."\n".'<name>'.htmlspecialchars(Configuration::get('PS_SHOP_NAME'), self::REPLACE_FLAGS, self::CHARSET, false).'</name>'."\n".'</author>'."\n\n";
1954
1955 $googleshoppingfile = fopen($generate_file_path, 'w');
1956
1957 // Add UTF-8 byte order mark
1958 fwrite($googleshoppingfile, pack("CCC", 0xef, 0xbb, 0xbf));
1959
1960 // File header
1961 fwrite($googleshoppingfile, $xml);
1962
1963 $sql = 'SELECT DISTINCT p.*, pl.*, ps.id_category_default as category_default, gc.*, glc.tax_included, gl.* '
1964 . 'FROM '._DB_PREFIX_.'product p '
1965 . 'INNER JOIN '._DB_PREFIX_.'product_lang pl ON pl.id_product = p.id_product '
1966 . 'INNER JOIN '._DB_PREFIX_.'product_shop ps ON ps.id_product = p.id_product '
1967 . 'INNER JOIN '._DB_PREFIX_.'category c ON c.id_category = p.id_category_default '
1968 . 'INNER JOIN '._DB_PREFIX_.'gshoppingflux gc ON gc.id_gcategory = ps.id_category_default '
1969 . 'INNER JOIN '._DB_PREFIX_.'gshoppingflux_lc glc ON glc.`id_glang` = '.$id_lang.' '
1970 . 'INNER JOIN '._DB_PREFIX_.'gshoppingflux_lang gl ON gl.id_gcategory = ps.id_category_default '
1971 . 'WHERE `p`.`price` > 0 AND `p`.`active` = 1 AND `c`.`active` = 1 AND `gc`.`export` = 1 '
1972 . 'AND `pl`.`id_lang` = '.$id_lang.' AND `gl`.`id_lang` = '.$id_lang;
1973
1974 // Multishops filter
1975 if (Configuration::get('PS_MULTISHOP_FEATURE_ACTIVE') && count(Shop::getShops(true, null, true)) > 1)
1976 $sql .= ' AND `gc`.`id_shop` = '.$id_shop.' AND `pl`.`id_shop` = '.$id_shop.' AND `ps`.`id_shop` = '.$id_shop.' AND `gl`.`id_shop` = '.$id_shop;
1977
1978 // Check EAN13
1979 if ($this->module_conf['no_gtin'] != 1)
1980 $sql .= ' AND `p`.`ean13` != "" AND `p`.`ean13` != 0';
1981
1982 // Check BRAND
1983 if ($this->module_conf['no_brand'] != 1)
1984 $sql .= ' AND `p`.`id_manufacturer` != "" AND `p`.`id_manufacturer` != 0';
1985
1986 $sql .= ' GROUP BY `p`.`id_product`;';
1987 $products = Db::getInstance()->ExecuteS($sql);
1988 $this->nb_total_products = 0;
1989 $this->nb_not_exported_products = 0;
1990 $this->nb_combinations= 0;
1991 $this->nb_prd_w_attr = array();
1992
1993 foreach ($products as $product) {
1994 $p = new Product($product['id_product'], true, $id_lang, $id_shop, $this->context);
1995
1996 $attributeCombinations = null;
1997 if ($this->module_conf['export_attributes'] == 1) {
1998 $attributeCombinations = $p->getAttributeCombinations($id_lang);
1999 }
2000
2001 if ($this->module_conf['mpn_type'] == 'reference' && !empty($product['reference']))
2002 $product['pid'] = $product['reference'];
2003 else if ($this->module_conf['mpn_type'] == 'supplier_reference' && !empty($product['supplier_reference']))
2004 $product['pid'] = $product['supplier_reference'];
2005 else
2006 $product['pid'] = $product['id_product'];
2007 $product['gid'] = $product['pid'];
2008
2009 $xml_googleshopping = $this->getItemXML($product, $lang, $id_curr, $id_shop);
2010 fwrite($googleshoppingfile, $xml_googleshopping);
2011
2012 if (count($attributeCombinations) > 0 && $this->module_conf['export_attributes'] == 1) {
2013 $attr = array();
2014 foreach ($attributeCombinations as $a => $attribute) {
2015 $attr[$attribute['id_product_attribute']][$attribute['id_attribute_group']] = $attribute;
2016 }
2017
2018 $combinum = 0;
2019 foreach ($attr as $id_attr => $v) {
2020 foreach ($v as $k => $a) {
2021 foreach ($this->categories_values[$product['id_gcategory']]['gcat_color[]'] as $c) {
2022 if ($k == $c) {
2023 $product['color'] = $a['attribute_name'];
2024 }
2025 }
2026 foreach ($this->categories_values[$product['id_gcategory']]['gcat_material[]'] as $c) {
2027 if ($k == $c) {
2028 $product['material'] = $a['attribute_name'];
2029 }
2030 }
2031 foreach ($this->categories_values[$product['id_gcategory']]['gcat_pattern[]'] as $c) {
2032 if ($k == $c) {
2033 $product['pattern'] = $a['attribute_name'];
2034 }
2035 }
2036 foreach ($this->categories_values[$product['id_gcategory']]['gcat_size[]'] as $c) {
2037 if ($k == $c) {
2038 $product['size'] = $a['attribute_name'];
2039 }
2040 }
2041 foreach($a as $k => $v){
2042 $product[$k] = $v;
2043 }
2044 }
2045
2046 if (empty($product['color']) && empty($product['material']) && empty($product['pattern']) && empty($product['size']))
2047 continue 2;
2048
2049 $combinum++;
2050 $product['item_group_id'] = $product['pid'];
2051 $product['gid'] = $product['pid'].'-'.$combinum;
2052 $xml_googleshopping = $this->getItemXML($product, $lang, $id_curr, $id_shop, $id_attr);
2053 fwrite($googleshoppingfile, $xml_googleshopping);
2054 $product['color'] = '';
2055 $product['material'] = '';
2056 $product['pattern'] = '';
2057 $product['size'] = '';
2058 }
2059 }
2060 }
2061
2062 $xml = '</channel>'."\n".'</rss>';
2063 fwrite($googleshoppingfile, $xml);
2064 fclose($googleshoppingfile);
2065
2066 @chmod($generate_file_path, 0777);
2067 return array(
2068 'nb_products' => $this->nb_total_products,
2069 'nb_combinations' => $this->nb_combinations,
2070 'nb_prod_w_attr' => count($this->nb_prd_w_attr),
2071 'non_exported_products' => $this->nb_not_exported_products
2072 );
2073 }
2074
2075 private function getItemXML($product, $lang, $id_curr, $id_shop, $combination = false)
2076 {
2077 $xml_googleshopping = '';
2078 $id_lang = (int)$lang['id_lang'];
2079 $title_limit = 70;
2080 $description_limit = 4990;
2081 $languages = Language::getLanguages();
2082 $tailleTabLang = sizeof($languages);
2083 $this->context->language->id = $id_lang;
2084 $this->context->shop->id = $id_shop;
2085 $p = new Product($product['id_product'], true, $id_lang, $id_shop, $this->context);
2086
2087 // Get module configuration for this shop
2088 if (!$combination)
2089 $product['quantity'] = StockAvailable::getQuantityAvailableByProduct($product['id_product'], 0, $id_shop);
2090
2091 // Exclude non-available products
2092 if ($this->module_conf['export_nap'] === 0 && $product['quantity'] < 1) {
2093 $this->nb_not_exported_products++;
2094 return;
2095 }
2096
2097 // Check minimum product price
2098 $price = Product::getPriceStatic((int)$product['id_product'], true);
2099 if ((float)$this->module_conf['export_min_price'] > 0 && (float)$this->module_conf['export_min_price'] > (float)$price)
2100 return;
2101
2102 $cat_link_rew = Category::getLinkRewrite($product['id_gcategory'], (int)$lang);
2103 $product_link = $this->context->link->getProductLink((int)($product['id_product']), $product['link_rewrite'], $cat_link_rew, $product['ean13'], (int)($product['id_lang']), $id_shop, $combination, true);
2104
2105 // Product name
2106 $title_crop = $product['name'];
2107
2108 // Product color attribute, if any
2109 if (!empty($product['color']))
2110 $title_crop .= ' '.$product['color'];
2111 if (!empty($product['material']))
2112 $title_crop .= ' '.$product['material'];
2113 if (!empty($product['pattern']))
2114 $title_crop .= ' '.$product['pattern'];
2115 if (!empty($product['size']))
2116 $title_crop .= ' '.$product['size'];
2117
2118 if (Tools::strlen($product['name']) > $title_limit) {
2119 $title_crop = Tools::substr($title_crop, 0, ($title_limit - 1));
2120 $title_crop = Tools::substr($title_crop, 0, strrpos($title_crop, " "));
2121 }
2122
2123 // Description type
2124 if ($this->module_conf['description'] == 'long')
2125 $description_crop = $product['description'];
2126
2127 else if ($this->module_conf['description'] == 'short')
2128 $description_crop = $product['description_short'];
2129
2130 else if ($this->module_conf['description'] == 'meta')
2131 $description_crop = $product['meta_description'];
2132
2133 $description_crop = $this->rip_tags($description_crop);
2134
2135 if (Tools::strlen($description_crop) > $description_limit) {
2136 $description_crop = Tools::substr($description_crop, 0, ($description_limit - 1));
2137 $description_crop = Tools::substr($description_crop, 0, strrpos($description_crop, " ")).' ...';
2138 }
2139
2140 if ($combination){
2141 $attribute = new Combination($combination);
2142 $feed_reference=$attribute->reference;
2143 } else {
2144 $feed_reference = $product['gid'];
2145 }
2146
2147 $xml_googleshopping .= '<item>'."\n";
2148 $xml_googleshopping .= '<g:id>'.$feed_reference.'</g:id>'."\n";
2149 $xml_googleshopping .= '<title><![CDATA['.$title_crop.']]></title>'."\n";
2150 $xml_googleshopping .= '<description><![CDATA['.$description_crop.']]></description>'."\n";
2151 $xml_googleshopping .= '<link><![CDATA['.htmlspecialchars($product_link, self::REPLACE_FLAGS, self::CHARSET, false).']]></link>'."\n";
2152
2153 // Image links
2154 $images = Image::getImages($lang['id_lang'], $product['id_product'], $combination);
2155 $indexTabLang = 0;
2156 if ($tailleTabLang > 1) {
2157 while (sizeof($images) < 1 && $indexTabLang < $tailleTabLang) {
2158 if ($languages[$indexTabLang]['id_lang'] != $lang['id_lang'])
2159 $images = Image::getImages($languages[$indexTabLang]['id_lang'], $product['id_product']);
2160
2161 $indexTabLang++;
2162 }
2163 }
2164 $nbimages = 0;
2165 $image_type = $this->module_conf['img_type'];
2166
2167 if ($image_type == '')
2168 $image_type = 'large_default';
2169
2170 foreach ($images as $im) {
2171 $image = $this->context->link->getImageLink($product['link_rewrite'], $product['id_product'].'-'.$im['id_image'], $image_type);
2172 $image = preg_replace('*http://'.Tools::getHttpHost().'/*', $this->uri, $image);
2173 if ($im['cover'] == 1 ) {
2174 $xml_googleshopping .= '<g:image_link><![CDATA['.$image.']]></g:image_link>'."\n";
2175 } else {
2176 $xml_googleshopping .= '<g:additional_image_link><![CDATA['.$image.']]></g:additional_image_link>'."\n";
2177 }
2178 // max images by product
2179 if (++$nbimages == 10)
2180 break;
2181 }
2182
2183 // Product condition, or category's condition attribute, or its parent one...
2184 // Product condition = new, used, refurbished
2185 if (empty($product['condition']))
2186 $product['condition'] = $this->categories_values[$product['id_gcategory']]['gcat_condition'];
2187
2188 if (!empty($product['condition']))
2189 $xml_googleshopping .= '<g:condition><![CDATA['.$product['condition'].']]></g:condition>'."\n";
2190
2191 // Shop category
2192 $breadcrumb = GCategories::getPath($product['id_gcategory'], '', $id_lang, $id_shop, $this->id_root);
2193 $product_type = '';
2194
2195 if (!empty($this->module_conf['product_type[]'][$id_lang])) {
2196 $product_type = $this->module_conf['product_type[]'][$id_lang];
2197
2198 if (!empty($breadcrumb))
2199 $product_type .= " > ";
2200 }
2201
2202 $product_type .= $breadcrumb;
2203 $xml_googleshopping .= '<g:product_type><![CDATA['.$product_type.']]></g:product_type>'."\n";
2204
2205 // Matching Google category, or parent categories' one
2206 $product['gcategory'] = $this->categories_values[$product['category_default']]['gcategory'];
2207 $xml_googleshopping .= '<g:google_product_category><![CDATA['.$product['gcategory'].']]></g:google_product_category>'."\n";
2208
2209 // Product quantity & availability
2210 if (empty($this->categories_values[$product['category_default']]['gcat_avail'])) {
2211 if ($this->module_conf['quantity'] == 1)
2212 $xml_googleshopping .= '<g:quantity>'.$product['quantity'].'</g:quantity>'."\n";
2213
2214 if ($product['quantity'] > 0 && $product['available_for_order'])
2215 $xml_googleshopping .= '<g:availability>in stock</g:availability>'."\n";
2216 elseif($p->isAvailableWhenOutOfStock((int)$p->out_of_stock) && $product['available_for_order'])
2217 $xml_googleshopping .= '<g:availability>preorder</g:availability>'."\n";
2218 else
2219 $xml_googleshopping .= '<g:availability>out of stock</g:availability>'."\n";
2220 }
2221
2222 else {
2223 if ($this->module_conf['quantity'] == 1 && $product['quantity'] > 0)
2224 $xml_googleshopping .= '<g:quantity>'.$product['quantity'].'</g:quantity>'."\n";
2225 $xml_googleshopping .= '<g:availability>'.$this->categories_values[$product['category_default']]['gcat_avail'].'</g:availability>'."\n";
2226 }
2227
2228 // Price(s)
2229 $currency = new Currency((int)$id_curr);
2230 $use_tax = ($product['tax_included'] ? true : false);
2231 $no_tax = (!$use_tax ? true : false);
2232 $product['price'] = (float)$p->getPriceStatic($product['id_product'], $use_tax, $combination)*$currency->conversion_rate;
2233 $product['price_without_reduct'] = (float)$p->getPriceWithoutReduct($no_tax, $combination)*$currency->conversion_rate;
2234 $product['price'] = number_format(round($product['price'], 2, PHP_ROUND_HALF_DOWN), 2, '.', ' ');
2235 $product['price_without_reduct'] = number_format(round($product['price_without_reduct'], 2, PHP_ROUND_HALF_DOWN), 2, '.', ' ');
2236 if ((float)($product['price']) < (float)($product['price_without_reduct'])) {
2237 $xml_googleshopping .= '<g:price>'.$product['price_without_reduct'].' '.$currency->iso_code.'</g:price>'."\n";
2238 $xml_googleshopping .= '<g:sale_price>'.$product['price'].' '.$currency->iso_code.'</g:sale_price>'."\n";
2239 }
2240 else
2241 $xml_googleshopping .= '<g:price>'.$product['price'].' '.$currency->iso_code.'</g:price>'."\n";
2242
2243 $identifier_exists = 0;
2244 // GTIN (EAN, UPC, JAN, ISBN)
2245 if (!empty($product['ean13'])) {
2246 $xml_googleshopping .= '<g:gtin>'.$product['ean13'].'</g:gtin>'."\n";
2247 $identifier_exists++;
2248 }
2249
2250 // Brand
2251 if ($this->module_conf['no_brand'] != 0 && !empty($product['id_manufacturer'])) {
2252 $xml_googleshopping .= '<g:brand><![CDATA['.htmlspecialchars(Manufacturer::getNameById((int)$product['id_manufacturer']), self::REPLACE_FLAGS, self::CHARSET, false).']]></g:brand>'."\n";
2253 $identifier_exists++;
2254 }
2255
2256 // MPN
2257 if (empty($product['supplier_reference']))
2258 $product['supplier_reference'] = ProductSupplier::getProductSupplierReference($product['id_product'], 0, $product['id_supplier']);
2259
2260 if ($this->module_conf['mpn_type'] == 'reference' && !empty($product['reference'])) {
2261 $xml_googleshopping .= '<g:mpn><![CDATA['.$product['reference'].']]></g:mpn>'."\n";
2262 $identifier_exists++;
2263 }
2264
2265 else if ($this->module_conf['mpn_type'] == 'supplier_reference' && !empty($product['supplier_reference'])) {
2266 $xml_googleshopping .= '<g:mpn><![CDATA['.$product['supplier_reference'].']]></g:mpn>'."\n";
2267 $identifier_exists++;
2268 }
2269
2270 // Tag "identifier_exists"
2271 if ($this->module_conf['id_exists_tag'] && $identifier_exists < 2) {
2272 $xml_googleshopping .= '<g:identifier_exists>FALSE</g:identifier_exists>'."\n";
2273 }
2274
2275 // Product gender and age_group attributes association
2276 $product_features = $this->getProductFeatures($product['id_product'], $id_lang, $id_shop);
2277 $product['gender'] = $this->categories_values[$product['category_default']]['gcat_gender'];
2278 $product['age_group'] = $this->categories_values[$product['category_default']]['gcat_age_group'];
2279 foreach ($product_features as $feature) {
2280 switch ($feature['id_feature']) {
2281 case $this->module_conf['gender']:
2282 $product['gender'] = $feature['value'];
2283 continue 2;
2284
2285 case $this->module_conf['age_group']:
2286 $product['age_group'] = $feature['value'];
2287 continue 2;
2288 }
2289
2290 if (!$product['color']) {
2291 foreach ($this->module_conf['color[]'] as $id => $v)
2292 if ($v == $feature['id_feature'])
2293 $product['color'] = $feature['value'];
2294 }
2295 if (!$product['material']) {
2296 foreach ($this->module_conf['material[]'] as $id => $v)
2297 if ($v == $feature['id_feature'])
2298 $product['material'] = $feature['value'];
2299 }
2300 if (!$product['pattern']) {
2301 foreach ($this->module_conf['pattern[]'] as $id => $v)
2302 if ($v == $feature['id_feature'])
2303 $product['pattern'] = $feature['value'];
2304 }
2305 if (!$product['size']) {
2306 foreach ($this->module_conf['size[]'] as $id => $v)
2307 if ($v == $feature['id_feature'])
2308 $product['size'] = $feature['value'];
2309 }
2310 }
2311
2312 // Product gender attribute, or category gender attribute, or parent's one
2313 if (!empty($product['gender']))
2314 $xml_googleshopping .= '<g:gender><![CDATA['.$product['gender'].']]></g:gender>'."\n";
2315
2316 // Product age_group attribute, or category age_group attribute, or parent's one
2317 if (!empty($product['age_group']))
2318 $xml_googleshopping .= '<g:age_group><![CDATA['.$product['age_group'].']]></g:age_group>'."\n";
2319
2320 // Product attributes combination groups
2321 if ($combination && !empty($product['item_group_id']))
2322 $xml_googleshopping .= '<g:item_group_id>'.$product['item_group_id'].'</g:item_group_id>'."\n";
2323
2324 // Product color attribute, or category color attribute, or parent's one
2325 if (!empty($product['color']))
2326 $xml_googleshopping .= '<g:color><![CDATA['.$product['color'].']]></g:color>'."\n";
2327
2328 // Product material attribute, or category material attribute, or parent's one
2329 if (!empty($product['material']))
2330 $xml_googleshopping .= '<g:material><![CDATA['.$product['material'].']]></g:material>'."\n";
2331
2332 // Product pattern attribute, or category pattern attribute, or parent's one
2333 if (!empty($product['pattern']))
2334 $xml_googleshopping .= '<g:pattern><![CDATA['.$product['pattern'].']]></g:pattern>'."\n";
2335
2336 // Product size attribute, or category size attribute, or parent's one
2337 if (!empty($product['size']))
2338 $xml_googleshopping .= '<g:size><![CDATA['.$product['size'].']]></g:size>'."\n";
2339
2340 // Featured products
2341 if ($this->module_conf['featured_products'] == 1 && $product['on_sale'] != '0') {
2342 $xml_googleshopping .= '<g:featured_product>true</g:featured_product>'."\n";
2343 }
2344
2345 // Shipping
2346 $xml_googleshopping .= '<g:shipping>'."\n";
2347 $xml_googleshopping .= "\t".'<g:country>'.$this->module_conf['shipping_country'].'</g:country>'."\n";
2348 $xml_googleshopping .= "\t".'<g:service>Standard</g:service>'."\n";
2349 $xml_googleshopping .= "\t".'<g:price>'.number_format($this->module_conf['shipping_price'], 2, '.', ' ').' '.$currency->iso_code.'</g:price>'."\n";
2350 $xml_googleshopping .= '</g:shipping>'."\n";
2351
2352 // Shipping weight
2353 if ($product['weight'] != '0') {
2354 $xml_googleshopping .= '<g:shipping_weight>'.number_format($product['weight'], 2, '.', '').' '.Configuration::get('PS_WEIGHT_UNIT').'</g:shipping_weight>'."\n";
2355 }
2356
2357 $xml_googleshopping .= '</item>'."\n\n";
2358
2359 if ($combination) {
2360 $this->nb_combinations++;
2361 $this->nb_prd_w_attr[$product['id_product']] = 1;
2362 }
2363 $this->nb_total_products++;
2364
2365 return $xml_googleshopping;
2366 }
2367}