From 34a7c7667d442cc4374cf840c969dcbd30ed1c94 Mon Sep 17 00:00:00 2001 From: Norbert Penel Date: Fri, 11 Aug 2017 14:40:29 +0200 Subject: [PATCH] Add Dolistore module Explore and find dolistore modules directly in your Dolibarr --- htdocs/dolistore/ajax/image.php | 65 + .../class/PSWebServiceLibrary.class.php | 409 ++++ htdocs/dolistore/class/dolistore.class.php | 308 +++ htdocs/dolistore/class/init.php | 72 + .../core/modules/modDolistore.class.php | 159 ++ htdocs/dolistore/css/dolistore.css | 234 ++ htdocs/dolistore/img/Download-128.png | Bin 0 -> 761 bytes htdocs/dolistore/img/NoImageAvailable.png | Bin 0 -> 11231 bytes htdocs/dolistore/img/compatible.png | Bin 0 -> 2147 bytes htdocs/dolistore/img/dolistore.png | Bin 0 -> 11317 bytes htdocs/dolistore/img/follow.png | Bin 0 -> 2869 bytes htdocs/dolistore/img/object_dolistore.png | Bin 0 -> 1851 bytes htdocs/dolistore/index.php | 115 + htdocs/dolistore/js/dolistore.js.php | 79 + htdocs/dolistore/js/fancybox/blank.gif | Bin 0 -> 43 bytes .../js/fancybox/fancybox_loading.gif | Bin 0 -> 6567 bytes .../js/fancybox/fancybox_loading@2x.gif | Bin 0 -> 13984 bytes .../js/fancybox/fancybox_overlay.png | Bin 0 -> 1003 bytes .../dolistore/js/fancybox/fancybox_sprite.png | Bin 0 -> 1362 bytes .../js/fancybox/fancybox_sprite@2x.png | Bin 0 -> 6553 bytes .../js/fancybox/helpers/fancybox_buttons.png | Bin 0 -> 1080 bytes .../helpers/jquery.fancybox-buttons.css | 97 + .../helpers/jquery.fancybox-buttons.js | 122 + .../fancybox/helpers/jquery.fancybox-media.js | 201 ++ .../helpers/jquery.fancybox-thumbs.css | 55 + .../helpers/jquery.fancybox-thumbs.js | 165 ++ .../dolistore/js/fancybox/jquery.fancybox.css | 275 +++ .../dolistore/js/fancybox/jquery.fancybox.js | 2018 +++++++++++++++++ .../js/fancybox/jquery.fancybox.pack.js | 46 + htdocs/dolistore/langs/de_DE/dolistore.lang | 22 + htdocs/dolistore/langs/en_EN/dolistore.lang | 22 + htdocs/dolistore/langs/es_ES/dolistore.lang | 22 + htdocs/dolistore/langs/fr_FR/dolistore.lang | 22 + htdocs/dolistore/langs/it_IT/dolistore.lang | 22 + 34 files changed, 4530 insertions(+) create mode 100644 htdocs/dolistore/ajax/image.php create mode 100644 htdocs/dolistore/class/PSWebServiceLibrary.class.php create mode 100644 htdocs/dolistore/class/dolistore.class.php create mode 100644 htdocs/dolistore/class/init.php create mode 100644 htdocs/dolistore/core/modules/modDolistore.class.php create mode 100644 htdocs/dolistore/css/dolistore.css create mode 100644 htdocs/dolistore/img/Download-128.png create mode 100644 htdocs/dolistore/img/NoImageAvailable.png create mode 100644 htdocs/dolistore/img/compatible.png create mode 100644 htdocs/dolistore/img/dolistore.png create mode 100644 htdocs/dolistore/img/follow.png create mode 100644 htdocs/dolistore/img/object_dolistore.png create mode 100644 htdocs/dolistore/index.php create mode 100644 htdocs/dolistore/js/dolistore.js.php create mode 100644 htdocs/dolistore/js/fancybox/blank.gif create mode 100644 htdocs/dolistore/js/fancybox/fancybox_loading.gif create mode 100644 htdocs/dolistore/js/fancybox/fancybox_loading@2x.gif create mode 100644 htdocs/dolistore/js/fancybox/fancybox_overlay.png create mode 100644 htdocs/dolistore/js/fancybox/fancybox_sprite.png create mode 100644 htdocs/dolistore/js/fancybox/fancybox_sprite@2x.png create mode 100644 htdocs/dolistore/js/fancybox/helpers/fancybox_buttons.png create mode 100644 htdocs/dolistore/js/fancybox/helpers/jquery.fancybox-buttons.css create mode 100644 htdocs/dolistore/js/fancybox/helpers/jquery.fancybox-buttons.js create mode 100644 htdocs/dolistore/js/fancybox/helpers/jquery.fancybox-media.js create mode 100644 htdocs/dolistore/js/fancybox/helpers/jquery.fancybox-thumbs.css create mode 100644 htdocs/dolistore/js/fancybox/helpers/jquery.fancybox-thumbs.js create mode 100644 htdocs/dolistore/js/fancybox/jquery.fancybox.css create mode 100644 htdocs/dolistore/js/fancybox/jquery.fancybox.js create mode 100644 htdocs/dolistore/js/fancybox/jquery.fancybox.pack.js create mode 100644 htdocs/dolistore/langs/de_DE/dolistore.lang create mode 100644 htdocs/dolistore/langs/en_EN/dolistore.lang create mode 100644 htdocs/dolistore/langs/es_ES/dolistore.lang create mode 100644 htdocs/dolistore/langs/fr_FR/dolistore.lang create mode 100644 htdocs/dolistore/langs/it_IT/dolistore.lang diff --git a/htdocs/dolistore/ajax/image.php b/htdocs/dolistore/ajax/image.php new file mode 100644 index 00000000000..5bc6c9f2f0f --- /dev/null +++ b/htdocs/dolistore/ajax/image.php @@ -0,0 +1,65 @@ +. + * + * This program is free software; you can redistribute it and/or modifyion 2.0 (the "License"); + * it under the terms of the GNU General Public License as published bypliance with the License. + * the Free Software Foundation; either version 3 of the License, or + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see http://www.gnu.org/ + */ + +if (!defined('REQUIRE_JQUERY_BLOCKUI')) define('REQUIRE_JQUERY_BLOCKUI', 1); +/** + * \file htdocs/commande/info.php + * \ingroup commande + * \brief Page des informations d'une commande + */ +$res = 0; +if (!$res && file_exists("../main.inc.php")) $res = @include("../main.inc.php"); +if (!$res && file_exists("../../main.inc.php")) $res = @include("../../main.inc.php"); +if (!$res && file_exists("../../../main.inc.php")) $res = @include("../../../main.inc.php"); +if (!$res && file_exists("../../../../main.inc.php")) $res = @include("../../../../main.inc.php"); +if (!$res && file_exists("../../../dolibarr/htdocs/main.inc.php")) + $res = @include("../../../dolibarr/htdocs/main.inc.php"); // Used on dev env only +if (!$res && file_exists("../../../../dolibarr/htdocs/main.inc.php")) + $res = @include("../../../../dolibarr/htdocs/main.inc.php"); // Used on dev env only +if (!$res && file_exists("../../../../../dolibarr/htdocs/main.inc.php")) + $res = @include("../../../../../dolibarr/htdocs/main.inc.php"); // Used on dev env only +if (!$res) die("Include of main fails"); + +// CORE + +global $lang, $user, $conf; + + +dol_include_once('/dolistore/class/dolistore.class.php'); +$dolistore = new Dolistore(); + +$id_product = GETPOST('id_product', 'int'); +$id_image = GETPOST('id_image', 'int'); +// quality : image resize with this in the URL : "cart_default", "home_default", "large_default", "medium_default", "small_default", "thickbox_default" +$quality = GETPOST('quality', 'alpha'); + +try { + $url = $conf->global->MAIN_MODULE_DOLISTORE_API_SRV.'/api/images/products/'.$id_product.'/'.$id_image.'/'.$quality; + $api = new PrestaShopWebservice($conf->global->MAIN_MODULE_DOLISTORE_API_SRV, + $conf->global->MAIN_MODULE_DOLISTORE_API_KEY, $dolistore->debug_api); + //echo $url; + $request = $api->executeRequest($url, array(CURLOPT_CUSTOMREQUEST => 'GET')); + header('Content-type:image'); + print $request['response']; +} catch (PrestaShopWebserviceException $e) { + // Here we are dealing with errors + $trace = $e->getTrace(); + if ($trace[0]['args'][0] == 404) die('Bad ID'); + else if ($trace[0]['args'][0] == 401) die('Bad auth key'); + else die('Can not access to '.$conf->global->MAIN_MODULE_DOLISTORE_API_SRV); +} \ No newline at end of file diff --git a/htdocs/dolistore/class/PSWebServiceLibrary.class.php b/htdocs/dolistore/class/PSWebServiceLibrary.class.php new file mode 100644 index 00000000000..8f55f6fd323 --- /dev/null +++ b/htdocs/dolistore/class/PSWebServiceLibrary.class.php @@ -0,0 +1,409 @@ + +* @copyright 2007-2013 PrestaShop SA +* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) +* International Registered Trademark & Property of PrestaShop SA +* PrestaShop Webservice Library +* @package PrestaShopWebservice +*/ + +/** + * @package PrestaShopWebservice + */ +class PrestaShopWebservice +{ + + /** @var string Shop URL */ + protected $url; + + /** @var string Authentification key */ + protected $key; + + /** @var boolean is debug activated */ + protected $debug; + + /** @var string PS version */ + protected $version; + + /** @var array compatible versions of PrestaShop Webservice */ + const psCompatibleVersionsMin = '1.4.0.0'; + const psCompatibleVersionsMax = '1.6.99.99'; + + /** + * PrestaShopWebservice constructor. Throw an exception when CURL is not installed/activated + * + * getMessage(); + * } + * ?> + * + * @param string $url Root URL for the shop + * @param string $key Authentification key + * @param mixed $debug Debug mode Activated (true) or deactivated (false) + */ + function __construct($url, $key, $debug = true) { + if (!extension_loaded('curl')) + throw new PrestaShopWebserviceException('Please activate the PHP extension \'curl\' to allow use of PrestaShop webservice library'); + $this->url = $url; + $this->key = $key; + $this->debug = $debug; + $this->version = 'unknown'; + } + + /** + * Take the status code and throw an exception if the server didn't return 200 or 201 code + * @param int $status_code Status code of an HTTP return + */ + protected function checkStatusCode($status_code) + { + $error_label = 'This call to PrestaShop Web Services failed and returned an HTTP status of %d. That means: %s.'; + switch($status_code) + { + case 200: case 201: break; + case 204: throw new PrestaShopWebserviceException(sprintf($error_label, $status_code, 'No content'));break; + case 400: throw new PrestaShopWebserviceException(sprintf($error_label, $status_code, 'Bad Request'));break; + case 401: throw new PrestaShopWebserviceException(sprintf($error_label, $status_code, 'Unauthorized'));break; + case 404: throw new PrestaShopWebserviceException(sprintf($error_label, $status_code, 'Not Found'));break; + case 405: throw new PrestaShopWebserviceException(sprintf($error_label, $status_code, 'Method Not Allowed'));break; + case 500: throw new PrestaShopWebserviceException(sprintf($error_label, $status_code, 'Internal Server Error'));break; + default: throw new PrestaShopWebserviceException('This call to PrestaShop Web Services returned an unexpected HTTP status of:' . $status_code); + } + } + /** + * Handles a CURL request to PrestaShop Webservice. Can throw exception. + * @param string $url Resource name + * @param mixed $curl_params CURL parameters (sent to curl_set_opt) + * @return array status_code, response + */ + public function executeRequest($url, $curl_params = array()) + { + $defaultParams = array( + CURLOPT_HEADER => TRUE, + CURLOPT_RETURNTRANSFER => TRUE, + CURLINFO_HEADER_OUT => TRUE, + CURLOPT_HTTPAUTH => CURLAUTH_BASIC, + CURLOPT_USERPWD => $this->key.':', + CURLOPT_HTTPHEADER => array( 'Expect:' ) + ); + + $session = curl_init($url); + + $curl_options = array(); + foreach ($defaultParams as $defkey => $defval) + { + if (isset($curl_params[$defkey])) + $curl_options[$defkey] = $curl_params[$defkey]; + else + $curl_options[$defkey] = $defaultParams[$defkey]; + } + foreach ($curl_params as $defkey => $defval) + if (!isset($curl_options[$defkey])) + $curl_options[$defkey] = $curl_params[$defkey]; + + curl_setopt_array($session, $curl_options); + $response = curl_exec($session); + + $index = strpos($response, "\r\n\r\n"); + if ($index === false && $curl_params[CURLOPT_CUSTOMREQUEST] != 'HEAD') + throw new PrestaShopWebserviceException('Bad HTTP response'); + + $header = substr($response, 0, $index); + $body = substr($response, $index + 4); + + $headerArrayTmp = explode("\n", $header); + + $headerArray = array(); + foreach ($headerArrayTmp as &$headerItem) + { + $tmp = explode(':', $headerItem); + $tmp = array_map('trim', $tmp); + if (count($tmp) == 2) + $headerArray[$tmp[0]] = $tmp[1]; + } + + if (array_key_exists('PSWS-Version', $headerArray)) + { + $this->version = $headerArray['PSWS-Version']; + if ( + version_compare(PrestaShopWebservice::psCompatibleVersionsMin, $headerArray['PSWS-Version']) == 1 || + version_compare(PrestaShopWebservice::psCompatibleVersionsMax, $headerArray['PSWS-Version']) == -1 + ) + throw new PrestaShopWebserviceException('This library is not compatible with this version of PrestaShop. Please upgrade/downgrade this library'); + } + + if ($this->debug) + { + $this->printDebug('HTTP REQUEST HEADER', curl_getinfo($session, CURLINFO_HEADER_OUT)); + $this->printDebug('HTTP RESPONSE HEADER', $header); + + } + $status_code = curl_getinfo($session, CURLINFO_HTTP_CODE); + if ($status_code === 0) + throw new PrestaShopWebserviceException('CURL Error: '.curl_error($session)); + curl_close($session); + if ($this->debug) + { + if ($curl_params[CURLOPT_CUSTOMREQUEST] == 'PUT' || $curl_params[CURLOPT_CUSTOMREQUEST] == 'POST') + $this->printDebug('XML SENT', urldecode($curl_params[CURLOPT_POSTFIELDS])); + if ($curl_params[CURLOPT_CUSTOMREQUEST] != 'DELETE' && $curl_params[CURLOPT_CUSTOMREQUEST] != 'HEAD') + $this->printDebug('RETURN HTTP BODY', $body); + } + return array('status_code' => $status_code, 'response' => $body, 'header' => $header); + } + + public function printDebug($title, $content) + { + echo '
'.$title.'
'.htmlentities($content).'
'; + } + + public function getVersion() + { + return $this->version; + } + + /** + * Load XML from string. Can throw exception + * @param string $response String from a CURL response + * @return SimpleXMLElement status_code, response + */ + protected function parseXML($response) + { + if ($response != '') + { + libxml_clear_errors(); + libxml_use_internal_errors(true); + $xml = simplexml_load_string($response,'SimpleXMLElement', LIBXML_NOCDATA); + if (libxml_get_errors()) + { + $msg = var_export(libxml_get_errors(), true); + libxml_clear_errors(); + throw new PrestaShopWebserviceException('HTTP XML response is not parsable: '.$msg); + } + return $xml; + } + else + throw new PrestaShopWebserviceException('HTTP response is empty'); + } + + /** + * Add (POST) a resource + *

Unique parameter must take :

+ * 'resource' => Resource name
+ * 'postXml' => Full XML string to add resource

+ * Examples are given in the tutorial

+ * @param array $options + * @return SimpleXMLElement status_code, response + */ + public function add($options) + { + $xml = ''; + + if (isset($options['resource'], $options['postXml']) || isset($options['url'], $options['postXml'])) + { + $url = (isset($options['resource']) ? $this->url.'/api/'.$options['resource'] : $options['url']); + $xml = $options['postXml']; + if (isset($options['id_shop'])) + $url .= '&id_shop='.$options['id_shop']; + if (isset($options['id_group_shop'])) + $url .= '&id_group_shop='.$options['id_group_shop']; + } + else + throw new PrestaShopWebserviceException('Bad parameters given'); + $request = self::executeRequest($url, array(CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS => $xml)); + + self::checkStatusCode($request['status_code']); + return self::parseXML($request['response']); + } + + /** + * Retrieve (GET) a resource + *

Unique parameter must take :

+ * 'url' => Full URL for a GET request of Webservice (ex: http://mystore.com/api/customers/1/)
+ * OR
+ * 'resource' => Resource name,
+ * 'id' => ID of a resource you want to get

+ *

+ * + * get(array('resource' => 'orders', 'id' => 1)); + * // Here in $xml, a SimpleXMLElement object you can parse + * foreach ($xml->children()->children() as $attName => $attValue) + * echo $attName.' = '.$attValue.'
'; + * } + * catch (PrestaShopWebserviceException $ex) + * { + * echo 'Error : '.$ex->getMessage(); + * } + * ?> + *
+ * @param array $options Array representing resource to get. + * @return SimpleXMLElement status_code, response + */ + public function get($options) + { + if (isset($options['url'])) + $url = $options['url']; + elseif (isset($options['resource'])) + { + $url = $this->url.'/api/'.$options['resource']; + $url_params = array(); + if (isset($options['id'])) + $url .= '/'.$options['id']; + + $params = array('filter', 'display', 'sort', 'limit', 'id_shop', 'id_group_shop'); + foreach ($params as $p) + foreach ($options as $k => $o) + if (strpos($k, $p) !== false) + $url_params[$k] = $options[$k]; + if (count($url_params) > 0) + $url .= '?'.http_build_query($url_params); + } + else + throw new PrestaShopWebserviceException('Bad parameters given '); + + $request = self::executeRequest($url, array(CURLOPT_CUSTOMREQUEST => 'GET')); + self::checkStatusCode($request['status_code']);// check the response validity + return self::parseXML($request['response']); + } + + /** + * Head method (HEAD) a resource + * + * @param array $options Array representing resource for head request. + * @return SimpleXMLElement status_code, response + */ + public function head($options) + { + if (isset($options['url'])) + $url = $options['url']; + elseif (isset($options['resource'])) + { + $url = $this->url.'/api/'.$options['resource']; + $url_params = array(); + if (isset($options['id'])) + $url .= '/'.$options['id']; + + $params = array('filter', 'display', 'sort', 'limit'); + foreach ($params as $p) + foreach ($options as $k => $o) + if (strpos($k, $p) !== false) + $url_params[$k] = $options[$k]; + if (count($url_params) > 0) + $url .= '?'.http_build_query($url_params); + } + else + throw new PrestaShopWebserviceException('Bad parameters given'); + $request = self::executeRequest($url, array(CURLOPT_CUSTOMREQUEST => 'HEAD', CURLOPT_NOBODY => true)); + self::checkStatusCode($request['status_code']);// check the response validity + return $request['header']; + } + /** + * Edit (PUT) a resource + *

Unique parameter must take :

+ * 'resource' => Resource name ,
+ * 'id' => ID of a resource you want to edit,
+ * 'putXml' => Modified XML string of a resource

+ * Examples are given in the tutorial

+ * @param array $options Array representing resource to edit. + */ + public function edit($options) + { + $xml = ''; + if (isset($options['url'])) + $url = $options['url']; + elseif ((isset($options['resource'], $options['id']) || isset($options['url'])) && $options['putXml']) + { + $url = (isset($options['url']) ? $options['url'] : $this->url.'/api/'.$options['resource'].'/'.$options['id']); + $xml = $options['putXml']; + if (isset($options['id_shop'])) + $url .= '&id_shop='.$options['id_shop']; + if (isset($options['id_group_shop'])) + $url .= '&id_group_shop='.$options['id_group_shop']; + } + else + throw new PrestaShopWebserviceException('Bad parameters given'); + + $request = self::executeRequest($url, array(CURLOPT_CUSTOMREQUEST => 'PUT', CURLOPT_POSTFIELDS => $xml)); + self::checkStatusCode($request['status_code']);// check the response validity + return self::parseXML($request['response']); + } + + /** + * Delete (DELETE) a resource. + * Unique parameter must take :

+ * 'resource' => Resource name
+ * 'id' => ID or array which contains IDs of a resource(s) you want to delete

+ * + * delete(array('resource' => 'orders', 'id' => 1)); + * // Following code will not be executed if an exception is thrown. + * echo 'Successfully deleted.'; + * } + * catch (PrestaShopWebserviceException $ex) + * { + * echo 'Error : '.$ex->getMessage(); + * } + * ?> + * + * @param array $options Array representing resource to delete. + */ + public function delete($options) + { + if (isset($options['url'])) + $url = $options['url']; + elseif (isset($options['resource']) && isset($options['id'])) + if (is_array($options['id'])) + $url = $this->url.'/api/'.$options['resource'].'/?id=['.implode(',', $options['id']).']'; + else + $url = $this->url.'/api/'.$options['resource'].'/'.$options['id']; + if (isset($options['id_shop'])) + $url .= '&id_shop='.$options['id_shop']; + if (isset($options['id_group_shop'])) + $url .= '&id_group_shop='.$options['id_group_shop']; + $request = self::executeRequest($url, array(CURLOPT_CUSTOMREQUEST => 'DELETE')); + self::checkStatusCode($request['status_code']);// check the response validity + return true; + } + + +} + +/** + * @package PrestaShopWebservice + */ +class PrestaShopWebserviceException extends Exception { } \ No newline at end of file diff --git a/htdocs/dolistore/class/dolistore.class.php b/htdocs/dolistore/class/dolistore.class.php new file mode 100644 index 00000000000..35900d66f7d --- /dev/null +++ b/htdocs/dolistore/class/dolistore.class.php @@ -0,0 +1,308 @@ +. + * + * This program is free software; you can redistribute it and/or modifyion 2.0 (the "License"); + * it under the terms of the GNU General Public License as published bypliance with the License. + * the Free Software Foundation; either version 3 of the License, or + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see http://www.gnu.org/ + */ +dol_include_once('/core/lib/admin.lib.php'); +dol_include_once('/dolistore/class/PSWebServiceLibrary.class.php'); + +class Dolistore extends DolistoreModel +{ + // params + public $start // beginning of pagination + , $end // end of pagination + , $per_page // pagination: display per page + , $categorie // the current categorie + , $search // the search keywords + // setups + , $url // the url of this page + , $shop_url // the url of the shop + , $vat_rate // the vat rate used in the shop (prices are provided without vat) + , $lang // the integer representing the lang in the store + , $debug_api; // usefull if no dialog + + function __construct($options = array('start' => 0, 'end' => 10, 'per_page' => 50, 'categorie' => 0)) + { + global $conf, $langs; + + $this->start = $options['start']; + $this->end = $options['end']; + $this->per_page = $options['per_page']; + $this->categorie = $options['categorie']; + $this->search = $options['search']; + + $this->url = dol_buildpath('/dolistore/index.php', 2); + $this->shop_url = 'https://www.dolistore.com/index.php?controller=product&id_product='; + $this->vat_rate = 1.2; // 20% de TVA + $this->debug_api = false; + + if ($this->end == 0) { + $this->end = $this->per_page; + } + + $lang = explode('_', $langs->defaultlang); + $lang = $lang[0]; + $lang_array = ['fr', 'en', 'es', 'it', 'de']; + if (!in_array($lang, $lang_array)) { + $lang = 'en'; + } + $this->lang = array_search($lang, $lang_array) + 1; // 1=fr 2=en ... + + try { + $this->api = new PrestaShopWebservice($conf->global->MAIN_MODULE_DOLISTORE_API_SRV, + $conf->global->MAIN_MODULE_DOLISTORE_API_KEY, $this->debug_api); + + // Here we set the option array for the Webservice : we want products resources + $opt = array(); + $opt['resource'] = 'products'; + // make a search to limit the id returned. + if ($this->search != '') { + $opt2 = array(); + $opt2['url'] = $conf->global->MAIN_MODULE_DOLISTORE_API_SRV.'/api/search?query='.$this->search.'&language='.$this->lang; + // Call + $xml = $this->api->get($opt2); + $products = array(); + foreach ($xml->products->children() as $product) { + $products[] = (int) $product['id']; + } + $opt['filter[id]'] = '['.implode('|', $products).']'; + } elseif ($this->categorie != 0) { + $opt2 = array(); + $opt2['resource'] = 'categories'; + $opt2['id'] = $this->categorie; + // Call + $xml = $this->api->get($opt2); + $products = array(); + foreach ($xml->category->associations->products->children() as $product) { + $products[] = (int) $product->id; + } + $opt['filter[id]'] = '['.implode('|', $products).']'; + } + $opt['display'] = '[id,name,id_default_image,id_category_default,reference,price,condition,show_price,date_add,date_upd,description_short,description,module_version,dolibarr_min,dolibarr_max]'; + $opt['sort'] = 'id_desc'; + $opt['filter[active]'] = '[1]'; + $opt['limit'] = "$this->start,$this->end"; + // Call + $xml = $this->api->get($opt); + $this->products = $xml->products->children(); + + + // Here we set the option array for the Webservice : we want categories resources + $opt = array(); + $opt['resource'] = 'categories'; + $opt['display'] = '[id,id_parent,nb_products_recursive,active,is_root_category,name,description]'; + $opt['sort'] = 'id_asc'; + // Call + $xml = $this->api->get($opt); + $this->categories = $xml->categories->children(); + } catch (PrestaShopWebserviceException $e) { + // Here we are dealing with errors + $trace = $e->getTrace(); + if ($trace[0]['args'][0] == 404) die('Bad ID'); + else if ($trace[0]['args'][0] == 401) die('Bad auth key'); + else die('Can not access to '.$conf->global->MAIN_MODULE_DOLISTORE_API_SRV); + } + } + + function get_previous_url() + { + $param_array = array(); + if ($this->start < $this->per_page) { + $sub = 0; + } else { + $sub = $this->per_page; + } + $param_array['start'] = $this->start - $sub; + $param_array['end'] = $this->end - $sub; + if ($this->categorie != 0) { + $param_array['categorie'] = $this->categorie; + } + $param = http_build_query($param_array); + return $this->url."?$param"; + } + + function get_next_url() + { + $param_array = array(); + if (count($this->products) < $this->per_page) { + $add = 0; + } else { + $add = $this->per_page; + } + $param_array['start'] = $this->start + $add; + $param_array['end'] = $this->end + $add; + if ($this->categorie != 0) { + $param_array['categorie'] = $this->categorie; + } + $param = http_build_query($param_array); + return $this->url."?$param"; + } + + function version_compare($v1, $v2) + { + $v1 = explode('.', $v1); + $v2 = explode('.', $v2); + $ret = 0; + $level = 0; + $count1 = count($v1); + $count2 = count($v2); + $maxcount = max($count1, $count2); + while ($level < $maxcount) { + $operande1 = isset($v1[$level]) ? $v1[$level] : 'x'; + $operande2 = isset($v2[$level]) ? $v2[$level] : 'x'; + $level++; + if (strtoupper($operande1) == 'X' || strtoupper($operande2) == 'X' || $operande1 == '*' || $operande2 == '*') { + break; + } + if ($operande1 < $operande2) { + $ret = -$level; + break; + } + if ($operande1 > $operande2) { + $ret = $level; + break; + } + } + //print join('.',$versionarray1).'('.count($versionarray1).') / '.join('.',$versionarray2).'('.count($versionarray2).') => '.$ret.'
'."\n"; + return $ret; + } +} + +class DolistoreModel +{ + + function get_categories($parent = 0) + { + if (!isset($this->categories)) die('not possible'); + if ($parent != 0) { + $html = '
    '; + } else { + $html = ''; + } + + for ($i = 0; $i < count($this->categories); $i++) { + $cat = $this->categories[$i]; + if ($cat->is_root_category == 1 && $parent == 0) { + $html .= '
  • '.$cat->name->language[$this->lang].' '.$cat->nb_products_recursive.'

    '; + $html .= self::get_categories($cat->id); + $html .= "
  • \n"; + } elseif (trim($cat->id_parent) == $parent && $cat->active == 1 && trim($cat->id_parent) != 0) { // si cat est de ce niveau + $select = ($cat->id == $this->categorie) ? ' selected' : ''; + $html .= '
  • '.$cat->name->language[$this->lang].' '.$cat->nb_products_recursive.''; + $html .= self::get_categories($cat->id); + $html .= "
  • \n"; + } else { + + } + } + + if ($html == '
      ') { + return ''; + } + if ($parent != 0) { + return $html.'
    '; + } else { + return $html; + } + } + + function get_products() + { + global $langs, $conf; + $html = ""; + $parity = "pair"; + $last_month = time() - (30 * 24 * 60 * 60); + foreach ($this->products as $product) { + $parity = ($parity == "impair") ? 'pair' : 'impair'; + + // check new product ? + $newapp = ''; + if ($last_month < strtotime($product->date_add)) { + $newapp .= ''.$langs->trans('New').' '; + } + + // check updated ? + if ($last_month < strtotime($product->date_upd) && $newapp == '') { + $newapp .= ''.$langs->trans('Updated').' '; + } + + // add image or default ? + if ($product->id_default_image != '') { + $image_url = dol_buildPath('/dolistore/ajax/image.php?id_product=', 2).$product->id.'&id_image='.$product->id_default_image; + $images = ''. + ''; + } else { + $images = ''; + } + + // free or pay ? + if ($product->price > 0) { + $price = '

    '.price(round((float) $product->price * $this->vat_rate, 2)).' €

    '; + $download_link = ''; + } else { + $price = $langs->trans('Free'); + $download_link = ''; + } + + //checking versions + if ($this->version_compare($product->dolibarr_min, DOL_VERSION) <= 0) { + if ($this->version_compare($product->dolibarr_max, DOL_VERSION) >= 0) { + //compatible + $version = ''.$langs->trans('CompatibleUpTo', $product->dolibarr_max, + $product->dolibarr_min, $product->dolibarr_max).''; + $compatible = ''; + } else { + //never compatible, module expired + $version = ''.$langs->trans('NotCompatible', DOL_VERSION, + $product->dolibarr_min, $product->dolibarr_max).''; + $compatible = 'NotCompatible'; + } + } else { + //need update + $version = ''.$langs->trans('CompatibleAfterUpdate', DOL_VERSION, + $product->dolibarr_min, $product->dolibarr_max).''; + $compatible = 'NotCompatible'; + } + + //output template + $html .= ' +
    '.$newapp.$images.'
    +

    '.$product->name->language[$this->lang].'Details' + .'
    '.$version.'

    + '.dol_print_date(strtotime($product->date_upd)).' - '.$langs->trans('Référence').': '.$product->reference.' - '.$langs->trans('Id').': '.$product->id.'

    '.$product->description_short->language[$this->lang].' + '.$product->description->language[$this->lang].' + '.$price.' + '.$download_link.' + '; + } + return $html; + } + + function get_previous_link($text = '<<') + { + return "$text"; + } + + function get_next_link($text = '>>') + { + return "$text"; + } +} \ No newline at end of file diff --git a/htdocs/dolistore/class/init.php b/htdocs/dolistore/class/init.php new file mode 100644 index 00000000000..df5773d9e7d --- /dev/null +++ b/htdocs/dolistore/class/init.php @@ -0,0 +1,72 @@ +CRUD Tutorial - Customer's list + +* @copyright 2007-2013 PrestaShop SA +* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) +* International Registered Trademark & Property of PrestaShop SA +* PrestaShop Webservice Library +* @package PrestaShopWebservice +*/ +// Here we define constants /!\ You need to replace this parameters +//https://dolistorecatalogpublickey1234567@vmdevwww.dolistore.com/api/ +define('DEBUG', true); // Debug mode +define('PS_SHOP_PATH', 'http://vmdevwww.dolistore.com/'); // Root path of your PrestaShop store +define('PS_WS_AUTH_KEY', 'dolistorecatalogpublickey1234567'); // Auth key (Get it in your Back Office) +require_once('./PSWebServiceLibrary.php'); +// Here we make the WebService Call +try +{ + $webService = new PrestaShopWebservice(PS_SHOP_PATH, PS_WS_AUTH_KEY, DEBUG); + + // Here we set the option array for the Webservice : we want customers resources + $opt['resource'] = 'categories'; + $opt['id'] = '1'; + + // Call + $xml = $webService->get($opt); + // Here we get the elements from children of customers markup "customer" + $resources = $xml->categories->children(); +} +catch (PrestaShopWebserviceException $e) +{ + // Here we are dealing with errors + $trace = $e->getTrace(); + if ($trace[0]['args'][0] == 404) echo 'Bad ID'; + else if ($trace[0]['args'][0] == 401) echo 'Bad auth key'; + else echo 'Other error'; +} +// We set the Title +echo "

    Categories's List

    "; +echo ''; +// if $resources is set we can lists element in it otherwise do nothing cause there's an error +if (isset($resources)) +{ + echo ''; + foreach ($resources as $resource) + { + // Iterates on the found IDs + echo ''; + } +} +echo '
    Id
    '.$resource->attributes().'
    '; +?> + \ No newline at end of file diff --git a/htdocs/dolistore/core/modules/modDolistore.class.php b/htdocs/dolistore/core/modules/modDolistore.class.php new file mode 100644 index 00000000000..a582b93a038 --- /dev/null +++ b/htdocs/dolistore/core/modules/modDolistore.class.php @@ -0,0 +1,159 @@ +. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + * Classe de description et activation du module DOLISTORE + */ + + +include_once DOL_DOCUMENT_ROOT.'/core/modules/DolibarrModules.class.php'; + +class modDolistore extends DolibarrModules +{ + + /** + * Constructor. Define names, constants, directories, boxes, permissions + * + * @param DoliDB $db Database handler + */ + function __construct($db) + { + global $conf, $langs; + + $this->db = $db; + $this->numero = 66666; + + + // Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module) + $this->name = /* $langs->trans( */preg_replace('/^mod/i', '', get_class($this))/* ) */; + + $this->boxes = array(); + + + $this->description = $langs->trans("DOLISTOREdescription"); + + $this->descriptionlong = $langs->trans("DOLISTOREdescriptionLong"); + + $this->family = "interface"; + + $this->module_position = 1; + $this->version = 'dolibarr'; + $this->picto = 'dolistore@dolistore'; + $this->special=1; + $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); + + // Data directories to create when module is enabled + $this->dirs = array(); + + // Dependances + $this->depends = array(); + $this->requiredby = array(); + $this->langfiles = array('dolistore@dolistore'); + + // Config pages + //$this->config_page_url = array("index.php?page=config@dolistore"); + + + + $this->module_parts = array( + 'triggers' => 0, + // Set this to 1 if module overwrite template dir (core/tpl) + 'tpl' => 0, + ); + + + + + + // Main menu entries + $r = 0; + + $this->menu[$r] = array( + //'fk_menu' => -1, // Put 0 if this is a top menu + 'fk_menu' => 'fk_mainmenu=home,fk_leftmenu=setup', + 'type' => 'left', // This is a left menu entry + 'titre' => 'DOLISTOREMENU', + 'mainmenu' => 'home', + 'leftmenu' => 'setup', + 'url' => '/dolistore/index.php?mainmenu=home&leftmenu=setup', + 'langs' => 'dolistore@dolistore', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. + 'position' => 1, + 'enabled' => '$leftmenu=="setup" && $conf->dolistore->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. + //'perms' => '$user->rights->edi->message->view', // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules + 'perms' => '', + 'target' => '', + 'user' => 0); // 0=Menu for internal users, 1=external users, 2=both + + $r++; + + // Constantes + $this->const = array(); + + + $r = 0; + $this->const[$r][0] = 'MAIN_MODULE_'.strtoupper($this->name).'_API_SRV'; + $this->const[$r][1] = "chaine"; + $this->const[$r][2] = "https://www.dolistore.com"; + $this->const[$r][3] = "Server URL"; + $this->const[$r][4] = 0; + $this->const[$r][5] = 1; // supprime la constante à la désactivation du module + $r++; + + $this->const[$r][0] = 'MAIN_MODULE_'.strtoupper($this->name).'_API_KEY'; + $this->const[$r][1] = "chaine"; + $this->const[$r][2] = "dolistorecatalogpublickey1234567"; + $this->const[$r][3] = "API key to authenticate"; + $this->const[$r][4] = 0; + $this->const[$r][5] = 1; // supprime la constante à la désactivation du module + $r++; + + } + + /** + * Function called when module is enabled. + * The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database. + * It also creates data directories + * + * @param string $options Options when enabling module ('', 'noboxes') + * @return int 1 if OK, 0 if KO + */ + function init($options = '') + { + global $conf; + + $this->remove($options); + + $sql = array(); + + return $this->_init($sql, $options); + } + + /** + * Function called when module is disabled. + * Remove from database constants, boxes and permissions from Dolibarr database. + * Data directories are not deleted + * + * @param string $options Options when enabling module ('', 'noboxes') + * @return int 1 if OK, 0 if KO + */ + function remove($options = '') + { + $sql = array(); + + return $this->_remove($sql, $options); + } +} \ No newline at end of file diff --git a/htdocs/dolistore/css/dolistore.css b/htdocs/dolistore/css/dolistore.css new file mode 100644 index 00000000000..18549c3ed83 --- /dev/null +++ b/htdocs/dolistore/css/dolistore.css @@ -0,0 +1,234 @@ + +div.divsearchfield { + float: left; + margin: 4px 12px 4px 2px; + padding-left: 2px; +} + +.margeCoteGauche,.margeCote{ + padding-right: 20px!important; +} +.margeCote,.margeCoteDroite{ + padding-left: 20px!important; +} +.nomargesupinf{ + margin-top: 0; + margin-bottom: 0; +} +#category-tree-left{ + display: none; + vertical-align: top; + width: 24%; +} +#listing-content{ + box-sizing: border-box; + display: inline-block; + width: 100%; +} +.tree{ + margin: 0px 0px 0px 0px; + padding:0px; + list-style: none; line-height: 2em; font-family: Arial; +} +.tree li{ + font-size: 16px; + position: relative;list-style: none; +} +.tree li:before{ + position: absolute; + left: -15px; + top: -4px; + content: ''; + display: block; + border-left: 1px solid #ddd; + height: 1em; + border-bottom: 1px solid #ddd; + width: 10px; +} +.tree li:after{ + position: absolute; + left: -15px; + bottom: -7px; + content: ''; + display: block; + border-left: 1px solid #ddd; + height: 100%; +} + +.tree li.root{ + margin: 0px 0px 0px 0px; +} +.tree li.root:before{ + display: none; +} + +.tree li.root:after{ + display: none; +} +.tree li:last-child:after{ + display: none +} +.blockUI { + cursor: auto!important; +} +.newAppParent{ + position: relative; + overflow: hidden; + min-height: 100px; +} +.newApp, .updatedApp{ + background-color: orange; + box-shadow: 0 0 20px rgba(0, 0, 0, 0.35); + box-sizing: border-box; + color: white; + display: block; + font-size: 18px; + font-weight: bold; + left: -34px; + padding: 5px 0; + position: absolute; + text-align: center; + text-shadow: 0 0 5px rgba(0, 0, 0, 0.35); + top: 22px; + transform: rotate(-45deg); + width: 150px; +} +.updatedApp{ + background-color: greenyellow; +} +.notcompatible { + color: red; +} +.compatibleafterupdate { + color: orange; +} +.compatible { + background-image: url("../img/compatible.png"); + background-position: left center; + background-repeat: no-repeat; + color: green; + display: inline-block; + height: 32px; + line-height: 32px; + padding-left: 35px; +} +tr.app { + height:250px; +} + +div#newsDoli.tabBar { + margin-top: 50px; + margin-right: 30px; +} +.selected { + text-decoration: underline!important; +} +.searchDolistore, .searchDolistore:hover { + padding-left: 30px; + padding-right: 30px; + font-weight: bold; +} +.searchDolistore:hover { + text-decoration: underline!important; +} + +.score{ + font-size: 16px; + font-weight: bold; +} +.formReviewArea{ + display:none; +} +.formReview div.divsearchfield{ + float: none; +} +.input100{ + box-sizing: border-box; + width: 100%; +} +.input50{ + box-sizing: border-box; + width: 49%; +} +textarea.row4{ + min-height: 100px; +} + + +.reviewList { + max-height: 150px; + overflow-y: scroll; +} + +.reviewRow{ + margin-bottom: 20px; +} +.reviewRow .reviewMarge { + float:left; + width: 220px; + padding: 0 20px 20px 0; +} +.reviewRow .score { + font-size: 48px; + display: block; + text-align: center; +} +.reviewRow .reviewDate { + color:grey; +} +.reviewRow:after{ + clear: both; + content:''; + display: block; +} +h2.appTitle small{ + font-weight: normal; +} +tr.NotCompatible{ + /* IE 8 */ + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=25)"; + + /* IE 5-7 */ + filter: alpha(opacity=25); + + /* Netscape */ + -moz-opacity: 0.25; + + /* Safari 1.x */ + -khtml-opacity: 0.25; + + /* Good browsers */ + opacity: 0.25; +} +tr.NotCompatible:hover{ + /* IE 8 */ + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; + + /* IE 5-7 */ + filter: alpha(opacity=100); + + /* Netscape */ + -moz-opacity: 1; + + /* Safari 1.x */ + -khtml-opacity: 1; + + /* Good browsers */ + opacity: 1; +} +@media only screen and (min-width: 1150px) { + #categorieArea{ + display:none; + } + #category-tree-left{ + display:inline-block; + } + #listing-content{ + width: 75%; + } +} +span.details{ + font-size: 12px; + margin-left: 10px; + vertical-align: super; +} \ No newline at end of file diff --git a/htdocs/dolistore/img/Download-128.png b/htdocs/dolistore/img/Download-128.png new file mode 100644 index 0000000000000000000000000000000000000000..89756d1f012c1aee0605d4b07cd36c38b04f62e1 GIT binary patch literal 761 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSEX7WqAsj$Z!;#Vf4nJ za0`PlBg3pY5)2GXvproLLn`LHy?d}%*ippwqCH2a3`c8&!g5XyrA7~EiJ9Okl_x<`m4E#~1 zT)~U=>;8XamNBRnQFD*~^Y1acMaDG^pZvn8{SwMfc@NUL7OeH+yucZ9wb5YpoBsD6;#-`r4YJAS+xoy8sb6xB zzPGPyVBNNO!{ryZyFjk#zT=*_{o?kmU;f3H$t4__civ-X|DnG6@Aq~0)>kovZ}{@h z`j7KOE+YmD<_2Rp@w?(sdP$vh$Mg9_C6WCMg02T2th%193QW5Up00i_>zopr06va6 A*#H0l literal 0 HcmV?d00001 diff --git a/htdocs/dolistore/img/NoImageAvailable.png b/htdocs/dolistore/img/NoImageAvailable.png new file mode 100644 index 0000000000000000000000000000000000000000..9a88d4362da95325a581414a98c520e4080cb203 GIT binary patch literal 11231 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 LrhMINi?II#Y zKuKPxKa+~0haf2+A3(ZboE(@qJRa%liorX(xVqx)k&ZaLBNnH6T^;bwL>E`0BLVsG zL8+qgS@Fa$s^7<0s+AWi5rTL`ELJ2EVMIFk zRRt;_VDi~Khz)X)YDGpID1^LFs!abZfy4VG%N2Y)Ce?vq#S9)6kHM)+S_RVS{~yZX zd_oJLFyOCz|EI7ZB8>-N!vFy&pT;t?r)fB}L02oOwOJ;jhj5CR2>AP-3i zcSYJpvbii!B-rr*Pp1o2bFnq0LNI6PHkD!^x_0xUm1$U%N6naEx{7xJ2V zAGxfxbD^xs#j29QsvG-Xjb7bSxko+yWLwqZlkowr%I$oWtrdl+78p!>D1b_e5X;*l zr6Cc!jD5fnfMJwhzt0=R?7e4dWnyf75C2V`um+z6$7lOkEZWj8!8>xlKWbTHuWzU6 z2oyMUX`6_?4>K&;@D@f&I+bl6YJa^%XL&_=ZB*K#_xqI{hR3g$%`2~^_l!JNJV^iD zeaZ;2z4^4+)R(e8m=mpcc{JDP4R4)iIHUBgzHyCiD(x4)J(>d!e$-{OqsIa57&rb< zgP#NK-x7!`Z}ra$HTLJQv&O3zY~UK^C!cKiDPh)9Bwt^f?~3y~Jp!M$S+KEaMV1^i zK`fP2@c)HAa=)x;^JZ;M9<_0?sGk>f;_|liuSUS<)=an$+3i(ht#j&LL@jBVr&(qd zIqlz?Ukn?jAvH5CvTD}#(J`OnG~qvM3!AQnp3&DL$Ie?k+^eB19VAu7?)k+mW7Mhn zyf#6$XW_w(5@wE7HV$_1^<=JW@1a%-oF>Kn@U&AWwJHr3{31|OR`l-ck>Kfp&V#ok zK^~GWnG<^0^qZKlXNASb{qLU3uS4)0;kuo<$}PE#nFHNp+LT-Vt)q|IUq6b91;rj3 zH_>-ly?X5zW2y-TT-eQljh5#KSsEMBKVl~zUe#ArJq)^|oKku&Nr5X@YCAG*$EiI_ z1i2hajLxi}pBRg?mFdOReS5%?WVaP8JL0`<$yE`gO#M&4r`@z%ue4&q$T(eESU@Gd zpS{sj)^Ki)9UVw|{n`-XbA%EtOP4Hp_3 zzfK5D@Ig&IXy+l=nq&{_m~biiviM7#{=M$(i*x?fU8v^qISFTM#YLZ!C$3KPusEs*%jq9mp&`c-Fnw87Q6{{4q$Hn*_XCM z_`??oa_!lS3-qp)dL!#yjwdjWy!5+?gsoAFDKd2y{&Td{f$GP*VsDQ1#D_x zw^7lQeCKTHnc{D4cF*YQSO3ER^~kQnAPpF0h1Z6=L?mL{8hpxAt0Ldzn(-F8?NU5; z1Zo8cPM01q+k@WHr3gpe_|i;R8d<+=Q+?K7z(hCCa*mn1`(GVF=*4#_xCI?&4j&4> z+$o>Ct(hWyVNqtCsR)*lz?_#Cj@HyG(7K+6+dAU12`l?wwq%$cT5sz5-O)P9?zVK= z^PM-7tty8|q=oXs!Hbx};OY}6M~!yetDh~HZu{qUt@cJZdXT{0&NzQ*d{TZZCF-_w zHQ75qTXeAoQ}({hu(jq9BKulit-ZMU3z5S;lT-7DOza|x%f~6+vWNSi5TR}7uKMMw zqWz$_4w4G_TQbo5d}G66E|@2RT8`pwR KLDci)SlJ(Mu5>g2 literal 0 HcmV?d00001 diff --git a/htdocs/dolistore/img/dolistore.png b/htdocs/dolistore/img/dolistore.png new file mode 100644 index 0000000000000000000000000000000000000000..d3fc61e72939cfbac8e625c856768e945a254954 GIT binary patch literal 11317 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 literal 0 HcmV?d00001 diff --git a/htdocs/dolistore/img/follow.png b/htdocs/dolistore/img/follow.png new file mode 100644 index 0000000000000000000000000000000000000000..78383c1157fe4345d5ca4b14377a4542e13c4fa6 GIT binary patch literal 2869 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 Yc>G=Dk4nMX*&kUy?*QgG&uHbp0c}UCaR2}S literal 0 HcmV?d00001 diff --git a/htdocs/dolistore/img/object_dolistore.png b/htdocs/dolistore/img/object_dolistore.png new file mode 100644 index 0000000000000000000000000000000000000000..213d0e0a3b745c3f64b6dee834fa5fd317da233b GIT binary patch literal 1851 zcmaJ?c~BEq99~2YQ4mA~6`eIONR=d;NC=5WBv}Fx!X*mc=2#@aW<#<-5=0@io&f_Y zf<**HZSkOJL=Y;d9LBqXh}4scXlE2l#j94kQPKWUx-+}){oZ`v_dDP0rpWMMd%HNVG{3mXs7Q7o4MJ69OoLi$FD+ELXAB9MVT!HnBG!Q%T@Q2%f|teF`d0 z7zy$)B?2-i5Lp8GL7*RvLYw8wWHNm~Iz)r05S>b+lW9!$EIJ#4z|Rkf@TQc;v!h}D zXJ3THAtm6rf=#8Sr>9fWXHhWaYATJzVwpAQbTWY;t2A<4q$bN%9zzN+qLL_O3S5TC zL9?PrjHTin5)tXA6i~$%S-I+SnTUc>)glFzMuE&J4FQG1|A(UJ7qkkGM!v@TpTepb zjRK)YBPuLaDIppc?_qYOVDprS2*;E$7?wO##mEE<$5aWJ0^}`VfI^W(CO6w3@j@Y6 zAXnicxdaiw91@{Gk;$ZN*pK1Q=Q3bFK9^6U!TdlTi_Z0@@fa`(dz@AUXyZn>ZsNm$FGEg(EVf!yCXZS zE~LHkKYj;|s4|A66qv5uQWf`KD!#~Kx4PX{7t&!(g-&Fo` zQ9^P+W!jVLdat|>d-lBKsx?9RKd)@$C8RiUM{ile%+_qYyaF$w zxb=$oSBLlK(OYS~2hCK6q`08?3;P@UZec)c7O+Nx>XF31$ z{H4d^F??uyEH6sq@>t+^Bha(fuv5jKOXX}b1PXC_r15zHGxZSyW>@Ox*Sn|3^TCRR=Vvixewa@+**OSD}zHXmgujZ5u9}JcDFiwcSOxic*@8^ z;89Qi)PlD+GbYdI_a2l@2-&%+;9Okq+cAGT3|?n%N84og)_>Uc-VOq)lAkVmb~bmw P{5ul_g~La=t91VW#hTZW literal 0 HcmV?d00001 diff --git a/htdocs/dolistore/index.php b/htdocs/dolistore/index.php new file mode 100644 index 00000000000..1295801b436 --- /dev/null +++ b/htdocs/dolistore/index.php @@ -0,0 +1,115 @@ +. + * + * This program is free software; you can redistribute it and/or modifyion 2.0 (the "License"); + * it under the terms of the GNU General Public License as published bypliance with the License. + * the Free Software Foundation; either version 3 of the License, or + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see http://www.gnu.org/ + */ + +if (!defined('REQUIRE_JQUERY_BLOCKUI')) define('REQUIRE_JQUERY_BLOCKUI', 1); +/** + * \file htdocs/commande/info.php + * \ingroup commande + * \brief Page des informations d'une commande + */ +$res = 0; +if (!$res && file_exists("../main.inc.php")) $res = @include("../main.inc.php"); +if (!$res && file_exists("../../main.inc.php")) $res = @include("../../main.inc.php"); +if (!$res && file_exists("../../../main.inc.php")) $res = @include("../../../main.inc.php"); +if (!$res && file_exists("../../../../main.inc.php")) $res = @include("../../../../main.inc.php"); +if (!$res && file_exists("../../../dolibarr/htdocs/main.inc.php")) + $res = @include("../../../dolibarr/htdocs/main.inc.php"); // Used on dev env only +if (!$res && file_exists("../../../../dolibarr/htdocs/main.inc.php")) + $res = @include("../../../../dolibarr/htdocs/main.inc.php"); // Used on dev env only +if (!$res && file_exists("../../../../../dolibarr/htdocs/main.inc.php")) + $res = @include("../../../../../dolibarr/htdocs/main.inc.php"); // Used on dev env only +if (!$res) die("Include of main fails"); + +// CORE + +global $lang, $user, $conf; + + +dol_include_once('/dolistore/class/dolistore.class.php'); +$options = array(); +$options['per_page'] = 20; +$options['categorie'] = GETPOST('categorie', 'int') + 0; +$options['start'] = GETPOST('start', 'int') + 0; +$options['end'] = GETPOST('end', 'int') + 0; +$options['search'] = GETPOST('search_keyword', 'alpha'); +$dolistore = new Dolistore($options); +/* + * View + */ + +/* * ************************************************* + * VIEW + * + * Put here all code to build page + * ************************************************** */ + +// llxHeader('', iconv(iconv_get_encoding($langs->trans($lbl_folder)), $character_set_client . "//TRANSLIT", $langs->trans($lbl_folder)) . ' (' . $info->Nmsgs . ') ', ''); + +$morejs = array("/dolistore/js/dolistore.js.php", + "/dolistore/js/fancybox/jquery.fancybox.pack.js", + "/dolistore/js/fancybox/helpers/jquery.fancybox-thumbs.js"); +$morecss = array("/dolistore/css/dolistore.css", + "/dolistore/js/fancybox/jquery.fancybox.css", + "/dolistore/js/fancybox/helpers/jquery.fancybox-thumbs.css"); +llxHeader('', $langs->trans('DOLISTOREMENU'), '', '', '', '', $morejs, $morecss, 0, 0); +?>
    + + +
    + + +
    trans('Extensions disponibles sur le Dolistore') ?>
    +
    + trans('DOLISTOREdescriptionLong') ?>

    + +
    +
    +
      + get_categories(); ?> +
    +
    +
    + + + + + + + + get_products($categorie); ?> + + + + + + +
    get_previous_link() ?> get_next_link() ?> trans('AchatTelechargement') ?>
    get_previous_link() ?> get_next_link() ?> trans('AchatTelechargement') ?>
    +
    +
    +. + * + * This program is free software; you can redistribute it and/or modifyion 2.0 (the "License"); + * it under the terms of the GNU General Public License as published bypliance with the License. + * the Free Software Foundation; either version 3 of the License, or + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see http://www.gnu.org/ + */ +$res = 0; +if (!$res && file_exists("../main.inc.php")) $res = @include("../main.inc.php"); +if (!$res && file_exists("../../main.inc.php")) $res = @include("../../main.inc.php"); +if (!$res && file_exists("../../../main.inc.php")) $res = @include("../../../main.inc.php"); +if (!$res && file_exists("../../../../main.inc.php")) $res = @include("../../../../main.inc.php"); +if (!$res && file_exists("../../../dolibarr/htdocs/main.inc.php")) + $res = @include("../../../dolibarr/htdocs/main.inc.php"); // Used on dev env only +if (!$res && file_exists("../../../../dolibarr/htdocs/main.inc.php")) + $res = @include("../../../../dolibarr/htdocs/main.inc.php"); // Used on dev env only +if (!$res && file_exists("../../../../../dolibarr/htdocs/main.inc.php")) + $res = @include("../../../../../dolibarr/htdocs/main.inc.php"); // Used on dev env only +if (!$res) die("Include of main fails"); + +global $langs; + +ob_start(); +?>