HEX
Server: Apache
System: Linux srv13.cpanelhost.cl 3.10.0-962.3.2.lve1.5.38.el7.x86_64 #1 SMP Thu Jun 18 05:28:41 EDT 2020 x86_64
User: cca63905 (4205)
PHP: 7.3.20
Disabled: NONE
Upload Files
File: /home4/cca63905/www/guiaweb/htdocs/core/lib/sendings.lib.php
<?php
/* Copyright (C) 2008-2012	Laurent Destailleur	<eldy@users.sourceforge.net>
 * Copyright (C) 2012		Regis Houssin		<regis.houssin@inodbox.com>
 * Copyright (C) 2024-2025	MDW					<mdeweerd@users.noreply.github.com>
 * Copyright (C) 2025       Frédéric France         <frederic.france@free.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
 */

/**
 *	\file       htdocs/core/lib/sendings.lib.php
 *	\ingroup    expedition
 *	\brief      Library for expedition module
 */
require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';


/**
 * Prepare array with list of tabs
 *
 * @param   Expedition	$object		Object related to tabs
 * @return	array<array{0:string,1:string,2:string}>	Array of tabs to show
 */
function shipping_prepare_head($object)
{
	global $db, $langs, $conf, $user;

	// Load translation files required by the page
	$langs->loadLangs(array("sendings", "deliveries"));

	$h = 0;
	$head = array();

	$head[$h][0] = DOL_URL_ROOT."/expedition/card.php?id=".$object->id;
	$head[$h][1] = $langs->trans("SendingCard");
	$head[$h][2] = 'shipping';
	$h++;

	if ($object->status == Expedition::STATUS_DRAFT) {
		$head[$h][0] = DOL_URL_ROOT."/expedition/dispatch.php?id=".$object->id;
		$head[$h][1] = $langs->trans("ShipmentDistribution");
		$head[$h][2] = 'dispatch';
		$h++;
	}

	if (getDolGlobalInt('MAIN_SUBMODULE_DELIVERY') && $user->hasRight('expedition', 'delivery', 'lire')) {
		// delivery link
		$object->fetchObjectLinked($object->id, $object->element);
		if (isset($object->linkedObjectsIds['delivery']) && is_array($object->linkedObjectsIds['delivery']) && count($object->linkedObjectsIds['delivery']) > 0) {        // If there is a delivery
			// Take first element of array
			$tmp = reset($object->linkedObjectsIds['delivery']);

			$head[$h][0] = DOL_URL_ROOT."/delivery/card.php?id=".((int) $tmp);
			$head[$h][1] = $langs->trans("DeliveryCard");
			$head[$h][2] = 'delivery';
			$h++;
		}
	}

	if (!getDolGlobalString('MAIN_DISABLE_CONTACTS_TAB')) {
		$objectsrc = $object;
		if (!getDolGlobalInt('SHIPPING_USE_ITS_OWN_CONTACTS') && $object->origin_type == 'commande' && $object->origin_id > 0) {
			$objectsrc = new Commande($db);
			$objectsrc->fetch($object->origin_id);
		}
		$nbContact = count($objectsrc->liste_contact(-1, 'internal')) + count($objectsrc->liste_contact(-1, 'external'));
		$head[$h][0] = DOL_URL_ROOT."/expedition/contact.php?id=".((int) $object->id);
		$head[$h][1] = $langs->trans("ContactsAddresses");
		if ($nbContact > 0) {
			$head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbContact.'</span>';
		}
		$head[$h][2] = 'contact';
		$h++;
	}

	// Files
	require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php';
	require_once DOL_DOCUMENT_ROOT . '/core/class/link.class.php';
	$upload_dir = $conf->expedition->dir_output . "/sending/" . dol_sanitizeFileName($object->ref);
	$nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$'));
	$nbLinks = Link::count($db, $object->element, $object->id);
	$head[$h][0] = DOL_URL_ROOT.'/expedition/document.php?id='.$object->id;
	$head[$h][1] = $langs->trans('Documents');
	if (($nbFiles + $nbLinks) > 0) {
		$head[$h][1] .= '<span class="badge marginleftonlyshort">'.($nbFiles + $nbLinks).'</span>';
	}
	$head[$h][2] = 'documents';
	$h++;

	// Notes
	$nbNote = 0;
	if (!empty($object->note_private)) {
		$nbNote++;
	}
	if (!empty($object->note_public)) {
		$nbNote++;
	}
	$head[$h][0] = DOL_URL_ROOT."/expedition/note.php?id=".$object->id;
	$head[$h][1] = $langs->trans("Notes");
	if ($nbNote > 0) {
		$head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbNote.'</span>';
	}
	$head[$h][2] = 'note';
	$h++;

	// Events
	$head[$h][0] = DOL_URL_ROOT . '/expedition/agenda.php?id=' . $object->id;
	$head[$h][1] = $langs->trans("Events");
	if (isModEnabled('agenda') && ($user->hasRight('agenda', 'myactions', 'read') || $user->hasRight('agenda', 'allactions', 'read'))) {
		$nbEvent = 0;
		// Enable caching of thirdparty count actioncomm
		require_once DOL_DOCUMENT_ROOT . '/core/lib/memory.lib.php';
		$cachekey = 'count_events_expedition_' . $object->id;
		$dataretrieved = dol_getcache($cachekey);
		if (!is_null($dataretrieved)) {
			$nbEvent = $dataretrieved;
		} else {
			$sql = "SELECT COUNT(id) as nb";
			$sql .= " FROM " . MAIN_DB_PREFIX . "actioncomm";
			$sql .= " WHERE fk_element = " . ((int) $object->id);
			$sql .= " AND elementtype = 'shipping'";
			$resql = $db->query($sql);
			if ($resql) {
				$obj = $db->fetch_object($resql);
				$nbEvent = $obj->nb;
			} else {
				dol_syslog('Failed to count actioncomm ' . $db->lasterror(), LOG_ERR);
			}
			dol_setcache($cachekey, $nbEvent, 120);    // If setting cache fails, this is not a problem, so we do not test result.
		}

		$head[$h][1] .= '/';
		$head[$h][1] .= $langs->trans("Agenda");
		if ($nbEvent > 0) {
			$head[$h][1] .= '<span class="badge marginleftonlyshort">' . $nbEvent . '</span>';
		}
	}
	$head[$h][2] = 'agenda';
	$h++;

	// Show more tabs from modules
	// Entries must be declared in modules descriptor with line
	// $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__');   to add new tab
	// $this->tabs = array('entity:-tabname);   												to remove a tab
	complete_head_from_modules($conf, $langs, $object, $head, $h, 'delivery');

	complete_head_from_modules($conf, $langs, $object, $head, $h, 'delivery', 'remove');

	return $head;
}


/**
 * Prepare array with list of tabs
 *
 * @param   Delivery	$object		Object related to tabs
 * @return	array<array{0:string,1:string,2:string}>	Array of tabs to show
 */
function delivery_prepare_head($object)
{
	global $langs, $db, $conf, $user;

	// Load translation files required by the page
	$langs->loadLangs(array("sendings", "deliveries"));

	$h = 0;
	$head = array();

	if (getDolGlobalInt('MAIN_SUBMODULE_EXPEDITION') && $user->hasRight('expedition', 'lire')) {
		$head[$h][0] = DOL_URL_ROOT."/expedition/card.php?id=".$object->origin_id;
		$head[$h][1] = $langs->trans("SendingCard");
		$head[$h][2] = 'shipping';
		$h++;
	}

	$head[$h][0] = DOL_URL_ROOT."/delivery/card.php?id=".$object->id;
	$head[$h][1] = $langs->trans("DeliveryCard");
	$head[$h][2] = 'delivery';
	$h++;

	// Show more tabs from modules
	// Entries must be declared in modules descriptor with line
	// $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__');   to add new tab
	// $this->tabs = array('entity:-tabname);   				to remove a tab
	// complete_head_from_modules  use $object->id for this link so we temporary change it

	$savObjectId = $object->id;

	// Get parent object
	$tmpobject = null;
	if ($object->origin_type) {
		$tmpobject = new Expedition($db);
		$tmpobject->fetch($object->origin_id);
	} else {
		$tmpobject = $object;
	}

	if (!getDolGlobalString('MAIN_DISABLE_CONTACTS_TAB')) {
		$objectsrc = $tmpobject;
		if ($tmpobject->origin_type == 'commande' && $tmpobject->origin_id > 0) {
			$objectsrc = new Commande($db);
			$objectsrc->fetch($tmpobject->origin_id);
		}
		$nbContact = count($objectsrc->liste_contact(-1, 'internal')) + count($objectsrc->liste_contact(-1, 'external'));
		$head[$h][0] = DOL_URL_ROOT."/expedition/contact.php?id=".$tmpobject->id;
		$head[$h][1] = $langs->trans("ContactsAddresses");
		if ($nbContact > 0) {
			$head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbContact.'</span>';
		}
		$head[$h][2] = 'contact';
		$h++;
	}

	// Files
	require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
	require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php';
	$upload_dir = $conf->expedition->dir_output."/sending/".dol_sanitizeFileName($tmpobject->ref);
	$nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$'));
	$nbLinks = Link::count($db, $tmpobject->element, $tmpobject->id);
	$head[$h][0] = DOL_URL_ROOT.'/expedition/document.php?id='.$tmpobject->id;
	$head[$h][1] = $langs->trans('Documents');
	if (($nbFiles + $nbLinks) > 0) {
		$head[$h][1] .= '<span class="badge marginleftonlyshort">'.($nbFiles + $nbLinks).'</span>';
	}
	$head[$h][2] = 'documents';
	$h++;

	// Notes
	$nbNote = 0;
	if (!empty($tmpobject->note_private)) {
		$nbNote++;
	}
	if (!empty($tmpobject->note_public)) {
		$nbNote++;
	}
	$head[$h][0] = DOL_URL_ROOT."/expedition/note.php?id=".$tmpobject->id;
	$head[$h][1] = $langs->trans("Notes");
	if ($nbNote > 0) {
		$head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbNote.'</span>';
	}
	$head[$h][2] = 'note';
	$h++;

	// Events
	$head[$h][0] = DOL_URL_ROOT . '/expedition/agenda.php?id=' . $tmpobject->id;
	$head[$h][1] = $langs->trans("Events");
	if (isModEnabled('agenda') && ($user->hasRight('agenda', 'myactions', 'read') || $user->hasRight('agenda', 'allactions', 'read'))) {
		$nbEvent = 0;
		// Enable caching of thirdparty count actioncomm
		require_once DOL_DOCUMENT_ROOT . '/core/lib/memory.lib.php';
		$cachekey = 'count_events_expedition_' . $tmpobject->id;
		$dataretrieved = dol_getcache($cachekey);
		if (!is_null($dataretrieved)) {
			$nbEvent = $dataretrieved;
		} else {
			$sql = "SELECT COUNT(id) as nb";
			$sql .= " FROM " . MAIN_DB_PREFIX . "actioncomm";
			$sql .= " WHERE fk_element = " . ((int) $tmpobject->id);
			$sql .= " AND elementtype = 'shipping'";
			$resql = $db->query($sql);
			if ($resql) {
				$obj = $db->fetch_object($resql);
				$nbEvent = $obj->nb;
			} else {
				dol_syslog('Failed to count actioncomm ' . $db->lasterror(), LOG_ERR);
			}
			dol_setcache($cachekey, $nbEvent, 120);    // If setting cache fails, this is not a problem, so we do not test result.
		}

		$head[$h][1] .= '/';
		$head[$h][1] .= $langs->trans("Agenda");
		if ($nbEvent > 0) {
			$head[$h][1] .= '<span class="badge marginleftonlyshort">' . $nbEvent . '</span>';
		}
	}
	$head[$h][2] = 'agenda';
	$h++;


	$object->id = $tmpobject->id;

	complete_head_from_modules($conf, $langs, $object, $head, $h, 'delivery');

	complete_head_from_modules($conf, $langs, $object, $head, $h, 'delivery', 'remove');

	$object->id = $savObjectId;
	return $head;
}

/**
 * List sendings and receive receipts
 *
 * @param   string		$origin			Origin ('commande', ...)
 * @param	int			$origin_id		Origin id
 * @param	string		$filter			Filter (Do not use a string from a user input)
 * @return	int							Return integer <0 if KO, >0 if OK
 */
function show_list_sending_receive($origin, $origin_id, $filter = '')
{
	global $db, $conf, $langs;
	global $form;

	$product_static = new Product($db);
	$expedition = new Expedition($db);
	$warehousestatic = new Entrepot($db);

	$sql = "SELECT obj.rowid, obj.fk_product, obj.label, obj.description, obj.product_type as fk_product_type, obj.qty as qty_asked, obj.date_start, obj.date_end, obj.special_code,";
	$sql .= " ed.rowid as edrowid, ed.qty as qty_shipped, ed.fk_expedition as expedition_id, ed.fk_elementdet, ed.fk_entrepot as warehouse_id,";
	$sql .= " e.rowid as sendingid, e.ref as exp_ref, e.date_creation, e.date_delivery, e.date_expedition, e.billed, e.fk_statut as status, e.signed_status,";
	$sql .= ' p.label as product_label, p.ref, p.fk_product_type, p.rowid as prodid, p.tobatch as product_tobatch,';
	$sql .= ' p.description as product_desc';
	$sql .= " FROM ".MAIN_DB_PREFIX."expeditiondet as ed,";
	$sql .= " ".MAIN_DB_PREFIX."expedition as e,";
	$sql .= " ".MAIN_DB_PREFIX.$origin."det as obj";	// for example llx_commandedet
	$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON obj.fk_product = p.rowid";
	//TODO Add link to expeditiondet_batch
	$sql .= " WHERE e.entity IN (".getEntity('expedition').")";
	$sql .= " AND obj.fk_".$origin." = ".((int) $origin_id);
	$sql .= " AND obj.rowid = ed.fk_elementdet";
	if (isModEnabled('subtotals')) {
		$sql .= " AND obj.special_code <> ".SUBTOTALS_SPECIAL_CODE;
	}
	$sql .= " AND ed.fk_expedition = e.rowid";
	if ($filter) {
		$sql .= $filter;
	}
	$sql .= " ORDER BY obj.rowid, obj.fk_product";

	dol_syslog("show_list_sending_receive", LOG_DEBUG);
	$resql = $db->query($sql);
	if ($resql) {
		$num = $db->num_rows($resql);
		$i = 0;

		if ($num) {
			if ($filter) {
				print load_fiche_titre($langs->trans("OtherSendingsForSameOrder"));
			} else {
				print load_fiche_titre($langs->trans("SendingsAndReceivingForSameOrder"));
			}

			print '<div class="div-table-responsive-no-min">';
			print '<table class="liste centpercent">';
			print '<tr class="liste_titre">';
			//print '<td class="left">'.$langs->trans("QtyOrdered").'</td>';
			print '<td>'.$langs->trans("SendingSheet").'</td>';
			print '<td>'.$langs->trans("Description").'</td>';
			print '<td class="center">'.$langs->trans("DateCreation").'</td>';
			print '<td class="center">'.$langs->trans("DateDeliveryPlanned").'</td>';
			print '<td class="center">'.$langs->trans("QtyPreparedOrShipped").'</td>';
			if (isModEnabled('stock')) {
				print '<td>'.$langs->trans("Warehouse").'</td>';
			}
			/*TODO Add link to expeditiondet_batch
			if (isModEnabled('productbatch'))
			{
				print '<td>';
				print '</td>';
			}*/
			if (getDolGlobalInt('MAIN_SUBMODULE_DELIVERY')) {
				print '<td>'.$langs->trans("DeliveryOrder").'</td>';
				//print '<td class="center">'.$langs->trans("QtyReceived").'</td>';
				print '<td class="right">'.$langs->trans("DeliveryDate").'</td>';
			}
			print "</tr>\n";

			while ($i < $num) {
				$objp = $db->fetch_object($resql);

				$expedition->id = $objp->expedition_id;
				$expedition->ref = $objp->exp_ref;
				$expedition->billed = $objp->billed;
				$expedition->statut = $objp->status;
				$expedition->status = $objp->status;
				$expedition->signed_status = $objp->signed_status;

				print '<tr class="oddeven">';

				// Sending id
				print '<td class="tdoverflowmax125">';
				print $expedition->getNomUrl(1);
				//print '<a href="'.DOL_URL_ROOT.'/expedition/card.php?id='.$objp->expedition_id.'">'.img_object($langs->trans("ShowSending"), 'sending').' '.$objp->exp_ref.'<a>';
				print '</td>';

				// Description
				if ($objp->fk_product > 0) {
					// Define output language
					if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
						$object = new $origin($db);
						'@phan-var-force CommonObject $object';
						$object->fetch($origin_id);
						$object->fetch_thirdparty();

						$prod = new Product($db);
						$prod->id = $objp->fk_product;
						$prod->getMultiLangs();

						$outputlangs = $langs;
						$newlang = '';
						if (empty($newlang) && GETPOST('lang_id', 'aZ09')) {
							$newlang = GETPOST('lang_id', 'aZ09');
						}
						if (empty($newlang)) {
							$newlang = $object->thirdparty->default_lang;
						}
						if (!empty($newlang)) {
							$outputlangs = new Translate("", $conf);
							$outputlangs->setDefaultLang($newlang);
						}

						$label = (!empty($prod->multilangs[$outputlangs->defaultlang]["label"])) ? $prod->multilangs[$outputlangs->defaultlang]["label"] : $objp->product_label;
					} else {
						$label = (!empty($objp->label) ? $objp->label : $objp->product_label);
					}

					print '<td>';

					// Show product and description
					$product_static->type = $objp->fk_product_type;
					$product_static->id = $objp->fk_product;
					$product_static->ref = $objp->ref;
					$product_static->status_batch = $objp->product_tobatch;

					$text = $product_static->getNomUrl(1);
					$text .= ' - '.$label;
					$description = (getDolGlobalInt('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE') ? '' : dol_htmlentitiesbr($objp->description));
					print $form->textwithtooltip($text, $description, 3, 0, '', (string) $i);

					// Show range
					print_date_range($objp->date_start, $objp->date_end);

					// Add description in form
					if (getDolGlobalInt('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE')) {
						print(!empty($objp->description) ? ((empty($objp->product) || $objp->description != $objp->product) ? '<br>'.dol_htmlentitiesbr($objp->description) : '') : '');
					}

					print '</td>';
				} else {
					print "<td>";
					if ($objp->fk_product_type == 1) {
						$text = img_object($langs->trans('Service'), 'service');
					} else {
						$text = img_object($langs->trans('Product'), 'product');
					}

					if (!empty($objp->label)) {
						$text .= ' <strong>'.$objp->label.'</strong>';
						print $form->textwithtooltip($text, $objp->description, 3, 0, '', (string) $i);
					} else {
						print $text.' '.nl2br($objp->description);
					}

					// Show range
					print_date_range($objp->date_start, $objp->date_end);
					print "</td>\n";
				}

				//print '<td class="center">'.$objp->qty_asked.'</td>';

				// Date creation
				print '<td class="nowrap center">'.dol_print_date($db->jdate($objp->date_creation), 'day').'</td>';

				// Date shipping creation
				print '<td class="nowrap center">'.dol_print_date($db->jdate($objp->date_delivery), 'day').'</td>';

				// Qty shipped
				print '<td class="center">'.$objp->qty_shipped.'</td>';

				// Warehouse
				if (isModEnabled('stock')) {
					print '<td class="tdoverflowmax125">';
					if ($objp->warehouse_id > 0) {
						$warehousestatic->fetch($objp->warehouse_id);
						print $warehousestatic->getNomUrl(1);
					}
					print '</td>';
				}

				// Batch number management
				/*TODO Add link to expeditiondet_batch
				if (isModEnabled('productbatch'))
				{
					//var_dump($objp->edrowid);
					$lines[$i]->detail_batch
					if (isset($lines[$i]->detail_batch))
					{
						print '<td>';
						if ($lines[$i]->product_tobatch)
						{
							$detail = '';
							foreach ($lines[$i]->detail_batch as $dbatch)
							{
								$detail.= $langs->trans("Batch").': '.$dbatch->batch;
								$detail.= ' - '.$langs->trans("SellByDate").': '.dol_print_date($dbatch->sellby,"day");
								$detail.= ' - '.$langs->trans("EatByDate").': '.dol_print_date($dbatch->eatby,"day");
								$detail.= ' - '.$langs->trans("Qty").': '.$dbatch->qty;
								$detail.= '<br>';
							}
							print $form->textwithtooltip(img_picto('', 'object_barcode').' '.$langs->trans("DetailBatchNumber"),$detail);
						}
						else
						{
							print $langs->trans("NA");
						}
						print '</td>';
					} else {
						print '<td></td>';
					}
				}*/

				// Information on receipt
				if (getDolGlobalInt('MAIN_SUBMODULE_DELIVERY')) {
					include_once DOL_DOCUMENT_ROOT.'/delivery/class/delivery.class.php';
					$expedition->fetchObjectLinked($expedition->id, $expedition->element, null, 'delivery');
					//var_dump($expedition->linkedObjects);

					$receiving = '';
					if (!empty($expedition->linkedObjects['delivery'])) {
						$receiving = reset($expedition->linkedObjects['delivery']); // Take first link
					}

					if (!empty($receiving)) {
						/** @var Delivery $receiving */
						'@phan-var-force Delivery $receiving';
						// $expedition->fk_elementdet = id of det line of order
						// $receiving->fk_origin_line = id of det line of order
						// $receiving->origin may be 'shipping'
						// $receiving->origin_id may be id of shipping

						// Ref
						print '<td>';
						print $receiving->getNomUrl(1);
						//print '<a href="'.DOL_URL_ROOT.'/delivery/card.php?id='.$livraison_id.'">'.img_object($langs->trans("ShowReceiving"),'sending').' '.$objp->livraison_ref.'<a>';
						print '</td>';
						// Qty received
						//print '<td class="center">';
						// TODO No solution for the moment to link a line det of receipt with a line det of shipping,
						// so no way to know the qty received for this line of shipping.
						//print $langs->trans("FeatureNotYetAvailable");
						//print '</td>';
						// Date shipping real
						print '<td class="right">';
						print dol_print_date($receiving->date_delivery, 'day');
						print '</td>';
					} else {
						//print '<td>&nbsp;</td>';
						print '<td>&nbsp;</td>';
						print '<td>&nbsp;</td>';
					}
				}
				print '</tr>';
				$i++;
			}

			print '</table>';
			print '</div>';
		}
		$db->free($resql);
	} else {
		dol_print_error($db);
	}

	return 1;
}