dispatch.php 59 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445
  1. <?php
  2. /* Copyright (C) 2004-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  3. * Copyright (C) 2004-2016 Laurent Destailleur <eldy@users.sourceforge.net>
  4. * Copyright (C) 2005 Eric Seigne <eric.seigne@ryxeo.com>
  5. * Copyright (C) 2005-2009 Regis Houssin <regis.houssin@inodbox.com>
  6. * Copyright (C) 2010-2021 Juanjo Menent <jmenent@2byte.es>
  7. * Copyright (C) 2014 Cedric Gross <c.gross@kreiz-it.fr>
  8. * Copyright (C) 2016 Florian Henry <florian.henry@atm-consulting.fr>
  9. * Copyright (C) 2017-2022 Ferran Marcet <fmarcet@2byte.es>
  10. * Copyright (C) 2018-2022 Frédéric France <frederic.france@netlogic.fr>
  11. * Copyright (C) 2019-2020 Christophe Battarel <christophe@altairis.fr>
  12. *
  13. * This program is free software; you can redistribute it and/or modify
  14. * it under the terms of the GNU General Public License as published by
  15. * the Free Software Foundation; either version 3 of the License, or
  16. * (at your option) any later version.
  17. *
  18. * This program is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU General Public License
  24. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  25. */
  26. /**
  27. * \file htdocs/expedition/dispatch.php
  28. * \ingroup expedition
  29. * \brief Page to dispatch shipments
  30. */
  31. // Load Dolibarr environment
  32. require '../main.inc.php';
  33. require_once DOL_DOCUMENT_ROOT.'/core/modules/supplier_order/modules_commandefournisseur.php';
  34. require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
  35. require_once DOL_DOCUMENT_ROOT.'/core/lib/fourn.lib.php';
  36. require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
  37. require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.dispatch.class.php';
  38. require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
  39. require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
  40. require_once DOL_DOCUMENT_ROOT.'/core/lib/sendings.lib.php';
  41. if (isModEnabled('project')) {
  42. require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
  43. }
  44. // Load translation files required by the page
  45. $langs->loadLangs(array("sendings", "companies", "bills", 'deliveries', 'orders', 'stocks', 'other', 'propal', 'receptions'));
  46. if (isModEnabled('productbatch')) {
  47. $langs->load('productbatch');
  48. }
  49. // Security check
  50. $id = GETPOST("id", 'int');
  51. $ref = GETPOST('ref');
  52. $lineid = GETPOST('lineid', 'int');
  53. $action = GETPOST('action', 'aZ09');
  54. $fk_default_warehouse = GETPOST('fk_default_warehouse', 'int');
  55. $cancel = GETPOST('cancel', 'alpha');
  56. $confirm = GETPOST('confirm', 'alpha');
  57. $error = 0;
  58. $errors = array();
  59. if ($user->socid) {
  60. $socid = $user->socid;
  61. }
  62. $hookmanager->initHooks(array('expeditiondispatch'));
  63. // Recuperation de l'id de projet
  64. $projectid = 0;
  65. if (GETPOSTISSET("projectid")) {
  66. $projectid = GETPOST("projectid", 'int');
  67. }
  68. $object = new Expedition($db);
  69. $objectorder = new Commande($db);
  70. if ($id > 0 || !empty($ref)) {
  71. $result = $object->fetch($id, $ref);
  72. if ($result <= 0) {
  73. setEventMessages($object->error, $object->errors, 'errors');
  74. }
  75. $result = $object->fetch_thirdparty();
  76. if ($result < 0) {
  77. setEventMessages($object->error, $object->errors, 'errors');
  78. }
  79. if (!empty($object->origin)) {
  80. $origin = $object->origin;
  81. $object->fetch_origin();
  82. $typeobject = $object->origin;
  83. }
  84. }
  85. // $id is id of a purchase order.
  86. $result = restrictedArea($user, 'expedition', $object, '');
  87. if (!isModEnabled('stock')) {
  88. accessforbidden('Module stock disabled');
  89. }
  90. $usercancreate = $user->hasRight('expedition', 'creer');
  91. $permissiontoadd = $usercancreate; // Used by the include of actions_addupdatedelete.inc.php
  92. /*
  93. * Actions
  94. */
  95. $parameters = array();
  96. $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
  97. if ($reshook < 0) {
  98. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  99. }
  100. // Update a dispatched line
  101. if ($action == 'updatelines' && $usercancreate) {
  102. $db->begin();
  103. $error = 0;
  104. $expeditiondispatch = new ExpeditionLigne($db);
  105. $expeditionlinebatch = new ExpeditionLineBatch($db);
  106. $pos = 0;
  107. foreach ($_POST as $key => $value) {
  108. // without batch module enabled
  109. $reg = array();
  110. if (preg_match('/^product_.*([0-9]+)_([0-9]+)$/i', $key, $reg)) {
  111. $pos++;
  112. if (preg_match('/^product_([0-9]+)_([0-9]+)$/i', $key, $reg)) {
  113. $modebatch = "barcode";
  114. } elseif (preg_match('/^product_batch_([0-9]+)_([0-9]+)$/i', $key, $reg)) { // With batchmode enabled
  115. $modebatch = "batch";
  116. }
  117. $numline = $pos;
  118. if ($modebatch == "barcode") {
  119. $prod = "product_".$reg[1].'_'.$reg[2];
  120. } else {
  121. $prod = 'product_batch_'.$reg[1].'_'.$reg[2];
  122. }
  123. $qty = "qty_".$reg[1].'_'.$reg[2];
  124. $ent = "entrepot_".$reg[1].'_'.$reg[2];
  125. $fk_commandedet = "fk_commandedet_".$reg[1].'_'.$reg[2];
  126. $idline = GETPOST("idline_".$reg[1].'_'.$reg[2]);
  127. $warehouse_id = GETPOSTINT($ent);
  128. $prod_id = GETPOSTINT($prod);
  129. //$pu = "pu_".$reg[1].'_'.$reg[2]; // This is unit price including discount
  130. $lot = '';
  131. $dDLUO = '';
  132. $dDLC = '';
  133. if ($modebatch == "batch") { //TODO: Make impossible to input non existing batch code
  134. $lot = GETPOST('lot_number_'.$reg[1].'_'.$reg[2]);
  135. $dDLUO = dol_mktime(12, 0, 0, GETPOST('dluo_'.$reg[1].'_'.$reg[2].'month', 'int'), GETPOST('dluo_'.$reg[1].'_'.$reg[2].'day', 'int'), GETPOST('dluo_'.$reg[1].'_'.$reg[2].'year', 'int'));
  136. $dDLC = dol_mktime(12, 0, 0, GETPOST('dlc_'.$reg[1].'_'.$reg[2].'month', 'int'), GETPOST('dlc_'.$reg[1].'_'.$reg[2].'day', 'int'), GETPOST('dlc_'.$reg[1].'_'.$reg[2].'year', 'int'));
  137. }
  138. $newqty = price2num(GETPOST($qty, 'alpha'), 'MS');
  139. //var_dump("modebatch=".$modebatch." newqty=".$newqty." ent=".$ent." idline=".$idline);
  140. // We ask to move a qty
  141. if (($modebatch == "batch" && $newqty >= 0) || ($modebatch == "barcode" && $newqty != 0)) {
  142. if ($newqty > 0) { // If we want a qty, we make test on input data
  143. if (!($warehouse_id > 0)) {
  144. dol_syslog('No dispatch for line '.$key.' as no warehouse was chosen.');
  145. $text = $langs->transnoentities('Warehouse').', '.$langs->transnoentities('Line').' '.($numline);
  146. setEventMessages($langs->trans('ErrorFieldRequired', $text), null, 'errors');
  147. $error++;
  148. }
  149. if (!$error && $modebatch == "batch") {
  150. $sql = "SELECT pb.rowid ";
  151. $sql .= " FROM ".MAIN_DB_PREFIX."product_batch as pb";
  152. $sql .= " JOIN ".MAIN_DB_PREFIX."product_stock as ps";
  153. $sql .= " ON ps.rowid = pb.fk_product_stock";
  154. $sql .= " WHERE pb.batch = '".$db->escape($lot)."'";
  155. $sql .= " AND ps.fk_product = ".((int) $prod_id) ;
  156. $sql .= " AND ps.fk_entrepot = ".((int) $warehouse_id) ;
  157. $resql = $db->query($sql);
  158. if ($resql) {
  159. $num = $db->num_rows($resql);
  160. if ($num > 1) {
  161. dol_syslog('No dispatch for line '.$key.' as too many combination warehouse, product, batch code was found ('.$num.').');
  162. setEventMessages($langs->trans('ErrorTooManyCombinationBatchcode', $numline, $num), null, 'errors');
  163. $error++;
  164. } elseif ($num < 1) {
  165. $tmpwarehouse = new Entrepot($db);
  166. $tmpwarehouse->fetch($warehouse_id);
  167. $tmpprod = new Product($db);
  168. $tmpprod->fetch($prod_id);
  169. dol_syslog('No dispatch for line '.$key.' as no combination warehouse, product, batch code was found.');
  170. setEventMessages($langs->trans('ErrorNoCombinationBatchcode', $numline, $tmpwarehouse->ref, $tmpprod->ref, $lot), null, 'errors');
  171. $error++;
  172. }
  173. $db->free($resql);
  174. }
  175. }
  176. }
  177. //var_dump($key.' '.$newqty.' '.$idline.' '.$error);
  178. if (!$error) {
  179. $qtystart = 0;
  180. if ($idline > 0) {
  181. $result = $expeditiondispatch->fetch($idline); // get line from llx_expeditiondet
  182. if ($result < 0) {
  183. setEventMessages($expeditiondispatch->error, $expeditiondispatch->errors, 'errors');
  184. $error++;
  185. } else {
  186. $qtystart = $expeditiondispatch->qty;
  187. $expeditiondispatch->qty = $newqty;
  188. $expeditiondispatch->entrepot_id = GETPOST($ent, 'int');
  189. if ($newqty > 0) {
  190. $result = $expeditiondispatch->update($user);
  191. } else {
  192. $result = $expeditiondispatch->delete($user);
  193. }
  194. if ($result < 0) {
  195. setEventMessages($expeditiondispatch->error, $expeditiondispatch->errors, 'errors');
  196. $error++;
  197. }
  198. if (!$error && $modebatch == "batch") {
  199. if ($newqty > 0) {
  200. $suffixkeyfordate = preg_replace('/^product_batch/', '', $key);
  201. $sellby = dol_mktime(0, 0, 0, GETPOST('dlc'.$suffixkeyfordate.'month'), GETPOST('dlc'.$suffixkeyfordate.'day'), GETPOST('dlc'.$suffixkeyfordate.'year'), '');
  202. $eatby = dol_mktime(0, 0, 0, GETPOST('dluo'.$suffixkeyfordate.'month'), GETPOST('dluo'.$suffixkeyfordate.'day'), GETPOST('dluo'.$suffixkeyfordate.'year'));
  203. $sqlsearchdet = "SELECT rowid FROM ".MAIN_DB_PREFIX.$expeditionlinebatch->table_element;
  204. $sqlsearchdet .= " WHERE fk_expeditiondet = ".((int) $idline);
  205. $sqlsearchdet .= " AND batch = '".$db->escape($lot)."'";
  206. $resqlsearchdet = $db->query($sqlsearchdet);
  207. if ($resqlsearchdet) {
  208. $objsearchdet = $db->fetch_object($resqlsearchdet);
  209. } else {
  210. dol_print_error($db);
  211. }
  212. if ($objsearchdet) {
  213. $sql = "UPDATE ".MAIN_DB_PREFIX.$expeditionlinebatch->table_element." SET";
  214. $sql .= " eatby = ".($eatby ? "'".$db->idate($eatby)."'" : "null");
  215. $sql .= " , sellby = ".($sellby ? "'".$db->idate($sellby)."'" : "null");
  216. $sql .= " , qty = ".((float) $newqty);
  217. $sql .= " , fk_warehouse = ".((int) $warehouse_id);
  218. $sql .= " WHERE rowid = ".((int) $objsearchdet->rowid);
  219. } else {
  220. $sql = "INSERT INTO ".MAIN_DB_PREFIX.$expeditionlinebatch->table_element." (";
  221. $sql .= "fk_expeditiondet, eatby, sellby, batch, qty, fk_origin_stock, fk_warehouse)";
  222. $sql .= " VALUES (".((int) $idline).", ".($eatby ? "'".$db->idate($eatby)."'" : "null").", ".($sellby ? "'".$db->idate($sellby)."'" : "null").", ";
  223. $sql .= " '".$db->escape($lot)."', ".((float) $newqty).", 0, ".((int) $warehouse_id).")";
  224. }
  225. } else {
  226. $sql = " DELETE FROM ".MAIN_DB_PREFIX.$expeditionlinebatch->table_element;
  227. $sql .= " WHERE fk_expeditiondet = ".((int) $idline);
  228. $sql .= " AND batch = '".$db->escape($lot)."'";
  229. }
  230. $resql = $db->query($sql);
  231. if (!$resql) {
  232. dol_print_error($db);
  233. $error++;
  234. }
  235. }
  236. }
  237. } else {
  238. $expeditiondispatch->fk_expedition = $object->id;
  239. $expeditiondispatch->entrepot_id = GETPOST($ent, 'int');
  240. $expeditiondispatch->fk_origin_line = GETPOST($fk_commandedet, 'int');
  241. $expeditiondispatch->qty = $newqty;
  242. if ($newqty > 0) {
  243. $idline = $expeditiondispatch->insert($user);
  244. if ($idline < 0) {
  245. setEventMessages($expeditiondispatch->error, $expeditiondispatch->errors, 'errors');
  246. $error++;
  247. }
  248. if ($modebatch == "batch" && !$error) {
  249. $expeditionlinebatch->sellby = $dDLUO;
  250. $expeditionlinebatch->eatby = $dDLC;
  251. $expeditionlinebatch->batch = $lot;
  252. $expeditionlinebatch->qty = $newqty;
  253. $expeditionlinebatch->fk_origin_stock = 0;
  254. $expeditionlinebatch->fk_warehouse = GETPOST($ent, 'int');
  255. $result = $expeditionlinebatch->create($idline);
  256. if ($result < 0) {
  257. setEventMessages($expeditionlinebatch->error, $expeditionlinebatch->errors, 'errors');
  258. $error++;
  259. }
  260. }
  261. }
  262. }
  263. // If module stock is enabled and the stock decrease is done on edtion of this page
  264. /*
  265. if (!$error && GETPOST($ent, 'int') > 0 && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_DISPATCH_ORDER)) {
  266. $mouv = new MouvementStock($db);
  267. $product = GETPOST($prod, 'int');
  268. $entrepot = GETPOST($ent, 'int');
  269. $qtymouv = price2num(GETPOST($qty, 'alpha'), 'MS') - $qtystart;
  270. $price = price2num(GETPOST($pu), 'MU');
  271. $comment = GETPOST('comment');
  272. $inventorycode = dol_print_date(dol_now(), 'dayhourlog');
  273. $now = dol_now();
  274. $eatby = '';
  275. $sellby = '';
  276. $batch = '';
  277. if ($modebatch == "batch") {
  278. $eatby = $dDLUO;
  279. $sellby = $dDLC;
  280. $batch = $lot ;
  281. }
  282. if ($product > 0 && $qtymouv != 0) {
  283. // $price should take into account discount (except if option STOCK_EXCLUDE_DISCOUNT_FOR_PMP is on)
  284. $mouv->origin = $objectorder;
  285. $mouv->setOrigin($objectorder->element, $objectorder->id);
  286. // Method change if qty < 0
  287. if (!empty($conf->global->SUPPLIER_ORDER_ALLOW_NEGATIVE_QTY_FOR_SUPPLIER_ORDER_RETURN) && $qtymouv < 0) {
  288. $result = $mouv->reception($user, $product, $entrepot, $qtymouv*(-1), $price, $comment, $eatby, $sellby, $batch, '', 0, $inventorycode);
  289. } else {
  290. $result = $mouv->livraison($user, $product, $entrepot, $qtymouv, $price, $comment, $now, $eatby, $sellby, $batch, 0, $inventorycode);
  291. }
  292. if ($result < 0) {
  293. setEventMessages($mouv->error, $mouv->errors, 'errors');
  294. $error++;
  295. }
  296. }
  297. }
  298. */
  299. }
  300. }
  301. }
  302. }
  303. if ($error > 0) {
  304. $db->rollback();
  305. setEventMessages($error, $errors, 'errors');
  306. } else {
  307. $db->commit();
  308. setEventMessages($langs->trans("ReceptionUpdated"), null);
  309. header("Location: ".DOL_URL_ROOT.'/expedition/dispatch.php?id='.$object->id);
  310. exit;
  311. }
  312. } elseif ($action == 'setdate_livraison' && $usercancreate) {
  313. $datedelivery = dol_mktime(GETPOST('liv_hour', 'int'), GETPOST('liv_min', 'int'), 0, GETPOST('liv_month', 'int'), GETPOST('liv_day', 'int'), GETPOST('liv_year', 'int'));
  314. $object->fetch($id);
  315. $result = $object->setDeliveryDate($user, $datedelivery);
  316. if ($result < 0) {
  317. setEventMessages($object->error, $object->errors, 'errors');
  318. }
  319. }
  320. /*
  321. * View
  322. */
  323. $now = dol_now();
  324. $form = new Form($db);
  325. $formproduct = new FormProduct($db);
  326. $warehouse_static = new Entrepot($db);
  327. $title = $object->ref." - ".$langs->trans('ShipmentDistribution');
  328. $help_url = 'EN:Module_Shipments|FR:Module_Expéditions|ES:M&oacute;dulo_Expediciones|DE:Modul_Lieferungen';
  329. $morejs = array('/expedition/js/lib_dispatch.js.php');
  330. llxHeader('', $title, $help_url, '', 0, 0, $morejs);
  331. if ($object->id > 0 || !empty($object->ref)) {
  332. $lines = $object->lines; // This is an array of detail of line, on line per source order line found intolines[]->fk_origin_line, then each line may have sub data
  333. //var_dump($lines[0]->fk_origin_line); exit;
  334. $num_prod = count($lines);
  335. if (!empty($object->origin) && $object->origin_id > 0) {
  336. $object->origin = 'commande';
  337. $typeobject = $object->origin;
  338. $origin = $object->origin;
  339. $origin_id = $object->origin_id;
  340. $object->fetch_origin(); // Load property $object->commande, $object->propal, ...
  341. }
  342. $soc = new Societe($db);
  343. $soc->fetch($object->socid);
  344. $author = new User($db);
  345. $author->fetch($object->user_author_id);
  346. $head = shipping_prepare_head($object);
  347. print dol_get_fiche_head($head, 'dispatch', $langs->trans("Shipment"), -1, $object->picto);
  348. $formconfirm = '';
  349. // Confirmation to delete line
  350. if ($action == 'ask_deleteline') {
  351. $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1);
  352. }
  353. // Call Hook formConfirm
  354. $parameters = array('lineid' => $lineid);
  355. // Note that $action and $object may be modified by hook
  356. $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action);
  357. if (empty($reshook)) {
  358. $formconfirm .= $hookmanager->resPrint;
  359. } elseif ($reshook > 0) {
  360. $formconfirm = $hookmanager->resPrint;
  361. }
  362. // Print form confirm
  363. print $formconfirm;
  364. if ($typeobject == 'commande' && $object->$typeobject->id && isModEnabled('commande')) {
  365. $objectsrc = new Commande($db);
  366. $objectsrc->fetch($object->$typeobject->id);
  367. }
  368. if ($typeobject == 'propal' && $object->$typeobject->id && isModEnabled("propal")) {
  369. $objectsrc = new Propal($db);
  370. $objectsrc->fetch($object->$typeobject->id);
  371. }
  372. // Shipment card
  373. $linkback = '<a href="'.DOL_URL_ROOT.'/expedition/list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
  374. $morehtmlref = '<div class="refidno">';
  375. // Ref customer shipment
  376. $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_customer', $object->ref_customer, $object, $user->hasRight('expedition', 'creer'), 'string', '', 0, 1);
  377. $morehtmlref .= $form->editfieldval("RefCustomer", 'ref_customer', $object->ref_customer, $object, $user->hasRight('expedition', 'creer'), 'string'.(isset($conf->global->THIRDPARTY_REF_INPUT_SIZE) ? ':' . getDolGlobalString('THIRDPARTY_REF_INPUT_SIZE') : ''), '', null, null, '', 1);
  378. // Thirdparty
  379. $morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1);
  380. // Project
  381. if (isModEnabled('project')) {
  382. $langs->load("projects");
  383. $morehtmlref .= '<br>';
  384. if (0) { // Do not change on reception
  385. $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
  386. if ($action != 'classify' && $permissiontoadd) {
  387. $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
  388. }
  389. $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, (!getDolGlobalString('PROJECT_CAN_ALWAYS_LINK_TO_ALL_SUPPLIERS') ? $object->socid : -1), $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
  390. } else {
  391. if (!empty($objectsrc) && !empty($objectsrc->fk_project)) {
  392. $proj = new Project($db);
  393. $proj->fetch($objectsrc->fk_project);
  394. $morehtmlref .= $proj->getNomUrl(1);
  395. if ($proj->title) {
  396. $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
  397. }
  398. }
  399. }
  400. }
  401. $morehtmlref .= '</div>';
  402. dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
  403. print '<div class="fichecenter">';
  404. print '<div class="underbanner clearboth"></div>';
  405. print '<table class="border tableforfield centpercent">';
  406. // Linked documents
  407. if ($typeobject == 'commande' && $object->$typeobject->id && isModEnabled('commande')) {
  408. print '<tr><td>';
  409. print $langs->trans("RefOrder").'</td>';
  410. print '<td colspan="3">';
  411. print $objectsrc->getNomUrl(1, 'commande');
  412. print "</td>\n";
  413. print '</tr>';
  414. }
  415. if ($typeobject == 'propal' && $object->$typeobject->id && isModEnabled("propal")) {
  416. print '<tr><td>';
  417. print $langs->trans("RefProposal").'</td>';
  418. print '<td colspan="3">';
  419. print $objectsrc->getNomUrl(1, 'expedition');
  420. print "</td>\n";
  421. print '</tr>';
  422. }
  423. // Date creation
  424. print '<tr><td class="titlefield">'.$langs->trans("DateCreation").'</td>';
  425. print '<td colspan="3">'.dol_print_date($object->date_creation, "dayhour", "tzuserrel")."</td>\n";
  426. print '</tr>';
  427. // Delivery date planned
  428. print '<tr><td height="10">';
  429. print '<table class="nobordernopadding" width="100%"><tr><td>';
  430. print $langs->trans('DateDeliveryPlanned');
  431. print '</td>';
  432. if ($action != 'editdate_livraison') {
  433. print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editdate_livraison&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->trans('SetDeliveryDate'), 1).'</a></td>';
  434. }
  435. print '</tr></table>';
  436. print '</td><td colspan="2">';
  437. if ($action == 'editdate_livraison') {
  438. print '<form name="setdate_livraison" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
  439. print '<input type="hidden" name="token" value="'.newToken().'">';
  440. print '<input type="hidden" name="action" value="setdate_livraison">';
  441. print $form->selectDate($object->date_delivery ? $object->date_delivery : -1, 'liv_', 1, 1, '', "setdate_livraison", 1, 0);
  442. print '<input type="submit" class="button button-edit smallpaddingimp" value="'.$langs->trans('Modify').'">';
  443. print '</form>';
  444. } else {
  445. print $object->date_delivery ? dol_print_date($object->date_delivery, 'dayhour') : '&nbsp;';
  446. }
  447. print '</td>';
  448. print '</tr></table>';
  449. print '<br><center>';
  450. if (isModEnabled('barcode') || isModEnabled('productbatch')) {
  451. print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=updatebyscaning&token='.currentToken().'" class="marginrightonly paddingright marginleftonly paddingleft">'.img_picto('', 'barcode', 'class="paddingrightonly"').$langs->trans("UpdateByScaning").'</a>';
  452. }
  453. print '<a href="#" id="resetalltoexpected" class="marginrightonly paddingright marginleftonly paddingleft">'.img_picto("", 'autofill', 'class="pictofixedwidth"').$langs->trans("RestoreWithCurrentQtySaved").'</a></td>';
  454. // Link to clear qty
  455. print '<a href="#" id="autoreset" class="marginrightonly paddingright marginleftonly paddingleft">'.img_picto("", 'eraser', 'class="pictofixedwidth"').$langs->trans("ClearQtys").'</a></td>';
  456. print '<center>';
  457. print '<br>';
  458. $disabled = 0; // This is used to disable or not the bulk selection of target warehouse. No reason to have it disabled so forced to 0.
  459. if ($object->statut == Expedition::STATUS_DRAFT) {
  460. require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
  461. $formproduct = new FormProduct($db);
  462. $formproduct->loadWarehouses();
  463. $entrepot = new Entrepot($db);
  464. $listwarehouses = $entrepot->list_array(1);
  465. print '<form method="post" action="'.$_SERVER["PHP_SELF"].'">';
  466. print '<input type="hidden" name="token" value="'.newToken().'">';
  467. print '<input type="hidden" name="action" value="updatelines">';
  468. print '<input type="hidden" name="id" value="'.$object->id.'">';
  469. print '<div class="div-table-responsive-no-min">';
  470. print '<table class="noborder centpercent">';
  471. // Get list of lines of the shipment $products_dispatched, with qty dispatched for each product id
  472. $products_dispatched = array();
  473. $sql = "SELECT ed.fk_origin_line as rowid, sum(ed.qty) as qty";
  474. $sql .= " FROM ".MAIN_DB_PREFIX."expeditiondet as ed";
  475. $sql .= " WHERE ed.fk_expedition = ".((int) $object->id);
  476. $sql .= " GROUP BY ed.fk_origin_line";
  477. $resql = $db->query($sql);
  478. if ($resql) {
  479. $num = $db->num_rows($resql);
  480. $i = 0;
  481. if ($num) {
  482. while ($i < $num) {
  483. $objd = $db->fetch_object($resql);
  484. $products_dispatched[$objd->rowid] = price2num($objd->qty, 'MS');
  485. $i++;
  486. }
  487. }
  488. $db->free($resql);
  489. }
  490. //$sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref AS sref, SUM(l.qty) as qty,";
  491. $sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, '' AS sref, l.qty as qty,";
  492. $sql .= " p.ref, p.label, p.tobatch, p.fk_default_warehouse, p.barcode";
  493. // Enable hooks to alter the SQL query (SELECT)
  494. $parameters = array();
  495. $reshook = $hookmanager->executeHooks(
  496. 'printFieldListSelect',
  497. $parameters,
  498. $object,
  499. $action
  500. );
  501. if ($reshook < 0) {
  502. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  503. }
  504. $sql .= $hookmanager->resPrint;
  505. $sql .= " FROM ".MAIN_DB_PREFIX."commandedet as l";
  506. $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON l.fk_product=p.rowid";
  507. $sql .= " WHERE l.fk_commande = ".((int) $objectsrc->id);
  508. if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
  509. $sql .= " AND l.product_type = 0";
  510. }
  511. // Enable hooks to alter the SQL query (WHERE)
  512. $parameters = array();
  513. $reshook = $hookmanager->executeHooks(
  514. 'printFieldListWhere',
  515. $parameters,
  516. $object,
  517. $action
  518. );
  519. if ($reshook < 0) {
  520. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  521. }
  522. $sql .= $hookmanager->resPrint;
  523. //$sql .= " GROUP BY p.ref, p.label, p.tobatch, p.fk_default_warehouse, l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref"; // Calculation of amount dispatched is done per fk_product so we must group by fk_product
  524. $sql .= " ORDER BY l.rang, p.ref, p.label";
  525. $resql = $db->query($sql);
  526. if ($resql) {
  527. $num = $db->num_rows($resql);
  528. $i = 0;
  529. $numline = 1;
  530. if ($num) {
  531. print '<tr class="liste_titre">';
  532. print '<td>'.$langs->trans("Description").'</td>';
  533. if (isModEnabled('productbatch')) {
  534. print '<td class="dispatch_batch_number_title">'.$langs->trans("batch_number").'</td>';
  535. if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
  536. print '<td class="dispatch_dlc_title">'.$langs->trans("SellByDate").'</td>';
  537. }
  538. if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
  539. print '<td class="dispatch_dluo_title">'.$langs->trans("EatByDate").'</td>';
  540. }
  541. } else {
  542. print '<td></td>';
  543. print '<td></td>';
  544. print '<td></td>';
  545. }
  546. print '<td class="right">'.$langs->trans("QtyOrdered").'</td>';
  547. if ($object->status == Expedition::STATUS_DRAFT) {
  548. print '<td class="right">'.$langs->trans("QtyToShip"); // Qty to dispatch (sum for all lines of batch detail if there is)
  549. } else {
  550. print '<td class="right">'.$langs->trans("QtyDispatchedShort").'</td>';
  551. }
  552. print '<td class="right">'.$langs->trans("Details");
  553. print '<td width="32"></td>';
  554. if (getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
  555. if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
  556. print '<td class="right">'.$langs->trans("Price").'</td>';
  557. print '<td class="right">'.$langs->trans("ReductionShort").' (%)</td>';
  558. print '<td class="right">'.$langs->trans("UpdatePrice").'</td>';
  559. }
  560. }
  561. print '<td align="right">'.$langs->trans("Warehouse");
  562. // Select warehouse to force it everywhere
  563. if (count($listwarehouses) > 1) {
  564. print '<br><span class="opacitymedium">'.$langs->trans("ForceTo").'</span> '.$form->selectarray('fk_default_warehouse', $listwarehouses, $fk_default_warehouse, 1, 0, 0, '', 0, 0, $disabled, '', 'minwidth100 maxwidth300', 1);
  565. } elseif (count($listwarehouses) == 1) {
  566. print '<br><span class="opacitymedium">'.$langs->trans("ForceTo").'</span> '.$form->selectarray('fk_default_warehouse', $listwarehouses, $fk_default_warehouse, 0, 0, 0, '', 0, 0, $disabled, '', 'minwidth100 maxwidth300', 1);
  567. }
  568. print '</td>';
  569. // Enable hooks to append additional columns
  570. $parameters = array();
  571. $reshook = $hookmanager->executeHooks(
  572. 'printFieldListTitle',
  573. $parameters,
  574. $object,
  575. $action
  576. );
  577. if ($reshook < 0) {
  578. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  579. }
  580. print $hookmanager->resPrint;
  581. print "</tr>\n";
  582. }
  583. $nbfreeproduct = 0; // Nb of lins of free products/services
  584. $nbproduct = 0; // Nb of predefined product lines to dispatch (already done or not) if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is off (default)
  585. // or nb of line that remain to dispatch if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is on.
  586. $conf->cache['product'] = array();
  587. // Loop on each line of origin order
  588. while ($i < $num) {
  589. $objp = $db->fetch_object($resql);
  590. // On n'affiche pas les produits libres
  591. if (!$objp->fk_product > 0) {
  592. $nbfreeproduct++;
  593. } else {
  594. $alreadydispatched = isset($products_dispatched[$objp->rowid]) ? $products_dispatched[$objp->rowid] : 0;
  595. $remaintodispatch = price2num($objp->qty, 5); // Calculation of dispatched
  596. if ($remaintodispatch < 0 && !getDolGlobalString('SUPPLIER_ORDER_ALLOW_NEGATIVE_QTY_FOR_SUPPLIER_ORDER_RETURN')) {
  597. $remaintodispatch = 0;
  598. }
  599. if ($remaintodispatch || !getDolGlobalString('SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED')) {
  600. $nbproduct++;
  601. // To show detail cref and description value, we must make calculation by cref
  602. // print ($objp->cref?' ('.$objp->cref.')':'');
  603. // if ($objp->description) print '<br>'.nl2br($objp->description);
  604. $suffix = '_0_'.$i;
  605. print "\n";
  606. print '<!-- Line to dispatch '.$suffix.' -->'."\n";
  607. // hidden fields for js function
  608. print '<input id="qty_ordered'.$suffix.'" type="hidden" value="'.$objp->qty.'">';
  609. print '<input id="qty_dispatched'.$suffix.'" type="hidden" data-dispatched="'.((float) $alreadydispatched).'" value="'.(float) $alreadydispatched.'">';
  610. print '<tr class="oddeven">';
  611. if (empty($conf->cache['product'][$objp->fk_product])) {
  612. $tmpproduct = new Product($db);
  613. $tmpproduct->fetch($objp->fk_product);
  614. $conf->cache['product'][$objp->fk_product] = $tmpproduct;
  615. } else {
  616. $tmpproduct = $conf->cache['product'][$objp->fk_product];
  617. }
  618. $linktoprod = $tmpproduct->getNomUrl(1);
  619. $linktoprod .= ' - '.$objp->label."\n";
  620. if (isModEnabled('productbatch')) {
  621. if ($objp->tobatch) {
  622. // Product
  623. print '<td id="product_'.$i.'" data-idproduct="'.$objp->fk_product.'" data-barcode="'.$objp->barcode.'">';
  624. print $linktoprod;
  625. print "</td>";
  626. print '<td class="dispatch_batch_number"></td>';
  627. if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
  628. print '<td class="dispatch_dlc"></td>';
  629. }
  630. if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
  631. print '<td class="dispatch_dluo"></td>';
  632. }
  633. } else {
  634. // Product
  635. print '<td id="product_'.$i.'" data-idproduct="'.$objp->fk_product.'" data-barcode="'.$objp->barcode.'">';
  636. print $linktoprod;
  637. print "</td>";
  638. print '<td class="dispatch_batch_number">';
  639. print '<span class="opacitymedium small">'.$langs->trans("ProductDoesNotUseBatchSerial").'</span>';
  640. print '</td>';
  641. if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
  642. print '<td class="dispatch_dlc"></td>';
  643. }
  644. if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
  645. print '<td class="dispatch_dluo"></td>';
  646. }
  647. }
  648. } else {
  649. print '<td colspan="4">';
  650. print $linktoprod;
  651. print "</td>";
  652. }
  653. // Define unit price for PMP calculation
  654. $up_ht_disc = $objp->subprice;
  655. if (!empty($objp->remise_percent) && !getDolGlobalString('STOCK_EXCLUDE_DISCOUNT_FOR_PMP')) {
  656. $up_ht_disc = price2num($up_ht_disc * (100 - $objp->remise_percent) / 100, 'MU');
  657. }
  658. // Qty ordered
  659. print '<td class="right">'.$objp->qty.'</td>';
  660. // Already dispatched
  661. print '<td class="right">'.$alreadydispatched.'</td>';
  662. print '<td class="right">';
  663. print '</td>'; // Qty to dispatch
  664. print '<td>';
  665. print '</td>'; // Dispatch column
  666. print '<td></td>'; // Warehouse column
  667. /*$sql = "SELECT cfd.rowid, cfd.qty, cfd.fk_entrepot, cfd.batch, cfd.eatby, cfd.sellby, cfd.fk_product";
  668. $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as cfd";
  669. $sql .= " WHERE cfd.fk_commandefourndet = ".(int) $objp->rowid;*/
  670. $sql = "SELECT ed.rowid, ed.qty, ed.fk_entrepot,";
  671. $sql .= " eb.batch, eb.eatby, eb.sellby, cd.fk_product";
  672. $sql .= " FROM ".MAIN_DB_PREFIX."expeditiondet as ed";
  673. $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."expeditiondet_batch as eb on ed.rowid = eb.fk_expeditiondet";
  674. $sql .= " JOIN ".MAIN_DB_PREFIX."commandedet as cd on ed.fk_origin_line = cd.rowid";
  675. $sql .= " WHERE ed.fk_origin_line =".(int) $objp->rowid;
  676. $sql .= " AND ed.fk_expedition =".(int) $object->id;
  677. $sql .= " ORDER BY ed.rowid, ed.fk_origin_line";
  678. $resultsql = $db->query($sql);
  679. $j = 0;
  680. if ($resultsql) {
  681. $numd = $db->num_rows($resultsql);
  682. while ($j < $numd) {
  683. $suffix = "_".$j."_".$i;
  684. $objd = $db->fetch_object($resultsql);
  685. if (isModEnabled('productbatch') && (!empty($objd->batch) || (is_null($objd->batch) && $tmpproduct->status_batch > 0))) {
  686. $type = 'batch';
  687. // Enable hooks to append additional columns
  688. $parameters = array(
  689. // allows hook to distinguish between the rows with information and the rows with dispatch form input
  690. 'is_information_row' => true,
  691. 'j' => $j,
  692. 'suffix' => $suffix,
  693. 'objd' => $objd,
  694. );
  695. $reshook = $hookmanager->executeHooks(
  696. 'printFieldListValue',
  697. $parameters,
  698. $object,
  699. $action
  700. );
  701. if ($reshook < 0) {
  702. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  703. }
  704. print $hookmanager->resPrint;
  705. print '</tr>';
  706. print '<!-- line for batch '.$numline.' -->';
  707. print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
  708. print '<td>';
  709. print '<input id="fk_commandedet'.$suffix.'" name="fk_commandedet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
  710. print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="'.$objd->rowid.'">';
  711. print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objd->fk_product.'">';
  712. print '<!-- This is a U.P. (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
  713. print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
  714. print '</td>';
  715. print '<td>';
  716. print '<input type="text" class="inputlotnumber quatrevingtquinzepercent" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.(GETPOSTISSET('lot_number'.$suffix) ? GETPOST('lot_number'.$suffix) : $objd->batch).'">';
  717. //print '<input type="hidden" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.$objd->batch.'">';
  718. print '</td>';
  719. if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
  720. print '<td class="nowraponall">';
  721. $dlcdatesuffix = !empty($objd->sellby) ? dol_stringtotime($objd->sellby) : dol_mktime(0, 0, 0, GETPOST('dlc'.$suffix.'month'), GETPOST('dlc'.$suffix.'day'), GETPOST('dlc'.$suffix.'year'));
  722. print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, '', '', 1, '');
  723. print '</td>';
  724. }
  725. if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
  726. print '<td class="nowraponall">';
  727. $dluodatesuffix = !empty($objd->eatby) ? dol_stringtotime($objd->eatby) : dol_mktime(0, 0, 0, GETPOST('dluo'.$suffix.'month'), GETPOST('dluo'.$suffix.'day'), GETPOST('dluo'.$suffix.'year'));
  728. print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, '', '', 1, '');
  729. print '</td>';
  730. }
  731. print '<td colspan="2">&nbsp;</td>'; // Supplier ref + Qty ordered + qty already dispatched
  732. } else {
  733. $type = 'dispatch';
  734. $colspan = 6;
  735. $colspan = (getDolGlobalString('PRODUCT_DISABLE_SELLBY')) ? --$colspan : $colspan;
  736. $colspan = (getDolGlobalString('PRODUCT_DISABLE_EATBY')) ? --$colspan : $colspan;
  737. // Enable hooks to append additional columns
  738. $parameters = array(
  739. // allows hook to distinguish between the rows with information and the rows with dispatch form input
  740. 'is_information_row' => true,
  741. 'j' => $j,
  742. 'suffix' => $suffix,
  743. 'objd' => $objd,
  744. );
  745. $reshook = $hookmanager->executeHooks(
  746. 'printFieldListValue',
  747. $parameters,
  748. $object,
  749. $action
  750. );
  751. if ($reshook < 0) {
  752. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  753. }
  754. print $hookmanager->resPrint;
  755. print '</tr>';
  756. print '<!-- line no batch '.$numline.' -->';
  757. print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
  758. print '<td colspan="'.$colspan.'">';
  759. print '<input id="fk_commandedet'.$suffix.'" name="fk_commandedet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
  760. print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="'.$objd->rowid.'">';
  761. print '<input name="product'.$suffix.'" type="hidden" value="'.$objd->fk_product.'">';
  762. print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
  763. print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
  764. print '</td>';
  765. }
  766. // Qty to dispatch
  767. print '<td class="right nowraponall">';
  768. print '<a href="" id="reset'.$suffix.'" class="resetline">'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').'</a>';
  769. $suggestedvalue = (GETPOSTISSET('qty'.$suffix) ? GETPOST('qty'.$suffix, 'int') : $objd->qty);
  770. //var_dump($suggestedvalue);exit;
  771. print '<input id="qty'.$suffix.'" onchange="onChangeDispatchLineQty($(this))" name="qty'.$suffix.'" data-type="'.$type.'" data-index="'.$i.'" class="width50 right qtydispatchinput" value="'.$suggestedvalue.'" data-expected="'.$objd->qty.'">';
  772. print '</td>';
  773. print '<td>';
  774. if (isModEnabled('productbatch') && $objp->tobatch > 0) {
  775. $type = 'batch';
  776. print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" '.($numd != $j+1 ? 'style="display:none"' : '').' onClick="addDispatchLine('.$i.', \''.$type.'\')"');
  777. } else {
  778. $type = 'dispatch';
  779. print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" '.($numd != $j+1 ? 'style="display:none"' : '').' onClick="addDispatchLine('.$i.', \''.$type.'\')"');
  780. }
  781. print '</td>';
  782. // Warehouse
  783. print '<td class="right">';
  784. if (count($listwarehouses) > 1) {
  785. print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ? GETPOST("entrepot".$suffix) : $objd->fk_entrepot, "entrepot".$suffix, '', 1, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix);
  786. } elseif (count($listwarehouses) == 1) {
  787. print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ? GETPOST("entrepot".$suffix) : $objd->fk_entrepot, "entrepot".$suffix, '', 0, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix);
  788. } else {
  789. $langs->load("errors");
  790. print $langs->trans("ErrorNoWarehouseDefined");
  791. }
  792. print "</td>\n";
  793. // Enable hooks to append additional columns
  794. $parameters = array(
  795. 'is_information_row' => false, // this is a dispatch form row
  796. 'i' => $i,
  797. 'suffix' => $suffix,
  798. 'objp' => $objp,
  799. );
  800. $reshook = $hookmanager->executeHooks(
  801. 'printFieldListValue',
  802. $parameters,
  803. $object,
  804. $action
  805. );
  806. if ($reshook < 0) {
  807. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  808. }
  809. print $hookmanager->resPrint;
  810. print "</tr>\n";
  811. $j++;
  812. $numline++;
  813. }
  814. $suffix = "_".$j."_".$i;
  815. }
  816. if ($j == 0) {
  817. if (isModEnabled('productbatch') && !empty($objp->tobatch)) {
  818. $type = 'batch';
  819. // Enable hooks to append additional columns
  820. $parameters = array(
  821. // allows hook to distinguish between the rows with information and the rows with dispatch form input
  822. 'is_information_row' => true,
  823. 'j' => $j,
  824. 'suffix' => $suffix,
  825. 'objp' => $objp,
  826. );
  827. $reshook = $hookmanager->executeHooks(
  828. 'printFieldListValue',
  829. $parameters,
  830. $object,
  831. $action
  832. );
  833. if ($reshook < 0) {
  834. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  835. }
  836. print $hookmanager->resPrint;
  837. print '</tr>';
  838. print '<!-- line for batch '.$numline.' (not dispatched line yet for this order line) -->';
  839. print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
  840. print '<td>';
  841. print '<input id="fk_commandedet'.$suffix.'" name="fk_commandedet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
  842. print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="-1">';
  843. print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
  844. print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
  845. print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
  846. print '</td>';
  847. print '<td>';
  848. print '<input type="text" class="inputlotnumber quatrevingtquinzepercent" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.GETPOST('lot_number'.$suffix).'">';
  849. print '</td>';
  850. if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
  851. print '<td class="nowraponall">';
  852. $dlcdatesuffix = dol_mktime(0, 0, 0, GETPOST('dlc'.$suffix.'month'), GETPOST('dlc'.$suffix.'day'), GETPOST('dlc'.$suffix.'year'));
  853. print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, '', '', 1, '');
  854. print '</td>';
  855. }
  856. if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
  857. print '<td class="nowraponall">';
  858. $dluodatesuffix = dol_mktime(0, 0, 0, GETPOST('dluo'.$suffix.'month'), GETPOST('dluo'.$suffix.'day'), GETPOST('dluo'.$suffix.'year'));
  859. print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, '', '', 1, '');
  860. print '</td>';
  861. }
  862. print '<td colspan="2">&nbsp;</td>'; // Supplier ref + Qty ordered + qty already dispatched
  863. } else {
  864. $type = 'dispatch';
  865. $colspan = 6;
  866. $colspan = (getDolGlobalString('PRODUCT_DISABLE_SELLBY')) ? --$colspan : $colspan;
  867. $colspan = (getDolGlobalString('PRODUCT_DISABLE_EATBY')) ? --$colspan : $colspan;
  868. // Enable hooks to append additional columns
  869. $parameters = array(
  870. // allows hook to distinguish between the rows with information and the rows with dispatch form input
  871. 'is_information_row' => true,
  872. 'j' => $j,
  873. 'suffix' => $suffix,
  874. 'objp' => $objp,
  875. );
  876. $reshook = $hookmanager->executeHooks(
  877. 'printFieldListValue',
  878. $parameters,
  879. $object,
  880. $action
  881. );
  882. if ($reshook < 0) {
  883. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  884. }
  885. print $hookmanager->resPrint;
  886. print '</tr>';
  887. print '<!-- line no batch '.$numline.' (not dispatched line yet for this order line) -->';
  888. print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
  889. print '<td colspan="'.$colspan.'">';
  890. print '<input id="fk_commandedet'.$suffix.'" name="fk_commandedet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
  891. print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="-1">';
  892. print '<input name="product'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
  893. print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
  894. print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
  895. print '</td>';
  896. }
  897. // Qty to dispatch
  898. print '<td class="right">';
  899. print '<a href="" id="reset'.$suffix.'" class="resetline">'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').'</a>';
  900. $amounttosuggest = (GETPOSTISSET('qty'.$suffix) ? GETPOST('qty'.$suffix, 'int') : (!getDolGlobalString('SUPPLIER_ORDER_DISPATCH_FORCE_QTY_INPUT_TO_ZERO') ? $remaintodispatch : 0));
  901. if (count($products_dispatched)) {
  902. // There is already existing lines into llx_expeditiondet, this means a plan for the shipment has already been started.
  903. // In such a case, we do not suggest new values, we suggest the value known.
  904. $amounttosuggest = (GETPOSTISSET('qty'.$suffix) ? GETPOST('qty'.$suffix, 'int') : (isset($products_dispatched[$objp->rowid]) ? $products_dispatched[$objp->rowid] : ''));
  905. }
  906. print '<input id="qty'.$suffix.'" onchange="onChangeDispatchLineQty($(this))" name="qty'.$suffix.'" data-index="'.$i.'" data-type="text" class="width50 right qtydispatchinput" value="'.$amounttosuggest.'" data-expected="'.$amounttosuggest.'">';
  907. print '</td>';
  908. print '<td>';
  909. if (isModEnabled('productbatch') && $objp->tobatch > 0) {
  910. $type = 'batch';
  911. print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
  912. } else {
  913. $type = 'dispatch';
  914. print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
  915. }
  916. print '</td>';
  917. // Warehouse
  918. print '<td class="right">';
  919. if (count($listwarehouses) > 1) {
  920. print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ? GETPOST("entrepot".$suffix) : ($objp->fk_default_warehouse ? $objp->fk_default_warehouse : ''), "entrepot".$suffix, '', 1, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix);
  921. } elseif (count($listwarehouses) == 1) {
  922. print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ? GETPOST("entrepot".$suffix) : ($objp->fk_default_warehouse ? $objp->fk_default_warehouse : ''), "entrepot".$suffix, '', 0, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix);
  923. } else {
  924. $langs->load("errors");
  925. print $langs->trans("ErrorNoWarehouseDefined");
  926. }
  927. print "</td>\n";
  928. // Enable hooks to append additional columns
  929. $parameters = array(
  930. 'is_information_row' => false, // this is a dispatch form row
  931. 'i' => $i,
  932. 'suffix' => $suffix,
  933. 'objp' => $objp,
  934. );
  935. $reshook = $hookmanager->executeHooks(
  936. 'printFieldListValue',
  937. $parameters,
  938. $object,
  939. $action
  940. );
  941. if ($reshook < 0) {
  942. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  943. }
  944. print $hookmanager->resPrint;
  945. print "</tr>\n";
  946. }
  947. }
  948. }
  949. $i++;
  950. }
  951. $db->free($resql);
  952. } else {
  953. dol_print_error($db);
  954. }
  955. print "</table>\n";
  956. print '</div>';
  957. if ($nbproduct) {
  958. //$checkboxlabel = $langs->trans("CloseReceivedSupplierOrdersAutomatically", $langs->transnoentitiesnoconv('StatusOrderReceivedAll'));
  959. print '<div class="center">';
  960. $parameters = array();
  961. $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
  962. // modified by hook
  963. if (empty($reshook)) {
  964. /*if (empty($conf->reception->enabled)) {
  965. print $langs->trans("Comment").' : ';
  966. print '<input type="text" class="minwidth400" maxlength="128" name="comment" value="';
  967. print GETPOSTISSET("comment") ? GETPOST("comment") : $langs->trans("DispatchSupplierOrder", $object->ref);
  968. // print ' / '.$object->ref_supplier; // Not yet available
  969. print '" class="flat"><br>';
  970. print '<input type="checkbox" checked="checked" name="closeopenorder"> '.$checkboxlabel;
  971. }
  972. $dispatchBt = empty($conf->reception->enabled) ? $langs->trans("Receive") : $langs->trans("CreateReception");
  973. print '<br>';
  974. */
  975. print '<input type="submit" id="submitform" class="button" name="dispatch" value="'.$langs->trans("Save").'"';
  976. $disabled = 0;
  977. if (!$usercancreate) {
  978. $disabled = 1;
  979. }
  980. if (count($listwarehouses) <= 0) {
  981. $disabled = 1;
  982. }
  983. if ($disabled) {
  984. print ' disabled';
  985. }
  986. print '>';
  987. }
  988. print '</div>';
  989. }
  990. // Message if nothing to dispatch
  991. if (!$nbproduct) {
  992. print "<br>\n";
  993. if (!getDolGlobalString('SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED')) {
  994. print '<div class="opacitymedium">'.$langs->trans("NoPredefinedProductToDispatch").'</div>'; // No predefined line at all
  995. } else {
  996. print '<div class="opacitymedium">'.$langs->trans("NoMorePredefinedProductToDispatch").'</div>'; // No predefined line that remain to be dispatched.
  997. }
  998. }
  999. print '</form>';
  1000. }
  1001. print dol_get_fiche_end();
  1002. // Popup for mass barcode scanning
  1003. if ($action == 'updatebyscaning') {
  1004. if ($permissiontoadd) {
  1005. // Output the javascript to manage the scanner tool.
  1006. print '<script>';
  1007. print '
  1008. var duplicatedbatchcode = [];
  1009. var errortab1 = [];
  1010. var errortab2 = [];
  1011. var errortab3 = [];
  1012. var errortab4 = [];
  1013. function barcodescannerjs(){
  1014. console.log("We catch inputs in scanner box");
  1015. jQuery("#scantoolmessage").text();
  1016. var selectaddorreplace = $("select[name=selectaddorreplace]").val();
  1017. var barcodemode = $("input[name=barcodemode]:checked").val();
  1018. var barcodeproductqty = $("input[name=barcodeproductqty]").val();
  1019. var warehousetouse = $("select[name=warehousenew]").val();
  1020. var textarea = $("textarea[name=barcodelist]").val();
  1021. var textarray = textarea.split(/[\s,;]+/);
  1022. var tabproduct = [];
  1023. duplicatedbatchcode = [];
  1024. errortab1 = [];
  1025. errortab2 = [];
  1026. errortab3 = [];
  1027. errortab4 = [];
  1028. textarray = textarray.filter(function(value){
  1029. return value != "";
  1030. });
  1031. if(textarray.some((element) => element != "")){
  1032. $(".qtydispatchinput").each(function(){
  1033. id = $(this).attr(\'id\');
  1034. idarray = id.split(\'_\');
  1035. idproduct = idarray[2];
  1036. id = idarray[1] + \'_\' + idarray[2];
  1037. console.log("Analyze the line "+id+" in inventory, barcodemode="+barcodemode);
  1038. warehouse = $("#entrepot_"+id).val();
  1039. console.log(warehouse);
  1040. productbarcode = $("#product_"+idproduct).attr(\'data-barcode\');
  1041. console.log(productbarcode);
  1042. productbatchcode = $("#lot_number_"+id).val();
  1043. if(productbatchcode == undefined){
  1044. productbatchcode = "";
  1045. }
  1046. console.log(productbatchcode);
  1047. if (barcodemode != "barcodeforproduct") {
  1048. tabproduct.forEach(product=>{
  1049. console.log("product.Batch="+product.Batch+" productbatchcode="+productbatchcode);
  1050. if(product.Batch != "" && product.Batch == productbatchcode){
  1051. console.log("duplicate batch code found for batch code "+productbatchcode);
  1052. duplicatedbatchcode.push(productbatchcode);
  1053. }
  1054. })
  1055. }
  1056. productinput = $("#qty_"+id).val();
  1057. if(productinput == ""){
  1058. productinput = 0
  1059. }
  1060. tabproduct.push({\'Id\':id,\'Warehouse\':warehouse,\'Barcode\':productbarcode,\'Batch\':productbatchcode,\'Qty\':productinput,\'fetched\':false});
  1061. });
  1062. console.log("Loop on each record entered in the textarea");
  1063. textarray.forEach(function(element,index){
  1064. console.log("Process record element="+element+" id="+id);
  1065. var verify_batch = false;
  1066. var verify_barcode = false;
  1067. switch(barcodemode){
  1068. case "barcodeforautodetect":
  1069. verify_barcode = barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,"barcode",true);
  1070. verify_batch = barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,"lotserial",true);
  1071. break;
  1072. case "barcodeforproduct":
  1073. verify_barcode = barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,"barcode");
  1074. break;
  1075. case "barcodeforlotserial":
  1076. verify_batch = barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,"lotserial");
  1077. break;
  1078. default:
  1079. alert(\''.dol_escape_js($langs->trans("ErrorWrongBarcodemode")).' "\'+barcodemode+\'"\');
  1080. throw \''.dol_escape_js($langs->trans('ErrorWrongBarcodemode')).' "\'+barcodemode+\'"\';
  1081. }
  1082. if (verify_batch == false && verify_barcode == false) { /* If the 2 flags are false, not found error */
  1083. errortab2.push(element);
  1084. } else if (verify_batch == true && verify_barcode == true) { /* If the 2 flags are true, error: we don t know which one to take */
  1085. errortab3.push(element);
  1086. } else if (verify_batch == true) {
  1087. console.log("element="+element);
  1088. console.log(duplicatedbatchcode);
  1089. if (duplicatedbatchcode.includes(element)) {
  1090. errortab1.push(element);
  1091. }
  1092. }
  1093. });
  1094. if (Object.keys(errortab1).length < 1 && Object.keys(errortab2).length < 1 && Object.keys(errortab3).length < 1) {
  1095. tabproduct.forEach(product => {
  1096. if(product.Qty!=0){
  1097. if(product.hasOwnProperty("reelqty")){
  1098. idprod = $("td[data-idproduct=\'"+product.fk_product+"\']").attr("id");
  1099. idproduct = idprod.split("_")[1];
  1100. console.log("We create a new line for product_"+idproduct);
  1101. if(product.Barcode != null){
  1102. modedispatch = "dispatch";
  1103. } else {
  1104. modedispatch = "batch";
  1105. }
  1106. addDispatchLine(idproduct,modedispatch);
  1107. console.log($("tr[name^=\'"+modedispatch+"_\'][name$=\'_"+idproduct+"\']"));
  1108. nbrTrs = $("tr[name^=\'"+modedispatch+"_\'][name$=\'_"+idproduct+"\']").length;
  1109. $("#qty_"+(nbrTrs-1)+"_"+idproduct).val(product.Qty);
  1110. $("#entrepot_"+(nbrTrs-1)+"_"+idproduct).val(product.Warehouse);
  1111. if(modedispatch == "batch"){
  1112. $("#lot_number_"+(nbrTrs-1)+"_"+idproduct).val(product.Batch);
  1113. }
  1114. } else {
  1115. console.log("We change #qty_"+product.Id +" to match input in scanner box");
  1116. $("#qty_"+product.Id).val(product.Qty);
  1117. }
  1118. }
  1119. });
  1120. jQuery("#scantoolmessage").text("'.dol_escape_js($langs->transnoentities("QtyWasAddedToTheScannedBarcode")).'\n");
  1121. /* document.forms["formrecord"].submit(); */
  1122. } else {
  1123. let stringerror = "";
  1124. if (Object.keys(errortab1).length > 0) {
  1125. stringerror += "<br>'.dol_escape_js($langs->transnoentities('ErrorSameBatchNumber')).': ";
  1126. errortab1.forEach(element => {
  1127. stringerror += (element + ", ")
  1128. });
  1129. stringerror = stringerror.slice(0, -2); /* Remove last ", " */
  1130. }
  1131. if (Object.keys(errortab2).length > 0) {
  1132. stringerror += "<br>'.dol_escape_js($langs->transnoentities('ErrorCantFindCodeInInventory')).': ";
  1133. errortab2.forEach(element => {
  1134. stringerror += (element + ", ")
  1135. });
  1136. stringerror = stringerror.slice(0, -2); /* Remove last ", " */
  1137. }
  1138. if (Object.keys(errortab3).length > 0) {
  1139. stringerror += "<br>'.dol_escape_js($langs->transnoentities('ErrorCodeScannedIsBothProductAndSerial')).': ";
  1140. errortab3.forEach(element => {
  1141. stringerror += (element + ", ")
  1142. });
  1143. stringerror = stringerror.slice(0, -2); /* Remove last ", " */
  1144. }
  1145. if (Object.keys(errortab4).length > 0) {
  1146. stringerror += "<br>'.dol_escape_js($langs->transnoentities('ErrorBarcodeNotFoundForProductWarehouse')).': ";
  1147. errortab4.forEach(element => {
  1148. stringerror += (element + ", ")
  1149. });
  1150. stringerror = stringerror.slice(0, -2); /* Remove last ", " */
  1151. }
  1152. jQuery("#scantoolmessage").html(\''.dol_escape_js($langs->transnoentities("ErrorOnElementsInventory")).'\' + stringerror);
  1153. //alert("'.dol_escape_js($langs->trans("ErrorOnElementsInventory")).' :\n" + stringerror);
  1154. }
  1155. }
  1156. }
  1157. /* This methode is called by parent barcodescannerjs() */
  1158. function barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,mode,autodetect=false){
  1159. BarcodeIsInProduct=0;
  1160. newproductrow=0
  1161. result=false;
  1162. tabproduct.forEach(product => {
  1163. $.ajax({ url: \''.DOL_URL_ROOT.'/expedition/ajax/searchfrombarcode.php\',
  1164. data: { "token":"'.newToken().'", "action":"existbarcode","fk_entrepot": warehousetouse, "barcode":element, "mode":mode},
  1165. type: \'POST\',
  1166. async: false,
  1167. success: function(response) {
  1168. if (response.status == "success"){
  1169. console.log(response.message);
  1170. if(!newproductrow){
  1171. newproductrow = response.object;
  1172. }
  1173. }else{
  1174. if (mode!="lotserial" && autodetect==false && !errortab4.includes(element)){
  1175. errortab4.push(element);
  1176. console.error(response.message);
  1177. }
  1178. }
  1179. },
  1180. error : function(output) {
  1181. console.error("Error on barcodeserialforproduct function");
  1182. },
  1183. });
  1184. console.log("Product "+(index+=1)+": "+element);
  1185. if(mode == "barcode"){
  1186. testonproduct = product.Barcode
  1187. }else if (mode == "lotserial"){
  1188. testonproduct = product.Batch
  1189. }
  1190. testonwarehouse = product.Warehouse;
  1191. if(testonproduct == element && testonwarehouse == warehousetouse){
  1192. if(selectaddorreplace == "add"){
  1193. productqty = parseInt(product.Qty,10);
  1194. product.Qty = productqty + parseInt(barcodeproductqty,10);
  1195. }else if(selectaddorreplace == "replace"){
  1196. if(product.fetched == false){
  1197. product.Qty = barcodeproductqty
  1198. product.fetched=true
  1199. }else{
  1200. productqty = parseInt(product.Qty,10);
  1201. product.Qty = productqty + parseInt(barcodeproductqty,10);
  1202. }
  1203. }
  1204. BarcodeIsInProduct+=1;
  1205. }
  1206. })
  1207. if(BarcodeIsInProduct==0 && newproductrow!=0){
  1208. tabproduct.push({\'Id\':tabproduct.length-1,\'Warehouse\':newproductrow.fk_warehouse,\'Barcode\':mode=="barcode"?element:null,\'Batch\':mode=="lotserial"?element:null,\'Qty\':barcodeproductqty,\'fetched\':true,\'reelqty\':newproductrow.reelqty,\'fk_product\':newproductrow.fk_product,\'mode\':mode});
  1209. result = true;
  1210. }
  1211. if(BarcodeIsInProduct > 0){
  1212. result = true;
  1213. }
  1214. return result;
  1215. }
  1216. ';
  1217. print '</script>';
  1218. }
  1219. include DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
  1220. $formother = new FormOther($db);
  1221. print $formother->getHTMLScannerForm("barcodescannerjs", 'all', 1);
  1222. }
  1223. // traitement entrepot par défaut
  1224. print '<script type="text/javascript">
  1225. $(document).ready(function () {
  1226. $("select[name=fk_default_warehouse]").change(function() {
  1227. console.log("warehouse is modified");
  1228. var fk_default_warehouse = $("option:selected", this).val();
  1229. $("select[name^=entrepot_]").val(fk_default_warehouse).change();
  1230. });
  1231. $("#autoreset").click(function() {
  1232. console.log("we click on autoreset");
  1233. $(".autoresettr").each(function(){
  1234. id = $(this).attr("name");
  1235. idtab = id.split("_");
  1236. console.log("we process line "+id+" "+idtab);
  1237. if ($(this).data("remove") == "clear") { /* data-remove=clear means that line qty must be cleared but line must not be removed */
  1238. console.log("We clear the object to expected value")
  1239. $("#qty_"+idtab[1]+"_"+idtab[2]).val("");
  1240. /*
  1241. qtyexpected = $("#qty_"+idtab[1]+"_"+idtab[2]).data("expected")
  1242. console.log(qtyexpected);
  1243. $("#qty_"+idtab[1]+"_"+idtab[2]).val(qtyexpected);
  1244. qtydispatched = $("#qty_dispatched_0_"+idtab[2]).data("dispatched")
  1245. $("#qty_dispatched_0_"+idtab[2]).val(qtydispatched);
  1246. */
  1247. } else { /* data-remove=remove means that line must be removed */
  1248. console.log("We remove the object")
  1249. $(this).remove();
  1250. $("tr[name^=\'"+idtab[0]+"_\'][name$=\'_"+idtab[2]+"\']:last .splitbutton").show();
  1251. }
  1252. });
  1253. return false;
  1254. });
  1255. $("#resetalltoexpected").click(function(){
  1256. $(".qtydispatchinput").each(function(){
  1257. console.log("We reset to expected "+$(this).attr("id")+" qty to dispatch");
  1258. $(this).val($(this).data("expected"));
  1259. });
  1260. return false;
  1261. });
  1262. $(".resetline").on("click", function(event) {
  1263. event.preventDefault();
  1264. id = $(this).attr("id");
  1265. id = id.split("reset_");
  1266. console.log("Reset trigger for id = qty_"+id[1]);
  1267. $("#qty_"+id[1]).val("");
  1268. });
  1269. });
  1270. </script>';
  1271. }
  1272. // End of page
  1273. llxFooter();
  1274. $db->close();