dolibarr 25.0.0-alpha
myobject.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2017 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2023-2025 Frédéric France <frederic.france@free.fr>
4 * Copyright (C) ---Replace with your own copyright and developer email---
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
26// Put here all includes required by your class file
27require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
28//require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
29//require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
30
35{
39 public $module = 'mymodule';
40
44 public $element = 'myobject';
45
50 public $TRIGGER_PREFIX = 'MYMODULE_MYOBJECT'; // Will be used to build trgiger keys 'MYMODULE_MYOBJECT_MODIFY', ...
51
55 public $table_element = 'mymodule_myobject';
56
60 //public $element_for_permission = 'mymodule';
61
65 public $picto = 'fa-file';
66
70 public $isextrafieldmanaged = 0;
71
76 public $ismultientitymanaged = 0;
77
78
79 const STATUS_DRAFT = 0;
80 const STATUS_VALIDATED = 1;
81 const STATUS_CANCELED = 9;
82
126 // BEGIN MODULEBUILDER PROPERTIES
131 public $fields = array(
132 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'position' => 1, 'notnull' => 1, 'visible' => 0, 'noteditable' => 1, 'index' => 1, 'css' => 'left', 'comment' => 'Id', 'lang' => 'mymodule@mymodule'),
133 'ref' => array('type' => 'varchar(128)', 'label' => 'Ref', 'enabled' => 1, 'position' => 15, 'notnull' => 1, 'visible' => 1, 'index' => 1, 'searchall' => 1, 'showoncombobox' => 1, 'validate' => 1, 'comment' => 'Reference of object', 'lang' => 'mymodule@mymodule'),
134 'entity' => array('type' => 'integer', 'label' => 'Entity', 'default' => '1', 'enabled' => 1, 'visible' => 0, 'notnull' => 1, 'position' => 20, 'index' => 1),
135 'label' => array('type' => 'varchar(255)', 'label' => 'Label', 'enabled' => 1, 'position' => 30, 'notnull' => 0, 'visible' => 1, 'alwayseditable' => 1, 'searchall' => 1, 'css' => 'minwidth300', 'cssview' => 'wordbreak', 'help' => 'Help text', 'showoncombobox' => 2, 'validate' => 1, 'lang' => 'mymodule@mymodule'),
136 'amount' => array('type' => 'price', 'label' => 'Amount', 'enabled' => 1, 'position' => 40, 'notnull' => 0, 'visible' => 1, 'default' => 'null', 'isameasure' => 1, 'help' => 'Help text for amount', 'validate' => 1, 'lang' => 'mymodule@mymodule'),
137 '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', 'validate' => 1, 'lang' => 'mymodule@mymodule'),
138 'fk_soc' => array('type' => 'integer:Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))', 'label' => 'ThirdParty', 'picto' => 'company', 'enabled' => 'isModEnabled("societe")', 'position' => 50, 'notnull' => -1, 'visible' => 1, 'index' => 1, 'css' => 'maxwidth500 widthcentpercentminusxx', 'csslist' => 'tdoverflowmax150', 'help' => 'OrganizationEventLinkToThirdParty', 'validate' => 1, 'lang' => 'mymodule@mymodule'),
139 'fk_project' => array('type' => 'integer:Project:projet/class/project.class.php:1', 'label' => 'Project', 'picto' => 'project', 'enabled' => 'isModEnabled("project")', 'position' => 52, 'notnull' => -1, 'visible' => -1, 'index' => 1, 'css' => 'maxwidth500 widthcentpercentminusxx', 'csslist' => 'tdoverflowmax150', 'validate' => 1, 'lang' => 'mymodule@mymodule'),
140 'description' => array('type' => 'text', 'label' => 'Description', 'enabled' => 1, 'position' => 60, 'notnull' => 0, 'visible' => 3, 'validate' => 1, 'lang' => 'mymodule@mymodule'),
141 'note_public' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'position' => 61, 'notnull' => 0, 'visible' => 0, 'cssview' => 'wordbreak', 'validate' => 1, 'lang' => 'mymodule@mymodule'),
142 'note_private' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'position' => 62, 'notnull' => 0, 'visible' => 0, 'cssview' => 'wordbreak', 'validate' => 1, 'lang' => 'mymodule@mymodule'),
143 'date_creation' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'position' => 500, 'notnull' => 1, 'visible' => -2, 'lang' => 'mymodule@mymodule'),
144 'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'position' => 501, 'notnull' => 0, 'visible' => -2, 'lang' => 'mymodule@mymodule'),
145 'fk_user_creat' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserAuthor', 'picto' => 'user', 'enabled' => 1, 'position' => 510, 'notnull' => 1, 'visible' => -2, 'foreignkey' => '0', 'csslist' => 'tdoverflowmax150', 'lang' => 'mymodule@mymodule'),
146 'fk_user_modif' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'picto' => 'user', 'enabled' => 1, 'position' => 511, 'notnull' => -1, 'visible' => -2, 'csslist' => 'tdoverflowmax150', 'lang' => 'mymodule@mymodule'),
147 'last_main_doc' => array('type' => 'varchar(255)', 'label' => 'LastMainDoc', 'enabled' => 1, 'position' => 600, 'notnull' => 0, 'visible' => 0, 'lang' => 'mymodule@mymodule'),
148 'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'position' => 1000, 'notnull' => -1, 'visible' => -2, 'lang' => 'mymodule@mymodule'),
149 'model_pdf' => array('type' => 'varchar(255)', 'label' => 'Model pdf', 'enabled' => 1, 'position' => 1010, 'notnull' => -1, 'visible' => 0, 'lang' => 'mymodule@mymodule'),
150 'status' => array('type' => 'integer', 'label' => 'Status', 'enabled' => 1, 'position' => 2000, 'notnull' => 1, 'visible' => 1, 'index' => 1, 'arrayofkeyval' => array(0 => 'Draft', '1' => 'Validated', 9 => 'Canceled'), 'validate' => 1, 'lang' => 'mymodule@mymodule'),
151 );
152
156 public $rowid;
157
161 public $ref;
162
166 public $label;
167
171 public $amount;
172
176 public $socid; // both socid and fk_soc are used
180 public $fk_soc; // both socid and fk_soc are used
181
185 public $status;
186
190 public $fk_user_creat;
191
195 public $fk_user_modif;
196
200 public $last_main_doc;
201
205 public $import_key;
206 // END MODULEBUILDER PROPERTIES
207
208 //BEGIN MODULEBUILDER LINES
209 // If this object has a subtable with lines
210
214 public $table_element_line = 'mymodule_myobjectline';
215
219 public $fk_element = 'fk_myobject';
220
224 public $class_element_line = 'MyObjectline';
225
229 protected $childtables = array('mychildtable' => array('name' => 'MyObject', 'fk_element' => 'fk_myobject'));
230
236 protected $childtablesoncascade = array('mymodule_myobjectdet');
237
241 public $lines = array();
242
243 //END MODULEBUILDER LINES
244
250 public function __construct(DoliDB $db)
251 {
252 global $langs;
253
254 $this->db = $db;
255
256 if (!getDolGlobalInt('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid']) && !empty($this->fields['ref'])) {
257 $this->fields['rowid']['visible'] = 0;
258 }
259 if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
260 $this->fields['entity']['enabled'] = 0;
261 }
262
263 // Example to show how to set values of fields definition dynamically
264 /*if ($user->hasRight('mymodule', 'myobject', 'read')) {
265 $this->fields['myfield']['visible'] = 1;
266 $this->fields['myfield']['noteditable'] = 0;
267 }*/
268
269 // Unset fields that are disabled
270 foreach ($this->fields as $key => $val) {
271 if (isset($val['enabled']) && empty($val['enabled'])) {
272 unset($this->fields[$key]);
273 }
274 }
275
276 // Translate some data of arrayofkeyval
277 if (is_object($langs)) {
278 foreach ($this->fields as $key => $val) {
279 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
280 foreach ($val['arrayofkeyval'] as $key2 => $val2) {
281 $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
282 }
283 }
284 }
285 }
286 }
287
295 public function create(User $user, $notrigger = 0)
296 {
297 $result = $this->createCommon($user, $notrigger);
298
299 // uncomment lines below if you want to validate object after creation
300 // if ($result > 0) {
301 // $this->fetch($this->id); // needed to retrieve some fields (ie date_creation for masked ref)
302 // $resultupdate = $this->validate($user, $notrigger);
303 // if ($resultupdate < 0) { return $resultupdate; }
304 // }
305
306 return $result;
307 }
308
316 public function createFromClone(User $user, $fromid)
317 {
318 global $langs, $extrafields;
319 $error = 0;
320
321 dol_syslog(__METHOD__, LOG_DEBUG);
322
323 $object = new self($this->db);
324
325 $this->db->begin();
326
327 // Load source object
328 $result = $object->fetchCommon($fromid);
329 //BEGIN MODULEBUILDER LINES
330 if ($result > 0 && !empty($object->table_element_line)) {
331 $object->fetchLines();
332 }
333
334 // get lines so they will be clone
335 foreach ($this->lines as $line) {
336 $line->fetch_optionals();
337 }
338 //END MODULEBUILDER LINES
339 // Reset some properties
340 unset($object->id);
341 unset($object->fk_user_creat);
342 unset($object->import_key);
343
344 // Clear fields
345 if (property_exists($object, 'ref')) {
346 $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default'];
347 }
348 if (property_exists($object, 'label')) {
349 $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default'];
350 }
351 if (property_exists($object, 'status')) {
352 $object->status = self::STATUS_DRAFT;
353 }
354 if (property_exists($object, 'date_creation')) {
355 $object->date_creation = dol_now();
356 }
357 if (property_exists($object, 'date_modification')) {
358 $object->date_modification = null;
359 }
360 // ...
361 // Clear extrafields that are unique
362 if (is_array($object->array_options) && count($object->array_options) > 0) {
363 $extrafields->fetch_name_optionals_label($this->table_element);
364 foreach ($object->array_options as $key => $option) {
365 $shortkey = preg_replace('/options_/', '', $key);
366 if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) {
367 //var_dump($key);
368 //var_dump($clonedObj->array_options[$key]); exit;
369 unset($object->array_options[$key]);
370 }
371 }
372 }
373
374 // Create clone
375 $object->context['createfromclone'] = 'createfromclone';
376 $result = $object->createCommon($user);
377 if ($result < 0) {
378 $error++;
380 }
381
382 if (!$error) {
383 // copy internal contacts
384 if ($this->copy_linked_contact($object, 'internal') < 0) {
385 $error++;
386 }
387 }
388
389 if (!$error) {
390 // copy external contacts if same company
391 if (!empty($object->socid) && ((property_exists($this, 'fk_soc') && ($this->fk_soc == $object->socid)) || (property_exists($this, 'socid') && ($this->socid == $object->socid)))) { // @phpstan-ignore-line
392 if ($this->copy_linked_contact($object, 'external') < 0) {
393 $error++;
394 }
395 }
396 }
397
398 unset($object->context['createfromclone']);
399
400 // End
401 if (!$error) {
402 $this->db->commit();
403 return $object;
404 } else {
405 $this->db->rollback();
406 return -1;
407 }
408 }
409
419 public function fetch($id, $ref = null, $noextrafields = 0, $nolines = 0)
420 {
421 $result = $this->fetchCommon($id, $ref, '', $noextrafields);
422 //BEGIN MODULEBUILDER LINES
423 if ($result > 0 && !empty($this->table_element_line) && empty($nolines)) {
424 $this->fetchLines($noextrafields);
425 }
426 //END MODULEBUILDER LINES
427 return $result;
428 }
429
436 public function fetchLines($noextrafields = 0)
437 {
438 $this->lines = array();
439
440 $result = $this->fetchLinesCommon('', $noextrafields);
441 return $result;
442 }
443 //END MODULEBUILDER LINES
458 public function fetchAll($sortorder = '', $sortfield = '', $limit = 1000, $offset = 0, string $filter = '', $filtermode = 'AND')
459 {
460 dol_syslog(__METHOD__, LOG_DEBUG);
461
462 $records = array();
463
464 $sql = "SELECT ";
465 $sql .= $this->getFieldList('t');
466 $sql .= " FROM ".$this->db->prefix().$this->table_element." as t";
467 if (!empty($this->isextrafieldmanaged) && $this->isextrafieldmanaged == 1) {
468 $sql .= " LEFT JOIN ".$this->db->prefix().$this->table_element."_extrafields as te ON te.fk_object = t.rowid";
469 }
470 if (!empty($this->ismultientitymanaged) && (int) $this->ismultientitymanaged == 1) {
471 $sql .= " WHERE t.entity IN (".getEntity($this->element).")";
472 } elseif (preg_match('/^\w+@\w+$/', (string) $this->ismultientitymanaged)) {
473 $tmparray = explode('@', (string) $this->ismultientitymanaged);
474 $sql .= " LEFT JOIN ".$this->db->prefix().$this->db->sanitize($tmparray[1])." as pt ON t.".$this->db->sanitize($tmparray[0])." = pt.rowid";
475 $sql .= " WHERE pt.entity IN (".getEntity($this->element).")";
476 } else {
477 $sql .= " WHERE 1 = 1";
478 }
479
480 // Manage filter
481 $errormessage = '';
482 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
483 if ($errormessage) {
484 $this->errors[] = $errormessage;
485 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
486 return -1;
487 }
488
489 if (!empty($sortfield)) {
490 $sql .= $this->db->order($sortfield, $sortorder);
491 }
492 if (!empty($limit)) {
493 $sql .= $this->db->plimit($limit, $offset);
494 }
495
496 $resql = $this->db->query($sql);
497 if ($resql) {
498 $num = $this->db->num_rows($resql);
499 $i = 0;
500 while ($i < ($limit ? min($limit, $num) : $num)) {
501 $obj = $this->db->fetch_object($resql);
502
503 $record = new self($this->db);
504 $record->setVarsFromFetchObj($obj);
505
506 if (!empty($record->isextrafieldmanaged)) {
507 $record->fetch_optionals();
508 }
509
510 $records[$record->id] = $record;
511
512 $i++;
513 }
514 $this->db->free($resql);
515
516 return $records;
517 } else {
518 $this->errors[] = 'Error '.$this->db->lasterror();
519 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
520
521 return -1;
522 }
523 }
524
532 public function update(User $user, $notrigger = 0)
533 {
534 return $this->updateCommon($user, $notrigger);
535 }
536
544 public function delete(User $user, $notrigger = 0)
545 {
546 return $this->deleteCommon($user, $notrigger);
547 //return $this->deleteCommon($user, $notrigger, 1);
548 }
549
550 //BEGIN MODULEBUILDER LINES
559 public function deleteLine(User $user, $idline, $notrigger = 0)
560 {
561 if ($this->status < 0) {
562 $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
563 return -2;
564 }
565
566 return $this->deleteLineCommon($user, $idline, $notrigger);
567 }
568 //END MODULEBUILDER LINES
569
570
578 public function validate($user, $notrigger = 0)
579 {
580 global $conf;
581
582 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
583
584 $error = 0;
585
586 // Protection
587 if ($this->status == self::STATUS_VALIDATED) {
588 dol_syslog(get_class($this)."::validate action abandoned: already validated", LOG_WARNING);
589 return 0;
590 }
591
592 /* if (! ((!getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('mymodule', 'myobject', 'write'))
593 || (getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('mymodule', 'myobject_advance', 'validate')))
594 {
595 $this->error='NotEnoughPermissions';
596 dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
597 return -1;
598 }*/
599
600 $now = dol_now();
601
602 $this->db->begin();
603
604 // Define new ref
605 if (preg_match('/^[\‍(]?PROV/i', $this->ref) || empty($this->ref)) { // empty should not happened, but when it occurs, the test save life
606 $num = $this->getNextNumRef();
607 } else {
608 $num = (string) $this->ref;
609 }
610 $this->newref = $num;
611
612 if (!empty($num)) {
613 // Validate
614 $sql = "UPDATE ".$this->db->prefix().$this->table_element;
615 $sql .= " SET ";
616 if (!empty($this->fields['ref'])) {
617 $sql .= " ref = '".$this->db->escape($num)."',";
618 }
619 $sql .= " status = ".self::STATUS_VALIDATED;
620 if (!empty($this->fields['date_validation'])) {
621 $sql .= ", date_validation = '".$this->db->idate($now)."'";
622 }
623 if (!empty($this->fields['fk_user_valid'])) {
624 $sql .= ", fk_user_valid = ".((int) $user->id);
625 }
626 $sql .= " WHERE rowid = ".((int) $this->id);
627
628 dol_syslog(get_class($this)."::validate()", LOG_DEBUG);
629 $resql = $this->db->query($sql);
630 if (!$resql) {
631 dol_print_error($this->db);
632 $this->error = $this->db->lasterror();
633 $error++;
634 }
635
636 if (!$error && !$notrigger) {
637 // Call trigger
638 $result = $this->call_trigger('MYOBJECT_VALIDATE', $user);
639 if ($result < 0) {
640 $error++;
641 }
642 // End call triggers
643 }
644 }
645
646 if (!$error) {
647 $this->oldref = $this->ref;
648
649 // Rename directory if dir was a temporary ref
650 if (preg_match('/^[\‍(]?PROV/i', $this->ref)) {
651 // Now we rename also files into index
652 $sql = 'UPDATE '.$this->db->prefix()."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'myobject/".$this->db->escape($this->newref)."'";
653 $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'myobject/".$this->db->escape($this->ref)."' and entity = ".((int) $conf->entity);
654 $resql = $this->db->query($sql);
655 if (!$resql) {
656 $error++;
657 $this->error = $this->db->lasterror();
658 }
659 $sql = 'UPDATE '.$this->db->prefix()."ecm_files set filepath = 'myobject/".$this->db->escape($this->newref)."'";
660 $sql .= " WHERE filepath = 'myobject/".$this->db->escape($this->ref)."' and entity = ".((int) $conf->entity);
661 $resql = $this->db->query($sql);
662 if (!$resql) {
663 $error++;
664 $this->error = $this->db->lasterror();
665 }
666
667 // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
668 $oldref = dol_sanitizeFileName($this->ref);
669 $newref = dol_sanitizeFileName($num);
670 $dirsource = $conf->mymodule->dir_output.'/myobject/'.$oldref;
671 $dirdest = $conf->mymodule->dir_output.'/myobject/'.$newref;
672 if (!$error && file_exists($dirsource)) {
673 dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest);
674
675 if (@rename($dirsource, $dirdest)) {
676 dol_syslog("Rename ok");
677 // Rename docs starting with $oldref with $newref
678 $listoffiles = dol_dir_list($conf->mymodule->dir_output.'/myobject/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
679 foreach ($listoffiles as $fileentry) {
680 $dirsource = $fileentry['name'];
681 $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
682 $dirsource = $fileentry['path'].'/'.$dirsource;
683 $dirdest = $fileentry['path'].'/'.$dirdest;
684 @rename($dirsource, $dirdest);
685 }
686 }
687 }
688 }
689 }
690
691 // Set new ref and current status
692 if (!$error) {
693 $this->ref = $num;
694 $this->status = self::STATUS_VALIDATED;
695 }
696
697 if (!$error) {
698 $this->db->commit();
699 return 1;
700 } else {
701 $this->db->rollback();
702 return -1;
703 }
704 }
705
706
714 public function setDraft($user, $notrigger = 0)
715 {
716 // Protection
717 if ($this->status <= self::STATUS_DRAFT) {
718 return 0;
719 }
720
721 /* if (! ((!getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('mymodule','write'))
722 || (getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('mymodule','mymodule_advance','validate'))))
723 {
724 $this->error='Permission denied';
725 return -1;
726 }*/
727
728 return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'MYMODULE_MYOBJECT_UNVALIDATE');
729 }
730
738 public function cancel($user, $notrigger = 0)
739 {
740 // Protection
741 if ($this->status != self::STATUS_VALIDATED) {
742 return 0;
743 }
744
745 /* if (! ((!getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('mymodule','write'))
746 || (getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('mymodule','mymodule_advance','validate'))))
747 {
748 $this->error='Permission denied';
749 return -1;
750 }*/
751
752 return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'MYMODULE_MYOBJECT_CANCEL');
753 }
754
762 public function reopen($user, $notrigger = 0)
763 {
764 // Protection
765 if ($this->status == self::STATUS_VALIDATED) {
766 return 0;
767 }
768
769 /*if (! ((!getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('mymodule','write'))
770 || (getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('mymodule','mymodule_advance','validate'))))
771 {
772 $this->error='Permission denied';
773 return -1;
774 }*/
775
776 return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'MYMODULE_MYOBJECT_REOPEN');
777 }
778
786 public function getTooltipContentArray($params)
787 {
788 global $langs;
789
790 $datas = [];
791
792 if (getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER')) {
793 return ['optimize' => $langs->trans("ShowMyObject")];
794 }
795 $datas['picto'] = img_picto('', $this->picto).' <u>'.$langs->trans("MyObject").'</u>';
796 if (isset($this->status)) {
797 $datas['picto'] .= ' '.$this->getLibStatut(5);
798 }
799 if (property_exists($this, 'ref')) {
800 $datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
801 }
802 if (property_exists($this, 'label')) {
803 $datas['label'] = '<br>'.$langs->trans('Label').':</b> '.$this->label;
804 }
805
806 return $datas;
807 }
808
819 public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
820 {
821 global $conf, $langs, $hookmanager;
822
823 if (!empty($conf->dol_no_mouse_hover)) {
824 $notooltip = 1; // Force disable tooltips
825 }
826
827 $result = '';
828 $params = [
829 'id' => (string) $this->id,
830 'objecttype' => $this->element.($this->module ? '@'.$this->module : ''),
831 'option' => $option,
832 ];
833 $classfortooltip = 'classfortooltip';
834 $dataparams = '';
835 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
836 $classfortooltip = 'classforajaxtooltip';
837 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
838 $label = '';
839 } else {
840 $label = implode($this->getTooltipContentArray($params));
841 }
842
843 $baseurl = dol_buildpath('/mymodule/myobject_card.php', 1);
844 $query = ['id' => $this->id];
845 if ($option !== 'nolink') {
846 // Add param to save lastsearch_values or not
847 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
848 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
849 $add_save_lastsearch_values = 1;
850 }
851 if ($add_save_lastsearch_values) {
852 $query = array_merge($query, ['save_lastsearch_values' => 1]);
853 }
854 }
855 $url = dolBuildUrl($baseurl, $query);
856
857 $linkclose = '';
858 if (empty($notooltip)) {
859 if (getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER')) {
860 $label = $langs->trans("ShowMyObject");
861 $linkclose .= ' alt="'.dolPrintHTMLForAttribute($label).'"';
862 }
863 $linkclose .= ($label ? ' title="'.dolPrintHTMLForAttribute($label).'"' : ' title="tocomplete"');
864 $linkclose .= $dataparams.' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"';
865 } else {
866 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
867 }
868
869 if ($option == 'nolink') {
870 $linkstart = '<span';
871 } else {
872 $linkstart = '<a href="'.$url.'"';
873 }
874 $linkstart .= $linkclose.'>';
875 if ($option == 'nolink') {
876 $linkend = '</span>';
877 } else {
878 $linkend = '</a>';
879 }
880
881 $result .= $linkstart;
882
883 if (empty($this->showphoto_on_popup)) {
884 if ($withpicto) {
885 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), (($withpicto != 2) ? 'class="paddingright"' : ''), 0, 0, $notooltip ? 0 : 1);
886 }
887 } else {
888 if ($withpicto) {
889 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
890
891 list($class, $module) = explode('@', $this->picto);
892 $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref);
893 $filearray = dol_dir_list($upload_dir, "files");
894 $filename = $filearray[0]['name'];
895 if (!empty($filename)) {
896 $pospoint = strpos($filearray[0]['name'], '.');
897
898 $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint);
899 if (!getDolGlobalString(strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS')) {
900 $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>';
901 } else {
902 $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>';
903 }
904
905 $result .= '</div>';
906 } else {
907 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'"'), 0, 0, $notooltip ? 0 : 1);
908 }
909 }
910 }
911
912 if ($withpicto != 2) {
913 $result .= $this->ref;
914 }
915
916 $result .= $linkend;
917 //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
918
919 global $action, $hookmanager;
920 $hookmanager->initHooks(array($this->element.'dao'));
921 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
922 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
923 if ($reshook > 0) {
924 $result = $hookmanager->resPrint;
925 } else {
926 $result .= $hookmanager->resPrint;
927 }
928
929 return $result;
930 }
931
939 public function getKanbanView($option = '', $arraydata = null)
940 {
941 global $conf, $langs;
942
943 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
944
945 $return = '<div class="box-flex-item box-flex-grow-zero">';
946 $return .= '<div class="info-box info-box-sm">';
947 $return .= '<span class="info-box-icon bg-infobox-action">';
948 $return .= img_picto('', $this->picto);
949 $return .= '</span>';
950 $return .= '<div class="info-box-content">';
951 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref).'</span>';
952 if ($selected >= 0) {
953 $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
954 }
955 if (property_exists($this, 'label')) {
956 $return .= ' <div class="inline-block opacitymedium valignmiddle tdoverflowmax100">'.$this->label.'</div>';
957 }
958 if (property_exists($this, 'thirdparty') && is_object($this->thirdparty)) {
959 $return .= '<br><div class="info-box-ref tdoverflowmax150">'.$this->thirdparty->getNomUrl(1).'</div>';
960 }
961 if (property_exists($this, 'amount')) {
962 $return .= '<br>';
963 $return .= '<span class="info-box-label amount">'.price($this->amount, 0, $langs, 1, -1, -1, $conf->currency).'</span>';
964 }
965 if (method_exists($this, 'getLibStatut')) {
966 $return .= '<br><div class="info-box-status">'.$this->getLibStatut(3).'</div>';
967 }
968 $return .= '</div>';
969 $return .= '</div>';
970 $return .= '</div>';
971
972 return $return;
973 }
974
981 public function getLabelStatus($mode = 0)
982 {
983 return $this->LibStatut($this->status, $mode);
984 }
985
992 public function getLibStatut($mode = 0)
993 {
994 return $this->LibStatut($this->status, $mode);
995 }
996
997 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1005 public function LibStatut($status, $mode = 0)
1006 {
1007 // phpcs:enable
1008 if (is_null($status)) {
1009 return '';
1010 }
1011
1012 $paramsBadge = array('badgeParams' => array('attr' => array(
1013 'data-status-element' => $this->element,
1014 'data-status' => (int) $status
1015 )));
1016
1017
1018 if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
1019 global $langs;
1020 //$langs->load("mymodule@mymodule");
1021 $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
1022 $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Enabled');
1023 $this->labelStatus[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Disabled');
1024 $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
1025 $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Enabled');
1026 $this->labelStatusShort[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Disabled');
1027 }
1028
1029 $statusType = 'status'.$status;
1030 //if ($status == self::STATUS_VALIDATED) $statusType = 'status1';
1031 if ($status == self::STATUS_CANCELED) {
1032 $statusType = 'status6';
1033 }
1034
1035 return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode, '', $paramsBadge);
1036 }
1037
1044 public function info($id)
1045 {
1046 $sql = "SELECT t.rowid, t.date_creation as datec";
1047 if (!empty($this->isextrafieldmanaged) && $this->isextrafieldmanaged == 1) {
1048 $sql .= ", GREATEST(t.tms, COALESCE(te.tms, t.tms)) as datem";
1049 } else {
1050 $sql .= ", t.tms as datem";
1051 }
1052 if (!empty($this->fields['date_validation'])) {
1053 $sql .= ", t.date_validation as datev";
1054 }
1055 if (!empty($this->fields['fk_user_creat'])) {
1056 $sql .= ", t.fk_user_creat";
1057 }
1058 if (!empty($this->fields['fk_user_modif'])) {
1059 $sql .= ", t.fk_user_modif";
1060 }
1061 if (!empty($this->fields['fk_user_valid'])) {
1062 $sql .= ", t.fk_user_valid";
1063 }
1064 $sql .= " FROM ".$this->db->prefix().$this->table_element." as t";
1065 if (!empty($this->isextrafieldmanaged) && $this->isextrafieldmanaged == 1) {
1066 $sql .= " LEFT JOIN ".$this->db->prefix().$this->table_element."_extrafields as te ON te.fk_object = t.rowid";
1067 }
1068 $sql .= " WHERE t.rowid = ".((int) $id);
1069
1070 $result = $this->db->query($sql);
1071 if ($result) {
1072 if ($this->db->num_rows($result)) {
1073 $obj = $this->db->fetch_object($result);
1074
1075 $this->id = $obj->rowid;
1076
1077 if (!empty($this->fields['fk_user_creat'])) {
1078 $this->user_creation_id = $obj->fk_user_creat;
1079 }
1080 if (!empty($this->fields['fk_user_modif'])) {
1081 $this->user_modification_id = $obj->fk_user_modif;
1082 }
1083 if (!empty($this->fields['fk_user_valid'])) {
1084 $this->user_validation_id = $obj->fk_user_valid;
1085 }
1086 $this->date_creation = $this->db->jdate($obj->datec);
1087 $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
1088 if (!empty($obj->datev)) {
1089 $this->date_validation = empty($obj->datev) ? '' : $this->db->jdate($obj->datev);
1090 }
1091 }
1092
1093 $this->db->free($result);
1094 } else {
1095 dol_print_error($this->db);
1096 }
1097 }
1098
1105 public function initAsSpecimen()
1106 {
1107 // Set here init that are not commonf fields
1108 // $this->property1 = ...
1109 // $this->property2 = ...
1110
1111 return $this->initAsSpecimenCommon();
1112 }
1113
1114 //BEGIN MODULEBUILDER LINES
1120 public function getLinesArray()
1121 {
1122 $this->lines = array();
1123
1124 $objectline = new MyObjectLine($this->db);
1125 $result = $objectline->fetchAll('ASC', 'position', 0, 0, '(fk_myobject:=:'.((int) $this->id).')');
1126
1127 if (is_numeric($result)) {
1128 $this->setErrorsFromObject($objectline);
1129 return $result;
1130 } else {
1132 $this->lines = $result;
1133 return $this->lines;
1134 }
1135 }
1136 //END MODULEBUILDER LINES
1137
1143 public function getNextNumRef()
1144 {
1145 global $langs, $conf;
1146 $langs->load("mymodule@mymodule");
1147
1148 if (!getDolGlobalString('MYMODULE_MYOBJECT_ADDON')) {
1149 $conf->global->MYMODULE_MYOBJECT_ADDON = 'mod_myobject_standard';
1150 }
1151
1152 if (getDolGlobalString('MYMODULE_MYOBJECT_ADDON')) {
1153 $mybool = false;
1154
1155 $file = getDolGlobalString('MYMODULE_MYOBJECT_ADDON').".php";
1156 $classname = getDolGlobalString('MYMODULE_MYOBJECT_ADDON');
1157
1158 // Include file with class
1159 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1160 foreach ($dirmodels as $reldir) {
1161 $dir = dol_buildpath($reldir."core/modules/mymodule/");
1162
1163 // Load file with numbering class (if found)
1164 $mybool = $mybool || @include_once $dir.$file;
1165 }
1166
1167 if (!$mybool) {
1168 dol_print_error(null, "Failed to include file ".$file);
1169 return '';
1170 }
1171
1172 if (class_exists($classname)) {
1173 $obj = new $classname();
1174 '@phan-var-force ModeleNumRefMyObject $obj';
1175 $numref = $obj->getNextValue($this);
1176
1177 if ($numref != '' && $numref != '-1') {
1178 return $numref;
1179 } else {
1180 $this->error = $obj->error;
1181 //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1182 return "";
1183 }
1184 } else {
1185 print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname;
1186 return "";
1187 }
1188 } else {
1189 print $langs->trans("ErrorNumberingModuleNotSetup", $this->element);
1190 return "";
1191 }
1192 }
1193
1205 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
1206 {
1207 global $langs;
1208
1209 $result = 0;
1210 $includedocgeneration = 0;
1211
1212 $langs->load("mymodule@mymodule");
1213
1214 if (!dol_strlen($modele)) {
1215 if (!empty($this->model_pdf)) {
1216 $modele = $this->model_pdf;
1217 } else {
1218 $modele = getDolGlobalString('MYOBJECT_ADDON_PDF', 'standard_myobject');
1219 }
1220 }
1221
1222 $modelpath = "core/modules/mymodule/doc/";
1223
1224 if ($includedocgeneration && !empty($modele)) {
1225 $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
1226 }
1227
1228 return $result;
1229 }
1230
1240 public function validateField($fields, $fieldKey, $fieldValue)
1241 {
1242 // Add your own validation rules here.
1243 // ...
1244
1245 return parent::validateField($fields, $fieldKey, $fieldValue);
1246 }
1247
1255 public function doScheduledJob()
1256 {
1257 //global $conf, $langs;
1258
1259 //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlogfile.log';
1260
1261 $error = 0;
1262 $this->output = '';
1263 $this->error = '';
1264
1265 dol_syslog(__METHOD__." start", LOG_INFO);
1266
1267 //$now = dol_now();
1268
1269 $this->db->begin();
1270
1271 // ...
1272
1273 $this->db->commit();
1274
1275 dol_syslog(__METHOD__." end", LOG_INFO);
1276
1277 return $error;
1278 }
1279}
1280
1281
1282require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
1283//BEGIN MODULEBUILDER LINES
1288{
1289 // To complete with content of an object MyObjectLine
1290 // We should have a field rowid, fk_myobject and position
1291
1296 public $parent_element = ''; // Example: '' or 'myobject'
1297
1302 public $fk_parent_attribute = ''; // Example: '' or 'fk_myobject'
1303
1307 public $isextrafieldmanaged = 0;
1308
1313 public $ismultientitymanaged = 0;
1314
1315
1321 public function __construct(DoliDB $db)
1322 {
1323 $this->db = $db;
1324 }
1325}
1326//END MODULEBUILDER LINES
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
$object ref
Definition info.php:90
Parent class of all other business classes (invoices, contracts, proposals, orders,...
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 for MyObject.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
Create a document onto disk according to template module.
createFromClone(User $user, $fromid)
Clone an object into another one.
getKanbanView($option='', $arraydata=null)
Return a thumb for kanban views.
getLibStatut($mode=0)
Return the label of the status.
create(User $user, $notrigger=0)
Create object into database.
update(User $user, $notrigger=0)
Update object into database.
getTooltipContentArray($params)
getTooltipContentArray
reopen($user, $notrigger=0)
Set back to validated status.
setDraft($user, $notrigger=0)
Set draft status.
getNomUrl($withpicto=0, $option='', $notooltip=0, $morecss='', $save_lastsearch_value=-1)
Return a link to the object card (with optionally the picto)
LibStatut($status, $mode=0)
Return the label of a given status.
validateField($fields, $fieldKey, $fieldValue)
Return validation test result for a field.
getNextNumRef()
Returns the reference to the following non used object depending on the active numbering module.
fetchAll($sortorder='', $sortfield='', $limit=1000, $offset=0, string $filter='', $filtermode='AND')
Load list of objects in memory from the database.
initAsSpecimen()
Initialize object with example values Id must be 0 if object instance is a specimen.
__construct(DoliDB $db)
Constructor.
deleteLine(User $user, $idline, $notrigger=0)
Delete a line of object in database.
cancel($user, $notrigger=0)
Set cancel status.
fetchLines($noextrafields=0)
Load object lines in memory from the database.
info($id)
Load the info information in the object.
doScheduledJob()
Action executed by scheduler CAN BE A CRON TASK.
fetch($id, $ref=null, $noextrafields=0, $nolines=0)
Load object in memory from the database.
getLabelStatus($mode=0)
Return the label of the status.
validate($user, $notrigger=0)
Validate object.
$fields
'type' field format: 'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortf...
getLinesArray()
Create an array of lines.
Class MyObjectLine.
$parent_element
To overload.
$fk_parent_attribute
To overload.
__construct(DoliDB $db)
Constructor.
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...
Definition index.php:169
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $db
API class for accounts.
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.
Definition files.lib.php:64
dol_now($mode='gmt')
Return date for now.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
dolBuildUrl($url, $params=[], $addtoken=false, $anchor='')
Return path of url.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
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)
forgeSQLFromUniversalSearchCriteria
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
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.
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
buildzip.php
print $langs trans('Date')." left Ref Label right Qty right Price right TotalHT right TotalTTC right right right right right right right right right centpercent right TotalHT right n right VAT right n right TotalVAT right n No sujeto a RE IRPF right TotalLT1 right n right TotalLT2 right n right TotalTTC right n takeposcustomercurrency takeposcustomercurrency takeposcustomercurrency takeposcustomercurrency right TotalTTC takeposcustomercurrency right takeposcustomercurrency n right Paid right PaymentTypeShortLIQ right SELECT p pos_change as p datep as p p num_paiement as f pf amount as amount
Definition receipt.php:489