Bläddra i källkod

Add experimental module TakePOS

Laurent Destailleur 6 år sedan
förälder
incheckning
f990719daa
57 ändrade filer med 4789 tillägg och 4 borttagningar
  1. 2 1
      ChangeLog
  2. 0 1
      htdocs/core/modules/modCashDesk.class.php
  3. 337 0
      htdocs/core/modules/modTakePos.class.php
  4. 2 0
      htdocs/langs/en_US/admin.lang
  5. 5 0
      htdocs/takepos/ChangeLog.md
  6. 100 0
      htdocs/takepos/README.md
  7. 77 0
      htdocs/takepos/admin/about.php
  8. 202 0
      htdocs/takepos/admin/orderprinters.php
  9. 259 0
      htdocs/takepos/admin/setup.php
  10. 62 0
      htdocs/takepos/ajax.php
  11. 223 0
      htdocs/takepos/class/actions_takepos.class.php
  12. 58 0
      htdocs/takepos/css/colorbox.css
  13. BIN
      htdocs/takepos/css/images/border.png
  14. BIN
      htdocs/takepos/css/images/controls.png
  15. BIN
      htdocs/takepos/css/images/loading.gif
  16. BIN
      htdocs/takepos/css/images/loading_background.png
  17. 114 0
      htdocs/takepos/css/pos.css
  18. 1265 0
      htdocs/takepos/customers.php
  19. 53 0
      htdocs/takepos/dev/img/README.md
  20. BIN
      htdocs/takepos/dev/img/gfdl-129x44.png
  21. BIN
      htdocs/takepos/dev/img/gfdl-66x23.png
  22. 110 0
      htdocs/takepos/dev/img/gfdl-logo.svg
  23. 74 0
      htdocs/takepos/dev/img/gpl-v3-logo.svg
  24. BIN
      htdocs/takepos/dev/img/gplv3-127x51.png
  25. BIN
      htdocs/takepos/dev/img/gplv3-88x31.png
  26. 70 0
      htdocs/takepos/dev/img/takepos.svg
  27. 176 0
      htdocs/takepos/floors.php
  28. 59 0
      htdocs/takepos/freezone.php
  29. BIN
      htdocs/takepos/genimg/add.jpg
  30. BIN
      htdocs/takepos/genimg/empty.jpg
  31. 142 0
      htdocs/takepos/genimg/index.php
  32. BIN
      htdocs/takepos/img/arrow-next-top.png
  33. BIN
      htdocs/takepos/img/arrow-next.png
  34. BIN
      htdocs/takepos/img/arrow-prev-top.png
  35. BIN
      htdocs/takepos/img/arrow-prev.png
  36. BIN
      htdocs/takepos/img/gfdl.png
  37. BIN
      htdocs/takepos/img/gplv3.png
  38. BIN
      htdocs/takepos/img/marketplace/cashcontrol.jpg
  39. BIN
      htdocs/takepos/img/marketplace/takeposmobile.jpg
  40. BIN
      htdocs/takepos/img/object_takepos.png
  41. BIN
      htdocs/takepos/img/table.gif
  42. BIN
      htdocs/takepos/img/takepos.png
  43. 287 0
      htdocs/takepos/invoice.php
  44. 5 0
      htdocs/takepos/js/jquery.colorbox-min.js
  45. 15 0
      htdocs/takepos/js/takepos.js
  46. 24 0
      htdocs/takepos/langs/en_US/takepos.lang
  47. 22 0
      htdocs/takepos/langs/es_ES/takepos.lang
  48. 24 0
      htdocs/takepos/langs/fr_FR/takepos.lang
  49. 58 0
      htdocs/takepos/lib/takepos.lib.php
  50. 3 0
      htdocs/takepos/modulebuilder.txt
  51. 122 0
      htdocs/takepos/pay.php
  52. 108 0
      htdocs/takepos/receipt.php
  53. 26 0
      htdocs/takepos/sql/llx_takepos_floor_tables.sql
  54. 406 0
      htdocs/takepos/takepos.php
  55. 289 0
      htdocs/takepos/test/phpunit/TakePosFunctionalTest.php
  56. 5 1
      htdocs/theme/eldy/style.css.php
  57. 5 1
      htdocs/theme/md/style.css.php

+ 2 - 1
ChangeLog

@@ -8,7 +8,8 @@ For Users:
 NEW: Stable module: Website
 NEW: Stable module: WebDAV
 NEW: Stable module: Module Builder
-NEW: Stable module "Skype" has been replaced with module "Social Networks" to support more tools. 
+NEW: Stable module "Skype" has been replaced with module "Social Networks" to support more tools.
+NEW: Experimental module "TakePos"
 NEW: Dolibarr can provide information in page title when multicompany is enabled of not, making
      Android application like DoliDroid able to provide native features for multicompany module.
 NEW: Compatibility with PHP 7.3

+ 0 - 1
htdocs/core/modules/modCashDesk.class.php

@@ -81,7 +81,6 @@ class modCashDesk extends DolibarrModules
 
 		// Permissions
 		$this->rights = array();
-		$this->rights_class = 'cashdesk';
 		$r=0;
 
 		$r++;

+ 337 - 0
htdocs/core/modules/modTakePos.class.php

@@ -0,0 +1,337 @@
+<?php
+/* Copyright (C) 2004-2018 Laurent Destailleur  <eldy@users.sourceforge.net>
+ * Copyright (C) 2018 SuperAdmin
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * 	\defgroup   takepos     Module TakePos
+ *  \brief      TakePos module descriptor.
+ *
+ *  \file       htdocs/takepos/core/modules/modTakePos.class.php
+ *  \ingroup    takepos
+ *  \brief      Description and activation file for module TakePos
+ */
+include_once DOL_DOCUMENT_ROOT .'/core/modules/DolibarrModules.class.php';
+
+
+/**
+ *  Class to describe and enable module TakePos
+ */
+class modTakePos extends DolibarrModules
+{
+	/**
+	 * Constructor. Define names, constants, directories, boxes, permissions
+	 *
+	 * @param DoliDB $db Database handler
+	 */
+	public function __construct($db)
+	{
+        global $langs,$conf;
+
+        $this->db = $db;
+
+		// Id for module (must be unique).
+		// Use here a free id (See in Home -> System information -> Dolibarr for list of used modules id).
+		$this->numero = 50150;
+		// Key text used to identify module (for permissions, menus, etc...)
+		$this->rights_class = 'takepos';
+
+		// Family can be 'crm','financial','hr','projects','products','ecm','technic','interface','other'
+		// It is used to group modules by family in module setup page
+		$this->family = "portal";
+		// Module position in the family on 2 digits ('01', '10', '20', ...)
+		$this->module_position = '90';
+		// Gives the possibility to the module, to provide his own family info and position of this family (Overwrite $this->family and $this->module_position. Avoid this)
+		//$this->familyinfo = array('myownfamily' => array('position' => '01', 'label' => $langs->trans("MyOwnFamily")));
+
+		// Module label (no space allowed), used if translation string 'ModuleTakePosName' not found (MyModue is name of module).
+		$this->name = preg_replace('/^mod/i','',get_class($this));
+		// Module description, used if translation string 'ModuleTakePosDesc' not found (MyModue is name of module).
+		$this->description = "Point of sales module (Touch Screen POS)";
+		// Used only if file README.md and README-LL.md not found.
+		$this->descriptionlong = "Point Of Sales (compliant with touch screen)";
+
+		// Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated' or a version string like 'x.y.z'
+		$this->version = 'experimental';
+		// Key used in llx_const table to save module status enabled/disabled (where TAKEPOS is value of property name of module in uppercase)
+		$this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);
+		// Name of image file used for this module.
+		// If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue'
+		// If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module'
+		$this->picto='list';
+
+		// Defined all module parts (triggers, login, substitutions, menus, css, etc...)
+		// for default path (eg: /takepos/core/xxxxx) (0=disable, 1=enable)
+		// for specific path of parts (eg: /takepos/core/modules/barcode)
+		// for specific css file (eg: /takepos/css/takepos.css.php)
+		$this->module_parts = array(
+		                        	'triggers' => 0,                                 	// Set this to 1 if module has its own trigger directory (core/triggers)
+									'login' => 0,                                    	// Set this to 1 if module has its own login method file (core/login)
+									'substitutions' => 1,                            	// Set this to 1 if module has its own substitution function file (core/substitutions)
+									'menus' => 0,                                    	// Set this to 1 if module has its own menus handler directory (core/menus)
+									'theme' => 0,                                    	// Set this to 1 if module has its own theme directory (theme)
+		                        	'tpl' => 0,                                      	// Set this to 1 if module overwrite template dir (core/tpl)
+									'barcode' => 0,                                  	// Set this to 1 if module has its own barcode directory (core/modules/barcode)
+									'models' => 0,                                   	// Set this to 1 if module has its own models directory (core/modules/xxx)
+									'hooks' => array('data'=>array('invoicecard'), 'entity'=>'0') 	// Set here all hooks context managed by module. To find available hook context, make a "grep -r '>initHooks(' *" on source code. You can also set hook context 'all'
+		                        );
+
+		// Data directories to create when module is enabled.
+		// Example: this->dirs = array("/takepos/temp","/takepos/subdir");
+		$this->dirs = array();
+
+		// Config pages. Put here list of php page, stored into takepos/admin directory, to use to setup module.
+		$this->config_page_url = array("setup.php@takepos");
+
+		// Dependencies
+		$this->hidden = false;			// A condition to hide module
+		$this->depends = array('modFacture','modProduct','modCategorie');			// List of module class names as string that must be enabled if this module is enabled
+		$this->requiredby = array();	// List of module ids to disable if this one is disabled
+		$this->conflictwith = array();	// List of module class names as string this module is in conflict with
+		$this->langfiles = array("takepos@takepos");
+		$this->phpmin = array(5,43);					// Minimum version of PHP required by module
+		$this->need_dolibarr_version = array(4,0);	// Minimum version of Dolibarr required by module
+		$this->warnings_activation = array();                     // Warning to show when we activate module. array('always'='text') or array('FR'='textfr','ES'='textes'...)
+		$this->warnings_activation_ext = array();                 // Warning to show when we activate an external module. array('always'='text') or array('FR'='textfr','ES'='textes'...)
+		//$this->automatic_activation = array('FR'=>'TakePosWasAutomaticallyActivatedBecauseOfYourCountryChoice');
+		//$this->always_enabled = true;								// If true, can't be disabled
+
+		// Constants
+		// List of particular constants to add when module is enabled (key, 'chaine', value, desc, visible, 'current' or 'allentities', deleteonunactive)
+		// Example: $this->const=array(0=>array('TAKEPOS_MYNEWCONST1','chaine','myvalue','This is a constant to add',1),
+		//                             1=>array('TAKEPOS_MYNEWCONST2','chaine','myvalue','This is another constant to add',0, 'current', 1)
+		// );
+		$this->const = array(
+			//1=>array('TAKEPOS_MYCONSTANT', 'chaine', 'avalue', 'This is a constant to add', 1, 'allentities', 1)
+		);
+
+
+		if (! isset($conf->takepos) || ! isset($conf->takepos->enabled))
+		{
+			$conf->takepos=new stdClass();
+			$conf->takepos->enabled=0;
+		}
+
+
+		// Array to add new pages in new tabs
+        $this->tabs = array();
+		// Example:
+		// $this->tabs[] = array('data'=>'objecttype:+tabname1:Title1:mylangfile@takepos:$user->rights->takepos->read:/takepos/mynewtab1.php?id=__ID__');  					// To add a new tab identified by code tabname1
+        // $this->tabs[] = array('data'=>'objecttype:+tabname2:SUBSTITUTION_Title2:mylangfile@takepos:$user->rights->othermodule->read:/takepos/mynewtab2.php?id=__ID__',  	// To add another new tab identified by code tabname2. Label will be result of calling all substitution functions on 'Title2' key.
+        // $this->tabs[] = array('data'=>'objecttype:-tabname:NU:conditiontoremove');                                                     										// To remove an existing tab identified by code tabname
+        //
+        // Where objecttype can be
+		// 'categories_x'	  to add a tab in category view (replace 'x' by type of category (0=product, 1=supplier, 2=customer, 3=member)
+		// 'contact'          to add a tab in contact view
+		// 'contract'         to add a tab in contract view
+		// 'group'            to add a tab in group view
+		// 'intervention'     to add a tab in intervention view
+		// 'invoice'          to add a tab in customer invoice view
+		// 'invoice_supplier' to add a tab in supplier invoice view
+		// 'member'           to add a tab in fundation member view
+		// 'opensurveypoll'	  to add a tab in opensurvey poll view
+		// 'order'            to add a tab in customer order view
+		// 'order_supplier'   to add a tab in supplier order view
+		// 'payment'		  to add a tab in payment view
+		// 'payment_supplier' to add a tab in supplier payment view
+		// 'product'          to add a tab in product view
+		// 'propal'           to add a tab in propal view
+		// 'project'          to add a tab in project view
+		// 'stock'            to add a tab in stock view
+		// 'thirdparty'       to add a tab in third party view
+		// 'user'             to add a tab in user view
+
+
+        // Dictionaries
+		$this->dictionaries=array();
+        /* Example:
+        $this->dictionaries=array(
+            'langs'=>'mylangfile@takepos',
+            'tabname'=>array(MAIN_DB_PREFIX."table1",MAIN_DB_PREFIX."table2",MAIN_DB_PREFIX."table3"),		// List of tables we want to see into dictonnary editor
+            'tablib'=>array("Table1","Table2","Table3"),													// Label of tables
+            'tabsql'=>array('SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table1 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table2 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table3 as f'),	// Request to select fields
+            'tabsqlsort'=>array("label ASC","label ASC","label ASC"),																					// Sort order
+            'tabfield'=>array("code,label","code,label","code,label"),																					// List of fields (result of select to show dictionary)
+            'tabfieldvalue'=>array("code,label","code,label","code,label"),																				// List of fields (list of fields to edit a record)
+            'tabfieldinsert'=>array("code,label","code,label","code,label"),																			// List of fields (list of fields for insert)
+            'tabrowid'=>array("rowid","rowid","rowid"),																									// Name of columns with primary key (try to always name it 'rowid')
+            'tabcond'=>array($conf->takepos->enabled,$conf->takepos->enabled,$conf->takepos->enabled)												// Condition to show each dictionary
+        );
+        */
+
+
+        // Boxes/Widgets
+		// Add here list of php file(s) stored in takepos/core/boxes that contains class to show a widget.
+        $this->boxes = array(
+        	//0=>array('file'=>'takeposwidget1.php@takepos','note'=>'Widget provided by TakePos','enabledbydefaulton'=>'Home'),
+        	//1=>array('file'=>'takeposwidget2.php@takepos','note'=>'Widget provided by TakePos'),
+        	//2=>array('file'=>'takeposwidget3.php@takepos','note'=>'Widget provided by TakePos')
+        );
+
+
+		// Cronjobs (List of cron jobs entries to add when module is enabled)
+		// unit_frequency must be 60 for minute, 3600 for hour, 86400 for day, 604800 for week
+		$this->cronjobs = array(
+			//0=>array('label'=>'MyJob label', 'jobtype'=>'method', 'class'=>'/takepos/class/myobject.class.php', 'objectname'=>'MyObject', 'method'=>'doScheduledJob', 'parameters'=>'', 'comment'=>'Comment', 'frequency'=>2, 'unitfrequency'=>3600, 'status'=>0, 'test'=>true)
+		);
+		// Example: $this->cronjobs=array(0=>array('label'=>'My label', 'jobtype'=>'method', 'class'=>'/dir/class/file.class.php', 'objectname'=>'MyClass', 'method'=>'myMethod', 'parameters'=>'param1, param2', 'comment'=>'Comment', 'frequency'=>2, 'unitfrequency'=>3600, 'status'=>0, 'test'=>true),
+		//                                1=>array('label'=>'My label', 'jobtype'=>'command', 'command'=>'', 'parameters'=>'param1, param2', 'comment'=>'Comment', 'frequency'=>1, 'unitfrequency'=>3600*24, 'status'=>0, 'test'=>true)
+		// );
+
+
+		// Permissions
+		$this->rights = array();		// Permission array used by this module
+
+		/*$r=0;
+		$this->rights[$r][0] = $this->numero + $r;	// Permission id (must not be already used)
+		$this->rights[$r][1] = 'Read myobject of TakePos';	// Permission label
+		$this->rights[$r][3] = 1; 					// Permission by default for new user (0/1)
+		$this->rights[$r][4] = 'read';				// In php code, permission will be checked by test if ($user->rights->takepos->level1->level2)
+		$this->rights[$r][5] = '';				    // In php code, permission will be checked by test if ($user->rights->takepos->level1->level2)
+
+		$r++;
+		$this->rights[$r][0] = $this->numero + $r;	// Permission id (must not be already used)
+		$this->rights[$r][1] = 'Create/Update myobject of TakePos';	// Permission label
+		$this->rights[$r][3] = 1; 					// Permission by default for new user (0/1)
+		$this->rights[$r][4] = 'write';				// In php code, permission will be checked by test if ($user->rights->takepos->level1->level2)
+		$this->rights[$r][5] = '';				    // In php code, permission will be checked by test if ($user->rights->takepos->level1->level2)
+
+		$r++;
+		$this->rights[$r][0] = $this->numero + $r;	// Permission id (must not be already used)
+		$this->rights[$r][1] = 'Delete myobject of TakePos';	// Permission label
+		$this->rights[$r][3] = 1; 					// Permission by default for new user (0/1)
+		$this->rights[$r][4] = 'delete';				// In php code, permission will be checked by test if ($user->rights->takepos->level1->level2)
+		$this->rights[$r][5] = '';				    // In php code, permission will be checked by test if ($user->rights->takepos->level1->level2)
+		*/
+
+		// Main menu entries
+		$this->menu = array();			// List of menus to add
+		$r=0;
+
+		// Add here entries to declare new menus
+
+		/* BEGIN MODULEBUILDER TOPMENU */
+		$this->menu[$r++]=array('fk_menu'=>'',			                // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode
+								'type'=>'top',			                // This is a Top menu entry
+								'titre'=>'PointOfSale',
+								'mainmenu'=>'takepos',
+								'leftmenu'=>'',
+								'url'=>'/takepos/takepos.php',
+								'langs'=>'takepos@takepos',	        // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
+								'position'=>1000+$r,
+								'enabled'=>'$conf->takepos->enabled',	// Define condition to show or hide menu entry. Use '$conf->takepos->enabled' if entry must be visible if module is enabled.
+								'perms'=>'1',			                // Use 'perms'=>'$user->rights->takepos->level1->level2' if you want your menu with a permission rules
+								'target'=>'takepos',
+								'user'=>2);				                // 0=Menu for internal users, 1=external users, 2=both
+
+		/* END MODULEBUILDER TOPMENU */
+
+		/* BEGIN MODULEBUILDER LEFTMENU MYOBJECT
+		$this->menu[$r++]=array(	'fk_menu'=>'fk_mainmenu=takepos',	    // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode
+								'type'=>'left',			                // This is a Left menu entry
+								'titre'=>'List MyObject',
+								'mainmenu'=>'takepos',
+								'leftmenu'=>'takepos_myobject_list',
+								'url'=>'/takepos/myobject_list.php',
+								'langs'=>'takepos@takepos',	        // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
+								'position'=>1000+$r,
+								'enabled'=>'$conf->takepos->enabled',  // Define condition to show or hide menu entry. Use '$conf->takepos->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected.
+								'perms'=>'1',			                // Use 'perms'=>'$user->rights->takepos->level1->level2' if you want your menu with a permission rules
+								'target'=>'',
+								'user'=>2);				                // 0=Menu for internal users, 1=external users, 2=both
+		$this->menu[$r++]=array(	'fk_menu'=>'fk_mainmenu=takepos,fk_leftmenu=takepos',	    // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode
+								'type'=>'left',			                // This is a Left menu entry
+								'titre'=>'New MyObject',
+								'mainmenu'=>'takepos',
+								'leftmenu'=>'takepos_myobject_new',
+								'url'=>'/takepos/myobject_page.php?action=create',
+								'langs'=>'takepos@takepos',	        // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
+								'position'=>1000+$r,
+								'enabled'=>'$conf->takepos->enabled',  // Define condition to show or hide menu entry. Use '$conf->takepos->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected.
+								'perms'=>'1',			                // Use 'perms'=>'$user->rights->takepos->level1->level2' if you want your menu with a permission rules
+								'target'=>'',
+								'user'=>2);				                // 0=Menu for internal users, 1=external users, 2=both
+		END MODULEBUILDER LEFTMENU MYOBJECT */
+
+
+		// Exports
+		$r=1;
+
+		/* BEGIN MODULEBUILDER EXPORT MYOBJECT */
+		/*
+		$langs->load("takepos@takepos");
+		$this->export_code[$r]=$this->rights_class.'_'.$r;
+		$this->export_label[$r]='MyObjectLines';	// Translation key (used only if key ExportDataset_xxx_z not found)
+		$this->export_icon[$r]='myobject@takepos';
+		$keyforclass = 'MyObject'; $keyforclassfile='/mymobule/class/myobject.class.php'; $keyforelement='myobject';
+		include DOL_DOCUMENT_ROOT.'/core/commonfieldsinexport.inc.php';
+		$keyforselect='myobject'; $keyforaliasextra='extra'; $keyforelement='myobject';
+		include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php';
+		//$this->export_dependencies_array[$r]=array('mysubobject'=>'ts.rowid', 't.myfield'=>array('t.myfield2','t.myfield3')); // To force to activate one or several fields if we select some fields that need same (like to select a unique key if we ask a field of a child to avoid the DISTINCT to discard them, or for computed field than need several other fields)
+		$this->export_sql_start[$r]='SELECT DISTINCT ';
+		$this->export_sql_end[$r]  =' FROM '.MAIN_DB_PREFIX.'myobject as t';
+		$this->export_sql_end[$r] .=' WHERE 1 = 1';
+		$this->export_sql_end[$r] .=' AND t.entity IN ('.getEntity('myobject').')';
+		$r++; */
+		/* END MODULEBUILDER EXPORT MYOBJECT */
+	}
+
+	/**
+	 *	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
+	 */
+	public function init($options='')
+	{
+		$this->_load_tables('/takepos/sql/');
+
+		// Create extrafields
+		include_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
+		$extrafields = new ExtraFields($this->db);
+
+		//$result1=$extrafields->addExtraField('myattr1', "New Attr 1 label", 'boolean', 1,  3, 'thirdparty',   0, 0, '', '', 1, '', 0, 0, '', '', 'takepos@takepos', '$conf->takepos->enabled');
+		//$result2=$extrafields->addExtraField('myattr2', "New Attr 2 label", 'varchar', 1, 10, 'project',      0, 0, '', '', 1, '', 0, 0, '', '', 'takepos@takepos', '$conf->takepos->enabled');
+		//$result3=$extrafields->addExtraField('myattr3', "New Attr 3 label", 'varchar', 1, 10, 'bank_account', 0, 0, '', '', 1, '', 0, 0, '', '', 'takepos@takepos', '$conf->takepos->enabled');
+		//$result4=$extrafields->addExtraField('myattr4', "New Attr 4 label", 'select',  1,  3, 'thirdparty',   0, 1, '', array('options'=>array('code1'=>'Val1','code2'=>'Val2','code3'=>'Val3')), 1 '', 0, 0, '', '', 'takepos@takepos', '$conf->takepos->enabled');
+		//$result5=$extrafields->addExtraField('myattr5', "New Attr 5 label", 'text',    1, 10, 'user',         0, 0, '', '', 1, '', 0, 0, '', '', 'takepos@takepos', '$conf->takepos->enabled');
+
+		$sql = array();
+
+		// Remove permissions and default values
+		$this->remove($options);
+
+		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
+	 */
+	public function remove($options = '')
+	{
+		$sql = array();
+
+		return $this->_remove($sql, $options);
+	}
+
+}

+ 2 - 0
htdocs/langs/en_US/admin.lang

@@ -620,6 +620,8 @@ Module50000Name=PayBox
 Module50000Desc=Offer customers a PayBox online payment page (credit/debit cards). This can be used to allow your customers to make free payments or for a payment on a particular Dolibarr object (invoice, order, ...)
 Module50100Name=Point of sales
 Module50100Desc=Point of sales module (POS).
+Module50150Name=Point of sales
+Module50150Desc=Point of sales module (Touch screen POS).
 Module50200Name=Paypal
 Module50200Desc=Offer customers a PayPal online payment page (PayPal account or credit/debit cards). This can be used to allow your customers to make free payments or for a payment on a particular Dolibarr object (invoice, order, ...)
 Module50400Name=Accounting (advanced)

+ 5 - 0
htdocs/takepos/ChangeLog.md

@@ -0,0 +1,5 @@
+# CHANGELOG TAKEPOS FOR <a href="https://www.dolibarr.org">DOLIBARR ERP CRM</a>
+
+## 1.0
+Initial version
+

+ 100 - 0
htdocs/takepos/README.md

@@ -0,0 +1,100 @@
+# TAKEPOS FOR <a href="https://www.takepos.com">DOLIBARR ERP CRM</a>
+
+## Features
+Touch Screen POS
+
+<!--
+![Screenshot takepos](img/screenshot_takepos.png?raw=true "TakePos"){imgmd}
+-->
+
+Other modules are available on <a href="https://www.dolistore.com" target="_new">Dolistore.com</a>.
+
+
+
+### Translations
+
+Translations can be define manually by editing files into directories [langs](langs). 
+
+<!--
+This module contains also a sample configuration for Transifex, under the hidden directory [.tx](.tx), so it is possible to manage translation using this service. 
+
+For more informations, see the [translator's documentation](https://wiki.dolibarr.org/index.php/Translator_documentation).
+
+There is a [Transifex project](https://transifex.com/projects/p/dolibarr-module-template) for this module.
+-->
+
+
+<!--
+
+Install
+-------
+
+### From the ZIP file and GUI interface
+
+- If you get the module in a zip file (like when downloading it from the market place [Dolistore](https://www.dolistore.com)), go into
+menu ```Home - Setup - Modules - Deploy external module``` and upload the zip file.
+
+
+Note: If this screen tell you there is no custom directory, check your setup is correct: 
+
+- In your Dolibarr installation directory, edit the ```htdocs/conf/conf.php``` file and check that following lines are not commented:
+
+    ```php
+    //$dolibarr_main_url_root_alt ...
+    //$dolibarr_main_document_root_alt ...
+    ```
+
+- Uncomment them if necessary (delete the leading ```//```) and assign a sensible value according to your Dolibarr installation
+
+    For example :
+
+    - UNIX:
+        ```php
+        $dolibarr_main_url_root_alt = '/custom';
+        $dolibarr_main_document_root_alt = '/var/www/Dolibarr/htdocs/custom';
+        ```
+
+    - Windows:
+        ```php
+        $dolibarr_main_url_root_alt = '/custom';
+        $dolibarr_main_document_root_alt = 'C:/My Web Sites/Dolibarr/htdocs/custom';
+        ```
+        
+### From a GIT repository
+
+- Clone the repository in ```$dolibarr_main_document_root_alt/takepos```
+
+```sh
+cd ....../custom
+git clone git@github.com:gitlogin/takepos.git takepos
+```
+
+### <a name="final_steps"></a>Final steps
+
+From your browser:
+
+  - Log into Dolibarr as a super-administrator
+  - Go to "Setup" -> "Modules"
+  - You should now be able to find and enable the module
+
+
+
+-->
+
+
+Licenses
+--------
+
+### Main code
+
+![GPLv3 logo](img/gplv3.png)
+
+GPLv3 or (at your option) any later version.
+
+See [COPYING](COPYING) for more information.
+
+#### Documentation
+
+All texts and readmes.
+
+![GFDL logo](img/gfdl.png)

+ 77 - 0
htdocs/takepos/admin/about.php

@@ -0,0 +1,77 @@
+<?php
+/* Copyright (C) 2004-2017 Laurent Destailleur  <eldy@users.sourceforge.net>
+ * Copyright (C) 2018 SuperAdmin
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file    takepos/admin/about.php
+ * \ingroup takepos
+ * \brief   About page of module TakePos.
+ */
+
+require '../../main.inc.php';	// Load $user and permissions
+require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
+require_once '../lib/takepos.lib.php';
+
+// Translations
+$langs->load("errors");
+$langs->load("admin");
+$langs->load("takepos@takepos");
+
+// Access control
+if (! $user->admin) {
+	accessforbidden();
+}
+
+// Parameters
+$action = GETPOST('action', 'alpha');
+$backtopage = GETPOST('backtopage', 'alpha');
+
+
+/*
+ * Actions
+ */
+
+// None
+
+
+/*
+ * View
+ */
+
+$form = new Form($db);
+
+$page_name = "TakePosAbout";
+llxHeader('', $langs->trans($page_name));
+
+// Subheader
+$linkback = '<a href="'.($backtopage?$backtopage:DOL_URL_ROOT.'/admin/modules.php').'">'.$langs->trans("BackToModuleList").'</a>';
+
+print load_fiche_titre($langs->trans($page_name), $linkback, 'object_takepos@takepos');
+
+// Configuration header
+$head = takeposAdminPrepareHead();
+dol_fiche_head($head, 'about', '', 0, 'takepos@takepos');
+
+dol_include_once('/takepos/core/modules/modTakePos.class.php');
+$tmpmodule = new modTakePos($db);
+print $tmpmodule->getDescLong();
+
+// Page end
+dol_fiche_end();
+llxFooter();
+$db->close();

+ 202 - 0
htdocs/takepos/admin/orderprinters.php

@@ -0,0 +1,202 @@
+<?php
+/* Copyright (C) 2005       Matthieu Valleton   <mv@seeschloss.org>
+ * Copyright (C) 2005       Eric Seigne         <eric.seigne@ryxeo.com>
+ * Copyright (C) 2006-2016  Laurent Destailleur <eldy@users.sourceforge.net>
+ * Copyright (C) 2007       Patrick Raguin      <patrick.raguin@gmail.com>
+ * Copyright (C) 2005-2012  Regis Houssin       <regis.houssin@capnetworks.com>
+ * Copyright (C) 2015       Raphaël Doursenaud  <rdoursenaud@gpcsolutions.fr>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ *      \file       htdocs/takepos/admin/orderprinters.php
+ *      \ingroup    takepos
+ *      \brief      Home page of category area
+ */
+
+require '../../main.inc.php';	// Load $user and permissions
+require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/treeview.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
+
+$langs->load("main");
+$langs->load("categories");
+$langs->load("takepos");
+$langs->load("printing");
+
+if (! $user->rights->categorie->lire) accessforbidden();
+
+$id=GETPOST('id','int');
+$type=(GETPOST('type','aZ09') ? GETPOST('type','aZ09') : Categorie::TYPE_PRODUCT);
+$catname=GETPOST('catname','alpha');
+$action=GETPOST('action');
+$printer1=GETPOST('printer1');
+$printer2=GETPOST('printer2');
+
+if (is_numeric($type)) $type=Categorie::$MAP_ID_TO_CODE[$type];	// For backward compatibility
+
+/*
+ * Actions
+ */
+print $action;
+if ($action=="SavePrinter1"){
+	$printedcategories=";";
+	if (is_array($printer1)) foreach ($printer1 as $cat){
+		$printedcategories=$printedcategories.$cat.";";
+	}
+	dolibarr_set_const($db,"TAKEPOS_PRINTED_CATEGORIES_1", $printedcategories,'chaine',0,'',$conf->entity);
+}
+
+if ($action=="SavePrinter2"){
+	$printedcategories=";";
+	if (is_array($printer2)) foreach ($printer2 as $cat){
+		$printedcategories=$printedcategories.$cat.";";
+	}
+	dolibarr_set_const($db,"TAKEPOS_PRINTED_CATEGORIES_2", $printedcategories,'chaine',0,'',$conf->entity);
+}
+
+
+/*
+ * View
+ */
+
+$categstatic = new Categorie($db);
+$form = new Form($db);
+
+if ($type == Categorie::TYPE_PRODUCT)       { $title=$langs->trans("ProductsCategoriesArea");  $typetext='product'; }
+elseif ($type == Categorie::TYPE_SUPPLIER)  { $title=$langs->trans("SuppliersCategoriesArea"); $typetext='supplier'; }
+elseif ($type == Categorie::TYPE_CUSTOMER)  { $title=$langs->trans("CustomersCategoriesArea"); $typetext='customer'; }
+elseif ($type == Categorie::TYPE_MEMBER)    { $title=$langs->trans("MembersCategoriesArea");   $typetext='member'; }
+elseif ($type == Categorie::TYPE_CONTACT)   { $title=$langs->trans("ContactsCategoriesArea");  $typetext='contact'; }
+elseif ($type == Categorie::TYPE_ACCOUNT)   { $title=$langs->trans("AccountsCategoriesArea");  $typetext='bank_account'; }
+elseif ($type == Categorie::TYPE_PROJECT)   { $title=$langs->trans("ProjectsCategoriesArea");  $typetext='project'; }
+elseif ($type == Categorie::TYPE_USER)      { $title=$langs->trans("UsersCategoriesArea");     $typetext='user'; }
+else                                        { $title=$langs->trans("CategoriesArea");          $typetext='unknown'; }
+
+$arrayofjs=array('/includes/jquery/plugins/jquerytreeview/jquery.treeview.js', '/includes/jquery/plugins/jquerytreeview/lib/jquery.cookie.js');
+$arrayofcss=array('/includes/jquery/plugins/jquerytreeview/jquery.treeview.css');
+
+llxHeader('',$title,'','',0,0,$arrayofjs,$arrayofcss);
+
+
+print load_fiche_titre($langs->trans("OrderPrinters"));
+
+//print '<table border="0" width="100%" class="notopnoleftnoright">';
+//print '<tr><td valign="top" width="30%" class="notopnoleft">';
+print '<div class="fichecenter"><div class="fichethirdleft">';
+
+
+//print '</td><td valign="top" width="70%">';
+print '</div><div class="fichetwothirdright"><div class="ficheaddleft">';
+
+
+//print '</td></tr></table>';
+print '</div></div></div>';
+
+print '<div class="fichecenter"><br>';
+
+
+// Charge tableau des categories
+$cate_arbo = $categstatic->get_full_arbo($typetext);
+
+// Define fulltree array
+$fulltree=$cate_arbo;
+
+// Define data (format for treeview)
+$data=array();
+$data[] = array('rowid'=>0,'fk_menu'=>-1,'title'=>"racine",'mainmenu'=>'','leftmenu'=>'','fk_mainmenu'=>'','fk_leftmenu'=>'');
+foreach($fulltree as $key => $val)
+{
+	$categstatic->id=$val['id'];
+	$categstatic->ref=$val['label'];
+	$categstatic->color=$val['color'];
+	$categstatic->type=$type;
+	$li=$categstatic->getNomUrl(1,'',60);
+	$desc=dol_htmlcleanlastbr($val['description']);
+
+	$data[] = array(
+	'rowid'=>$val['rowid'],
+	'fk_menu'=>$val['fk_menu'],
+	'fk_menu'=>$val['fk_parent'],
+	'label'=>$val['label']
+	);
+}
+
+//Printer1
+print '<table class="liste nohover" width="100%">';
+print '<tr class="liste_titre"><td>'.$langs->trans("Printer").' 1</td><td></td><td align="right">';
+print '</td></tr>';
+$nbofentries=(count($data) - 1);
+print '<form action="orderprinters.php">';
+if ($nbofentries > 0)
+{
+	print '<tr class="pair"><td colspan="3">';
+	print '<input type="hidden" name="action" value="SavePrinter1">';
+	foreach ($data as $row) {
+		if (strpos($conf->global->TAKEPOS_PRINTED_CATEGORIES_1, ';'.$row["rowid"].';') !== false) $checked='checked'; else $checked='';
+		if ($row["fk_menu"]==0) print '<input type="checkbox" name="printer1[]" value="'.$row["rowid"].'" '.$checked.'>'.$row["label"].'<br>';
+	}
+	print '</td></tr>';
+}
+else
+{
+	print '<tr class="pair">';
+	print '<td colspan="3"><table class="nobordernopadding"><tr class="nobordernopadding"><td>'.img_picto_common('','treemenu/branchbottom.gif').'</td>';
+	print '<td valign="middle">';
+	print $langs->trans("NoCategoryYet");
+	print '</td>';
+	print '<td>&nbsp;</td>';
+	print '</table></td>';
+	print '</tr>';
+}
+print "</table>";
+print '<input type="submit" value="'.$langs->trans("Save").'"></form><br><br>';
+
+//Printer2
+print '<table class="liste nohover" width="100%">';
+print '<tr class="liste_titre"><td>'.$langs->trans("Printer").' 2</td><td></td><td align="right">';
+print '</td></tr>';
+$nbofentries=(count($data) - 1);
+print '<form action="orderprinters.php">';
+if ($nbofentries > 0)
+{
+	print '<tr class="pair"><td colspan="3">';
+	print '<input type="hidden" name="action" value="SavePrinter2">';
+	foreach ($data as $row) {
+		if (strpos($conf->global->TAKEPOS_PRINTED_CATEGORIES_2, ';'.$row["rowid"].';') !== false) $checked='checked'; else $checked='';
+		if ($row["fk_menu"]==0) print '<input type="checkbox" name="printer2[]" value="'.$row["rowid"].'" '.$checked.'>'.$row["label"].'<br>';
+	}
+	print '</td></tr>';
+}
+else
+{
+	print '<tr class="pair">';
+	print '<td colspan="3"><table class="nobordernopadding"><tr class="nobordernopadding"><td>'.img_picto_common('','treemenu/branchbottom.gif').'</td>';
+	print '<td valign="middle">';
+	print $langs->trans("NoCategoryYet");
+	print '</td>';
+	print '<td>&nbsp;</td>';
+	print '</table></td>';
+	print '</tr>';
+}
+print "</table>";
+print '<input type="submit" value="'.$langs->trans("Save").'"></form>';
+
+print '</div>';
+
+llxFooter();
+
+$db->close();

+ 259 - 0
htdocs/takepos/admin/setup.php

@@ -0,0 +1,259 @@
+<?php
+/* Copyright (C) 2008-2011 Laurent Destailleur  <eldy@users.sourceforge.net>
+ * Copyright (C) 2011-2017 Juanjo Menent		<jmenent@2byte.es>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ *	\file       htdocs/takepos/admin/setup.php
+ *	\ingroup    takepos
+ *	\brief      Setup page for TakePos module
+ */
+
+require '../../main.inc.php';	// Load $user and permissions
+require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
+
+// If socid provided by ajax company selector
+if (! empty($_REQUEST['CASHDESK_ID_THIRDPARTY_id']))
+{
+	$_GET['CASHDESK_ID_THIRDPARTY'] = GETPOST('CASHDESK_ID_THIRDPARTY_id','alpha');
+	$_POST['CASHDESK_ID_THIRDPARTY'] = GETPOST('CASHDESK_ID_THIRDPARTY_id','alpha');
+	$_REQUEST['CASHDESK_ID_THIRDPARTY'] = GETPOST('CASHDESK_ID_THIRDPARTY_id','alpha');
+}
+
+// Security check
+if (!$user->admin)
+accessforbidden();
+
+$langs->load("admin");
+$langs->load("cashdesk");
+
+
+/*
+ * Actions
+ */
+if (GETPOST('action','alpha') == 'set')
+{
+	$db->begin();
+
+	if (GETPOST('socid','int') < 0) $_POST["socid"]='';
+
+	$res = dolibarr_set_const($db,"CASHDESK_ID_THIRDPARTY",(GETPOST('socid','int') > 0 ? GETPOST('socid','int') : ''),'chaine',0,'',$conf->entity);
+	$res = dolibarr_set_const($db,"CASHDESK_ID_BANKACCOUNT_CASH",(GETPOST('CASHDESK_ID_BANKACCOUNT_CASH','alpha') > 0 ? GETPOST('CASHDESK_ID_BANKACCOUNT_CASH','alpha') : ''),'chaine',0,'',$conf->entity);
+	$res = dolibarr_set_const($db,"CASHDESK_ID_BANKACCOUNT_CHEQUE",(GETPOST('CASHDESK_ID_BANKACCOUNT_CHEQUE','alpha') > 0 ? GETPOST('CASHDESK_ID_BANKACCOUNT_CHEQUE','alpha') : ''),'chaine',0,'',$conf->entity);
+	$res = dolibarr_set_const($db,"CASHDESK_ID_BANKACCOUNT_CB",(GETPOST('CASHDESK_ID_BANKACCOUNT_CB','alpha') > 0 ? GETPOST('CASHDESK_ID_BANKACCOUNT_CB','alpha') : ''),'chaine',0,'',$conf->entity);
+	$res = dolibarr_set_const($db,"CASHDESK_ID_WAREHOUSE",(GETPOST('CASHDESK_ID_WAREHOUSE','alpha') > 0 ? GETPOST('CASHDESK_ID_WAREHOUSE','alpha') : ''),'chaine',0,'',$conf->entity);
+	$res = dolibarr_set_const($db,"CASHDESK_NO_DECREASE_STOCK",GETPOST('CASHDESK_NO_DECREASE_STOCK','alpha'),'chaine',0,'',$conf->entity);
+	$res = dolibarr_set_const($db,"CASHDESK_SERVICES", GETPOST('CASHDESK_SERVICES','alpha'),'chaine',0,'',$conf->entity);
+	$res = dolibarr_set_const($db,"TAKEBOX", GETPOST('TAKEBOX','alpha'),'chaine',0,'',$conf->entity);
+	$res = dolibarr_set_const($db,"TAKEPOS_BAR_RESTAURANT", GETPOST('TAKEPOS_BAR_RESTAURANT','alpha'),'chaine',0,'',$conf->entity);
+    $res = dolibarr_set_const($db,"TAKEPOS_PRINT_SERVER", GETPOST('TAKEPOS_PRINT_SERVER','alpha'),'chaine',0,'',$conf->entity);
+	$res = dolibarr_set_const($db,"TAKEPOS_ORDER_PRINTERS", GETPOST('TAKEPOS_ORDER_PRINTERS','alpha'),'chaine',0,'',$conf->entity);
+
+	dol_syslog("admin/cashdesk: level ".GETPOST('level','alpha'));
+
+	if (! $res > 0) $error++;
+
+ 	if (! $error)
+    {
+        $db->commit();
+	    setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
+    }
+    else
+    {
+        $db->rollback();
+	    setEventMessages($langs->trans("Error"), null, 'errors');
+    }
+}
+
+/*
+ * View
+ */
+
+$form=new Form($db);
+$formproduct=new FormProduct($db);
+
+llxHeader('',$langs->trans("CashDeskSetup"));
+
+$linkback='<a href="'.DOL_URL_ROOT.'/admin/modules.php">'.$langs->trans("BackToModuleList").'</a>';
+print load_fiche_titre($langs->trans("CashDeskSetup"),$linkback,'title_setup');
+print '<br>';
+
+
+// Mode
+$var=true;
+print '<form action="'.$_SERVER["PHP_SELF"].'" method="post">';
+print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
+print '<input type="hidden" name="action" value="set">';
+
+print '<table class="noborder" width="100%">';
+print '<tr class="liste_titre">';
+print '<td>'.$langs->trans("Parameters").'</td><td>'.$langs->trans("Value").'</td>';
+print "</tr>\n";
+
+print '<tr class="oddeven"><td width=\"50%\">'.$langs->trans("CashDeskThirdPartyForSell").'</td>';
+print '<td colspan="2">';
+print $form->select_company($conf->global->CASHDESK_ID_THIRDPARTY,'socid','s.client in (1,3) AND s.status = 1',1,0,1,array(),0);
+print '</td></tr>';
+if (! empty($conf->banque->enabled))
+{
+
+	print '<tr class="oddeven"><td>'.$langs->trans("CashDeskBankAccountForSell").'</td>';
+	print '<td colspan="2">';
+	$form->select_comptes($conf->global->CASHDESK_ID_BANKACCOUNT_CASH,'CASHDESK_ID_BANKACCOUNT_CASH',0,"courant=2",1);
+	print '</td></tr>';
+
+
+	print '<tr class="oddeven"><td>'.$langs->trans("CashDeskBankAccountForCheque").'</td>';
+	print '<td colspan="2">';
+	$form->select_comptes($conf->global->CASHDESK_ID_BANKACCOUNT_CHEQUE,'CASHDESK_ID_BANKACCOUNT_CHEQUE',0,"courant=1",1);
+	print '</td></tr>';
+
+
+	print '<tr class="oddeven"><td>'.$langs->trans("CashDeskBankAccountForCB").'</td>';
+	print '<td colspan="2">';
+	$form->select_comptes($conf->global->CASHDESK_ID_BANKACCOUNT_CB,'CASHDESK_ID_BANKACCOUNT_CB',0,"courant=1",1);
+	print '</td></tr>';
+}
+
+if (! empty($conf->stock->enabled))
+{
+
+	print '<tr class="oddeven"><td>'.$langs->trans("CashDeskDoNotDecreaseStock").'</td>';	// Force warehouse (this is not a default value)
+	print '<td colspan="2">';
+	if (empty($conf->productbatch->enabled)) {
+	   print $form->selectyesno('CASHDESK_NO_DECREASE_STOCK',$conf->global->CASHDESK_NO_DECREASE_STOCK,1);
+	}
+	else
+	{
+	    if (!$conf->global->CASHDESK_NO_DECREASE_STOCK) {
+	       $res = dolibarr_set_const($db,"CASHDESK_NO_DECREASE_STOCK",1,'chaine',0,'',$conf->entity);
+	    }
+	    print $langs->trans('StockDecreaseForPointOfSaleDisabledbyBatch');
+	}
+	print '</td></tr>';
+
+	$disabled=$conf->global->CASHDESK_NO_DECREASE_STOCK;
+
+
+	print '<tr class="oddeven"><td>'.$langs->trans("CashDeskIdWareHouse").'</td>';	// Force warehouse (this is not a default value)
+	print '<td colspan="2">';
+	if (! $disabled)
+	{
+		print $formproduct->selectWarehouses($conf->global->CASHDESK_ID_WAREHOUSE,'CASHDESK_ID_WAREHOUSE','',1,$disabled);
+		print ' <a href="'.DOL_URL_ROOT.'/product/stock/card.php?action=create&backtopage='.urlencode($_SERVER["PHP_SELF"]).'">('.$langs->trans("Create").')</a>';
+	}
+	else
+	{
+		print $langs->trans("StockDecreaseForPointOfSaleDisabled");
+	}
+	print '</td></tr>';
+}
+
+if (! empty($conf->service->enabled))
+{
+    $var=! $var;
+    print '<tr class="oddeven"><td>';
+    print $langs->trans("CashdeskShowServices");
+    print '<td colspan="2">';
+    print $form->selectyesno("CASHDESK_SERVICES",$conf->global->CASHDESK_SERVICES,1);
+    print "</td></tr>\n";
+}
+
+// Use Takepos printing
+$var=! $var;
+print '<tr class="oddeven"><td>';
+print $langs->trans("DolibarrReceiptPrinter").' TakeBOX (<a href="http://en.takepos.com/takebox">'.$langs->trans("TakeboxNecesary").'</a>)';
+print '<td colspan="2">';
+print $form->selectyesno("TAKEBOX",$conf->global->TAKEBOX,1);
+print "</td></tr>\n";
+
+if ($conf->global->TAKEBOX){
+    print '<tr class="oddeven value"><td>';
+    print $langs->trans("IPAddress").' (<a href="http://en.takepos.com/takebox">'.$langs->trans("TakeboxNecesary").'</a>)';
+    print '<td colspan="2">';
+    print '<input type="text" size="20" id="TAKEPOS_PRINT_SERVER" name="TAKEPOS_PRINT_SERVER" value="'.$conf->global->TAKEPOS_PRINT_SERVER.'">';
+    print '</td></tr>';
+}
+
+// Bar Restaurant mode
+$var=! $var;
+print '<tr class="oddeven"><td>';
+print 'Bar Restaurant';
+print '<td colspan="2">';
+print $form->selectyesno("TAKEPOS_BAR_RESTAURANT",$conf->global->TAKEPOS_BAR_RESTAURANT,1);
+print "</td></tr>\n";
+
+if ($conf->global->TAKEPOS_BAR_RESTAURANT and $conf->global->TAKEBOX){
+    print '<tr class="oddeven value"><td>';
+    print $langs->trans("OrderPrinters").' (<a href="orderprinters.php?leftmenu=setup">'.$langs->trans("Setup").'</a>)';
+    print '<td colspan="2">';
+    print $form->selectyesno("TAKEPOS_ORDER_PRINTERS",$conf->global->TAKEPOS_ORDER_PRINTERS,1);
+    print '</td></tr>';
+}
+
+print '</table>';
+print '<br>';
+
+print '<div class="center"><input type="submit" class="button" value="'.$langs->trans("Save").'"></div>';
+
+print "</form>\n";
+
+
+
+// Marketplace
+print "<br><table summary=\"list_of_modules\" class=\"noborder\" width=\"100%\">\n";
+print "<tr class=\"liste_titre\">\n";
+print '<td colspan="2">TakePOS Marketplace</td>';
+print '<td>'.$langs->trans("URL").'</td>';
+print '</tr>';
+
+print "<tr class=\"oddeven\">\n";
+$url='https://www.dolistore.com/en/modules/980-TakePOS-7-mobile.html';
+print '<td align="left"><a href="'.$url.'" target="_blank" rel="external"><img border="0" class="imgautosize imgmaxwidth180" src="../img/marketplace/takeposmobile.jpg"></a></td>';
+print '<td>TakePOS for mobile devices</td>';
+print '<td><a href="'.$url.'" target="_blank" rel="external">'.$url.'</a></td>';
+print '</tr>';
+
+print "<tr class=\"oddeven\">\n";
+$url='https://www.dolistore.com/en/modules/949-Cash-Control-7.html';
+print '<td align="left"><a href="'.$url.'" target="_blank" rel="external"><img border="0" class="imgautosize imgmaxwidth180" src="../img/marketplace/cashcontrol.jpg"></a></td>';
+print '<td>TakePOS CashControl</td>';
+print '<td><a href="'.$url.'" target="_blank" rel="external">'.$url.'</a></td>';
+print '</tr>';
+
+print "</table>\n";
+print '<br>';
+
+// Support
+print "<br><table summary=\"list_of_modules\" class=\"noborder\" width=\"100%\">\n";
+print "<tr class=\"liste_titre\">\n";
+print '<td colspan="2">TakePOS Support</td>';
+print '<td>'.$langs->trans("URL").'</td>';
+print '</tr>';
+
+print "<tr class=\"oddeven\">\n";
+$url='http://www.takepos.com';
+print '<td align="left"><a href="'.$url.'" target="_blank" rel="external"><img border="0" class="imgautosize imgmaxwidth180" src="../img/takepos.png"></a></td>';
+print '<td>TakePOS official developers</td>';
+print '<td><a href="'.$url.'" target="_blank" rel="external">'.$url.'</a></td>';
+print '</tr>';
+
+print "</table>\n";
+print '<br>';
+
+llxFooter();
+$db->close();

+ 62 - 0
htdocs/takepos/ajax.php

@@ -0,0 +1,62 @@
+<?php
+/* Copyright (C) 2001-2004	Andreu Bisquerra	<jove@bisquerra.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ *	\file       htdocs/takepos/ajax.php
+ *	\brief      Ajax search component for TakePos. It search products of a category.
+ */
+
+//if (! defined('NOREQUIREUSER'))	define('NOREQUIREUSER','1');	// Not disabled cause need to load personalized language
+//if (! defined('NOREQUIREDB'))		define('NOREQUIREDB','1');		// Not disabled cause need to load personalized language
+if (! defined('NOREQUIRESOC'))		define('NOREQUIRESOC','1');
+//if (! defined('NOREQUIRETRAN'))		define('NOREQUIRETRAN','1');
+if (! defined('NOCSRFCHECK'))		define('NOCSRFCHECK','1');
+if (! defined('NOTOKENRENEWAL'))	define('NOTOKENRENEWAL','1');
+if (! defined('NOREQUIREMENU'))		define('NOREQUIREMENU','1');
+if (! defined('NOREQUIREHTML'))		define('NOREQUIREHTML','1');
+if (! defined('NOREQUIREAJAX'))		define('NOREQUIREAJAX','1');
+
+require '../main.inc.php';	// Load $user and permissions
+require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
+
+$category = GETPOST('category');
+$action = GETPOST('action');
+$term = GETPOST('term');
+
+
+/*
+ * View
+ */
+
+if ($action=="getProducts"){
+	$object = new Categorie($db);
+	$result=$object->fetch($category);
+	$prods = $object->getObjectsInCateg("product");
+	echo json_encode($prods);
+}
+
+if ($action=="search"){
+	$sql = 'SELECT * FROM '.MAIN_DB_PREFIX.'product';
+	$sql.= ' WHERE entity IN ('.getEntity('product').')';
+	$sql .= natural_search(array('label','barcode'), $term);
+	$resql = $db->query($sql);
+	$rows = array();
+	while($row = $db->fetch_array ($resql)){
+		$rows[] = $row;
+	}
+	echo json_encode($rows);
+}

+ 223 - 0
htdocs/takepos/class/actions_takepos.class.php

@@ -0,0 +1,223 @@
+<?php
+/* Copyright (C) 2018 SuperAdmin
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file    takepos/class/actions_takepos.class.php
+ * \ingroup takepos
+ * \brief   Hooks of takepos module
+ */
+
+/**
+ * Class ActionsTakePos
+ */
+class ActionsTakePos
+{
+    /**
+     * @var DoliDB Database handler.
+     */
+    public $db;
+    /**
+     * @var string Error
+     */
+    public $error = '';
+    /**
+     * @var array Errors
+     */
+    public $errors = array();
+
+
+	/**
+	 * @var array Hook results. Propagated to $hookmanager->resArray for later reuse
+	 */
+	public $results = array();
+
+	/**
+	 * @var string String displayed by executeHook() immediately after return
+	 */
+	public $resprints;
+
+
+	/**
+	 * Constructor
+	 *
+	 *  @param		DoliDB		$db      Database handler
+	 */
+	public function __construct($db)
+	{
+	    $this->db = $db;
+	}
+
+	/**
+	 * Overloading the doActions function : replacing the parent's function with the one below
+	 *
+	 * @param   array()         $parameters     Hook metadatas (context, etc...)
+	 * @param   CommonObject    $object         The object to process (an invoice if you are in invoice module, a propale in propale's module, etc...)
+	 * @param   string          $action         Current action (if set). Generally create or edit or null
+	 * @param   HookManager     $hookmanager    Hook manager propagated to allow calling another hook
+	 * @return  int                             < 0 on error, 0 on success, 1 to replace standard code
+	 */
+	public function doActions($parameters, &$object, &$action, $hookmanager)
+	{
+		global $conf, $user, $langs;
+
+		$error = 0; // Error counter
+
+        /* print_r($parameters); print_r($object); echo "action: " . $action; */
+	    if (in_array($parameters['currentcontext'], array('somecontext1','somecontext2')))	    // do something only for the context 'somecontext1' or 'somecontext2'
+	    {
+			// Do what you want here...
+			// You can for example call global vars like $fieldstosearchall to overwrite them, or update database depending on $action and $_POST values.
+		}
+
+		if (! $error) {
+			$this->results = array('myreturn' => 999);
+			$this->resprints = 'A text to show';
+			return 0;                                    // or return 1 to replace standard code
+		} else {
+			$this->errors[] = 'Error message';
+			return -1;
+		}
+	}
+
+
+	/**
+	 * Overloading the doActions function : replacing the parent's function with the one below
+	 *
+	 * @param   array()         $parameters     Hook metadatas (context, etc...)
+	 * @param   CommonObject    $object         The object to process (an invoice if you are in invoice module, a propale in propale's module, etc...)
+	 * @param   string          $action         Current action (if set). Generally create or edit or null
+	 * @param   HookManager     $hookmanager    Hook manager propagated to allow calling another hook
+	 * @return  int                             < 0 on error, 0 on success, 1 to replace standard code
+	 */
+	public function addMoreActionsButtons($parameters, &$object, &$action, $hookmanager)
+	{
+	    global $conf, $user, $langs;
+
+	    $error = 0; // Error counter
+
+        /* print_r($parameters); print_r($object); echo "action: " . $action; */
+	    if (in_array($parameters['currentcontext'], array('invoicecard')))		// do something only for the context 'somecontext1' or 'somecontext2'
+	    {
+
+			if (file_exists("../../takepos/receipt.php")) $receipt_url=DOL_URL_ROOT."/takepos/receipt.php";
+			if (file_exists("../../custom/takepos/receipt.php")) $receipt_url=DOL_URL_ROOT."/custom/takepos/receipt.php";
+	        print '<div class="inline-block divButAction"><a target="_blank" class="butAction" href="' . $receipt_url . '?facid=' . $object->id.'">' . $langs->trans('Ticket') .'</a></div>';
+	    }
+
+	    if (! $error) {
+	        $this->results = array('myreturn' => 999);
+	        $this->resprints = 'A text to show';
+	        return 0;                                    // or return 1 to replace standard code
+	    } else {
+	        $this->errors[] = 'Error message';
+	        return -1;
+	    }
+	}
+
+
+	/**
+	 * Overloading the addMoreMassActions function : replacing the parent's function with the one below
+	 *
+	 * @param   array()         $parameters     Hook metadatas (context, etc...)
+	 * @param   CommonObject    $object         The object to process (an invoice if you are in invoice module, a propale in propale's module, etc...)
+	 * @param   string          $action         Current action (if set). Generally create or edit or null
+	 * @param   HookManager     $hookmanager    Hook manager propagated to allow calling another hook
+	 * @return  int                             < 0 on error, 0 on success, 1 to replace standard code
+	 */
+	public function addMoreMassActions($parameters, &$object, &$action, $hookmanager)
+	{
+	    global $conf, $user, $langs;
+
+	    $error = 0; // Error counter
+
+        /* print_r($parameters); print_r($object); echo "action: " . $action; */
+	    if (in_array($parameters['currentcontext'], array('somecontext1','somecontext2')))		// do something only for the context 'somecontext1' or 'somecontext2'
+	    {
+	        $this->resprints = '<option value="0"'.($disabled?' disabled="disabled"':'').'>'.$langs->trans("TakePosMassAction").'</option>';
+	    }
+
+	    if (! $error) {
+	        return 0;                                    // or return 1 to replace standard code
+	    } else {
+	        $this->errors[] = 'Error message';
+	        return -1;
+	    }
+	}
+
+
+
+	/**
+	 * Execute action
+	 *
+	 * @param	array	$parameters		Array of parameters
+	 * @param   Object	$object		   	Object output on PDF
+	 * @param   string	$action     	'add', 'update', 'view'
+	 * @return  int 		        	<0 if KO,
+	 *                          		=0 if OK but we want to process standard actions too,
+	 *  	                            >0 if OK and we want to replace standard actions.
+	 */
+	function beforePDFCreation($parameters, &$object, &$action)
+	{
+		global $langs,$conf;
+		global $hookmanager;
+
+		$outputlangs=$langs;
+
+		$ret=0; $deltemp=array();
+		dol_syslog(get_class($this).'::executeHooks action='.$action);
+
+		/* print_r($parameters); print_r($object); echo "action: " . $action; */
+		if (in_array($parameters['currentcontext'], array('somecontext1','somecontext2')))		// do something only for the context 'somecontext1' or 'somecontext2'
+		{
+
+		}
+
+		return $ret;
+	}
+
+	/**
+	 * Execute action
+	 *
+	 * @param	array	$parameters		Array of parameters
+	 * @param   Object	$pdfhandler   	PDF builder handler
+	 * @param   string	$action     	'add', 'update', 'view'
+	 * @return  int 		        	<0 if KO,
+	 *                          		=0 if OK but we want to process standard actions too,
+	 *  	                            >0 if OK and we want to replace standard actions.
+	 */
+	function afterPDFCreation($parameters, &$pdfhandler, &$action)
+	{
+		global $langs,$conf;
+		global $hookmanager;
+
+		$outputlangs=$langs;
+
+		$ret=0; $deltemp=array();
+		dol_syslog(get_class($this).'::executeHooks action='.$action);
+
+		/* print_r($parameters); print_r($object); echo "action: " . $action; */
+		if (in_array($parameters['currentcontext'], array('somecontext1','somecontext2')))		// do something only for the context 'somecontext1' or 'somecontext2'
+		{
+
+		}
+
+		return $ret;
+	}
+
+	/* Add here any other hooked methods... */
+
+}

+ 58 - 0
htdocs/takepos/css/colorbox.css

@@ -0,0 +1,58 @@
+/*
+    Colorbox Core Style:
+    The following CSS is consistent between example themes and should not be altered.
+*/
+#colorbox, #cboxOverlay, #cboxWrapper{position:absolute; top:0; left:0; z-index:9999; overflow:hidden; -webkit-transform: translate3d(0,0,0);}
+#cboxWrapper {max-width:none;}
+#cboxOverlay{position:fixed; width:100%; height:100%;}
+#cboxMiddleLeft, #cboxBottomLeft{clear:left;}
+#cboxContent{position:relative;}
+#cboxLoadedContent{overflow:auto; -webkit-overflow-scrolling: touch;}
+#cboxTitle{margin:0;}
+#cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%; height:100%;}
+#cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{cursor:pointer;}
+.cboxPhoto{float:left; margin:auto; border:0; display:block; max-width:none; -ms-interpolation-mode:bicubic;}
+.cboxIframe{width:100%; height:100%; display:block; border:0; padding:0; margin:0;}
+#colorbox, #cboxContent, #cboxLoadedContent{box-sizing:content-box; -moz-box-sizing:content-box; -webkit-box-sizing:content-box;}
+
+/* 
+    User Style:
+    Change the following styles to modify the appearance of Colorbox.  They are
+    ordered & tabbed in a way that represents the nesting of the generated HTML.
+*/
+#cboxOverlay{background:#000; opacity: 0.9; filter: alpha(opacity = 90);}
+#colorbox{outline:0;}
+    #cboxTopLeft{width:14px; height:14px; background:url(images/controls.png) no-repeat 0 0;}
+    #cboxTopCenter{height:14px; background:url(images/border.png) repeat-x top left;}
+    #cboxTopRight{width:14px; height:14px; background:url(images/controls.png) no-repeat -36px 0;}
+    #cboxBottomLeft{width:14px; height:43px; background:url(images/controls.png) no-repeat 0 -32px;}
+    #cboxBottomCenter{height:43px; background:url(images/border.png) repeat-x bottom left;}
+    #cboxBottomRight{width:14px; height:43px; background:url(images/controls.png) no-repeat -36px -32px;}
+    #cboxMiddleLeft{width:14px; background:url(images/controls.png) repeat-y -175px 0;}
+    #cboxMiddleRight{width:14px; background:url(images/controls.png) repeat-y -211px 0;}
+    #cboxContent{background:#fff; overflow:visible;}
+        .cboxIframe{background:#fff;}
+        #cboxError{padding:50px; border:1px solid #ccc;}
+        #cboxLoadedContent{margin-bottom:5px;}
+        #cboxLoadingOverlay{background:url(images/loading_background.png) no-repeat center center;}
+        #cboxLoadingGraphic{background:url(images/loading.gif) no-repeat center center;}
+        #cboxTitle{position:absolute; bottom:-25px; left:0; text-align:center; width:100%; font-weight:bold; color:#7C7C7C;}
+        #cboxCurrent{position:absolute; bottom:-25px; left:58px; font-weight:bold; color:#7C7C7C;}
+
+        /* these elements are buttons, and may need to have additional styles reset to avoid unwanted base styles */
+        #cboxPrevious, #cboxNext, #cboxSlideshow, #cboxClose {border:0; padding:0; margin:0; overflow:visible;  position:absolute; bottom:-29px; background:url(images/controls.png) no-repeat 0px 0px; width:23px; height:23px; text-indent:-9999px;}
+        
+        /* avoid outlines on :active (mouseclick), but preserve outlines on :focus (tabbed navigating) */
+        #cboxPrevious:active, #cboxNext:active, #cboxSlideshow:active, #cboxClose:active {outline:0;}
+
+        #cboxPrevious{left:0px; background-position: -51px -25px;}
+        #cboxPrevious:hover{background-position:-51px 0px;}
+        #cboxNext{left:27px; background-position:-75px -25px;}
+        #cboxNext:hover{background-position:-75px 0px;}
+        #cboxClose{right:0; background-position:-100px -25px;}
+        #cboxClose:hover{background-position:-100px 0px;}
+
+        .cboxSlideshow_on #cboxSlideshow{background-position:-125px 0px; right:27px;}
+        .cboxSlideshow_on #cboxSlideshow:hover{background-position:-150px 0px;}
+        .cboxSlideshow_off #cboxSlideshow{background-position:-150px -25px; right:27px;}
+        .cboxSlideshow_off #cboxSlideshow:hover{background-position:-125px 0px;}

BIN
htdocs/takepos/css/images/border.png


BIN
htdocs/takepos/css/images/controls.png


BIN
htdocs/takepos/css/images/loading.gif


BIN
htdocs/takepos/css/images/loading_background.png


+ 114 - 0
htdocs/takepos/css/pos.css

@@ -0,0 +1,114 @@
+html,body {
+    padding:0;
+    margin:0;
+    height:100%;
+}
+
+body {
+    width:100%;
+}
+
+.row {
+    width:100%;
+    height:50%;
+}
+
+.row div {
+    width:33%;
+    height:100%;
+    float:left;
+}
+
+button.calcbutton {
+	display: inline-block;
+	position: relative;
+	padding: 0;
+	line-height: normal;
+	cursor: pointer;
+	vertical-align: middle;
+	text-align: center;
+	font-size:180%;
+	overflow: visible; /* removes extra width in IE */
+	width:24%;
+	height:24%;
+}
+
+button.calcbutton2 {
+	display: inline-block;
+	position: relative;
+	padding: 0;
+	line-height: normal;
+	cursor: pointer;
+	vertical-align: middle;
+	text-align: center;
+	font-size:120%;
+	overflow: visible; /* removes extra width in IE */
+	width:24%;
+	height:24%;
+}
+
+button.actionbutton {
+	display: inline-block;
+	position: relative;
+	padding: 0;
+	line-height: normal;
+	cursor: pointer;
+	vertical-align: middle;
+	text-align: center;
+	font-size:100%;
+	overflow: visible; /* removes extra width in IE */
+	width:32%;
+	height:32%;
+}
+
+div.wrapper{
+	float:left; /* important */
+	position:relative; /* important(so we can absolutely position the description div */
+	width:21.5%;
+	height:23%;
+	margin:1%;
+	border: 0.1em solid;
+	box-shadow: 3px 3px 2px #888;
+	text-align: center;
+}
+
+div.wrapper2{
+	float:left; /* important */
+	position:relative; /* important(so we can absolutely position the description div */
+	width:10.2%;
+	height:23%;
+	margin-top:0.5%;
+	margin-bottom:0.5%;
+	margin-left:0.5%;
+	margin-right:0.5%;
+	border: 0.1em solid;
+	box-shadow: 3px 3px 2px #888;
+	text-align: center;
+}
+
+div.description{
+	position:absolute; /* absolute position (so we can position it where we want)*/
+	bottom:0px; /* position will be on bottom */
+	left:0px;
+	width:100%;
+	/* styling bellow */
+	background-color:black;
+	font-family: 'tahoma';
+	font-size:100%;
+	color:white;
+	opacity:0.8; /* transparency */
+	filter:alpha(opacity=80); /* IE transparency */
+	text-align:center;
+}
+
+@media only screen and (max-aspect-ratio: 6/4) {
+	div.description{
+	min-height:20%;
+	}
+}
+
+p.description_content{
+	padding:10px;
+	margin:0px;
+	
+}

+ 1265 - 0
htdocs/takepos/customers.php

@@ -0,0 +1,1265 @@
+<?php
+/* Copyright (C) 2001-2004  Rodolphe Quiedeville    <rodolphe@quiedeville.org>
+ * Copyright (C) 2004-2016  Laurent Destailleur     <eldy@users.sourceforge.net>
+ * Copyright (C) 2005-2012  Regis Houssin           <regis.houssin@capnetworks.com>
+ * Copyright (C) 2012       Marcos García           <marcosgdf@gmail.com>
+ * Copyright (C) 2013-2015  Raphaël Doursenaud      <rdoursenaud@gpcsolutions.fr>
+ * Copyright (C) 2015       Florian Henry           <florian.henry@open-concept.pro>
+ * Copyright (C) 2016       Josep Lluis Amador      <joseplluis@lliuretic.cat>
+ * Copyright (C) 2016       Ferran Marcet      		<fmarcet@2byte.es>
+ * Copyright (C) 2017       Rui Strecht      		<rui.strecht@aliartalentos.com>
+ * Copyright (C) 2017       Juanjo Menent      		<jmenent@2byte.es>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ *	\file       htdocs/takepos/customers.php
+ *	\ingroup    societe
+ *	\brief      Page to show list of third parties. TODO Merge with societe/list.php
+ */
+
+require '../main.inc.php';	// Load $user and permissions
+include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
+require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
+require_once DOL_DOCUMENT_ROOT.'/societe/class/client.class.php';
+
+$langs->loadLangs(array("companies", "commercial", "customers", "suppliers", "bills", "compta", "categories"));
+
+$action=GETPOST('action','alpha');
+$massaction=GETPOST('massaction','alpha');
+$show_files=GETPOST('show_files','int');
+$confirm=GETPOST('confirm','alpha');
+$toselect = GETPOST('toselect', 'array');
+$idcustomer = GETPOST('idcustomer');
+$place = GETPOST('place');
+$_GET['optioncss'] = 'print';
+
+if ($action=="change") {
+    $sql="UPDATE ".MAIN_DB_PREFIX."facture set fk_soc=".$idcustomer." where facnumber='(PROV-POS-".$place.")'";
+    $resql = $db->query($sql);
+    ?>
+    <script>
+    parent.$("#poslines").load("invoice.php?place="+<?php print $place;?>, function() {
+        parent.$("#poslines").scrollTop(parent.$("#poslines")[0].scrollHeight);
+        parent.$.colorbox.close();
+    });
+    </script>
+    <?php
+    exit;
+}
+
+// Security check
+$socid = GETPOST('socid','int');
+if ($user->societe_id) $socid=$user->societe_id;
+$result = restrictedArea($user,'societe',$socid,'');
+
+$search_all=trim(GETPOST('search_all', 'alphanohtml')?GETPOST('search_all', 'alphanohtml'):GETPOST('sall', 'alphanohtml'));
+$search_cti=preg_replace('/^0+/', '', preg_replace('/[^0-9]/', '', GETPOST('search_cti', 'alphanohtml')));	// Phone number without any special chars
+
+$search_id=trim(GETPOST("search_id","int"));
+$search_nom=trim(GETPOST("search_nom"));
+$search_alias=trim(GETPOST("search_alias"));
+$search_nom_only=trim(GETPOST("search_nom_only"));
+$search_barcode=trim(GETPOST("search_barcode"));
+$search_customer_code=trim(GETPOST('search_customer_code'));
+$search_supplier_code=trim(GETPOST('search_supplier_code'));
+$search_account_customer_code=trim(GETPOST('search_account_customer_code'));
+$search_account_supplier_code=trim(GETPOST('search_account_supplier_code'));
+$search_town=trim(GETPOST("search_town"));
+$search_zip=trim(GETPOST("search_zip"));
+$search_state=trim(GETPOST("search_state"));
+$search_region=trim(GETPOST("search_region"));
+$search_email=trim(GETPOST('search_email'));
+$search_phone=trim(GETPOST('search_phone'));
+$search_url=trim(GETPOST('search_url'));
+$search_idprof1=trim(GETPOST('search_idprof1'));
+$search_idprof2=trim(GETPOST('search_idprof2'));
+$search_idprof3=trim(GETPOST('search_idprof3'));
+$search_idprof4=trim(GETPOST('search_idprof4'));
+$search_idprof5=trim(GETPOST('search_idprof5'));
+$search_idprof6=trim(GETPOST('search_idprof6'));
+$search_vat=trim(GETPOST('search_vat'));
+$search_sale=trim(GETPOST("search_sale",'int'));
+$search_categ_cus=trim(GETPOST("search_categ_cus",'int'));
+$search_categ_sup=trim(GETPOST("search_categ_sup",'int'));
+$search_country=GETPOST("search_country",'intcomma');
+$search_type_thirdparty=GETPOST("search_type_thirdparty",'int');
+$search_status=GETPOST("search_status",'int');
+$search_type=GETPOST('search_type','alpha');
+$search_level_from = GETPOST("search_level_from","alpha");
+$search_level_to   = GETPOST("search_level_to","alpha");
+$search_stcomm=GETPOST('search_stcomm','int');
+$search_import_key  = GETPOST("search_import_key","alpha");
+
+$type=GETPOST('type');
+$optioncss=GETPOST('optioncss','alpha');
+$mode=GETPOST("mode");
+
+$diroutputmassaction=$conf->societe->dir_output . '/temp/massgeneration/'.$user->id;
+
+$limit = GETPOST('limit','int')?GETPOST('limit','int'):$conf->liste_limit;
+$sortfield=GETPOST("sortfield",'alpha');
+$sortorder=GETPOST("sortorder",'alpha');
+$page=GETPOST("page",'int');
+if (! $sortorder) $sortorder="ASC";
+if (! $sortfield) $sortfield="s.nom";
+if (empty($page) || $page == -1) { $page = 0; }
+$offset = $limit * $page;
+$pageprev = $page - 1;
+$pagenext = $page + 1;
+
+// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
+$contextpage='thirdpartylist';
+/*if ($search_type == '1,3') { $contextpage='customerlist'; $type='c'; }
+if ($search_type == '2,3') { $contextpage='prospectlist'; $type='p'; }
+if ($search_type == '4') { $contextpage='supplierlist'; $type='f'; }
+*/
+if ($type == 'c') { $contextpage='customerlist'; if ($search_type=='') $search_type='1,3'; }
+if ($type == 'p') { $contextpage='prospectlist'; if ($search_type=='') $search_type='2,3'; }
+if ($type == 'f') { $contextpage='supplierlist'; if ($search_type=='') $search_type='4'; }
+
+// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
+$hookmanager->initHooks(array($contextpage));
+$extrafields = new ExtraFields($db);
+
+// fetch optionals attributes and labels
+$extralabels = $extrafields->fetch_name_optionals_label('societe');
+$search_array_options=$extrafields->getOptionalsFromPost($extralabels,'','search_');
+
+// List of fields to search into when doing a "search in all"
+$fieldstosearchall = array(
+	's.nom'=>"ThirdPartyName",
+	's.name_alias'=>"AliasNameShort",
+	's.code_client'=>"CustomerCode",
+	's.code_fournisseur'=>"SupplierCode",
+	's.code_compta'=>"CustomerAccountancyCodeShort",
+	's.code_compta_fournisseur'=>"SupplierAccountancyCodeShort",
+	's.email'=>"EMail",
+	's.url'=>"URL",
+	's.tva_intra'=>"VATIntra",
+	's.siren'=>"ProfId1",
+	's.siret'=>"ProfId2",
+	's.ape'=>"ProfId3",
+);
+if (($tmp = $langs->transnoentities("ProfId4".$mysoc->country_code)) && $tmp != "ProfId4".$mysoc->country_code && $tmp != '-') $fieldstosearchall['s.idprof4']='ProfId4';
+if (($tmp = $langs->transnoentities("ProfId5".$mysoc->country_code)) && $tmp != "ProfId5".$mysoc->country_code && $tmp != '-') $fieldstosearchall['s.idprof5']='ProfId5';
+if (($tmp = $langs->transnoentities("ProfId6".$mysoc->country_code)) && $tmp != "ProfId6".$mysoc->country_code && $tmp != '-') $fieldstosearchall['s.idprof6']='ProfId6';
+if (!empty($conf->barcode->enabled)) $fieldstosearchall['s.barcode']='Gencod';
+
+// Define list of fields to show into list
+$checkedcustomercode=(in_array($contextpage, array('thirdpartylist', 'customerlist', 'prospectlist')) ? 1 : 0);
+$checkedsuppliercode=(in_array($contextpage, array('supplierlist')) ? 1 : 0);
+$checkedcustomeraccountcode=(in_array($contextpage, array('customerlist')) ? 1 : 0);
+$checkedsupplieraccountcode=(in_array($contextpage, array('supplierlist')) ? 1 : 0);
+$checkedtypetiers=1;
+$checkedprofid1=0;
+$checkedprofid2=0;
+$checkedprofid3=0;
+$checkedprofid4=0;
+$checkedprofid5=0;
+$checkedprofid6=0;
+//$checkedprofid4=((($tmp = $langs->transnoentities("ProfId4".$mysoc->country_code)) && $tmp != "ProfId4".$mysoc->country_code && $tmp != '-') ? 1 : 0);
+//$checkedprofid5=((($tmp = $langs->transnoentities("ProfId5".$mysoc->country_code)) && $tmp != "ProfId5".$mysoc->country_code && $tmp != '-') ? 1 : 0);
+//$checkedprofid6=((($tmp = $langs->transnoentities("ProfId6".$mysoc->country_code)) && $tmp != "ProfId6".$mysoc->country_code && $tmp != '-') ? 1 : 0);
+$checkprospectlevel=(in_array($contextpage, array('prospectlist')) ? 1 : 0);
+$checkstcomm=(in_array($contextpage, array('prospectlist')) ? 1 : 0);
+$arrayfields=array(
+	's.rowid'=>array('label'=>"TechnicalID", 'checked'=>($conf->global->MAIN_SHOW_TECHNICAL_ID?1:0), 'enabled'=>($conf->global->MAIN_SHOW_TECHNICAL_ID?1:0)),
+	's.nom'=>array('label'=>"ThirdPartyName", 'checked'=>1),
+	's.name_alias'=>array('label'=>"AliasNameShort", 'checked'=>1),
+	's.barcode'=>array('label'=>"Gencod", 'checked'=>1, 'enabled'=>(! empty($conf->barcode->enabled))),
+	's.code_client'=>array('label'=>"CustomerCodeShort", 'checked'=>$checkedcustomercode),
+	's.code_fournisseur'=>array('label'=>"SupplierCodeShort", 'checked'=>$checkedsuppliercode, 'enabled'=>(! empty($conf->fournisseur->enabled))),
+	's.code_compta'=>array('label'=>"CustomerAccountancyCodeShort", 'checked'=>$checkedcustomeraccountcode),
+	's.code_compta_fournisseur'=>array('label'=>"SupplierAccountancyCodeShort", 'checked'=>$checkedsupplieraccountcode, 'enabled'=>(! empty($conf->fournisseur->enabled))),
+	's.town'=>array('label'=>"Town", 'checked'=>1),
+	's.zip'=>array('label'=>"Zip", 'checked'=>1),
+	'state.nom'=>array('label'=>"State", 'checked'=>0),
+	'region.nom'=>array('label'=>"Region", 'checked'=>0),
+	'country.code_iso'=>array('label'=>"Country", 'checked'=>0),
+	's.email'=>array('label'=>"Email", 'checked'=>0),
+	's.url'=>array('label'=>"Url", 'checked'=>0),
+	's.phone'=>array('label'=>"Phone", 'checked'=>1),
+	'typent.code'=>array('label'=>"ThirdPartyType", 'checked'=>$checkedtypetiers),
+	's.siren'=>array('label'=>"ProfId1Short", 'checked'=>$checkedprofid1),
+	's.siret'=>array('label'=>"ProfId2Short", 'checked'=>$checkedprofid2),
+	's.ape'=>array('label'=>"ProfId3Short", 'checked'=>$checkedprofid3),
+	's.idprof4'=>array('label'=>"ProfId4Short", 'checked'=>$checkedprofid4),
+	's.idprof5'=>array('label'=>"ProfId5Short", 'checked'=>$checkedprofid5),
+	's.idprof6'=>array('label'=>"ProfId6Short", 'checked'=>$checkedprofid6),
+	's.tva_intra'=>array('label'=>"VATIntra", 'checked'=>0),
+	'customerorsupplier'=>array('label'=>'Nature', 'checked'=>1),
+	's.fk_prospectlevel'=>array('label'=>"ProspectLevelShort", 'checked'=>$checkprospectlevel),
+	's.fk_stcomm'=>array('label'=>"StatusProsp", 'checked'=>$checkstcomm),
+	's.datec'=>array('label'=>"DateCreation", 'checked'=>0, 'position'=>500),
+	's.tms'=>array('label'=>"DateModificationShort", 'checked'=>0, 'position'=>500),
+	's.status'=>array('label'=>"Status", 'checked'=>1, 'position'=>1000),
+	's.import_key'=>array('label'=>"ImportId", 'checked'=>0, 'position'=>1100),
+);
+// Extra fields
+if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label))
+{
+   foreach($extrafields->attribute_label as $key => $val)
+   {
+		if (! empty($extrafields->attribute_list[$key])) $arrayfields["ef.".$key]=array('label'=>$extrafields->attribute_label[$key], 'checked'=>(($extrafields->attribute_list[$key]<0)?0:1), 'position'=>$extrafields->attribute_pos[$key], 'enabled'=>(abs($extrafields->attribute_list[$key])!=3 && $extrafields->attribute_perms[$key]));
+   }
+}
+
+$object = new Societe($db);
+
+
+/*
+ * Actions
+ */
+
+if (GETPOST('cancel','alpha')) { $action='list'; $massaction=''; }
+if (! GETPOST('confirmmassaction','alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') { $massaction=''; }
+
+$parameters=array();
+$reshook=$hookmanager->executeHooks('doActions',$parameters, $object, $action);    // Note that $action and $object may have been modified by some hooks
+if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
+
+if (empty($reshook))
+{
+	// Selection of new fields
+	include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php';
+
+	// Did we click on purge search criteria ?
+	if (GETPOST('button_removefilter_x','alpha') || GETPOST('button_removefilter.x','alpha') || GETPOST('button_removefilter','alpha')) // All tests are required to be compatible with all browsers
+	{
+		$search_id='';
+		$search_nom='';
+		$search_alias='';
+		$search_categ_cus=0;
+		$search_categ_sup=0;
+		$search_sale='';
+		$search_barcode="";
+		$search_customer_code='';
+		$search_supplier_code='';
+		$search_account_customer_code='';
+		$search_account_supplier_code='';
+		$search_town="";
+		$search_zip="";
+		$search_state="";
+		$search_country='';
+		$search_email='';
+		$search_phone='';
+		$search_url='';
+		$search_idprof1='';
+		$search_idprof2='';
+		$search_idprof3='';
+		$search_idprof4='';
+		$search_idprof5='';
+		$search_idprof6='';
+		$search_vat='';
+		$search_type='';
+		$search_type_thirdparty='';
+		$search_status=-1;
+		$search_stcomm='';
+	 	$search_level_from='';
+	 	$search_level_to='';
+	 	$search_import_key='';
+	 	$toselect='';
+		$search_array_options=array();
+	}
+
+	// Mass actions
+	$objectclass='Societe';
+	$objectlabel='ThirdParty';
+	$permtoread = $user->rights->societe->lire;
+	$permtodelete = $user->rights->societe->supprimer;
+	$uploaddir = $conf->societe->dir_output;
+	include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php';
+
+	if ($action == 'setstcomm')
+	{
+		$object = new Client($db);
+		$result=$object->fetch(GETPOST('stcommsocid'));
+		$object->stcomm_id=dol_getIdFromCode($db, GETPOST('stcomm','alpha'), 'c_stcomm');
+		$result=$object->update($object->id, $user);
+		if ($result < 0) setEventMessages($object->error,$object->errors,'errors');
+
+		$action='';
+	}
+}
+
+if ($search_status=='') $search_status=1; // always display active thirdparty first
+
+
+
+/*
+ * View
+ */
+
+/*
+ REM: Rules on permissions to see thirdparties
+ Internal or External user + No permission to see customers => See nothing
+ Internal user socid=0 + Permission to see ALL customers    => See all thirdparties
+ Internal user socid=0 + No permission to see ALL customers => See only thirdparties linked to user that are sale representative
+ External user socid=x + Permission to see ALL customers    => Can see only himself
+ External user socid=x + No permission to see ALL customers => Can see only himself
+ */
+
+$form=new Form($db);
+$formother=new FormOther($db);
+$companystatic=new Societe($db);
+$formcompany=new FormCompany($db);
+$prospectstatic=new Client($db);
+$prospectstatic->client=2;
+$prospectstatic->loadCacheOfProspStatus();
+
+
+$title=$langs->trans("ListOfThirdParties");
+if ($type == 'c' && (empty($search_type) || ($search_type == '1,3'))) $title=$langs->trans("ListOfCustomers");
+if ($type == 'p' && (empty($search_type) || ($search_type == '2,3'))) $title=$langs->trans("ListOfProspects");
+if ($type == 'f' && (empty($search_type) || ($search_type == '4'))) $title=$langs->trans("ListOfSuppliers");
+
+// If both parameters are set, search for everything BETWEEN them
+if ($search_level_from != '' && $search_level_to != '')
+{
+	// Ensure that these parameters are numbers
+	$search_level_from = (int) $search_level_from;
+	$search_level_to = (int) $search_level_to;
+
+	// If from is greater than to, reverse orders
+	if ($search_level_from > $search_level_to)
+	{
+		$tmp = $search_level_to;
+		$search_level_to = $search_level_from;
+		$search_level_from = $tmp;
+	}
+
+	// Generate the SQL request
+	$sortwhere = '(sortorder BETWEEN '.$search_level_from.' AND '.$search_level_to.') AS is_in_range';
+}
+// If only "from" parameter is set, search for everything GREATER THAN it
+else if ($search_level_from != '')
+{
+	// Ensure that this parameter is a number
+	$search_level_from = (int) $search_level_from;
+
+	// Generate the SQL request
+	$sortwhere = '(sortorder >= '.$search_level_from.') AS is_in_range';
+}
+// If only "to" parameter is set, search for everything LOWER THAN it
+else if ($search_level_to != '')
+{
+	// Ensure that this parameter is a number
+	$search_level_to = (int) $search_level_to;
+
+	// Generate the SQL request
+	$sortwhere = '(sortorder <= '.$search_level_to.') AS is_in_range';
+}
+// If no parameters are set, dont search for anything
+else
+{
+	$sortwhere = '0 as is_in_range';
+}
+
+// Select every potentiels, and note each potentiels which fit in search parameters
+dol_syslog('societe/list.php',LOG_DEBUG);
+$sql = "SELECT code, label, sortorder, ".$sortwhere;
+$sql.= " FROM ".MAIN_DB_PREFIX."c_prospectlevel";
+$sql.= " WHERE active > 0";
+$sql.= " ORDER BY sortorder";
+
+$resql = $db->query($sql);
+if ($resql)
+{
+	$tab_level = array();
+	$search_levels = array();
+
+	while ($obj = $db->fetch_object($resql))
+	{
+		// Compute level text
+		$level=$langs->trans($obj->code);
+		if ($level == $obj->code) $level=$langs->trans($obj->label);
+
+		// Put it in the array sorted by sortorder
+		$tab_level[$obj->sortorder] = $level;
+
+		// If this potentiel fit in parameters, add its code to the $search_levels array
+		if ($obj->is_in_range == 1)
+		{
+			$search_levels[] = '"'.preg_replace('[^A-Za-z0-9_-]', '', $obj->code).'"';
+		}
+	}
+
+	// Implode the $search_levels array so that it can be use in a "IN (...)" where clause.
+	// If no paramters was set, $search_levels will be empty
+	$search_levels = implode(',', $search_levels);
+}
+else dol_print_error($db);
+
+$sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.barcode, s.town, s.zip, s.datec, s.code_client, s.code_fournisseur, s.logo,";
+$sql.= " st.libelle as stcomm, s.fk_stcomm as stcomm_id, s.fk_prospectlevel, s.prefix_comm, s.client, s.fournisseur, s.canvas, s.status as status,";
+$sql.= " s.email, s.phone, s.url, s.siren as idprof1, s.siret as idprof2, s.ape as idprof3, s.idprof4 as idprof4, s.idprof5 as idprof5, s.idprof6 as idprof6, s.tva_intra, s.fk_pays,";
+$sql.= " s.tms as date_update, s.datec as date_creation,";
+$sql.= " s.code_compta,s.code_compta_fournisseur,";
+$sql.= " typent.code as typent_code,";
+$sql.= " state.code_departement as state_code, state.nom as state_name,";
+$sql.= " region.code_region as region_code, region.nom as region_name";
+// We'll need these fields in order to filter by sale (including the case where the user can only see his prospects)
+if ($search_sale) $sql .= ", sc.fk_soc, sc.fk_user";
+// We'll need these fields in order to filter by categ
+if ($search_categ_cus) $sql .= ", cc.fk_categorie, cc.fk_soc";
+if ($search_categ_sup) $sql .= ", cs.fk_categorie, cs.fk_soc";
+// Add fields from extrafields
+foreach ($extrafields->attribute_label as $key => $val) $sql.=($extrafields->attribute_type[$key] != 'separate' ? ",ef.".$key.' as options_'.$key : '');
+// Add fields from hooks
+$parameters=array();
+$reshook=$hookmanager->executeHooks('printFieldListSelect',$parameters);    // Note that $action and $object may have been modified by hook
+$sql.=$hookmanager->resPrint;
+$sql.= " FROM ".MAIN_DB_PREFIX."societe as s";
+if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_extrafields as ef on (s.rowid = ef.fk_object)";
+$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_country as country on (country.rowid = s.fk_pays)";
+$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_typent as typent on (typent.id = s.fk_typent)";
+$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_departements as state on (state.rowid = s.fk_departement)";
+$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_regions as region on (region.	code_region = state.fk_region)";
+// We'll need this table joined to the select in order to filter by categ
+if (! empty($search_categ_cus)) $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX."categorie_societe as cc ON s.rowid = cc.fk_soc"; // We'll need this table joined to the select in order to filter by categ
+if (! empty($search_categ_sup)) $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX."categorie_fournisseur as cs ON s.rowid = cs.fk_soc"; // We'll need this table joined to the select in order to filter by categ
+$sql.= " ,".MAIN_DB_PREFIX."c_stcomm as st";
+// We'll need this table joined to the select in order to filter by sale
+if ($search_sale || (!$user->rights->societe->client->voir && !$socid)) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
+$sql.= " WHERE s.fk_stcomm = st.id";
+$sql.= " AND s.entity IN (".getEntity('societe').")";
+if (! $user->rights->societe->client->voir && ! $socid)	$sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id;
+if ($socid)                $sql.= " AND s.rowid = ".$socid;
+if ($search_sale)          $sql.= " AND s.rowid = sc.fk_soc";        // Join for the needed table to filter by sale
+if (! $user->rights->fournisseur->lire) $sql.=" AND (s.fournisseur <> 1 OR s.client <> 0)";    // client=0, fournisseur=0 must be visible
+if ($search_sale)          $sql.= " AND sc.fk_user = ".$db->escape($search_sale);
+if ($search_categ_cus > 0) $sql.= " AND cc.fk_categorie = ".$db->escape($search_categ_cus);
+if ($search_categ_sup > 0) $sql.= " AND cs.fk_categorie = ".$db->escape($search_categ_sup);
+if ($search_categ_cus == -2)   $sql.= " AND cc.fk_categorie IS NULL";
+if ($search_categ_sup == -2)   $sql.= " AND cs.fk_categorie IS NULL";
+
+if ($search_all)           $sql.= natural_search(array_keys($fieldstosearchall), $search_all);
+if (strlen($search_cti))   $sql.= natural_search('s.phone', $search_cti);
+
+if ($search_id > 0)        $sql.= natural_search("s.rowid",$search_id,1);
+if ($search_nom)           $sql.= natural_search("s.nom",$search_nom);
+if ($search_alias)         $sql.= natural_search("s.name_alias",$search_alias);
+if ($search_nom_only)      $sql.= natural_search("s.nom",$search_nom_only);
+if ($search_customer_code) $sql.= natural_search("s.code_client",$search_customer_code);
+if ($search_supplier_code) $sql.= natural_search("s.code_fournisseur",$search_supplier_code);
+if ($search_account_customer_code) $sql.= natural_search("s.code_compta",$search_account_customer_code);
+if ($search_account_supplier_code) $sql.= natural_search("s.code_compta_fournisseur",$search_account_supplier_code);
+if ($search_town)          $sql.= natural_search("s.town",$search_town);
+if (strlen($search_zip))   $sql.= natural_search("s.zip",$search_zip);
+if ($search_state)         $sql.= natural_search("state.nom",$search_state);
+if ($search_region)         $sql.= natural_search("region.nom",$search_region);
+if ($search_country)       $sql .= " AND s.fk_pays IN (".$search_country.')';
+if ($search_email)         $sql.= natural_search("s.email",$search_email);
+if (strlen($search_phone)) $sql.= natural_search("s.phone", $search_phone);
+if ($search_url)           $sql.= natural_search("s.url",$search_url);
+if (strlen($search_idprof1)) $sql.= natural_search("s.siren",$search_idprof1);
+if (strlen($search_idprof2)) $sql.= natural_search("s.siret",$search_idprof2);
+if (strlen($search_idprof3)) $sql.= natural_search("s.ape",$search_idprof3);
+if (strlen($search_idprof4)) $sql.= natural_search("s.idprof4",$search_idprof4);
+if (strlen($search_idprof5)) $sql.= natural_search("s.idprof5",$search_idprof5);
+if (strlen($search_idprof6)) $sql.= natural_search("s.idprof6",$search_idprof6);
+if (strlen($search_vat))     $sql.= natural_search("s.tva_intra",$search_vat);
+// Filter on type of thirdparty
+if ($search_type > 0 && in_array($search_type,array('1,3','2,3'))) $sql .= " AND s.client IN (".$db->escape($search_type).")";
+if ($search_type > 0 && in_array($search_type,array('4')))         $sql .= " AND s.fournisseur = 1";
+if ($search_type == '0') $sql .= " AND s.client = 0 AND s.fournisseur = 0";
+if ($search_status!='' && $search_status >= 0) $sql .= " AND s.status = ".$db->escape($search_status);
+if (!empty($conf->barcode->enabled) && $search_barcode) $sql.= natural_search("s.barcode", $search_barcode);
+if ($search_type_thirdparty) $sql .= " AND s.fk_typent IN (".$search_type_thirdparty.')';
+if ($search_levels)  $sql .= " AND s.fk_prospectlevel IN (".$search_levels.')';
+if ($search_stcomm != '' && $search_stcomm != -2) $sql.= natural_search("s.fk_stcomm",$search_stcomm,2);
+if ($search_import_key)    $sql.= natural_search("s.import_key",$search_import_key);
+// Add where from extra fields
+include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
+
+// Add where from hooks
+$parameters=array();
+$reshook=$hookmanager->executeHooks('printFieldListWhere',$parameters);    // Note that $action and $object may have been modified by hook
+$sql.=$hookmanager->resPrint;
+
+$sql.= $db->order($sortfield,$sortorder);
+
+// Count total nb of records
+$nbtotalofrecords = '';
+if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST))
+{
+	$result = $db->query($sql);
+	$nbtotalofrecords = $db->num_rows($result);
+}
+
+$sql.= $db->plimit($limit+1, $offset);
+
+$resql = $db->query($sql);
+if (! $resql)
+{
+	dol_print_error($db);
+	exit;
+}
+
+$num = $db->num_rows($resql);
+
+$arrayofselected=is_array($toselect)?$toselect:array();
+
+if ($num == 1 && ! empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && ($search_all != '' || $search_cti != '') && $action != 'list')
+{
+	$obj = $db->fetch_object($resql);
+	$id = $obj->rowid;
+	header("Location: ".DOL_URL_ROOT.'/societe/card.php?socid='.$id);
+	exit;
+}
+
+$help_url='EN:Module_Third_Parties|FR:Module_Tiers|ES:Empresas';
+llxHeader('',$langs->trans("ThirdParty"),$help_url);
+
+$param='';
+if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.$contextpage;
+if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit;
+if ($search_all != '')     $param = "&sall=".urlencode($search_all);
+if ($sall != '')           $param .= "&sall=".urlencode($sall);
+if ($search_categ_cus > 0) $param.='&search_categ_cus='.urlencode($search_categ_cus);
+if ($search_categ_sup > 0) $param.='&search_categ_sup='.urlencode($search_categ_sup);
+if ($search_sale > 0)	   $param.='&search_sale='.urlencode($search_sale);
+if ($search_id > 0)        $param.= "&search_id=".urlencode($search_id);
+if ($search_nom != '')     $param.= "&search_nom=".urlencode($search_nom);
+if ($search_alias != '')   $param.= "&search_alias=".urlencode($search_alias);
+if ($search_town != '')    $param.= "&search_town=".urlencode($search_town);
+if ($search_zip != '')     $param.= "&search_zip=".urlencode($search_zip);
+if ($search_phone != '')   $param.= "&search_phone=".urlencode($search_phone);
+if ($search_email != '')   $param.= "&search_email=".urlencode($search_email);
+if ($search_url != '')     $param.= "&search_url=".urlencode($search_url);
+if ($search_state != '')   $param.= "&search_state=".urlencode($search_state);
+if ($search_country != '') $param.= "&search_country=".urlencode($search_country);
+if ($search_customer_code != '') $param.= "&search_customer_code=".urlencode($search_customer_code);
+if ($search_supplier_code != '') $param.= "&search_supplier_code=".urlencode($search_supplier_code);
+if ($search_account_customer_code != '') $param.= "&search_account_customer_code=".urlencode($search_account_customer_code);
+if ($search_account_supplier_code != '') $param.= "&search_account_supplier_code=".urlencode($search_account_supplier_code);
+if ($search_barcode != '') $param.= "&search_barcode=".urlencode($search_barcode);
+if ($search_idprof1 != '') $param.= '&search_idprof1='.urlencode($search_idprof1);
+if ($search_idprof2 != '') $param.= '&search_idprof2='.urlencode($search_idprof2);
+if ($search_idprof3 != '') $param.= '&search_idprof3='.urlencode($search_idprof3);
+if ($search_idprof4 != '') $param.= '&search_idprof4='.urlencode($search_idprof4);
+if ($search_idprof5 != '') $param.= '&search_idprof5='.urlencode($search_idprof5);
+if ($search_idprof6 != '') $param.= '&search_idprof6='.urlencode($search_idprof6);
+if ($search_vat != '')     $param.= '&search_vat='.urlencode($search_vat);
+if ($search_type_thirdparty != '')    $param.='&search_type_thirdparty='.urlencode($search_type_thirdparty);
+if ($search_type != '')    $param.='&search_type='.urlencode($search_type);
+if ($optioncss != '')      $param.='&optioncss='.urlencode($optioncss);
+if ($search_status != '')  $param.='&search_status='.urlencode($search_status);
+if ($search_stcomm != '')  $param.='&search_stcomm='.urlencode($search_stcomm);
+if ($search_level_from != '') $param.='&search_level_from='.urlencode($search_level_from);
+if ($search_level_to != '')   $param.='&search_level_to='.urlencode($search_level_to);
+if ($search_import_key != '') $param.='&search_import_key='.urlencode($search_import_key);
+if ($type != '') $param.='&type='.urlencode($type);
+// Add $param from extra fields
+include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
+
+// Show delete result message
+if (GETPOST('delsoc'))
+{
+	setEventMessages($langs->trans("CompanyDeleted",GETPOST('delsoc')), null, 'mesgs');
+}
+
+// List of mass actions available
+$arrayofmassactions =  array(
+	'presend'=>$langs->trans("SendByMail"),
+//    'builddoc'=>$langs->trans("PDFMerge"),
+);
+//if($user->rights->societe->creer) $arrayofmassactions['createbills']=$langs->trans("CreateInvoiceForThisCustomer");
+if ($user->rights->societe->supprimer) $arrayofmassactions['predelete']=$langs->trans("Delete");
+if (GETPOST('nomassaction','int') || in_array($massaction, array('presend','predelete'))) $arrayofmassactions=array();
+$massactionbutton=$form->selectMassAction('', $arrayofmassactions);
+
+print '<form method="post" action="'.$_SERVER["PHP_SELF"].'" name="formfilter">';
+if ($optioncss != '') print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
+print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
+print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">';
+print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
+print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
+print '<input type="hidden" name="page" value="'.$page.'">';
+
+print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_companies', 0, '', '', $limit);
+
+$langs->load("other");
+$textprofid=array();
+foreach(array(1,2,3,4,5,6) as $key)
+{
+	$label=$langs->transnoentities("ProfId".$key.$mysoc->country_code);
+	$textprofid[$key]='';
+	if ($label != "ProfId".$key.$mysoc->country_code)
+	{	// Get only text between ()
+		if (preg_match('/\((.*)\)/i',$label,$reg)) $label=$reg[1];
+		$textprofid[$key]=$langs->trans("ProfIdShortDesc",$key,$mysoc->country_code,$label);
+	}
+}
+
+$topicmail="Information";
+$modelmail="thirdparty";
+$objecttmp=new Societe($db);
+$trackid='thi'.$object->id;
+include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php';
+
+if ($search_all)
+{
+	foreach($fieldstosearchall as $key => $val) $fieldstosearchall[$key]=$langs->trans($val);
+	print $langs->trans("FilterOnInto", $search_all) . join(', ',$fieldstosearchall);
+}
+
+// Filter on categories
+$moreforfilter='';
+if (empty($type) || $type == 'c' || $type == 'p')
+{
+	if (! empty($conf->categorie->enabled))
+	{
+		require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
+		$moreforfilter.='<div class="divsearchfield">';
+	 	$moreforfilter.=$langs->trans('CustomersProspectsCategoriesShort').': ';
+		$moreforfilter.=$formother->select_categories('customer', $search_categ_cus, 'search_categ_cus', 1, $langs->trans('CustomersProspectsCategoriesShort'));
+	 	$moreforfilter.='</div>';
+	}
+}
+if (empty($type) || $type == 'f')
+{
+	if (! empty($conf->categorie->enabled))
+	{
+		require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
+		$moreforfilter.='<div class="divsearchfield">';
+		$moreforfilter.=$langs->trans('SuppliersCategoriesShort').': ';
+		$moreforfilter.=$formother->select_categories('supplier',$search_categ_sup,'search_categ_sup',1);
+		$moreforfilter.='</div>';
+	}
+}
+
+// If the user can view prospects other than his'
+if ($user->rights->societe->client->voir || $socid)
+{
+ 	$moreforfilter.='<div class="divsearchfield">';
+ 	$moreforfilter.=$langs->trans('SalesRepresentatives'). ': ';
+	$moreforfilter.=$formother->select_salesrepresentatives($search_sale,'search_sale',$user, 0, 1, 'maxwidth300');
+	$moreforfilter.='</div>';
+}
+if ($moreforfilter)
+{
+	print '<div class="liste_titre liste_titre_bydiv centpercent">';
+	print $moreforfilter;
+	$parameters=array('type'=>$type);
+	$reshook=$hookmanager->executeHooks('printFieldPreListTitle',$parameters);    // Note that $action and $object may have been modified by hook
+	print $hookmanager->resPrint;
+	print '</div>';
+}
+
+$varpage=empty($contextpage)?$_SERVER["PHP_SELF"]:$contextpage;
+$selectedfields=$form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage);	// This also change content of $arrayfields
+if ($massactionbutton) $selectedfields.=$form->showCheckAddButtons('checkforselect', 1);
+
+if (empty($arrayfields['customerorsupplier']['checked'])) print '<input type="hidden" name="type" value="'.$type.'">';
+
+print '<div class="div-table-responsive">';
+print '<table class="tagtable liste'.($moreforfilter?" listwithfilterbefore":"").'">'."\n";
+
+// Fields title search
+print '<tr class="liste_titre_filter">';
+if (! empty($arrayfields['s.rowid']['checked']))
+{
+	print '<td class="liste_titre">';
+	print '<input class="flat searchstring" type="text" name="search_id" size="1" value="'.dol_escape_htmltag($search_id).'">';
+	print '</td>';
+}
+if (! empty($arrayfields['s.nom']['checked']))
+{
+	print '<td class="liste_titre">';
+	if (! empty($search_nom_only) && empty($search_nom)) $search_nom=$search_nom_only;
+	print '<input class="flat searchstring" type="text" name="search_nom" size="8" value="'.dol_escape_htmltag($search_nom).'">';
+	print '</td>';
+}
+if (! empty($arrayfields['s.name_alias']['checked']))
+{
+	print '<td class="liste_titre">';
+	print '<input class="flat searchstring" type="text" name="search_alias" size="8" value="'.dol_escape_htmltag($search_alias).'">';
+	print '</td>';
+}
+// Barcode
+if (! empty($arrayfields['s.barcode']['checked']))
+{
+	print '<td class="liste_titre">';
+	print '<input class="flat searchstring" type="text" name="search_barcode" size="6" value="'.dol_escape_htmltag($search_barcode).'">';
+	print '</td>';
+}
+// Customer code
+if (! empty($arrayfields['s.code_client']['checked']))
+{
+	print '<td class="liste_titre">';
+	print '<input class="flat searchstring" size="8" type="text" name="search_customer_code" value="'.dol_escape_htmltag($search_customer_code).'">';
+	print '</td>';
+}
+// Supplier code
+if (! empty($arrayfields['s.code_fournisseur']['checked']))
+{
+	print '<td class="liste_titre">';
+	print '<input class="flat searchstring" size="8" type="text" name="search_supplier_code" value="'.dol_escape_htmltag($search_supplier_code).'">';
+	print '</td>';
+}
+// Account Customer code
+if (! empty($arrayfields['s.code_compta']['checked']))
+{
+	print '<td class="liste_titre">';
+	print '<input class="flat searchstring" size="8" type="text" name="search_account_customer_code" value="'.dol_escape_htmltag($search_account_customer_code).'">';
+	print '</td>';
+}
+// Account Supplier code
+if (! empty($arrayfields['s.code_compta_fournisseur']['checked']))
+{
+	print '<td class="liste_titre">';
+	print '<input class="flat" size="8" type="text" name="search_account_supplier_code" value="'.dol_escape_htmltag($search_account_supplier_code).'">';
+	print '</td>';
+}
+// Town
+if (! empty($arrayfields['s.town']['checked']))
+{
+	print '<td class="liste_titre">';
+	print '<input class="flat searchstring" size="6" type="text" name="search_town" value="'.dol_escape_htmltag($search_town).'">';
+	print '</td>';
+}
+// Zip
+if (! empty($arrayfields['s.zip']['checked']))
+{
+	print '<td class="liste_titre">';
+	print '<input class="flat searchstring" size="4" type="text" name="search_zip" value="'.dol_escape_htmltag($search_zip).'">';
+	print '</td>';
+}
+// State
+if (! empty($arrayfields['state.nom']['checked']))
+{
+	print '<td class="liste_titre">';
+	print '<input class="flat searchstring" size="4" type="text" name="search_state" value="'.dol_escape_htmltag($search_state).'">';
+	print '</td>';
+}
+// Region
+if (! empty($arrayfields['region.nom']['checked']))
+{
+	print '<td class="liste_titre">';
+	print '<input class="flat searchstring" size="4" type="text" name="search_region" value="'.dol_escape_htmltag($search_region).'">';
+	print '</td>';
+}
+// Country
+if (! empty($arrayfields['country.code_iso']['checked']))
+{
+	print '<td class="liste_titre" align="center">';
+	print $form->select_country($search_country,'search_country','',0,'maxwidth100');
+	print '</td>';
+}
+// Company type
+if (! empty($arrayfields['typent.code']['checked']))
+{
+	print '<td class="liste_titre maxwidthonsmartphone" align="center">';
+	print $form->selectarray("search_type_thirdparty", $formcompany->typent_array(0), $search_type_thirdparty, 0, 0, 0, '', 0, 0, 0, (empty($conf->global->SOCIETE_SORT_ON_TYPEENT)?'ASC':$conf->global->SOCIETE_SORT_ON_TYPEENT));
+	print '</td>';
+}
+if (! empty($arrayfields['s.email']['checked']))
+{
+	// Email
+	print '<td class="liste_titre">';
+	print '<input class="flat searchemail" size="4" type="text" name="search_email" value="'.dol_escape_htmltag($search_email).'">';
+	print '</td>';
+}
+if (! empty($arrayfields['s.phone']['checked']))
+{
+	// Phone
+	print '<td class="liste_titre">';
+	print '<input class="flat searchstring" size="4" type="text" name="search_phone" value="'.dol_escape_htmltag($search_phone).'">';
+	print '</td>';
+}
+if (! empty($arrayfields['s.url']['checked']))
+{
+	// Url
+	print '<td class="liste_titre">';
+	print '<input class="flat searchstring" size="4" type="text" name="search_url" value="'.dol_escape_htmltag($search_url).'">';
+	print '</td>';
+}
+if (! empty($arrayfields['s.siren']['checked']))
+{
+	// IdProf1
+	print '<td class="liste_titre">';
+	print '<input class="flat searchstring" size="4" type="text" name="search_idprof1" value="'.dol_escape_htmltag($search_idprof1).'">';
+	print '</td>';
+}
+if (! empty($arrayfields['s.siret']['checked']))
+{
+	// IdProf2
+	print '<td class="liste_titre">';
+	print '<input class="flat searchstring" size="4" type="text" name="search_idprof2" value="'.dol_escape_htmltag($search_idprof2).'">';
+	print '</td>';
+}
+if (! empty($arrayfields['s.ape']['checked']))
+{
+	// IdProf3
+	print '<td class="liste_titre">';
+	print '<input class="flat searchstring" size="4" type="text" name="search_idprof3" value="'.dol_escape_htmltag($search_idprof3).'">';
+	print '</td>';
+}
+if (! empty($arrayfields['s.idprof4']['checked']))
+{
+	// IdProf4
+	print '<td class="liste_titre">';
+	print '<input class="flat searchstring" size="4" type="text" name="search_idprof4" value="'.dol_escape_htmltag($search_idprof4).'">';
+	print '</td>';
+}
+if (! empty($arrayfields['s.idprof5']['checked']))
+{
+	// IdProf5
+	print '<td class="liste_titre">';
+	print '<input class="flat searchstring" size="4" type="text" name="search_idprof5" value="'.dol_escape_htmltag($search_idprof5).'">';
+	print '</td>';
+}
+if (! empty($arrayfields['s.idprof6']['checked']))
+{
+	// IdProf6
+	print '<td class="liste_titre">';
+	print '<input class="flat searchstring" size="4" type="text" name="search_idprof6" value="'.dol_escape_htmltag($search_idprof6).'">';
+	print '</td>';
+}
+if (! empty($arrayfields['s.tva_intra']['checked']))
+{
+	// Vat number
+	print '<td class="liste_titre">';
+	print '<input class="flat searchstring" size="4" type="text" name="search_vat" value="'.dol_escape_htmltag($search_vat).'">';
+	print '</td>';
+}
+
+// Type (customer/prospect/supplier)
+if (! empty($arrayfields['customerorsupplier']['checked']))
+{
+	print '<td class="liste_titre maxwidthonsmartphone" align="middle">';
+	if ($type != '') print '<input type="hidden" name="type" value="'.$type.'">';
+	print '<select class="flat" name="search_type">';
+	print '<option value="-1"'.($search_type==''?' selected':'').'>&nbsp;</option>';
+	if (empty($conf->global->SOCIETE_DISABLE_CUSTOMERS)) print '<option value="1,3"'.($search_type=='1,3'?' selected':'').'>'.$langs->trans('Customer').'</option>';
+	if (empty($conf->global->SOCIETE_DISABLE_PROSPECTS)) print '<option value="2,3"'.($search_type=='2,3'?' selected':'').'>'.$langs->trans('Prospect').'</option>';
+	//if (empty($conf->global->SOCIETE_DISABLE_PROSPECTS)) print '<option value="3"'.($search_type=='3'?' selected':'').'>'.$langs->trans('ProspectCustomer').'</option>';
+	print '<option value="4"'.($search_type=='4'?' selected':'').'>'.$langs->trans('Supplier').'</option>';
+	print '<option value="0"'.($search_type=='0'?' selected':'').'>'.$langs->trans('Others').'</option>';
+	print '</select></td>';
+}
+if (! empty($arrayfields['s.fk_prospectlevel']['checked']))
+{
+	// Prospect level
+ 	print '<td class="liste_titre" align="center">';
+ 	$options_from = '<option value="">&nbsp;</option>';	 	// Generate in $options_from the list of each option sorted
+ 	foreach ($tab_level as $tab_level_sortorder => $tab_level_label)
+ 	{
+ 		$options_from .= '<option value="'.$tab_level_sortorder.'"'.($search_level_from == $tab_level_sortorder ? ' selected':'').'>';
+ 		$options_from .= $langs->trans($tab_level_label);
+ 		$options_from .= '</option>';
+ 	}
+ 	array_reverse($tab_level, true);	// Reverse the list
+ 	$options_to = '<option value="">&nbsp;</option>';		// Generate in $options_to the list of each option sorted in the reversed order
+ 	foreach ($tab_level as $tab_level_sortorder => $tab_level_label)
+ 	{
+ 		$options_to .= '<option value="'.$tab_level_sortorder.'"'.($search_level_to == $tab_level_sortorder ? ' selected':'').'>';
+ 		$options_to .= $langs->trans($tab_level_label);
+ 		$options_to .= '</option>';
+ 	}
+
+	// Print these two select
+ 	print $langs->trans("From").' <select class="flat" name="search_level_from">'.$options_from.'</select>';
+ 	print ' ';
+ 	print $langs->trans("to").' <select class="flat" name="search_level_to">'.$options_to.'</select>';
+
+	print '</td>';
+}
+
+if (! empty($arrayfields['s.fk_stcomm']['checked']))
+{
+	// Prospect status
+	print '<td class="liste_titre maxwidthonsmartphone" align="center">';
+	$arraystcomm=array();
+	foreach($prospectstatic->cacheprospectstatus as $key => $val)
+	{
+		$arraystcomm[$val['id']]=($langs->trans("StatusProspect".$val['id']) != "StatusProspect".$val['id'] ? $langs->trans("StatusProspect".$val['id']) : $val['label']);
+	}
+	print $form->selectarray('search_stcomm', $arraystcomm, $search_stcomm, -2);
+	print '</td>';
+}
+// Extra fields
+include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php';
+
+// Fields from hook
+$parameters=array('arrayfields'=>$arrayfields);
+$reshook=$hookmanager->executeHooks('printFieldListOption',$parameters);    // Note that $action and $object may have been modified by hook
+print $hookmanager->resPrint;
+// Date creation
+if (! empty($arrayfields['s.datec']['checked']))
+{
+	print '<td class="liste_titre">';
+	print '</td>';
+}
+// Date modification
+if (! empty($arrayfields['s.tms']['checked']))
+{
+	print '<td class="liste_titre">';
+	print '</td>';
+}
+// Status
+if (! empty($arrayfields['s.status']['checked']))
+{
+	print '<td class="liste_titre maxwidthonsmartphone center">';
+	print $form->selectarray('search_status', array('0'=>$langs->trans('ActivityCeased'),'1'=>$langs->trans('InActivity')), $search_status, 1);
+	print '</td>';
+}
+if (! empty($arrayfields['s.import_key']['checked']))
+{
+	print '<td class="liste_titre center">';
+	print '<input class="flat searchstring" type="text" name="search_import_key" size="3" value="'.dol_escape_htmltag($search_import_key).'">';
+	print '</td>';
+}
+// Action column
+print '<td class="liste_titre" align="right">';
+$searchpicto=$form->showFilterButtons();
+print $searchpicto;
+print '</td>';
+
+print "</tr>\n";
+
+print '<tr class="liste_titre">';
+if (! empty($arrayfields['s.rowid']['checked']))                   print_liste_field_titre($arrayfields['s.rowid']['label'], $_SERVER["PHP_SELF"],"s.rowid","",$param,"",$sortfield,$sortorder);
+if (! empty($arrayfields['s.nom']['checked']))                     print_liste_field_titre($arrayfields['s.nom']['label'], $_SERVER["PHP_SELF"],"s.nom","",$param,"",$sortfield,$sortorder);
+if (! empty($arrayfields['s.name_alias']['checked']))              print_liste_field_titre($arrayfields['s.name_alias']['label'], $_SERVER["PHP_SELF"],"s.name_alias","",$param,"",$sortfield,$sortorder);
+if (! empty($arrayfields['s.barcode']['checked']))                 print_liste_field_titre($arrayfields['s.barcode']['label'], $_SERVER["PHP_SELF"], "s.barcode",$param,'','',$sortfield,$sortorder);
+if (! empty($arrayfields['s.code_client']['checked']))             print_liste_field_titre($arrayfields['s.code_client']['label'],$_SERVER["PHP_SELF"],"s.code_client","",$param,'',$sortfield,$sortorder);
+if (! empty($arrayfields['s.code_fournisseur']['checked']))        print_liste_field_titre($arrayfields['s.code_fournisseur']['label'],$_SERVER["PHP_SELF"],"s.code_fournisseur","",$param,'',$sortfield,$sortorder);
+if (! empty($arrayfields['s.code_compta']['checked']))             print_liste_field_titre($arrayfields['s.code_compta']['label'],$_SERVER["PHP_SELF"],"s.code_compta","",$param,'',$sortfield,$sortorder);
+if (! empty($arrayfields['s.code_compta_fournisseur']['checked'])) print_liste_field_titre($arrayfields['s.code_compta_fournisseur']['label'],$_SERVER["PHP_SELF"],"s.code_compta_fournisseur","",$param,'',$sortfield,$sortorder);
+if (! empty($arrayfields['s.town']['checked']))           print_liste_field_titre($arrayfields['s.town']['label'],$_SERVER["PHP_SELF"],"s.town","",$param,'',$sortfield,$sortorder);
+if (! empty($arrayfields['s.zip']['checked']))            print_liste_field_titre($arrayfields['s.zip']['label'],$_SERVER["PHP_SELF"],"s.zip","",$param,'',$sortfield,$sortorder);
+if (! empty($arrayfields['state.nom']['checked']))        print_liste_field_titre($arrayfields['state.nom']['label'],$_SERVER["PHP_SELF"],"state.nom","",$param,'',$sortfield,$sortorder);
+if (! empty($arrayfields['region.nom']['checked']))       print_liste_field_titre($arrayfields['region.nom']['label'],$_SERVER["PHP_SELF"],"region.nom","",$param,'',$sortfield,$sortorder);
+if (! empty($arrayfields['country.code_iso']['checked'])) print_liste_field_titre($arrayfields['country.code_iso']['label'],$_SERVER["PHP_SELF"],"country.code_iso","",$param,'align="center"',$sortfield,$sortorder);
+if (! empty($arrayfields['typent.code']['checked']))      print_liste_field_titre($arrayfields['typent.code']['label'],$_SERVER["PHP_SELF"],"typent.code","",$param,'align="center"',$sortfield,$sortorder);
+if (! empty($arrayfields['s.email']['checked']))          print_liste_field_titre($arrayfields['s.email']['label'],$_SERVER["PHP_SELF"],"s.email","",$param,'',$sortfield,$sortorder);
+if (! empty($arrayfields['s.phone']['checked']))          print_liste_field_titre($arrayfields['s.phone']['label'],$_SERVER["PHP_SELF"],"s.phone","",$param,'',$sortfield,$sortorder);
+if (! empty($arrayfields['s.url']['checked']))            print_liste_field_titre($arrayfields['s.url']['label'],$_SERVER["PHP_SELF"],"s.url","",$param,'',$sortfield,$sortorder);
+if (! empty($arrayfields['s.siren']['checked']))          print_liste_field_titre($form->textwithpicto($langs->trans("ProfId1Short"),$textprofid[1],1,0),$_SERVER["PHP_SELF"],"s.siren","",$param,'class="nowrap"',$sortfield,$sortorder);
+if (! empty($arrayfields['s.siret']['checked']))          print_liste_field_titre($form->textwithpicto($langs->trans("ProfId2Short"),$textprofid[2],1,0),$_SERVER["PHP_SELF"],"s.siret","",$param,'class="nowrap"',$sortfield,$sortorder);
+if (! empty($arrayfields['s.ape']['checked']))            print_liste_field_titre($form->textwithpicto($langs->trans("ProfId3Short"),$textprofid[3],1,0),$_SERVER["PHP_SELF"],"s.ape","",$param,'class="nowrap"',$sortfield,$sortorder);
+if (! empty($arrayfields['s.idprof4']['checked']))        print_liste_field_titre($form->textwithpicto($langs->trans("ProfId4Short"),$textprofid[4],1,0),$_SERVER["PHP_SELF"],"s.idprof4","",$param,'class="nowrap"',$sortfield,$sortorder);
+if (! empty($arrayfields['s.idprof5']['checked']))        print_liste_field_titre($form->textwithpicto($langs->trans("ProfId5Short"),$textprofid[4],1,0),$_SERVER["PHP_SELF"],"s.idprof5","",$param,'class="nowrap"',$sortfield,$sortorder);
+if (! empty($arrayfields['s.idprof6']['checked']))        print_liste_field_titre($form->textwithpicto($langs->trans("ProfId6Short"),$textprofid[4],1,0),$_SERVER["PHP_SELF"],"s.idprof6","",$param,'class="nowrap"',$sortfield,$sortorder);
+if (! empty($arrayfields['s.tva_intra']['checked']))      print_liste_field_titre($arrayfields['s.tva_intra']['label'],$_SERVER["PHP_SELF"],"s.tva_intra","",$param,'class="nowrap"',$sortfield,$sortorder);
+if (! empty($arrayfields['customerorsupplier']['checked']))        print_liste_field_titre('');   // type of customer
+if (! empty($arrayfields['s.fk_prospectlevel']['checked']))        print_liste_field_titre($arrayfields['s.fk_prospectlevel']['label'],$_SERVER["PHP_SELF"],"s.fk_prospectlevel","",$param,'align="center"',$sortfield,$sortorder);
+if (! empty($arrayfields['s.fk_stcomm']['checked']))               print_liste_field_titre($arrayfields['s.fk_stcomm']['label'],$_SERVER["PHP_SELF"],"s.fk_stcomm","",$param,'align="center"',$sortfield,$sortorder);
+// Extra fields
+include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
+// Hook fields
+$parameters=array('arrayfields'=>$arrayfields,'param'=>$param,'sortfield'=>$sortfield,'sortorder'=>$sortorder);
+$reshook=$hookmanager->executeHooks('printFieldListTitle',$parameters);    // Note that $action and $object may have been modified by hook
+print $hookmanager->resPrint;
+if (! empty($arrayfields['s.datec']['checked']))      print_liste_field_titre($arrayfields['s.datec']['label'],$_SERVER["PHP_SELF"],"s.datec","",$param,'align="center" class="nowrap"',$sortfield,$sortorder);
+if (! empty($arrayfields['s.tms']['checked']))        print_liste_field_titre($arrayfields['s.tms']['label'],$_SERVER["PHP_SELF"],"s.tms","",$param,'align="center" class="nowrap"',$sortfield,$sortorder);
+if (! empty($arrayfields['s.status']['checked']))     print_liste_field_titre($arrayfields['s.status']['label'],$_SERVER["PHP_SELF"],"s.status","",$param,'align="center"',$sortfield,$sortorder);
+if (! empty($arrayfields['s.import_key']['checked'])) print_liste_field_titre($arrayfields['s.import_key']['label'],$_SERVER["PHP_SELF"],"s.import_key","",$param,'align="center"',$sortfield,$sortorder);
+print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"],"",'','','align="center"',$sortfield,$sortorder,'maxwidthsearch ');
+print "</tr>\n";
+
+
+$i = 0;
+$totalarray=array();
+while ($i < min($num, $limit))
+{
+	$obj = $db->fetch_object($resql);
+
+	$companystatic->id=$obj->rowid;
+	$companystatic->name=$obj->name;
+	$companystatic->name_alias=$obj->name_alias;
+	$companystatic->logo=$obj->logo;
+	$companystatic->canvas=$obj->canvas;
+	$companystatic->client=$obj->client;
+	$companystatic->status=$obj->status;
+	$companystatic->email=$obj->email;
+	$companystatic->fournisseur=$obj->fournisseur;
+	$companystatic->code_client=$obj->code_client;
+	$companystatic->code_fournisseur=$obj->code_fournisseur;
+
+	$companystatic->code_compta_client=$obj->code_compta;
+	$companystatic->code_compta_fournisseur=$obj->code_compta_fournisseur;
+
+   	$companystatic->fk_prospectlevel=$obj->fk_prospectlevel;
+
+	print '<tr class="oddeven" onclick="location.href=\'customers.php?action=change&idcustomer='.$obj->rowid.'&place='.$place.'\'">';
+	if (! empty($arrayfields['s.rowid']['checked']))
+	{
+		print '<td class="tdoverflowmax50">';
+		print $obj->rowid;
+		print "</td>\n";
+		if (! $i) $totalarray['nbfield']++;
+	}
+	if (! empty($arrayfields['s.nom']['checked']))
+	{
+		$savalias = $obj->name_alias;
+		if (! empty($arrayfields['s.name_alias']['checked'])) $companystatic->name_alias='';
+		print '<td class="tdoverflowmax200">';
+		print $obj->name;
+		print "</td>\n";
+        if (! $i) $totalarray['nbfield']++;
+	}
+	if (! empty($arrayfields['s.name_alias']['checked']))
+	{
+		print '<td class="tdoverflowmax200">';
+		print $companystatic->name_alias;
+		print "</td>\n";
+		if (! $i) $totalarray['nbfield']++;
+	}
+	// Barcode
+	if (! empty($arrayfields['s.barcode']['checked']))
+	{
+		print '<td>'.$obj->barcode.'</td>';
+		if (! $i) $totalarray['nbfield']++;
+	}
+	// Customer code
+	if (! empty($arrayfields['s.code_client']['checked']))
+	{
+		print '<td>'.$obj->code_client.'</td>';
+		if (! $i) $totalarray['nbfield']++;
+	}
+	// Supplier code
+	if (! empty($arrayfields['s.code_fournisseur']['checked']))
+	{
+		print '<td>'.$obj->code_fournisseur.'</td>';
+		if (! $i) $totalarray['nbfield']++;
+	}
+	// Account customer code
+	if (! empty($arrayfields['s.code_compta']['checked']))
+	{
+		print '<td>'.$obj->code_compta.'</td>';
+		if (! $i) $totalarray['nbfield']++;
+	}
+	// Account supplier code
+	if (! empty($arrayfields['s.code_compta_fournisseur']['checked']))
+	{
+		print '<td>'.$obj->code_compta_fournisseur.'</td>';
+		if (! $i) $totalarray['nbfield']++;
+	}
+	// Town
+	if (! empty($arrayfields['s.town']['checked']))
+	{
+		print "<td>".$obj->town."</td>\n";
+		if (! $i) $totalarray['nbfield']++;
+	}
+	// Zip
+	if (! empty($arrayfields['s.zip']['checked']))
+	{
+		print "<td>".$obj->zip."</td>\n";
+		if (! $i) $totalarray['nbfield']++;
+	}
+	// State
+	if (! empty($arrayfields['state.nom']['checked']))
+	{
+		print "<td>".$obj->state_name."</td>\n";
+		if (! $i) $totalarray['nbfield']++;
+	}
+	// Region
+	if (! empty($arrayfields['region.nom']['checked']))
+	{
+		print "<td>".$obj->region_name."</td>\n";
+		if (! $i) $totalarray['nbfield']++;
+	}
+	// Country
+	if (! empty($arrayfields['country.code_iso']['checked']))
+	{
+		print '<td align="center">';
+		$tmparray=getCountry($obj->fk_pays,'all');
+		print $tmparray['label'];
+		print '</td>';
+		if (! $i) $totalarray['nbfield']++;
+	}
+	// Type ent
+	if (! empty($arrayfields['typent.code']['checked']))
+	{
+		print '<td align="center">';
+		if (! is_array($typenArray) || count($typenArray)==0) $typenArray = $formcompany->typent_array(1);
+		print $typenArray[$obj->typent_code];
+		print '</td>';
+		if (! $i) $totalarray['nbfield']++;
+	}
+	if (! empty($arrayfields['s.email']['checked']))
+	{
+		print "<td>".$obj->email."</td>\n";
+		if (! $i) $totalarray['nbfield']++;
+	}
+	if (! empty($arrayfields['s.phone']['checked']))
+	{
+		print "<td>".$obj->phone."</td>\n";
+		if (! $i) $totalarray['nbfield']++;
+	}
+	if (! empty($arrayfields['s.url']['checked']))
+	{
+		print "<td>".$obj->url."</td>\n";
+		if (! $i) $totalarray['nbfield']++;
+	}
+	if (! empty($arrayfields['s.siren']['checked']))
+	{
+		print "<td>".$obj->idprof1."</td>\n";
+		if (! $i) $totalarray['nbfield']++;
+	}
+	if (! empty($arrayfields['s.siret']['checked']))
+	{
+		print "<td>".$obj->idprof2."</td>\n";
+		if (! $i) $totalarray['nbfield']++;
+	}
+	if (! empty($arrayfields['s.ape']['checked']))
+	{
+		print "<td>".$obj->idprof3."</td>\n";
+		if (! $i) $totalarray['nbfield']++;
+	}
+	if (! empty($arrayfields['s.idprof4']['checked']))
+	{
+		print "<td>".$obj->idprof4."</td>\n";
+		if (! $i) $totalarray['nbfield']++;
+	}
+	if (! empty($arrayfields['s.idprof5']['checked']))
+	{
+		print "<td>".$obj->idprof5."</td>\n";
+		if (! $i) $totalarray['nbfield']++;
+	}
+	if (! empty($arrayfields['s.idprof6']['checked']))
+	{
+		print "<td>".$obj->idprof6."</td>\n";
+		if (! $i) $totalarray['nbfield']++;
+	}
+	if (! empty($arrayfields['s.tva_intra']['checked']))
+	{
+		print "<td>".$obj->tva_intra."</td>\n";
+		if (! $i) $totalarray['nbfield']++;
+	}
+	// Type
+	if (! empty($arrayfields['customerorsupplier']['checked']))
+	{
+		print '<td align="center">';
+		$s='';
+		if (($obj->client==1 || $obj->client==3) && empty($conf->global->SOCIETE_DISABLE_CUSTOMERS))
+		{
+	  		$companystatic->name=$langs->trans("Customer");
+	  		$companystatic->name_alias='';
+			$s.=$companystatic->getNomUrl(0,'customer',0,1);
+		}
+		if (($obj->client==2 || $obj->client==3) && empty($conf->global->SOCIETE_DISABLE_PROSPECTS))
+		{
+			if ($s) $s.=" / ";
+			$companystatic->name=$langs->trans("Prospect");
+	  		$companystatic->name_alias='';
+			$s.=$companystatic->getNomUrl(0,'prospect',0,1);
+		}
+		if (! empty($conf->fournisseur->enabled) && $obj->fournisseur)
+		{
+			if ($s) $s.=" / ";
+			$companystatic->name=$langs->trans("Supplier");
+	  		$companystatic->name_alias='';
+			$s.=$companystatic->getNomUrl(0,'supplier',0,1);
+		}
+		print $s;
+		print '</td>';
+		if (! $i) $totalarray['nbfield']++;
+	}
+
+	if (! empty($arrayfields['s.fk_prospectlevel']['checked']))
+	{
+		// Prospect level
+		print '<td align="center">';
+		print $companystatic->getLibProspLevel();
+		print "</td>";
+		if (! $i) $totalarray['nbfield']++;
+	}
+
+	if (! empty($arrayfields['s.fk_stcomm']['checked']))
+	{
+		// Prospect status
+		print '<td align="center" class="nowrap"><div class="nowrap">';
+		print '<div class="inline-block">'.$companystatic->LibProspCommStatut($obj->stcomm_id,2,$prospectstatic->cacheprospectstatus[$obj->stcomm_id]['label']);
+		print '</div> - <div class="inline-block">';
+		foreach($prospectstatic->cacheprospectstatus as $key => $val)
+		{
+			$titlealt='default';
+			if (! empty($val['code']) && ! in_array($val['code'], array('ST_NO', 'ST_NEVER', 'ST_TODO', 'ST_PEND', 'ST_DONE'))) $titlealt=$val['label'];
+			if ($obj->stcomm_id != $val['id']) print '<a class="pictosubstatus" href="'.$_SERVER["PHP_SELF"].'?stcommsocid='.$obj->rowid.'&stcomm='.$val['code'].'&action=setstcomm'.$param.($page?'&page='.urlencode($page):'').'">'.img_action($titlealt,$val['code']).'</a>';
+		}
+		print '</div></div></td>';
+		if (! $i) $totalarray['nbfield']++;
+	}
+	// Extra fields
+	include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
+	// Fields from hook
+	$parameters=array('arrayfields'=>$arrayfields, 'obj'=>$obj);
+	$reshook=$hookmanager->executeHooks('printFieldListValue',$parameters);    // Note that $action and $object may have been modified by hook
+	print $hookmanager->resPrint;
+	// Date creation
+	if (! empty($arrayfields['s.datec']['checked']))
+	{
+		print '<td align="center" class="nowrap">';
+		print dol_print_date($db->jdate($obj->date_creation), 'dayhour', 'tzuser');
+		print '</td>';
+		if (! $i) $totalarray['nbfield']++;
+	}
+	// Date modification
+	if (! empty($arrayfields['s.tms']['checked']))
+	{
+		print '<td align="center" class="nowrap">';
+		print dol_print_date($db->jdate($obj->date_update), 'dayhour', 'tzuser');
+		print '</td>';
+		if (! $i) $totalarray['nbfield']++;
+	}
+	// Status
+	if (! empty($arrayfields['s.status']['checked']))
+	{
+		print '<td align="center" class="nowrap">'.$companystatic->getLibStatut(3).'</td>';
+		if (! $i) $totalarray['nbfield']++;
+	}
+	if (! empty($arrayfields['s.import_key']['checked']))
+	{
+		print '<td class="tdoverflowmax100">';
+		print $obj->import_key;
+		print "</td>\n";
+		if (! $i) $totalarray['nbfield']++;
+	}
+
+	// Action column
+	print '<td class="nowrap" align="center">';
+	if ($massactionbutton || $massaction)   // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
+	{
+		$selected=0;
+		if (in_array($obj->rowid, $arrayofselected)) $selected=1;
+		print '<input id="cb'.$obj->rowid.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->rowid.'"'.($selected?' checked="checked"':'').'>';
+	}
+	print '</td>';
+	if (! $i) $totalarray['nbfield']++;
+
+	print '</tr>'."\n";
+	$i++;
+}
+
+$db->free($resql);
+
+$parameters=array('arrayfields'=>$arrayfields, 'sql'=>$sql);
+$reshook=$hookmanager->executeHooks('printFieldListFooter',$parameters);    // Note that $action and $object may have been modified by hook
+print $hookmanager->resPrint;
+
+print "</table>";
+print "</div>";
+
+print '</form>';
+
+llxFooter();
+$db->close();

+ 53 - 0
htdocs/takepos/dev/img/README.md

@@ -0,0 +1,53 @@
+Source images
+=============
+
+Used to generate icons and publication assets.
+
+Icons
+-----
+
+### Dolibarr
+
+These resides in the [/img](../../img) directory.
+
+#### Small
+
+Required.
+Name must begin by ```object_```.
+
+- Sample:  ![object_takepos.png](../../img/object_takepos.png) [object_takepos.png](../../img/object_takepos.png)
+- Size: 14×14 pixels
+- Type: PNG
+
+#### Large
+
+Optional.
+
+- Sample: ![takepos.png](../../img/takepos.png) [takepos.png](../../img/takepos.png)
+- Size: 32×32 pixels
+- Type: PNG
+
+### Dolistore
+
+Designed to fit a 512×512 icon + publisher branding.
+
+- Size: 704×704
+- Type: PNG
+
+Export to 512×512
+
+### Transifex
+
+- Size: 96×96
+- Type: PNG
+
+### Others
+
+To be on the safe side, you may also want to generate all popular sizes:
+- 16×16
+- 32×32
+- 48×48
+- 64×64
+- 128×128
+- 256×256
+- 512×512

BIN
htdocs/takepos/dev/img/gfdl-129x44.png


BIN
htdocs/takepos/dev/img/gfdl-66x23.png


+ 110 - 0
htdocs/takepos/dev/img/gfdl-logo.svg

@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="110.72372"
+   height="37.900333"
+   id="svg3330"
+   version="1.1"
+   inkscape:version="0.48.0 r9654"
+   sodipodi:docname="New document 4">
+  <defs
+     id="defs3332" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="3.959798"
+     inkscape:cx="51.755214"
+     inkscape:cy="19.316583"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:window-width="1680"
+     inkscape:window-height="950"
+     inkscape:window-x="0"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata3335">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-319.64995,-513.41138)">
+    <g
+       id="g5424"
+       transform="matrix(1.1204236,0,0,1.1204236,378.23897,-788.71491)">
+      <path
+         sodipodi:nodetypes="cccccc"
+         inkscape:connector-curvature="0"
+         id="rect6744"
+         d="m -51.39745,1163.0948 85,0 0,29.5252 -85,0 2,-14.7626 z"
+         style="fill:#f5efbc;fill-opacity:1;stroke:#000000;stroke-width:1.79999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0" />
+      <text
+         transform="scale(0.90245956,1.1080829)"
+         sodipodi:linespacing="125%"
+         id="text6752-6"
+         y="1071.2108"
+         x="-15.68348"
+         style="font-size:24.31293869px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu Bold"
+         xml:space="preserve"><tspan
+           style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:URW Palladio L;-inkscape-font-specification:URW Palladio L Bold"
+           y="1071.2108"
+           x="-15.68348"
+           id="tspan6754-4"
+           sodipodi:role="line">GFDL</tspan></text>
+      <path
+         inkscape:connector-curvature="0"
+         id="path7064-6"
+         d="m 19.61576,1166.8577 0,24 0.1875,0 c -0.12127,0.1989 -0.1875,0.4164 -0.1875,0.625 0,2.002 5.8203,3.625 13,3.625 7.1797,0 13,-1.623 13,-3.625 0,-0.2086 -0.0662,-0.4261 -0.1875,-0.625 l 0.1875,0 0,-24 -26,0 z"
+         style="color:#000000;fill:#f5efbc;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.79999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         transform="translate(-321.63424,901.70446)"
+         d="m 367.25,264.98718 c 0,2.00203 -5.8203,3.625 -13,3.625 -7.1797,0 -13,-1.62297 -13,-3.625 0,-2.00203 5.8203,-3.625 13,-3.625 7.1797,0 13,1.62297 13,3.625 z"
+         sodipodi:ry="3.625"
+         sodipodi:rx="13"
+         sodipodi:cy="264.98718"
+         sodipodi:cx="354.25"
+         id="path7064"
+         style="color:#000000;fill:#f5efbc;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.79999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         sodipodi:type="arc" />
+      <path
+         sodipodi:nodetypes="cccccc"
+         inkscape:connector-curvature="0"
+         id="path7104"
+         d="m 45.06778,1167.3815 c -2.44864,5.5993 -9.9067,7.192 -21.52831,5.7955 l 5.7779,9.7599 -6.02275,7.2171 c 7.75095,3.1192 17.18643,1.5723 22.07112,-0.1842 z"
+         style="fill:#2e439b;fill-opacity:1;stroke:#000000;stroke-width:1.39999986;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         sodipodi:nodetypes="ccscc"
+         inkscape:connector-curvature="0"
+         id="path7106"
+         d="m 34.45935,1165.7653 c -3.4695,-0.1017 -8.01646,0.018 -10.47747,0.7778 1.2102,0.9782 6.11198,1.5627 9.94714,1.2348 3.20297,-0.2738 6.08198,-0.1311 7.93857,-1.1503 -0.70667,-1.1077 -3.93837,-3.3774 -7.91865,-3.2613"
+         style="fill:none;stroke:#000000;stroke-width:1.39999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+    </g>
+  </g>
+</svg>

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 74 - 0
htdocs/takepos/dev/img/gpl-v3-logo.svg


BIN
htdocs/takepos/dev/img/gplv3-127x51.png


BIN
htdocs/takepos/dev/img/gplv3-88x31.png


+ 70 - 0
htdocs/takepos/dev/img/takepos.svg

@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="14"
+   height="14"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="object_mymodule.svg"
+   inkscape:export-filename="/home/raph/Travail/src/zenfusion-modules/img/object_mymodule.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="3.959798"
+     inkscape:cx="24.310822"
+     inkscape:cy="18.155032"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1920"
+     inkscape:window-height="1021"
+     inkscape:window-x="1080"
+     inkscape:window-y="867"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-1038.3622)">
+    <text
+       xml:space="preserve"
+       style="font-size:12.99629784px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif"
+       x="0.35272363"
+       y="1050.0994"
+       id="text2985"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan2987"
+         x="0.35272363"
+         y="1050.0994">M</tspan></text>
+  </g>
+</svg>

+ 176 - 0
htdocs/takepos/floors.php

@@ -0,0 +1,176 @@
+<?php
+/* Copyright (C) 2018	Andreu Bisquerra	<jove@bisquerra.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+//if (! defined('NOREQUIREUSER'))	define('NOREQUIREUSER','1');	// Not disabled cause need to load personalized language
+//if (! defined('NOREQUIREDB'))		define('NOREQUIREDB','1');		// Not disabled cause need to load personalized language
+//if (! defined('NOREQUIRESOC'))		define('NOREQUIRESOC','1');
+//if (! defined('NOREQUIRETRAN'))		define('NOREQUIRETRAN','1');
+if (! defined('NOCSRFCHECK'))		define('NOCSRFCHECK','1');
+if (! defined('NOTOKENRENEWAL'))	define('NOTOKENRENEWAL','1');
+if (! defined('NOREQUIREMENU'))		define('NOREQUIREMENU','1');
+if (! defined('NOREQUIREHTML'))		define('NOREQUIREHTML','1');
+if (! defined('NOREQUIREAJAX'))		define('NOREQUIREAJAX','1');
+
+$_GET['theme']="md"; // Force theme. MD theme provides better look and feel to TakePOS
+
+require '../main.inc.php';	// Load $user and permissions
+
+$floor=GETPOST('floor');
+if ($floor=="") $floor=1;
+$id = GETPOST('id');
+$action = GETPOST('action');
+$left = GETPOST('left');
+$top = GETPOST('top');
+$place = GETPOST('place');
+$newname = GETPOST('newname');
+$mode = GETPOST('mode');
+
+if ($action=="getTables"){
+    $sql="SELECT * from ".MAIN_DB_PREFIX."takepos_floor_tables where floor=".$floor;
+    $resql = $db->query($sql);
+    $rows = array();
+    while($row = $db->fetch_array ($resql)){
+        $rows[] = $row;
+    }
+    echo json_encode($rows);
+    exit;
+}
+
+if ($action=="update")
+{
+    if ($left>95) $left=95;
+    if ($top>95) $top=95;
+    if ($left>3 or $top>4) $db->query("update ".MAIN_DB_PREFIX."takepos_floor_tables set leftpos=$left, toppos=$top where label='$place'");
+    else $db->query("delete from ".MAIN_DB_PREFIX."takepos_floor_tables where label='$place'");
+}
+
+if ($action=="updatename")
+{
+	$newname = preg_replace("/[^a-zA-Z0-9\s]/", "", $newname); // Only English chars
+	if (strlen($newname) > 3) $newname = substr($newname, 0, 3); // Only 3 chars
+    $db->query("update ".MAIN_DB_PREFIX."takepos_floor_tables set label='$newname' where label='$place'");
+}
+
+if ($action=="add")
+{
+    $asdf=$db->query("insert into ".MAIN_DB_PREFIX."takepos_floor_tables values ('', '', '', '45', '45', $floor)");
+	$db->query("update ".MAIN_DB_PREFIX."takepos_floor_tables set label=rowid where label=''"); // No empty table names
+}
+
+// Title
+$title='TakePOS - Dolibarr '.DOL_VERSION;
+if (! empty($conf->global->MAIN_APPLICATION_TITLE)) $title='TakePOS - '.$conf->global->MAIN_APPLICATION_TITLE;
+top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss);
+?>
+<link rel="stylesheet" href="css/pos.css?a=xxx">
+<style type="text/css">
+div.tablediv{
+background-image:url(img/table.gif);
+-moz-background-size:100% 100%;
+-webkit-background-size:100% 100%;
+background-size:100% 100%;
+height:10%;
+width:10%;
+text-align: center;
+font-size:300%;
+color:white;
+}
+html, body
+{
+height: 100%;
+}
+</style>
+
+<script>
+var DragDrop='<?php echo $langs->trans("DragDrop"); ?>';
+
+function updateplace(idplace, left, top) {
+	$.ajax({
+		type: "POST",
+		url: "floors.php",
+		data: { action: "update", left: left, top: top, place: idplace }
+		}).done(function( msg ) {
+		window.location.href='floors.php?mode=edit&floor=<?php echo $floor;?>';
+	});
+}
+
+function updatename(before) {
+	var after=$("#"+before).text();
+	$.ajax({
+		type: "POST",
+		url: "floors.php",
+		data: { action: "updatename", place: before, newname: after }
+		}).done(function( msg ) {
+		window.location.href='floors.php?mode=edit&floor=<?php echo $floor;?>';
+		});
+	}
+
+function LoadPlace(place){
+	parent.location.href='takepos.php?place='+place;
+}
+
+
+$( document ).ready(function() {
+	$.getJSON('./floors.php?action=getTables&floor=<?php echo $floor; ?>', function(data) {
+        $.each(data, function(key, val) {
+			<?php if ($mode=="edit"){?>
+			$('body').append('<div class="tablediv" contenteditable onblur="updatename('+val.label+');" style="position: absolute; left: '+val.leftpos+'%; top: '+val.toppos+'%;" id="'+val.label+'">'+val.label+'</div>');
+			$( "#"+val.label ).draggable(
+				{
+					start: function() {
+					$("#add").html("<?php echo $langs->trans("Delete"); ?>");
+                    },
+					stop: function() {
+					var left=$(this).offset().left*100/$(window).width();
+					var top=$(this).offset().top*100/$(window).height();
+					updateplace($(this).attr('id'), left, top);
+					}
+				}
+			);
+			//simultaneous draggable and contenteditable
+			$('#'+val.label).draggable().bind('click', function(){
+				$(this).focus();
+			})
+			<?php }
+			else {?>
+			$('body').append('<div class="tablediv" onclick="LoadPlace('+val.label+');" style="position: absolute; left: '+val.leftpos+'%; top: '+val.toppos+'%;" id="'+val.label+'">'+val.label+'</div>');
+			<?php } ?>
+		});
+	});
+});
+
+</script>
+</head>
+<body style="overflow: hidden">
+<?php if ($user->admin){?>
+<div style="position: absolute; left: 0.1%; top: 0.8%; width:8%; height:11%;">
+<?php if ($mode=="edit"){?>
+<a id="add" onclick="window.location.href='floors.php?mode=edit&action=add&floor=<?php echo $floor;?>';"><?php echo $langs->trans("AddTable"); ?></a>
+<?php } else { ?>
+<a onclick="window.location.href='floors.php?mode=edit&floor=<?php echo $floor;?>';"><?php echo $langs->trans("Edit"); ?></a>
+<?php } ?>
+</div>
+<?php }
+?>
+
+<div style="position: absolute; left: 25%; bottom: 8%; width:50%; height:3%;">
+    <center>
+    <h1><img src="./img/arrow-prev.png" width="5%" onclick="location.href='floors.php?floor=<?php if ($floor>1) { $floor--; echo $floor; $floor++;} else echo "1"; ?>';"><?php echo $langs->trans("Floor")." ".$floor; ?><img src="./img/arrow-next.png" width="5%" onclick="location.href='floors.php?floor=<?php $floor++; echo $floor; ?>';"></h1>
+    </center>
+</div>
+</body>
+</html>

+ 59 - 0
htdocs/takepos/freezone.php

@@ -0,0 +1,59 @@
+<?php
+/* Copyright (C) 2018	Andreu Bisquerra	<jove@bisquerra.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+//if (! defined('NOREQUIREUSER'))	define('NOREQUIREUSER','1');	// Not disabled cause need to load personalized language
+//if (! defined('NOREQUIREDB'))		define('NOREQUIREDB','1');		// Not disabled cause need to load personalized language
+//if (! defined('NOREQUIRESOC'))		define('NOREQUIRESOC','1');
+//if (! defined('NOREQUIRETRAN'))		define('NOREQUIRETRAN','1');
+if (! defined('NOCSRFCHECK'))		define('NOCSRFCHECK','1');
+if (! defined('NOTOKENRENEWAL'))	define('NOTOKENRENEWAL','1');
+if (! defined('NOREQUIREMENU'))		define('NOREQUIREMENU','1');
+if (! defined('NOREQUIREHTML'))		define('NOREQUIREHTML','1');
+if (! defined('NOREQUIREAJAX'))		define('NOREQUIREAJAX','1');
+
+require '../main.inc.php';	// Load $user and permissions
+
+$langs->load("bills");
+$langs->load("cashdesk");
+$place = GETPOST('place');
+
+
+/*
+ * View
+ */
+
+top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss);
+
+?>
+<script>
+function Save(){
+	$.get( "invoice.php", { action: "freezone", place: "<?php echo $place;?>", desc:$('#desc').val(), number:$('#price').val()} );
+	parent.$.colorbox.close();
+}
+</script>
+</head>
+<body>
+<br>
+<center>
+<input type="text" id="desc" name="desc" style="width:40%;font-size: 200%;" placeholder="<?php echo $langs->trans('Description');?>">
+<input type="text" id="price" name="price" style="width:15%;font-size: 200%;" placeholder="<?php echo $langs->trans('Price');?>">
+<input type="hidden" name="place" value="<?php echo $place;?>">
+<input type="button" style="width:15%;font-size: 200%;" value="OK" onclick="Save();">
+</center>
+
+</body>
+</html>

BIN
htdocs/takepos/genimg/add.jpg


BIN
htdocs/takepos/genimg/empty.jpg


+ 142 - 0
htdocs/takepos/genimg/index.php

@@ -0,0 +1,142 @@
+<?php
+/* Copyright (C) 2018	Andreu Bisquerra	<jove@bisquerra.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+//if (! defined('NOREQUIREUSER'))	define('NOREQUIREUSER','1');	// Not disabled cause need to load personalized language
+//if (! defined('NOREQUIREDB'))		define('NOREQUIREDB','1');		// Not disabled cause need to load personalized language
+if (! defined('NOREQUIRESOC'))		define('NOREQUIRESOC','1');
+//if (! defined('NOREQUIRETRAN'))		define('NOREQUIRETRAN','1');
+if (! defined('NOCSRFCHECK'))		define('NOCSRFCHECK','1');
+if (! defined('NOTOKENRENEWAL'))	define('NOTOKENRENEWAL','1');
+if (! defined('NOREQUIREMENU'))		define('NOREQUIREMENU','1');
+if (! defined('NOREQUIREHTML'))		define('NOREQUIREHTML','1');
+if (! defined('NOREQUIREAJAX'))		define('NOREQUIREAJAX','1');
+
+require '../../main.inc.php';	// Load $user and permissions
+
+$id= GETPOST('id');
+$w= GETPOST('w');
+$h= GETPOST('h');
+$query= GETPOST('query');
+
+
+
+/*
+ * View
+ */
+
+header('Content-Type: image/jpeg');
+header('Cache-Control: max-age=604800, public, must-revalidate');
+header('Pragma: cache');
+
+if ($query=="cat")
+{
+	require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
+	require_once DOL_DOCUMENT_ROOT.'/core/lib/categories.lib.php';
+
+	$object = new Categorie($db);
+	$result = $object->fetch($id);
+	$upload_dir = $conf->categorie->multidir_output[$object->entity];
+	$pdir = get_exdir($object->id,2,0,0,$object,'category') . $object->id ."/photos/";
+	$dir = $upload_dir.'/'.$pdir;
+	foreach ($object->liste_photos($dir) as $key => $obj)
+	{
+		$filename=$obj['photo'];
+	}
+
+	// The file
+	$filename = $dir.$filename;
+	if (!file_exists($filename)) $filename="empty.jpg";
+
+	// Dimensions
+	list($width, $height) = getimagesize($filename);
+	$new_width = $w;
+	$new_height = $h;
+
+	// Resample
+	$image_p = imagecreatetruecolor($new_width, $new_height);
+	$image = imagecreatefromjpeg($filename);
+	imagecopyresampled($image_p, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
+
+	// Add icon
+	$icon = imagecreatefromjpeg('add.jpg');
+	list($width, $height) = getimagesize('add.jpg');
+	$new_width = $w*0.3;
+	$new_height = $h*0.3;
+	$icon_p = imagecreatetruecolor($new_width, $new_height);
+	imagecopyresampled($icon_p, $icon, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
+	imagecopymerge($image_p, $icon_p,  0, 0, 0, 0, $new_width, $new_height, 100);
+
+	// Output
+	imagejpeg($image_p, null, 100);
+}
+else if ($query=="pro")
+{
+	require_once(DOL_DOCUMENT_ROOT."/product/class/product.class.php");
+	$objProd = new Product($db);
+	$objProd->fetch($id);
+
+	$dir .= get_exdir(0,0,0,0,$objProd,'product').$objProd->ref.'/';
+	$pdir .= get_exdir(0,0,0,0,$objProd,'product').$objProd->ref.'/';
+
+	foreach ($objProd->liste_photos($dir) as $key => $obj)
+	{
+		$filename=$obj['photo'];
+	}
+	$filename = $dir.$filename;
+
+	if (!file_exists($filename)){
+		$dir = $conf->product->multidir_output[$objProd->entity].'/'.$pdir;
+		foreach ($objProd->liste_photos($dir) as $key => $obj)
+		{
+		$filename=$obj['photo'];
+		}
+		$filename = $dir.$filename;
+	}
+
+	if (!file_exists($filename)) $filename="empty.jpg";
+
+	// Dimensions
+	list($width, $height) = getimagesize($filename);
+	$new_width = $w;
+	$new_height = $h;
+
+	// Resample
+	$image_p = imagecreatetruecolor($new_width, $new_height);
+	$image = imagecreatefromjpeg($filename);
+	imagecopyresampled($image_p, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
+
+	// Output
+	imagejpeg($image_p, null, 100);
+}
+else
+{
+	// The file
+	$filename = $query.".jpg";
+
+	// Dimensions
+	list($width, $height) = getimagesize($filename);
+	$new_width = $w;
+	$new_height = $h;
+
+	// Resample
+	$image_p = imagecreatetruecolor($new_width, $new_height);
+	$image = imagecreatefromjpeg($filename);
+	imagecopyresampled($image_p, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
+
+	// Output
+	imagejpeg($image_p, null, 100);
+}

BIN
htdocs/takepos/img/arrow-next-top.png


BIN
htdocs/takepos/img/arrow-next.png


BIN
htdocs/takepos/img/arrow-prev-top.png


BIN
htdocs/takepos/img/arrow-prev.png


BIN
htdocs/takepos/img/gfdl.png


BIN
htdocs/takepos/img/gplv3.png


BIN
htdocs/takepos/img/marketplace/cashcontrol.jpg


BIN
htdocs/takepos/img/marketplace/takeposmobile.jpg


BIN
htdocs/takepos/img/object_takepos.png


BIN
htdocs/takepos/img/table.gif


BIN
htdocs/takepos/img/takepos.png


+ 287 - 0
htdocs/takepos/invoice.php

@@ -0,0 +1,287 @@
+<?php
+/* Copyright (C) 2018	Andreu Bisquerra	<jove@bisquerra.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+//if (! defined('NOREQUIREUSER'))	define('NOREQUIREUSER','1');	// Not disabled cause need to load personalized language
+//if (! defined('NOREQUIREDB'))		define('NOREQUIREDB','1');		// Not disabled cause need to load personalized language
+//if (! defined('NOREQUIRESOC'))		define('NOREQUIRESOC','1');
+//if (! defined('NOREQUIRETRAN'))		define('NOREQUIRETRAN','1');
+if (! defined('NOCSRFCHECK'))		define('NOCSRFCHECK','1');
+if (! defined('NOTOKENRENEWAL'))	define('NOTOKENRENEWAL','1');
+if (! defined('NOREQUIREMENU'))		define('NOREQUIREMENU','1');
+if (! defined('NOREQUIREHTML'))		define('NOREQUIREHTML','1');
+if (! defined('NOREQUIREAJAX'))		define('NOREQUIREAJAX','1');
+
+require '../main.inc.php';	// Load $user and permissions
+require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
+require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
+
+$langs->load("bills");
+$langs->load("cashdesk");
+
+$id = GETPOST('id');
+$action = GETPOST('action');
+$idproduct = GETPOST('idproduct');
+$place = GETPOST('place');
+$number = GETPOST('number');
+$idline = GETPOST('idline');
+$desc = GETPOST('desc');
+$pay = GETPOST('pay');
+
+$sql="SELECT rowid FROM ".MAIN_DB_PREFIX."facture where facnumber='(PROV-POS-".$place.")'";
+$resql = $db->query($sql);
+$row = $db->fetch_array ($resql);
+$placeid=$row[0];
+if (! $placeid) $placeid=0; // not necesary
+else{
+	$invoice = new Facture($db);
+	$invoice->fetch($placeid);
+}
+
+/*
+ * Actions
+ */
+
+if ($action == 'valid' && $user->rights->facture->creer){
+	if ($pay=="cash") $bankaccount=$conf->global->CASHDESK_ID_BANKACCOUNT_CASH;
+	else if ($pay=="card") $bankaccount=$conf->global->CASHDESK_ID_BANKACCOUNT_CB;
+	$now=dol_now();
+	$invoice = new Facture($db);
+	$invoice->fetch($placeid);
+	if (! empty($conf->stock->enabled) and $conf->global->CASHDESK_NO_DECREASE_STOCK!="1") $invoice->validate($user, '', $conf->global->CASHDESK_ID_WAREHOUSE);
+	else $invoice->validate($user);
+	// Add the payment
+	$payment=new Paiement($db);
+	$payment->datepaye=$now;
+	$payment->bank_account=$bankaccount;
+	$payment->amounts[$invoice->id]=$invoice->total_ttc;
+	if ($pay=="cash") $payment->paiementid=4;
+	else if ($pay=="card") $payment->paiementid=6;
+	$payment->num_paiement=$invoice->facnumber;
+	$payment->create($user);
+	$payment->addPaymentToBank($user, 'payment', '(CustomerInvoicePayment)', $bankaccount, '', '');
+	$invoice->set_paid($user);
+}
+
+if (($action=="addline" or $action=="freezone") and $placeid==0)
+{
+	if ($placeid==0) {
+	$invoice = new Facture($db);
+	$invoice->socid=$conf->global->CASHDESK_ID_THIRDPARTY;
+	$invoice->date=mktime();
+	$invoice->ref="asdf";
+	$placeid=$invoice->create($user);
+	$sql="UPDATE ".MAIN_DB_PREFIX."facture set facnumber='(PROV-POS-".$place.")' where rowid=".$placeid;
+	$db->query($sql);
+	}
+}
+
+if ($action=="addline"){
+	$prod = new Product($db);
+	$prod->fetch($idproduct);
+	$invoice->addline($prod->description, $prod->price, 1, $prod->tva_tx, $prod->localtax1_tx, $prod->localtax2_tx, $idproduct, $prod->remise_percent, '', 0, 0, 0, '', $prod->price_base_type, $prod->price_ttc, $prod->type, - 1, 0, '', 0, 0, null, 0, '', 0, 100, '', null, 0);
+	$invoice->fetch($placeid);
+}
+
+if ($action=="freezone"){
+	$invoice->addline($desc, $number, 1, $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS, 0, 0, 0, 0, '', 0, 0, 0, '', 'TTC', $number, 0, - 1, 0, '', 0, 0, null, 0, '', 0, 100, '', null, 0);
+	$invoice->fetch($placeid);
+}
+
+if ($action=="deleteline"){
+    if ($idline>0 and $placeid>0){ //If exist invoice and line, to avoid errors if deleted from other device or no line selected
+        $invoice->deleteline($idline);
+        $invoice->fetch($placeid);
+    }
+    else if ($placeid>0){ //If exist invoice, but no line selected, proced to delete last line
+        $sql="SELECT rowid FROM ".MAIN_DB_PREFIX."facturedet where fk_facture='$placeid' order by rowid DESC";
+        $resql = $db->query($sql);
+        $row = $db->fetch_array ($resql);
+        $deletelineid=$row[0];
+        $invoice->deleteline($deletelineid);
+        $invoice->fetch($deletelineid);
+    }
+}
+
+if ($action=="updateqty"){
+    foreach ($invoice->lines as $line){
+        if ($line->id==$idline) $result = $invoice->updateline($line->id, $line->desc, $line->subprice, $number, $line->remise_percent,
+			$line->date_start, $line->date_end, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type,
+			$line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->situation_percent,
+			$line->fk_unit);
+    }
+	$invoice->fetch($placeid);
+}
+
+if ($action=="updateprice"){
+    foreach ($invoice->lines as $line){
+        if ($line->id==$idline) $result = $invoice->updateline($line->id, $line->desc, $number, $line->qty, $line->remise_percent,
+			$line->date_start, $line->date_end, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type,
+			$line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->situation_percent,
+			$line->fk_unit);
+    }
+	$invoice->fetch($placeid);
+}
+
+if ($action=="updatereduction"){
+    foreach ($invoice->lines as $line){
+        if ($line->id==$idline) $result = $invoice->updateline($line->id, $line->desc, $line->subprice, $line->qty, $number,
+			$line->date_start, $line->date_end, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type,
+			$line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->situation_percent,
+			$line->fk_unit);
+    }
+	$invoice->fetch($placeid);
+}
+
+if ($action=="order"){
+	require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
+	$headerorder='<html><br><b>'.$langs->trans('Place').' '.$place.'<br><table width="65%"><thead><tr><th align="left">'.$langs->trans("Label").'</th><th align="right">'.$langs->trans("Qty").'</th></tr></thead><tbody>';
+	$footerorder='</tbody></table>'.dol_print_date(dol_now(), 'dayhour').'<br></html>';
+	$order_receipt_printer1="";
+	$order_receipt_printer2="";
+	$catsprinter1 = explode(';',$conf->global->TAKEPOS_PRINTED_CATEGORIES_1);
+	$catsprinter2 = explode(';',$conf->global->TAKEPOS_PRINTED_CATEGORIES_2);
+	foreach ($invoice->lines as $line){
+		if ($line->special_code=="3") continue;
+		$c = new Categorie($db);
+		$existing = $c->containing($line->fk_product, Categorie::TYPE_PRODUCT, 'id');
+		$result = array_intersect($catsprinter1, $existing);
+		$count=count($result);
+		if ($count>0){
+			$sql="UPDATE ".MAIN_DB_PREFIX."facturedet set special_code='3' where rowid=$line->rowid";
+			$db->query($sql);
+			$order_receipt_printer1.='<tr>'.$line->product_label.'<td align="right">'.$line->qty.'</td></tr>';
+		}
+    }
+	foreach ($invoice->lines as $line){
+		if ($line->special_code=="3") continue;
+		$c = new Categorie($db);
+		$existing = $c->containing($line->fk_product, Categorie::TYPE_PRODUCT, 'id');
+		$result = array_intersect($catsprinter2, $existing);
+		$count=count($result);
+		if ($count>0){
+			$sql="UPDATE ".MAIN_DB_PREFIX."facturedet set special_code='3' where rowid=$line->rowid";
+			$db->query($sql);
+			$order_receipt_printer2.='<tr>'.$line->product_label.'<td align="right">'.$line->qty.'</td></tr>';
+		}
+    }
+	$invoice->fetch($placeid);
+}
+
+?>
+<style>
+.selected {
+	color: red;
+}
+.order {
+	color: limegreen;
+}
+</style>
+<script language="javascript">
+var selectedline=0;
+var selectedtext="";
+$(document).ready(function(){
+    $('table tbody tr').click(function(){
+		$('table tbody tr').removeClass("selected");
+        $(this).addClass("selected");
+		if (selectedline==this.id) return; // If is already selected
+        else selectedline=this.id;
+        selectedtext=$('#'+selectedline).find("td:first").html();
+    });
+<?php if ($action=="order" and $order_receipt_printer1!=""){
+	?>
+	$.ajax({
+		type: "POST",
+		url: 'http://<?php print $conf->global->TAKEPOS_PRINT_SERVER;?>:8111/print',
+		data: '<?php print $headerorder.$order_receipt_printer1.$footerorder; ?>'
+	});
+<?php
+}
+if ($action=="order" and $order_receipt_printer2!=""){
+	?>
+	$.ajax({
+		type: "POST",
+		url: 'http://<?php print $conf->global->TAKEPOS_PRINT_SERVER;?>:8111/print2',
+		data: '<?php print $headerorder.$order_receipt_printer2.$footerorder; ?>'
+	});
+<?php
+}
+if ($action=="search"){
+	?>
+	$('#search').focus();
+	<?php
+}
+?>
+});
+
+function Print(id){
+	$.colorbox({href:"receipt.php?facid="+id, width:"40%", height:"90%", transition:"none", iframe:"true", title:"<?php echo $langs->trans("PrintTicket");?>"});
+}
+
+function TakeposPrinting(id){
+	var receipt;
+	$.get("receipt.php?facid="+id, function(data, status){
+        receipt=data.replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '');;
+		$.ajax({
+			type: "POST",
+			url: 'http://<?php print $conf->global->TAKEPOS_PRINT_SERVER;?>:8111/print',
+			data: receipt
+		});
+    });
+}
+</script>
+<?php
+print '<div class="div-table-responsive-no-min">';
+print '<table id="tablelines" class="noborder noshadow" width="100%">';
+print '<tr class="liste_titre nodrag nodrop">';
+print '<td class="linecoldescription">'.$langs->trans('Description').'</td>';
+print '<td class="linecolqty" align="right">'.$langs->trans('Qty').'</td>';
+print '<td class="linecolht" align="right">'.$langs->trans('TotalHTShort').'</td>';
+print "</tr>\n";
+if ($placeid>0) foreach ($invoice->lines as $line)
+{
+	print '<tr class="drag drop oddeven';
+	if ($line->special_code=="3") print ' order';
+	print '" id="'.$line->rowid.'">';
+	print '<td>'.$line->product_label.$line->desc.'</td>';
+	print '<td align="right">'.$line->qty.'</td>';
+	print '<td align="right">'.price($line->total_ttc).'</td>';
+	print '</tr>';
+}
+print '</table>';
+print '<p style="font-size:120%;" align="right"><b>'.$langs->trans('TotalTTC');
+if($conf->global->TAKEPOS_BAR_RESTAURANT) print " ".$langs->trans('Place')." ".$place;
+print ': '.price($invoice->total_ttc, 1, '', 1, - 1, - 1, $conf->currency).'&nbsp;</b></p>';
+
+//if ($invoice->socid != $conf->global->CASHDESK_ID_THIRDPARTY){
+    $soc = new Societe($db);
+    if ($invoice->socid > 0) $soc->fetch($invoice->socid);
+    else $soc->fetch($conf->global->CASHDESK_ID_THIRDPARTY);
+    print '<p style="font-size:120%;" align="right">';
+    print $langs->trans("Customer").': '.$soc->name;
+    print '</p>';
+//}
+if ($action=="valid"){
+	print '<p style="font-size:120%;" align="center"><b>'.$invoice->facnumber." ".$langs->trans('BillShortStatusValidated').'</b></p>';
+	if ($conf->global->TAKEBOX) print '<center><button type="button" onclick="TakeposPrinting('.$placeid.');">'.$langs->trans('PrintTicket').'</button><center>';
+	else print '<center><button type="button" onclick="Print('.$placeid.');">'.$langs->trans('PrintTicket').'</button><center>';
+}
+if ($action=="search"){
+	print '<center>
+	<input type="text" id="search" name="search" onkeyup="Search2();" name="search" style="width:80%;font-size: 150%;" placeholder='.$langs->trans('Search').'
+	</center>';
+}
+print '</div>';

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 5 - 0
htdocs/takepos/js/jquery.colorbox-min.js


+ 15 - 0
htdocs/takepos/js/takepos.js

@@ -0,0 +1,15 @@
+/* Copyright (C) 2018	Charles-FR BENKE		<jove@bisquerra.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */

+ 24 - 0
htdocs/takepos/langs/en_US/takepos.lang

@@ -0,0 +1,24 @@
+# Copyright (C) 2018 SuperAdmin
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+PointOfSale=Point Of Sales
+CloseBill=Close Bill
+Floors=Floors
+Floor=Floor
+AddTable=Add table
+Place=Place
+TakeboxNecesary='TakeBOX' application required
+OrderPrinters=Order printers
+SearchProduct=Search product

+ 22 - 0
htdocs/takepos/langs/es_ES/takepos.lang

@@ -0,0 +1,22 @@
+# Copyright (C) 2018 SuperAdmin
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+CloseBill=Cerrar venta
+Floors=Salones
+Floor=Salón
+AddTable=Añadir mesa
+Place=Puesto
+TakeboxNecesary=Aplicación 'TakeBOX' requerida
+OrderPrinters=Impresoras de pedido

+ 24 - 0
htdocs/takepos/langs/fr_FR/takepos.lang

@@ -0,0 +1,24 @@
+# Copyright (C) 2018 SuperAdmin
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+PointOfSale=Point de Vente
+CloseBill=Fermer Bill
+Floors=Étages
+Floor=Étage
+AddTable=Ajouter une table
+Place=Endroit
+TakeboxNecesary='TakeBOX' Application requise
+OrderPrinters=Commande imprimantes
+SearchProduct=Recherche produit

+ 58 - 0
htdocs/takepos/lib/takepos.lib.php

@@ -0,0 +1,58 @@
+<?php
+/* Copyright (C) 2018 SuperAdmin
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file    takepos/lib/takepos.lib.php
+ * \ingroup takepos
+ * \brief   Library files with common functions for TakePos
+ */
+
+/**
+ * Prepare admin pages header
+ *
+ * @return array
+ */
+function takeposAdminPrepareHead()
+{
+	global $langs, $conf;
+
+	$langs->load("takepos@takepos");
+
+	$h = 0;
+	$head = array();
+
+	$head[$h][0] = dol_buildpath("/takepos/admin/setup.php", 1);
+	$head[$h][1] = $langs->trans("Settings");
+	$head[$h][2] = 'settings';
+	$h++;
+	$head[$h][0] = dol_buildpath("/takepos/admin/about.php", 1);
+	$head[$h][1] = $langs->trans("About");
+	$head[$h][2] = 'about';
+	$h++;
+
+	// Show more tabs from modules
+	// Entries must be declared in modules descriptor with line
+	//$this->tabs = array(
+	//	'entity:+tabname:Title:@takepos:/takepos/mypage.php?id=__ID__'
+	//); // to add new tab
+	//$this->tabs = array(
+	//	'entity:-tabname:Title:@takepos:/takepos/mypage.php?id=__ID__'
+	//); // to remove a tab
+	complete_head_from_modules($conf, $langs, $object, $head, $h, 'takepos');
+
+	return $head;
+}

+ 3 - 0
htdocs/takepos/modulebuilder.txt

@@ -0,0 +1,3 @@
+# DO NOT DELETE THIS FILE MANUALLY
+# File to flag module built using official module template.
+# When this file is present into a module directory, you can edit it with the module builder tool. Use ModuleBuilder if you want to delete module. 

+ 122 - 0
htdocs/takepos/pay.php

@@ -0,0 +1,122 @@
+<?php
+/* Copyright (C) 2018	Andreu Bisquerra	<jove@bisquerra.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+//if (! defined('NOREQUIREUSER'))	define('NOREQUIREUSER','1');	// Not disabled cause need to load personalized language
+//if (! defined('NOREQUIREDB'))		define('NOREQUIREDB','1');		// Not disabled cause need to load personalized language
+//if (! defined('NOREQUIRESOC'))		define('NOREQUIRESOC','1');
+//if (! defined('NOREQUIRETRAN'))		define('NOREQUIRETRAN','1');
+if (! defined('NOCSRFCHECK'))		define('NOCSRFCHECK','1');
+if (! defined('NOTOKENRENEWAL'))	define('NOTOKENRENEWAL','1');
+if (! defined('NOREQUIREMENU'))		define('NOREQUIREMENU','1');
+if (! defined('NOREQUIREHTML'))		define('NOREQUIREHTML','1');
+if (! defined('NOREQUIREAJAX'))		define('NOREQUIREAJAX','1');
+
+$_GET['theme']="md"; // Force theme. MD theme provides better look and feel to TakePOS
+
+require '../main.inc.php';	// Load $user and permissions
+require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
+
+$place = GETPOST('place');
+
+
+/*
+ * View
+ */
+
+$sql="SELECT rowid FROM ".MAIN_DB_PREFIX."facture where facnumber='(PROV-POS-".$place.")'";
+$resql = $db->query($sql);
+$row = $db->fetch_array ($resql);
+$placeid=$row[0];
+if (! $placeid) $placeid=0; // Developing error message with no lines
+else{
+	$invoice = new Facture($db);
+	$invoice->fetch($placeid);
+}
+
+top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss);
+
+$langs->load("main");
+$langs->load("bills");
+$langs->load("cashdesk");
+?>
+<link rel="stylesheet" href="css/pos.css">
+	<script>
+	var received=0;
+	function addreceived(price)
+	{
+	received+=parseFloat(price);
+	$('#change1').html(received.toFixed(2));
+	if (received><?php echo $invoice->total_ttc;?>)
+		{
+		var change=parseFloat(received-<?php echo $invoice->total_ttc;?>);
+		$('#change2').html(change.toFixed(2));
+		}
+	}
+
+	function reset()
+	{
+		received=0;
+		addreceived(0);
+		$('#change2').html(received.toFixed(2));
+	}
+
+	function Validate(payment){
+        parent.$("#poslines").load("invoice.php?place=<?php echo $place;?>&action=valid&pay="+payment, function() {
+            parent.$("#poslines").scrollTop(parent.$("#poslines")[0].scrollHeight);
+            parent.$.colorbox.close();
+        });
+
+	}
+</script>
+</head>
+<body>
+
+<div style="position:absolute; top:2%; left:5%; height:36%; width:91%;">
+<center>
+<div style="width:40%; background-color:#222222; border-radius:8px; margin-bottom: 4px;">
+<center><span style='font-family: digital; font-size: 280%;'><font color="white"><?php echo $langs->trans('TotalTTC');?>: </font><font color="red"><span id="totaldisplay"><?php echo price($invoice->total_ttc, 1, '', 1, - 1, - 1, $conf->currency) ?></span></span></center>
+</div>
+<div style="width:40%; background-color:#333333; border-radius:8px; margin-bottom: 4px;">
+<center><span style='font-family: digital; font-size: 250%;'><font color="white"><?php echo $langs->trans("AlreadyPaid"); ?>: </font><font color="red"><span id="change1"><?php echo price(0) ?></span></center>
+</div>
+<div style="width:40%; background-color:#333333; border-radius:8px; margin-bottom: 4px;">
+<center><span style='font-family: digital; font-size: 250%;'><font color="white"><?php echo $langs->trans("Change"); ?>: </font><font color="red"><span id="change2"><?php echo price(0) ?></span></span></center>
+</div>
+</center>
+</div>
+
+<div style="position:absolute; top:40%; left:5%; height:55%; width:91%;">
+<button type="button" class="calcbutton" onclick="addreceived(10);">10</button>
+<button type="button" class="calcbutton" onclick="addreceived(20);">20</button>
+<button type="button" class="calcbutton" onclick="addreceived(50);">50</button>
+<button type="button" class="calcbutton2" onclick="Validate('cash');"><?php echo $langs->trans("Cash"); ?></button>
+<button type="button" class="calcbutton" onclick="addreceived(1);">1</button>
+<button type="button" class="calcbutton" onclick="addreceived(2);">2</button>
+<button type="button" class="calcbutton" onclick="addreceived(5);">5</button>
+<button type="button" class="calcbutton2" onclick="Validate('card');"><?php echo $langs->trans("PaymentTypeCB"); ?></button>
+<button type="button" class="calcbutton" onclick="addreceived(0.10);">0.10</button>
+<button type="button" class="calcbutton" onclick="addreceived(0.20);">0.20</button>
+<button type="button" class="calcbutton" onclick="addreceived(0.50);">0.50</button>
+<button type="button" class="calcbutton2" onclick="printclick();"><span id="printtext"><?php echo $langs->trans("GoBack"); ?></span></button>
+<button type="button" class="calcbutton" onclick="addreceived(0.01);">0.01</button>
+<button type="button" class="calcbutton" onclick="addreceived(0.02);">0.02</button>
+<button type="button" class="calcbutton" onclick="addreceived(0.05);">0.05</button>
+<button type="button" class="calcbutton2" onclick="reset();"><span style='font-size: 150%;'>C</span></button>
+</div>
+
+</body>
+</html>

+ 108 - 0
htdocs/takepos/receipt.php

@@ -0,0 +1,108 @@
+<?php
+/* Copyright (C) 2007-2008 Jeremie Ollivier    <jeremie.o@laposte.net>
+ * Copyright (C) 2011      Laurent Destailleur <eldy@users.sourceforge.net>
+ * Copyright (C) 2012      Marcos García       <marcosgdf@gmail.com>
+ * Copyright (C) 2018      Andreu Bisquerra    <jove@bisquerra.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+require '../main.inc.php';	// Load $user and permissions
+include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
+
+$langs->load("main");
+$langs->load('cashdesk');
+
+
+/*
+ * View
+ */
+
+top_httphead('text/html');
+
+$facid=GETPOST('facid','int');
+$place=GETPOST('place','int');
+if ($place>0){
+    $sql="SELECT rowid FROM ".MAIN_DB_PREFIX."facture where facnumber='(PROV-POS-".$place.")'";
+    $resql = $db->query($sql);
+    $row = $db->fetch_array ($resql);
+    $facid=$row[0];
+}
+$object=new Facture($db);
+$object->fetch($facid);
+
+// IMPORTANT: This file is sended to 'Takepos Printing' application. Keep basic file. No external files as css, js... If you need images use absolut path.
+?>
+<html>
+<body>
+<center>
+<font size="4">
+<?php echo $mysoc->name; ?>
+</font>
+</center>
+<br>
+<p align="left">
+<?php print dol_nl2br(dol_format_address($mysoc)); ?>
+</p>
+<p align="right">
+<?php
+print $langs->trans('Date')." ".dol_print_date($object->date, 'day').'<br>';
+if ($mysoc->country_code == 'ES') print "Factura simplificada ";
+print $object->ref;
+?>
+</p>
+<br>
+
+<table width="100%">
+    <thead>
+	<tr>
+        <th align="center"><?php print $langs->trans("Label"); ?></th>
+        <th align="right"><?php print $langs->trans("Qty"); ?></th>
+        <th align="right"><?php print $langs->trans("TotalTTC"); ?></th>
+	</tr>
+    </thead>
+    <tbody>
+    <?php
+    foreach ($object->lines as $line)
+    {
+    ?>
+    <tr>
+        <td><?php echo $line->product_label;?></td>
+        <td align="right"><?php echo $line->qty;?></td>
+        <td align="right"><?php echo price($line->total_ttc);?></td>
+    </tr>
+    <?php
+    }
+    ?>
+    </tbody>
+</table>
+<br>
+<table align="right">
+<tr>
+    <th align="right"><?php echo $langs->trans("TotalHT");?></th>
+    <td align="right"><?php echo price($object->total_ht, 1, '', 1, - 1, - 1, $conf->currency)."\n";?></td>
+</tr>
+<tr>
+    <th align="right"><?php echo $langs->trans("TotalVAT").'</th><td align="right">'.price($object->total_tva, 1, '', 1, - 1, - 1, $conf->currency)."\n";?></td>
+</tr>
+<tr>
+    <th align="right"><?php echo ''.$langs->trans("TotalTTC").'</th><td align="right">'.price($object->total_ttc, 1, '', 1, - 1, - 1, $conf->currency)."\n";?></td>
+</tr>
+</table>
+
+<script type="text/javascript">
+    window.print();
+</script>
+</body>
+</html>

+ 26 - 0
htdocs/takepos/sql/llx_takepos_floor_tables.sql

@@ -0,0 +1,26 @@
+-- Copyright (C) 2018 SuperAdmin
+--
+-- 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 http://www.gnu.org/licenses/.
+
+
+CREATE TABLE llx_takepos_floor_tables(
+	-- BEGIN MODULEBUILDER FIELDS
+	rowid INTEGER AUTO_INCREMENT PRIMARY KEY,
+	entity INTEGER DEFAULT 1 NOT NULL,
+	label VARCHAR(255),
+    leftpos float,
+    toppos	float,
+    floor int(3)
+	-- END MODULEBUILDER FIELDS
+) ENGINE=innodb;

+ 406 - 0
htdocs/takepos/takepos.php

@@ -0,0 +1,406 @@
+<?php
+/* Copyright (C) 2018	Andreu Bisquerra	<jove@bisquerra.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+//if (! defined('NOREQUIREUSER'))	define('NOREQUIREUSER','1');	// Not disabled cause need to load personalized language
+//if (! defined('NOREQUIREDB'))		define('NOREQUIREDB','1');		// Not disabled cause need to load personalized language
+//if (! defined('NOREQUIRESOC'))		define('NOREQUIRESOC','1');
+//if (! defined('NOREQUIRETRAN'))		define('NOREQUIRETRAN','1');
+if (! defined('NOCSRFCHECK'))		define('NOCSRFCHECK','1');
+if (! defined('NOTOKENRENEWAL'))	define('NOTOKENRENEWAL','1');
+if (! defined('NOREQUIREMENU'))		define('NOREQUIREMENU','1');
+if (! defined('NOREQUIREHTML'))		define('NOREQUIREHTML','1');
+if (! defined('NOREQUIREAJAX'))		define('NOREQUIREAJAX','1');
+
+$_GET['theme']="md"; // Force theme. MD theme provides better look and feel to TakePOS
+
+require '../main.inc.php';	// Load $user and permissions
+require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
+require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
+require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
+
+$place = GETPOST('place');
+if ($place=="") $place="0";
+$action = GETPOST('action');
+
+$langs->load("main");
+$langs->load("bills");
+$langs->load("orders");
+$langs->load("commercial");
+
+
+/*
+ * View
+ */
+
+// Title
+$title='TakePOS - Dolibarr '.DOL_VERSION;
+if (! empty($conf->global->MAIN_APPLICATION_TITLE)) $title='TakePOS - '.$conf->global->MAIN_APPLICATION_TITLE;
+top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss);
+
+?>
+<link rel="stylesheet" href="css/pos.css?a=xxx">
+<script type="text/javascript" src="js/takepos.js" ></script>
+<link rel="stylesheet" href="css/colorbox.css" type="text/css" media="screen" />
+<script type="text/javascript" src="js/jquery.colorbox-min.js"></script>
+<script language="javascript">
+<?php
+$categorie = new Categorie($db);
+$categories = $categorie->get_full_arbo('product');
+?>
+var categories = JSON.parse( '<?php echo json_encode($categories);?>' );
+var currentcat;
+var pageproducts=0;
+var pagecategories=0;
+var place="<?php echo $place;?>";
+var editaction="qty";
+var editnumber="";
+function PrintCategories(first){
+	for (i = 0; i < 14; i++) {
+		if (typeof (categories[parseInt(i)+parseInt(first)]) == "undefined") break;
+		$("#catdesc"+i).text(categories[parseInt(i)+parseInt(first)]['label']);
+        $("#catimg"+i).attr("src","genimg/?query=cat&w=55&h=50&id="+categories[parseInt(i)+parseInt(first)]['rowid']);
+        $("#catdiv"+i).data("rowid",categories[parseInt(i)+parseInt(first)]['rowid']);
+	}
+}
+
+function MoreCategories(moreorless){
+	if (moreorless=="more"){
+		$('#catimg15').animate({opacity: '0.5'}, 100);
+		$('#catimg15').animate({opacity: '1'}, 100);
+		pagecategories=pagecategories+1;
+	}
+	if (moreorless=="less"){
+		$('#catimg14').animate({opacity: '0.5'}, 100);
+		$('#catimg14').animate({opacity: '1'}, 100);
+		if (pagecategories==0) return; //Return if no less pages
+		pagecategories=pagecategories-1;
+	}
+	if (typeof (categories[14*pagecategories] && moreorless=="more") == "undefined"){ // Return if no more pages
+		pagecategories=pagecategories-1;
+		return;
+	}
+	for (i = 0; i < 14; i++) {
+		if (typeof (categories[i+(14*pagecategories)]) == "undefined"){
+				$("#catdesc"+i).text("");
+				$("#catimg"+i).attr("src","");
+				continue;
+			}
+		$("#catdesc"+i).text(categories[i+(14*pagecategories)]['label']);
+        $("#catimg"+i).attr("src","genimg/?query=cat&w=55&h=50&id="+categories[i+(14*pagecategories)]['rowid']);
+        $("#catdiv"+i).data("rowid",categories[i+(14*pagecategories)]['rowid']);
+	}
+}
+
+function LoadProducts(position){
+    $('#catimg'+position).animate({opacity: '0.5'}, 100);
+	$('#catimg'+position).animate({opacity: '1'}, 100);
+	currentcat=$('#catdiv'+position).data('rowid');
+    if (currentcat=="") return;
+	pageproducts=0;
+	$.getJSON('./ajax.php?action=getProducts&category='+currentcat, function(data) {
+		for (i = 0; i < 30; i++) {
+			if (typeof (data[i]) == "undefined"){
+				$("#prodesc"+i).text("");
+				$("#proimg"+i).attr("src","");
+                $("#prodiv"+i).data("rowid","");
+				continue;
+			}
+			$("#prodesc"+i).text(data[parseInt(i)]['label']);
+			$("#proimg"+i).attr("src","genimg/?query=pro&w=55&h=50&id="+data[i]['id']);
+			$("#prodiv"+i).data("rowid",data[i]['id']);
+		}
+	});
+}
+
+function MoreProducts(moreorless){
+	if (moreorless=="more"){
+		$('#proimg31').animate({opacity: '0.5'}, 100);
+		$('#proimg31').animate({opacity: '1'}, 100);
+		pageproducts=pageproducts+1;
+	}
+	if (moreorless=="less"){
+		$('#proimg30').animate({opacity: '0.5'}, 100);
+		$('#proimg30').animate({opacity: '1'}, 100);
+		if (pageproducts==0) return; //Return if no less pages
+		pageproducts=pageproducts-1;
+	}
+	$.getJSON('./ajax.php?action=getProducts&category='+currentcat, function(data) {
+		if (typeof (data[(30*pageproducts)]) == "undefined" && moreorless=="more"){ // Return if no more pages
+			pageproducts=pageproducts-1;
+			return;
+		}
+		for (i = 0; i < 30; i++) {
+			if (typeof (data[i+(30*pageproducts)]) == "undefined"){
+				$("#prodesc"+i).text("");
+				$("#proimg"+i).attr("src","");
+                $("#prodiv"+i).data("rowid","");
+				continue;
+			}
+			$("#prodesc"+i).text(data[parseInt(i+(30*pageproducts))]['label']);
+			$("#proimg"+i).attr("src","genimg/?query=pro&w=55&h=50&id="+data[i+(30*pageproducts)]['id']);
+			$("#prodiv"+i).data("rowid",data[i+(30*pageproducts)]['id']);
+		}
+	});
+}
+
+function ClickProduct(position){
+    $('#proimg'+position).animate({opacity: '0.5'}, 100);
+	$('#proimg'+position).animate({opacity: '1'}, 100);
+	idproduct=$('#prodiv'+position).data('rowid');
+    if (idproduct=="") return;
+	$("#poslines").load("invoice.php?action=addline&place="+place+"&idproduct="+idproduct, function() {
+		$('#poslines').scrollTop($('#poslines')[0].scrollHeight);
+	});
+
+}
+
+function deleteline(){
+	$("#poslines").load("invoice.php?action=deleteline&place="+place+"&idline="+selectedline, function() {
+		$('#poslines').scrollTop($('#poslines')[0].scrollHeight);
+	});
+}
+
+function Customer(){
+	$.colorbox({href:"customers.php?nomassaction=1&place="+place, width:"90%", height:"80%", transition:"none", iframe:"true", title:"<?php echo $langs->trans("Customer");?>"});
+}
+
+function CloseBill(){
+	$.colorbox({href:"pay.php?place="+place, width:"80%", height:"90%", transition:"none", iframe:"true", title:"<?php echo $langs->trans("CloseBill");?>"});
+}
+
+function Floors(){
+	$.colorbox({href:"floors.php?place="+place, width:"90%", height:"90%", transition:"none", iframe:"true", title:"<?php echo $langs->trans("Floors");?>"});
+}
+
+function FreeZone(){
+	$.colorbox({href:"freezone.php?place="+place, onClosed: function () { Refresh(); },width:"80%", height:"30%", transition:"none", iframe:"true", title:"<?php echo $langs->trans("FreeZone");?>"});
+}
+
+function Refresh(){
+	$("#poslines").load("invoice.php?place="+place, function() {
+		$('#poslines').scrollTop($('#poslines')[0].scrollHeight);
+	});
+}
+
+function Search(){
+	$("#poslines").load("invoice.php?action=search&place="+place, function() {
+		$('#poslines').scrollTop($('#poslines')[0].scrollHeight);
+	});
+}
+
+function Search2(){
+	pageproducts=0;
+	$.getJSON('./ajax.php?action=search&term='+$('#search').val(), function(data) {
+		for (i = 0; i < 30; i++) {
+			if (typeof (data[i]) == "undefined"){
+				$("#prodesc"+i).text("");
+				$("#proimg"+i).attr("src","");
+                $("#prodiv"+i).data("rowid","");
+				continue;
+			}
+			$("#prodesc"+i).text(data[parseInt(i)]['label']);
+			$("#proimg"+i).attr("src","genimg/?query=pro&w=55&h=50&id="+data[i]['rowid']);
+			$("#prodiv"+i).data("rowid",data[i]['rowid']);
+		}
+	});
+}
+
+function Edit(number){
+    var text=selectedtext+"<br> ";
+    if (number=='c'){
+        editnumber="";
+        Refresh();
+        return;
+    }
+    else if (number=='qty'){
+        if (editaction=='qty' && editnumber!=""){
+            $("#poslines").load("invoice.php?action=updateqty&place="+place+"&idline="+selectedline+"&number="+editnumber, function() {
+                editnumber="";
+                $('#poslines').scrollTop($('#poslines')[0].scrollHeight);
+                $("#qty").html("<?php echo $langs->trans("Qty"); ?>");
+            });
+            return;
+        }
+        else {
+            editaction="qty";
+        }
+    }
+    else if (number=='p'){
+        if (editaction=='p' && editnumber!=""){
+            $("#poslines").load("invoice.php?action=updateprice&place="+place+"&idline="+selectedline+"&number="+editnumber, function() {
+                editnumber="";
+                $('#poslines').scrollTop($('#poslines')[0].scrollHeight);
+                $("#price").html("<?php echo $langs->trans("Price"); ?>");
+            });
+            return;
+        }
+        else {
+            editaction="p";
+        }
+    }
+    else if (number=='r'){
+        if (editaction=='r' && editnumber!=""){
+            $("#poslines").load("invoice.php?action=updatereduction&place="+place+"&idline="+selectedline+"&number="+editnumber, function() {
+                editnumber="";
+                $('#poslines').scrollTop($('#poslines')[0].scrollHeight);
+                $("#reduction").html("<?php echo $langs->trans("ReductionShort"); ?>");
+            });
+            return;
+        }
+        else {
+            editaction="r";
+        }
+    }
+    else {
+        editnumber=editnumber+number;
+    }
+    if (editaction=='qty'){
+        text=text+"<?php echo $langs->trans("Modify")." -> ".$langs->trans("Qty").": "; ?>";
+        $("#qty").html("OK");
+        $("#price").html("<?php echo $langs->trans("Price"); ?>");
+        $("#reduction").html("<?php echo $langs->trans("ReductionShort"); ?>");
+    }
+    if (editaction=='p'){
+        text=text+"<?php echo $langs->trans("Modify")." -> ".$langs->trans("Price").": "; ?>";
+        $("#qty").html("<?php echo $langs->trans("Qty"); ?>");
+        $("#price").html("OK");
+        $("#reduction").html("<?php echo $langs->trans("ReductionShort"); ?>");
+    }
+    if (editaction=='r'){
+        text=text+"<?php echo $langs->trans("Modify")." -> ".$langs->trans("ReductionShort").": "; ?>";
+        $("#qty").html("<?php echo $langs->trans("Qty"); ?>");
+        $("#price").html("<?php echo $langs->trans("Price"); ?>");
+        $("#reduction").html("OK");
+    }
+    $('#'+selectedline).find("td:first").html(text+editnumber);
+}
+
+function TakeposPrintingOrder(){
+	$("#poslines").load("invoice.php?action=order&place="+place, function() {
+		$('#poslines').scrollTop($('#poslines')[0].scrollHeight);
+	});
+}
+
+$( document ).ready(function() {
+    PrintCategories(0);
+	LoadProducts(0);
+	Refresh();
+});
+</script>
+
+<body style="overflow: hidden; background-color:#E8E8E8;">
+
+<div id="poslines" style="position:absolute; top:2%; left:0.5%; height:36%; width:31%; overflow: auto;">
+</div>
+
+<div style="position:absolute; top:1%; left:32.5%; height:37%; width:32.5%;">
+    <button type="button" class="calcbutton" onclick="Edit(7);">7</button>
+    <button type="button" class="calcbutton" onclick="Edit(8);">8</button>
+    <button type="button" class="calcbutton" onclick="Edit(9);">9</button>
+    <button type="button" id="qty" class="calcbutton2" onclick="Edit('qty');"><?php echo $langs->trans("Qty"); ?></button>
+    <button type="button" class="calcbutton" onclick="Edit(4);">4</button>
+    <button type="button" class="calcbutton" onclick="Edit(5);">5</button>
+    <button type="button" class="calcbutton" onclick="Edit(6);">6</button>
+    <button type="button" id="price" class="calcbutton2" onclick="Edit('p');"><?php echo $langs->trans("Price"); ?></button>
+    <button type="button" class="calcbutton" onclick="Edit(1);">1</button>
+    <button type="button" class="calcbutton" onclick="Edit(2);">2</button>
+    <button type="button" class="calcbutton" onclick="Edit(3);">3</button>
+    <button type="button" id="reduction" class="calcbutton2" onclick="Edit('r');"><?php echo $langs->trans("ReductionShort"); ?></button>
+    <button type="button" class="calcbutton" onclick="Edit(0);">0</button>
+    <button type="button" class="calcbutton" onclick="Edit('.');">.</button>
+    <button type="button" class="calcbutton" onclick="Edit('c');">C</button>
+    <button type="button" class="calcbutton2" id="delete" style="color: red;" onclick="deleteline();"><b>X</b></button>
+</div>
+
+<?php
+// User menu and external TakePOS modules
+$menus = array();
+$r=0;
+$menus[$r++]=array('title'=>$langs->trans("SearchProduct"),
+					'action'=>'Search();');
+$menus[$r++]=array('title'=>$langs->trans("FreeZone"),
+                   'action'=>'FreeZone();');
+$menus[$r++]=array('title'=>$langs->trans("Customer"),
+					'action'=>'Customer();');
+$menus[$r++]=array('title'=>$langs->trans("BackOffice"),
+                   'action'=>'window.open(\''.DOL_URL_ROOT.'\', \'backoffice\');');
+$menus[$r++]=array('title'=>$langs->trans("ValidateBill"),
+					'action'=>'CloseBill();');
+$menus[$r++]=array('title'=>$langs->trans("Logout"),
+                   'action'=>'window.location.href=\''.DOL_URL_ROOT.'/user/logout.php\';');
+if($conf->global->TAKEPOS_BAR_RESTAURANT){
+	$menus[$r++]=array('title'=>$langs->trans("Floors"),
+					'action'=>'Floors();');
+	if ($conf->global->TAKEPOS_ORDER_PRINTERS){
+		$menus[$r++]=array('title'=>$langs->trans("Order"),
+						'action'=>'TakeposPrintingOrder();');
+	}
+}
+?>
+<div style="position:absolute; top:1%; left:65.5%; height:37%; width:32.5%;">
+<?php
+foreach($menus as $menu) {
+    echo '<button type="button" class="actionbutton" onclick="'.$menu['action'].'">'.$menu['title'].'</button>';
+}
+?>
+</div>
+
+<div style="position:absolute; top:39%; left:0.3%; height:59%; width:32%;">
+	<?php
+	$count=0;
+	while ($count<16)
+	{
+	?>
+	<div class='wrapper' <?php if ($count==14) echo 'onclick="MoreCategories(\'less\');"'; else if ($count==15) echo 'onclick="MoreCategories(\'more\');"'; else echo 'onclick="LoadProducts('.$count.');"';?> id='catdiv<?php echo $count;?>'>
+		<img class='imgwrapper' <?php if ($count==14) echo 'src="img/arrow-prev-top.png"'; if ($count==15) echo 'src="img/arrow-next-top.png"';?> width="98%" id='catimg<?php echo $count;?>'/>
+		<div class='description'>
+			<div class='description_content' id='catdesc<?php echo $count;?>'></div>
+		</div>
+	</div>
+	<?php
+    $count++;
+	}
+	?>
+</div>
+
+<div style="position:absolute; top:39%; left:32%; height:58%; width:72%;">
+<?php
+$count=0;
+while ($count<32)
+	{
+	?>
+	<div class='wrapper2' id='prodiv<?php echo $count;?>' <?php if ($count==30) {?> onclick="MoreProducts('less');" <?php } if ($count==31) {?> onclick="MoreProducts('more');" <?php } else echo 'onclick="ClickProduct('.$count.');"';?>>
+		<img class='imgwrapper' <?php if ($count==30) echo 'src="img/arrow-prev-top.png"'; if ($count==31) echo 'src="img/arrow-next-top.png"';?> width="95%" id='proimg<?php echo $count;?>'/>
+		<div class='description'>
+			<div class='description_content' id='prodesc<?php echo $count;?>'></div>
+		</div>
+	</div>
+	<?php
+	$count++;
+	}
+?>
+</div>
+
+</body>
+<?php
+
+llxFooter();
+
+$db->close();
+
+
+

+ 289 - 0
htdocs/takepos/test/phpunit/TakePosFunctionalTest.php

@@ -0,0 +1,289 @@
+<?php
+/* Copyright (C) 2007-2017 Laurent Destailleur  <eldy@users.sourceforge.net>
+ * Copyright (C) 2018 SuperAdmin
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file    test/functional/TakePosFunctionalTest.php
+ * \ingroup takepos
+ * \brief   Example Selenium test.
+ *
+ * Put detailed description here.
+ */
+
+namespace test\functional;
+
+use PHPUnit_Extensions_Selenium2TestCase_WebDriverException;
+
+/**
+ * Class TakePosFunctionalTest
+ *
+ * Requires chromedriver for Google Chrome
+ * Requires geckodriver for Mozilla Firefox
+ *
+ * @fixme Firefox (Geckodriver/Marionette) support
+ * @todo Opera linux support
+ * @todo Windows support (IE, Google Chrome, Mozilla Firefox, Safari)
+ * @todo OSX support (Safari, Google Chrome, Mozilla Firefox)
+ *
+ * @package Testtakepos
+ */
+class TakePosFunctionalTest extends \PHPUnit_Extensions_Selenium2TestCase
+{
+	// TODO: move to a global configuration file?
+	/** @var string Base URL of the webserver under test */
+	protected static $base_url = 'http://dev.zenfusion.fr';
+	/**
+	 * @var string Dolibarr admin username
+	 * @see authenticate
+	 */
+	protected static $dol_admin_user = 'admin';
+	/**
+	 * @var string Dolibarr admin password
+	 * @see authenticate
+	 */
+	protected static $dol_admin_pass = 'admin';
+	/** @var int Dolibarr module ID */
+	private static $module_id = 500000; // TODO: autodetect?
+
+	/** @var array Browsers to test with */
+	public static $browsers = array(
+		array(
+			'browser' => 'Google Chrome on Linux',
+			'browserName' => 'chrome',
+			'sessionStrategy' => 'shared',
+			'desiredCapabilities' => array()
+		),
+		// Geckodriver does not keep the session at the moment?!
+		// XPath selectors also don't seem to work
+//        array(
+//            'browser' => 'Mozilla Firefox on Linux',
+//            'browserName' => 'firefox',
+//            'sessionStrategy' => 'shared',
+//            'desiredCapabilities' => array(
+//                'marionette' => true
+//            )
+//        )
+	);
+
+	/**
+	 * Helper function to select links by href
+	 *
+	 * @param  string  $value      Href
+	 * @return mixed               Helper string
+	 */
+	protected function byHref($value)
+	{
+		$anchor = null;
+		$anchors = $this->elements($this->using('tag name')->value('a'));
+		foreach ($anchors as $anchor) {
+			if (strstr($anchor->attribute('href'), $value)) {
+				break;
+			}
+		}
+		return $anchor;
+	}
+
+	/**
+	 * Global test setup
+	 */
+	public static function setUpBeforeClass()
+	{
+	}
+
+	/**
+	 * Unit test setup
+	 */
+	public function setUp()
+	{
+		$this->setSeleniumServerRequestsTimeout(3600);
+		$this->setBrowserUrl(self::$base_url);
+	}
+
+	/**
+	 * Verify pre conditions
+	 */
+	protected function assertPreConditions()
+	{
+	}
+
+	/**
+	 * Handle Dolibarr authentication
+	 */
+	private function authenticate()
+	{
+		try {
+			if ($this->byId('login')) {
+				$login = $this->byId('username');
+				$login->clear();
+				$login->value('admin');
+				$password = $this->byId('password');
+				$password->clear();
+				$password->value('admin');
+				$this->byId('login')->submit();
+			}
+		} catch (PHPUnit_Extensions_Selenium2TestCase_WebDriverException $e) {
+			// Login does not exist. Assume we are already authenticated
+		}
+	}
+
+	/**
+	 * Test enabling developer mode
+	 */
+	public function testEnableDeveloperMode()
+	{
+		$this->url('/admin/const.php');
+		$this->authenticate();
+		$main_features_level_path='//input[@value="MAIN_FEATURES_LEVEL"]/following::input[@type="text"]';
+		$main_features_level = $this->byXPath($main_features_level_path);
+		$main_features_level->clear();
+		$main_features_level->value('2');
+		$this->byName('update')->click();
+		// Page reloaded, we need a new XPath
+		$main_features_level = $this->byXPath($main_features_level_path);
+		return $this->assertEquals('2', $main_features_level->value(), "MAIN_FEATURES_LEVEL value is 2");
+	}
+
+	/**
+	 * Test enabling the module
+	 *
+	 * @depends testEnableDeveloperMode
+	 */
+	public function testModuleEnabled()
+	{
+		$this->url('/admin/modules.php');
+		$this->authenticate();
+		$module_status_image_path='//a[contains(@href, "' . self::$module_id . '")]/img';
+		$module_status_image = $this->byXPath($module_status_image_path);
+		if (strstr($module_status_image->attribute('src'), 'switch_off.png')) {
+			// Enable the module
+			$this->byHref('modTakePos')->click();
+		} else {
+			// Disable the module
+			$this->byHref('modTakePos')->click();
+			// Reenable the module
+			$this->byHref('modTakePos')->click();
+		}
+		// Page reloaded, we need a new Xpath
+		$module_status_image = $this->byXPath($module_status_image_path);
+		return $this->assertContains('switch_on.png', $module_status_image->attribute('src'), "Module enabled");
+	}
+
+	/**
+	 * Test access to the configuration page
+	 *
+	 * @depends testModuleEnabled
+	 */
+	public function testConfigurationPage()
+	{
+		$this->url('/custom/takepos/admin/setup.php');
+		$this->authenticate();
+		return $this->assertContains('takepos/admin/setup.php', $this->url(), 'Configuration page');
+	}
+
+	/**
+	 * Test access to the about page
+	 *
+	 * @depends testConfigurationPage
+	 */
+	public function testAboutPage()
+	{
+		$this->url('/custom/takepos/admin/about.php');
+		$this->authenticate();
+		return $this->assertContains('takepos/admin/about.php', $this->url(), 'About page');
+	}
+
+	/**
+	 * Test about page is rendering Markdown
+	 *
+	 * @depends testAboutPage
+	 */
+	public function testAboutPageRendersMarkdownReadme()
+	{
+		$this->url('/custom/takepos/admin/about.php');
+		$this->authenticate();
+		return $this->assertEquals(
+			'Dolibarr Module Template (aka My Module)',
+			$this->byTag('h1')->text(),
+			"Readme title"
+		);
+	}
+
+	/**
+	 * Test box is properly declared
+	 *
+	 * @depends testModuleEnabled
+	 */
+	public function testBoxDeclared()
+	{
+		$this->url('/admin/boxes.php');
+		$this->authenticate();
+		return $this->assertContains('takeposwidget1', $this->source(), "Box enabled");
+	}
+
+	/**
+	 * Test trigger is properly enabled
+	 *
+	 * @depends testModuleEnabled
+	 */
+	public function testTriggerDeclared()
+	{
+		$this->url('/admin/triggers.php');
+		$this->authenticate();
+		return $this->assertContains(
+			'interface_99_modTakePos_TakePosTriggers.class.php',
+			$this->byTag('body')->text(),
+			"Trigger declared"
+		);
+	}
+
+	/**
+	 * Test trigger is properly declared
+	 *
+	 * @depends testTriggerDeclared
+	 */
+	public function testTriggerEnabled()
+	{
+		$this->url('/admin/triggers.php');
+		$this->authenticate();
+		return $this->assertContains(
+			'tick.png',
+			$this->byXPath('//td[text()="interface_99_modTakePos_MyTrigger.class.php"]/following::img')->attribute('src'),
+			"Trigger enabled"
+		);
+	}
+
+	/**
+	 * Verify post conditions
+	 */
+	protected function assertPostConditions()
+	{
+	}
+
+	/**
+	 * Unit test teardown
+	 */
+	public function tearDown()
+	{
+	}
+
+	/**
+	 * Global test teardown
+	 */
+	public static function tearDownAfterClass()
+	{
+	}
+}

+ 5 - 1
htdocs/theme/eldy/style.css.php

@@ -1707,6 +1707,10 @@ div.mainmenu.cashdesk {
 	background-image: url(<?php echo dol_buildpath($path.'/theme/'.$theme.'/img/menus/pointofsale_over.png',1) ?>);
 }
 
+div.mainmenu.takepos {
+	background-image: url(<?php echo dol_buildpath($path.'/theme/'.$theme.'/img/menus/pointofsale_over.png',1) ?>);
+}
+
 div.mainmenu.companies {
 	background-image: url(<?php echo dol_buildpath($path.'/theme/'.$theme.'/img/menus/company_over.png',1) ?>);
 }
@@ -1776,7 +1780,7 @@ $mainmenuusedarray=array_unique(explode(',',$mainmenuused));
 
 $generic=1;
 // Put here list of menu entries when the div.mainmenu.menuentry was previously defined
-$divalreadydefined=array('home','companies','products','commercial','externalsite','accountancy','project','tools','members','agenda','ftp','holiday','hrm','bookmark','cashdesk','ecm','geoipmaxmind','gravatar','clicktodial','paypal','stripe','webservices','website');
+$divalreadydefined=array('home','companies','products','commercial','externalsite','accountancy','project','tools','members','agenda','ftp','holiday','hrm','bookmark','cashdesk','takepos','ecm','geoipmaxmind','gravatar','clicktodial','paypal','stripe','webservices','website');
 // Put here list of menu entries we are sure we don't want
 $divnotrequired=array('multicurrency','salaries','ticket','margin','opensurvey','paybox','expensereport','incoterm','prelevement','propal','workflow','notification','supplier_proposal','cron','product','productbatch','expedition');
 foreach($mainmenuusedarray as $val)

+ 5 - 1
htdocs/theme/md/style.css.php

@@ -1696,6 +1696,10 @@ div.mainmenu.cashdesk {
 	background-image: url(<?php echo dol_buildpath($path.'/theme/'.$theme.'/img/menus/pointofsale.png',1) ?>);
 }
 
+div.mainmenu.takepos {
+	background-image: url(<?php echo dol_buildpath($path.'/theme/'.$theme.'/img/menus/pointofsale.png',1) ?>);
+}
+
 div.mainmenu.companies {
 	background-image: url(<?php echo dol_buildpath($path.'/theme/'.$theme.'/img/menus/company.png',1) ?>);
 }
@@ -1769,7 +1773,7 @@ $mainmenuusedarray=array_unique(explode(',',$mainmenuused));
 
 $generic=1;
 // Put here list of menu entries when the div.mainmenu.menuentry was previously defined
-$divalreadydefined=array('home','companies','products','commercial','externalsite','accountancy','project','tools','members','agenda','ftp','holiday','hrm','bookmark','cashdesk','ecm','geoipmaxmind','gravatar','clicktodial','paypal','stripe','webservices','website');
+$divalreadydefined=array('home','companies','products','commercial','externalsite','accountancy','project','tools','members','agenda','ftp','holiday','hrm','bookmark','cashdesk','takepos','ecm','geoipmaxmind','gravatar','clicktodial','paypal','stripe','webservices','website');
 // Put here list of menu entries we are sure we don't want
 $divnotrequired=array('multicurrency','salaries','ticket','margin','opensurvey','paybox','expensereport','incoterm','prelevement','propal','workflow','notification','supplier_proposal','cron','product','productbatch','expedition');
 foreach($mainmenuusedarray as $val)

Vissa filer visades inte eftersom för många filer har ändrats