dispatch.php 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152
  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/fourn/commande/dispatch.php
  28. * \ingroup commande
  29. * \brief Page to dispatch receiving
  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/reception.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("bills", "orders", "sendings", "companies", "deliveries", "products", "stocks", "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. if ($user->socid) {
  58. $socid = $user->socid;
  59. }
  60. $hookmanager->initHooks(array('ordersupplierdispatch'));
  61. // Recuperation de l'id de projet
  62. $projectid = 0;
  63. if (GETPOSTISSET("projectid")) {
  64. $projectid = GETPOST("projectid", 'int');
  65. }
  66. $object = new Reception($db);
  67. if ($id > 0 || !empty($ref)) {
  68. $result = $object->fetch($id, $ref);
  69. if ($result < 0) {
  70. setEventMessages($object->error, $object->errors, 'errors');
  71. }
  72. $result = $object->fetch_thirdparty();
  73. if ($result < 0) {
  74. setEventMessages($object->error, $object->errors, 'errors');
  75. }
  76. if (!empty($object->origin)) {
  77. $origin = $object->origin;
  78. $object->fetch_origin();
  79. $typeobject = $object->origin;
  80. }
  81. if ($origin == 'order_supplier' && $object->$typeobject->id && (isModEnabled("fournisseur") && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) || isModEnabled("supplier_order"))) {
  82. $origin_id = $object->$typeobject->id;
  83. $objectsrc = new CommandeFournisseur($db);
  84. $objectsrc->fetch($object->$typeobject->id);
  85. }
  86. }
  87. if (empty($conf->reception->enabled)) {
  88. $permissiontoreceive = $user->rights->fournisseur->commande->receptionner;
  89. $permissiontocontrol = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->fournisseur->commande->receptionner)) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->fournisseur->commande_advance->check)));
  90. } else {
  91. $permissiontoreceive = $user->rights->reception->creer;
  92. $permissiontocontrol = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->reception->creer)) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->reception->reception_advance->validate)));
  93. }
  94. // $id is id of a purchase order.
  95. $result = restrictedArea($user, 'fournisseur', $object, 'reception');
  96. if (!isModEnabled('stock')) {
  97. accessforbidden();
  98. }
  99. $usercancreate = $user->hasRight('reception', 'creer');
  100. $permissiontoadd = $usercancreate; // Used by the include of actions_addupdatedelete.inc.php
  101. /*
  102. * Actions
  103. */
  104. $parameters = array();
  105. $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
  106. if ($reshook < 0) {
  107. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  108. }
  109. // Update a dispatched line
  110. if ($action == 'updatelines' && $permissiontoreceive) {
  111. $db->begin();
  112. $error = 0;
  113. $supplierorderdispatch = new CommandeFournisseurDispatch($db);
  114. $pos = 0;
  115. foreach ($_POST as $key => $value) {
  116. // without batch module enabled
  117. $reg = array();
  118. if (preg_match('/^product_.*([0-9]+)_([0-9]+)$/i', $key, $reg)) {
  119. $pos++;
  120. if (preg_match('/^product_([0-9]+)_([0-9]+)$/i', $key, $reg)) {
  121. $modebatch = "barcode";
  122. } elseif (preg_match('/^product_batch_([0-9]+)_([0-9]+)$/i', $key, $reg)) { // With batchmode enabled
  123. $modebatch = "batch";
  124. }
  125. $numline = $pos;
  126. if ($modebatch == "barcode") {
  127. $prod = "product_".$reg[1].'_'.$reg[2];
  128. } else {
  129. $prod = 'product_batch_'.$reg[1].'_'.$reg[2];
  130. }
  131. $qty = "qty_".$reg[1].'_'.$reg[2];
  132. $ent = "entrepot_".$reg[1].'_'.$reg[2];
  133. $pu = "pu_".$reg[1].'_'.$reg[2]; // This is unit price including discount
  134. $fk_commandefourndet = "fk_commandefourndet_".$reg[1].'_'.$reg[2];
  135. $idline = GETPOST("idline_".$reg[1].'_'.$reg[2]);
  136. $lot = '';
  137. $dDLUO = '';
  138. $dDLC = '';
  139. if ($modebatch == "batch") {
  140. $lot = GETPOST('lot_number_'.$reg[1].'_'.$reg[2]);
  141. $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'));
  142. $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'));
  143. }
  144. if (!empty($conf->global->SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT)) {
  145. if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
  146. $dto = GETPOST("dto_".$reg[1].'_'.$reg[2], 'int');
  147. if (!empty($dto)) {
  148. $unit_price = price2num(GETPOST("pu_".$reg[1]) * (100 - $dto) / 100, 'MU');
  149. }
  150. $saveprice = "saveprice_".$reg[1].'_'.$reg[2];
  151. }
  152. }
  153. // We ask to move a qty
  154. if (($modebatch == "batch" && GETPOST($qty) > 0) || ($modebatch == "barcode" && GETPOST($qty) != 0)) {
  155. if (!(GETPOST($ent, 'int') > 0)) {
  156. dol_syslog('No dispatch for line '.$key.' as no warehouse was chosen.');
  157. $text = $langs->transnoentities('Warehouse').', '.$langs->transnoentities('Line').' '.($numline);
  158. setEventMessages($langs->trans('ErrorFieldRequired', $text), null, 'errors');
  159. $error++;
  160. }
  161. if (!$error) {
  162. if ($idline > 0) {
  163. $result = $supplierorderdispatch->fetch($idline);
  164. if ($result < 0) {
  165. setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
  166. $error++;
  167. } else {
  168. $qtystart = $supplierorderdispatch->qty;
  169. $supplierorderdispatch->qty = GETPOST($qty);
  170. $supplierorderdispatch->fk_entrepot = GETPOST($ent, 'int');
  171. if ($modebatch == "batch") {
  172. $supplierorderdispatch->eatby = $dDLUO;
  173. $supplierorderdispatch->sellby = $dDLC;
  174. }
  175. $result = $supplierorderdispatch->update($user);
  176. if ($result < 0) {
  177. setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
  178. $error++;
  179. }
  180. // If module stock is enabled and the stock increase is done on purchase order dispatching
  181. if (!$error && GETPOST($ent, 'int') > 0 && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) {
  182. $mouv = new MouvementStock($db);
  183. $product = GETPOST($prod, 'int');
  184. $entrepot = GETPOST($ent, 'int');
  185. $qtymouv = GETPOST($qty) - $qtystart;
  186. $price = GETPOST($pu);
  187. $comment = GETPOST('comment');
  188. $inventorycode = dol_print_date(dol_now(), 'dayhourlog');
  189. $now = dol_now();
  190. $eatby = '';
  191. $sellby = '';
  192. $batch = '';
  193. if ($modebatch == "batch") {
  194. $eatby = $dDLUO;
  195. $sellby = $dDLC;
  196. $batch = $supplierorderdispatch->batch;
  197. }
  198. if ($product > 0) {
  199. // $price should take into account discount (except if option STOCK_EXCLUDE_DISCOUNT_FOR_PMP is on)
  200. $mouv->origin = $objectsrc;
  201. $mouv->setOrigin($objectsrc->element, $objectsrc->id);
  202. // Method change if qty < 0
  203. if (!empty($conf->global->SUPPLIER_ORDER_ALLOW_NEGATIVE_QTY_FOR_SUPPLIER_ORDER_RETURN) && $qtymouv < 0) {
  204. $result = $mouv->livraison($user, $product, $entrepot, $qtymouv*(-1), $price, $comment, $now, $eatby, $sellby, $batch, 0, $inventorycode);
  205. } else {
  206. $result = $mouv->reception($user, $product, $entrepot, $qtymouv, $price, $comment, $eatby, $sellby, $batch, '', 0, $inventorycode);
  207. }
  208. if ($result < 0) {
  209. setEventMessages($mouv->error, $mouv->errors, 'errors');
  210. $error++;
  211. }
  212. }
  213. }
  214. }
  215. } else {
  216. $result = $objectsrc->dispatchProduct($user, GETPOST($prod, 'int'), GETPOST($qty), GETPOST($ent, 'int'), GETPOST($pu), GETPOST('comment'), $dDLUO, $dDLC, $lot, GETPOST($fk_commandefourndet, 'int'), 0, $object->id);
  217. if ($result < 0) {
  218. setEventMessages($objectsrc->error, $objectsrc->errors, 'errors');
  219. $error++;
  220. }
  221. }
  222. if (!$error && !empty($conf->global->SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT)) {
  223. if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
  224. $dto = price2num(GETPOST("dto_".$reg[1].'_'.$reg[2], 'int'), '');
  225. if (empty($dto)) {
  226. $dto = 0;
  227. }
  228. //update supplier price
  229. if (GETPOSTISSET($saveprice)) {
  230. // TODO Use class
  231. $sql = "UPDATE ".MAIN_DB_PREFIX."product_fournisseur_price";
  232. $sql .= " SET unitprice='".price2num(GETPOST($pu), 'MU')."'";
  233. $sql .= ", price=".price2num(GETPOST($pu), 'MU')."*quantity";
  234. $sql .= ", remise_percent = ".((float) $dto);
  235. $sql .= " WHERE fk_soc=".((int) $object->socid);
  236. $sql .= " AND fk_product=".((int) GETPOST($prod, 'int'));
  237. $resql = $db->query($sql);
  238. }
  239. }
  240. }
  241. }
  242. }
  243. }
  244. }
  245. if ($error > 0) {
  246. $db->rollback();
  247. setEventMessages($error, $errors, 'errors');
  248. } else {
  249. $db->commit();
  250. setEventMessages($langs->trans("ReceptionUpdated"), null);
  251. }
  252. }
  253. /*
  254. * View
  255. */
  256. $now = dol_now();
  257. $form = new Form($db);
  258. $formproduct = new FormProduct($db);
  259. $warehouse_static = new Entrepot($db);
  260. $supplierorderdispatch = new CommandeFournisseurDispatch($db);
  261. $title = $object->ref." - ".$langs->trans('ReceptionDistribution');
  262. $help_url = 'EN:Module_Suppliers_Orders|FR:CommandeFournisseur|ES:Módulo_Pedidos_a_proveedores';
  263. $morejs = array('/fourn/js/lib_dispatch.js.php');
  264. llxHeader('', $title, $help_url, '', 0, 0, $morejs);
  265. if ($id > 0 || !empty($ref)) {
  266. if (!empty($object->origin) && $object->origin_id > 0) {
  267. $object->origin = 'CommandeFournisseur';
  268. $typeobject = $object->origin;
  269. $origin = $object->origin;
  270. $origin_id = $object->origin_id;
  271. $object->fetch_origin(); // Load property $object->commande, $object->propal, ...
  272. }
  273. $soc = new Societe($db);
  274. $soc->fetch($object->socid);
  275. $author = new User($db);
  276. $author->fetch($object->user_author_id);
  277. $head = reception_prepare_head($object);
  278. $title = $langs->trans("SupplierOrder");
  279. print dol_get_fiche_head($head, 'dispatch', $langs->trans("Reception"), -1, 'dollyrevert');
  280. $formconfirm = '';
  281. // Confirmation to delete line
  282. if ($action == 'ask_deleteline') {
  283. $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1);
  284. }
  285. // Call Hook formConfirm
  286. $parameters = array('lineid' => $lineid);
  287. // Note that $action and $object may be modified by hook
  288. $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action);
  289. if (empty($reshook)) {
  290. $formconfirm .= $hookmanager->resPrint;
  291. } elseif ($reshook > 0) {
  292. $formconfirm = $hookmanager->resPrint;
  293. }
  294. // Print form confirm
  295. print $formconfirm;
  296. // Reception card
  297. $linkback = '<a href="'.DOL_URL_ROOT.'/reception/list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
  298. $morehtmlref = '<div class="refidno">';
  299. // Ref customer reception
  300. $morehtmlref .= $form->editfieldkey("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, $user->rights->reception->creer, 'string', '', 0, 1);
  301. $morehtmlref .= $form->editfieldval("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, $user->rights->reception->creer, 'string', '', null, null, '', 1);
  302. // Thirdparty
  303. $morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1);
  304. // Project
  305. if (isModEnabled('project')) {
  306. $langs->load("projects");
  307. $morehtmlref .= '<br>';
  308. if (0) { // Do not change on reception
  309. $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
  310. if ($action != 'classify' && $permissiontoadd) {
  311. $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
  312. }
  313. $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, (empty($conf->global->PROJECT_CAN_ALWAYS_LINK_TO_ALL_SUPPLIERS) ? $object->socid : -1), $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
  314. } else {
  315. if (!empty($objectsrc) && !empty($objectsrc->fk_project)) {
  316. $proj = new Project($db);
  317. $proj->fetch($objectsrc->fk_project);
  318. $morehtmlref .= $proj->getNomUrl(1);
  319. if ($proj->title) {
  320. $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
  321. }
  322. }
  323. }
  324. }
  325. $morehtmlref .= '</div>';
  326. dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
  327. print '<div class="fichecenter">';
  328. print '<div class="underbanner clearboth"></div>';
  329. print '<table class="border tableforfield" width="100%">';
  330. // Linked documents
  331. if ($typeobject == 'commande' && $object->$typeobject->id && isModEnabled('commande')) {
  332. print '<tr><td>';
  333. print $langs->trans("RefOrder").'</td>';
  334. print '<td colspan="3">';
  335. print $objectsrc->getNomUrl(1, 'commande');
  336. print "</td>\n";
  337. print '</tr>';
  338. }
  339. if ($typeobject == 'propal' && $object->$typeobject->id && isModEnabled("propal")) {
  340. print '<tr><td>';
  341. print $langs->trans("RefProposal").'</td>';
  342. print '<td colspan="3">';
  343. print $objectsrc->getNomUrl(1, 'reception');
  344. print "</td>\n";
  345. print '</tr>';
  346. }
  347. if ($typeobject == 'CommandeFournisseur' && $object->$typeobject->id && isModEnabled("propal")) {
  348. print '<tr><td>';
  349. print $langs->trans("SupplierOrder").'</td>';
  350. print '<td colspan="3">';
  351. print $objectsrc->getNomUrl(1, 'reception');
  352. print "</td>\n";
  353. print '</tr>';
  354. }
  355. // Date creation
  356. print '<tr><td class="titlefield">'.$langs->trans("DateCreation").'</td>';
  357. print '<td colspan="3">'.dol_print_date($object->date_creation, "dayhour", "tzuserrel")."</td>\n";
  358. print '</tr>';
  359. // Delivery date planned
  360. print '<tr><td height="10">';
  361. print '<table class="nobordernopadding" width="100%"><tr><td>';
  362. print $langs->trans('DateDeliveryPlanned');
  363. print '</td>';
  364. print '</tr></table>';
  365. print '</td><td colspan="2">';
  366. print $object->date_delivery ? dol_print_date($object->date_delivery, 'dayhour') : '&nbsp;';
  367. print '</td>';
  368. print '</tr>';
  369. print '</table>';
  370. print '<br><center>';
  371. print '<a href="#" id="resetalltoexpected" class="marginrightonly paddingright marginleftonly paddingleft">'.img_picto("", 'autofill', 'class="pictofixedwidth"').$langs->trans("RestoreWithCurrentQtySaved").'</a></td>';
  372. // Link to clear qty
  373. print '<a href="#" id="autoreset" class="marginrightonly paddingright marginleftonly paddingleft">'.img_picto("", 'eraser', 'class="pictofixedwidth"').$langs->trans("ClearQtys").'</a></td>';
  374. print '<center>';
  375. print '<br>';
  376. $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.
  377. if ($object->statut == Reception::STATUS_DRAFT) {
  378. require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
  379. $formproduct = new FormProduct($db);
  380. $formproduct->loadWarehouses();
  381. $entrepot = new Entrepot($db);
  382. $listwarehouses = $entrepot->list_array(1);
  383. print '<form method="post" action="'.$_SERVER["PHP_SELF"].'">';
  384. print '<input type="hidden" name="token" value="'.newToken().'">';
  385. print '<input type="hidden" name="action" value="updatelines">';
  386. print '<input type="hidden" name="id" value="'.$object->id.'">';
  387. print '<div class="div-table-responsive-no-min">';
  388. print '<table class="noborder centpercent">';
  389. // Get list of lines from the original Order into $products_dispatched with qty dispatched for each product id
  390. $products_dispatched = array();
  391. $sql = "SELECT l.rowid, cfd.fk_product, sum(cfd.qty) as qty";
  392. $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as cfd";
  393. $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."commande_fournisseurdet as l on l.rowid = cfd.fk_commandefourndet";
  394. $sql .= " WHERE cfd.fk_reception = ".((int) $object->id);
  395. $sql .= " GROUP BY l.rowid, cfd.fk_product";
  396. $resql = $db->query($sql);
  397. if ($resql) {
  398. $num = $db->num_rows($resql);
  399. $i = 0;
  400. if ($num) {
  401. while ($i < $num) {
  402. $objd = $db->fetch_object($resql);
  403. $products_dispatched[$objd->rowid] = price2num($objd->qty, 'MS');
  404. $i++;
  405. }
  406. }
  407. $db->free($resql);
  408. }
  409. //$sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref AS sref, SUM(l.qty) as qty,";
  410. $sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref AS sref, l.qty as qty,";
  411. $sql .= " p.ref, p.label, p.tobatch, p.fk_default_warehouse";
  412. // Enable hooks to alter the SQL query (SELECT)
  413. $parameters = array();
  414. $reshook = $hookmanager->executeHooks(
  415. 'printFieldListSelect',
  416. $parameters,
  417. $object,
  418. $action
  419. );
  420. if ($reshook < 0) {
  421. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  422. }
  423. $sql .= $hookmanager->resPrint;
  424. $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as l";
  425. $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON l.fk_product=p.rowid";
  426. $sql .= " WHERE l.fk_commande = ".((int) $objectsrc->id);
  427. if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
  428. $sql .= " AND l.product_type = 0";
  429. }
  430. // Enable hooks to alter the SQL query (WHERE)
  431. $parameters = array();
  432. $reshook = $hookmanager->executeHooks(
  433. 'printFieldListWhere',
  434. $parameters,
  435. $object,
  436. $action
  437. );
  438. if ($reshook < 0) {
  439. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  440. }
  441. $sql .= $hookmanager->resPrint;
  442. //$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
  443. $sql .= " ORDER BY l.rang, p.ref, p.label";
  444. $resql = $db->query($sql);
  445. if ($resql) {
  446. $num = $db->num_rows($resql);
  447. $i = 0;
  448. if ($num) {
  449. print '<tr class="liste_titre">';
  450. print '<td>'.$langs->trans("Description").'</td>';
  451. if (isModEnabled('productbatch')) {
  452. print '<td class="dispatch_batch_number_title">'.$langs->trans("batch_number").'</td>';
  453. if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
  454. print '<td class="dispatch_dlc_title">'.$langs->trans("SellByDate").'</td>';
  455. }
  456. if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
  457. print '<td class="dispatch_dluo_title">'.$langs->trans("EatByDate").'</td>';
  458. }
  459. } else {
  460. print '<td></td>';
  461. print '<td></td>';
  462. print '<td></td>';
  463. }
  464. print '<td class="right">'.$langs->trans("SupplierRef").'</td>';
  465. print '<td class="right">'.$langs->trans("QtyOrdered").'</td>';
  466. print '<td class="right">'.$langs->trans("QtyDispatchedShort").'</td>';
  467. print ' <td class="right">'.$langs->trans("QtyToDispatchShort");
  468. //print '<br><a href="#" id="autoreset">'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').$langs->trans("Reset").'</a></td>';
  469. print '<td width="32"></td>';
  470. if (!empty($conf->global->SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT)) {
  471. if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
  472. print '<td class="right">'.$langs->trans("Price").'</td>';
  473. print '<td class="right">'.$langs->trans("ReductionShort").' (%)</td>';
  474. print '<td class="right">'.$langs->trans("UpdatePrice").'</td>';
  475. }
  476. }
  477. print '<td align="right">'.$langs->trans("Warehouse");
  478. // Select warehouse to force it everywhere
  479. if (count($listwarehouses) > 1) {
  480. 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);
  481. } elseif (count($listwarehouses) == 1) {
  482. 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);
  483. }
  484. print '</td>';
  485. // Enable hooks to append additional columns
  486. $parameters = array();
  487. $reshook = $hookmanager->executeHooks(
  488. 'printFieldListTitle',
  489. $parameters,
  490. $object,
  491. $action
  492. );
  493. if ($reshook < 0) {
  494. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  495. }
  496. print $hookmanager->resPrint;
  497. print "</tr>\n";
  498. }
  499. $nbfreeproduct = 0; // Nb of lins of free products/services
  500. $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)
  501. // or nb of line that remain to dispatch if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is on.
  502. $conf->cache['product'] = array();
  503. // Loop on each source order line (may be more or less than current number of lines in llx_commande_fournisseurdet)
  504. while ($i < $num) {
  505. $objp = $db->fetch_object($resql);
  506. // On n'affiche pas les produits libres
  507. if (!$objp->fk_product > 0) {
  508. $nbfreeproduct++;
  509. } else {
  510. $alreadydispatched = isset($products_dispatched[$objp->rowid])?$products_dispatched[$objp->rowid]:0;
  511. $remaintodispatch = price2num($objp->qty, 5); // Calculation of dispatched
  512. if ($remaintodispatch < 0 && empty($conf->global->SUPPLIER_ORDER_ALLOW_NEGATIVE_QTY_FOR_SUPPLIER_ORDER_RETURN)) {
  513. $remaintodispatch = 0;
  514. }
  515. if ($remaintodispatch || empty($conf->global->SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED)) {
  516. $nbproduct++;
  517. // To show detail cref and description value, we must make calculation by cref
  518. // print ($objp->cref?' ('.$objp->cref.')':'');
  519. // if ($objp->description) print '<br>'.nl2br($objp->description);
  520. $suffix = '_0_'.$i;
  521. print "\n";
  522. print '<!-- Line to dispatch '.$suffix.' -->'."\n";
  523. // hidden fields for js function
  524. print '<input id="qty_ordered'.$suffix.'" type="hidden" value="'.$objp->qty.'">';
  525. print '<input id="qty_dispatched'.$suffix.'" type="hidden" data-dispatched="'.((float) $alreadydispatched).'" value="'.(float) $alreadydispatched.'">';
  526. print '<tr class="oddeven">';
  527. if (empty($conf->cache['product'][$objp->fk_product])) {
  528. $tmpproduct = new Product($db);
  529. $tmpproduct->fetch($objp->fk_product);
  530. $conf->cache['product'][$objp->fk_product] = $tmpproduct;
  531. } else {
  532. $tmpproduct = $conf->cache['product'][$objp->fk_product];
  533. }
  534. $linktoprod = $tmpproduct->getNomUrl(1);
  535. $linktoprod .= ' - '.$objp->label."\n";
  536. if (isModEnabled('productbatch')) {
  537. if ($objp->tobatch) {
  538. // Product
  539. print '<td>';
  540. print $linktoprod;
  541. print "</td>";
  542. print '<td class="dispatch_batch_number"></td>';
  543. if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
  544. print '<td class="dispatch_dlc"></td>';
  545. }
  546. if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
  547. print '<td class="dispatch_dluo"></td>';
  548. }
  549. } else {
  550. // Product
  551. print '<td>';
  552. print $linktoprod;
  553. print "</td>";
  554. print '<td class="dispatch_batch_number">';
  555. print '<span class="opacitymedium small">'.$langs->trans("ProductDoesNotUseBatchSerial").'</small>';
  556. print '</td>';
  557. if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
  558. print '<td class="dispatch_dlc"></td>';
  559. }
  560. if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
  561. print '<td class="dispatch_dluo"></td>';
  562. }
  563. }
  564. } else {
  565. print '<td colspan="4">';
  566. print $linktoprod;
  567. print "</td>";
  568. }
  569. // Define unit price for PMP calculation
  570. $up_ht_disc = $objp->subprice;
  571. if (!empty($objp->remise_percent) && empty($conf->global->STOCK_EXCLUDE_DISCOUNT_FOR_PMP)) {
  572. $up_ht_disc = price2num($up_ht_disc * (100 - $objp->remise_percent) / 100, 'MU');
  573. }
  574. // Supplier ref
  575. print '<td class="right">'.$objp->sref.'</td>';
  576. // Qty ordered
  577. print '<td class="right">'.$objp->qty.'</td>';
  578. // Already dispatched
  579. print '<td class="right">'.$alreadydispatched.'</td>';
  580. print '<td class="right">';
  581. print '</td>'; // Qty to dispatch
  582. print '<td>';
  583. print '</td>'; // Dispatch column
  584. print '<td></td>'; // Warehouse column
  585. $sql = "SELECT cfd.rowid, cfd.qty, cfd.fk_entrepot, cfd.batch, cfd.eatby, cfd.sellby, cfd.fk_product";
  586. $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as cfd";
  587. $sql .= " WHERE cfd.fk_reception = ".((int) $object->id);
  588. $sql .= " AND cfd.fk_commande = ".((int) $objectsrc->id);
  589. $sql .= " AND cfd.fk_commandefourndet = ".(int) $objp->rowid;
  590. //print $sql;
  591. $resultsql = $db->query($sql);
  592. $j = 0;
  593. if ($resultsql) {
  594. $numd = $db->num_rows($resultsql);
  595. while ($j < $numd) {
  596. $suffix = "_".$j."_".$i;
  597. $objd = $db->fetch_object($resultsql);
  598. if (isModEnabled('productbatch') && !empty($objd->batch)) {
  599. $type = 'batch';
  600. // Enable hooks to append additional columns
  601. $parameters = array(
  602. // allows hook to distinguish between the rows with information and the rows with dispatch form input
  603. 'is_information_row' => true,
  604. 'j' => $j,
  605. 'suffix' => $suffix,
  606. 'objd' => $objd,
  607. );
  608. $reshook = $hookmanager->executeHooks(
  609. 'printFieldListValue',
  610. $parameters,
  611. $object,
  612. $action
  613. );
  614. if ($reshook < 0) {
  615. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  616. }
  617. print $hookmanager->resPrint;
  618. print '</tr>';
  619. print '<!-- line for batch '.$numline.' -->';
  620. print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
  621. print '<td>';
  622. print '<input id="fk_commandefourndet'.$suffix.'" name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
  623. print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="'.$objd->rowid.'">';
  624. print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objd->fk_product.'">';
  625. print '<!-- This is a U.P. (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
  626. if (!empty($conf->global->SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT)) { // Not tested !
  627. print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
  628. } else {
  629. print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
  630. }
  631. print '</td>';
  632. print '<td>';
  633. print '<input disabled="" type="text" class="inputlotnumber quatrevingtquinzepercent" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.$objd->batch.'">';
  634. print '</td>';
  635. if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
  636. print '<td class="nowraponall">';
  637. $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'));
  638. print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, '', '', 1, '');
  639. print '</td>';
  640. }
  641. if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
  642. print '<td class="nowraponall">';
  643. $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'));
  644. print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, '', '', 1, '');
  645. print '</td>';
  646. }
  647. print '<td colspan="3">&nbsp;</td>'; // Supplier ref + Qty ordered + qty already dispatched
  648. } else {
  649. $type = 'dispatch';
  650. $colspan = 7;
  651. $colspan = (!empty($conf->global->PRODUCT_DISABLE_SELLBY)) ? --$colspan : $colspan;
  652. $colspan = (!empty($conf->global->PRODUCT_DISABLE_EATBY)) ? --$colspan : $colspan;
  653. // Enable hooks to append additional columns
  654. $parameters = array(
  655. // allows hook to distinguish between the rows with information and the rows with dispatch form input
  656. 'is_information_row' => true,
  657. 'j' => $j,
  658. 'suffix' => $suffix,
  659. 'objd' => $objd,
  660. );
  661. $reshook = $hookmanager->executeHooks(
  662. 'printFieldListValue',
  663. $parameters,
  664. $object,
  665. $action
  666. );
  667. if ($reshook < 0) {
  668. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  669. }
  670. print $hookmanager->resPrint;
  671. print '</tr>';
  672. print '<!-- line no batch '.$numline.' -->';
  673. print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
  674. print '<td colspan="'.$colspan.'">';
  675. print '<input id="fk_commandefourndet'.$suffix.'" name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
  676. print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="'.$objd->rowid.'">';
  677. print '<input name="product'.$suffix.'" type="hidden" value="'.$objd->fk_product.'">';
  678. print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
  679. if (!empty($conf->global->SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT)) { // Not tested !
  680. print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
  681. } else {
  682. print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
  683. }
  684. print '</td>';
  685. }
  686. // Qty to dispatch
  687. print '<td class="right">';
  688. print '<a href="#" id="reset'.$suffix.'" class="resetline">'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').'</a>';
  689. print '<input id="qty'.$suffix.'" onchange="onChangeDispatchLineQty($(this))" name="qty'.$suffix.'" data-type="'.$type.'" data-index="'.$i.'" class="width50 right qtydispatchinput" value="'.(GETPOSTISSET('qty'.$suffix) ? GETPOST('qty'.$suffix, 'int') : $objd->qty).'" data-expected="'.$objd->qty.'">';
  690. print '</td>';
  691. print '<td>';
  692. if (isModEnabled('productbatch') && $objp->tobatch > 0) {
  693. $type = 'batch';
  694. print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" '.($numd != $j+1 ? 'style="display:none"' : '').' onClick="addDispatchLine('.$i.', \''.$type.'\')"');
  695. } else {
  696. $type = 'dispatch';
  697. print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" '.($numd != $j+1 ? 'style="display:none"' : '').' onClick="addDispatchLine('.$i.', \''.$type.'\')"');
  698. }
  699. print '</td>';
  700. if (!empty($conf->global->SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT)) {
  701. if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
  702. // Price
  703. print '<td class="right">';
  704. print '<input id="pu'.$suffix.'" name="pu'.$suffix.'" type="text" size="8" value="'.price((GETPOST('pu'.$suffix) != '' ? price2num(GETPOST('pu'.$suffix)) : $up_ht_disc)).'">';
  705. print '</td>';
  706. // Discount
  707. print '<td class="right">';
  708. print '<input id="dto'.$suffix.'" name="dto'.$suffix.'" type="text" size="8" value="'.(GETPOST('dto'.$suffix) != '' ? GETPOST('dto'.$suffix) : '').'">';
  709. print '</td>';
  710. // Save price
  711. print '<td class="center">';
  712. print '<input class="flat checkformerge" type="checkbox" name="saveprice'.$suffix.'" value="'.(GETPOST('saveprice'.$suffix) != '' ? GETPOST('saveprice'.$suffix) : '').'">';
  713. print '</td>';
  714. }
  715. }
  716. // Warehouse
  717. print '<td class="right">';
  718. if (count($listwarehouses) > 1) {
  719. print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ?GETPOST("entrepot".$suffix) : $objd->fk_entrepot, "entrepot".$suffix, '', 1, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix);
  720. } elseif (count($listwarehouses) == 1) {
  721. print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ?GETPOST("entrepot".$suffix) : $objd->fk_entrepot, "entrepot".$suffix, '', 0, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix);
  722. } else {
  723. $langs->load("errors");
  724. print $langs->trans("ErrorNoWarehouseDefined");
  725. }
  726. print "</td>\n";
  727. // Enable hooks to append additional columns
  728. $parameters = array(
  729. 'is_information_row' => false, // this is a dispatch form row
  730. 'i' => $i,
  731. 'suffix' => $suffix,
  732. 'objp' => $objp,
  733. );
  734. $reshook = $hookmanager->executeHooks(
  735. 'printFieldListValue',
  736. $parameters,
  737. $object,
  738. $action
  739. );
  740. if ($reshook < 0) {
  741. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  742. }
  743. print $hookmanager->resPrint;
  744. print "</tr>\n";
  745. $j++;
  746. $numline++;
  747. }
  748. $suffix = "_".$j."_".$i;
  749. }
  750. if ($j == 0) {
  751. if (isModEnabled('productbatch') && !empty($objp->tobatch)) {
  752. $type = 'batch';
  753. // Enable hooks to append additional columns
  754. $parameters = array(
  755. // allows hook to distinguish between the rows with information and the rows with dispatch form input
  756. 'is_information_row' => true,
  757. 'j' => $j,
  758. 'suffix' => $suffix,
  759. 'objp' => $objp,
  760. );
  761. $reshook = $hookmanager->executeHooks(
  762. 'printFieldListValue',
  763. $parameters,
  764. $object,
  765. $action
  766. );
  767. if ($reshook < 0) {
  768. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  769. }
  770. print $hookmanager->resPrint;
  771. print '</tr>';
  772. print '<!-- line for batch '.$numline.' (not dispatched line yet for this order line) -->';
  773. print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'">';
  774. print '<td>';
  775. print '<input id="fk_commandefourndet'.$suffix.'" name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
  776. print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="-1">';
  777. print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
  778. print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
  779. if (!empty($conf->global->SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT)) { // Not tested !
  780. print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
  781. } else {
  782. print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
  783. }
  784. print '</td>';
  785. print '<td>';
  786. print '<input type="text" class="inputlotnumber quatrevingtquinzepercent" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.GETPOST('lot_number'.$suffix).'">';
  787. print '</td>';
  788. if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
  789. print '<td class="nowraponall">';
  790. $dlcdatesuffix = dol_mktime(0, 0, 0, GETPOST('dlc'.$suffix.'month'), GETPOST('dlc'.$suffix.'day'), GETPOST('dlc'.$suffix.'year'));
  791. print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, '', '', 1, '');
  792. print '</td>';
  793. }
  794. if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
  795. print '<td class="nowraponall">';
  796. $dluodatesuffix = dol_mktime(0, 0, 0, GETPOST('dluo'.$suffix.'month'), GETPOST('dluo'.$suffix.'day'), GETPOST('dluo'.$suffix.'year'));
  797. print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, '', '', 1, '');
  798. print '</td>';
  799. }
  800. print '<td colspan="3">&nbsp;</td>'; // Supplier ref + Qty ordered + qty already dispatched
  801. } else {
  802. $type = 'dispatch';
  803. $colspan = 7;
  804. $colspan = (!empty($conf->global->PRODUCT_DISABLE_SELLBY)) ? --$colspan : $colspan;
  805. $colspan = (!empty($conf->global->PRODUCT_DISABLE_EATBY)) ? --$colspan : $colspan;
  806. // Enable hooks to append additional columns
  807. $parameters = array(
  808. // allows hook to distinguish between the rows with information and the rows with dispatch form input
  809. 'is_information_row' => true,
  810. 'j' => $j,
  811. 'suffix' => $suffix,
  812. 'objp' => $objp,
  813. );
  814. $reshook = $hookmanager->executeHooks(
  815. 'printFieldListValue',
  816. $parameters,
  817. $object,
  818. $action
  819. );
  820. if ($reshook < 0) {
  821. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  822. }
  823. print $hookmanager->resPrint;
  824. print '</tr>';
  825. print '<!-- line no batch '.$numline.' (not dispatched line yet for this order line) -->';
  826. print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
  827. print '<td colspan="'.$colspan.'">';
  828. print '<input id="fk_commandefourndet'.$suffix.'" name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
  829. print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="-1">';
  830. print '<input name="product'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
  831. print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
  832. if (!empty($conf->global->SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT)) { // Not tested !
  833. print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" data-type="text" value="'.price2num($up_ht_disc, 'MU').'">';
  834. } else {
  835. print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
  836. }
  837. print '</td>';
  838. }
  839. // Qty to dispatch
  840. print '<td class="right">';
  841. print '<a href="#" id="reset'.$suffix.'" class="resetline">'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').'</a>';
  842. print '<input id="qty'.$suffix.'" onchange="onChangeDispatchLineQty($(this))" name="qty'.$suffix.'" data-index="'.$i.'" data-type="text" class="width50 right qtydispatchinput" value="'.(GETPOSTISSET('qty'.$suffix) ? GETPOST('qty'.$suffix, 'int') : (empty($conf->global->SUPPLIER_ORDER_DISPATCH_FORCE_QTY_INPUT_TO_ZERO) ? $remaintodispatch : 0)).'" data-expected="'.$remaintodispatch.'">';
  843. print '</td>';
  844. print '<td>';
  845. if (isModEnabled('productbatch') && $objp->tobatch > 0) {
  846. $type = 'batch';
  847. print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
  848. } else {
  849. $type = 'dispatch';
  850. print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
  851. }
  852. print '</td>';
  853. if (!empty($conf->global->SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT)) {
  854. if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
  855. // Price
  856. print '<td class="right">';
  857. print '<input id="pu'.$suffix.'" name="pu'.$suffix.'" type="text" size="8" value="'.price((GETPOST('pu'.$suffix) != '' ? price2num(GETPOST('pu'.$suffix)) : $up_ht_disc)).'">';
  858. print '</td>';
  859. // Discount
  860. print '<td class="right">';
  861. print '<input id="dto'.$suffix.'" name="dto'.$suffix.'" type="text" size="8" value="'.(GETPOST('dto'.$suffix) != '' ? GETPOST('dto'.$suffix) : '').'">';
  862. print '</td>';
  863. // Save price
  864. print '<td class="center">';
  865. print '<input class="flat checkformerge" type="checkbox" name="saveprice'.$suffix.'" value="'.(GETPOST('saveprice'.$suffix) != '' ? GETPOST('saveprice'.$suffix) : '').'">';
  866. print '</td>';
  867. }
  868. }
  869. // Warehouse
  870. print '<td class="right">';
  871. if (count($listwarehouses) > 1) {
  872. 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);
  873. } elseif (count($listwarehouses) == 1) {
  874. 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);
  875. } else {
  876. $langs->load("errors");
  877. print $langs->trans("ErrorNoWarehouseDefined");
  878. }
  879. print "</td>\n";
  880. // Enable hooks to append additional columns
  881. $parameters = array(
  882. 'is_information_row' => false, // this is a dispatch form row
  883. 'i' => $i,
  884. 'suffix' => $suffix,
  885. 'objp' => $objp,
  886. );
  887. $reshook = $hookmanager->executeHooks(
  888. 'printFieldListValue',
  889. $parameters,
  890. $object,
  891. $action
  892. );
  893. if ($reshook < 0) {
  894. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  895. }
  896. print $hookmanager->resPrint;
  897. print "</tr>\n";
  898. }
  899. }
  900. }
  901. $i++;
  902. }
  903. $db->free($resql);
  904. } else {
  905. dol_print_error($db);
  906. }
  907. print "</table>\n";
  908. print '</div>';
  909. if ($nbproduct) {
  910. $checkboxlabel = $langs->trans("CloseReceivedSupplierOrdersAutomatically", $langs->transnoentitiesnoconv('StatusOrderReceivedAll'));
  911. print '<div class="center">';
  912. $parameters = array();
  913. $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
  914. // modified by hook
  915. if (empty($reshook)) {
  916. if (empty($conf->reception->enabled)) {
  917. print $langs->trans("Comment").' : ';
  918. print '<input type="text" class="minwidth400" maxlength="128" name="comment" value="';
  919. print GETPOSTISSET("comment") ? GETPOST("comment") : $langs->trans("DispatchSupplierOrder", $object->ref);
  920. // print ' / '.$object->ref_supplier; // Not yet available
  921. print '" class="flat"><br>';
  922. print '<input type="checkbox" checked="checked" name="closeopenorder"> '.$checkboxlabel;
  923. }
  924. $dispatchBt = empty($conf->reception->enabled) ? $langs->trans("Receive") : $langs->trans("CreateReception");
  925. print '<br>';
  926. print '<input type="submit" id="submitform" class="button" name="dispatch" value="'.$langs->trans("Save").'"';
  927. $disabled = 0;
  928. if (!$permissiontoreceive) {
  929. $disabled = 1;
  930. }
  931. if (count($listwarehouses) <= 0) {
  932. $disabled = 1;
  933. }
  934. if ($disabled) {
  935. print ' disabled';
  936. }
  937. print '>';
  938. }
  939. print '</div>';
  940. }
  941. // Message if nothing to dispatch
  942. if (!$nbproduct) {
  943. print "<br>\n";
  944. if (empty($conf->global->SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED)) {
  945. print '<div class="opacitymedium">'.$langs->trans("NoPredefinedProductToDispatch").'</div>'; // No predefined line at all
  946. } else {
  947. print '<div class="opacitymedium">'.$langs->trans("NoMorePredefinedProductToDispatch").'</div>'; // No predefined line that remain to be dispatched.
  948. }
  949. }
  950. print '</form>';
  951. }
  952. print dol_get_fiche_end();
  953. // traitement entrepot par défaut
  954. print '<script type="text/javascript">
  955. $(document).ready(function () {
  956. $("select[name=fk_default_warehouse]").change(function() {
  957. var fk_default_warehouse = $("option:selected", this).val();
  958. $("select[name^=entrepot_]").val(fk_default_warehouse).change();
  959. });
  960. $("#autoreset").click(function() {
  961. $(".autoresettr").each(function(){
  962. id = $(this).attr("name");
  963. idtab = id.split("_");
  964. if ($(this).data("remove") == "clear"){
  965. console.log("We clear the object to expected value")
  966. $("#qty_"+idtab[1]+"_"+idtab[2]).val("");
  967. /*
  968. qtyexpected = $("#qty_"+idtab[1]+"_"+idtab[2]).data("expected")
  969. console.log(qtyexpected);
  970. $("#qty_"+idtab[1]+"_"+idtab[2]).val(qtyexpected);
  971. qtydispatched = $("#qty_dispatched_0_"+idtab[2]).data("dispatched")
  972. $("#qty_dispatched_0_"+idtab[2]).val(qtydispatched);
  973. */
  974. } else {
  975. console.log("We remove the object")
  976. $(this).remove();
  977. $("tr[name^=\'"+idtab[0]+"_\'][name$=\'_"+idtab[2]+"\']:last .splitbutton").show();
  978. }
  979. });
  980. return false;
  981. });
  982. $("#resetalltoexpected").click(function(){
  983. $(".qtydispatchinput").each(function(){
  984. console.log("We reset to expected "+$(this).attr("id")+" qty to dispatch");
  985. $(this).val($(this).data("expected"));
  986. });
  987. return false;
  988. });
  989. $(".resetline").click(function(){
  990. id = $(this).attr("id");
  991. id = id.split("reset_");
  992. console.log("Reset trigger for id = qty_"+id[1]);
  993. $("#qty_"+id[1]).val("");
  994. });
  995. });
  996. </script>';
  997. }
  998. // End of page
  999. llxFooter();
  1000. $db->close();