shipment.php 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928
  1. <?php
  2. /* Copyright (C) 2003-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  3. * Copyright (C) 2005-2012 Laurent Destailleur <eldy@users.sourceforge.net>
  4. * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
  5. * Copyright (C) 2012-2015 Juanjo Menent <jmenent@2byte.es>
  6. * Copyright (C) 2018-2021 Frédéric France <frederic.france@netlogic.fr>
  7. * Copyright (C) 2018-2022 Philippe Grand <philippe.grand@atoo-net.com>
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  21. */
  22. /**
  23. * \file htdocs/expedition/shipment.php
  24. * \ingroup expedition
  25. * \brief Tab shipments/delivery receipts on the order
  26. */
  27. // Load Dolibarr environment
  28. require '../main.inc.php';
  29. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
  30. require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
  31. require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
  32. require_once DOL_DOCUMENT_ROOT.'/core/lib/order.lib.php';
  33. require_once DOL_DOCUMENT_ROOT.'/core/lib/sendings.lib.php';
  34. require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
  35. if (isModEnabled('project')) {
  36. require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
  37. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
  38. }
  39. if (isModEnabled('stock')) {
  40. require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
  41. }
  42. if (isModEnabled("propal")) {
  43. require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
  44. }
  45. if (isModEnabled("product") || isModEnabled("service")) {
  46. require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
  47. }
  48. // Load translation files required by the page
  49. $langs->loadLangs(array('orders', 'sendings', 'companies', 'bills', 'propal', 'deliveries', 'stocks', 'productbatch', 'incoterm', 'other'));
  50. $id = GETPOST('id', 'int'); // id of order
  51. $ref = GETPOST('ref', 'alpha');
  52. $action = GETPOST('action', 'aZ09');
  53. $hookmanager->initHooks(array('ordershipmentcard'));
  54. // Security check
  55. $socid = 0;
  56. if (!empty($user->socid)) {
  57. $socid = $user->socid;
  58. }
  59. $result = restrictedArea($user, 'commande', $id);
  60. $object = new Commande($db);
  61. $shipment = new Expedition($db);
  62. $extrafields = new ExtraFields($db);
  63. // fetch optionals attributes and labels
  64. $extrafields->fetch_name_optionals_label($object->table_element);
  65. // Load object
  66. include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once
  67. // Security check
  68. if ($user->socid) {
  69. $socid = $user->socid;
  70. }
  71. $result = restrictedArea($user, 'expedition', 0, ''); // We use 0 for id, because there is no particular shipment on this tab, only id of order is known
  72. /*
  73. * Actions
  74. */
  75. $parameters = array('socid' => $socid);
  76. $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
  77. if ($reshook < 0) {
  78. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  79. }
  80. if (empty($reshook)) {
  81. // Categorisation dans projet
  82. if ($action == 'classin') {
  83. $object->fetch($id);
  84. $object->setProject(GETPOST('projectid', 'int'));
  85. }
  86. if ($action == 'confirm_cloture' && GETPOST('confirm', 'alpha') == 'yes') {
  87. $object->fetch($id);
  88. $result = $object->cloture($user);
  89. } elseif ($action == 'setref_client' && $user->rights->commande->creer) {
  90. // Positionne ref commande client
  91. $result = $object->set_ref_client($user, GETPOST('ref_client'));
  92. if ($result < 0) {
  93. setEventMessages($object->error, $object->errors, 'errors');
  94. }
  95. }
  96. if ($action == 'setdatedelivery' && $user->rights->commande->creer) {
  97. $datedelivery = dol_mktime(GETPOST('liv_hour', 'int'), GETPOST('liv_min', 'int'), 0, GETPOST('liv_month', 'int'), GETPOST('liv_day', 'int'), GETPOST('liv_year', 'int'));
  98. $object->fetch($id);
  99. $result = $object->setDeliveryDate($user, $datedelivery);
  100. if ($result < 0) {
  101. setEventMessages($object->error, $object->errors, 'errors');
  102. }
  103. }
  104. /*
  105. if ($action == 'setdeliveryaddress' && $user->rights->commande->creer)
  106. {
  107. $object = new Commande($db);
  108. $object->fetch($id);
  109. $object->setDeliveryAddress(GETPOST('delivery_address_id','int'));
  110. if ($result < 0)
  111. setEventMessages($object->error, $object->errors, 'errors');
  112. }
  113. */
  114. if ($action == 'setmode' && $user->rights->commande->creer) {
  115. $object->fetch($id);
  116. $result = $object->setPaymentMethods(GETPOST('mode_reglement_id', 'int'));
  117. if ($result < 0) {
  118. setEventMessages($object->error, $object->errors, 'errors');
  119. }
  120. }
  121. if ($action == 'setavailability' && $user->rights->commande->creer) {
  122. $object->fetch($id);
  123. $result = $object->availability(GETPOST('availability_id'));
  124. if ($result < 0) {
  125. setEventMessages($object->error, $object->errors, 'errors');
  126. }
  127. }
  128. if ($action == 'setdemandreason' && $user->rights->commande->creer) {
  129. $object->fetch($id);
  130. $result = $object->demand_reason(GETPOST('demand_reason_id'));
  131. if ($result < 0) {
  132. setEventMessages($object->error, $object->errors, 'errors');
  133. }
  134. }
  135. if ($action == 'setconditions' && $user->rights->commande->creer) {
  136. $object->fetch($id);
  137. $result = $object->setPaymentTerms(GETPOST('cond_reglement_id', 'int'));
  138. if ($result < 0) {
  139. setEventMessages($object->error, $object->errors, 'errors');
  140. }
  141. } elseif ($action == 'set_incoterms' && isModEnabled('incoterm')) {
  142. // Set incoterm
  143. $result = $object->setIncoterms(GETPOST('incoterm_id', 'int'), GETPOST('location_incoterms', 'alpha'));
  144. if ($result < 0) {
  145. setEventMessages($object->error, $object->errors, 'errors');
  146. }
  147. }
  148. // shipping method
  149. if ($action == 'setshippingmethod' && $user->rights->commande->creer) {
  150. $object->fetch($id);
  151. $result = $object->setShippingMethod(GETPOST('shipping_method_id', 'int'));
  152. if ($result < 0) {
  153. setEventMessages($object->error, $object->errors, 'errors');
  154. }
  155. }
  156. // warehouse
  157. if ($action == 'setwarehouse' && $user->rights->commande->creer) {
  158. $object->fetch($id);
  159. $result = $object->setWarehouse(GETPOST('warehouse_id', 'int'));
  160. if ($result < 0) {
  161. setEventMessages($object->error, $object->errors, 'errors');
  162. }
  163. }
  164. if ($action == 'update_extras') {
  165. $object->oldcopy = dol_clone($object);
  166. // Fill array 'array_options' with data from update form
  167. $ret = $extrafields->setOptionalsFromPost(null, $object, GETPOST('attribute', 'restricthtml'));
  168. if ($ret < 0) {
  169. $error++;
  170. }
  171. if (!$error) {
  172. // Actions on extra fields
  173. $result = $object->insertExtraFields('SHIPMENT_MODIFY');
  174. if ($result < 0) {
  175. setEventMessages($object->error, $object->errors, 'errors');
  176. $error++;
  177. }
  178. }
  179. if ($error) {
  180. $action = 'edit_extras';
  181. }
  182. }
  183. if ($action == 'set_thirdparty' && $user->rights->commande->creer) {
  184. $object->fetch($id);
  185. $object->setValueFrom('fk_soc', $socid, '', '', 'date', '', $user, 'ORDER_MODIFY');
  186. header('Location: '.$_SERVER["PHP_SELF"].'?id='.$id);
  187. exit();
  188. }
  189. include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
  190. }
  191. /*
  192. * View
  193. */
  194. $form = new Form($db);
  195. $formfile = new FormFile($db);
  196. $formproduct = new FormProduct($db);
  197. if (isModEnabled('project')) {
  198. $formproject = new FormProjets($db);
  199. }
  200. $title = $object->ref." - ".$langs->trans('Shipments');
  201. $help_url = 'EN:Customers_Orders|FR:Commandes_Clients|ES:Pedidos de clientes|DE:Modul_Kundenaufträge';
  202. llxHeader('', $title, $help_url);
  203. if ($id > 0 || !empty($ref)) {
  204. $object = new Commande($db);
  205. if ($object->fetch($id, $ref) > 0) {
  206. $object->loadExpeditions(1);
  207. $product_static = new Product($db);
  208. $soc = new Societe($db);
  209. $soc->fetch($object->socid);
  210. $author = new User($db);
  211. $author->fetch($object->user_author_id);
  212. $res = $object->fetch_optionals();
  213. $head = commande_prepare_head($object);
  214. print dol_get_fiche_head($head, 'shipping', $langs->trans("CustomerOrder"), -1, 'order');
  215. $formconfirm = '';
  216. // Confirm validation
  217. if ($action == 'cloture') {
  218. $formconfirm = $form->formconfirm($_SERVER['PHP_SELF']."?id=".urlencode($id), $langs->trans("CloseShipment"), $langs->trans("ConfirmCloseShipment"), "confirm_cloture");
  219. }
  220. // Call Hook formConfirm
  221. $parameters = array('formConfirm' => $formconfirm);
  222. $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
  223. if (empty($reshook)) {
  224. $formconfirm .= $hookmanager->resPrint;
  225. } elseif ($reshook > 0) {
  226. $formconfirm = $hookmanager->resPrint;
  227. }
  228. // Print form confirm
  229. print $formconfirm;
  230. // Order card
  231. $linkback = '<a href="'.DOL_URL_ROOT.'/commande/list.php?restore_lastsearch_values=1'.(!empty($socid) ? '?socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
  232. $morehtmlref = '<div class="refidno">';
  233. // Ref customer
  234. $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_customer', $object->ref_client, $object, $user->rights->commande->creer, 'string', '', 0, 1);
  235. $morehtmlref .= $form->editfieldval("RefCustomer", 'ref_customer', $object->ref_client, $object, $user->rights->commande->creer, 'string', '', null, null, '', 1);
  236. // Thirdparty
  237. $morehtmlref .= '<br>'.$soc->getNomUrl(1);
  238. // Project
  239. if (isModEnabled('project')) {
  240. $langs->load("projects");
  241. $morehtmlref .= '<br>';
  242. if (0) { // Do not change on shipment
  243. $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
  244. if ($action != 'classify') {
  245. $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
  246. }
  247. $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $objectsrc->socid, $objectsrc->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
  248. } else {
  249. if (!empty($objectsrc) && !empty($objectsrc->fk_project)) {
  250. $proj = new Project($db);
  251. $proj->fetch($objectsrc->fk_project);
  252. $morehtmlref .= $proj->getNomUrl(1);
  253. if ($proj->title) {
  254. $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
  255. }
  256. }
  257. }
  258. }
  259. $morehtmlref .= '</div>';
  260. dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
  261. print '<div class="fichecenter">';
  262. print '<div class="fichehalfleft">';
  263. print '<div class="underbanner clearboth"></div>';
  264. print '<table class="border centpercent tableforfield">';
  265. // Discounts for third party
  266. if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) {
  267. $filterabsolutediscount = "fk_facture_source IS NULL"; // If we want deposit to be substracted to payments only and not to total of final invoice
  268. $filtercreditnote = "fk_facture_source IS NOT NULL"; // If we want deposit to be substracted to payments only and not to total of final invoice
  269. } else {
  270. $filterabsolutediscount = "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')";
  271. $filtercreditnote = "fk_facture_source IS NOT NULL AND (description NOT LIKE '(DEPOSIT)%' OR description LIKE '(EXCESS RECEIVED)%')";
  272. }
  273. print '<tr><td class="titlefield">'.$langs->trans('Discounts').'</td><td colspan="2">';
  274. $absolute_discount = $soc->getAvailableDiscounts('', $filterabsolutediscount);
  275. $absolute_creditnote = $soc->getAvailableDiscounts('', $filtercreditnote);
  276. $absolute_discount = price2num($absolute_discount, 'MT');
  277. $absolute_creditnote = price2num($absolute_creditnote, 'MT');
  278. $thirdparty = $soc;
  279. $discount_type = 0;
  280. $backtopage = urlencode($_SERVER["PHP_SELF"].'?id='.$object->id);
  281. $cannotApplyDiscount = 1;
  282. include DOL_DOCUMENT_ROOT.'/core/tpl/object_discounts.tpl.php';
  283. print '</td></tr>';
  284. // Date
  285. print '<tr><td>'.$langs->trans('Date').'</td>';
  286. print '<td colspan="2">';
  287. print dol_print_date($object->date, 'day');
  288. if ($object->hasDelay() && empty($object->delivery_date)) { // If there is a delivery date planned, warning should be on this date
  289. print ' '.img_picto($langs->trans("Late").' : '.$object->showDelay(), "warning");
  290. }
  291. print '</td>';
  292. print '</tr>';
  293. // Delivery date planned
  294. print '<tr><td height="10">';
  295. print '<table class="nobordernopadding" width="100%"><tr><td>';
  296. print $langs->trans('DateDeliveryPlanned');
  297. print '</td>';
  298. if ($action != 'editdate_livraison') {
  299. print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editdate_livraison&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->trans('SetDeliveryDate'), 1).'</a></td>';
  300. }
  301. print '</tr></table>';
  302. print '</td><td colspan="2">';
  303. if ($action == 'editdate_livraison') {
  304. print '<form name="setdate_livraison" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
  305. print '<input type="hidden" name="token" value="'.newToken().'">';
  306. print '<input type="hidden" name="action" value="setdatedelivery">';
  307. print $form->selectDate($object->delivery_date ? $object->delivery_date : -1, 'liv_', 1, 1, '', "setdate_livraison", 1, 0);
  308. print '<input type="submit" class="button button-edit" value="'.$langs->trans('Modify').'">';
  309. print '</form>';
  310. } else {
  311. print dol_print_date($object->delivery_date, 'dayhour');
  312. if ($object->hasDelay() && !empty($object->delivery_date)) {
  313. print ' '.img_picto($langs->trans("Late").' : '.$object->showDelay(), "warning");
  314. }
  315. }
  316. print '</td>';
  317. // Note on several rows
  318. //print '<td rowspan="'.$nbrow.'" valign="top">'.$langs->trans('NotePublic').' :<br>';
  319. //print nl2br($object->note_public);
  320. //print '</td>';
  321. print '</tr>';
  322. // Delivery delay
  323. print '<tr><td height="10">';
  324. print '<table class="nobordernopadding" width="100%"><tr><td>';
  325. print $langs->trans('AvailabilityPeriod');
  326. print '</td>';
  327. if ($action != 'editavailability') {
  328. print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editavailability&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->trans('SetAvailability'), 1).'</a></td>';
  329. }
  330. print '</tr></table>';
  331. print '</td><td colspan="2">';
  332. if ($action == 'editavailability') {
  333. $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id, $object->availability_id, 'availability_id', 1);
  334. } else {
  335. $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id, $object->availability_id, 'none', 1);
  336. }
  337. print '</td></tr>';
  338. // Shipping Method
  339. print '<tr><td>';
  340. print '<table width="100%" class="nobordernopadding"><tr><td>';
  341. print $langs->trans('SendingMethod');
  342. print '</td>';
  343. if ($action != 'editshippingmethod' && $user->rights->expedition->creer) {
  344. print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editshippingmethod&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->trans('SetShippingMode'), 1).'</a></td>';
  345. }
  346. print '</tr></table>';
  347. print '</td><td colspan="2">';
  348. if ($action == 'editshippingmethod') {
  349. $form->formSelectShippingMethod($_SERVER['PHP_SELF'].'?id='.$object->id, $object->shipping_method_id, 'shipping_method_id', 1);
  350. } else {
  351. $form->formSelectShippingMethod($_SERVER['PHP_SELF'].'?id='.$object->id, $object->shipping_method_id, 'none');
  352. }
  353. print '</td>';
  354. print '</tr>';
  355. // Warehouse
  356. if (isModEnabled('stock') && !empty($conf->global->WAREHOUSE_ASK_WAREHOUSE_DURING_ORDER)) {
  357. require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
  358. $formproduct = new FormProduct($db);
  359. print '<tr><td>';
  360. print '<table width="100%" class="nobordernopadding"><tr><td>';
  361. print $langs->trans('Warehouse');
  362. print '</td>';
  363. if ($action != 'editwarehouse' && $user->rights->commande->creer) {
  364. print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editwarehouse&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->trans('SetWarehouse'), 1).'</a></td>';
  365. }
  366. print '</tr></table>';
  367. print '</td><td colspan="2">';
  368. if ($action == 'editwarehouse') {
  369. $formproduct->formSelectWarehouses($_SERVER['PHP_SELF'].'?id='.$object->id, $object->warehouse_id, 'warehouse_id', 1);
  370. } else {
  371. $formproduct->formSelectWarehouses($_SERVER['PHP_SELF'].'?id='.$object->id, $object->warehouse_id, 'none');
  372. }
  373. print '</td>';
  374. print '</tr>';
  375. }
  376. // Source reason (why we have an order)
  377. print '<tr><td height="10">';
  378. print '<table class="nobordernopadding" width="100%"><tr><td>';
  379. print $langs->trans('Source');
  380. print '</td>';
  381. if ($action != 'editdemandreason') {
  382. print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editdemandreason&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->trans('SetDemandReason'), 1).'</a></td>';
  383. }
  384. print '</tr></table>';
  385. print '</td><td colspan="2">';
  386. if ($action == 'editdemandreason') {
  387. $form->formInputReason($_SERVER['PHP_SELF'].'?id='.$object->id, $object->demand_reason_id, 'demand_reason_id', 1);
  388. } else {
  389. $form->formInputReason($_SERVER['PHP_SELF'].'?id='.$object->id, $object->demand_reason_id, 'none');
  390. }
  391. // Terms of payment
  392. /*
  393. print '<tr><td height="10">';
  394. print '<table class="nobordernopadding" width="100%"><tr><td>';
  395. print $langs->trans('PaymentConditionsShort');
  396. print '</td>';
  397. if ($action != 'editconditions' && $object->statut == Expedition::STATUS_VALIDATED) print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editconditions&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->trans('SetConditions'),1).'</a></td>';
  398. print '</tr></table>';
  399. print '</td><td colspan="2">';
  400. if ($action == 'editconditions')
  401. {
  402. $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id,$object->cond_reglement_id,'cond_reglement_id');
  403. }
  404. else
  405. {
  406. $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id,$object->cond_reglement_id,'none');
  407. }
  408. print '</td></tr>';
  409. // Mode of payment
  410. print '<tr><td>';
  411. print '<table class="nobordernopadding" width="100%"><tr><td>';
  412. print $langs->trans('PaymentMode');
  413. print '</td>';
  414. if ($action != 'editmode' && $object->statut == Expedition::STATUS_VALIDATED) print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editmode&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->trans('SetMode'),1).'</a></td>';
  415. print '</tr></table>';
  416. print '</td><td colspan="2">';
  417. if ($action == 'editmode')
  418. {
  419. $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id,$object->mode_reglement_id,'mode_reglement_id');
  420. }
  421. else
  422. {
  423. $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id,$object->mode_reglement_id,'none');
  424. }
  425. print '</td></tr>';*/
  426. $tmparray = $object->getTotalWeightVolume();
  427. $totalWeight = $tmparray['weight'];
  428. $totalVolume = $tmparray['volume'];
  429. if ($totalWeight || $totalVolume) {
  430. print '<tr><td>'.$langs->trans("CalculatedWeight").'</td>';
  431. print '<td colspan="2">';
  432. print showDimensionInBestUnit($totalWeight, 0, "weight", $langs, isset($conf->global->MAIN_WEIGHT_DEFAULT_ROUND) ? $conf->global->MAIN_WEIGHT_DEFAULT_ROUND : -1, isset($conf->global->MAIN_WEIGHT_DEFAULT_UNIT) ? $conf->global->MAIN_WEIGHT_DEFAULT_UNIT : 'no');
  433. print '</td></tr>';
  434. print '<tr><td>'.$langs->trans("CalculatedVolume").'</td>';
  435. print '<td colspan="2">';
  436. print showDimensionInBestUnit($totalVolume, 0, "volume", $langs, isset($conf->global->MAIN_VOLUME_DEFAULT_ROUND) ? $conf->global->MAIN_VOLUME_DEFAULT_ROUND : -1, isset($conf->global->MAIN_VOLUME_DEFAULT_UNIT) ? $conf->global->MAIN_VOLUME_DEFAULT_UNIT : 'no');
  437. print '</td></tr>';
  438. }
  439. // TODO How record was recorded OrderMode (llx_c_input_method)
  440. // Incoterms
  441. if (isModEnabled('incoterm')) {
  442. print '<tr><td>';
  443. print '<table width="100%" class="nobordernopadding"><tr><td>';
  444. print $langs->trans('IncotermLabel');
  445. print '<td><td class="right">';
  446. if ($user->rights->commande->creer) {
  447. print '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'/expedition/shipment.php?id='.$object->id.'&action=editincoterm&token='.newToken().'">'.img_edit().'</a>';
  448. } else {
  449. print '&nbsp;';
  450. }
  451. print '</td></tr></table>';
  452. print '</td>';
  453. print '<td colspan="2">';
  454. if ($action != 'editincoterm') {
  455. print $form->textwithpicto($object->display_incoterms(), $object->label_incoterms, 1);
  456. } else {
  457. print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms) ? $object->location_incoterms : ''), $_SERVER['PHP_SELF'].'?id='.$object->id);
  458. }
  459. print '</td></tr>';
  460. }
  461. $expe = new Expedition($db);
  462. $extrafields->fetch_name_optionals_label($expe->table_element);
  463. // Other attributes
  464. $cols = 2;
  465. include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
  466. print '</table>';
  467. print '</div>';
  468. print '<div class="fichehalfright">';
  469. print '<div class="underbanner clearboth"></div>';
  470. print '<table class="border centpercent tableforfield">';
  471. if (isModEnabled("multicurrency") && ($object->multicurrency_code != $conf->currency)) {
  472. // Multicurrency Amount HT
  473. print '<tr><td class="titlefieldmiddle">'.$form->editfieldkey('MulticurrencyAmountHT', 'multicurrency_total_ht', '', $object, 0).'</td>';
  474. print '<td class="nowrap">'.price($object->multicurrency_total_ht, '', $langs, 0, - 1, - 1, (!empty($object->multicurrency_code) ? $object->multicurrency_code : $conf->currency)).'</td>';
  475. print '</tr>';
  476. // Multicurrency Amount VAT
  477. print '<tr><td>'.$form->editfieldkey('MulticurrencyAmountVAT', 'multicurrency_total_tva', '', $object, 0).'</td>';
  478. print '<td class="nowrap">'.price($object->multicurrency_total_tva, '', $langs, 0, - 1, - 1, (!empty($object->multicurrency_code) ? $object->multicurrency_code : $conf->currency)).'</td>';
  479. print '</tr>';
  480. // Multicurrency Amount TTC
  481. print '<tr><td>'.$form->editfieldkey('MulticurrencyAmountTTC', 'multicurrency_total_ttc', '', $object, 0).'</td>';
  482. print '<td class="nowrap">'.price($object->multicurrency_total_ttc, '', $langs, 0, - 1, - 1, (!empty($object->multicurrency_code) ? $object->multicurrency_code : $conf->currency)).'</td>';
  483. print '</tr>';
  484. }
  485. // Total HT
  486. print '<tr><td class="titlefieldmiddle">'.$langs->trans('AmountHT').'</td>';
  487. print '<td>'.price($object->total_ht, 0, '', 1, -1, -1, $conf->currency).'</td>';
  488. print '</tr>';
  489. // Total VAT
  490. print '<tr><td>'.$langs->trans('AmountVAT').'</td><td>'.price($object->total_tva, 0, '', 1, -1, -1, $conf->currency).'</td>';
  491. print '</tr>';
  492. // Amount Local Taxes
  493. if ($mysoc->localtax1_assuj == "1" || $object->total_localtax1 != 0) { // Localtax1
  494. print '<tr><td>'.$langs->transcountry("AmountLT1", $mysoc->country_code).'</td>';
  495. print '<td>'.price($object->total_localtax1, 1, '', 1, - 1, - 1, $conf->currency).'</td></tr>';
  496. }
  497. if ($mysoc->localtax2_assuj == "1" || $object->total_localtax2 != 0) { // Localtax2 IRPF
  498. print '<tr><td>'.$langs->transcountry("AmountLT2", $mysoc->country_code).'</td>';
  499. print '<td>'.price($object->total_localtax2, 1, '', 1, - 1, - 1, $conf->currency).'</td></tr>';
  500. }
  501. // Total TTC
  502. print '<tr><td>'.$langs->trans('AmountTTC').'</td><td>'.price($object->total_ttc, 0, '', 1, -1, -1, $conf->currency).'</td>';
  503. print '</tr>';
  504. print '</table>';
  505. print '</div>';
  506. print '</div>';
  507. print '<div class="clearboth"></div><br>';
  508. /**
  509. * Lines or orders with quantity shipped and remain to ship
  510. * Note: Qty shipped are already available into $object->expeditions[fk_product]
  511. */
  512. print '<table id="tablelines" class="noborder noshadow" width="100%">';
  513. $sql = "SELECT cd.rowid, cd.fk_product, cd.product_type as type, cd.label, cd.description,";
  514. $sql .= " cd.price, cd.tva_tx, cd.subprice,";
  515. $sql .= " cd.qty, cd.fk_unit,";
  516. $sql .= ' cd.date_start,';
  517. $sql .= ' cd.date_end,';
  518. $sql .= ' cd.special_code,';
  519. $sql .= ' p.rowid as prodid, p.label as product_label, p.entity, p.ref, p.fk_product_type as product_type, p.description as product_desc,';
  520. $sql .= ' p.weight, p.weight_units, p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,';
  521. $sql .= ' p.surface, p.surface_units, p.volume, p.volume_units';
  522. $sql .= ', p.tobatch, p.tosell, p.tobuy, p.barcode';
  523. $sql .= ', u.short_label as unit_order';
  524. $sql .= " FROM ".MAIN_DB_PREFIX."commandedet as cd";
  525. $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON cd.fk_product = p.rowid";
  526. $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_units as u ON cd.fk_unit = u.rowid";
  527. $sql .= " WHERE cd.fk_commande = ".((int) $object->id);
  528. $sql .= " ORDER BY cd.rang, cd.rowid";
  529. //print $sql;
  530. dol_syslog("shipment.php", LOG_DEBUG);
  531. $resql = $db->query($sql);
  532. if ($resql) {
  533. $num = $db->num_rows($resql);
  534. $i = 0;
  535. print '<thead>';
  536. print '<tr class="liste_titre">';
  537. print '<th>'.$langs->trans("Description").'</th>';
  538. print '<th class="center">'.$langs->trans("QtyOrdered").'</th>';
  539. print '<th class="center">'.$langs->trans("QtyShipped").'</th>';
  540. print '<th class="center">'.$langs->trans("KeepToShip").'</th>';
  541. if (isModEnabled('stock')) {
  542. print '<th class="center">'.$langs->trans("RealStock").'</th>';
  543. } else {
  544. print '<th>&nbsp;</th>';
  545. }
  546. print "</tr>\n";
  547. print '</thead>';
  548. $toBeShipped = array();
  549. $toBeShippedTotal = 0;
  550. while ($i < $num) {
  551. $objp = $db->fetch_object($resql);
  552. $parameters = array('i' => $i, 'line' => $objp, 'num' => $num);
  553. $reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $object, $action);
  554. if ($reshook < 0) {
  555. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  556. }
  557. if (empty($reshook)) {
  558. // Show product and description
  559. $type = isset($objp->type) ? $objp->type : $objp->product_type;
  560. // Try to enhance type detection using date_start and date_end for free lines where type
  561. // was not saved.
  562. if (!empty($objp->date_start)) {
  563. $type = 1;
  564. }
  565. if (!empty($objp->date_end)) {
  566. $type = 1;
  567. }
  568. print '<tr class="oddeven">';
  569. // Product label
  570. if ($objp->fk_product > 0) {
  571. // Define output language
  572. if (getDolGlobalInt('MAIN_MULTILANGS') && !empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) {
  573. $object->fetch_thirdparty();
  574. $prod = new Product($db);
  575. $prod->id = $objp->fk_product;
  576. $prod->entity = $objp->entity;
  577. $prod->getMultiLangs();
  578. $outputlangs = $langs;
  579. $newlang = '';
  580. if (empty($newlang) && GETPOST('lang_id', 'aZ09')) {
  581. $newlang = GETPOST('lang_id', 'aZ09');
  582. }
  583. if (empty($newlang)) {
  584. $newlang = $object->thirdparty->default_lang;
  585. }
  586. if (!empty($newlang)) {
  587. $outputlangs = new Translate("", $conf);
  588. $outputlangs->setDefaultLang($newlang);
  589. }
  590. $label = (!empty($prod->multilangs[$outputlangs->defaultlang]["label"])) ? $prod->multilangs[$outputlangs->defaultlang]["label"] : $objp->product_label;
  591. } else {
  592. $label = (!empty($objp->label) ? $objp->label : $objp->product_label);
  593. }
  594. print '<td>';
  595. print '<a name="'.$objp->rowid.'"></a>'; // ancre pour retourner sur la ligne
  596. // Show product and description
  597. $product_static->type = $type;
  598. $product_static->id = $objp->fk_product;
  599. $product_static->ref = $objp->ref;
  600. $product_static->entity = $objp->entity;
  601. $product_static->status = $objp->tosell;
  602. $product_static->status_buy = $objp->tobuy;
  603. $product_static->status_batch = $objp->tobatch;
  604. $product_static->barcode = $objp->barcode;
  605. $product_static->weight = $objp->weight;
  606. $product_static->weight_units = $objp->weight_units;
  607. $product_static->length = $objp->length;
  608. $product_static->length_units = $objp->length_units;
  609. $product_static->width = $objp->width;
  610. $product_static->width_units = $objp->width_units;
  611. $product_static->height = $objp->height;
  612. $product_static->height_units = $objp->height_units;
  613. $product_static->surface = $objp->surface;
  614. $product_static->surface_units = $objp->surface_units;
  615. $product_static->volume = $objp->volume;
  616. $product_static->volume_units = $objp->volume_units;
  617. $text = $product_static->getNomUrl(1);
  618. $text .= ' - '.$label;
  619. $description = (getDolGlobalInt('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE') ? '' : dol_htmlentitiesbr($objp->description)).'<br>';
  620. $description .= $product_static->show_photos('product', $conf->product->multidir_output[$product_static->entity], 1, 1, 0, 0, 0, 80);
  621. print $form->textwithtooltip($text, $description, 3, '', '', $i);
  622. // Show range
  623. print_date_range($db->jdate($objp->date_start), $db->jdate($objp->date_end));
  624. // Add description in form
  625. if (getDolGlobalInt('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE')) {
  626. print ($objp->description && $objp->description != $objp->product_label) ? '<br>'.dol_htmlentitiesbr($objp->description) : '';
  627. }
  628. print '</td>';
  629. } else {
  630. print "<td>";
  631. if ($type == 1) {
  632. $text = img_object($langs->trans('Service'), 'service');
  633. } else {
  634. $text = img_object($langs->trans('Product'), 'product');
  635. }
  636. if (!empty($objp->label)) {
  637. $text .= ' <strong>'.$objp->label.'</strong>';
  638. print $form->textwithtooltip($text, $objp->description, 3, '', '', $i);
  639. } else {
  640. print $text.' '.nl2br($objp->description);
  641. }
  642. // Show range
  643. print_date_range($db->jdate($objp->date_start), $db->jdate($objp->date_end));
  644. print "</td>\n";
  645. }
  646. // Qty ordered
  647. print '<td class="center">'.$objp->qty.($objp->unit_order ? ' '.$objp->unit_order : '').'</td>';
  648. // Qty already shipped
  649. $qtyProdCom = $objp->qty;
  650. print '<td class="center">';
  651. // Nb of sending products for this line of order
  652. $qtyAlreadyShipped = (!empty($object->expeditions[$objp->rowid]) ? $object->expeditions[$objp->rowid] : 0);
  653. print $qtyAlreadyShipped;
  654. print ($objp->unit_order ? ' '.$objp->unit_order : '').'</td>';
  655. // Qty remains to ship
  656. print '<td class="center">';
  657. if ($type == 0 || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
  658. $toBeShipped[$objp->fk_product] = $objp->qty - $qtyAlreadyShipped;
  659. $toBeShippedTotal += $toBeShipped[$objp->fk_product];
  660. print $toBeShipped[$objp->fk_product];
  661. } else {
  662. print '0 ('.$langs->trans("Service").')';
  663. }
  664. print ($objp->unit_order ? ' '.$objp->unit_order : '').'</td>';
  665. if ($objp->fk_product > 0) {
  666. $product = new Product($db);
  667. $product->fetch($objp->fk_product);
  668. $product->load_stock('warehouseopen');
  669. }
  670. if ($objp->fk_product > 0 && ($type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) && isModEnabled('stock')) {
  671. print '<td class="center">';
  672. print $product->stock_reel;
  673. if ($product->stock_reel < $toBeShipped[$objp->fk_product]) {
  674. print ' '.img_warning($langs->trans("StockTooLow"));
  675. if (!empty($conf->global->STOCK_CORRECT_STOCK_IN_SHIPMENT)) {
  676. $nbPiece = $toBeShipped[$objp->fk_product] - $product->stock_reel;
  677. print ' &nbsp; '.$langs->trans("GoTo").' <a href="'.DOL_URL_ROOT.'/product/stock/product.php?id='.((int) $product->id).'&action=correction&nbpiece='.urlencode($nbPiece).'&backtopage='.urlencode($_SERVER["PHP_SELF"].'?id='.((int) $object->id)).'">'.$langs->trans("CorrectStock").'</a>';
  678. }
  679. }
  680. print '</td>';
  681. } else {
  682. print '<td>&nbsp;</td>';
  683. }
  684. print "</tr>\n";
  685. // Show subproducts lines
  686. if ($objp->fk_product > 0 && !empty($conf->global->PRODUIT_SOUSPRODUITS)) {
  687. // Set tree of subproducts in product->sousprods
  688. $product->get_sousproduits_arbo();
  689. //var_dump($product->sousprods);exit;
  690. // Define a new tree with quantiies recalculated
  691. $prods_arbo = $product->get_arbo_each_prod($qtyProdCom);
  692. //var_dump($prods_arbo);
  693. if (count($prods_arbo) > 0) {
  694. foreach ($prods_arbo as $key => $value) {
  695. $img = '';
  696. if ($value['stock'] < $value['stock_alert']) {
  697. $img = img_warning($langs->trans("StockTooLow"));
  698. }
  699. print '<tr class="oddeven"><td>&nbsp; &nbsp; &nbsp; -> <a href="'.DOL_URL_ROOT."/product/card.php?id=".$value['id'].'">'.$value['fullpath'].'</a> ('.$value['nb'].')</td>';
  700. print '<td class="center"> '.$value['nb_total'].'</td>';
  701. print '<td>&nbsp;</td>';
  702. print '<td>&nbsp;</td>';
  703. print '<td class="center">'.$value['stock'].' '.$img.'</td></tr>'."\n";
  704. }
  705. }
  706. }
  707. }
  708. $i++;
  709. }
  710. $db->free($resql);
  711. if (!$num) {
  712. print '<tr '.$bc[false].'><td colspan="5">'.$langs->trans("NoArticleOfTypeProduct").'<br>';
  713. }
  714. print "</table>";
  715. } else {
  716. dol_print_error($db);
  717. }
  718. print '</div>';
  719. /*
  720. * Boutons Actions
  721. */
  722. if (empty($user->socid)) {
  723. print '<div class="tabsAction">';
  724. // Bouton expedier sans gestion des stocks
  725. if (!isModEnabled('stock') && ($object->statut > Commande::STATUS_DRAFT && $object->statut < Commande::STATUS_CLOSED)) {
  726. if ($user->rights->expedition->creer) {
  727. print '<a class="butAction" href="'.DOL_URL_ROOT.'/expedition/card.php?action=create&amp;origin=commande&amp;object_id='.$id.'">'.$langs->trans("CreateShipment").'</a>';
  728. if ($toBeShippedTotal <= 0) {
  729. print ' '.img_warning($langs->trans("WarningNoQtyLeftToSend"));
  730. }
  731. } else {
  732. print '<a class="butActionRefused classfortooltip" href="#">'.$langs->trans("CreateShipment").'</a>';
  733. }
  734. }
  735. print "</div>";
  736. }
  737. // Bouton expedier avec gestion des stocks
  738. if (isModEnabled('stock') && $object->statut == Commande::STATUS_DRAFT) {
  739. print $langs->trans("ValidateOrderFirstBeforeShipment");
  740. }
  741. if (isModEnabled('stock') && ($object->statut > Commande::STATUS_DRAFT && $object->statut < Commande::STATUS_CLOSED)) {
  742. if ($user->rights->expedition->creer) {
  743. //print load_fiche_titre($langs->trans("CreateShipment"));
  744. print '<div class="tabsAction">';
  745. print '<form method="GET" action="'.DOL_URL_ROOT.'/expedition/card.php">';
  746. print '<input type="hidden" name="action" value="create">';
  747. //print '<input type="hidden" name="id" value="'.$object->id.'">';
  748. print '<input type="hidden" name="shipping_method_id" value="'.$object->shipping_method_id.'">';
  749. print '<input type="hidden" name="origin" value="commande">';
  750. print '<input type="hidden" name="origin_id" value="'.$object->id.'">';
  751. print '<input type="hidden" name="projectid" value="'.$object->fk_project.'">';
  752. //print '<table class="border centpercent">';
  753. $langs->load("stocks");
  754. //print '<tr>';
  755. if (isModEnabled('stock')) {
  756. //print '<td>';
  757. print $langs->trans("WarehouseSource");
  758. //print '</td>';
  759. //print '<td>';
  760. print $formproduct->selectWarehouses(!empty($object->warehouse_id) ? $object->warehouse_id : 'ifone', 'entrepot_id', '', 1, 0, 0, '', 0, 0, array(), 'minwidth200');
  761. if (count($formproduct->cache_warehouses) <= 0) {
  762. print ' &nbsp; '.$langs->trans("WarehouseSourceNotDefined").' <a href="'.DOL_URL_ROOT.'/product/stock/card.php?action=create">'.$langs->trans("AddOne").'</a>';
  763. }
  764. //print '</td>';
  765. }
  766. //print '<td class="center">';
  767. print '<input type="submit" class="butAction" named="save" value="'.$langs->trans("CreateShipment").'">';
  768. if ($toBeShippedTotal <= 0) {
  769. print ' '.img_warning($langs->trans("WarningNoQtyLeftToSend"));
  770. }
  771. //print '</td></tr>';
  772. //print "</table>";
  773. print "</form>\n";
  774. print '</div>';
  775. $somethingshown = 1;
  776. } else {
  777. print '<div class="tabsAction">';
  778. print '<a class="butActionRefused classfortooltip" href="#">'.$langs->trans("CreateShipment").'</a>';
  779. print '</div>';
  780. }
  781. }
  782. show_list_sending_receive('commande', $object->id);
  783. } else {
  784. /* Order not found */
  785. setEventMessages($langs->trans("NonExistentOrder"), null, 'errors');
  786. }
  787. }
  788. // End of page
  789. llxFooter();
  790. $db->close();