28require_once DOL_DOCUMENT_ROOT.
'/core/class/commonobjectline.class.php';
40 public $element =
'stocktransferline';
45 public $table_element =
'stocktransfer_stocktransferline';
50 public $picto =
'stocktransferline@stocktransfer';
52 const STATUS_DRAFT = 0;
53 const STATUS_VALIDATED = 1;
54 const STATUS_CANCELED = 9;
86 public $fields = array(
87 'rowid' => array(
'type' =>
'integer',
'label' =>
'TechnicalID',
'enabled' => 1,
'position' => 1,
'notnull' => 1,
'visible' => 0,
'noteditable' => 1,
'index' => 1,
'comment' =>
"Id"),
88 'amount' => array(
'type' =>
'price',
'label' =>
'Amount',
'enabled' => 1,
'position' => 40,
'notnull' => 0,
'visible' => 1,
'default' =>
'null',
'isameasure' => 1,
'help' =>
"Help text for amount",),
89 'qty' => array(
'type' =>
'real',
'label' =>
'Qty',
'enabled' => 1,
'position' => 45,
'notnull' => 0,
'visible' => 1,
'default' =>
'0',
'isameasure' => 1,
'css' =>
'maxwidth75imp',
'help' =>
"Help text for quantity",),
90 'fk_warehouse_destination' => array(
'type' =>
'integer:Entrepot:product/stock/class/entrepot.class.php',
'label' =>
'Entrepôt de destination',
'enabled' => 1,
'position' => 50,
'notnull' => 1,
'visible' => 1,),
91 'fk_warehouse_source' => array(
'type' =>
'integer:Entrepot:product/stock/class/entrepot.class.php',
'label' =>
'Entrepôt source',
'enabled' => 1,
'position' => 50,
'notnull' => 1,
'visible' => 1,),
92 'fk_stocktransfer' => array(
'type' =>
'integer:StockTransfer:stocktransfer/stock/class/stocktransfer.class.php',
'label' =>
'StockTransfer',
'enabled' => 1,
'position' => 50,
'notnull' => 1,
'visible' => 0,),
93 'fk_product' => array(
'type' =>
'integer:Product:product/class/product.class.php',
'label' =>
'Product',
'enabled' => 1,
'position' => 50,
'notnull' => 1,
'visible' => 1,),
94 'batch' => array(
'type' =>
'varchar(128)',
'label' =>
'Batch',
'enabled' => 1,
'position' => 1000,
'notnull' => -1,
'visible' => 1,),
95 'pmp' => array(
'type' =>
'double',
'label' =>
'PMP',
'enabled' => 1,
'position' => 50,
'notnull' => 0,
'visible' => 1,),
96 'rang' => array(
'type' =>
'integer',
'label' =>
'Qty',
'enabled' => 1,
'position' => 45,
'notnull' => 0,
'visible' => 0,
'default' =>
'0',
'isameasure' => 1,
'css' =>
'maxwidth75imp',
'help' =>
"Help text for quantity",),
114 public $fk_warehouse_destination;
118 public $fk_warehouse_source;
122 public $fk_stocktransfer;
147 global
$conf, $langs;
151 $this->ismultientitymanaged = 0;
152 $this->isextrafieldmanaged = 1;
155 $this->fields[
'rowid'][
'visible'] = 0;
157 if (!
isModEnabled(
'multicompany') && isset($this->fields[
'entity'])) {
158 $this->fields[
'entity'][
'enabled'] = 0;
168 foreach ($this->fields as $key => $val) {
169 if (isset($val[
'enabled']) && empty($val[
'enabled'])) {
170 unset($this->fields[$key]);
175 if (is_object($langs)) {
176 foreach ($this->fields as $key => $val) {
177 if (isset($val[
'arrayofkeyval']) && is_array($val[
'arrayofkeyval'])) {
178 foreach ($val[
'arrayofkeyval'] as $key2 => $val2) {
179 $this->fields[$key][
'arrayofkeyval'][$key2] = $langs->trans($val2);
207 global $langs, $extrafields;
217 $result =
$object->fetchCommon($fromid);
218 if ($result > 0 && !empty(
$object->table_element_line)) {
232 $object->ref = empty($this->fields[
'ref'][
'default']) ?
"copy_of_".$object->ref : $this->fields[
'ref'][
'default'];
233 $object->label = empty($this->fields[
'label'][
'default']) ? $langs->trans(
"CopyOf").
" ".
$object->label : $this->fields[
'label'][
'default'];
234 $object->status = self::STATUS_DRAFT;
237 if (is_array(
$object->array_options) && count(
$object->array_options) > 0) {
238 $extrafields->fetch_name_optionals_label($this->table_element);
239 foreach (
$object->array_options as $key => $option) {
240 $shortkey = preg_replace(
'/options_/',
'', $key);
241 if (!empty($extrafields->attributes[$this->table_element][
'unique'][$shortkey])) {
242 unset(
$object->array_options[$key]);
248 $object->context[
'createfromclone'] =
'createfromclone';
249 $result =
$object->createCommon($user);
264 if (property_exists($this,
'socid') && $this->socid ==
$object->socid) {
271 unset(
$object->context[
'createfromclone']);
278 $this->db->rollback();
290 public function fetch($id, $ref =
null)
293 if ($result > 0 && !empty($this->table_element_line)) {
306 $this->lines = array();
325 public function fetchAll($sortorder =
'', $sortfield =
'', $limit = 0, $offset = 0, $filter =
'', $filtermode =
'AND')
333 $sql .=
' FROM '.MAIN_DB_PREFIX.$this->table_element.
' as t';
334 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
335 $sql .=
' WHERE t.entity IN ('.getEntity($this->element).
')';
337 $sql .=
' WHERE 1 = 1';
344 $this->errors[] = $errormessage;
345 dol_syslog(__METHOD__.
' '.implode(
',', $this->errors), LOG_ERR);
349 if (!empty($sortfield)) {
350 $sql .= $this->db->order($sortfield, $sortorder);
352 if (!empty($limit)) {
353 $sql .=
' '.$this->db->plimit($limit, $offset);
356 $resql = $this->db->query($sql);
358 $num = $this->db->num_rows($resql);
360 while ($i < ($limit ? min($limit, $num) : $num)) {
361 $obj = $this->db->fetch_object($resql);
363 $record =
new self($this->db);
364 $record->setVarsFromFetchObj($obj);
366 $records[$record->id] = $record;
370 $this->db->free($resql);
374 $this->errors[] =
'Error '.$this->db->lasterror();
375 dol_syslog(__METHOD__.
' '.implode(
',', $this->errors), LOG_ERR);
400 public function delete(
User $user, $notrigger = 0)
417 $this->error =
'ErrorDeleteLineNotAllowedByObjectStatus';
435 global $user, $langs;
437 require_once DOL_DOCUMENT_ROOT .
'/product/class/product.class.php';
438 include_once DOL_DOCUMENT_ROOT .
'/product/stock/class/mouvementstock.class.php';
439 include_once DOL_DOCUMENT_ROOT .
'/product/stock/stocktransfer/class/stocktransfer.class.php';
442 $p->fetch($this->fk_product);
445 $op[0] =
"+".trim((
string) $this->qty);
446 $op[1] =
"-".trim((
string) $this->qty);
449 $movementstock->origin_type = $st->origin_type;
450 $movementstock->origin_id = $this->fk_stocktransfer;
452 if (empty($this->batch)) {
453 $result = $movementstock->_create(
457 (
float) $op[$direction],
459 empty($direction) ? $this->pmp : 0,
469 if ($p->hasbatch()) {
470 $arraybatchinfo = $p->loadBatchInfo($this->batch);
471 if (count($arraybatchinfo) > 0) {
472 $firstrecord = array_shift($arraybatchinfo);
473 $dlc = $firstrecord[
'eatby'];
474 $dluo = $firstrecord[
'sellby'];
480 $result = $movementstock->_create(
484 (
float) $op[$direction],
486 empty($direction) ? $this->pmp : 0,
500 $this->error = $langs->trans(
'StockTransferNoBatchForProduct', $p->getNomUrl());
501 $this->errors[] = $this->error;
518 global
$conf, $langs;
520 require_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
525 if ($this->
status == self::STATUS_VALIDATED) {
526 dol_syslog(get_class($this).
"::validate action abandoned: already validated", LOG_WARNING);
543 if (!$error && (preg_match(
'/^[\(]?PROV/i', $this->
ref) || empty($this->
ref))) {
548 $this->newref = $num;
552 $sql =
"UPDATE ".MAIN_DB_PREFIX.$this->table_element;
553 $sql .=
" SET ref = '".$this->db->escape($num).
"',";
554 $sql .=
" status = ".self::STATUS_VALIDATED;
555 if (!empty($this->fields[
'date_validation'])) {
556 $sql .=
", date_validation = '".$this->db->idate($now).
"',";
558 if (!empty($this->fields[
'fk_user_valid'])) {
559 $sql .=
", fk_user_valid = ".((int) $user->id);
561 $sql .=
" WHERE rowid = ".((int) $this->
id);
563 dol_syslog(get_class($this).
"::validate()", LOG_DEBUG);
564 $resql = $this->db->query($sql);
567 $this->error = $this->db->lasterror();
571 if (!$error && !$notrigger) {
573 $result = $this->call_trigger(
'STOCKTRANSFERLINE_VALIDATE', $user);
582 $this->oldref = $this->ref;
585 if (preg_match(
'/^[\(]?PROV/i', $this->
ref)) {
587 $sql =
'UPDATE '.MAIN_DB_PREFIX.
"ecm_files set filename = CONCAT('".$this->db->escape($this->newref).
"', SUBSTR(filename, ".(strlen($this->
ref) + 1).
")), filepath = 'stocktransferline/".$this->db->escape($this->newref).
"'";
588 $sql .=
" WHERE filename LIKE '".$this->db->escape($this->
ref).
"%' AND filepath = 'stocktransferline/".$this->db->escape($this->
ref).
"' and entity = ".((int)
$conf->entity);
589 $resql = $this->db->query($sql);
592 $this->error = $this->db->lasterror();
594 $sql =
'UPDATE '.MAIN_DB_PREFIX.
"ecm_files set filepath = 'stocktransferline/".$this->db->escape($this->newref).
"'";
595 $sql .=
" WHERE filepath = 'stocktransferline/".$this->db->escape($this->
ref).
"' and entity = ".((int)
$conf->entity);
596 $resql = $this->db->query($sql);
599 $this->error = $this->db->lasterror();
605 $dirsource =
$conf->stocktransfer->dir_output.
'/stocktransferline/'.$oldref;
606 $dirdest =
$conf->stocktransfer->dir_output.
'/stocktransferline/'.$newref;
607 if (!$error && file_exists($dirsource)) {
608 dol_syslog(get_class($this).
"::validate() rename dir ".$dirsource.
" into ".$dirdest);
610 if (@rename($dirsource, $dirdest)) {
613 $listoffiles =
dol_dir_list(
$conf->stocktransfer->dir_output.
'/stocktransferline/'.$newref,
'files', 1,
'^'.preg_quote($oldref,
'/'));
614 foreach ($listoffiles as $fileentry) {
615 $dirsource = $fileentry[
'name'];
616 $dirdest = preg_replace(
'/^'.preg_quote($oldref,
'/').
'/', $newref, $dirsource);
617 $dirsource = $fileentry[
'path'].
'/'.$dirsource;
618 $dirdest = $fileentry[
'path'].
'/'.$dirdest;
619 @rename($dirsource, $dirdest);
629 $this->
status = self::STATUS_VALIDATED;
636 $this->db->rollback();
652 if ($this->
status <= self::STATUS_DRAFT) {
663 return $this->
setStatusCommon($user, self::STATUS_DRAFT, $notrigger,
'STOCKTRANSFERLINE_UNVALIDATE');
673 public function cancel($user, $notrigger = 0)
676 if ($this->
status != self::STATUS_VALIDATED) {
687 return $this->
setStatusCommon($user, self::STATUS_CANCELED, $notrigger,
'STOCKTRANSFERLINE_CLOSE');
697 public function reopen($user, $notrigger = 0)
700 if ($this->
status != self::STATUS_CANCELED) {
711 return $this->
setStatusCommon($user, self::STATUS_VALIDATED, $notrigger,
'STOCKTRANSFERLINE_REOPEN');
724 public function getNomUrl($withpicto = 0, $option =
'', $notooltip = 0, $morecss =
'', $save_lastsearch_value = -1)
726 global
$conf, $langs, $hookmanager;
728 if (!empty(
$conf->dol_no_mouse_hover)) {
734 $label =
'<u>'.$langs->trans(
"StockTransferLine").
'</u>';
736 $label .=
'<b>'.$langs->trans(
'Ref').
':</b> '.$this->ref;
737 if (isset($this->
status)) {
738 $label .=
'<br><b>'.$langs->trans(
"Status").
":</b> ".$this->
getLibStatut(5);
741 $url =
dol_buildpath(
'/stocktransfer/stocktransferline_card.php', 1).
'?id='.$this->id;
743 if ($option !=
'nolink') {
745 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
746 if ($save_lastsearch_value == -1 && isset($_SERVER[
"PHP_SELF"]) && preg_match(
'/list\.php/', $_SERVER[
"PHP_SELF"])) {
747 $add_save_lastsearch_values = 1;
749 if ($add_save_lastsearch_values) {
750 $url .=
'&save_lastsearch_values=1';
755 if (empty($notooltip)) {
757 $label = $langs->trans(
"ShowStockTransferLine");
758 $linkclose .=
' alt="'.dolPrintHTMLForAttribute($label).
'"';
760 $linkclose .=
' title="'.dolPrintHTMLForAttribute($label).
'"';
761 $linkclose .=
' class="classfortooltip'.($morecss ?
' '.$morecss :
'').
'"';
763 $linkclose = ($morecss ?
' class="'.$morecss.
'"' :
'');
766 $linkstart =
'<a href="'.$url.
'"';
767 $linkstart .= $linkclose.
'>';
770 $result .= $linkstart;
772 if (empty($this->showphoto_on_popup)) {
774 $result .=
img_object(($notooltip ?
'' : $label), ($this->picto ? $this->picto :
'generic'), ($notooltip ? (($withpicto != 2) ?
'class="paddingright"' :
'') :
'class="'.(($withpicto != 2) ?
'paddingright ' :
'').
'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
778 require_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
780 list($class, $module) = explode(
'@', $this->picto);
783 $filename = $filearray[0][
'name'];
784 if (!empty($filename)) {
785 $pospoint = strpos($filearray[0][
'name'],
'.');
787 $pathtophoto = $class.
'/'.$this->
ref.
'/thumbs/'.substr($filename, 0, $pospoint).
'_mini'.substr($filename, $pospoint);
789 $result .=
'<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref"><img class="photo'.$module.
'" alt="No photo" border="0" src="'.DOL_URL_ROOT.
'/viewimage.php?modulepart='.$module.
'&entity='.
$conf->entity.
'&file='.urlencode($pathtophoto).
'"></div></div>';
791 $result .=
'<div class="floatleft inline-block valignmiddle divphotoref"><img class="photouserphoto userphoto" alt="No photo" border="0" src="'.DOL_URL_ROOT.
'/viewimage.php?modulepart='.$module.
'&entity='.
$conf->entity.
'&file='.urlencode($pathtophoto).
'"></div>';
796 $result .=
img_object(($notooltip ?
'' : $label), ($this->picto ? $this->picto :
'generic'), ($notooltip ? (($withpicto != 2) ?
'class="paddingright"' :
'') :
'class="'.(($withpicto != 2) ?
'paddingright ' :
'').
'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
801 if ($withpicto != 2) {
802 $result .= $this->ref;
808 global $action, $hookmanager;
809 $hookmanager->initHooks(array(
'stocktransferlinedao'));
810 $parameters = array(
'id' => $this->
id,
'getnomurl' => $result);
811 $reshook = $hookmanager->executeHooks(
'getNomUrl', $parameters, $this, $action);
813 $result = $hookmanager->resPrint;
815 $result .= $hookmanager->resPrint;
843 if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
846 $this->labelStatus[self::STATUS_DRAFT] = $langs->trans(
'Draft');
847 $this->labelStatus[self::STATUS_VALIDATED] = $langs->trans(
'Enabled');
848 $this->labelStatus[self::STATUS_CANCELED] = $langs->trans(
'Disabled');
849 $this->labelStatusShort[self::STATUS_DRAFT] = $langs->trans(
'Draft');
850 $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->trans(
'Enabled');
851 $this->labelStatusShort[self::STATUS_CANCELED] = $langs->trans(
'Disabled');
854 $statusType =
'status'.$status;
856 if ($status == self::STATUS_CANCELED) {
857 $statusType =
'status6';
860 return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status],
'', $statusType, $mode);
871 $sql =
'SELECT rowid, date_creation as datec, tms as datem,';
872 $sql .=
' fk_user_creat, fk_user_modif';
873 $sql .=
' FROM '.MAIN_DB_PREFIX.$this->table_element.
' as t';
874 $sql .=
' WHERE t.rowid = '.((int) $id);
875 $result = $this->db->query($sql);
877 if ($this->db->num_rows($result)) {
878 $obj = $this->db->fetch_object($result);
879 $this->
id = $obj->rowid;
881 $this->user_creation_id = $obj->fk_user_creat;
882 $this->user_modification_id = $obj->fk_user_modif;
883 $this->date_creation = $this->db->jdate($obj->datec);
884 $this->date_modification = empty($obj->datem) ?
'' : $this->db->jdate($obj->datem);
887 $this->db->free($result);
911 global $langs,
$conf;
912 $langs->load(
"stocks");
915 $conf->global->STOCKTRANSFER_STOCKTRANSFERLINE_ADDON =
'mod_stocktransferline_standard';
925 $dirmodels = array_merge(array(
'/'), (array)
$conf->modules_parts[
'models']);
926 foreach ($dirmodels as $reldir) {
930 $mybool = ((bool) @include_once $dir.$file) || $mybool;
938 if (class_exists($classname)) {
939 $obj =
new $classname();
940 '@phan-var-force ModeleNumRefStockTransfer $obj';
941 $numref = $obj->getNextValue($this);
943 if ($numref !=
'' && $numref !=
'-1') {
946 $this->error = $obj->error;
951 print $langs->trans(
"Error").
" ".$langs->trans(
"ClassNotFound").
' '.$classname;
955 print $langs->trans(
"ErrorNumberingModuleNotSetup", $this->element);
971 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams =
null)
973 global
$conf, $langs;
976 $includedocgeneration = 0;
978 $langs->load(
"stocks");
981 $modele =
'standard_stocktransferline';
983 if (!empty($this->model_pdf)) {
984 $modele = $this->model_pdf;
990 $modelpath =
"core/modules/stocktransfer/doc/";
992 if ($includedocgeneration) {
993 $result = $this->
commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
1022 $this->db->commit();
if(! $sortfield) if(! $sortorder) $object
deleteLineCommon(User $user, $idline, $notrigger=0)
Delete a line of object in database.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
setErrorsFromObject($object)
setErrorsFromObject
createCommon(User $user, $notrigger=0)
Create object in the database.
getFieldList($alias='', $excludefields=array())
Function to concat keys of fields.
updateCommon(User $user, $notrigger=0)
Update object into database.
setStatusCommon($user, $status, $notrigger=0, $triggercode='')
Set to a status.
initAsSpecimenCommon()
Initialise object with example values Id must be 0 if object instance is a specimen.
copy_linked_contact($objFrom, $source='internal')
Copy contact from one element to current.
fetchLinesCommon($morewhere='', $noextrafields=0)
Load object in memory from the database.
fetchCommon($id, $ref=null, $morewhere='', $noextrafields=0)
Load object in memory from the database.
deleteCommon(User $user, $notrigger=0, $forcechilddeletion=0)
Delete object in database.
Parent class for class inheritance lines of business objects This class is useless for the moment so ...
Class to manage Dolibarr database access.
Class to manage stock movements.
Class to manage products or services.
Class for StockTransferLine.
reopen($user, $notrigger=0)
Set back to validated status.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
Create a document onto disk according to template module.
getLibStatut($mode=0)
Return label of the status.
setDraft($user, $notrigger=0)
Set draft status.
fetch($id, $ref=null)
Load object in memory from the database.
fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, $filter='', $filtermode='AND')
Load list of objects in memory from the database.
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
__construct(DoliDB $db)
Constructor.
fetchLines()
Load object lines in memory from the database.
validate($user, $notrigger=0)
Validate object.
cancel($user, $notrigger=0)
Set cancel status.
doStockMovement($label, $code_inv, $fk_entrepot, $direction=1)
Makes all stock movements (add quantity, remove quantity or cancel all actions)
doScheduledJob()
Action executed by scheduler CAN BE A CRON TASK.
createFromClone(User $user, $fromid)
Clone an object into another one.
LibStatut($status, $mode=0)
Return the status.
info($id)
Load the info information in the object.
update(User $user, $notrigger=0)
Update object into database.
getNextNumRef()
Returns the reference to the following non used object depending on the active numbering module.
getNomUrl($withpicto=0, $option='', $notooltip=0, $morecss='', $save_lastsearch_value=-1)
Return a link to the object card (with optionally the picto)
create(User $user, $notrigger=0)
Create object into database.
deleteLine(User $user, $idline, $notrigger=0)
Delete a line of object in database.
Class to manage Dolibarr users.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
dol_dir_list($utf8_path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
dol_now($mode='gmt')
Return date for now.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0, $forbiddenfields=array())
forgeSQLFromUniversalSearchCriteria
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string