dispatch.php 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339
  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-2020 Ferran Marcet <fmarcet@2byte.es>
  10. * Copyright (C) 2018 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. require '../../main.inc.php';
  32. require_once DOL_DOCUMENT_ROOT.'/core/modules/supplier_order/modules_commandefournisseur.php';
  33. require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
  34. require_once DOL_DOCUMENT_ROOT.'/core/lib/fourn.lib.php';
  35. require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
  36. require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.dispatch.class.php';
  37. require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
  38. require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
  39. if (!empty($conf->projet->enabled)) {
  40. require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
  41. }
  42. // Load translation files required by the page
  43. $langs->loadLangs(array("bills", "orders", "sendings", "companies", "deliveries", "products", "stocks", "receptions"));
  44. if (!empty($conf->productbatch->enabled)) {
  45. $langs->load('productbatch');
  46. }
  47. // Security check
  48. $id = GETPOST("id", 'int');
  49. $ref = GETPOST('ref');
  50. $lineid = GETPOST('lineid', 'int');
  51. $action = GETPOST('action', 'aZ09');
  52. $fk_default_warehouse = GETPOST('fk_default_warehouse', 'int');
  53. $cancel = GETPOST('cancel', 'alpha');
  54. $confirm = GETPOST('confirm', 'alpha');
  55. if ($user->socid) {
  56. $socid = $user->socid;
  57. }
  58. $result = restrictedArea($user, 'fournisseur', $id, 'commande_fournisseur', 'commande');
  59. if (empty($conf->stock->enabled)) {
  60. accessforbidden();
  61. }
  62. $hookmanager->initHooks(array('ordersupplierdispatch'));
  63. // Recuperation de l'id de projet
  64. $projectid = 0;
  65. if ($_GET["projectid"]) {
  66. $projectid = GETPOST("projectid", 'int');
  67. }
  68. $object = new CommandeFournisseur($db);
  69. if ($id > 0 || !empty($ref)) {
  70. $result = $object->fetch($id, $ref);
  71. if ($result < 0) {
  72. setEventMessages($object->error, $object->errors, 'errors');
  73. }
  74. $result = $object->fetch_thirdparty();
  75. if ($result < 0) {
  76. setEventMessages($object->error, $object->errors, 'errors');
  77. }
  78. }
  79. /*
  80. * Actions
  81. */
  82. $parameters = array();
  83. $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
  84. if ($reshook < 0) {
  85. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  86. }
  87. if ($action == 'checkdispatchline' && !((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)))) {
  88. $error = 0;
  89. $supplierorderdispatch = new CommandeFournisseurDispatch($db);
  90. $db->begin();
  91. $result = $supplierorderdispatch->fetch($lineid);
  92. if (!$result) {
  93. $error++;
  94. setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
  95. $action = '';
  96. }
  97. if (!$error) {
  98. $result = $supplierorderdispatch->setStatut(1);
  99. if ($result < 0) {
  100. setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
  101. $error++;
  102. $action = '';
  103. }
  104. }
  105. if (!$error) {
  106. $result = $object->calcAndSetStatusDispatch($user);
  107. if ($result < 0) {
  108. setEventMessages($object->error, $object->errors, 'errors');
  109. $error++;
  110. $action = '';
  111. }
  112. }
  113. if (!$error) {
  114. $db->commit();
  115. } else {
  116. $db->rollback();
  117. }
  118. }
  119. if ($action == 'uncheckdispatchline' && !((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)))) {
  120. $error = 0;
  121. $supplierorderdispatch = new CommandeFournisseurDispatch($db);
  122. $db->begin();
  123. $result = $supplierorderdispatch->fetch($lineid);
  124. if (!$result) {
  125. $error++;
  126. setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
  127. $action = '';
  128. }
  129. if (!$error) {
  130. $result = $supplierorderdispatch->setStatut(0);
  131. if ($result < 0) {
  132. setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
  133. $error++;
  134. $action = '';
  135. }
  136. }
  137. if (!$error) {
  138. $result = $object->calcAndSetStatusDispatch($user);
  139. if ($result < 0) {
  140. setEventMessages($object->error, $object->errors, 'errors');
  141. $error++;
  142. $action = '';
  143. }
  144. }
  145. if (!$error) {
  146. $db->commit();
  147. } else {
  148. $db->rollback();
  149. }
  150. }
  151. if ($action == 'denydispatchline' && !((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)))) {
  152. $error = 0;
  153. $supplierorderdispatch = new CommandeFournisseurDispatch($db);
  154. $db->begin();
  155. $result = $supplierorderdispatch->fetch($lineid);
  156. if (!$result) {
  157. $error++;
  158. setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
  159. $action = '';
  160. }
  161. if (!$error) {
  162. $result = $supplierorderdispatch->setStatut(2);
  163. if ($result < 0) {
  164. setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
  165. $error++;
  166. $action = '';
  167. }
  168. }
  169. if (!$error) {
  170. $result = $object->calcAndSetStatusDispatch($user);
  171. if ($result < 0) {
  172. setEventMessages($object->error, $object->errors, 'errors');
  173. $error++;
  174. $action = '';
  175. }
  176. }
  177. if (!$error) {
  178. $db->commit();
  179. } else {
  180. $db->rollback();
  181. }
  182. }
  183. if ($action == 'dispatch' && $user->rights->fournisseur->commande->receptionner) {
  184. $error = 0;
  185. $db->begin();
  186. $pos = 0;
  187. foreach ($_POST as $key => $value) {
  188. // without batch module enabled
  189. $reg = array();
  190. if (preg_match('/^product_([0-9]+)_([0-9]+)$/i', $key, $reg)) {
  191. $pos++;
  192. // $numline=$reg[2] + 1; // line of product
  193. $numline = $pos;
  194. $prod = "product_".$reg[1].'_'.$reg[2];
  195. $qty = "qty_".$reg[1].'_'.$reg[2];
  196. $ent = "entrepot_".$reg[1].'_'.$reg[2];
  197. if (empty(GETPOST($ent))) {
  198. $ent = $fk_default_warehouse;
  199. }
  200. $pu = "pu_".$reg[1].'_'.$reg[2]; // This is unit price including discount
  201. $fk_commandefourndet = "fk_commandefourndet_".$reg[1].'_'.$reg[2];
  202. if (!empty($conf->global->SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT)) {
  203. if (empty($conf->multicurrency->enabled) && empty($conf->dynamicprices->enabled)) {
  204. $dto = GETPOST("dto_".$reg[1].'_'.$reg[2], 'int');
  205. if (!empty($dto)) {
  206. $unit_price = price2num(GETPOST("pu_".$reg[1]) * (100 - $dto) / 100, 'MU');
  207. }
  208. $saveprice = "saveprice_".$reg[1].'_'.$reg[2];
  209. }
  210. }
  211. // We ask to move a qty
  212. if (GETPOST($qty) != 0) {
  213. if (!(GETPOST($ent, 'int') > 0)) {
  214. dol_syslog('No dispatch for line '.$key.' as no warehouse was chosen.');
  215. $text = $langs->transnoentities('Warehouse').', '.$langs->transnoentities('Line').' '.($numline);
  216. setEventMessages($langs->trans('ErrorFieldRequired', $text), null, 'errors');
  217. $error++;
  218. }
  219. if (!$error) {
  220. $result = $object->dispatchProduct($user, GETPOST($prod, 'int'), GETPOST($qty), GETPOST($ent, 'int'), GETPOST($pu), GETPOST('comment'), '', '', '', GETPOST($fk_commandefourndet, 'int'), $notrigger);
  221. if ($result < 0) {
  222. setEventMessages($object->error, $object->errors, 'errors');
  223. $error++;
  224. }
  225. if (!$error && !empty($conf->global->SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT)) {
  226. if (empty($conf->multicurrency->enabled) && empty($conf->dynamicprices->enabled)) {
  227. $dto = price2num(GETPOST("dto_".$reg[1].'_'.$reg[2], 'int'), '');
  228. if (empty($dto)) {
  229. $dto = 0;
  230. }
  231. //update supplier price
  232. if (GETPOSTISSET($saveprice)) {
  233. // TODO Use class
  234. $sql = "UPDATE ".MAIN_DB_PREFIX."product_fournisseur_price";
  235. $sql .= " SET unitprice='".price2num(GETPOST($pu), 'MU')."'";
  236. $sql .= ", price=".price2num(GETPOST($pu), 'MU')."*quantity";
  237. $sql .= ", remise_percent = ".((float) $dto);
  238. $sql .= " WHERE fk_soc=".((int) $object->socid);
  239. $sql .= " AND fk_product=".((int) GETPOST($prod, 'int'));
  240. $resql = $db->query($sql);
  241. }
  242. }
  243. }
  244. }
  245. }
  246. }
  247. // with batch module enabled
  248. if (preg_match('/^product_batch_([0-9]+)_([0-9]+)$/i', $key, $reg)) {
  249. $pos++;
  250. // eat-by date dispatch
  251. // $numline=$reg[2] + 1; // line of product
  252. $numline = $pos;
  253. $prod = 'product_batch_'.$reg[1].'_'.$reg[2];
  254. $qty = 'qty_'.$reg[1].'_'.$reg[2];
  255. $ent = 'entrepot_'.$reg[1].'_'.$reg[2];
  256. $pu = 'pu_'.$reg[1].'_'.$reg[2];
  257. $fk_commandefourndet = 'fk_commandefourndet_'.$reg[1].'_'.$reg[2];
  258. $lot = 'lot_number_'.$reg[1].'_'.$reg[2];
  259. $dDLUO = dol_mktime(12, 0, 0, $_POST['dluo_'.$reg[1].'_'.$reg[2].'month'], $_POST['dluo_'.$reg[1].'_'.$reg[2].'day'], $_POST['dluo_'.$reg[1].'_'.$reg[2].'year']);
  260. $dDLC = dol_mktime(12, 0, 0, $_POST['dlc_'.$reg[1].'_'.$reg[2].'month'], $_POST['dlc_'.$reg[1].'_'.$reg[2].'day'], $_POST['dlc_'.$reg[1].'_'.$reg[2].'year']);
  261. $fk_commandefourndet = 'fk_commandefourndet_'.$reg[1].'_'.$reg[2];
  262. if (!empty($conf->global->SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT)) {
  263. if (empty($conf->multicurrency->enabled) && empty($conf->dynamicprices->enabled)) {
  264. $dto = GETPOST("dto_".$reg[1].'_'.$reg[2], 'int');
  265. if (!empty($dto)) {
  266. $unit_price = price2num(GETPOST("pu_".$reg[1]) * (100 - $dto) / 100, 'MU');
  267. }
  268. $saveprice = "saveprice_".$reg[1].'_'.$reg[2];
  269. }
  270. }
  271. // We ask to move a qty
  272. if (GETPOST($qty) > 0) {
  273. if (!(GETPOST($ent, 'int') > 0)) {
  274. dol_syslog('No dispatch for line '.$key.' as no warehouse was chosen.');
  275. $text = $langs->transnoentities('Warehouse').', '.$langs->transnoentities('Line').' '.($numline).'-'.($reg[1] + 1);
  276. setEventMessages($langs->trans('ErrorFieldRequired', $text), null, 'errors');
  277. $error++;
  278. }
  279. if (!(GETPOST($lot, 'alpha') || $dDLUO || $dDLC)) {
  280. dol_syslog('No dispatch for line '.$key.' as serial/eat-by/sellby date are not set');
  281. $text = $langs->transnoentities('atleast1batchfield').', '.$langs->transnoentities('Line').' '.($numline).'-'.($reg[1] + 1);
  282. setEventMessages($langs->trans('ErrorFieldRequired', $text), null, 'errors');
  283. $error++;
  284. }
  285. if (!$error) {
  286. $result = $object->dispatchProduct($user, GETPOST($prod, 'int'), GETPOST($qty), GETPOST($ent, 'int'), GETPOST($pu), GETPOST('comment'), $dDLC, $dDLUO, GETPOST($lot, 'alpha'), GETPOST($fk_commandefourndet, 'int'), $notrigger);
  287. if ($result < 0) {
  288. setEventMessages($object->error, $object->errors, 'errors');
  289. $error++;
  290. }
  291. if (!$error && !empty($conf->global->SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT)) {
  292. if (empty($conf->multicurrency->enabled) && empty($conf->dynamicprices->enabled)) {
  293. $dto = GETPOST("dto_".$reg[1].'_'.$reg[2], 'int');
  294. //update supplier price
  295. if (GETPOSTISSET($saveprice)) {
  296. // TODO Use class
  297. $sql = "UPDATE ".MAIN_DB_PREFIX."product_fournisseur_price";
  298. $sql .= " SET unitprice = ".price2num(GETPOST($pu), 'MU', 2);
  299. $sql .= ", price = ".price2num(GETPOST($pu), 'MU', 2)." * quantity";
  300. $sql .= ", remise_percent = ".price2num((empty($dto) ? 0 : $dto), 3, 2)."'";
  301. $sql .= " WHERE fk_soc = ".((int) $object->socid);
  302. $sql .= " AND fk_product=".((int) GETPOST($prod, 'int'));
  303. $resql = $db->query($sql);
  304. }
  305. }
  306. }
  307. }
  308. }
  309. }
  310. }
  311. if (!$error) {
  312. $result = $object->calcAndSetStatusDispatch($user, GETPOST('closeopenorder') ? 1 : 0, GETPOST('comment'));
  313. if ($result < 0) {
  314. setEventMessages($object->error, $object->errors, 'errors');
  315. $error++;
  316. }
  317. }
  318. if (!$notrigger && !$error) {
  319. global $conf, $langs, $user;
  320. // Call trigger
  321. $result = $object->call_trigger('ORDER_SUPPLIER_DISPATCH', $user);
  322. // End call triggers
  323. if ($result < 0) {
  324. setEventMessages($object->error, $object->errors, 'errors');
  325. $error++;
  326. }
  327. }
  328. if ($result >= 0 && !$error) {
  329. $db->commit();
  330. header("Location: dispatch.php?id=".$id);
  331. exit();
  332. } else {
  333. $db->rollback();
  334. }
  335. }
  336. // Remove a dispatched line
  337. if ($action == 'confirm_deleteline' && $confirm == 'yes' && $user->rights->fournisseur->commande->receptionner) {
  338. $db->begin();
  339. $supplierorderdispatch = new CommandeFournisseurDispatch($db);
  340. $result = $supplierorderdispatch->fetch($lineid);
  341. if ($result > 0) {
  342. $qty = $supplierorderdispatch->qty;
  343. $entrepot = $supplierorderdispatch->fk_entrepot;
  344. $product = $supplierorderdispatch->fk_product;
  345. $price = price2num(GETPOST('price', 'alpha'), 'MU');
  346. $comment = $supplierorderdispatch->comment;
  347. $eatby = $supplierorderdispatch->eatby;
  348. $sellby = $supplierorderdispatch->sellby;
  349. $batch = $supplierorderdispatch->batch;
  350. $result = $supplierorderdispatch->delete($user);
  351. }
  352. if ($result < 0) {
  353. $errors = $object->errors;
  354. $error++;
  355. } else {
  356. // If module stock is enabled and the stock increase is done on purchase order dispatching
  357. if ($entrepot > 0 && !empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER) && empty($supplierorderdispatch->fk_reception)) {
  358. $mouv = new MouvementStock($db);
  359. if ($product > 0) {
  360. $mouv->origin = &$object;
  361. $result = $mouv->livraison($user, $product, $entrepot, $qty, $price, $comment, '', $eatby, $sellby, $batch);
  362. if ($result < 0) {
  363. $errors = $mouv->errors;
  364. $error++;
  365. }
  366. }
  367. }
  368. }
  369. if ($error > 0) {
  370. $db->rollback();
  371. setEventMessages($error, $errors, 'errors');
  372. } else {
  373. $db->commit();
  374. }
  375. }
  376. // Update a dispatched line
  377. if ($action == 'updateline' && $user->rights->fournisseur->commande->receptionner) {
  378. $db->begin();
  379. $error = 0;
  380. $supplierorderdispatch = new CommandeFournisseurDispatch($db);
  381. $result = $supplierorderdispatch->fetch($lineid);
  382. if ($result > 0) {
  383. $qty = $supplierorderdispatch->qty;
  384. $entrepot = $supplierorderdispatch->fk_entrepot;
  385. $product = $supplierorderdispatch->fk_product;
  386. $price = price2num(GETPOST('price'), '', 2);
  387. $comment = $supplierorderdispatch->comment;
  388. $eatby = $supplierorderdispatch->eatby;
  389. $sellby = $supplierorderdispatch->sellby;
  390. $batch = $supplierorderdispatch->batch;
  391. $supplierorderdispatch->qty = price2num(GETPOST('qty', 'alpha'), 'MS', 2);
  392. $supplierorderdispatch->fk_entrepot = GETPOST('fk_entrepot');
  393. $result = $supplierorderdispatch->update($user);
  394. }
  395. if ($result < 0) {
  396. $error++;
  397. $errors = $supplierorderdispatch->errors;
  398. } else {
  399. // If module stock is enabled and the stock increase is done on purchase order dispatching
  400. if ($entrepot > 0 && !empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) {
  401. $mouv = new MouvementStock($db);
  402. if ($product > 0) {
  403. $mouv->origin = &$object;
  404. $result = $mouv->livraison($user, $product, $entrepot, $qty, $price, $comment, '', $eatby, $sellby, $batch);
  405. if ($result < 0) {
  406. $errors = $mouv->errors;
  407. $error++;
  408. } else {
  409. $mouv->origin = &$object;
  410. $result = $mouv->reception($user, $product, $supplierorderdispatch->fk_entrepot, $supplierorderdispatch->qty, $price, $comment, $eatby, $sellby, $batch);
  411. if ($result < 0) {
  412. $errors = $mouv->errors;
  413. $error++;
  414. }
  415. }
  416. }
  417. }
  418. }
  419. if ($error > 0) {
  420. $db->rollback();
  421. setEventMessages($error, $errors, 'errors');
  422. } else {
  423. $db->commit();
  424. }
  425. }
  426. /*
  427. * View
  428. */
  429. $now = dol_now();
  430. $form = new Form($db);
  431. $formproduct = new FormProduct($db);
  432. $warehouse_static = new Entrepot($db);
  433. $supplierorderdispatch = new CommandeFournisseurDispatch($db);
  434. $help_url = 'EN:Module_Suppliers_Orders|FR:CommandeFournisseur|ES:Módulo_Pedidos_a_proveedores';
  435. $morejs = array('/fourn/js/lib_dispatch.js.php');
  436. llxHeader('', $langs->trans("OrderDispatch"), $help_url, '', 0, 0, $morejs);
  437. if ($id > 0 || !empty($ref)) {
  438. $soc = new Societe($db);
  439. $soc->fetch($object->socid);
  440. $author = new User($db);
  441. $author->fetch($object->user_author_id);
  442. $head = ordersupplier_prepare_head($object);
  443. $title = $langs->trans("SupplierOrder");
  444. print dol_get_fiche_head($head, 'dispatch', $title, -1, 'order');
  445. $formconfirm = '';
  446. // Confirmation to delete line
  447. if ($action == 'ask_deleteline') {
  448. $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1);
  449. }
  450. // Call Hook formConfirm
  451. $parameters = array('lineid' => $lineid);
  452. // Note that $action and $object may be modified by hook
  453. $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action);
  454. if (empty($reshook)) {
  455. $formconfirm .= $hookmanager->resPrint;
  456. } elseif ($reshook > 0) {
  457. $formconfirm = $hookmanager->resPrint;
  458. }
  459. // Print form confirm
  460. print $formconfirm;
  461. // Supplier order card
  462. $linkback = '<a href="'.DOL_URL_ROOT.'/fourn/commande/list.php'.(!empty($socid) ? '?socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
  463. $morehtmlref = '<div class="refidno">';
  464. // Ref supplier
  465. $morehtmlref .= $form->editfieldkey("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, 0, 'string', '', 0, 1);
  466. $morehtmlref .= $form->editfieldval("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, 0, 'string', '', null, null, '', 1);
  467. // Thirdparty
  468. $morehtmlref .= '<br>'.$langs->trans('ThirdParty').' : '.$object->thirdparty->getNomUrl(1);
  469. // Project
  470. if (!empty($conf->projet->enabled)) {
  471. $langs->load("projects");
  472. $morehtmlref .= '<br>'.$langs->trans('Project').' ';
  473. if ($user->rights->fournisseur->commande->creer || $user->rights->supplier_order->creer) {
  474. if ($action != 'classify') {
  475. //$morehtmlref.='<a class="editfielda" href="' . $_SERVER['PHP_SELF'] . '?action=classify&token='.newToken().'&id=' . $object->id . '">' . img_edit($langs->transnoentitiesnoconv('SetProject')) . '</a> : ';
  476. $morehtmlref .= ' : ';
  477. }
  478. if ($action == 'classify') {
  479. //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1);
  480. $morehtmlref .= '<form method="post" action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'">';
  481. $morehtmlref .= '<input type="hidden" name="action" value="classin">';
  482. $morehtmlref .= '<input type="hidden" name="token" value="'.newToken().'">';
  483. $morehtmlref .= $formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1);
  484. $morehtmlref .= '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
  485. $morehtmlref .= '</form>';
  486. } else {
  487. $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1);
  488. }
  489. } else {
  490. if (!empty($object->fk_project)) {
  491. $proj = new Project($db);
  492. $proj->fetch($object->fk_project);
  493. $morehtmlref .= ' : '.$proj->getNomUrl(1);
  494. if ($proj->title) {
  495. $morehtmlref .= ' - '.$proj->title;
  496. }
  497. } else {
  498. $morehtmlref .= '';
  499. }
  500. }
  501. }
  502. $morehtmlref .= '</div>';
  503. dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
  504. print '<div class="fichecenter">';
  505. print '<div class="underbanner clearboth"></div>';
  506. print '<table class="border tableforfield" width="100%">';
  507. // Date
  508. if ($object->methode_commande_id > 0) {
  509. print '<tr><td class="titlefield">'.$langs->trans("Date").'</td><td>';
  510. if ($object->date_commande) {
  511. print dol_print_date($object->date_commande, "dayhour")."\n";
  512. }
  513. print "</td></tr>";
  514. if ($object->methode_commande) {
  515. print '<tr><td>'.$langs->trans("Method").'</td><td>'.$object->getInputMethod().'</td></tr>';
  516. }
  517. }
  518. // Author
  519. print '<tr><td class="titlefield">'.$langs->trans("AuthorRequest").'</td>';
  520. print '<td>'.$author->getNomUrl(1, '', 0, 0, 0).'</td>';
  521. print '</tr>';
  522. $parameters = array();
  523. $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
  524. print "</table>";
  525. print '</div>';
  526. // if ($mesg) print $mesg;
  527. print '<br>';
  528. $disabled = 1;
  529. if (!empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) {
  530. $disabled = 0;
  531. }
  532. // Line of orders
  533. if ($object->statut <= CommandeFournisseur::STATUS_ACCEPTED || $object->statut >= CommandeFournisseur::STATUS_CANCELED) {
  534. print '<br><span class="opacitymedium">'.$langs->trans("OrderStatusNotReadyToDispatch").'</span>';
  535. }
  536. if ($object->statut == CommandeFournisseur::STATUS_ORDERSENT
  537. || $object->statut == CommandeFournisseur::STATUS_RECEIVED_PARTIALLY
  538. || $object->statut == CommandeFournisseur::STATUS_RECEIVED_COMPLETELY) {
  539. require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
  540. $formproduct = new FormProduct($db);
  541. $formproduct->loadWarehouses();
  542. $entrepot = new Entrepot($db);
  543. $listwarehouses = $entrepot->list_array(1);
  544. if (empty($conf->reception->enabled)) {
  545. print '<form method="POST" action="dispatch.php?id='.$object->id.'">';
  546. } else {
  547. print '<form method="post" action="'.dol_buildpath('/reception/card.php', 1).'?originid='.$object->id.'&origin=supplierorder">';
  548. }
  549. print '<input type="hidden" name="token" value="'.newToken().'">';
  550. if (empty($conf->reception->enabled)) {
  551. print '<input type="hidden" name="action" value="dispatch">';
  552. } else {
  553. print '<input type="hidden" name="action" value="create">';
  554. }
  555. print '<div class="div-table-responsive-no-min">';
  556. print '<table class="noborder centpercent">';
  557. // Set $products_dispatched with qty dispatched for each product id
  558. $products_dispatched = array();
  559. $sql = "SELECT l.rowid, cfd.fk_product, sum(cfd.qty) as qty";
  560. $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as cfd";
  561. $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."commande_fournisseurdet as l on l.rowid = cfd.fk_commandefourndet";
  562. $sql .= " WHERE cfd.fk_commande = ".((int) $object->id);
  563. $sql .= " GROUP BY l.rowid, cfd.fk_product";
  564. $resql = $db->query($sql);
  565. if ($resql) {
  566. $num = $db->num_rows($resql);
  567. $i = 0;
  568. if ($num) {
  569. while ($i < $num) {
  570. $objd = $db->fetch_object($resql);
  571. $products_dispatched[$objd->rowid] = price2num($objd->qty, 5);
  572. $i++;
  573. }
  574. }
  575. $db->free($resql);
  576. }
  577. $sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref AS sref, SUM(l.qty) as qty,";
  578. $sql .= " p.ref, p.label, p.tobatch, p.fk_default_warehouse";
  579. // Enable hooks to alter the SQL query (SELECT)
  580. $parameters = array();
  581. $reshook = $hookmanager->executeHooks(
  582. 'printFieldListSelect',
  583. $parameters,
  584. $object,
  585. $action
  586. );
  587. if ($reshook < 0) {
  588. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  589. }
  590. $sql .= $hookmanager->resPrint;
  591. $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as l";
  592. $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON l.fk_product=p.rowid";
  593. $sql .= " WHERE l.fk_commande = ".((int) $object->id);
  594. if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
  595. $sql .= " AND l.product_type = 0";
  596. }
  597. // Enable hooks to alter the SQL query (WHERE)
  598. $parameters = array();
  599. $reshook = $hookmanager->executeHooks(
  600. 'printFieldListWhere',
  601. $parameters,
  602. $object,
  603. $action
  604. );
  605. if ($reshook < 0) {
  606. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  607. }
  608. $sql .= $hookmanager->resPrint;
  609. $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
  610. $sql .= " ORDER BY p.ref, p.label";
  611. $resql = $db->query($sql);
  612. if ($resql) {
  613. $num = $db->num_rows($resql);
  614. $i = 0;
  615. if ($num) {
  616. print '<tr class="liste_titre">';
  617. print '<td>'.$langs->trans("Description").'</td>';
  618. if (!empty($conf->productbatch->enabled)) {
  619. print '<td class="dispatch_batch_number_title">'.$langs->trans("batch_number").'</td>';
  620. if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
  621. print '<td class="dispatch_dlc_title">'.$langs->trans("SellByDate").'</td>';
  622. }
  623. if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
  624. print '<td class="dispatch_dluo_title">'.$langs->trans("EatByDate").'</td>';
  625. }
  626. } else {
  627. print '<td></td>';
  628. print '<td></td>';
  629. print '<td></td>';
  630. }
  631. print '<td class="right">'.$langs->trans("SupplierRef").'</td>';
  632. print '<td class="right">'.$langs->trans("QtyOrdered").'</td>';
  633. print '<td class="right">'.$langs->trans("QtyDispatchedShort").'</td>';
  634. print ' <td class="right">'.$langs->trans("QtyToDispatchShort");
  635. print '<br><a href="#" id="autoreset">'.$langs->trans("Reset").'</a></td>';
  636. print '<td width="32"></td>';
  637. if (!empty($conf->global->SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT)) {
  638. if (empty($conf->multicurrency->enabled) && empty($conf->dynamicprices->enabled)) {
  639. print '<td class="right">'.$langs->trans("Price").'</td>';
  640. print '<td class="right">'.$langs->trans("ReductionShort").' (%)</td>';
  641. print '<td class="right">'.$langs->trans("UpdatePrice").'</td>';
  642. }
  643. }
  644. print '<td align="right">'.$langs->trans("Warehouse");
  645. // Select warehouse to force it everywhere
  646. if (count($listwarehouses) > 1) {
  647. print '<br>'.$langs->trans("ForceTo").' '.$form->selectarray('fk_default_warehouse', $listwarehouses, $fk_default_warehouse, 1, 0, 0, '', 0, 0, $disabled, '', 'minwidth100 maxwidth300', 1);
  648. } elseif (count($listwarehouses) == 1) {
  649. print '<br>'.$langs->trans("ForceTo").' '.$form->selectarray('fk_default_warehouse', $listwarehouses, $fk_default_warehouse, 0, 0, 0, '', 0, 0, $disabled, '', 'minwidth100 maxwidth300', 1);
  650. }
  651. print '</td>';
  652. // Enable hooks to append additional columns
  653. $parameters = array();
  654. $reshook = $hookmanager->executeHooks(
  655. 'printFieldListTitle',
  656. $parameters,
  657. $object,
  658. $action
  659. );
  660. if ($reshook < 0) {
  661. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  662. }
  663. print $hookmanager->resPrint;
  664. print "</tr>\n";
  665. }
  666. $nbfreeproduct = 0; // Nb of lins of free products/services
  667. $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)
  668. // or nb of line that remain to dispatch if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is on.
  669. while ($i < $num) {
  670. $objp = $db->fetch_object($resql);
  671. // On n'affiche pas les produits libres
  672. if (!$objp->fk_product > 0) {
  673. $nbfreeproduct++;
  674. } else {
  675. $remaintodispatch = price2num($objp->qty - ((float) $products_dispatched[$objp->rowid]), 5); // Calculation of dispatched
  676. if ($remaintodispatch < 0) {
  677. $remaintodispatch = 0;
  678. }
  679. if ($remaintodispatch || empty($conf->global->SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED)) {
  680. $nbproduct++;
  681. // To show detail cref and description value, we must make calculation by cref
  682. // print ($objp->cref?' ('.$objp->cref.')':'');
  683. // if ($objp->description) print '<br>'.nl2br($objp->description);
  684. $suffix = '_0_'.$i;
  685. print "\n";
  686. print '<!-- Line to dispatch '.$suffix.' -->'."\n";
  687. // hidden fields for js function
  688. print '<input id="qty_ordered'.$suffix.'" type="hidden" value="'.$objp->qty.'">';
  689. print '<input id="qty_dispatched'.$suffix.'" type="hidden" value="'.(float) $products_dispatched[$objp->rowid].'">';
  690. print '<tr class="oddeven">';
  691. $linktoprod = '<a href="'.DOL_URL_ROOT.'/product/fournisseurs.php?id='.$objp->fk_product.'">'.img_object($langs->trans("ShowProduct"), 'product').' '.$objp->ref.'</a>';
  692. $linktoprod .= ' - '.$objp->label."\n";
  693. if (!empty($conf->productbatch->enabled)) {
  694. if ($objp->tobatch) {
  695. print '<td>';
  696. print $linktoprod;
  697. print "</td>";
  698. print '<td class="dispatch_batch_number"></td>';
  699. if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
  700. print '<td class="dispatch_dlc"></td>';
  701. }
  702. if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
  703. print '<td class="dispatch_dluo"></td>';
  704. }
  705. } else {
  706. print '<td>';
  707. print $linktoprod;
  708. print "</td>";
  709. print '<td class="dispatch_batch_number">';
  710. print $langs->trans("ProductDoesNotUseBatchSerial");
  711. print '</td>';
  712. if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
  713. print '<td class="dispatch_dlc"></td>';
  714. }
  715. if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
  716. print '<td class="dispatch_dluo"></td>';
  717. }
  718. }
  719. } else {
  720. print '<td colspan="4">';
  721. print $linktoprod;
  722. print "</td>";
  723. }
  724. // Define unit price for PMP calculation
  725. $up_ht_disc = $objp->subprice;
  726. if (!empty($objp->remise_percent) && empty($conf->global->STOCK_EXCLUDE_DISCOUNT_FOR_PMP)) {
  727. $up_ht_disc = price2num($up_ht_disc * (100 - $objp->remise_percent) / 100, 'MU');
  728. }
  729. // Supplier ref
  730. print '<td class="right">'.$objp->sref.'</td>';
  731. // Qty ordered
  732. print '<td class="right">'.$objp->qty.'</td>';
  733. // Already dispatched
  734. print '<td class="right">'.$products_dispatched[$objp->rowid].'</td>';
  735. if (!empty($conf->productbatch->enabled) && $objp->tobatch > 0) {
  736. $type = 'batch';
  737. print '<td class="right">';
  738. print '</td>'; // Qty to dispatch
  739. print '<td>';
  740. //print img_picto($langs->trans('AddDispatchBatchLine'), 'split.png', 'onClick="addDispatchLine(' . $i . ',\'' . $type . '\')"');
  741. print '</td>'; // Dispatch column
  742. print '<td></td>'; // Warehouse column
  743. // Enable hooks to append additional columns
  744. $parameters = array(
  745. 'is_information_row' => true, // allows hook to distinguish between the
  746. // rows with information and the rows with
  747. // dispatch form input
  748. 'objp' => $objp
  749. );
  750. $reshook = $hookmanager->executeHooks(
  751. 'printFieldListValue',
  752. $parameters,
  753. $object,
  754. $action
  755. );
  756. if ($reshook < 0) {
  757. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  758. }
  759. print $hookmanager->resPrint;
  760. print '</tr>';
  761. print '<tr class="oddeven" name="'.$type.$suffix.'">';
  762. print '<td>';
  763. print '<input name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
  764. print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
  765. print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
  766. if (!empty($conf->global->SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT)) { // Not tested !
  767. print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
  768. } else {
  769. print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
  770. }
  771. print '</td>';
  772. print '<td>';
  773. print '<input type="text" class="inputlotnumber quatrevingtquinzepercent" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.GETPOST('lot_number'.$suffix).'">';
  774. print '</td>';
  775. if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
  776. print '<td class="nowraponall">';
  777. $dlcdatesuffix = dol_mktime(0, 0, 0, GETPOST('dlc'.$suffix.'month'), GETPOST('dlc'.$suffix.'day'), GETPOST('dlc'.$suffix.'year'));
  778. print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, '', '', 1, '');
  779. print '</td>';
  780. }
  781. if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
  782. print '<td class="nowraponall">';
  783. $dluodatesuffix = dol_mktime(0, 0, 0, GETPOST('dluo'.$suffix.'month'), GETPOST('dluo'.$suffix.'day'), GETPOST('dluo'.$suffix.'year'));
  784. print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, '', '', 1, '');
  785. print '</td>';
  786. }
  787. print '<td colspan="3">&nbsp;</td>'; // Supplier ref + Qty ordered + qty already dispatched
  788. } else {
  789. $type = 'dispatch';
  790. $colspan = 7;
  791. $colspan = (!empty($conf->global->PRODUCT_DISABLE_SELLBY)) ? --$colspan : $colspan;
  792. $colspan = (!empty($conf->global->PRODUCT_DISABLE_EATBY)) ? --$colspan : $colspan;
  793. print '<td class="right">';
  794. print '</td>'; // Qty to dispatch
  795. print '<td>';
  796. //print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'onClick="addDispatchLine(' . $i . ',\'' . $type . '\')"');
  797. print '</td>'; // Dispatch column
  798. print '<td></td>'; // Warehouse column
  799. // Enable hooks to append additional columns
  800. $parameters = array(
  801. 'is_information_row' => true, // allows hook to distinguish between the
  802. // rows with information and the rows with
  803. // dispatch form input
  804. 'objp' => $objp
  805. );
  806. $reshook = $hookmanager->executeHooks(
  807. 'printFieldListValue',
  808. $parameters,
  809. $object,
  810. $action
  811. );
  812. if ($reshook < 0) {
  813. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  814. }
  815. print $hookmanager->resPrint;
  816. print '</tr>';
  817. print '<tr class="oddeven" name="'.$type.$suffix.'">';
  818. print '<td colspan="'.$colspan.'">';
  819. print '<input name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
  820. print '<input name="product'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
  821. print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
  822. if (!empty($conf->global->SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT)) { // Not tested !
  823. print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
  824. } else {
  825. print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
  826. }
  827. print '</td>';
  828. }
  829. // Qty to dispatch
  830. print '<td class="right">';
  831. print '<input id="qty'.$suffix.'" name="qty'.$suffix.'" type="text" class="width50 right" value="'.(GETPOSTISSET('qty'.$suffix) ? GETPOST('qty'.$suffix, 'int') : (empty($conf->global->SUPPLIER_ORDER_DISPATCH_FORCE_QTY_INPUT_TO_ZERO) ? $remaintodispatch : 0)).'">';
  832. print '</td>';
  833. print '<td>';
  834. if (!empty($conf->productbatch->enabled) && $objp->tobatch > 0) {
  835. $type = 'batch';
  836. print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
  837. } else {
  838. $type = 'dispatch';
  839. print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
  840. }
  841. print '</td>';
  842. if (!empty($conf->global->SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT)) {
  843. if (empty($conf->multicurrency->enabled) && empty($conf->dynamicprices->enabled)) {
  844. // Price
  845. print '<td class="right">';
  846. print '<input id="pu'.$suffix.'" name="pu'.$suffix.'" type="text" size="8" value="'.price((GETPOST('pu'.$suffix) != '' ? GETPOST('pu'.$suffix) : $up_ht_disc)).'">';
  847. print '</td>';
  848. // Discount
  849. print '<td class="right">';
  850. print '<input id="dto'.$suffix.'" name="dto'.$suffix.'" type="text" size="8" value="'.(GETPOST('dto'.$suffix) != '' ? GETPOST('dto'.$suffix) : '').'">';
  851. print '</td>';
  852. // Save price
  853. print '<td class="center">';
  854. print '<input class="flat checkformerge" type="checkbox" name="saveprice'.$suffix.'" value="'.(GETPOST('saveprice'.$suffix) != '' ? GETPOST('saveprice'.$suffix) : '').'">';
  855. print '</td>';
  856. }
  857. }
  858. // Warehouse
  859. print '<td class="right">';
  860. if (count($listwarehouses) > 1) {
  861. 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);
  862. } elseif (count($listwarehouses) == 1) {
  863. 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);
  864. } else {
  865. $langs->load("errors");
  866. print $langs->trans("ErrorNoWarehouseDefined");
  867. }
  868. print "</td>\n";
  869. // Enable hooks to append additional columns
  870. $parameters = array(
  871. 'is_information_row' => false // this is a dispatch form row
  872. );
  873. $reshook = $hookmanager->executeHooks(
  874. 'printFieldListValue',
  875. $parameters,
  876. $object,
  877. $action
  878. );
  879. if ($reshook < 0) {
  880. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  881. }
  882. print $hookmanager->resPrint;
  883. print "</tr>\n";
  884. }
  885. }
  886. $i++;
  887. }
  888. $db->free($resql);
  889. } else {
  890. dol_print_error($db);
  891. }
  892. print "</table>\n";
  893. print '</div>';
  894. if ($nbproduct) {
  895. $checkboxlabel = $langs->trans("CloseReceivedSupplierOrdersAutomatically", $langs->transnoentitiesnoconv('StatusOrderReceivedAll'));
  896. print '<div class="center">';
  897. $parameters = array();
  898. $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
  899. // modified by hook
  900. if (empty($reshook)) {
  901. if (empty($conf->reception->enabled)) {
  902. print $langs->trans("Comment").' : ';
  903. print '<input type="text" class="minwidth400" maxlength="128" name="comment" value="';
  904. print GETPOSTISSET("comment") ? GETPOST("comment") : $langs->trans("DispatchSupplierOrder", $object->ref);
  905. // print ' / '.$object->ref_supplier; // Not yet available
  906. print '" class="flat"><br>';
  907. print '<input type="checkbox" checked="checked" name="closeopenorder"> '.$checkboxlabel;
  908. }
  909. $dispatchBt = empty($conf->reception->enabled) ? $langs->trans("Receive") : $langs->trans("CreateReception");
  910. print '<br><input type="submit" class="button" name="dispatch" value="'.dol_escape_htmltag($dispatchBt).'"';
  911. if (count($listwarehouses) <= 0) {
  912. print ' disabled';
  913. }
  914. print '>';
  915. }
  916. print '</div>';
  917. }
  918. // Message if nothing to dispatch
  919. if (!$nbproduct) {
  920. print "<br>\n";
  921. if (empty($conf->global->SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED)) {
  922. print '<div class="opacitymedium">'.$langs->trans("NoPredefinedProductToDispatch").'</div>'; // No predefined line at all
  923. } else {
  924. print '<div class="opacitymedium">'.$langs->trans("NoMorePredefinedProductToDispatch").'</div>'; // No predefined line that remain to be dispatched.
  925. }
  926. }
  927. print '</form>';
  928. }
  929. print dol_get_fiche_end();
  930. // traitement entrepot par défaut
  931. print '<script type="text/javascript">
  932. $(document).ready(function () {
  933. $("select[name=fk_default_warehouse]").change(function() {
  934. var fk_default_warehouse = $("option:selected", this).val();
  935. $("select[name^=entrepot_]").val(fk_default_warehouse).change();
  936. });
  937. jQuery("#autoreset").click(function() {';
  938. $i = 0;
  939. while ($i < $nbproduct) {
  940. print ' jQuery("#qty_0_'.$i.'").val("");';
  941. $i++;
  942. }
  943. print '
  944. });
  945. });
  946. </script>';
  947. // List of lines already dispatched
  948. $sql = "SELECT p.rowid as pid, p.ref, p.label,";
  949. $sql .= " e.rowid as warehouse_id, e.ref as entrepot,";
  950. $sql .= " cfd.rowid as dispatchlineid, cfd.fk_product, cfd.qty, cfd.eatby, cfd.sellby, cfd.batch, cfd.comment, cfd.status, cfd.datec";
  951. $sql .= " ,cd.rowid, cd.subprice";
  952. if ($conf->reception->enabled) {
  953. $sql .= " ,cfd.fk_reception, r.date_delivery";
  954. }
  955. $sql .= " FROM ".MAIN_DB_PREFIX."product as p,";
  956. $sql .= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as cfd";
  957. $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."commande_fournisseurdet as cd ON cd.rowid = cfd.fk_commandefourndet";
  958. $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e ON cfd.fk_entrepot = e.rowid";
  959. if ($conf->reception->enabled) {
  960. $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."reception as r ON cfd.fk_reception = r.rowid";
  961. }
  962. $sql .= " WHERE cfd.fk_commande = ".((int) $object->id);
  963. $sql .= " AND cfd.fk_product = p.rowid";
  964. $sql .= " ORDER BY cfd.rowid ASC";
  965. $resql = $db->query($sql);
  966. if ($resql) {
  967. $num = $db->num_rows($resql);
  968. $i = 0;
  969. if ($num > 0) {
  970. print "<br>\n";
  971. print load_fiche_titre($langs->trans("ReceivingForSameOrder"));
  972. print '<div class="div-table-responsive">';
  973. print '<table id="dispatch_received_products" class="noborder centpercent">';
  974. print '<tr class="liste_titre">';
  975. if ($conf->reception->enabled) {
  976. print '<td>'.$langs->trans("Reception").'</td>';
  977. }
  978. print '<td>'.$langs->trans("Product").'</td>';
  979. print '<td>'.$langs->trans("DateCreation").'</td>';
  980. print '<td>'.$langs->trans("DateDeliveryPlanned").'</td>';
  981. if (!empty($conf->productbatch->enabled)) {
  982. print '<td class="dispatch_batch_number_title">'.$langs->trans("batch_number").'</td>';
  983. if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
  984. print '<td class="dispatch_dlc_title">'.$langs->trans("SellByDate").'</td>';
  985. }
  986. if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
  987. print '<td class="dispatch_dluo_title">'.$langs->trans("EatByDate").'</td>';
  988. }
  989. }
  990. print '<td class="right">'.$langs->trans("QtyDispatched").'</td>';
  991. print '<td>'.$langs->trans("Warehouse").'</td>';
  992. print '<td>'.$langs->trans("Comment").'</td>';
  993. // Status
  994. if (!empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS) && empty($reception->rowid)) {
  995. print '<td class="center" colspan="2">'.$langs->trans("Status").'</td>';
  996. } elseif (!empty($conf->reception->enabled)) {
  997. print '<td class="center"></td>';
  998. }
  999. print '<td class="center" colspan="2"></td>';
  1000. print "</tr>\n";
  1001. while ($i < $num) {
  1002. $objp = $db->fetch_object($resql);
  1003. if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
  1004. print '<form name="editdispatchedlines" id="editdispatchedlines" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'#line_'.GETPOST('lineid', 'int').'" method="POST">
  1005. <input type="hidden" name="token" value="'.newToken().'">
  1006. <input type="hidden" name="action" value="updateline">
  1007. <input type="hidden" name="mode" value="">
  1008. <input type="hidden" name="lineid" value="'.$objp->dispatchlineid.'">';
  1009. }
  1010. print '<tr class="oddeven" id="line_'.$objp->dispatchlineid.'" >';
  1011. if (!empty($conf->reception->enabled)) {
  1012. print '<td>';
  1013. if (!empty($objp->fk_reception)) {
  1014. $reception = new Reception($db);
  1015. $reception->fetch($objp->fk_reception);
  1016. print $reception->getNomUrl(1);
  1017. }
  1018. print "</td>";
  1019. }
  1020. print '<td>';
  1021. print '<a href="'.DOL_URL_ROOT.'/product/fournisseurs.php?id='.$objp->fk_product.'">'.img_object($langs->trans("ShowProduct"), 'product').' '.$objp->ref.'</a>';
  1022. print ' - '.$objp->label;
  1023. print "</td>\n";
  1024. print '<td>'.dol_print_date($db->jdate($objp->datec), 'day').'</td>';
  1025. print '<td>'.dol_print_date($db->jdate($objp->date_delivery), 'day').'</td>';
  1026. if (!empty($conf->productbatch->enabled)) {
  1027. if ($objp->batch) {
  1028. include_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php';
  1029. $lot = new Productlot($db);
  1030. $lot->fetch(0, $objp->pid, $objp->batch);
  1031. print '<td class="dispatch_batch_number">'.$lot->getNomUrl(1).'</td>';
  1032. if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
  1033. print '<td class="dispatch_dlc">'.dol_print_date($lot->sellby, 'day').'</td>';
  1034. }
  1035. if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
  1036. print '<td class="dispatch_dluo">'.dol_print_date($lot->eatby, 'day').'</td>';
  1037. }
  1038. } else {
  1039. print '<td class="dispatch_batch_number"></td>';
  1040. if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
  1041. print '<td class="dispatch_dlc"></td>';
  1042. }
  1043. if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
  1044. print '<td class="dispatch_dluo"></td>';
  1045. }
  1046. }
  1047. }
  1048. // Qty
  1049. print '<td class="right">';
  1050. if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
  1051. print '<input style="width: 50px;" type="text" min="1" name="qty" value="'.$objp->qty.'" />';
  1052. } else {
  1053. print $objp->qty;
  1054. }
  1055. print '<input type="hidden" name="price" value="'.$objp->subprice.'" />';
  1056. print '</td>';
  1057. // Warehouse
  1058. print '<td>';
  1059. if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
  1060. if (count($listwarehouses) > 1) {
  1061. print $formproduct->selectWarehouses(GETPOST("fk_entrepot") ?GETPOST("fk_entrepot") : ($objp->warehouse_id ? $objp->warehouse_id : ''), "fk_entrepot", '', 1, 0, $objp->fk_product, '', 1, 1, null, 'csswarehouse');
  1062. } elseif (count($listwarehouses) == 1) {
  1063. print $formproduct->selectWarehouses(GETPOST("fk_entrepot") ?GETPOST("fk_entrepot") : ($objp->warehouse_id ? $objp->warehouse_id : ''), "fk_entrepot", '', 0, 0, $objp->fk_product, '', 1, 1, null, 'csswarehouse');
  1064. } else {
  1065. $langs->load("errors");
  1066. print $langs->trans("ErrorNoWarehouseDefined");
  1067. }
  1068. } else {
  1069. $warehouse_static->id = $objp->warehouse_id;
  1070. $warehouse_static->label = $objp->entrepot;
  1071. print $warehouse_static->getNomUrl(1);
  1072. }
  1073. print '</td>';
  1074. // Comment
  1075. print '<td class="tdoverflowmax300" style="white-space: pre;">'.$objp->comment.'</td>';
  1076. // Status
  1077. if (!empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS) && empty($reception->rowid)) {
  1078. print '<td class="right">';
  1079. $supplierorderdispatch->status = (empty($objp->status) ? 0 : $objp->status);
  1080. // print $supplierorderdispatch->status;
  1081. print $supplierorderdispatch->getLibStatut(5);
  1082. print '</td>';
  1083. // Add button to check/uncheck disaptching
  1084. print '<td class="center">';
  1085. if ((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))) {
  1086. if (empty($objp->status)) {
  1087. print '<a class="button buttonRefused" href="#">'.$langs->trans("Approve").'</a>';
  1088. print '<a class="button buttonRefused" href="#">'.$langs->trans("Deny").'</a>';
  1089. } else {
  1090. print '<a class="button buttonRefused" href="#">'.$langs->trans("Disapprove").'</a>';
  1091. print '<a class="button buttonRefused" href="#">'.$langs->trans("Deny").'</a>';
  1092. }
  1093. } else {
  1094. $disabled = '';
  1095. if ($object->statut == 5) {
  1096. $disabled = 1;
  1097. }
  1098. if (empty($objp->status)) {
  1099. print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=checkdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Approve").'</a>';
  1100. print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=denydispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Deny").'</a>';
  1101. }
  1102. if ($objp->status == 1) {
  1103. print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=uncheckdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Reinit").'</a>';
  1104. print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=denydispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Deny").'</a>';
  1105. }
  1106. if ($objp->status == 2) {
  1107. print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=uncheckdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Reinit").'</a>';
  1108. print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=checkdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Approve").'</a>';
  1109. }
  1110. }
  1111. print '</td>';
  1112. } elseif (!empty($conf->reception->enabled)) {
  1113. print '<td class="right">';
  1114. if (!empty($reception->id)) {
  1115. print $reception->getLibStatut(5);
  1116. }
  1117. print '</td>';
  1118. }
  1119. if ($action != 'editline' || $lineid != $objp->dispatchlineid) {
  1120. if (empty($reception->id) || ($reception->statut == Reception::STATUS_DRAFT)) { // only allow edit on draft reception
  1121. print '<td class="linecoledit center">';
  1122. print '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=editline&token='.newToken().'&lineid='.$objp->dispatchlineid.'#line_'.$objp->dispatchlineid.'">';
  1123. print img_edit();
  1124. print '</a>';
  1125. print '</td>';
  1126. print '<td class="linecoldelete center">';
  1127. print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=ask_deleteline&token='.newToken().'&lineid='.$objp->dispatchlineid.'#dispatch_received_products">';
  1128. print img_delete();
  1129. print '</a>';
  1130. print '</td>';
  1131. } else {
  1132. print '<td></td><td></td>';
  1133. }
  1134. } else {
  1135. print '<td class="center valignmiddle">';
  1136. print '<input type="submit" class="button button-save" id="savelinebutton" name="save" value="'.$langs->trans("Save").'" />';
  1137. print '</td>';
  1138. print '<td class="center valignmiddle">';
  1139. print '<input type="submit" class="button button-cancel" id="cancellinebutton" name="cancel" value="'.$langs->trans("Cancel").'" />';
  1140. print '</td>';
  1141. }
  1142. print "</tr>\n";
  1143. if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
  1144. print '</form>';
  1145. }
  1146. $i++;
  1147. }
  1148. $db->free($resql);
  1149. print "</table>\n";
  1150. print '</div>';
  1151. }
  1152. } else {
  1153. dol_print_error($db);
  1154. }
  1155. }
  1156. // End of page
  1157. llxFooter();
  1158. $db->close();