ajax.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. <?php
  2. /* Copyright (C) 2001-2004 Andreu Bisquerra <jove@bisquerra.com>
  3. * Copyright (C) 2020 Thibault FOUCART <support@ptibogxiv.net>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. /**
  19. * \file htdocs/takepos/ajax/ajax.php
  20. * \brief Ajax search component for TakePos. It search products of a category.
  21. */
  22. if (!defined('NOTOKENRENEWAL')) {
  23. define('NOTOKENRENEWAL', '1');
  24. }
  25. if (!defined('NOREQUIREMENU')) {
  26. define('NOREQUIREMENU', '1');
  27. }
  28. if (!defined('NOREQUIREHTML')) {
  29. define('NOREQUIREHTML', '1');
  30. }
  31. if (!defined('NOREQUIREAJAX')) {
  32. define('NOREQUIREAJAX', '1');
  33. }
  34. if (!defined('NOBROWSERNOTIF')) {
  35. define('NOBROWSERNOTIF', '1');
  36. }
  37. // Load Dolibarr environment
  38. require '../../main.inc.php'; // Load $user and permissions
  39. require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
  40. require_once DOL_DOCUMENT_ROOT."/product/class/product.class.php";
  41. $category = GETPOST('category', 'alphanohtml'); // Can be id of category or 'supplements'
  42. $action = GETPOST('action', 'aZ09');
  43. $term = GETPOST('term', 'alpha');
  44. $id = GETPOST('id', 'int');
  45. $search_start = GETPOST('search_start', 'int');
  46. $search_limit = GETPOST('search_limit', 'int');
  47. if (empty($user->rights->takepos->run)) {
  48. accessforbidden();
  49. }
  50. // Initialize technical object to manage hooks. Note that conf->hooks_modules contains array of hooks
  51. $hookmanager->initHooks(array('takeposproductsearch')); // new context for product search hooks
  52. /*
  53. * View
  54. */
  55. if ($action == 'getProducts') {
  56. top_httphead('application/json');
  57. $object = new Categorie($db);
  58. if ($category == "supplements") {
  59. $category = getDolGlobalInt('TAKEPOS_SUPPLEMENTS_CATEGORY');
  60. }
  61. $result = $object->fetch($category);
  62. if ($result > 0) {
  63. $prods = $object->getObjectsInCateg("product", 0, 0, 0, getDolGlobalString('TAKEPOS_SORTPRODUCTFIELD'), 'ASC');
  64. // Removed properties we don't need
  65. $res = array();
  66. if (is_array($prods) && count($prods) > 0) {
  67. foreach ($prods as $prod) {
  68. if (getDolGlobalInt('TAKEPOS_PRODUCT_IN_STOCK') == 1) {
  69. // remove products without stock
  70. $prod->load_stock('nobatch,novirtual');
  71. if ($prod->stock_warehouse[getDolGlobalString('CASHDESK_ID_WAREHOUSE'.$_SESSION['takeposterminal'])]->real <= 0) {
  72. continue;
  73. }
  74. }
  75. unset($prod->fields);
  76. unset($prod->db);
  77. $prod->price_formated = price(price2num($prod->price, 'MT'), 1, $langs, 1, -1, -1, $conf->currency);
  78. $prod->price_ttc_formated = price(price2num($prod->price_ttc, 'MT'), 1, $langs, 1, -1, -1, $conf->currency);
  79. $res[] = $prod;
  80. }
  81. }
  82. echo json_encode($res);
  83. } else {
  84. echo 'Failed to load category with id='.dol_escape_htmltag($category);
  85. }
  86. } elseif ($action == 'search' && $term != '') {
  87. top_httphead('application/json');
  88. // Change thirdparty with barcode
  89. require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
  90. $thirdparty = new Societe($db);
  91. $result = $thirdparty->fetch('', '', '', $term);
  92. if ($result && $thirdparty->id > 0) {
  93. $rows = array();
  94. $rows[] = array(
  95. 'rowid' => $thirdparty->id,
  96. 'name' => $thirdparty->name,
  97. 'barcode' => $thirdparty->barcode,
  98. 'object' => 'thirdparty'
  99. );
  100. echo json_encode($rows);
  101. exit;
  102. }
  103. // Define $filteroncategids, the filter on category ID if there is a Root category defined.
  104. $filteroncategids = '';
  105. if ($conf->global->TAKEPOS_ROOT_CATEGORY_ID > 0) { // A root category is defined, we must filter on products inside this category tree
  106. $object = new Categorie($db);
  107. //$result = $object->fetch($conf->global->TAKEPOS_ROOT_CATEGORY_ID);
  108. $arrayofcateg = $object->get_full_arbo('product', $conf->global->TAKEPOS_ROOT_CATEGORY_ID, 1);
  109. if (is_array($arrayofcateg) && count($arrayofcateg) > 0) {
  110. foreach ($arrayofcateg as $val) {
  111. $filteroncategids .= ($filteroncategids ? ', ' : '').$val['id'];
  112. }
  113. }
  114. }
  115. $barcode_rules = getDolGlobalString('TAKEPOS_BARCODE_RULE_TO_INSERT_PRODUCT');
  116. if (isModEnabled('barcode') && !empty($barcode_rules)) {
  117. $barcode_rules_list = array();
  118. // get barcode rules
  119. $barcode_char_nb = 0;
  120. $barcode_rules_arr = explode('+', $barcode_rules);
  121. foreach ($barcode_rules_arr as $barcode_rules_values) {
  122. $barcode_rules_values_arr = explode(':', $barcode_rules_values);
  123. if (count($barcode_rules_values_arr) == 2) {
  124. $char_nb = intval($barcode_rules_values_arr[1]);
  125. $barcode_rules_list[] = array('code' => $barcode_rules_values_arr[0], 'char_nb' => $char_nb);
  126. $barcode_char_nb += $char_nb;
  127. }
  128. }
  129. $barcode_value_list = array();
  130. $barcode_offset = 0;
  131. $barcode_length = dol_strlen($term);
  132. if ($barcode_length == $barcode_char_nb) {
  133. $rows = array();
  134. // split term with barcode rules
  135. foreach ($barcode_rules_list as $barcode_rule_arr) {
  136. $code = $barcode_rule_arr['code'];
  137. $char_nb = $barcode_rule_arr['char_nb'];
  138. $barcode_value_list[$code] = substr($term, $barcode_offset, $char_nb);
  139. $barcode_offset += $char_nb;
  140. }
  141. if (isset($barcode_value_list['ref'])) {
  142. // search product from reference
  143. $sql = "SELECT rowid, ref, label, tosell, tobuy, barcode, price, price_ttc";
  144. $sql .= " FROM " . $db->prefix() . "product as p";
  145. $sql .= " WHERE entity IN (" . getEntity('product') . ")";
  146. $sql .= " AND ref = '" . $db->escape($barcode_value_list['ref']) . "'";
  147. if ($filteroncategids) {
  148. $sql .= " AND EXISTS (SELECT cp.fk_product FROM " . $db->prefix() . "categorie_product as cp WHERE cp.fk_product = p.rowid AND cp.fk_categorie IN (".$db->sanitize($filteroncategids)."))";
  149. }
  150. $sql .= " AND tosell = 1";
  151. $sql .= " AND (barcode IS NULL OR barcode != '" . $db->escape($term) . "')";
  152. $resql = $db->query($sql);
  153. if ($resql && $db->num_rows($resql) == 1) {
  154. if ($obj = $db->fetch_object($resql)) {
  155. $qty = 1;
  156. if (isset($barcode_value_list['qu'])) {
  157. $qty_str = $barcode_value_list['qu'];
  158. if (isset($barcode_value_list['qd'])) {
  159. $qty_str .= '.' . $barcode_value_list['qd'];
  160. }
  161. $qty = floatval($qty_str);
  162. }
  163. $ig = '../public/theme/common/nophoto.png';
  164. if (empty($conf->global->TAKEPOS_HIDE_PRODUCT_IMAGES)) {
  165. $objProd = new Product($db);
  166. $objProd->fetch($obj->rowid);
  167. $image = $objProd->show_photos('product', $conf->product->multidir_output[$objProd->entity], 'small', 1);
  168. $match = array();
  169. preg_match('@src="([^"]+)"@', $image, $match);
  170. $file = array_pop($match);
  171. if ($file != '') {
  172. if (!defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
  173. $ig = $file.'&cache=1';
  174. } else {
  175. $ig = $file.'&cache=1&publictakepos=1&modulepart=product';
  176. }
  177. }
  178. }
  179. $rows[] = array(
  180. 'rowid' => $obj->rowid,
  181. 'ref' => $obj->ref,
  182. 'label' => $obj->label,
  183. 'tosell' => $obj->tosell,
  184. 'tobuy' => $obj->tobuy,
  185. 'barcode' => $obj->barcode,
  186. 'price' => $obj->price,
  187. 'price_ttc' => $obj->price_ttc,
  188. 'object' => 'product',
  189. 'img' => $ig,
  190. 'qty' => $qty,
  191. );
  192. }
  193. $db->free($resql);
  194. }
  195. }
  196. if (count($rows) == 1) {
  197. echo json_encode($rows);
  198. exit();
  199. }
  200. }
  201. }
  202. $sql = 'SELECT p.rowid, p.ref, p.label, p.tosell, p.tobuy, p.barcode, p.price, p.price_ttc' ;
  203. if (getDolGlobalInt('TAKEPOS_PRODUCT_IN_STOCK') == 1) {
  204. $sql .= ', ps.reel';
  205. }
  206. // Add fields from hooks
  207. $parameters = array();
  208. $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters);
  209. if ($reshook >= 0) {
  210. $sql .= $hookmanager->resPrint;
  211. }
  212. $sql .= ' FROM '.MAIN_DB_PREFIX.'product as p';
  213. if (getDolGlobalInt('TAKEPOS_PRODUCT_IN_STOCK') == 1) {
  214. $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_stock as ps';
  215. $sql .= ' ON (p.rowid = ps.fk_product';
  216. $sql .= " AND ps.fk_entrepot = ".((int) getDolGlobalInt("CASHDESK_ID_WAREHOUSE".$_SESSION['takeposterminal']));
  217. }
  218. // Add tables from hooks
  219. $parameters = array();
  220. $reshook = $hookmanager->executeHooks('printFieldListTables', $parameters);
  221. if ($reshook >= 0) {
  222. $sql .= $hookmanager->resPrint;
  223. }
  224. $sql .= ' WHERE entity IN ('.getEntity('product').')';
  225. if ($filteroncategids) {
  226. $sql .= ' AND EXISTS (SELECT cp.fk_product FROM '.MAIN_DB_PREFIX.'categorie_product as cp WHERE cp.fk_product = p.rowid AND cp.fk_categorie IN ('.$db->sanitize($filteroncategids).'))';
  227. }
  228. $sql .= ' AND tosell = 1';
  229. if (getDolGlobalInt('TAKEPOS_PRODUCT_IN_STOCK') == 1) {
  230. $sql .= ' AND ps.reel > 0';
  231. }
  232. $sql .= natural_search(array('ref', 'label', 'barcode'), $term);
  233. // Add where from hooks
  234. $parameters = array();
  235. $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters);
  236. if ($reshook >= 0) {
  237. $sql .= $hookmanager->resPrint;
  238. }
  239. // load only one page of products
  240. $sql.= $db->plimit($search_limit, $search_start);
  241. $resql = $db->query($sql);
  242. if ($resql) {
  243. $rows = array();
  244. while ($obj = $db->fetch_object($resql)) {
  245. $objProd = new Product($db);
  246. $objProd->fetch($obj->rowid);
  247. $image = $objProd->show_photos('product', $conf->product->multidir_output[$objProd->entity], 'small', 1);
  248. $match = array();
  249. preg_match('@src="([^"]+)"@', $image, $match);
  250. $file = array_pop($match);
  251. if ($file == "") {
  252. $ig = '../public/theme/common/nophoto.png';
  253. } else {
  254. if (!defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
  255. $ig = $file.'&cache=1';
  256. } else {
  257. $ig = $file.'&cache=1&publictakepos=1&modulepart=product';
  258. }
  259. }
  260. $row = array(
  261. 'rowid' => $obj->rowid,
  262. 'ref' => $obj->ref,
  263. 'label' => $obj->label,
  264. 'tosell' => $obj->tosell,
  265. 'tobuy' => $obj->tobuy,
  266. 'barcode' => $obj->barcode,
  267. 'price' => $obj->price,
  268. 'price_ttc' => $obj->price_ttc,
  269. 'object' => 'product',
  270. 'img' => $ig,
  271. 'qty' => 1,
  272. 'price_formated' => price(price2num($obj->price, 'MT'), 1, $langs, 1, -1, -1, $conf->currency),
  273. 'price_ttc_formated' => price(price2num($obj->price_ttc, 'MT'), 1, $langs, 1, -1, -1, $conf->currency)
  274. );
  275. // Add entries to row from hooks
  276. $parameters=array();
  277. $parameters['row'] = $row;
  278. $parameters['obj'] = $obj;
  279. $reshook = $hookmanager->executeHooks('completeAjaxReturnArray', $parameters);
  280. if ($reshook > 0) {
  281. // replace
  282. if (count($hookmanager->resArray)) {
  283. $row = $hookmanager->resArray;
  284. } else {
  285. $row = array();
  286. }
  287. } else {
  288. // add
  289. if (count($hookmanager->resArray)) {
  290. $rows[] = $hookmanager->resArray;
  291. }
  292. $rows[] = $row;
  293. }
  294. }
  295. echo json_encode($rows);
  296. } else {
  297. echo 'Failed to search product : '.$db->lasterror();
  298. }
  299. } elseif ($action == "opendrawer" && $term != '') {
  300. require_once DOL_DOCUMENT_ROOT.'/core/class/dolreceiptprinter.class.php';
  301. $printer = new dolReceiptPrinter($db);
  302. // check printer for terminal
  303. if (getDolGlobalInt('TAKEPOS_PRINTER_TO_USE'.$term) > 0) {
  304. $printer->initPrinter(getDolGlobalInt('TAKEPOS_PRINTER_TO_USE'.$term));
  305. // open cashdrawer
  306. $printer->pulse();
  307. $printer->close();
  308. }
  309. } elseif ($action == "printinvoiceticket" && $term != '' && $id > 0 && !empty($user->rights->facture->lire)) {
  310. require_once DOL_DOCUMENT_ROOT.'/core/class/dolreceiptprinter.class.php';
  311. require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
  312. $printer = new dolReceiptPrinter($db);
  313. // check printer for terminal
  314. if ((getDolGlobalInt('TAKEPOS_PRINTER_TO_USE'.$term) > 0 || getDolGlobalString('TAKEPOS_PRINT_METHOD') == "takeposconnector") && getDolGlobalInt('TAKEPOS_TEMPLATE_TO_USE_FOR_INVOICES'.$term) > 0) {
  315. $object = new Facture($db);
  316. $object->fetch($id);
  317. $ret = $printer->sendToPrinter($object, getDolGlobalString('TAKEPOS_TEMPLATE_TO_USE_FOR_INVOICES'.$term), getDolGlobalString('TAKEPOS_PRINTER_TO_USE'.$term));
  318. }
  319. } elseif ($action == 'getInvoice') {
  320. top_httphead('application/json');
  321. require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
  322. $object = new Facture($db);
  323. if ($id > 0) {
  324. $object->fetch($id);
  325. }
  326. echo json_encode($object);
  327. } elseif ($action == 'thecheck') {
  328. $place = GETPOST('place', 'alpha');
  329. require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
  330. require_once DOL_DOCUMENT_ROOT.'/core/class/dolreceiptprinter.class.php';
  331. $printer = new dolReceiptPrinter($db);
  332. $printer->sendToPrinter($object, getDolGlobalString('TAKEPOS_TEMPLATE_TO_USE_FOR_INVOICES'.$term), getDolGlobalString('TAKEPOS_PRINTER_TO_USE'.$term));
  333. }