dolibarr 18.0.6
commonobject.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2006-2015 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2005-2013 Regis Houssin <regis.houssin@inodbox.com>
4 * Copyright (C) 2010-2020 Juanjo Menent <jmenent@2byte.es>
5 * Copyright (C) 2012-2013 Christophe Battarel <christophe.battarel@altairis.fr>
6 * Copyright (C) 2011-2022 Philippe Grand <philippe.grand@atoo-net.com>
7 * Copyright (C) 2012-2015 Marcos García <marcosgdf@gmail.com>
8 * Copyright (C) 2012-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
9 * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
10 * Copyright (C) 2015-2022 Alexandre Spangaro <aspangaro@open-dsi.fr>
11 * Copyright (C) 2016 Bahfir abbes <dolipar@dolipar.org>
12 * Copyright (C) 2017 ATM Consulting <support@atm-consulting.fr>
13 * Copyright (C) 2017-2019 Nicolas ZABOURI <info@inovea-conseil.com>
14 * Copyright (C) 2017 Rui Strecht <rui.strecht@aliartalentos.com>
15 * Copyright (C) 2018-2023 Frédéric France <frederic.france@netlogic.fr>
16 * Copyright (C) 2018 Josep Lluís Amador <joseplluis@lliuretic.cat>
17 * Copyright (C) 2023 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
18 * Copyright (C) 2021 Grégory Blémand <gregory.blemand@atm-consulting.fr>
19 * Copyright (C) 2023 Lenin Rivas <lenin.rivas777@gmail.com>
20 *
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 3 of the License, or
24 * (at your option) any later version.
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License
32 * along with this program. If not, see <https://www.gnu.org/licenses/>.
33 */
34
45abstract class CommonObject
46{
47 const TRIGGER_PREFIX = ''; // to be overriden in child class implementations, i.e. 'BILL', 'TASK', 'PROPAL', etc.
48
52 public $module;
53
57 public $db;
58
62 public $id;
63
67 public $entity;
68
73 public $error;
74
78 public $errorhidden;
79
83 public $errors = array();
84
88 private $validateFieldsErrors = array();
89
93 public $element;
94
98 public $fk_element;
99
104 public $element_for_permission;
105
109 public $table_element;
110
114 public $table_element_line = '';
115
119 public $ismultientitymanaged;
120
124 public $import_key;
125
129 public $array_options = array();
130
134 public $fields = array();
135
139 public $array_languages = null; // Value is array() when load already tried
140
144 public $contacts_ids;
145
149 public $linked_objects;
150
154 public $linkedObjectsIds;
155
159 public $linkedObjects;
160
164 private $linkedObjectsFullLoaded = array();
165
169 public $oldcopy;
173 public $oldref;
174
178 protected $table_ref_field = '';
179
183 public $restrictiononfksoc = 0;
184
185
186 // Following vars are used by some objects only. We keep this property here in CommonObject to be able to provide common method using them.
187
191 public $context = array();
192
196 public $canvas;
197
202 public $project;
203
208 public $fk_project;
209
215 public $projet;
216
222
227 public $contact;
228
233 public $contact_id;
234
239 public $thirdparty;
240
245 public $user;
246
251 public $origin;
252
257 public $origin_id;
258
262 public $ref;
263
267 public $ref_ext;
268
272 public $ref_previous;
273
277 public $ref_next;
278
282 public $newref;
283
288 public $statut;
289
294 public $status;
295
296
301 public $country;
302
307 public $country_id;
308
313 public $country_code;
314
319 public $state;
320
325 public $state_id;
326
331 public $state_code;
332
337 public $region_id;
338
343 public $region_code;
344
349 public $region;
350
351
356 public $barcode_type;
357
362 public $barcode_type_code;
363
368 public $barcode_type_label;
369
374 public $barcode_type_coder;
375
380 public $mode_reglement_id;
381
386 public $cond_reglement_id;
387
391 public $demand_reason_id;
392
397 public $transport_mode_id;
398
404 public $cond_reglement;
405
411 public $fk_delivery_address;
412
417 public $shipping_method_id;
418
423 public $shipping_method;
424
428 public $multicurrency_code;
429
433 public $multicurrency_tx;
434
439 public $model_pdf;
440
446 public $modelpdf;
447
452 public $last_main_doc;
453
459 public $fk_bank;
460
465 public $fk_account;
466
470 public $openid;
471
476 public $note_public;
477
482 public $note_private;
483
488 public $note;
489
494 public $total_ht;
495
500 public $total_tva;
501
506 public $total_localtax1;
507
512 public $total_localtax2;
513
518 public $total_ttc;
519
523 public $lines;
524
529 public $comments = array();
530
534 public $name;
535
539 public $lastname;
540
544 public $firstname;
545
549 public $civility_id;
550
551 // Dates
555 public $date_creation;
556
560 public $date_validation; // Date validation
561
565 public $date_modification; // Date last change (tms field)
570 public $date_update;
571
575 public $date_cloture; // Date closing (tms field)
576
581 public $user_author;
586 public $user_creation;
590 public $user_creation_id;
591
596 public $user_valid;
601 public $user_validation;
605 public $user_validation_id;
609 public $user_closing_id;
610
615 public $user_modification;
619 public $user_modification_id;
620
621
626 public $fk_user_creat;
627
632 public $fk_user_modif;
633
634
635 public $next_prev_filter;
636
640 public $specimen = 0;
641
645 public $sendtoid;
646
650 public $alreadypaid;
651
652
653 public $labelStatus;
654 protected $labelStatusShort;
655
659 public $showphoto_on_popup;
660
664 public $nb = array();
665
669 public $output;
670
674 public $extraparams = array();
675
679 protected $childtables = array();
680
686 protected $childtablesoncascade = array();
687
688
689 // No constructor as it is an abstract class
690
691
702 public static function isExistingObject($element, $id, $ref = '', $ref_ext = '')
703 {
704 global $db, $conf;
705
706 $sql = "SELECT rowid, ref, ref_ext";
707 $sql .= " FROM ".$db->prefix().$element;
708 $sql .= " WHERE entity IN (".getEntity($element).")";
709
710 if ($id > 0) {
711 $sql .= " AND rowid = ".((int) $id);
712 } elseif ($ref) {
713 $sql .= " AND ref = '".$db->escape($ref)."'";
714 } elseif ($ref_ext) {
715 $sql .= " AND ref_ext = '".$db->escape($ref_ext)."'";
716 } else {
717 $error = 'ErrorWrongParameters';
718 dol_print_error(get_class()."::isExistingObject ".$error, LOG_ERR);
719 return -1;
720 }
721 if ($ref || $ref_ext) { // Because the same ref can exists in 2 different entities, we force the current one in priority
722 $sql .= " AND entity = ".((int) $conf->entity);
723 }
724
725 dol_syslog(get_class()."::isExistingObject", LOG_DEBUG);
726 $resql = $db->query($sql);
727 if ($resql) {
728 $num = $db->num_rows($resql);
729 if ($num > 0) {
730 return 1;
731 } else {
732 return 0;
733 }
734 }
735 return -1;
736 }
737
744 public function setErrorsFromObject($object)
745 {
746 if (!empty($object->error)) {
747 $this->error = $object->error;
748 }
749 if (!empty($object->errors)) {
750 $this->errors = array_merge($this->errors, $object->errors);
751 }
752 }
753
761 public function getTooltipContentArray($params)
762 {
763 return [];
764 }
765
773 public function getTooltipContent($params)
774 {
775 global $action, $extrafields, $langs, $hookmanager;
776
777 // If there is too much extrafields, we do not include them into tooltip
778 $MAX_EXTRAFIELDS_TO_SHOW_IN_TOOLTIP = getDolGlobalInt('MAX_EXTRAFIELDS_TO_SHOW_IN_TOOLTIP', 3);
779
780 $datas = $this->getTooltipContentArray($params);
781 $count = 0;
782
783 // Add extrafields
784 if (!empty($extrafields->attributes[$this->table_element]['label'])) {
785 foreach ($extrafields->attributes[$this->table_element]['label'] as $key => $val) {
786 if ($extrafields->attributes[$this->table_element]['type'][$key] == 'separate') {
787 continue;
788 }
789 if ($count >= abs($MAX_EXTRAFIELDS_TO_SHOW_IN_TOOLTIP)) {
790 $datas['more_extrafields'] = '<br>...';
791 break;
792 }
793 $enabled = 1;
794 if ($enabled && isset($extrafields->attributes[$this->table_element]['enabled'][$key])) {
795 $enabled = dol_eval($extrafields->attributes[$this->table_element]['enabled'][$key], 1, 1, '2');
796 }
797 if ($enabled && isset($extrafields->attributes[$this->table_element]['list'][$key])) {
798 $enabled = dol_eval($extrafields->attributes[$this->table_element]['list'][$key], 1, 1, '2');
799 }
800 $perms = 1;
801 if ($perms && isset($extrafields->attributes[$this->table_element]['perms'][$key])) {
802 $perms = dol_eval($extrafields->attributes[$this->table_element]['perms'][$key], 1, 1, '2');
803 }
804 if (empty($enabled)) {
805 continue; // 0 = Never visible field
806 }
807 if (abs($enabled) != 1 && abs($enabled) != 3 && abs($enabled) != 5 && abs($enabled) != 4) {
808 continue; // <> -1 and <> 1 and <> 3 = not visible on forms, only on list <> 4 = not visible at the creation
809 }
810 if (empty($perms)) {
811 continue; // 0 = Not visible
812 }
813 if (!empty($extrafields->attributes[$this->table_element]['langfile'][$key])) {
814 $langs->load($extrafields->attributes[$this->table_element]['langfile'][$key]);
815 }
816 $labelextra = $langs->trans((string) $extrafields->attributes[$this->table_element]['label'][$key]);
817 if ($extrafields->attributes[$this->table_element]['type'][$key] == 'separate') {
818 $datas[$key]= '<br><b><u>'. $labelextra . '</u></b>';
819 } else {
820 $value = (empty($this->array_options['options_' . $key]) ? '' : $this->array_options['options_' . $key]);
821 $datas[$key]= '<br><b>'. $labelextra . ':</b> ' . $extrafields->showOutputField($key, $value, '', $this->table_element);
822 $count++;
823 }
824 }
825 }
826
827 $hookmanager->initHooks(array($this->element . 'dao'));
828 $parameters = array(
829 'tooltipcontentarray' => &$datas,
830 'params' => $params,
831 );
832 // Note that $action and $object may have been modified by some hooks
833 $hookmanager->executeHooks('getTooltipContent', $parameters, $this, $action);
834
835 //var_dump($datas);
836 $label = implode($datas);
837
838 return $label;
839 }
840
841
847 public function errorsToString()
848 {
849 return $this->error.(is_array($this->errors) ? (($this->error != '' ? ', ' : '').join(', ', $this->errors)) : '');
850 }
851
852
859 public function getFormatedCustomerRef($objref)
860 {
861 global $hookmanager;
862
863 $parameters = array('objref'=>$objref);
864 $action = '';
865 $reshook = $hookmanager->executeHooks('getFormatedCustomerRef', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
866 if ($reshook > 0) {
867 return $hookmanager->resArray['objref'];
868 }
869 return $objref.(isset($hookmanager->resArray['objref']) ? $hookmanager->resArray['objref'] : '');
870 }
871
878 public function getFormatedSupplierRef($objref)
879 {
880 global $hookmanager;
881
882 $parameters = array('objref'=>$objref);
883 $action = '';
884 $reshook = $hookmanager->executeHooks('getFormatedSupplierRef', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
885 if ($reshook > 0) {
886 return $hookmanager->resArray['objref'];
887 }
888 return $objref.(isset($hookmanager->resArray['objref']) ? $hookmanager->resArray['objref'] : '');
889 }
890
900 public function getFullAddress($withcountry = 0, $sep = "\n", $withregion = 0, $extralangcode = '')
901 {
902 if ($withcountry && $this->country_id && (empty($this->country_code) || empty($this->country))) {
903 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
904 $tmparray = getCountry($this->country_id, 'all');
905 $this->country_code = $tmparray['code'];
906 $this->country = $tmparray['label'];
907 }
908
909 if ($withregion && $this->state_id && (empty($this->state_code) || empty($this->state) || empty($this->region) || empty($this->region_code))) {
910 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
911 $tmparray = getState($this->state_id, 'all', 0, 1);
912 $this->state_code = $tmparray['code'];
913 $this->state = $tmparray['label'];
914 $this->region_code = $tmparray['region_code'];
915 $this->region = $tmparray['region'];
916 }
917
918 return dol_format_address($this, $withcountry, $sep, '', 0, $extralangcode);
919 }
920
921
930 public function getLastMainDocLink($modulepart, $initsharekey = 0, $relativelink = 0)
931 {
932 global $user, $dolibarr_main_url_root;
933
934 if (empty($this->last_main_doc)) {
935 return ''; // No way to known which document name to use
936 }
937
938 include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
939 $ecmfile = new EcmFiles($this->db);
940 $result = $ecmfile->fetch(0, '', $this->last_main_doc);
941 if ($result < 0) {
942 $this->error = $ecmfile->error;
943 $this->errors = $ecmfile->errors;
944 return -1;
945 }
946
947 if (empty($ecmfile->id)) {
948 // Add entry into index
949 if ($initsharekey) {
950 require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
951
952 // TODO We can't, we dont' have full path of file, only last_main_doc and ->element, so we must first rebuild full path $destfull
953 /*
954 $ecmfile->filepath = $rel_dir;
955 $ecmfile->filename = $filename;
956 $ecmfile->label = md5_file(dol_osencode($destfull)); // hash of file content
957 $ecmfile->fullpath_orig = '';
958 $ecmfile->gen_or_uploaded = 'generated';
959 $ecmfile->description = ''; // indexed content
960 $ecmfile->keywords = ''; // keyword content
961 $ecmfile->share = getRandomPassword(true);
962 $result = $ecmfile->create($user);
963 if ($result < 0)
964 {
965 $this->error = $ecmfile->error;
966 $this->errors = $ecmfile->errors;
967 }
968 */
969 } else {
970 return '';
971 }
972 } elseif (empty($ecmfile->share)) {
973 // Add entry into index
974 if ($initsharekey) {
975 require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
976 $ecmfile->share = getRandomPassword(true);
977 $ecmfile->update($user);
978 } else {
979 return '';
980 }
981 }
982 // Define $urlwithroot
983 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
984 // This is to use external domain name found into config file
985 //if (DOL_URL_ROOT && ! preg_match('/\/$/', $urlwithouturlroot) && ! preg_match('/^\//', DOL_URL_ROOT)) $urlwithroot=$urlwithouturlroot.'/'.DOL_URL_ROOT;
986 //else
987 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT;
988 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
989
990 $forcedownload = 0;
991
992 $paramlink = '';
993 //if (!empty($modulepart)) $paramlink.=($paramlink?'&':'').'modulepart='.$modulepart; // For sharing with hash (so public files), modulepart is not required.
994 //if (!empty($ecmfile->entity)) $paramlink.='&entity='.$ecmfile->entity; // For sharing with hash (so public files), entity is not required.
995 //$paramlink.=($paramlink?'&':'').'file='.urlencode($filepath); // No need of name of file for public link, we will use the hash
996 if (!empty($ecmfile->share)) {
997 $paramlink .= ($paramlink ? '&' : '').'hashp='.$ecmfile->share; // Hash for public share
998 }
999 if ($forcedownload) {
1000 $paramlink .= ($paramlink ? '&' : '').'attachment=1';
1001 }
1002
1003 if ($relativelink) {
1004 $linktoreturn = 'document.php'.($paramlink ? '?'.$paramlink : '');
1005 } else {
1006 $linktoreturn = $urlwithroot.'/document.php'.($paramlink ? '?'.$paramlink : '');
1007 }
1008
1009 // Here $ecmfile->share is defined
1010 return $linktoreturn;
1011 }
1012
1013
1014 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1024 public function add_contact($fk_socpeople, $type_contact, $source = 'external', $notrigger = 0)
1025 {
1026 // phpcs:enable
1027 global $user, $langs;
1028
1029
1030 dol_syslog(get_class($this)."::add_contact $fk_socpeople, $type_contact, $source, $notrigger");
1031
1032 // Check parameters
1033 if ($fk_socpeople <= 0) {
1034 $langs->load("errors");
1035 $this->error = $langs->trans("ErrorWrongValueForParameterX", "1");
1036 dol_syslog(get_class($this)."::add_contact ".$this->error, LOG_ERR);
1037 return -1;
1038 }
1039 if (!$type_contact) {
1040 $langs->load("errors");
1041 $this->error = $langs->trans("ErrorWrongValueForParameterX", "2");
1042 dol_syslog(get_class($this)."::add_contact ".$this->error, LOG_ERR);
1043 return -2;
1044 }
1045
1046 $id_type_contact = 0;
1047 if (is_numeric($type_contact)) {
1048 $id_type_contact = $type_contact;
1049 } else {
1050 // We look for id type_contact
1051 $sql = "SELECT tc.rowid";
1052 $sql .= " FROM ".$this->db->prefix()."c_type_contact as tc";
1053 $sql .= " WHERE tc.element='".$this->db->escape($this->element)."'";
1054 $sql .= " AND tc.source='".$this->db->escape($source)."'";
1055 $sql .= " AND tc.code='".$this->db->escape($type_contact)."' AND tc.active=1";
1056 //print $sql;
1057 $resql = $this->db->query($sql);
1058 if ($resql) {
1059 $obj = $this->db->fetch_object($resql);
1060 if ($obj) {
1061 $id_type_contact = $obj->rowid;
1062 }
1063 }
1064 }
1065
1066 if ($id_type_contact == 0) {
1067 dol_syslog("CODE_NOT_VALID_FOR_THIS_ELEMENT: Code type of contact '".$type_contact."' does not exists or is not active for element ".$this->element.", we can ignore it");
1068 return 0;
1069 }
1070
1071 $datecreate = dol_now();
1072
1073 // Socpeople must have already been added by some trigger, then we have to check it to avoid DB_ERROR_RECORD_ALREADY_EXISTS error
1074 $TListeContacts = $this->liste_contact(-1, $source);
1075 $already_added = false;
1076 if (is_array($TListeContacts) && !empty($TListeContacts)) {
1077 foreach ($TListeContacts as $array_contact) {
1078 if ($array_contact['status'] == 4 && $array_contact['id'] == $fk_socpeople && $array_contact['fk_c_type_contact'] == $id_type_contact) {
1079 $already_added = true;
1080 break;
1081 }
1082 }
1083 }
1084
1085 if (!$already_added) {
1086 $this->db->begin();
1087
1088 // Insert into database
1089 $sql = "INSERT INTO ".$this->db->prefix()."element_contact";
1090 $sql .= " (element_id, fk_socpeople, datecreate, statut, fk_c_type_contact) ";
1091 $sql .= " VALUES (".$this->id.", ".((int) $fk_socpeople)." , ";
1092 $sql .= "'".$this->db->idate($datecreate)."'";
1093 $sql .= ", 4, ".((int) $id_type_contact);
1094 $sql .= ")";
1095
1096 $resql = $this->db->query($sql);
1097 if ($resql) {
1098 if (!$notrigger) {
1099 $result = $this->call_trigger(strtoupper($this->element).'_ADD_CONTACT', $user);
1100 if ($result < 0) {
1101 $this->db->rollback();
1102 return -1;
1103 }
1104 }
1105
1106 $this->db->commit();
1107 return 1;
1108 } else {
1109 if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
1110 $this->error = $this->db->errno();
1111 $this->db->rollback();
1112 return -2;
1113 } else {
1114 $this->error = $this->db->lasterror();
1115 $this->db->rollback();
1116 return -1;
1117 }
1118 }
1119 } else {
1120 return 0;
1121 }
1122 }
1123
1124 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1132 public function copy_linked_contact($objFrom, $source = 'internal')
1133 {
1134 // phpcs:enable
1135 $contacts = $objFrom->liste_contact(-1, $source);
1136 foreach ($contacts as $contact) {
1137 if ($this->add_contact($contact['id'], $contact['fk_c_type_contact'], $contact['source']) < 0) {
1138 return -1;
1139 }
1140 }
1141 return 1;
1142 }
1143
1144 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1154 public function update_contact($rowid, $statut, $type_contact_id = 0, $fk_socpeople = 0)
1155 {
1156 // phpcs:enable
1157 // Insert into database
1158 $sql = "UPDATE ".$this->db->prefix()."element_contact set";
1159 $sql .= " statut = ".$statut;
1160 if ($type_contact_id) {
1161 $sql .= ", fk_c_type_contact = ".((int) $type_contact_id);
1162 }
1163 if ($fk_socpeople) {
1164 $sql .= ", fk_socpeople = ".((int) $fk_socpeople);
1165 }
1166 $sql .= " where rowid = ".((int) $rowid);
1167 $resql = $this->db->query($sql);
1168 if ($resql) {
1169 return 0;
1170 } else {
1171 $this->error = $this->db->lasterror();
1172 return -1;
1173 }
1174 }
1175
1176 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1184 public function delete_contact($rowid, $notrigger = 0)
1185 {
1186 // phpcs:enable
1187 global $user;
1188
1189 $error = 0;
1190
1191 $this->db->begin();
1192
1193 if (!$error && empty($notrigger)) {
1194 // Call trigger
1195 $this->context['contact_id'] = ((int) $rowid);
1196 $result = $this->call_trigger(strtoupper($this->element).'_DELETE_CONTACT', $user);
1197 if ($result < 0) {
1198 $error++;
1199 }
1200 // End call triggers
1201 }
1202
1203 if (!$error) {
1204 dol_syslog(get_class($this)."::delete_contact", LOG_DEBUG);
1205
1206 $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_contact";
1207 $sql .= " WHERE rowid = ".((int) $rowid);
1208
1209 $result = $this->db->query($sql);
1210 if (!$result) {
1211 $error++;
1212 $this->errors[] = $this->db->lasterror();
1213 }
1214 }
1215
1216 if (!$error) {
1217 $this->db->commit();
1218 return 1;
1219 } else {
1220 $this->error = $this->db->lasterror();
1221 $this->db->rollback();
1222 return -1;
1223 }
1224 }
1225
1226 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1234 public function delete_linked_contact($source = '', $code = '')
1235 {
1236 // phpcs:enable
1237 $listId = '';
1238 $temp = array();
1239 $typeContact = $this->liste_type_contact($source, '', 0, 0, $code);
1240
1241 if (!empty($typeContact)) {
1242 foreach ($typeContact as $key => $value) {
1243 array_push($temp, $key);
1244 }
1245 $listId = implode(",", $temp);
1246 }
1247
1248 // If $listId is empty, we have not criteria on fk_c_type_contact so we will delete record on element_id for
1249 // any type or record instead of only the ones of the current object. So we do nothing in such a case.
1250 if (empty($listId)) {
1251 return 0;
1252 }
1253
1254 $sql = "DELETE FROM ".$this->db->prefix()."element_contact";
1255 $sql .= " WHERE element_id = ".((int) $this->id);
1256 $sql .= " AND fk_c_type_contact IN (".$this->db->sanitize($listId).")";
1257
1258 dol_syslog(get_class($this)."::delete_linked_contact", LOG_DEBUG);
1259 if ($this->db->query($sql)) {
1260 return 1;
1261 } else {
1262 $this->error = $this->db->lasterror();
1263 return -1;
1264 }
1265 }
1266
1267 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1279 public function liste_contact($statusoflink = -1, $source = 'external', $list = 0, $code = '', $status = -1, $arrayoftcids = array())
1280 {
1281 // phpcs:enable
1282 global $langs;
1283
1284 $tab = array();
1285
1286 $sql = "SELECT ec.rowid, ec.statut as statuslink, ec.fk_socpeople as id, ec.fk_c_type_contact"; // This field contains id of llx_socpeople or id of llx_user
1287 if ($source == 'internal') {
1288 $sql .= ", '-1' as socid, t.statut as statuscontact, t.login, t.photo";
1289 }
1290 if ($source == 'external' || $source == 'thirdparty') {
1291 $sql .= ", t.fk_soc as socid, t.statut as statuscontact";
1292 }
1293 $sql .= ", t.civility as civility, t.lastname as lastname, t.firstname, t.email";
1294 $sql .= ", tc.source, tc.element, tc.code, tc.libelle";
1295 $sql .= " FROM ".$this->db->prefix()."c_type_contact tc,";
1296 $sql .= " ".$this->db->prefix()."element_contact ec";
1297 if ($source == 'internal') { // internal contact (user)
1298 $sql .= " LEFT JOIN ".$this->db->prefix()."user t on ec.fk_socpeople = t.rowid";
1299 }
1300 if ($source == 'external' || $source == 'thirdparty') { // external contact (socpeople)
1301 $sql .= " LEFT JOIN ".$this->db->prefix()."socpeople t on ec.fk_socpeople = t.rowid";
1302 }
1303 $sql .= " WHERE ec.element_id = ".((int) $this->id);
1304 $sql .= " AND ec.fk_c_type_contact = tc.rowid";
1305 $sql .= " AND tc.element = '".$this->db->escape($this->element)."'";
1306 if ($code) {
1307 $sql .= " AND tc.code = '".$this->db->escape($code)."'";
1308 }
1309 if ($source == 'internal') {
1310 $sql .= " AND tc.source = 'internal'";
1311 if ($status >= 0) {
1312 $sql .= " AND t.statut = ".((int) $status);
1313 }
1314 }
1315 if ($source == 'external' || $source == 'thirdparty') {
1316 $sql .= " AND tc.source = 'external'";
1317 if ($status >= 0) {
1318 $sql .= " AND t.statut = ".((int) $status); // t is llx_socpeople
1319 }
1320 }
1321 $sql .= " AND tc.active = 1";
1322 if ($statusoflink >= 0) {
1323 $sql .= " AND ec.statut = ".((int) $statusoflink);
1324 }
1325 $sql .= " ORDER BY t.lastname ASC";
1326
1327 dol_syslog(get_class($this)."::liste_contact", LOG_DEBUG);
1328 $resql = $this->db->query($sql);
1329 if ($resql) {
1330 $num = $this->db->num_rows($resql);
1331 $i = 0;
1332 while ($i < $num) {
1333 $obj = $this->db->fetch_object($resql);
1334
1335 if (!$list) {
1336 $transkey = "TypeContact_".$obj->element."_".$obj->source."_".$obj->code;
1337 $libelle_type = ($langs->trans($transkey) != $transkey ? $langs->trans($transkey) : $obj->libelle);
1338 $tab[$i] = array(
1339 'parentId' => $this->id,
1340 'source' => $obj->source,
1341 'socid' => $obj->socid,
1342 'id' => $obj->id,
1343 'nom' => $obj->lastname, // For backward compatibility
1344 'civility' => $obj->civility,
1345 'lastname' => $obj->lastname,
1346 'firstname' => $obj->firstname,
1347 'email'=>$obj->email,
1348 'login'=> (empty($obj->login) ? '' : $obj->login),
1349 'photo' => (empty($obj->photo) ? '' : $obj->photo),
1350 'statuscontact' => $obj->statuscontact,
1351 'rowid' => $obj->rowid,
1352 'code' => $obj->code,
1353 'libelle' => $libelle_type,
1354 'status' => $obj->statuslink,
1355 'fk_c_type_contact' => $obj->fk_c_type_contact
1356 );
1357 } else {
1358 $tab[$i] = $obj->id;
1359 }
1360
1361 $i++;
1362 }
1363
1364 return $tab;
1365 } else {
1366 $this->error = $this->db->lasterror();
1367 dol_print_error($this->db);
1368 return -1;
1369 }
1370 }
1371
1372
1379 public function swapContactStatus($rowid)
1380 {
1381 $sql = "SELECT ec.datecreate, ec.statut, ec.fk_socpeople, ec.fk_c_type_contact,";
1382 $sql .= " tc.code, tc.libelle";
1383 $sql .= " FROM (".$this->db->prefix()."element_contact as ec, ".$this->db->prefix()."c_type_contact as tc)";
1384 $sql .= " WHERE ec.rowid =".((int) $rowid);
1385 $sql .= " AND ec.fk_c_type_contact=tc.rowid";
1386 $sql .= " AND tc.element = '".$this->db->escape($this->element)."'";
1387
1388 dol_syslog(get_class($this)."::swapContactStatus", LOG_DEBUG);
1389 $resql = $this->db->query($sql);
1390 if ($resql) {
1391 $obj = $this->db->fetch_object($resql);
1392 $newstatut = ($obj->statut == 4) ? 5 : 4;
1393 $result = $this->update_contact($rowid, $newstatut);
1394 $this->db->free($resql);
1395 return $result;
1396 } else {
1397 $this->error = $this->db->error();
1398 dol_print_error($this->db);
1399 return -1;
1400 }
1401 }
1402
1403 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1414 public function liste_type_contact($source = 'internal', $order = 'position', $option = 0, $activeonly = 0, $code = '')
1415 {
1416 // phpcs:enable
1417 global $langs;
1418
1419 if (empty($order)) {
1420 $order = 'position';
1421 }
1422 if ($order == 'position') {
1423 $order .= ',code';
1424 }
1425
1426 $tab = array();
1427 $sql = "SELECT DISTINCT tc.rowid, tc.code, tc.libelle, tc.position";
1428 $sql .= " FROM ".$this->db->prefix()."c_type_contact as tc";
1429 $sql .= " WHERE tc.element='".$this->db->escape($this->element)."'";
1430 if ($activeonly == 1) {
1431 $sql .= " AND tc.active=1"; // only the active types
1432 }
1433 if (!empty($source) && $source != 'all') {
1434 $sql .= " AND tc.source='".$this->db->escape($source)."'";
1435 }
1436 if (!empty($code)) {
1437 $sql .= " AND tc.code='".$this->db->escape($code)."'";
1438 }
1439 $sql .= $this->db->order($order, 'ASC');
1440
1441 //print "sql=".$sql;
1442 $resql = $this->db->query($sql);
1443 if ($resql) {
1444 $num = $this->db->num_rows($resql);
1445 $i = 0;
1446 while ($i < $num) {
1447 $obj = $this->db->fetch_object($resql);
1448
1449 $transkey = "TypeContact_".$this->element."_".$source."_".$obj->code;
1450 $libelle_type = ($langs->trans($transkey) != $transkey ? $langs->trans($transkey) : $obj->libelle);
1451 if (empty($option)) {
1452 $tab[$obj->rowid] = $libelle_type;
1453 } else {
1454 $tab[$obj->code] = $libelle_type;
1455 }
1456 $i++;
1457 }
1458 return $tab;
1459 } else {
1460 $this->error = $this->db->lasterror();
1461 //dol_print_error($this->db);
1462 return null;
1463 }
1464 }
1465
1477 public function listeTypeContacts($source = 'internal', $option = 0, $activeonly = 0, $code = '', $element = '', $excludeelement = '')
1478 {
1479 global $langs, $conf;
1480
1481 $langs->loadLangs(array('bills', 'contracts', 'interventions', 'orders', 'projects', 'propal', 'ticket', 'agenda'));
1482
1483 $tab = array();
1484
1485 $sql = "SELECT DISTINCT tc.rowid, tc.code, tc.libelle, tc.position, tc.element";
1486 $sql .= " FROM ".$this->db->prefix()."c_type_contact as tc";
1487
1488 $sqlWhere = array();
1489 if (!empty($element)) {
1490 $sqlWhere[] = " tc.element='".$this->db->escape($element)."'";
1491 }
1492 if (!empty($excludeelement)) {
1493 $sqlWhere[] = " tc.element <> '".$this->db->escape($excludeelement)."'";
1494 }
1495
1496 if ($activeonly == 1) {
1497 $sqlWhere[] = " tc.active=1"; // only the active types
1498 }
1499
1500 if (!empty($source) && $source != 'all') {
1501 $sqlWhere[] = " tc.source='".$this->db->escape($source)."'";
1502 }
1503
1504 if (!empty($code)) {
1505 $sqlWhere[] = " tc.code='".$this->db->escape($code)."'";
1506 }
1507
1508 if (count($sqlWhere) > 0) {
1509 $sql .= " WHERE ".implode(' AND ', $sqlWhere);
1510 }
1511
1512 $sql .= $this->db->order('tc.element, tc.position', 'ASC');
1513
1514 dol_syslog(__METHOD__, LOG_DEBUG);
1515 $resql = $this->db->query($sql);
1516 if ($resql) {
1517 $num = $this->db->num_rows($resql);
1518 if ($num > 0) {
1519 $langs->loadLangs(array("propal", "orders", "bills", "suppliers", "contracts", "supplier_proposal"));
1520
1521 while ($obj = $this->db->fetch_object($resql)) {
1522 $modulename = $obj->element;
1523 if (strpos($obj->element, 'project') !== false) {
1524 $modulename = 'projet';
1525 } elseif ($obj->element == 'contrat') {
1526 $element = 'contract';
1527 } elseif ($obj->element == 'action') {
1528 $modulename = 'agenda';
1529 } elseif (strpos($obj->element, 'supplier') !== false && $obj->element != 'supplier_proposal') {
1530 $modulename = 'fournisseur';
1531 } elseif (strpos($obj->element, 'supplier') !== false && $obj->element != 'supplier_proposal') {
1532 $modulename = 'fournisseur';
1533 }
1534 if (!empty($conf->{$modulename}->enabled)) {
1535 $libelle_element = $langs->trans('ContactDefault_'.$obj->element);
1536 $tmpelement = $obj->element;
1537 $transkey = "TypeContact_".$tmpelement."_".$source."_".$obj->code;
1538 $libelle_type = ($langs->trans($transkey) != $transkey ? $langs->trans($transkey) : $obj->libelle);
1539 if (empty($option)) {
1540 $tab[$obj->rowid] = $libelle_element.' - '.$libelle_type;
1541 } else {
1542 $tab[$obj->rowid] = $libelle_element.' - '.$libelle_type;
1543 }
1544 }
1545 }
1546 }
1547 return $tab;
1548 } else {
1549 $this->error = $this->db->lasterror();
1550 return null;
1551 }
1552 }
1553
1565 public function getIdContact($source, $code, $status = 0)
1566 {
1567 global $conf;
1568
1569 $result = array();
1570 $i = 0;
1571 //cas particulier pour les expeditions
1572 if ($this->element == 'shipping' && $this->origin_id != 0) {
1573 $id = $this->origin_id;
1574 $element = 'commande';
1575 } elseif ($this->element == 'reception' && $this->origin_id != 0) {
1576 $id = $this->origin_id;
1577 $element = 'order_supplier';
1578 } else {
1579 $id = $this->id;
1580 $element = $this->element;
1581 }
1582
1583 $sql = "SELECT ec.fk_socpeople";
1584 $sql .= " FROM ".$this->db->prefix()."element_contact as ec,";
1585 if ($source == 'internal') {
1586 $sql .= " ".$this->db->prefix()."user as c,";
1587 }
1588 if ($source == 'external') {
1589 $sql .= " ".$this->db->prefix()."socpeople as c,";
1590 }
1591 $sql .= " ".$this->db->prefix()."c_type_contact as tc";
1592 $sql .= " WHERE ec.element_id = ".((int) $id);
1593 $sql .= " AND ec.fk_socpeople = c.rowid";
1594 if ($source == 'internal') {
1595 $sql .= " AND c.entity IN (".getEntity('user').")";
1596 }
1597 if ($source == 'external') {
1598 $sql .= " AND c.entity IN (".getEntity('societe').")";
1599 }
1600 $sql .= " AND ec.fk_c_type_contact = tc.rowid";
1601 $sql .= " AND tc.element = '".$this->db->escape($element)."'";
1602 $sql .= " AND tc.source = '".$this->db->escape($source)."'";
1603 if ($code) {
1604 $sql .= " AND tc.code = '".$this->db->escape($code)."'";
1605 }
1606 $sql .= " AND tc.active = 1";
1607 if ($status) {
1608 $sql .= " AND ec.statut = ".((int) $status);
1609 }
1610
1611 dol_syslog(get_class($this)."::getIdContact", LOG_DEBUG);
1612 $resql = $this->db->query($sql);
1613 if ($resql) {
1614 while ($obj = $this->db->fetch_object($resql)) {
1615 $result[$i] = $obj->fk_socpeople;
1616 $i++;
1617 }
1618 } else {
1619 $this->error = $this->db->error();
1620 return null;
1621 }
1622
1623 return $result;
1624 }
1625
1626 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1633 public function fetch_contact($contactid = null)
1634 {
1635 // phpcs:enable
1636 if (empty($contactid)) {
1637 $contactid = $this->contact_id;
1638 }
1639
1640 if (empty($contactid)) {
1641 return 0;
1642 }
1643
1644 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1645 $contact = new Contact($this->db);
1646 $result = $contact->fetch($contactid);
1647 $this->contact = $contact;
1648 return $result;
1649 }
1650
1651 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1658 public function fetch_thirdparty($force_thirdparty_id = 0)
1659 {
1660 // phpcs:enable
1661 global $conf;
1662
1663 if (empty($this->socid) && empty($this->fk_soc) && empty($force_thirdparty_id)) {
1664 return 0;
1665 }
1666
1667 require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
1668
1669 $idtofetch = isset($this->socid) ? $this->socid : (isset($this->fk_soc) ? $this->fk_soc : 0);
1670 if ($force_thirdparty_id) {
1671 $idtofetch = $force_thirdparty_id;
1672 }
1673
1674 if ($idtofetch) {
1675 $thirdparty = new Societe($this->db);
1676 $result = $thirdparty->fetch($idtofetch);
1677 if ($result<0) {
1678 $this->errors=array_merge($this->errors, $thirdparty->errors);
1679 }
1680 $this->thirdparty = $thirdparty;
1681
1682 // Use first price level if level not defined for third party
1683 if (!empty($conf->global->PRODUIT_MULTIPRICES) && empty($this->thirdparty->price_level)) {
1684 $this->thirdparty->price_level = 1;
1685 }
1686
1687 return $result;
1688 } else {
1689 return -1;
1690 }
1691 }
1692
1693
1701 public function fetchOneLike($ref)
1702 {
1703 if (!$this->table_ref_field) {
1704 return 0;
1705 }
1706
1707 $sql = "SELECT rowid FROM ".$this->db->prefix().$this->table_element." WHERE ".$this->table_ref_field." LIKE '".$this->db->escape($ref)."' LIMIT 1";
1708
1709 $query = $this->db->query($sql);
1710
1711 if (!$this->db->num_rows($query)) {
1712 return 0;
1713 }
1714
1715 $result = $this->db->fetch_object($query);
1716
1717 return $this->fetch($result->rowid);
1718 }
1719
1720 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1728 public function fetch_barcode()
1729 {
1730 // phpcs:enable
1731 global $conf;
1732
1733 dol_syslog(get_class($this).'::fetch_barcode this->element='.$this->element.' this->barcode_type='.$this->barcode_type);
1734
1735 $idtype = $this->barcode_type;
1736 if (empty($idtype) && $idtype != '0') { // If type of barcode no set, we try to guess. If set to '0' it means we forced to have type remain not defined
1737 if ($this->element == 'product' && !empty($conf->global->PRODUIT_DEFAULT_BARCODE_TYPE)) {
1738 $idtype = $conf->global->PRODUIT_DEFAULT_BARCODE_TYPE;
1739 } elseif ($this->element == 'societe') {
1740 $idtype = $conf->global->GENBARCODE_BARCODETYPE_THIRDPARTY;
1741 } else {
1742 dol_syslog('Call fetch_barcode with barcode_type not defined and cant be guessed', LOG_WARNING);
1743 }
1744 }
1745
1746 if ($idtype > 0) {
1747 if (empty($this->barcode_type) || empty($this->barcode_type_code) || empty($this->barcode_type_label) || empty($this->barcode_type_coder)) { // If data not already loaded
1748 $sql = "SELECT rowid, code, libelle as label, coder";
1749 $sql .= " FROM ".$this->db->prefix()."c_barcode_type";
1750 $sql .= " WHERE rowid = ".((int) $idtype);
1751 dol_syslog(get_class($this).'::fetch_barcode', LOG_DEBUG);
1752 $resql = $this->db->query($sql);
1753 if ($resql) {
1754 $obj = $this->db->fetch_object($resql);
1755 $this->barcode_type = $obj->rowid;
1756 $this->barcode_type_code = $obj->code;
1757 $this->barcode_type_label = $obj->label;
1758 $this->barcode_type_coder = $obj->coder;
1759 return 1;
1760 } else {
1761 dol_print_error($this->db);
1762 return -1;
1763 }
1764 }
1765 }
1766 return 0;
1767 }
1768
1769 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1775 public function fetch_project()
1776 {
1777 // phpcs:enable
1778 return $this->fetch_projet();
1779 }
1780
1781 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1787 public function fetch_projet()
1788 {
1789 // phpcs:enable
1790 include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
1791
1792 if (empty($this->fk_project) && !empty($this->fk_projet)) {
1793 $this->fk_project = $this->fk_projet; // For backward compatibility
1794 }
1795 if (empty($this->fk_project)) {
1796 return 0;
1797 }
1798
1799 $project = new Project($this->db);
1800 $result = $project->fetch($this->fk_project);
1801
1802 $this->projet = $project; // deprecated
1803 $this->project = $project;
1804 return $result;
1805 }
1806
1807 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1813 public function fetch_product()
1814 {
1815 // phpcs:enable
1816 include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
1817
1818 if (empty($this->fk_product)) {
1819 return 0;
1820 }
1821
1822 $product = new Product($this->db);
1823 $result = $product->fetch($this->fk_product);
1824
1825 $this->product = $product;
1826 return $result;
1827 }
1828
1829 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1836 public function fetch_user($userid)
1837 {
1838 // phpcs:enable
1839 $user = new User($this->db);
1840 $result = $user->fetch($userid);
1841 $this->user = $user;
1842 return $result;
1843 }
1844
1845 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1851 public function fetch_origin()
1852 {
1853 // phpcs:enable
1854 if ($this->origin == 'shipping') {
1855 $this->origin = 'expedition';
1856 }
1857 if ($this->origin == 'delivery') {
1858 $this->origin = 'livraison';
1859 }
1860 if ($this->origin == 'order_supplier') {
1861 $this->origin = 'commandeFournisseur';
1862 }
1863
1864 $origin = $this->origin;
1865
1866 $classname = ucfirst($origin);
1867 $this->$origin = new $classname($this->db);
1868 $this->$origin->fetch($this->origin_id);
1869 }
1870
1880 public function fetchObjectFrom($table, $field, $key, $element = null)
1881 {
1882 global $conf;
1883
1884 $result = false;
1885
1886 $sql = "SELECT rowid FROM ".$this->db->prefix().$table;
1887 $sql .= " WHERE ".$field." = '".$this->db->escape($key)."'";
1888 if (!empty($element)) {
1889 $sql .= " AND entity IN (".getEntity($element).")";
1890 } else {
1891 $sql .= " AND entity = ".((int) $conf->entity);
1892 }
1893
1894 dol_syslog(get_class($this).'::fetchObjectFrom', LOG_DEBUG);
1895 $resql = $this->db->query($sql);
1896 if ($resql) {
1897 $row = $this->db->fetch_row($resql);
1898 // Test for avoid error -1
1899 if ($row[0] > 0) {
1900 $result = $this->fetch($row[0]);
1901 }
1902 }
1903
1904 return $result;
1905 }
1906
1915 public function getValueFrom($table, $id, $field)
1916 {
1917 $result = false;
1918 if (!empty($id) && !empty($field) && !empty($table)) {
1919 $sql = "SELECT ".$field." FROM ".$this->db->prefix().$table;
1920 $sql .= " WHERE rowid = ".((int) $id);
1921
1922 dol_syslog(get_class($this).'::getValueFrom', LOG_DEBUG);
1923 $resql = $this->db->query($sql);
1924 if ($resql) {
1925 $row = $this->db->fetch_row($resql);
1926 $result = $row[0];
1927 }
1928 }
1929 return $result;
1930 }
1931
1948 public function setValueFrom($field, $value, $table = '', $id = null, $format = '', $id_field = '', $fuser = null, $trigkey = '', $fk_user_field = 'fk_user_modif')
1949 {
1950 global $user;
1951
1952 if (empty($table)) {
1953 $table = $this->table_element;
1954 }
1955 if (empty($id)) {
1956 $id = $this->id;
1957 }
1958 if (empty($format)) {
1959 $format = 'text';
1960 }
1961 if (empty($id_field)) {
1962 $id_field = 'rowid';
1963 }
1964
1965 // Special case
1966 if ($table == 'product' && $field == 'note_private') {
1967 $field = 'note';
1968 }
1969
1970 if (in_array($table, array('actioncomm', 'adherent', 'advtargetemailing', 'cronjob', 'establishment'))) {
1971 $fk_user_field = 'fk_user_mod';
1972 }
1973 if (in_array($table, array('prelevement_bons'))) { // TODO Add a field fk_user_modif into llx_prelevement_bons
1974 $fk_user_field = '';
1975 }
1976
1977 if ($trigkey) {
1978 $oldvalue = null;
1979
1980 $sql = "SELECT " . $field;
1981 $sql .= " FROM " . MAIN_DB_PREFIX . $table;
1982 $sql .= " WHERE " . $id_field . " = " . ((int) $id);
1983
1984 $resql = $this->db->query($sql);
1985 if ($resql) {
1986 if ($obj = $this->db->fetch_object($resql)) {
1987 if ($format == 'date') {
1988 $oldvalue = $this->db->jdate($obj->$field);
1989 } else {
1990 $oldvalue = $obj->$field;
1991 }
1992 }
1993 } else {
1994 $this->error = $this->db->lasterror();
1995 return -1;
1996 }
1997 }
1998
1999 $error = 0;
2000
2001 dol_syslog(__METHOD__, LOG_DEBUG);
2002
2003 $this->db->begin();
2004
2005 $sql = "UPDATE ".$this->db->prefix().$table." SET ";
2006
2007 if ($format == 'text') {
2008 $sql .= $field." = '".$this->db->escape($value)."'";
2009 } elseif ($format == 'int') {
2010 $sql .= $field." = ".((int) $value);
2011 } elseif ($format == 'date') {
2012 $sql .= $field." = ".($value ? "'".$this->db->idate($value)."'" : "null");
2013 } elseif ($format == 'dategmt') {
2014 $sql .= $field." = ".($value ? "'".$this->db->idate($value, 'gmt')."'" : "null");
2015 }
2016
2017 if ($fk_user_field) {
2018 if (!empty($fuser) && is_object($fuser)) {
2019 $sql .= ", ".$fk_user_field." = ".((int) $fuser->id);
2020 } elseif (empty($fuser) || $fuser != 'none') {
2021 $sql .= ", ".$fk_user_field." = ".((int) $user->id);
2022 }
2023 }
2024
2025 $sql .= " WHERE ".$id_field." = ".((int) $id);
2026
2027 $resql = $this->db->query($sql);
2028 if ($resql) {
2029 if ($trigkey) {
2030 // call trigger with updated object values
2031 if (method_exists($this, 'fetch')) {
2032 $result = $this->fetch($id);
2033 } else {
2034 $result = $this->fetchCommon($id);
2035 }
2036 $this->oldcopy = clone $this;
2037 if (property_exists($this->oldcopy, $field)) {
2038 $this->oldcopy->$field = $oldvalue;
2039 }
2040
2041 if ($result >= 0) {
2042 $result = $this->call_trigger($trigkey, (!empty($fuser) && is_object($fuser)) ? $fuser : $user); // This may set this->errors
2043 }
2044 if ($result < 0) {
2045 $error++;
2046 }
2047 }
2048
2049 if (!$error) {
2050 if (property_exists($this, $field)) {
2051 $this->$field = $value;
2052 }
2053 $this->db->commit();
2054 return 1;
2055 } else {
2056 $this->db->rollback();
2057 return -2;
2058 }
2059 } else {
2060 if ($this->db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
2061 $this->error = 'DB_ERROR_RECORD_ALREADY_EXISTS';
2062 } else {
2063 $this->error = $this->db->lasterror();
2064 }
2065 $this->db->rollback();
2066 return -1;
2067 }
2068 }
2069
2070 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2080 public function load_previous_next_ref($filter, $fieldid, $nodbprefix = 0)
2081 {
2082 // phpcs:enable
2083 global $conf, $user;
2084
2085 if (!$this->table_element) {
2086 dol_print_error('', get_class($this)."::load_previous_next_ref was called on objet with property table_element not defined");
2087 return -1;
2088 }
2089 if ($fieldid == 'none') {
2090 return 1;
2091 }
2092
2093 // For backward compatibility
2094 if (in_array($this->table_element, array('facture_rec', 'facture_fourn_rec')) && $fieldid == 'title') {
2095 $fieldid = 'titre';
2096 }
2097
2098 // Security on socid
2099 $socid = 0;
2100 if ($user->socid > 0) {
2101 $socid = $user->socid;
2102 }
2103
2104 // this->ismultientitymanaged contains
2105 // 0=No test on entity, 1=Test with field entity, 'field@table'=Test with link by field@table
2106 $aliastablesociete = 's';
2107 if ($this->element == 'societe') {
2108 $aliastablesociete = 'te'; // te as table_element
2109 }
2110 $restrictiononfksoc = empty($this->restrictiononfksoc) ? 0 : $this->restrictiononfksoc;
2111 $sql = "SELECT MAX(te.".$fieldid.")";
2112 $sql .= " FROM ".(empty($nodbprefix) ?$this->db->prefix():'').$this->table_element." as te";
2113 if ($this->element == 'user' && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
2114 if (empty($user->admin) || !empty($user->entity) || $conf->entity != 1) {
2115 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."usergroup_user as ug ON ug.fk_user = te.rowid";
2116 }
2117 }
2118 if (isset($this->ismultientitymanaged) && !is_numeric($this->ismultientitymanaged)) {
2119 $tmparray = explode('@', $this->ismultientitymanaged);
2120 $sql .= ", ".$this->db->prefix().$tmparray[1]." as ".($tmparray[1] == 'societe' ? 's' : 'parenttable'); // If we need to link to this table to limit select to entity
2121 } elseif ($restrictiononfksoc == 1 && $this->element != 'societe' && empty($user->rights->societe->client->voir) && !$socid) {
2122 $sql .= ", ".$this->db->prefix()."societe as s"; // If we need to link to societe to limit select to socid
2123 } elseif ($restrictiononfksoc == 2 && $this->element != 'societe' && empty($user->rights->societe->client->voir) && !$socid) {
2124 $sql .= " LEFT JOIN ".$this->db->prefix()."societe as s ON te.fk_soc = s.rowid"; // If we need to link to societe to limit select to socid
2125 }
2126 if ($restrictiononfksoc && empty($user->rights->societe->client->voir) && !$socid) {
2127 $sql .= " LEFT JOIN ".$this->db->prefix()."societe_commerciaux as sc ON ".$aliastablesociete.".rowid = sc.fk_soc";
2128 }
2129 $sql .= " WHERE te.".$fieldid." < '".$this->db->escape($fieldid == 'rowid' ? $this->id : $this->ref)."'"; // ->ref must always be defined (set to id if field does not exists)
2130 if ($restrictiononfksoc == 1 && empty($user->rights->societe->client->voir) && !$socid) {
2131 $sql .= " AND sc.fk_user = ".((int) $user->id);
2132 }
2133 if ($restrictiononfksoc == 2 && empty($user->rights->societe->client->voir) && !$socid) {
2134 $sql .= " AND (sc.fk_user = ".((int) $user->id).' OR te.fk_soc IS NULL)';
2135 }
2136 if (!empty($filter)) {
2137 if (!preg_match('/^\s*AND/i', $filter)) {
2138 $sql .= " AND ";
2139 }
2140 $sql .= $filter;
2141 }
2142 if (isset($this->ismultientitymanaged) && !is_numeric($this->ismultientitymanaged)) {
2143 $tmparray = explode('@', $this->ismultientitymanaged);
2144 $sql .= " AND te.".$tmparray[0]." = ".($tmparray[1] == "societe" ? "s" : "parenttable").".rowid"; // If we need to link to this table to limit select to entity
2145 } elseif ($restrictiononfksoc == 1 && $this->element != 'societe' && empty($user->rights->societe->client->voir) && !$socid) {
2146 $sql .= ' AND te.fk_soc = s.rowid'; // If we need to link to societe to limit select to socid
2147 }
2148 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
2149 if ($this->element == 'user' && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
2150 if (!empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
2151 $sql .= " AND te.entity IS NOT NULL"; // Show all users
2152 } else {
2153 $sql .= " AND ug.entity IN (".getEntity('usergroup').")";
2154 }
2155 } else {
2156 $sql .= ' AND te.entity IN ('.getEntity($this->element).')';
2157 }
2158 }
2159 if (isset($this->ismultientitymanaged) && !is_numeric($this->ismultientitymanaged) && $this->element != 'societe') {
2160 $tmparray = explode('@', $this->ismultientitymanaged);
2161 $sql .= ' AND parenttable.entity IN ('.getEntity($tmparray[1]).')';
2162 }
2163 if ($restrictiononfksoc == 1 && $socid && $this->element != 'societe') {
2164 $sql .= ' AND te.fk_soc = '.((int) $socid);
2165 }
2166 if ($restrictiononfksoc == 2 && $socid && $this->element != 'societe') {
2167 $sql .= ' AND (te.fk_soc = '.((int) $socid).' OR te.fk_soc IS NULL)';
2168 }
2169 if ($restrictiononfksoc && $socid && $this->element == 'societe') {
2170 $sql .= ' AND te.rowid = '.((int) $socid);
2171 }
2172 //print 'socid='.$socid.' restrictiononfksoc='.$restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."<br>";
2173
2174 $result = $this->db->query($sql);
2175 if (!$result) {
2176 $this->error = $this->db->lasterror();
2177 return -1;
2178 }
2179 $row = $this->db->fetch_row($result);
2180 $this->ref_previous = $row[0];
2181
2182 $sql = "SELECT MIN(te.".$fieldid.")";
2183 $sql .= " FROM ".(empty($nodbprefix) ?$this->db->prefix():'').$this->table_element." as te";
2184 if ($this->element == 'user' && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
2185 if (empty($user->admin) || !empty($user->entity) || $conf->entity != 1) {
2186 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."usergroup_user as ug ON ug.fk_user = te.rowid";
2187 }
2188 }
2189 if (isset($this->ismultientitymanaged) && !is_numeric($this->ismultientitymanaged)) {
2190 $tmparray = explode('@', $this->ismultientitymanaged);
2191 $sql .= ", ".$this->db->prefix().$tmparray[1]." as ".($tmparray[1] == 'societe' ? 's' : 'parenttable'); // If we need to link to this table to limit select to entity
2192 } elseif ($restrictiononfksoc == 1 && $this->element != 'societe' && empty($user->rights->societe->client->voir) && !$socid) {
2193 $sql .= ", ".$this->db->prefix()."societe as s"; // If we need to link to societe to limit select to socid
2194 } elseif ($restrictiononfksoc == 2 && $this->element != 'societe' && empty($user->rights->societe->client->voir) && !$socid) {
2195 $sql .= " LEFT JOIN ".$this->db->prefix()."societe as s ON te.fk_soc = s.rowid"; // If we need to link to societe to limit select to socid
2196 }
2197 if ($restrictiononfksoc && empty($user->rights->societe->client->voir) && !$socid) {
2198 $sql .= " LEFT JOIN ".$this->db->prefix()."societe_commerciaux as sc ON ".$aliastablesociete.".rowid = sc.fk_soc";
2199 }
2200 $sql .= " WHERE te.".$fieldid." > '".$this->db->escape($fieldid == 'rowid' ? $this->id : $this->ref)."'"; // ->ref must always be defined (set to id if field does not exists)
2201 if ($restrictiononfksoc == 1 && empty($user->rights->societe->client->voir) && !$socid) {
2202 $sql .= " AND sc.fk_user = ".((int) $user->id);
2203 }
2204 if ($restrictiononfksoc == 2 && empty($user->rights->societe->client->voir) && !$socid) {
2205 $sql .= " AND (sc.fk_user = ".((int) $user->id).' OR te.fk_soc IS NULL)';
2206 }
2207 if (!empty($filter)) {
2208 if (!preg_match('/^\s*AND/i', $filter)) {
2209 $sql .= " AND "; // For backward compatibility
2210 }
2211 $sql .= $filter;
2212 }
2213 if (isset($this->ismultientitymanaged) && !is_numeric($this->ismultientitymanaged)) {
2214 $tmparray = explode('@', $this->ismultientitymanaged);
2215 $sql .= " AND te.".$tmparray[0]." = ".($tmparray[1] == "societe" ? "s" : "parenttable").".rowid"; // If we need to link to this table to limit select to entity
2216 } elseif ($restrictiononfksoc == 1 && $this->element != 'societe' && empty($user->rights->societe->client->voir) && !$socid) {
2217 $sql .= ' AND te.fk_soc = s.rowid'; // If we need to link to societe to limit select to socid
2218 }
2219 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
2220 if ($this->element == 'user' && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
2221 if (!empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
2222 $sql .= " AND te.entity IS NOT NULL"; // Show all users
2223 } else {
2224 $sql .= " AND ug.entity IN (".getEntity('usergroup').")";
2225 }
2226 } else {
2227 $sql .= ' AND te.entity IN ('.getEntity($this->element).')';
2228 }
2229 }
2230 if (isset($this->ismultientitymanaged) && !is_numeric($this->ismultientitymanaged) && $this->element != 'societe') {
2231 $tmparray = explode('@', $this->ismultientitymanaged);
2232 $sql .= ' AND parenttable.entity IN ('.getEntity($tmparray[1]).')';
2233 }
2234 if ($restrictiononfksoc == 1 && $socid && $this->element != 'societe') {
2235 $sql .= ' AND te.fk_soc = '.((int) $socid);
2236 }
2237 if ($restrictiononfksoc == 2 && $socid && $this->element != 'societe') {
2238 $sql .= ' AND (te.fk_soc = '.((int) $socid).' OR te.fk_soc IS NULL)';
2239 }
2240 if ($restrictiononfksoc && $socid && $this->element == 'societe') {
2241 $sql .= ' AND te.rowid = '.((int) $socid);
2242 }
2243 //print 'socid='.$socid.' restrictiononfksoc='.$restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."<br>";
2244 // Rem: Bug in some mysql version: SELECT MIN(rowid) FROM llx_socpeople WHERE rowid > 1 when one row in database with rowid=1, returns 1 instead of null
2245
2246 $result = $this->db->query($sql);
2247 if (!$result) {
2248 $this->error = $this->db->lasterror();
2249 return -2;
2250 }
2251 $row = $this->db->fetch_row($result);
2252 $this->ref_next = $row[0];
2253
2254 return 1;
2255 }
2256
2257
2265 public function getListContactId($source = 'external')
2266 {
2267 $contactAlreadySelected = array();
2268 $tab = $this->liste_contact(-1, $source);
2269 $num = count($tab);
2270 $i = 0;
2271 while ($i < $num) {
2272 if ($source == 'thirdparty') {
2273 $contactAlreadySelected[$i] = $tab[$i]['socid'];
2274 } else {
2275 $contactAlreadySelected[$i] = $tab[$i]['id'];
2276 }
2277 $i++;
2278 }
2279 return $contactAlreadySelected;
2280 }
2281
2282
2290 public function setProject($projectid, $notrigger = 0)
2291 {
2292 global $user;
2293 $error = 0;
2294
2295 if (!$this->table_element) {
2296 dol_syslog(get_class($this)."::setProject was called on objet with property table_element not defined", LOG_ERR);
2297 return -1;
2298 }
2299
2300 $sql = "UPDATE ".$this->db->prefix().$this->table_element;
2301 if (!empty($this->fields['fk_project'])) { // Common case
2302 if ($projectid) {
2303 $sql .= " SET fk_project = ".((int) $projectid);
2304 } else {
2305 $sql .= " SET fk_project = NULL";
2306 }
2307 $sql .= ' WHERE rowid = '.((int) $this->id);
2308 } elseif ($this->table_element == 'actioncomm') { // Special case for actioncomm
2309 if ($projectid) {
2310 $sql .= " SET fk_project = ".((int) $projectid);
2311 } else {
2312 $sql .= " SET fk_project = NULL";
2313 }
2314 $sql .= ' WHERE id = '.((int) $this->id);
2315 } else // Special case for old architecture objects
2316 {
2317 if ($projectid) {
2318 $sql .= ' SET fk_projet = '.((int) $projectid);
2319 } else {
2320 $sql .= ' SET fk_projet = NULL';
2321 }
2322 $sql .= " WHERE rowid = ".((int) $this->id);
2323 }
2324
2325 $this->db->begin();
2326
2327 dol_syslog(get_class($this)."::setProject", LOG_DEBUG);
2328 if ($this->db->query($sql)) {
2329 $this->fk_project = ((int) $projectid);
2330 } else {
2331 dol_print_error($this->db);
2332 $error++;
2333 }
2334
2335 // Triggers
2336 if (!$error && !$notrigger) {
2337 // Call triggers
2338 $result = $this->call_trigger(strtoupper($this->element) . '_MODIFY', $user);
2339 if ($result < 0) {
2340 $error++;
2341 } //Do also here what you must do to rollback action if trigger fail
2342 // End call triggers
2343 }
2344
2345 // Commit or rollback
2346 if ($error) {
2347 $this->db->rollback();
2348 return -1;
2349 } else {
2350 $this->db->commit();
2351 return 1;
2352 }
2353 }
2354
2361 public function setPaymentMethods($id)
2362 {
2363 global $user;
2364
2365 $error = 0; $notrigger = 0;
2366
2367 dol_syslog(get_class($this).'::setPaymentMethods('.$id.')');
2368
2369 if ($this->statut >= 0 || $this->element == 'societe') {
2370 // TODO uniformize field name
2371 $fieldname = 'fk_mode_reglement';
2372 if ($this->element == 'societe') {
2373 $fieldname = 'mode_reglement';
2374 }
2375 if (get_class($this) == 'Fournisseur') {
2376 $fieldname = 'mode_reglement_supplier';
2377 }
2378 if (get_class($this) == 'Tva') {
2379 $fieldname = 'fk_typepayment';
2380 }
2381 if (get_class($this) == 'Salary') {
2382 $fieldname = 'fk_typepayment';
2383 }
2384
2385 $sql = "UPDATE ".$this->db->prefix().$this->table_element;
2386 $sql .= " SET ".$fieldname." = ".(($id > 0 || $id == '0') ? ((int) $id) : 'NULL');
2387 $sql .= ' WHERE rowid='.((int) $this->id);
2388
2389 if ($this->db->query($sql)) {
2390 $this->mode_reglement_id = $id;
2391 // for supplier
2392 if (get_class($this) == 'Fournisseur') {
2393 $this->mode_reglement_supplier_id = $id;
2394 }
2395 // Triggers
2396 if (!$error && !$notrigger) {
2397 // Call triggers
2398 if (get_class($this) == 'Commande') {
2399 $result = $this->call_trigger('ORDER_MODIFY', $user);
2400 } else {
2401 $result = $this->call_trigger(strtoupper(get_class($this)).'_MODIFY', $user);
2402 }
2403 if ($result < 0) {
2404 $error++;
2405 }
2406 // End call triggers
2407 }
2408 return 1;
2409 } else {
2410 dol_syslog(get_class($this).'::setPaymentMethods Error '.$this->db->error());
2411 $this->error = $this->db->error();
2412 return -1;
2413 }
2414 } else {
2415 dol_syslog(get_class($this).'::setPaymentMethods, status of the object is incompatible');
2416 $this->error = 'Status of the object is incompatible '.$this->statut;
2417 return -2;
2418 }
2419 }
2420
2427 public function setMulticurrencyCode($code)
2428 {
2429 dol_syslog(get_class($this).'::setMulticurrencyCode('.$code.')');
2430 if ($this->statut >= 0 || $this->element == 'societe') {
2431 $fieldname = 'multicurrency_code';
2432
2433 $sql = 'UPDATE '.$this->db->prefix().$this->table_element;
2434 $sql .= " SET ".$fieldname." = '".$this->db->escape($code)."'";
2435 $sql .= ' WHERE rowid='.((int) $this->id);
2436
2437 if ($this->db->query($sql)) {
2438 $this->multicurrency_code = $code;
2439
2440 list($fk_multicurrency, $rate) = MultiCurrency::getIdAndTxFromCode($this->db, $code);
2441 if ($rate) {
2442 $this->setMulticurrencyRate($rate, 2);
2443 }
2444
2445 return 1;
2446 } else {
2447 dol_syslog(get_class($this).'::setMulticurrencyCode Error '.$sql.' - '.$this->db->error());
2448 $this->error = $this->db->error();
2449 return -1;
2450 }
2451 } else {
2452 dol_syslog(get_class($this).'::setMulticurrencyCode, status of the object is incompatible');
2453 $this->error = 'Status of the object is incompatible '.$this->statut;
2454 return -2;
2455 }
2456 }
2457
2465 public function setMulticurrencyRate($rate, $mode = 1)
2466 {
2467 dol_syslog(get_class($this).'::setMulticurrencyRate('.$rate.','.$mode.')');
2468 if ($this->statut >= 0 || $this->element == 'societe') {
2469 $fieldname = 'multicurrency_tx';
2470
2471 $sql = 'UPDATE '.$this->db->prefix().$this->table_element;
2472 $sql .= " SET ".$fieldname." = ".((float) $rate);
2473 $sql .= ' WHERE rowid='.((int) $this->id);
2474
2475 if ($this->db->query($sql)) {
2476 $this->multicurrency_tx = $rate;
2477
2478 // Update line price
2479 if (!empty($this->lines)) {
2480 foreach ($this->lines as &$line) {
2481 // Amounts in company currency will be recalculated
2482 if ($mode == 1) {
2483 $line->subprice = 0;
2484 }
2485
2486 // Amounts in foreign currency will be recalculated
2487 if ($mode == 2) {
2488 $line->multicurrency_subprice = 0;
2489 }
2490
2491 switch ($this->element) {
2492 case 'propal':
2495 $this->updateline(
2496 $line->id,
2497 $line->subprice,
2498 $line->qty,
2499 $line->remise_percent,
2500 $line->tva_tx,
2501 $line->localtax1_tx,
2502 $line->localtax2_tx,
2503 ($line->description ? $line->description : $line->desc),
2504 'HT',
2505 $line->info_bits,
2506 $line->special_code,
2507 $line->fk_parent_line,
2508 $line->skip_update_total,
2509 $line->fk_fournprice,
2510 $line->pa_ht,
2511 $line->label,
2512 $line->product_type,
2513 $line->date_start,
2514 $line->date_end,
2515 $line->array_options,
2516 $line->fk_unit,
2517 $line->multicurrency_subprice
2518 );
2519 break;
2520 case 'commande':
2523 $this->updateline(
2524 $line->id,
2525 ($line->description ? $line->description : $line->desc),
2526 $line->subprice,
2527 $line->qty,
2528 $line->remise_percent,
2529 $line->tva_tx,
2530 $line->localtax1_tx,
2531 $line->localtax2_tx,
2532 'HT',
2533 $line->info_bits,
2534 $line->date_start,
2535 $line->date_end,
2536 $line->product_type,
2537 $line->fk_parent_line,
2538 $line->skip_update_total,
2539 $line->fk_fournprice,
2540 $line->pa_ht,
2541 $line->label,
2542 $line->special_code,
2543 $line->array_options,
2544 $line->fk_unit,
2545 $line->multicurrency_subprice
2546 );
2547 break;
2548 case 'facture':
2551 $this->updateline(
2552 $line->id,
2553 ($line->description ? $line->description : $line->desc),
2554 $line->subprice,
2555 $line->qty,
2556 $line->remise_percent,
2557 $line->date_start,
2558 $line->date_end,
2559 $line->tva_tx,
2560 $line->localtax1_tx,
2561 $line->localtax2_tx,
2562 'HT',
2563 $line->info_bits,
2564 $line->product_type,
2565 $line->fk_parent_line,
2566 $line->skip_update_total,
2567 $line->fk_fournprice,
2568 $line->pa_ht,
2569 $line->label,
2570 $line->special_code,
2571 $line->array_options,
2572 $line->situation_percent,
2573 $line->fk_unit,
2574 $line->multicurrency_subprice
2575 );
2576 break;
2577 case 'supplier_proposal':
2580 $this->updateline(
2581 $line->id,
2582 $line->subprice,
2583 $line->qty,
2584 $line->remise_percent,
2585 $line->tva_tx,
2586 $line->localtax1_tx,
2587 $line->localtax2_tx,
2588 ($line->description ? $line->description : $line->desc),
2589 'HT',
2590 $line->info_bits,
2591 $line->special_code,
2592 $line->fk_parent_line,
2593 $line->skip_update_total,
2594 $line->fk_fournprice,
2595 $line->pa_ht,
2596 $line->label,
2597 $line->product_type,
2598 $line->array_options,
2599 $line->ref_fourn,
2600 $line->multicurrency_subprice
2601 );
2602 break;
2603 case 'order_supplier':
2606 $this->updateline(
2607 $line->id,
2608 ($line->description ? $line->description : $line->desc),
2609 $line->subprice,
2610 $line->qty,
2611 $line->remise_percent,
2612 $line->tva_tx,
2613 $line->localtax1_tx,
2614 $line->localtax2_tx,
2615 'HT',
2616 $line->info_bits,
2617 $line->product_type,
2618 false,
2619 $line->date_start,
2620 $line->date_end,
2621 $line->array_options,
2622 $line->fk_unit,
2623 $line->multicurrency_subprice,
2624 $line->ref_supplier
2625 );
2626 break;
2627 case 'invoice_supplier':
2630 $this->updateline(
2631 $line->id,
2632 ($line->description ? $line->description : $line->desc),
2633 $line->subprice,
2634 $line->tva_tx,
2635 $line->localtax1_tx,
2636 $line->localtax2_tx,
2637 $line->qty,
2638 0,
2639 'HT',
2640 $line->info_bits,
2641 $line->product_type,
2642 $line->remise_percent,
2643 false,
2644 $line->date_start,
2645 $line->date_end,
2646 $line->array_options,
2647 $line->fk_unit,
2648 $line->multicurrency_subprice,
2649 $line->ref_supplier
2650 );
2651 break;
2652 default:
2653 dol_syslog(get_class($this).'::setMulticurrencyRate no updateline defined', LOG_DEBUG);
2654 break;
2655 }
2656 }
2657 }
2658
2659 return 1;
2660 } else {
2661 dol_syslog(get_class($this).'::setMulticurrencyRate Error '.$sql.' - '.$this->db->error());
2662 $this->error = $this->db->error();
2663 return -1;
2664 }
2665 } else {
2666 dol_syslog(get_class($this).'::setMulticurrencyRate, status of the object is incompatible');
2667 $this->error = 'Status of the object is incompatible '.$this->statut;
2668 return -2;
2669 }
2670 }
2671
2679 public function setPaymentTerms($id, $deposit_percent = null)
2680 {
2681 dol_syslog(get_class($this).'::setPaymentTerms('.$id.', '.var_export($deposit_percent, true).')');
2682 if ($this->statut >= 0 || $this->element == 'societe') {
2683 // TODO uniformize field name
2684 $fieldname = 'fk_cond_reglement';
2685 if ($this->element == 'societe') {
2686 $fieldname = 'cond_reglement';
2687 }
2688 if (get_class($this) == 'Fournisseur') {
2689 $fieldname = 'cond_reglement_supplier';
2690 }
2691
2692 if (empty($deposit_percent) || $deposit_percent < 0) {
2693 $deposit_percent = getDictionaryValue('c_payment_term', 'deposit_percent', $id);
2694 }
2695
2696 if ($deposit_percent > 100) {
2697 $deposit_percent = 100;
2698 }
2699
2700 $sql = 'UPDATE '.$this->db->prefix().$this->table_element;
2701 $sql .= " SET ".$fieldname." = ".(($id > 0 || $id == '0') ? ((int) $id) : 'NULL');
2702 if (in_array($this->table_element, array('propal', 'commande', 'societe'))) {
2703 $sql .= " , deposit_percent = " . (empty($deposit_percent) ? 'NULL' : "'".$this->db->escape($deposit_percent)."'");
2704 }
2705 $sql .= ' WHERE rowid='.((int) $this->id);
2706
2707 if ($this->db->query($sql)) {
2708 $this->cond_reglement_id = $id;
2709 // for supplier
2710 if (get_class($this) == 'Fournisseur') {
2711 $this->cond_reglement_supplier_id = $id;
2712 }
2713 $this->cond_reglement = $id; // for compatibility
2714 $this->deposit_percent = $deposit_percent;
2715 return 1;
2716 } else {
2717 dol_syslog(get_class($this).'::setPaymentTerms Error '.$sql.' - '.$this->db->error());
2718 $this->error = $this->db->error();
2719 return -1;
2720 }
2721 } else {
2722 dol_syslog(get_class($this).'::setPaymentTerms, status of the object is incompatible');
2723 $this->error = 'Status of the object is incompatible '.$this->statut;
2724 return -2;
2725 }
2726 }
2727
2734 public function setTransportMode($id)
2735 {
2736 dol_syslog(get_class($this).'::setTransportMode('.$id.')');
2737 if ($this->statut >= 0 || $this->element == 'societe') {
2738 $fieldname = 'fk_transport_mode';
2739 if ($this->element == 'societe') {
2740 $fieldname = 'transport_mode';
2741 }
2742 if (get_class($this) == 'Fournisseur') {
2743 $fieldname = 'transport_mode_supplier';
2744 }
2745
2746 $sql = 'UPDATE '.$this->db->prefix().$this->table_element;
2747 $sql .= " SET ".$fieldname." = ".(($id > 0 || $id == '0') ? ((int) $id) : 'NULL');
2748 $sql .= ' WHERE rowid='.((int) $this->id);
2749
2750 if ($this->db->query($sql)) {
2751 $this->transport_mode_id = $id;
2752 // for supplier
2753 if (get_class($this) == 'Fournisseur') {
2754 $this->transport_mode_supplier_id = $id;
2755 }
2756 return 1;
2757 } else {
2758 dol_syslog(get_class($this).'::setTransportMode Error '.$sql.' - '.$this->db->error());
2759 $this->error = $this->db->error();
2760 return -1;
2761 }
2762 } else {
2763 dol_syslog(get_class($this).'::setTransportMode, status of the object is incompatible');
2764 $this->error = 'Status of the object is incompatible '.$this->statut;
2765 return -2;
2766 }
2767 }
2768
2776 {
2777 dol_syslog(get_class($this).'::setRetainedWarrantyPaymentTerms('.$id.')');
2778 if ($this->statut >= 0 || $this->element == 'societe') {
2779 $fieldname = 'retained_warranty_fk_cond_reglement';
2780
2781 $sql = 'UPDATE '.$this->db->prefix().$this->table_element;
2782 $sql .= " SET ".$fieldname." = ".((int) $id);
2783 $sql .= ' WHERE rowid='.((int) $this->id);
2784
2785 if ($this->db->query($sql)) {
2786 $this->retained_warranty_fk_cond_reglement = $id;
2787 return 1;
2788 } else {
2789 dol_syslog(get_class($this).'::setRetainedWarrantyPaymentTerms Error '.$sql.' - '.$this->db->error());
2790 $this->error = $this->db->error();
2791 return -1;
2792 }
2793 } else {
2794 dol_syslog(get_class($this).'::setRetainedWarrantyPaymentTerms, status of the object is incompatible');
2795 $this->error = 'Status of the object is incompatible '.$this->statut;
2796 return -2;
2797 }
2798 }
2799
2807 public function setDeliveryAddress($id)
2808 {
2809 $fieldname = 'fk_delivery_address';
2810 if ($this->element == 'delivery' || $this->element == 'shipping') {
2811 $fieldname = 'fk_address';
2812 }
2813
2814 $sql = "UPDATE ".$this->db->prefix().$this->table_element." SET ".$fieldname." = ".((int) $id);
2815 $sql .= " WHERE rowid = ".((int) $this->id)." AND fk_statut = 0";
2816
2817 if ($this->db->query($sql)) {
2818 $this->fk_delivery_address = $id;
2819 return 1;
2820 } else {
2821 $this->error = $this->db->error();
2822 dol_syslog(get_class($this).'::setDeliveryAddress Error '.$this->error);
2823 return -1;
2824 }
2825 }
2826
2827
2837 public function setShippingMethod($shipping_method_id, $notrigger = false, $userused = null)
2838 {
2839 global $user;
2840
2841 if (empty($userused)) {
2842 $userused = $user;
2843 }
2844
2845 $error = 0;
2846
2847 if (!$this->table_element) {
2848 dol_syslog(get_class($this)."::setShippingMethod was called on objet with property table_element not defined", LOG_ERR);
2849 return -1;
2850 }
2851
2852 $this->db->begin();
2853
2854 if ($shipping_method_id < 0) {
2855 $shipping_method_id = 'NULL';
2856 }
2857 dol_syslog(get_class($this).'::setShippingMethod('.$shipping_method_id.')');
2858
2859 $sql = "UPDATE ".$this->db->prefix().$this->table_element;
2860 $sql .= " SET fk_shipping_method = ".((int) $shipping_method_id);
2861 $sql .= " WHERE rowid=".((int) $this->id);
2862 $resql = $this->db->query($sql);
2863 if (!$resql) {
2864 dol_syslog(get_class($this).'::setShippingMethod Error ', LOG_DEBUG);
2865 $this->error = $this->db->lasterror();
2866 $error++;
2867 } else {
2868 if (!$notrigger) {
2869 // Call trigger
2870 $this->context = array('shippingmethodupdate'=>1);
2871 $result = $this->call_trigger(strtoupper(get_class($this)).'_MODIFY', $userused);
2872 if ($result < 0) {
2873 $error++;
2874 }
2875 // End call trigger
2876 }
2877 }
2878 if ($error) {
2879 $this->db->rollback();
2880 return -1;
2881 } else {
2882 $this->shipping_method_id = ($shipping_method_id == 'NULL') ?null:$shipping_method_id;
2883 $this->db->commit();
2884 return 1;
2885 }
2886 }
2887
2888
2895 public function setWarehouse($warehouse_id)
2896 {
2897 if (!$this->table_element) {
2898 dol_syslog(get_class($this)."::setWarehouse was called on objet with property table_element not defined", LOG_ERR);
2899 return -1;
2900 }
2901 if ($warehouse_id < 0) {
2902 $warehouse_id = 'NULL';
2903 }
2904 dol_syslog(get_class($this).'::setWarehouse('.$warehouse_id.')');
2905
2906 $sql = "UPDATE ".$this->db->prefix().$this->table_element;
2907 $sql .= " SET fk_warehouse = ".((int) $warehouse_id);
2908 $sql .= " WHERE rowid=".((int) $this->id);
2909
2910 if ($this->db->query($sql)) {
2911 $this->warehouse_id = ($warehouse_id == 'NULL') ?null:$warehouse_id;
2912 return 1;
2913 } else {
2914 dol_syslog(get_class($this).'::setWarehouse Error ', LOG_DEBUG);
2915 $this->error = $this->db->error();
2916 return 0;
2917 }
2918 }
2919
2920
2928 public function setDocModel($user, $modelpdf)
2929 {
2930 if (!$this->table_element) {
2931 dol_syslog(get_class($this)."::setDocModel was called on objet with property table_element not defined", LOG_ERR);
2932 return -1;
2933 }
2934
2935 $newmodelpdf = dol_trunc($modelpdf, 255);
2936
2937 $sql = "UPDATE ".$this->db->prefix().$this->table_element;
2938 $sql .= " SET model_pdf = '".$this->db->escape($newmodelpdf)."'";
2939 $sql .= " WHERE rowid = ".((int) $this->id);
2940
2941 dol_syslog(get_class($this)."::setDocModel", LOG_DEBUG);
2942 $resql = $this->db->query($sql);
2943 if ($resql) {
2944 $this->model_pdf = $modelpdf;
2945 $this->modelpdf = $modelpdf; // For bakward compatibility
2946 return 1;
2947 } else {
2948 dol_print_error($this->db);
2949 return 0;
2950 }
2951 }
2952
2953
2962 public function setBankAccount($fk_account, $notrigger = false, $userused = null)
2963 {
2964 global $user;
2965
2966 if (empty($userused)) {
2967 $userused = $user;
2968 }
2969
2970 $error = 0;
2971
2972 if (!$this->table_element) {
2973 dol_syslog(get_class($this)."::setBankAccount was called on objet with property table_element not defined", LOG_ERR);
2974 return -1;
2975 }
2976 $this->db->begin();
2977
2978 if ($fk_account < 0) {
2979 $fk_account = 'NULL';
2980 }
2981 dol_syslog(get_class($this).'::setBankAccount('.$fk_account.')');
2982
2983 $sql = "UPDATE ".$this->db->prefix().$this->table_element;
2984 $sql .= " SET fk_account = ".((int) $fk_account);
2985 $sql .= " WHERE rowid=".((int) $this->id);
2986
2987 $resql = $this->db->query($sql);
2988 if (!$resql) {
2989 dol_syslog(get_class($this).'::setBankAccount Error '.$sql.' - '.$this->db->error());
2990 $this->error = $this->db->lasterror();
2991 $error++;
2992 } else {
2993 if (!$notrigger) {
2994 // Call trigger
2995 $this->context = array('bankaccountupdate'=>1);
2996 $result = $this->call_trigger(strtoupper(get_class($this)).'_MODIFY', $userused);
2997 if ($result < 0) {
2998 $error++;
2999 }
3000 // End call trigger
3001 }
3002 }
3003 if ($error) {
3004 $this->db->rollback();
3005 return -1;
3006 } else {
3007 $this->fk_account = ($fk_account == 'NULL') ?null:$fk_account;
3008 $this->db->commit();
3009 return 1;
3010 }
3011 }
3012
3013
3014 // TODO: Move line related operations to CommonObjectLine?
3015
3016 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3026 public function line_order($renum = false, $rowidorder = 'ASC', $fk_parent_line = true)
3027 {
3028 // phpcs:enable
3029 if (!$this->table_element_line) {
3030 dol_syslog(get_class($this)."::line_order was called on objet with property table_element_line not defined", LOG_ERR);
3031 return -1;
3032 }
3033 if (!$this->fk_element) {
3034 dol_syslog(get_class($this)."::line_order was called on objet with property fk_element not defined", LOG_ERR);
3035 return -1;
3036 }
3037
3038 $fieldposition = 'rang'; // @todo Rename 'rang' into 'position'
3039 if (in_array($this->table_element_line, array('bom_bomline', 'ecm_files', 'emailcollector_emailcollectoraction', 'product_attribute_value'))) {
3040 $fieldposition = 'position';
3041 }
3042
3043 // Count number of lines to reorder (according to choice $renum)
3044 $nl = 0;
3045 $sql = "SELECT count(rowid) FROM ".$this->db->prefix().$this->table_element_line;
3046 $sql .= " WHERE ".$this->fk_element." = ".((int) $this->id);
3047 if (!$renum) {
3048 $sql .= " AND " . $fieldposition . " = 0";
3049 }
3050 if ($renum) {
3051 $sql .= " AND " . $fieldposition . " <> 0";
3052 }
3053
3054 dol_syslog(get_class($this)."::line_order", LOG_DEBUG);
3055 $resql = $this->db->query($sql);
3056 if ($resql) {
3057 $row = $this->db->fetch_row($resql);
3058 $nl = $row[0];
3059 } else {
3060 dol_print_error($this->db);
3061 }
3062 if ($nl > 0) {
3063 // The goal of this part is to reorder all lines, with all children lines sharing the same counter that parents.
3064 $rows = array();
3065
3066 // We first search all lines that are parent lines (for multilevel details lines)
3067 $sql = "SELECT rowid FROM ".$this->db->prefix().$this->table_element_line;
3068 $sql .= " WHERE ".$this->fk_element." = ".((int) $this->id);
3069 if ($fk_parent_line) {
3070 $sql .= ' AND fk_parent_line IS NULL';
3071 }
3072 $sql .= " ORDER BY " . $fieldposition . " ASC, rowid " . $rowidorder;
3073
3074 dol_syslog(get_class($this)."::line_order search all parent lines", LOG_DEBUG);
3075 $resql = $this->db->query($sql);
3076 if ($resql) {
3077 $i = 0;
3078 $num = $this->db->num_rows($resql);
3079 while ($i < $num) {
3080 $row = $this->db->fetch_row($resql);
3081 $rows[] = $row[0]; // Add parent line into array rows
3082 $childrens = $this->getChildrenOfLine($row[0]);
3083 if (!empty($childrens)) {
3084 foreach ($childrens as $child) {
3085 array_push($rows, $child);
3086 }
3087 }
3088 $i++;
3089 }
3090
3091 // Now we set a new number for each lines (parent and children with children included into parent tree)
3092 if (!empty($rows)) {
3093 foreach ($rows as $key => $row) {
3094 $this->updateRangOfLine($row, ($key + 1));
3095 }
3096 }
3097 } else {
3098 dol_print_error($this->db);
3099 }
3100 }
3101 return 1;
3102 }
3103
3111 public function getChildrenOfLine($id, $includealltree = 0)
3112 {
3113 $fieldposition = 'rang'; // @todo Rename 'rang' into 'position'
3114 if (in_array($this->table_element_line, array('bom_bomline', 'ecm_files', 'emailcollector_emailcollectoraction', 'product_attribute_value'))) {
3115 $fieldposition = 'position';
3116 }
3117
3118 $rows = array();
3119
3120 $sql = "SELECT rowid FROM ".$this->db->prefix().$this->table_element_line;
3121 $sql .= " WHERE ".$this->fk_element." = ".((int) $this->id);
3122 $sql .= ' AND fk_parent_line = '.((int) $id);
3123 $sql .= " ORDER BY " . $fieldposition . " ASC";
3124
3125 dol_syslog(get_class($this)."::getChildrenOfLine search children lines for line ".$id, LOG_DEBUG);
3126 $resql = $this->db->query($sql);
3127 if ($resql) {
3128 if ($this->db->num_rows($resql) > 0) {
3129 while ($row = $this->db->fetch_row($resql)) {
3130 $rows[] = $row[0];
3131 if (!empty($includealltree)) {
3132 $rows = array_merge($rows, $this->getChildrenOfLine($row[0], $includealltree));
3133 }
3134 }
3135 }
3136 }
3137 return $rows;
3138 }
3139
3140 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3148 public function line_up($rowid, $fk_parent_line = true)
3149 {
3150 // phpcs:enable
3151 $this->line_order(false, 'ASC', $fk_parent_line);
3152
3153 // Get rang of line
3154 $rang = $this->getRangOfLine($rowid);
3155
3156 // Update position of line
3157 $this->updateLineUp($rowid, $rang);
3158 }
3159
3160 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3168 public function line_down($rowid, $fk_parent_line = true)
3169 {
3170 // phpcs:enable
3171 $this->line_order(false, 'ASC', $fk_parent_line);
3172
3173 // Get rang of line
3174 $rang = $this->getRangOfLine($rowid);
3175
3176 // Get max value for rang
3177 $max = $this->line_max();
3178
3179 // Update position of line
3180 $this->updateLineDown($rowid, $rang, $max);
3181 }
3182
3190 public function updateRangOfLine($rowid, $rang)
3191 {
3192 global $hookmanager;
3193 $fieldposition = 'rang'; // @todo Rename 'rang' into 'position'
3194 if (in_array($this->table_element_line, array('bom_bomline', 'ecm_files', 'emailcollector_emailcollectoraction', 'product_attribute_value'))) {
3195 $fieldposition = 'position';
3196 }
3197
3198 $sql = "UPDATE ".$this->db->prefix().$this->table_element_line." SET ".$fieldposition." = ".((int) $rang);
3199 $sql .= ' WHERE rowid = '.((int) $rowid);
3200
3201 dol_syslog(get_class($this)."::updateRangOfLine", LOG_DEBUG);
3202 if (!$this->db->query($sql)) {
3203 dol_print_error($this->db);
3204 return -1;
3205 } else {
3206 $parameters=array('rowid'=>$rowid, 'rang'=>$rang, 'fieldposition' => $fieldposition);
3207 $action='';
3208 $reshook = $hookmanager->executeHooks('afterRankOfLineUpdate', $parameters, $this, $action);
3209 return 1;
3210 }
3211 }
3212
3213 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3220 public function line_ajaxorder($rows)
3221 {
3222 // phpcs:enable
3223 $num = count($rows);
3224 for ($i = 0; $i < $num; $i++) {
3225 $this->updateRangOfLine($rows[$i], ($i + 1));
3226 }
3227 }
3228
3236 public function updateLineUp($rowid, $rang)
3237 {
3238 if ($rang > 1) {
3239 $fieldposition = 'rang';
3240 if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction', 'product_attribute_value'))) {
3241 $fieldposition = 'position';
3242 }
3243
3244 $sql = "UPDATE ".$this->db->prefix().$this->table_element_line." SET ".$fieldposition." = ".((int) $rang);
3245 $sql .= " WHERE ".$this->fk_element." = ".((int) $this->id);
3246 $sql .= " AND " . $fieldposition . " = " . ((int) ($rang - 1));
3247 if ($this->db->query($sql)) {
3248 $sql = "UPDATE ".$this->db->prefix().$this->table_element_line." SET ".$fieldposition." = ".((int) ($rang - 1));
3249 $sql .= ' WHERE rowid = '.((int) $rowid);
3250 if (!$this->db->query($sql)) {
3251 dol_print_error($this->db);
3252 }
3253 } else {
3254 dol_print_error($this->db);
3255 }
3256 }
3257 }
3258
3267 public function updateLineDown($rowid, $rang, $max)
3268 {
3269 if ($rang < $max) {
3270 $fieldposition = 'rang';
3271 if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction', 'product_attribute_value'))) {
3272 $fieldposition = 'position';
3273 }
3274
3275 $sql = "UPDATE ".$this->db->prefix().$this->table_element_line." SET ".$fieldposition." = ".((int) $rang);
3276 $sql .= " WHERE ".$this->fk_element." = ".((int) $this->id);
3277 $sql .= " AND " . $fieldposition . " = " . ((int) ($rang + 1));
3278 if ($this->db->query($sql)) {
3279 $sql = "UPDATE ".$this->db->prefix().$this->table_element_line." SET ".$fieldposition." = ".((int) ($rang + 1));
3280 $sql .= ' WHERE rowid = '.((int) $rowid);
3281 if (!$this->db->query($sql)) {
3282 dol_print_error($this->db);
3283 }
3284 } else {
3285 dol_print_error($this->db);
3286 }
3287 }
3288 }
3289
3296 public function getRangOfLine($rowid)
3297 {
3298 $fieldposition = 'rang';
3299 if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction', 'product_attribute_value'))) {
3300 $fieldposition = 'position';
3301 }
3302
3303 $sql = "SELECT " . $fieldposition . " FROM ".$this->db->prefix().$this->table_element_line;
3304 $sql .= " WHERE rowid = ".((int) $rowid);
3305
3306 dol_syslog(get_class($this)."::getRangOfLine", LOG_DEBUG);
3307 $resql = $this->db->query($sql);
3308 if ($resql) {
3309 $row = $this->db->fetch_row($resql);
3310 return $row[0];
3311 }
3312
3313 return 0;
3314 }
3315
3322 public function getIdOfLine($rang)
3323 {
3324 $fieldposition = 'rang';
3325 if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction', 'product_attribute_value'))) {
3326 $fieldposition = 'position';
3327 }
3328
3329 $sql = "SELECT rowid FROM ".$this->db->prefix().$this->table_element_line;
3330 $sql .= " WHERE ".$this->fk_element." = ".((int) $this->id);
3331 $sql .= " AND " . $fieldposition . " = ".((int) $rang);
3332 $resql = $this->db->query($sql);
3333 if ($resql) {
3334 $row = $this->db->fetch_row($resql);
3335 return $row[0];
3336 }
3337
3338 return 0;
3339 }
3340
3341 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3348 public function line_max($fk_parent_line = 0)
3349 {
3350 // phpcs:enable
3351 $positionfield = 'rang';
3352 if (in_array($this->table_element, array('bom_bom', 'product_attribute'))) {
3353 $positionfield = 'position';
3354 }
3355
3356 // Search the last rang with fk_parent_line
3357 if ($fk_parent_line) {
3358 $sql = "SELECT max(".$positionfield.") FROM ".$this->db->prefix().$this->table_element_line;
3359 $sql .= " WHERE ".$this->fk_element." = ".((int) $this->id);
3360 $sql .= " AND fk_parent_line = ".((int) $fk_parent_line);
3361
3362 dol_syslog(get_class($this)."::line_max", LOG_DEBUG);
3363 $resql = $this->db->query($sql);
3364 if ($resql) {
3365 $row = $this->db->fetch_row($resql);
3366 if (!empty($row[0])) {
3367 return $row[0];
3368 } else {
3369 return $this->getRangOfLine($fk_parent_line);
3370 }
3371 }
3372 } else {
3373 // If not, search the last rang of element
3374 $sql = "SELECT max(".$positionfield.") FROM ".$this->db->prefix().$this->table_element_line;
3375 $sql .= " WHERE ".$this->fk_element." = ".((int) $this->id);
3376
3377 dol_syslog(get_class($this)."::line_max", LOG_DEBUG);
3378 $resql = $this->db->query($sql);
3379 if ($resql) {
3380 $row = $this->db->fetch_row($resql);
3381 return $row[0];
3382 }
3383 }
3384
3385 return 0;
3386 }
3387
3388 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3395 public function update_ref_ext($ref_ext)
3396 {
3397 // phpcs:enable
3398 if (!$this->table_element) {
3399 dol_syslog(get_class($this)."::update_ref_ext was called on objet with property table_element not defined", LOG_ERR);
3400 return -1;
3401 }
3402
3403 $sql = "UPDATE ".$this->db->prefix().$this->table_element;
3404 $sql .= " SET ref_ext = '".$this->db->escape($ref_ext)."'";
3405 $sql .= " WHERE ".(isset($this->table_rowid) ? $this->table_rowid : 'rowid')." = ".((int) $this->id);
3406
3407 dol_syslog(get_class($this)."::update_ref_ext", LOG_DEBUG);
3408 if ($this->db->query($sql)) {
3409 $this->ref_ext = $ref_ext;
3410 return 1;
3411 } else {
3412 $this->error = $this->db->error();
3413 return -1;
3414 }
3415 }
3416
3417 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3426 public function update_note($note, $suffix = '', $notrigger = 0)
3427 {
3428 // phpcs:enable
3429 global $user;
3430
3431 if (!$this->table_element) {
3432 $this->error = 'update_note was called on objet with property table_element not defined';
3433 dol_syslog(get_class($this)."::update_note was called on objet with property table_element not defined", LOG_ERR);
3434 return -1;
3435 }
3436 if (!in_array($suffix, array('', '_public', '_private'))) {
3437 $this->error = 'update_note Parameter suffix must be empty, \'_private\' or \'_public\'';
3438 dol_syslog(get_class($this)."::update_note Parameter suffix must be empty, '_private' or '_public'", LOG_ERR);
3439 return -2;
3440 }
3441
3442 $newsuffix = $suffix;
3443
3444 // Special cas
3445 if ($this->table_element == 'product' && $newsuffix == '_private') {
3446 $newsuffix = '';
3447 }
3448 if (in_array($this->table_element, array('actioncomm', 'adherent', 'advtargetemailing', 'cronjob', 'establishment'))) {
3449 $fieldusermod = "fk_user_mod";
3450 } elseif ($this->table_element == 'ecm_files') {
3451 $fieldusermod = "fk_user_m";
3452 } else {
3453 $fieldusermod = "fk_user_modif";
3454 }
3455 $sql = "UPDATE ".$this->db->prefix().$this->table_element;
3456 $sql .= " SET note".$newsuffix." = ".(!empty($note) ? ("'".$this->db->escape($note)."'") : "NULL");
3457 $sql .= ", ".$fieldusermod." = ".((int) $user->id);
3458 $sql .= " WHERE rowid = ".((int) $this->id);
3459
3460 dol_syslog(get_class($this)."::update_note", LOG_DEBUG);
3461 if ($this->db->query($sql)) {
3462 if ($suffix == '_public') {
3463 $this->note_public = $note;
3464 } elseif ($suffix == '_private') {
3465 $this->note_private = $note;
3466 } else {
3467 $this->note = $note; // deprecated
3468 $this->note_private = $note;
3469 }
3470 if (empty($notrigger)) {
3471 switch ($this->element) {
3472 case 'societe':
3473 $trigger_name = 'COMPANY_MODIFY';
3474 break;
3475 case 'commande':
3476 $trigger_name = 'ORDER_MODIFY';
3477 break;
3478 case 'facture':
3479 $trigger_name = 'BILL_MODIFY';
3480 break;
3481 case 'invoice_supplier':
3482 $trigger_name = 'BILL_SUPPLIER_MODIFY';
3483 break;
3484 case 'facturerec':
3485 $trigger_name = 'BILLREC_MODIFIY';
3486 break;
3487 case 'expensereport':
3488 $trigger_name = 'EXPENSE_REPORT_MODIFY';
3489 break;
3490 default:
3491 $trigger_name = strtoupper($this->element) . '_MODIFY';
3492 }
3493 $ret = $this->call_trigger($trigger_name, $user);
3494 if ($ret < 0) {
3495 return -1;
3496 }
3497 }
3498 return 1;
3499 } else {
3500 $this->error = $this->db->lasterror();
3501 return -1;
3502 }
3503 }
3504
3505 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3514 public function update_note_public($note)
3515 {
3516 // phpcs:enable
3517 return $this->update_note($note, '_public');
3518 }
3519
3520 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3531 public function update_price($exclspec = 0, $roundingadjust = 'none', $nodatabaseupdate = 0, $seller = null)
3532 {
3533 // phpcs:enable
3534 global $conf, $hookmanager, $action;
3535
3536 $parameters = array('exclspec' => $exclspec, 'roundingadjust' => $roundingadjust, 'nodatabaseupdate' => $nodatabaseupdate, 'seller' => $seller);
3537 $reshook = $hookmanager->executeHooks('updateTotalPrice', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3538 if ($reshook > 0) {
3539 return 1; // replacement code
3540 } elseif ($reshook < 0) {
3541 return -1; // failure
3542 } // reshook = 0 => execute normal code
3543
3544 // Some external module want no update price after a trigger because they have another method to calculate the total (ex: with an extrafield)
3545 $MODULE = "";
3546 if ($this->element == 'propal') {
3547 $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_PROPOSAL";
3548 } elseif ($this->element == 'commande' || $this->element == 'order') {
3549 $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_ORDER";
3550 } elseif ($this->element == 'facture' || $this->element == 'invoice') {
3551 $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_INVOICE";
3552 } elseif ($this->element == 'facture_fourn' || $this->element == 'supplier_invoice' || $this->element == 'invoice_supplier' || $this->element == 'invoice_supplier_rec') {
3553 $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_INVOICE";
3554 } elseif ($this->element == 'order_supplier' || $this->element == 'supplier_order') {
3555 $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_ORDER";
3556 } elseif ($this->element == 'supplier_proposal') {
3557 $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_PROPOSAL";
3558 }
3559
3560 if (!empty($MODULE)) {
3561 if (!empty($conf->global->$MODULE)) {
3562 $modsactivated = explode(',', $conf->global->$MODULE);
3563 foreach ($modsactivated as $mod) {
3564 if (isModEnabled($mod)) {
3565 return 1; // update was disabled by specific setup
3566 }
3567 }
3568 }
3569 }
3570
3571 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
3572
3573 $forcedroundingmode = $roundingadjust;
3574 if ($forcedroundingmode == 'auto' && isset($conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND)) {
3575 $forcedroundingmode = getDolGlobalString('MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND');
3576 } elseif ($forcedroundingmode == 'auto') {
3577 $forcedroundingmode = '0';
3578 }
3579
3580 $error = 0;
3581
3582 $multicurrency_tx = !empty($this->multicurrency_tx) ? $this->multicurrency_tx : 1;
3583
3584 // Define constants to find lines to sum (field name int the table_element_line not into table_element)
3585 $fieldtva = 'total_tva';
3586 $fieldlocaltax1 = 'total_localtax1';
3587 $fieldlocaltax2 = 'total_localtax2';
3588 $fieldup = 'subprice';
3589 if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') {
3590 $fieldtva = 'tva';
3591 $fieldup = 'pu_ht';
3592 }
3593 if ($this->element == 'invoice_supplier_rec') {
3594 $fieldup = 'pu_ht';
3595 }
3596 if ($this->element == 'expensereport') {
3597 $fieldup = 'value_unit';
3598 }
3599
3600 $sql = "SELECT rowid, qty, ".$fieldup." as up, remise_percent, total_ht, ".$fieldtva." as total_tva, total_ttc, ".$fieldlocaltax1." as total_localtax1, ".$fieldlocaltax2." as total_localtax2,";
3601 $sql .= ' tva_tx as vatrate, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, info_bits, product_type';
3602 if ($this->table_element_line == 'facturedet') {
3603 $sql .= ', situation_percent';
3604 }
3605 $sql .= ', multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
3606 $sql .= " FROM ".$this->db->prefix().$this->table_element_line;
3607 $sql .= " WHERE ".$this->fk_element." = ".((int) $this->id);
3608 if ($exclspec) {
3609 $product_field = 'product_type';
3610 if ($this->table_element_line == 'contratdet') {
3611 $product_field = ''; // contratdet table has no product_type field
3612 }
3613 if ($product_field) {
3614 $sql .= " AND ".$product_field." <> 9";
3615 }
3616 }
3617 $sql .= ' ORDER by rowid'; // We want to be sure to always use same order of line to not change lines differently when option MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND is used
3618
3619 dol_syslog(get_class($this)."::update_price", LOG_DEBUG);
3620
3621 $resql = $this->db->query($sql);
3622 if ($resql) {
3623 $this->total_ht = 0;
3624 $this->total_tva = 0;
3625 $this->total_localtax1 = 0;
3626 $this->total_localtax2 = 0;
3627 $this->total_ttc = 0;
3628 $total_ht_by_vats = array();
3629 $total_tva_by_vats = array();
3630 $total_ttc_by_vats = array();
3631 $this->multicurrency_total_ht = 0;
3632 $this->multicurrency_total_tva = 0;
3633 $this->multicurrency_total_ttc = 0;
3634
3635 $this->db->begin();
3636
3637 $num = $this->db->num_rows($resql);
3638 $i = 0;
3639 while ($i < $num) {
3640 $obj = $this->db->fetch_object($resql);
3641
3642 // Note: There is no check on detail line and no check on total, if $forcedroundingmode = 'none'
3643 $parameters = array('fk_element' => $obj->rowid);
3644 $reshook = $hookmanager->executeHooks('changeRoundingMode', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3645
3646 if (empty($reshook) && $forcedroundingmode == '0') { // Check if data on line are consistent. This may solve lines that were not consistent because set with $forcedroundingmode='auto'
3647 // This part of code is to fix data. We should not call it too often.
3648 $localtax_array = array($obj->localtax1_type, $obj->localtax1_tx, $obj->localtax2_type, $obj->localtax2_tx);
3649 $tmpcal = calcul_price_total($obj->qty, $obj->up, $obj->remise_percent, $obj->vatrate, $obj->localtax1_tx, $obj->localtax2_tx, 0, 'HT', $obj->info_bits, $obj->product_type, $seller, $localtax_array, (isset($obj->situation_percent) ? $obj->situation_percent : 100), $multicurrency_tx);
3650
3651 $diff_when_using_price_ht = price2num($tmpcal[1] - $obj->total_tva, 'MT', 1); // If price was set with tax price and unit price HT has a low number of digits, then we may have a diff on recalculation from unit price HT.
3652 $diff_on_current_total = price2num($obj->total_ttc - $obj->total_ht - $obj->total_tva - $obj->total_localtax1 - $obj->total_localtax2, 'MT', 1);
3653 //var_dump($obj->total_ht.' '.$obj->total_tva.' '.$obj->total_localtax1.' '.$obj->total_localtax2.' => '.$obj->total_ttc);
3654 //var_dump($diff_when_using_price_ht.' '.$diff_on_current_total);
3655
3656 if ($diff_on_current_total) {
3657 // This should not happen, we should always have in table: total_ttc = total_ht + total_vat + total_localtax1 + total_localtax2
3658 $sqlfix = "UPDATE ".$this->db->prefix().$this->table_element_line." SET ".$fieldtva." = ".price2num((float) $tmpcal[1]).", total_ttc = ".price2num((float) $tmpcal[2])." WHERE rowid = ".((int) $obj->rowid);
3659 dol_syslog('We found unconsistent data into detailed line (diff_on_current_total = '.$diff_on_current_total.') for line rowid = '.$obj->rowid." (ht=".$obj->total_ht." vat=".$obj->total_tva." tax1=".$obj->total_localtax1." tax2=".$obj->total_localtax2." ttc=".$obj->total_ttc."). We fix the total_vat and total_ttc of line by running sqlfix = ".$sqlfix, LOG_WARNING);
3660 $resqlfix = $this->db->query($sqlfix);
3661 if (!$resqlfix) {
3662 dol_print_error($this->db, 'Failed to update line');
3663 }
3664 $obj->total_tva = $tmpcal[1];
3665 $obj->total_ttc = $tmpcal[2];
3666 } elseif ($diff_when_using_price_ht && $roundingadjust == '0') {
3667 // After calculation from HT, total is consistent but we have found a difference between VAT part in calculation and into database and
3668 // we ask to force the use of rounding on line (like done on calculation) so we force update of line
3669 $sqlfix = "UPDATE ".$this->db->prefix().$this->table_element_line." SET ".$fieldtva." = ".price2num((float) $tmpcal[1]).", total_ttc = ".price2num((float) $tmpcal[2])." WHERE rowid = ".((int) $obj->rowid);
3670 dol_syslog('We found a line with different rounding data into detailed line (diff_when_using_price_ht = '.$diff_when_using_price_ht.' and diff_on_current_total = '.$diff_on_current_total.') for line rowid = '.$obj->rowid." (total vat of line calculated=".$tmpcal[1].", database=".$obj->total_tva."). We fix the total_vat and total_ttc of line by running sqlfix = ".$sqlfix);
3671 $resqlfix = $this->db->query($sqlfix);
3672 if (!$resqlfix) {
3673 dol_print_error($this->db, 'Failed to update line');
3674 }
3675 $obj->total_tva = $tmpcal[1];
3676 $obj->total_ttc = $tmpcal[2];
3677 }
3678 }
3679
3680 $this->total_ht += $obj->total_ht; // The field visible at end of line detail
3681 $this->total_tva += $obj->total_tva;
3682 $this->total_localtax1 += $obj->total_localtax1;
3683 $this->total_localtax2 += $obj->total_localtax2;
3684 $this->total_ttc += $obj->total_ttc;
3685 $this->multicurrency_total_ht += $obj->multicurrency_total_ht; // The field visible at end of line detail
3686 $this->multicurrency_total_tva += $obj->multicurrency_total_tva;
3687 $this->multicurrency_total_ttc += $obj->multicurrency_total_ttc;
3688
3689 if (!isset($total_ht_by_vats[$obj->vatrate])) {
3690 $total_ht_by_vats[$obj->vatrate] = 0;
3691 }
3692 if (!isset($total_tva_by_vats[$obj->vatrate])) {
3693 $total_tva_by_vats[$obj->vatrate] = 0;
3694 }
3695 if (!isset($total_ttc_by_vats[$obj->vatrate])) {
3696 $total_ttc_by_vats[$obj->vatrate] = 0;
3697 }
3698 $total_ht_by_vats[$obj->vatrate] += $obj->total_ht;
3699 $total_tva_by_vats[$obj->vatrate] += $obj->total_tva;
3700 $total_ttc_by_vats[$obj->vatrate] += $obj->total_ttc;
3701
3702 if ($forcedroundingmode == '1') { // Check if we need adjustement onto line for vat. TODO This works on the company currency but not on foreign currency
3703 $tmpvat = price2num($total_ht_by_vats[$obj->vatrate] * $obj->vatrate / 100, 'MT', 1);
3704 $diff = price2num($total_tva_by_vats[$obj->vatrate] - $tmpvat, 'MT', 1);
3705 //print 'Line '.$i.' rowid='.$obj->rowid.' vat_rate='.$obj->vatrate.' total_ht='.$obj->total_ht.' total_tva='.$obj->total_tva.' total_ttc='.$obj->total_ttc.' total_ht_by_vats='.$total_ht_by_vats[$obj->vatrate].' total_tva_by_vats='.$total_tva_by_vats[$obj->vatrate].' (new calculation = '.$tmpvat.') total_ttc_by_vats='.$total_ttc_by_vats[$obj->vatrate].($diff?" => DIFF":"")."<br>\n";
3706 if ($diff) {
3707 if (abs($diff) > (10 * pow(10, -1 * getDolGlobalInt('MAIN_MAX_DECIMALS_TOT', 0)))) {
3708 // If error is more than 10 times the accurancy of rounding. This should not happen.
3709 $errmsg = 'A rounding difference was detected into TOTAL but is too high to be corrected. Some data in your lines may be corrupted. Try to edit each line manually to fix this before restarting.';
3710 dol_syslog($errmsg, LOG_WARNING);
3711 $this->error = $errmsg;
3712 $error++;
3713 break;
3714 }
3715 $sqlfix = "UPDATE ".$this->db->prefix().$this->table_element_line." SET ".$fieldtva." = ".price2num($obj->total_tva - $diff).", total_ttc = ".price2num($obj->total_ttc - $diff)." WHERE rowid = ".((int) $obj->rowid);
3716 dol_syslog('We found a difference of '.$diff.' for line rowid = '.$obj->rowid.". We fix the total_vat and total_ttc of line by running sqlfix = ".$sqlfix);
3717
3718 $resqlfix = $this->db->query($sqlfix);
3719
3720 if (!$resqlfix) {
3721 dol_print_error($this->db, 'Failed to update line');
3722 }
3723
3724 $this->total_tva = (float) price2num($this->total_tva - $diff, '', 1);
3725 $this->total_ttc = (float) price2num($this->total_ttc - $diff, '', 1);
3726 $total_tva_by_vats[$obj->vatrate] = (float) price2num($total_tva_by_vats[$obj->vatrate] - $diff, '', 1);
3727 $total_ttc_by_vats[$obj->vatrate] = (float) price2num($total_ttc_by_vats[$obj->vatrate] - $diff, '', 1);
3728 }
3729 }
3730
3731 $i++;
3732 }
3733
3734 // Add revenue stamp to total
3735 $this->total_ttc += isset($this->revenuestamp) ? $this->revenuestamp : 0;
3736 $this->multicurrency_total_ttc += isset($this->revenuestamp) ? ($this->revenuestamp * $multicurrency_tx) : 0;
3737
3738 // Situations totals
3739 if (!empty($this->situation_cycle_ref) && $this->situation_counter > 1 && method_exists($this, 'get_prev_sits') && $this->type != $this::TYPE_CREDIT_NOTE) {
3740 $prev_sits = $this->get_prev_sits();
3741
3742 foreach ($prev_sits as $sit) { // $sit is an object Facture loaded with a fetch.
3743 $this->total_ht -= $sit->total_ht;
3744 $this->total_tva -= $sit->total_tva;
3745 $this->total_localtax1 -= $sit->total_localtax1;
3746 $this->total_localtax2 -= $sit->total_localtax2;
3747 $this->total_ttc -= $sit->total_ttc;
3748 $this->multicurrency_total_ht -= $sit->multicurrency_total_ht;
3749 $this->multicurrency_total_tva -= $sit->multicurrency_total_tva;
3750 $this->multicurrency_total_ttc -= $sit->multicurrency_total_ttc;
3751 }
3752 }
3753
3754 // Clean total
3755 $this->total_ht = (float) price2num($this->total_ht);
3756 $this->total_tva = (float) price2num($this->total_tva);
3757 $this->total_localtax1 = (float) price2num($this->total_localtax1);
3758 $this->total_localtax2 = (float) price2num($this->total_localtax2);
3759 $this->total_ttc = (float) price2num($this->total_ttc);
3760
3761 $this->db->free($resql);
3762
3763 // Now update global fields total_ht, total_ttc, total_tva, total_localtax1, total_localtax2, multicurrency_total_* of main object
3764 $fieldht = 'total_ht';
3765 $fieldtva = 'tva';
3766 $fieldlocaltax1 = 'localtax1';
3767 $fieldlocaltax2 = 'localtax2';
3768 $fieldttc = 'total_ttc';
3769 // Specific code for backward compatibility with old field names
3770 if (in_array($this->element, array('propal', 'commande', 'facture', 'facturerec', 'supplier_proposal', 'order_supplier', 'facture_fourn', 'invoice_supplier', 'invoice_supplier_rec', 'expensereport'))) {
3771 $fieldtva = 'total_tva';
3772 }
3773
3774 if (!$error && empty($nodatabaseupdate)) {
3775 $sql = "UPDATE ".$this->db->prefix().$this->table_element.' SET';
3776 $sql .= " ".$fieldht." = ".((float) price2num($this->total_ht, 'MT', 1)).",";
3777 $sql .= " ".$fieldtva." = ".((float) price2num($this->total_tva, 'MT', 1)).",";
3778 $sql .= " ".$fieldlocaltax1." = ".((float) price2num($this->total_localtax1, 'MT', 1)).",";
3779 $sql .= " ".$fieldlocaltax2." = ".((float) price2num($this->total_localtax2, 'MT', 1)).",";
3780 $sql .= " ".$fieldttc." = ".((float) price2num($this->total_ttc, 'MT', 1));
3781 $sql .= ", multicurrency_total_ht = ".((float) price2num($this->multicurrency_total_ht, 'MT', 1));
3782 $sql .= ", multicurrency_total_tva = ".((float) price2num($this->multicurrency_total_tva, 'MT', 1));
3783 $sql .= ", multicurrency_total_ttc = ".((float) price2num($this->multicurrency_total_ttc, 'MT', 1));
3784 $sql .= " WHERE rowid = ".((int) $this->id);
3785
3786 dol_syslog(get_class($this)."::update_price", LOG_DEBUG);
3787 $resql = $this->db->query($sql);
3788
3789 if (!$resql) {
3790 $error++;
3791 $this->error = $this->db->lasterror();
3792 $this->errors[] = $this->db->lasterror();
3793 }
3794 }
3795
3796 if (!$error) {
3797 $this->db->commit();
3798 return 1;
3799 } else {
3800 $this->db->rollback();
3801 return -1;
3802 }
3803 } else {
3804 dol_print_error($this->db, 'Bad request in update_price');
3805 return -1;
3806 }
3807 }
3808
3809 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3820 public function add_object_linked($origin = null, $origin_id = null, $f_user = null, $notrigger = 0)
3821 {
3822 // phpcs:enable
3823 global $user, $hookmanager, $action;
3824 $origin = (!empty($origin) ? $origin : $this->origin);
3825 $origin_id = (!empty($origin_id) ? $origin_id : $this->origin_id);
3826 $f_user = isset($f_user) ? $f_user : $user;
3827
3828 // Special case
3829 if ($origin == 'order') {
3830 $origin = 'commande';
3831 }
3832 if ($origin == 'invoice') {
3833 $origin = 'facture';
3834 }
3835 if ($origin == 'invoice_template') {
3836 $origin = 'facturerec';
3837 }
3838 if ($origin == 'supplierorder') {
3839 $origin = 'order_supplier';
3840 }
3841
3842 // Elements of the core modules which have `$module` property but may to which we don't want to prefix module part to the element name for finding the linked object in llx_element_element.
3843 // It's because an entry for this element may be exist in llx_element_element before this modification (version <=14.2) and ave named only with their element name in fk_source or fk_target.
3844 $coremodule = array('knowledgemanagement', 'partnership', 'workstation', 'ticket', 'recruitment', 'eventorganization', 'asset');
3845 // Add module part to target type if object has $module property and isn't in core modules.
3846 $targettype = ((!empty($this->module) && ! in_array($this->module, $coremodule)) ? $this->module.'_' : '').$this->element;
3847
3848 $parameters = array('targettype'=>$targettype);
3849 // Hook for explicitly set the targettype if it must be differtent than $this->element
3850 $reshook = $hookmanager->executeHooks('setLinkedObjectSourceTargetType', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3851 if ($reshook > 0) {
3852 if (!empty($hookmanager->resArray['targettype'])) $targettype = $hookmanager->resArray['targettype'];
3853 }
3854
3855 $this->db->begin();
3856 $error = 0;
3857
3858 $sql = "INSERT INTO " . $this->db->prefix() . "element_element (";
3859 $sql .= "fk_source";
3860 $sql .= ", sourcetype";
3861 $sql .= ", fk_target";
3862 $sql .= ", targettype";
3863 $sql .= ") VALUES (";
3864 $sql .= ((int) $origin_id);
3865 $sql .= ", '" . $this->db->escape($origin) . "'";
3866 $sql .= ", " . ((int) $this->id);
3867 $sql .= ", '" . $this->db->escape($targettype) . "'";
3868 $sql .= ")";
3869
3870 dol_syslog(get_class($this) . "::add_object_linked", LOG_DEBUG);
3871 if ($this->db->query($sql)) {
3872 if (!$notrigger) {
3873 // Call trigger
3874 $this->context['link_origin'] = $origin;
3875 $this->context['link_origin_id'] = $origin_id;
3876 $result = $this->call_trigger('OBJECT_LINK_INSERT', $f_user);
3877 if ($result < 0) {
3878 $error++;
3879 }
3880 // End call triggers
3881 }
3882 } else {
3883 $this->error = $this->db->lasterror();
3884 $error++;
3885 }
3886
3887 if (!$error) {
3888 $this->db->commit();
3889 return 1;
3890 } else {
3891 $this->db->rollback();
3892 return 0;
3893 }
3894 }
3895
3918 public function fetchObjectLinked($sourceid = null, $sourcetype = '', $targetid = null, $targettype = '', $clause = 'OR', $alsosametype = 1, $orderby = 'sourcetype', $loadalsoobjects = 1)
3919 {
3920 global $conf, $hookmanager, $action;
3921
3922 // Important for pdf generation time reduction
3923 // This boolean is true if $this->linkedObjects has already been loaded with all objects linked without filter
3924 if ($this->id > 0 && !empty($this->linkedObjectsFullLoaded[$this->id])) {
3925 return 1;
3926 }
3927
3928 $this->linkedObjectsIds = array();
3929 $this->linkedObjects = array();
3930
3931 $justsource = false;
3932 $justtarget = false;
3933 $withtargettype = false;
3934 $withsourcetype = false;
3935
3936 $parameters = array('sourcetype'=>$sourcetype, 'sourceid'=>$sourceid, 'targettype'=>$targettype, 'targetid'=>$targetid);
3937 // Hook for explicitly set the targettype if it must be differtent than $this->element
3938 $reshook = $hookmanager->executeHooks('setLinkedObjectSourceTargetType', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3939 if ($reshook > 0) {
3940 if (!empty($hookmanager->resArray['sourcetype'])) $sourcetype = $hookmanager->resArray['sourcetype'];
3941 if (!empty($hookmanager->resArray['sourceid'])) $sourceid = $hookmanager->resArray['sourceid'];
3942 if (!empty($hookmanager->resArray['targettype'])) $targettype = $hookmanager->resArray['targettype'];
3943 if (!empty($hookmanager->resArray['targetid'])) $targetid = $hookmanager->resArray['targetid'];
3944 }
3945
3946 if (!empty($sourceid) && !empty($sourcetype) && empty($targetid)) {
3947 $justsource = true; // the source (id and type) is a search criteria
3948 if (!empty($targettype)) {
3949 $withtargettype = true;
3950 }
3951 }
3952 if (!empty($targetid) && !empty($targettype) && empty($sourceid)) {
3953 $justtarget = true; // the target (id and type) is a search criteria
3954 if (!empty($sourcetype)) {
3955 $withsourcetype = true;
3956 }
3957 }
3958
3959 $sourceid = (!empty($sourceid) ? $sourceid : $this->id);
3960 $targetid = (!empty($targetid) ? $targetid : $this->id);
3961 $sourcetype = (!empty($sourcetype) ? $sourcetype : $this->element);
3962 $targettype = (!empty($targettype) ? $targettype : $this->element);
3963
3964 /*if (empty($sourceid) && empty($targetid))
3965 {
3966 dol_syslog('Bad usage of function. No source nor target id defined (nor as parameter nor as object id)', LOG_ERR);
3967 return -1;
3968 }*/
3969
3970 // Links between objects are stored in table element_element
3971 $sql = "SELECT rowid, fk_source, sourcetype, fk_target, targettype";
3972 $sql .= " FROM ".$this->db->prefix()."element_element";
3973 $sql .= " WHERE ";
3974 if ($justsource || $justtarget) {
3975 if ($justsource) {
3976 $sql .= "fk_source = ".((int) $sourceid)." AND sourcetype = '".$this->db->escape($sourcetype)."'";
3977 if ($withtargettype) {
3978 $sql .= " AND targettype = '".$this->db->escape($targettype)."'";
3979 }
3980 } elseif ($justtarget) {
3981 $sql .= "fk_target = ".((int) $targetid)." AND targettype = '".$this->db->escape($targettype)."'";
3982 if ($withsourcetype) {
3983 $sql .= " AND sourcetype = '".$this->db->escape($sourcetype)."'";
3984 }
3985 }
3986 } else {
3987 $sql .= "(fk_source = ".((int) $sourceid)." AND sourcetype = '".$this->db->escape($sourcetype)."')";
3988 $sql .= " ".$clause." (fk_target = ".((int) $targetid)." AND targettype = '".$this->db->escape($targettype)."')";
3989 if ($loadalsoobjects && $this->id > 0 && $sourceid == $this->id && $sourcetype == $this->element && $targetid == $this->id && $targettype == $this->element && $clause == 'OR') {
3990 $this->linkedObjectsFullLoaded[$this->id] = true;
3991 }
3992 }
3993 $sql .= " ORDER BY ".$orderby;
3994
3995 dol_syslog(get_class($this)."::fetchObjectLink", LOG_DEBUG);
3996 $resql = $this->db->query($sql);
3997 if ($resql) {
3998 $num = $this->db->num_rows($resql);
3999 $i = 0;
4000 while ($i < $num) {
4001 $obj = $this->db->fetch_object($resql);
4002 if ($justsource || $justtarget) {
4003 if ($justsource) {
4004 $this->linkedObjectsIds[$obj->targettype][$obj->rowid] = $obj->fk_target;
4005 } elseif ($justtarget) {
4006 $this->linkedObjectsIds[$obj->sourcetype][$obj->rowid] = $obj->fk_source;
4007 }
4008 } else {
4009 if ($obj->fk_source == $sourceid && $obj->sourcetype == $sourcetype) {
4010 $this->linkedObjectsIds[$obj->targettype][$obj->rowid] = $obj->fk_target;
4011 }
4012 if ($obj->fk_target == $targetid && $obj->targettype == $targettype) {
4013 $this->linkedObjectsIds[$obj->sourcetype][$obj->rowid] = $obj->fk_source;
4014 }
4015 }
4016 $i++;
4017 }
4018
4019 if (!empty($this->linkedObjectsIds)) {
4020 $tmparray = $this->linkedObjectsIds;
4021 foreach ($tmparray as $objecttype => $objectids) { // $objecttype is a module name ('facture', 'mymodule', ...) or a module name with a suffix ('project_task', 'mymodule_myobj', ...)
4022 // Parse element/subelement (ex: project_task, cabinetmed_consultation, ...)
4023 $module = $element = $subelement = $objecttype;
4024 $regs = array();
4025 if ($objecttype != 'supplier_proposal' && $objecttype != 'order_supplier' && $objecttype != 'invoice_supplier'
4026 && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
4027 $module = $element = $regs[1];
4028 $subelement = $regs[2];
4029 }
4030
4031 $classpath = $element.'/class';
4032 // To work with non standard classpath or module name
4033 if ($objecttype == 'facture') {
4034 $classpath = 'compta/facture/class';
4035 } elseif ($objecttype == 'facturerec') {
4036 $classpath = 'compta/facture/class';
4037 $module = 'facture';
4038 } elseif ($objecttype == 'propal') {
4039 $classpath = 'comm/propal/class';
4040 } elseif ($objecttype == 'supplier_proposal') {
4041 $classpath = 'supplier_proposal/class';
4042 } elseif ($objecttype == 'shipping') {
4043 $classpath = 'expedition/class';
4044 $subelement = 'expedition';
4045 $module = 'expedition';
4046 } elseif ($objecttype == 'delivery') {
4047 $classpath = 'delivery/class';
4048 $subelement = 'delivery';
4049 $module = 'delivery_note';
4050 } elseif ($objecttype == 'invoice_supplier' || $objecttype == 'order_supplier') {
4051 $classpath = 'fourn/class';
4052 $module = 'fournisseur';
4053 } elseif ($objecttype == 'fichinter') {
4054 $classpath = 'fichinter/class';
4055 $subelement = 'fichinter';
4056 $module = 'ficheinter';
4057 } elseif ($objecttype == 'subscription') {
4058 $classpath = 'adherents/class';
4059 $module = 'adherent';
4060 } elseif ($objecttype == 'contact') {
4061 $module = 'societe';
4062 }
4063 // Set classfile
4064 $classfile = strtolower($subelement);
4065 $classname = ucfirst($subelement);
4066
4067 if ($objecttype == 'order') {
4068 $classfile = 'commande';
4069 $classname = 'Commande';
4070 } elseif ($objecttype == 'invoice_supplier') {
4071 $classfile = 'fournisseur.facture';
4072 $classname = 'FactureFournisseur';
4073 } elseif ($objecttype == 'order_supplier') {
4074 $classfile = 'fournisseur.commande';
4075 $classname = 'CommandeFournisseur';
4076 } elseif ($objecttype == 'supplier_proposal') {
4077 $classfile = 'supplier_proposal';
4078 $classname = 'SupplierProposal';
4079 } elseif ($objecttype == 'facturerec') {
4080 $classfile = 'facture-rec';
4081 $classname = 'FactureRec';
4082 } elseif ($objecttype == 'subscription') {
4083 $classfile = 'subscription';
4084 $classname = 'Subscription';
4085 } elseif ($objecttype == 'project' || $objecttype == 'projet') {
4086 $classpath = 'projet/class';
4087 $classfile = 'project';
4088 $classname = 'Project';
4089 } elseif ($objecttype == 'conferenceorboothattendee') {
4090 $classpath = 'eventorganization/class';
4091 $classfile = 'conferenceorboothattendee';
4092 $classname = 'ConferenceOrBoothAttendee';
4093 $module = 'eventorganization';
4094 } elseif ($objecttype == 'conferenceorbooth') {
4095 $classpath = 'eventorganization/class';
4096 $classfile = 'conferenceorbooth';
4097 $classname = 'ConferenceOrBooth';
4098 $module = 'eventorganization';
4099 } elseif ($objecttype == 'mo') {
4100 $classpath = 'mrp/class';
4101 $classfile = 'mo';
4102 $classname = 'Mo';
4103 $module = 'mrp';
4104 }
4105
4106 // Here $module, $classfile and $classname are set, we can use them.
4107 if (isModEnabled($module) && (($element != $this->element) || $alsosametype)) {
4108 if ($loadalsoobjects && (is_numeric($loadalsoobjects) || ($loadalsoobjects === $objecttype))) {
4109 dol_include_once('/'.$classpath.'/'.$classfile.'.class.php');
4110 //print '/'.$classpath.'/'.$classfile.'.class.php '.class_exists($classname);
4111 if (class_exists($classname)) {
4112 foreach ($objectids as $i => $objectid) { // $i is rowid into llx_element_element
4113 $object = new $classname($this->db);
4114 $ret = $object->fetch($objectid);
4115 if ($ret >= 0) {
4116 $this->linkedObjects[$objecttype][$i] = $object;
4117 }
4118 }
4119 }
4120 }
4121 } else {
4122 unset($this->linkedObjectsIds[$objecttype]);
4123 }
4124 }
4125 }
4126 return 1;
4127 } else {
4128 dol_print_error($this->db);
4129 return -1;
4130 }
4131 }
4132
4139 public function clearObjectLinkedCache()
4140 {
4141 if ($this->id > 0 && !empty($this->linkedObjectsFullLoaded[$this->id])) {
4142 unset($this->linkedObjectsFullLoaded[$this->id]);
4143 }
4144
4145 return 1;
4146 }
4147
4160 public function updateObjectLinked($sourceid = null, $sourcetype = '', $targetid = null, $targettype = '', $f_user = null, $notrigger = 0)
4161 {
4162 global $user;
4163 $updatesource = false;
4164 $updatetarget = false;
4165 $f_user = isset($f_user) ? $f_user : $user;
4166
4167 if (!empty($sourceid) && !empty($sourcetype) && empty($targetid) && empty($targettype)) {
4168 $updatesource = true;
4169 } elseif (empty($sourceid) && empty($sourcetype) && !empty($targetid) && !empty($targettype)) {
4170 $updatetarget = true;
4171 }
4172
4173 $this->db->begin();
4174 $error = 0;
4175
4176 $sql = "UPDATE " . $this->db->prefix() . "element_element SET ";
4177 if ($updatesource) {
4178 $sql .= "fk_source = " . ((int) $sourceid);
4179 $sql .= ", sourcetype = '" . $this->db->escape($sourcetype) . "'";
4180 $sql .= " WHERE fk_target = " . ((int) $this->id);
4181 $sql .= " AND targettype = '" . $this->db->escape($this->element) . "'";
4182 } elseif ($updatetarget) {
4183 $sql .= "fk_target = " . ((int) $targetid);
4184 $sql .= ", targettype = '" . $this->db->escape($targettype) . "'";
4185 $sql .= " WHERE fk_source = " . ((int) $this->id);
4186 $sql .= " AND sourcetype = '" . $this->db->escape($this->element) . "'";
4187 }
4188
4189 dol_syslog(get_class($this) . "::updateObjectLinked", LOG_DEBUG);
4190 if ($this->db->query($sql)) {
4191 if (!$notrigger) {
4192 // Call trigger
4193 $this->context['link_source_id'] = $sourceid;
4194 $this->context['link_source_type'] = $sourcetype;
4195 $this->context['link_target_id'] = $targetid;
4196 $this->context['link_target_type'] = $targettype;
4197 $result = $this->call_trigger('OBJECT_LINK_MODIFY', $f_user);
4198 if ($result < 0) {
4199 $error++;
4200 }
4201 // End call triggers
4202 }
4203 } else {
4204 $this->error = $this->db->lasterror();
4205 $error++;
4206 }
4207
4208 if (!$error) {
4209 $this->db->commit();
4210 return 1;
4211 } else {
4212 $this->db->rollback();
4213 return -1;
4214 }
4215 }
4216
4230 public function deleteObjectLinked($sourceid = null, $sourcetype = '', $targetid = null, $targettype = '', $rowid = '', $f_user = null, $notrigger = 0)
4231 {
4232 global $user;
4233 $deletesource = false;
4234 $deletetarget = false;
4235 $f_user = isset($f_user) ? $f_user : $user;
4236
4237 if (!empty($sourceid) && !empty($sourcetype) && empty($targetid) && empty($targettype)) {
4238 $deletesource = true;
4239 } elseif (empty($sourceid) && empty($sourcetype) && !empty($targetid) && !empty($targettype)) {
4240 $deletetarget = true;
4241 }
4242
4243 $sourceid = (!empty($sourceid) ? $sourceid : $this->id);
4244 $sourcetype = (!empty($sourcetype) ? $sourcetype : $this->element);
4245 $targetid = (!empty($targetid) ? $targetid : $this->id);
4246 $targettype = (!empty($targettype) ? $targettype : $this->element);
4247 $this->db->begin();
4248 $error = 0;
4249
4250 if (!$notrigger) {
4251 // Call trigger
4252 $this->context['link_id'] = $rowid;
4253 $this->context['link_source_id'] = $sourceid;
4254 $this->context['link_source_type'] = $sourcetype;
4255 $this->context['link_target_id'] = $targetid;
4256 $this->context['link_target_type'] = $targettype;
4257 $result = $this->call_trigger('OBJECT_LINK_DELETE', $f_user);
4258 if ($result < 0) {
4259 $error++;
4260 }
4261 // End call triggers
4262 }
4263
4264 if (!$error) {
4265 $sql = "DELETE FROM " . $this->db->prefix() . "element_element";
4266 $sql .= " WHERE";
4267 if ($rowid > 0) {
4268 $sql .= " rowid = " . ((int) $rowid);
4269 } else {
4270 if ($deletesource) {
4271 $sql .= " fk_source = " . ((int) $sourceid) . " AND sourcetype = '" . $this->db->escape($sourcetype) . "'";
4272 $sql .= " AND fk_target = " . ((int) $this->id) . " AND targettype = '" . $this->db->escape($this->element) . "'";
4273 } elseif ($deletetarget) {
4274 $sql .= " fk_target = " . ((int) $targetid) . " AND targettype = '" . $this->db->escape($targettype) . "'";
4275 $sql .= " AND fk_source = " . ((int) $this->id) . " AND sourcetype = '" . $this->db->escape($this->element) . "'";
4276 } else {
4277 $sql .= " (fk_source = " . ((int) $this->id) . " AND sourcetype = '" . $this->db->escape($this->element) . "')";
4278 $sql .= " OR";
4279 $sql .= " (fk_target = " . ((int) $this->id) . " AND targettype = '" . $this->db->escape($this->element) . "')";
4280 }
4281 }
4282
4283 dol_syslog(get_class($this) . "::deleteObjectLinked", LOG_DEBUG);
4284 if (!$this->db->query($sql)) {
4285 $this->error = $this->db->lasterror();
4286 $this->errors[] = $this->error;
4287 $error++;
4288 }
4289 }
4290
4291 if (!$error) {
4292 $this->db->commit();
4293 return 1;
4294 } else {
4295 $this->db->rollback();
4296 return 0;
4297 }
4298 }
4299
4309 public static function getAllItemsLinkedByObjectID($fk_object_where, $field_select, $field_where, $table_element)
4310 {
4311 if (empty($fk_object_where) || empty($field_where) || empty($table_element)) {
4312 return -1;
4313 }
4314
4315 global $db;
4316
4317 $sql = "SELECT ".$field_select." FROM ".$db->prefix().$table_element." WHERE ".$field_where." = ".((int) $fk_object_where);
4318 $resql = $db->query($sql);
4319
4320 $TRes = array();
4321 if (!empty($resql)) {
4322 while ($res = $db->fetch_object($resql)) {
4323 $TRes[] = $res->{$field_select};
4324 }
4325 }
4326
4327 return $TRes;
4328 }
4329
4338 public static function deleteAllItemsLinkedByObjectID($fk_object_where, $field_where, $table_element)
4339 {
4340 if (empty($fk_object_where) || empty($field_where) || empty($table_element)) {
4341 return -1;
4342 }
4343
4344 global $db;
4345
4346 $sql = "DELETE FROM ".$db->prefix().$table_element." WHERE ".$field_where." = ".((int) $fk_object_where);
4347 $resql = $db->query($sql);
4348
4349 if (empty($resql)) {
4350 return 0;
4351 }
4352
4353 return 1;
4354 }
4355
4366 public function setStatut($status, $elementId = null, $elementType = '', $trigkey = '', $fieldstatus = 'fk_statut')
4367 {
4368 global $user, $langs, $conf;
4369
4370 $savElementId = $elementId; // To be used later to know if we were using the method using the id of this or not.
4371
4372 $elementId = (!empty($elementId) ? $elementId : $this->id);
4373 $elementTable = (!empty($elementType) ? $elementType : $this->table_element);
4374
4375 $this->db->begin();
4376
4377 if ($elementTable == 'facture_rec') {
4378 $fieldstatus = "suspended";
4379 }
4380 if ($elementTable == 'mailing') {
4381 $fieldstatus = "statut";
4382 }
4383 if ($elementTable == 'cronjob') {
4384 $fieldstatus = "status";
4385 }
4386 if ($elementTable == 'user') {
4387 $fieldstatus = "statut";
4388 }
4389 if ($elementTable == 'expensereport') {
4390 $fieldstatus = "fk_statut";
4391 }
4392 if ($elementTable == 'commande_fournisseur_dispatch') {
4393 $fieldstatus = "status";
4394 }
4395 if (isset($this->fields) && is_array($this->fields) && array_key_exists('status', $this->fields)) {
4396 $fieldstatus = 'status';
4397 }
4398
4399 $sql = "UPDATE ".$this->db->prefix().$elementTable;
4400 $sql .= " SET ".$fieldstatus." = ".((int) $status);
4401 // If status = 1 = validated, update also fk_user_valid
4402 // TODO Replace the test on $elementTable by doing a test on existence of the field in $this->fields
4403 if ($status == 1 && in_array($elementTable, array('expensereport', 'inventory'))) {
4404 $sql .= ", fk_user_valid = ".((int) $user->id);
4405 }
4406 if ($status == 1 && in_array($elementTable, array('expensereport'))) {
4407 $sql .= ", date_valid = '".$this->db->idate(dol_now())."'";
4408 }
4409 if ($status == 1 && in_array($elementTable, array('inventory'))) {
4410 $sql .= ", date_validation = '".$this->db->idate(dol_now())."'";
4411 }
4412 $sql .= " WHERE rowid = ".((int) $elementId);
4413 $sql .= " AND ".$fieldstatus." <> ".((int) $status); // We avoid update if status already correct
4414
4415 dol_syslog(get_class($this)."::setStatut", LOG_DEBUG);
4416 $resql = $this->db->query($sql);
4417 if ($resql) {
4418 $error = 0;
4419
4420 $nb_rows_affected = $this->db->affected_rows($resql); // should be 1 or 0 if status was already correct
4421
4422 if ($nb_rows_affected > 0) {
4423 if (empty($trigkey)) {
4424 // Try to guess trigkey (for backward compatibility, now we should have trigkey defined into the call of setStatus)
4425 if ($this->element == 'supplier_proposal' && $status == 2) {
4426 $trigkey = 'SUPPLIER_PROPOSAL_SIGN'; // 2 = SupplierProposal::STATUS_SIGNED. Can't use constant into this generic class
4427 }
4428 if ($this->element == 'supplier_proposal' && $status == 3) {
4429 $trigkey = 'SUPPLIER_PROPOSAL_REFUSE'; // 3 = SupplierProposal::STATUS_REFUSED. Can't use constant into this generic class
4430 }
4431 if ($this->element == 'supplier_proposal' && $status == 4) {
4432 $trigkey = 'SUPPLIER_PROPOSAL_CLOSE'; // 4 = SupplierProposal::STATUS_CLOSED. Can't use constant into this generic class
4433 }
4434 if ($this->element == 'fichinter' && $status == 3) {
4435 $trigkey = 'FICHINTER_CLASSIFY_DONE';
4436 }
4437 if ($this->element == 'fichinter' && $status == 2) {
4438 $trigkey = 'FICHINTER_CLASSIFY_BILLED';
4439 }
4440 if ($this->element == 'fichinter' && $status == 1) {
4441 $trigkey = 'FICHINTER_CLASSIFY_UNBILLED';
4442 }
4443 }
4444
4445 if ($trigkey) {
4446 // Call trigger
4447 $result = $this->call_trigger($trigkey, $user);
4448 if ($result < 0) {
4449 $error++;
4450 }
4451 // End call triggers
4452 }
4453 } else {
4454 // The status was probably already good. We do nothing more, no triggers.
4455 }
4456
4457 if (!$error) {
4458 $this->db->commit();
4459
4460 if (empty($savElementId)) {
4461 // If the element we update is $this (so $elementId was provided as null)
4462 if ($fieldstatus == 'tosell') {
4463 $this->status = $status;
4464 } elseif ($fieldstatus == 'tobuy') {
4465 $this->status_buy = $status;
4466 } else {
4467 $this->statut = $status;
4468 $this->status = $status;
4469 }
4470 }
4471
4472 return 1;
4473 } else {
4474 $this->db->rollback();
4475 dol_syslog(get_class($this)."::setStatut ".$this->error, LOG_ERR);
4476 return -1;
4477 }
4478 } else {
4479 $this->error = $this->db->lasterror();
4480 $this->db->rollback();
4481 return -1;
4482 }
4483 }
4484
4485
4493 public function getCanvas($id = 0, $ref = '')
4494 {
4495 global $conf;
4496
4497 if (empty($id) && empty($ref)) {
4498 return 0;
4499 }
4500 if (!empty($conf->global->MAIN_DISABLE_CANVAS)) {
4501 return 0; // To increase speed. Not enabled by default.
4502 }
4503
4504 // Clean parameters
4505 $ref = trim($ref);
4506
4507 $sql = "SELECT rowid, canvas";
4508 $sql .= " FROM ".$this->db->prefix().$this->table_element;
4509 $sql .= " WHERE entity IN (".getEntity($this->element).")";
4510 if (!empty($id)) {
4511 $sql .= " AND rowid = ".((int) $id);
4512 }
4513 if (!empty($ref)) {
4514 $sql .= " AND ref = '".$this->db->escape($ref)."'";
4515 }
4516
4517 $resql = $this->db->query($sql);
4518 if ($resql) {
4519 $obj = $this->db->fetch_object($resql);
4520 if ($obj) {
4521 $this->canvas = $obj->canvas;
4522 return 1;
4523 } else {
4524 return 0;
4525 }
4526 } else {
4527 dol_print_error($this->db);
4528 return -1;
4529 }
4530 }
4531
4532
4539 public function getSpecialCode($lineid)
4540 {
4541 $sql = "SELECT special_code FROM ".$this->db->prefix().$this->table_element_line;
4542 $sql .= " WHERE rowid = ".((int) $lineid);
4543 $resql = $this->db->query($sql);
4544 if ($resql) {
4545 $row = $this->db->fetch_row($resql);
4546 return (!empty($row[0]) ? $row[0] : 0);
4547 }
4548
4549 return 0;
4550 }
4551
4560 public function isObjectUsed($id = 0, $entity = 0)
4561 {
4562 global $langs;
4563
4564 if (empty($id)) {
4565 $id = $this->id;
4566 }
4567
4568 // Check parameters
4569 if (!isset($this->childtables) || !is_array($this->childtables) || count($this->childtables) == 0) {
4570 dol_print_error('Called isObjectUsed on a class with property this->childtables not defined');
4571 return -1;
4572 }
4573
4574 $arraytoscan = $this->childtables; // array('tablename'=>array('fk_element'=>'parentfield'), ...) or array('tablename'=>array('parent'=>table_parent, 'parentkey'=>'nameoffieldforparentfkkey'), ...)
4575 // For backward compatibility, we check if array is old format array('tablename1', 'tablename2', ...)
4576 $tmparray = array_keys($this->childtables);
4577 if (is_numeric($tmparray[0])) {
4578 $arraytoscan = array_flip($this->childtables);
4579 }
4580
4581 // Test if child exists
4582 $haschild = 0;
4583 foreach ($arraytoscan as $table => $element) {
4584 //print $id.'-'.$table.'-'.$elementname.'<br>';
4585 // Check if element can be deleted
4586 $sql = "SELECT COUNT(*) as nb";
4587 $sql.= " FROM ".$this->db->prefix().$table." as c";
4588 if (!empty($element['parent']) && !empty($element['parentkey'])) {
4589 $sql.= ", ".$this->db->prefix().$element['parent']." as p";
4590 }
4591 if (!empty($element['fk_element'])) {
4592 $sql.= " WHERE c.".$element['fk_element']." = ".((int) $id);
4593 } else {
4594 $sql.= " WHERE c.".$this->fk_element." = ".((int) $id);
4595 }
4596 if (!empty($element['parent']) && !empty($element['parentkey'])) {
4597 $sql.= " AND c.".$element['parentkey']." = p.rowid";
4598 }
4599 if (!empty($element['parent']) && !empty($element['parenttypefield']) && !empty($element['parenttypevalue'])) {
4600 $sql.= " AND c.".$element['parenttypefield']." = '".$this->db->escape($element['parenttypevalue'])."'";
4601 }
4602 if (!empty($entity)) {
4603 if (!empty($element['parent']) && !empty($element['parentkey'])) {
4604 $sql.= " AND p.entity = ".((int) $entity);
4605 } else {
4606 $sql.= " AND c.entity = ".((int) $entity);
4607 }
4608 }
4609
4610 $resql = $this->db->query($sql);
4611 if ($resql) {
4612 $obj = $this->db->fetch_object($resql);
4613 if ($obj->nb > 0) {
4614 $langs->load("errors");
4615 //print 'Found into table '.$table.', type '.$langs->transnoentitiesnoconv($elementname).', haschild='.$haschild;
4616 $haschild += $obj->nb;
4617 if (is_numeric($element)) { // very old usage array('table1', 'table2', ...)
4618 $this->errors[] = $langs->transnoentitiesnoconv("ErrorRecordHasAtLeastOneChildOfType", method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref, $table);
4619 } elseif (is_string($element)) { // old usage array('table1' => 'TranslateKey1', 'table2' => 'TranslateKey2', ...)
4620 $this->errors[] = $langs->transnoentitiesnoconv("ErrorRecordHasAtLeastOneChildOfType", method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref, $langs->transnoentitiesnoconv($element));
4621 } else { // new usage: $element['name']=Translation key
4622 $this->errors[] = $langs->transnoentitiesnoconv("ErrorRecordHasAtLeastOneChildOfType", method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref, $langs->transnoentitiesnoconv($element['name']));
4623 }
4624 break; // We found at least one, we stop here
4625 }
4626 } else {
4627 $this->errors[] = $this->db->lasterror();
4628 return -1;
4629 }
4630 }
4631 if ($haschild > 0) {
4632 $this->errors[] = "ErrorRecordHasChildren";
4633 return $haschild;
4634 } else {
4635 return 0;
4636 }
4637 }
4638
4645 public function hasProductsOrServices($predefined = -1)
4646 {
4647 $nb = 0;
4648
4649 foreach ($this->lines as $key => $val) {
4650 $qualified = 0;
4651 if ($predefined == -1) {
4652 $qualified = 1;
4653 }
4654 if ($predefined == 1 && $val->fk_product > 0) {
4655 $qualified = 1;
4656 }
4657 if ($predefined == 0 && $val->fk_product <= 0) {
4658 $qualified = 1;
4659 }
4660 if ($predefined == 2 && $val->fk_product > 0 && $val->product_type == 0) {
4661 $qualified = 1;
4662 }
4663 if ($predefined == 3 && $val->fk_product > 0 && $val->product_type == 1) {
4664 $qualified = 1;
4665 }
4666 if ($qualified) {
4667 $nb++;
4668 }
4669 }
4670 dol_syslog(get_class($this).'::hasProductsOrServices we found '.$nb.' qualified lines of products/servcies');
4671 return $nb;
4672 }
4673
4679 public function getTotalDiscount()
4680 {
4681 if (!empty($this->table_element_line) ) {
4682 $total_discount = 0.00;
4683
4684 $sql = "SELECT subprice as pu_ht, qty, remise_percent, total_ht";
4685 $sql .= " FROM ".$this->db->prefix().$this->table_element_line;
4686 $sql .= " WHERE ".$this->fk_element." = ".((int) $this->id);
4687
4688 dol_syslog(get_class($this).'::getTotalDiscount', LOG_DEBUG);
4689 $resql = $this->db->query($sql);
4690 if ($resql) {
4691 $num = $this->db->num_rows($resql);
4692 $i = 0;
4693 while ($i < $num) {
4694 $obj = $this->db->fetch_object($resql);
4695
4696 $pu_ht = $obj->pu_ht;
4697 $qty = $obj->qty;
4698 $total_ht = $obj->total_ht;
4699
4700 $total_discount_line = floatval(price2num(($pu_ht * $qty) - $total_ht, 'MT'));
4701 $total_discount += $total_discount_line;
4702
4703 $i++;
4704 }
4705 }
4706
4707 //print $total_discount; exit;
4708 return price2num($total_discount);
4709 }
4710
4711 return null;
4712 }
4713
4714
4721 public function getTotalWeightVolume()
4722 {
4723 $totalWeight = 0;
4724 $totalVolume = 0;
4725 // defined for shipment only
4726 $totalOrdered = '';
4727 // defined for shipment only
4728 $totalToShip = '';
4729
4730 foreach ($this->lines as $line) {
4731 if (isset($line->qty_asked)) {
4732 if (empty($totalOrdered)) {
4733 $totalOrdered = 0; // Avoid warning because $totalOrdered is ''
4734 }
4735 $totalOrdered += $line->qty_asked; // defined for shipment only
4736 }
4737 if (isset($line->qty_shipped)) {
4738 if (empty($totalToShip)) {
4739 $totalToShip = 0; // Avoid warning because $totalToShip is ''
4740 }
4741 $totalToShip += $line->qty_shipped; // defined for shipment only
4742 } elseif ($line->element == 'commandefournisseurdispatch' && isset($line->qty)) {
4743 if (empty($totalToShip)) {
4744 $totalToShip = 0;
4745 }
4746 $totalToShip += $line->qty; // defined for reception only
4747 }
4748
4749 // Define qty, weight, volume, weight_units, volume_units
4750 if ($this->element == 'shipping') {
4751 // for shipments
4752 $qty = $line->qty_shipped ? $line->qty_shipped : 0;
4753 } else {
4754 $qty = $line->qty ? $line->qty : 0;
4755 }
4756
4757 $weight = !empty($line->weight) ? $line->weight : 0;
4758 ($weight == 0 && !empty($line->product->weight)) ? $weight = $line->product->weight : 0;
4759 $volume = !empty($line->volume) ? $line->volume : 0;
4760 ($volume == 0 && !empty($line->product->volume)) ? $volume = $line->product->volume : 0;
4761
4762 $weight_units = !empty($line->weight_units) ? $line->weight_units : 0;
4763 ($weight_units == 0 && !empty($line->product->weight_units)) ? $weight_units = $line->product->weight_units : 0;
4764 $volume_units = !empty($line->volume_units) ? $line->volume_units : 0;
4765 ($volume_units == 0 && !empty($line->product->volume_units)) ? $volume_units = $line->product->volume_units : 0;
4766
4767 $weightUnit = 0;
4768 $volumeUnit = 0;
4769 if (!empty($weight_units)) {
4770 $weightUnit = $weight_units;
4771 }
4772 if (!empty($volume_units)) {
4773 $volumeUnit = $volume_units;
4774 }
4775
4776 if (empty($totalWeight)) {
4777 $totalWeight = 0; // Avoid warning because $totalWeight is ''
4778 }
4779 if (empty($totalVolume)) {
4780 $totalVolume = 0; // Avoid warning because $totalVolume is ''
4781 }
4782
4783 //var_dump($line->volume_units);
4784 if ($weight_units < 50) { // < 50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch)
4785 $trueWeightUnit = pow(10, $weightUnit);
4786 $totalWeight += $weight * $qty * $trueWeightUnit;
4787 } else {
4788 if ($weight_units == 99) {
4789 // conversion 1 Pound = 0.45359237 KG
4790 $trueWeightUnit = 0.45359237;
4791 $totalWeight += $weight * $qty * $trueWeightUnit;
4792 } elseif ($weight_units == 98) {
4793 // conversion 1 Ounce = 0.0283495 KG
4794 $trueWeightUnit = 0.0283495;
4795 $totalWeight += $weight * $qty * $trueWeightUnit;
4796 } else {
4797 $totalWeight += $weight * $qty; // This may be wrong if we mix different units
4798 }
4799 }
4800 if ($volume_units < 50) { // >50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch)
4801 //print $line->volume."x".$line->volume_units."x".($line->volume_units < 50)."x".$volumeUnit;
4802 $trueVolumeUnit = pow(10, $volumeUnit);
4803 //print $line->volume;
4804 $totalVolume += $volume * $qty * $trueVolumeUnit;
4805 } else {
4806 $totalVolume += $volume * $qty; // This may be wrong if we mix different units
4807 }
4808 }
4809
4810 return array('weight'=>$totalWeight, 'volume'=>$totalVolume, 'ordered'=>$totalOrdered, 'toship'=>$totalToShip);
4811 }
4812
4813
4819 public function setExtraParameters()
4820 {
4821 $this->db->begin();
4822
4823 $extraparams = (!empty($this->extraparams) ? json_encode($this->extraparams) : null);
4824
4825 $sql = "UPDATE ".$this->db->prefix().$this->table_element;
4826 $sql .= " SET extraparams = ".(!empty($extraparams) ? "'".$this->db->escape($extraparams)."'" : "null");
4827 $sql .= " WHERE rowid = ".((int) $this->id);
4828
4829 dol_syslog(get_class($this)."::setExtraParameters", LOG_DEBUG);
4830 $resql = $this->db->query($sql);
4831 if (!$resql) {
4832 $this->error = $this->db->lasterror();
4833 $this->db->rollback();
4834 return -1;
4835 } else {
4836 $this->db->commit();
4837 return 1;
4838 }
4839 }
4840
4841
4842 // --------------------
4843 // TODO: All functions here must be redesigned and moved as they are not business functions but output functions
4844 // --------------------
4845
4846 /* This is to show add lines */
4847
4857 public function formAddObjectLine($dateSelector, $seller, $buyer, $defaulttpldir = '/core/tpl')
4858 {
4859 global $conf, $user, $langs, $object, $hookmanager, $extrafields;
4860 global $form;
4861
4862 // Line extrafield
4863 if (!is_object($extrafields)) {
4864 require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
4865 $extrafields = new ExtraFields($this->db);
4866 }
4867 $extrafields->fetch_name_optionals_label($this->table_element_line);
4868
4869 // Output template part (modules that overwrite templates must declare this into descriptor)
4870 // Use global variables + $dateSelector + $seller and $buyer
4871 // Note: This is deprecated. If you need to overwrite the tpl file, use instead the hook 'formAddObjectLine'.
4872 $dirtpls = array_merge($conf->modules_parts['tpl'], array($defaulttpldir));
4873 foreach ($dirtpls as $module => $reldir) {
4874 if (!empty($module)) {
4875 $tpl = dol_buildpath($reldir.'/objectline_create.tpl.php');
4876 } else {
4877 $tpl = DOL_DOCUMENT_ROOT.$reldir.'/objectline_create.tpl.php';
4878 }
4879
4880 if (empty($conf->file->strict_mode)) {
4881 $res = @include $tpl;
4882 } else {
4883 $res = include $tpl; // for debug
4884 }
4885 if ($res) {
4886 break;
4887 }
4888 }
4889 }
4890
4891
4892
4893 /* This is to show array of line of details */
4894
4895
4910 public function printObjectLines($action, $seller, $buyer, $selected = 0, $dateSelector = 0, $defaulttpldir = '/core/tpl')
4911 {
4912 global $conf, $hookmanager, $langs, $user, $form, $extrafields, $object;
4913 // TODO We should not use global var for this
4914 global $inputalsopricewithtax, $usemargins, $disableedit, $disablemove, $disableremove, $outputalsopricetotalwithtax;
4915
4916 // Define usemargins
4917 $usemargins = 0;
4918 if (isModEnabled('margin') && !empty($this->element) && in_array($this->element, array('facture', 'facturerec', 'propal', 'commande'))) {
4919 $usemargins = 1;
4920 }
4921
4922 $num = count($this->lines);
4923
4924 // Line extrafield
4925 if (!is_object($extrafields)) {
4926 require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
4927 $extrafields = new ExtraFields($this->db);
4928 }
4929 $extrafields->fetch_name_optionals_label($this->table_element_line);
4930
4931 $parameters = array('num'=>$num, 'dateSelector'=>$dateSelector, 'seller'=>$seller, 'buyer'=>$buyer, 'selected'=>$selected, 'table_element_line'=>$this->table_element_line);
4932 $reshook = $hookmanager->executeHooks('printObjectLineTitle', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
4933 if (empty($reshook)) {
4934 // Output template part (modules that overwrite templates must declare this into descriptor)
4935 // Use global variables + $dateSelector + $seller and $buyer
4936 // Note: This is deprecated. If you need to overwrite the tpl file, use instead the hook.
4937 $dirtpls = array_merge($conf->modules_parts['tpl'], array($defaulttpldir));
4938 foreach ($dirtpls as $module => $reldir) {
4939 $res = 0;
4940 if (!empty($module)) {
4941 $tpl = dol_buildpath($reldir.'/objectline_title.tpl.php');
4942 } else {
4943 $tpl = DOL_DOCUMENT_ROOT.$reldir.'/objectline_title.tpl.php';
4944 }
4945 if (file_exists($tpl)) {
4946 if (empty($conf->file->strict_mode)) {
4947 $res = @include $tpl;
4948 } else {
4949 $res = include $tpl; // for debug
4950 }
4951 }
4952 if ($res) {
4953 break;
4954 }
4955 }
4956 }
4957
4958 $i = 0;
4959
4960 print "<!-- begin printObjectLines() --><tbody>\n";
4961 foreach ($this->lines as $line) {
4962 //Line extrafield
4963 $line->fetch_optionals();
4964
4965 //if (is_object($hookmanager) && (($line->product_type == 9 && !empty($line->special_code)) || !empty($line->fk_parent_line)))
4966 if (is_object($hookmanager)) { // Old code is commented on preceding line.
4967 if (empty($line->fk_parent_line)) {
4968 $parameters = array('line'=>$line, 'num'=>$num, 'i'=>$i, 'dateSelector'=>$dateSelector, 'seller'=>$seller, 'buyer'=>$buyer, 'selected'=>$selected, 'table_element_line'=>$line->table_element, 'defaulttpldir'=>$defaulttpldir);
4969 $reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
4970 } else {
4971 $parameters = array('line'=>$line, 'num'=>$num, 'i'=>$i, 'dateSelector'=>$dateSelector, 'seller'=>$seller, 'buyer'=>$buyer, 'selected'=>$selected, 'table_element_line'=>$line->table_element, 'fk_parent_line'=>$line->fk_parent_line, 'defaulttpldir'=>$defaulttpldir);
4972 $reshook = $hookmanager->executeHooks('printObjectSubLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
4973 }
4974 }
4975 if (empty($reshook)) {
4976 $this->printObjectLine($action, $line, '', $num, $i, $dateSelector, $seller, $buyer, $selected, $extrafields, $defaulttpldir);
4977 }
4978
4979 $i++;
4980 }
4981 print "</tbody><!-- end printObjectLines() -->\n";
4982 }
4983
5001 public function printObjectLine($action, $line, $var, $num, $i, $dateSelector, $seller, $buyer, $selected = 0, $extrafields = null, $defaulttpldir = '/core/tpl')
5002 {
5003 global $conf, $langs, $user, $object, $hookmanager;
5004 global $form;
5005 global $object_rights, $disableedit, $disablemove, $disableremove; // TODO We should not use global var for this !
5006
5007 $object_rights = $this->getRights();
5008
5009 $text = '';
5010 $description = '';
5011
5012 // Line in view mode
5013 if ($action != 'editline' || $selected != $line->id) {
5014 // Product
5015 if (!empty($line->fk_product) && $line->fk_product > 0) {
5016 $product_static = new Product($this->db);
5017 $product_static->fetch($line->fk_product);
5018
5019 $product_static->ref = $line->ref; //can change ref in hook
5020 $product_static->label = !empty($line->label) ? $line->label : ""; //can change label in hook
5021
5022 $text = $product_static->getNomUrl(1);
5023
5024 // Define output language and label
5025 if (getDolGlobalInt('MAIN_MULTILANGS')) {
5026 if (property_exists($this, 'socid') && !is_object($this->thirdparty)) {
5027 dol_print_error('', 'Error: Method printObjectLine was called on an object and object->fetch_thirdparty was not done before');
5028 return;
5029 }
5030
5031 $prod = new Product($this->db);
5032 $prod->fetch($line->fk_product);
5033
5034 $outputlangs = $langs;
5035 $newlang = '';
5036 if (empty($newlang) && GETPOST('lang_id', 'aZ09')) {
5037 $newlang = GETPOST('lang_id', 'aZ09');
5038 }
5039 if (!empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE) && empty($newlang) && is_object($this->thirdparty)) {
5040 $newlang = $this->thirdparty->default_lang; // To use language of customer
5041 }
5042 if (!empty($newlang)) {
5043 $outputlangs = new Translate("", $conf);
5044 $outputlangs->setDefaultLang($newlang);
5045 }
5046
5047 $label = (!empty($prod->multilangs[$outputlangs->defaultlang]["label"])) ? $prod->multilangs[$outputlangs->defaultlang]["label"] : $line->product_label;
5048 } else {
5049 $label = $line->product_label;
5050 }
5051
5052 $text .= ' - '.(!empty($line->label) ? $line->label : $label);
5053 $description .= (getDolGlobalInt('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE') ? '' : (!empty($line->description) ? dol_htmlentitiesbr($line->description) : '')); // Description is what to show on popup. We shown nothing if already into desc.
5054 }
5055
5056 $line->pu_ttc = price2num((!empty($line->subprice) ? $line->subprice : 0) * (1 + ((!empty($line->tva_tx) ? $line->tva_tx : 0) / 100)), 'MU');
5057
5058 // Output template part (modules that overwrite templates must declare this into descriptor)
5059 // Use global variables + $dateSelector + $seller and $buyer
5060 // Note: This is deprecated. If you need to overwrite the tpl file, use instead the hook printObjectLine and printObjectSubLine.
5061 $dirtpls = array_merge($conf->modules_parts['tpl'], array($defaulttpldir));
5062 foreach ($dirtpls as $module => $reldir) {
5063 $res = 0;
5064 if (!empty($module)) {
5065 $tpl = dol_buildpath($reldir.'/objectline_view.tpl.php');
5066 } else {
5067 $tpl = DOL_DOCUMENT_ROOT.$reldir.'/objectline_view.tpl.php';
5068 }
5069 if (file_exists($tpl)) {
5070 if (empty($conf->file->strict_mode)) {
5071 $res = @include $tpl;
5072 } else {
5073 $res = include $tpl; // for debug
5074 }
5075 }
5076 if ($res) {
5077 break;
5078 }
5079 }
5080 }
5081
5082 // Line in update mode
5083 if ($this->statut == 0 && $action == 'editline' && $selected == $line->id) {
5084 $label = (!empty($line->label) ? $line->label : (($line->fk_product > 0) ? $line->product_label : ''));
5085
5086 $line->pu_ttc = price2num($line->subprice * (1 + ($line->tva_tx / 100)), 'MU');
5087
5088 // Output template part (modules that overwrite templates must declare this into descriptor)
5089 // Use global variables + $dateSelector + $seller and $buyer
5090 // Note: This is deprecated. If you need to overwrite the tpl file, use instead the hook printObjectLine and printObjectSubLine.
5091 $dirtpls = array_merge($conf->modules_parts['tpl'], array($defaulttpldir));
5092 foreach ($dirtpls as $module => $reldir) {
5093 if (!empty($module)) {
5094 $tpl = dol_buildpath($reldir.'/objectline_edit.tpl.php');
5095 } else {
5096 $tpl = DOL_DOCUMENT_ROOT.$reldir.'/objectline_edit.tpl.php';
5097 }
5098
5099 if (empty($conf->file->strict_mode)) {
5100 $res = @include $tpl;
5101 } else {
5102 $res = include $tpl; // for debug
5103 }
5104 if ($res) {
5105 break;
5106 }
5107 }
5108 }
5109 }
5110
5111
5112 /* This is to show array of line of details of source object */
5113
5114
5125 public function printOriginLinesList($restrictlist = '', $selectedLines = array())
5126 {
5127 global $langs, $hookmanager, $conf, $form, $action;
5128
5129 print '<tr class="liste_titre">';
5130 print '<td class="linecolref">'.$langs->trans('Ref').'</td>';
5131 print '<td class="linecoldescription">'.$langs->trans('Description').'</td>';
5132 print '<td class="linecolvat right">'.$langs->trans('VATRate').'</td>';
5133 print '<td class="linecoluht right">'.$langs->trans('PriceUHT').'</td>';
5134 if (isModEnabled("multicurrency")) {
5135 print '<td class="linecoluht_currency right">'.$langs->trans('PriceUHTCurrency').'</td>';
5136 }
5137 print '<td class="linecolqty right">'.$langs->trans('Qty').'</td>';
5138 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
5139 print '<td class="linecoluseunit left">'.$langs->trans('Unit').'</td>';
5140 }
5141 print '<td class="linecoldiscount right">'.$langs->trans('ReductionShort').'</td>';
5142 print '<td class="linecolht right">'.$langs->trans('TotalHT').'</td>';
5143 print '<td class="center">'.$form->showCheckAddButtons('checkforselect', 1).'</td>';
5144 print '</tr>';
5145 $i = 0;
5146
5147 if (!empty($this->lines)) {
5148 foreach ($this->lines as $line) {
5149 $reshook = 0;
5150 //if (is_object($hookmanager) && (($line->product_type == 9 && !empty($line->special_code)) || !empty($line->fk_parent_line))) {
5151 if (is_object($hookmanager)) { // Old code is commented on preceding line.
5152 $parameters = array('line'=>$line, 'i'=>$i, 'restrictlist'=>$restrictlist, 'selectedLines'=> $selectedLines);
5153 if (!empty($line->fk_parent_line)) { $parameters['fk_parent_line'] = $line->fk_parent_line; }
5154 $reshook = $hookmanager->executeHooks('printOriginObjectLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
5155 }
5156 if (empty($reshook)) {
5157 $this->printOriginLine($line, '', $restrictlist, '/core/tpl', $selectedLines);
5158 }
5159
5160 $i++;
5161 }
5162 }
5163 }
5164
5178 public function printOriginLine($line, $var, $restrictlist = '', $defaulttpldir = '/core/tpl', $selectedLines = array())
5179 {
5180 global $langs, $conf;
5181
5182 //var_dump($line);
5183 if (!empty($line->date_start)) {
5184 $date_start = $line->date_start;
5185 } else {
5186 $date_start = $line->date_debut_prevue;
5187 if ($line->date_debut_reel) {
5188 $date_start = $line->date_debut_reel;
5189 }
5190 }
5191 if (!empty($line->date_end)) {
5192 $date_end = $line->date_end;
5193 } else {
5194 $date_end = $line->date_fin_prevue;
5195 if ($line->date_fin_reel) {
5196 $date_end = $line->date_fin_reel;
5197 }
5198 }
5199
5200 $this->tpl['id'] = $line->id;
5201
5202 $this->tpl['label'] = '';
5203 if (!empty($line->fk_parent_line)) {
5204 $this->tpl['label'] .= img_picto('', 'rightarrow');
5205 }
5206
5207 if (($line->info_bits & 2) == 2) { // TODO Not sure this is used for source object
5208 $discount = new DiscountAbsolute($this->db);
5209 $discount->fk_soc = $this->socid;
5210 $this->tpl['label'] .= $discount->getNomUrl(0, 'discount');
5211 } elseif (!empty($line->fk_product)) {
5212 $productstatic = new Product($this->db);
5213 $productstatic->id = $line->fk_product;
5214 $productstatic->ref = $line->ref;
5215 $productstatic->type = $line->fk_product_type;
5216 if (empty($productstatic->ref)) {
5217 $line->fetch_product();
5218 $productstatic = $line->product;
5219 }
5220
5221 $this->tpl['label'] .= $productstatic->getNomUrl(1);
5222 $this->tpl['label'] .= ' - '.(!empty($line->label) ? $line->label : $line->product_label);
5223 // Dates
5224 if ($line->product_type == 1 && ($date_start || $date_end)) {
5225 $this->tpl['label'] .= get_date_range($date_start, $date_end);
5226 }
5227 } else {
5228 $this->tpl['label'] .= ($line->product_type == -1 ? '&nbsp;' : ($line->product_type == 1 ? img_object($langs->trans(''), 'service') : img_object($langs->trans(''), 'product')));
5229 if (!empty($line->desc)) {
5230 $this->tpl['label'] .= $line->desc;
5231 } else {
5232 $this->tpl['label'] .= ($line->label ? '&nbsp;'.$line->label : '');
5233 }
5234
5235 // Dates
5236 if ($line->product_type == 1 && ($date_start || $date_end)) {
5237 $this->tpl['label'] .= get_date_range($date_start, $date_end);
5238 }
5239 }
5240
5241 if (!empty($line->desc)) {
5242 if ($line->desc == '(CREDIT_NOTE)') { // TODO Not sure this is used for source object
5243 $discount = new DiscountAbsolute($this->db);
5244 $discount->fetch($line->fk_remise_except);
5245 $this->tpl['description'] = $langs->transnoentities("DiscountFromCreditNote", $discount->getNomUrl(0));
5246 } elseif ($line->desc == '(DEPOSIT)') { // TODO Not sure this is used for source object
5247 $discount = new DiscountAbsolute($this->db);
5248 $discount->fetch($line->fk_remise_except);
5249 $this->tpl['description'] = $langs->transnoentities("DiscountFromDeposit", $discount->getNomUrl(0));
5250 } elseif ($line->desc == '(EXCESS RECEIVED)') {
5251 $discount = new DiscountAbsolute($this->db);
5252 $discount->fetch($line->fk_remise_except);
5253 $this->tpl['description'] = $langs->transnoentities("DiscountFromExcessReceived", $discount->getNomUrl(0));
5254 } elseif ($line->desc == '(EXCESS PAID)') {
5255 $discount = new DiscountAbsolute($this->db);
5256 $discount->fetch($line->fk_remise_except);
5257 $this->tpl['description'] = $langs->transnoentities("DiscountFromExcessPaid", $discount->getNomUrl(0));
5258 } else {
5259 $this->tpl['description'] = dol_trunc($line->desc, 60);
5260 }
5261 } else {
5262 $this->tpl['description'] = '&nbsp;';
5263 }
5264
5265 // VAT Rate
5266 $this->tpl['vat_rate'] = vatrate($line->tva_tx, true);
5267 $this->tpl['vat_rate'] .= (($line->info_bits & 1) == 1) ? '*' : '';
5268 if (!empty($line->vat_src_code) && !preg_match('/\‍(/', $this->tpl['vat_rate'])) {
5269 $this->tpl['vat_rate'] .= ' ('.$line->vat_src_code.')';
5270 }
5271
5272 $this->tpl['price'] = price($line->subprice);
5273 $this->tpl['total_ht'] = price($line->total_ht);
5274 $this->tpl['multicurrency_price'] = price($line->multicurrency_subprice);
5275 $this->tpl['qty'] = (($line->info_bits & 2) != 2) ? $line->qty : '&nbsp;';
5276 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
5277 $this->tpl['unit'] = $langs->transnoentities($line->getLabelOfUnit('long'));
5278 }
5279 $this->tpl['remise_percent'] = (($line->info_bits & 2) != 2) ? vatrate($line->remise_percent, true) : '&nbsp;';
5280
5281 // Is the line strike or not
5282 $this->tpl['strike'] = 0;
5283 if ($restrictlist == 'services' && $line->product_type != Product::TYPE_SERVICE) {
5284 $this->tpl['strike'] = 1;
5285 }
5286
5287 // Output template part (modules that overwrite templates must declare this into descriptor)
5288 // Use global variables + $dateSelector + $seller and $buyer
5289 $dirtpls = array_merge($conf->modules_parts['tpl'], array($defaulttpldir));
5290 foreach ($dirtpls as $module => $reldir) {
5291 if (!empty($module)) {
5292 $tpl = dol_buildpath($reldir.'/originproductline.tpl.php');
5293 } else {
5294 $tpl = DOL_DOCUMENT_ROOT.$reldir.'/originproductline.tpl.php';
5295 }
5296
5297 if (empty($conf->file->strict_mode)) {
5298 $res = @include $tpl;
5299 } else {
5300 $res = include $tpl; // for debug
5301 }
5302 if ($res) {
5303 break;
5304 }
5305 }
5306 }
5307
5308
5309 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5320 public function add_element_resource($resource_id, $resource_type, $busy = 0, $mandatory = 0)
5321 {
5322 // phpcs:enable
5323 $this->db->begin();
5324
5325 $sql = "INSERT INTO ".$this->db->prefix()."element_resources (";
5326 $sql .= "resource_id";
5327 $sql .= ", resource_type";
5328 $sql .= ", element_id";
5329 $sql .= ", element_type";
5330 $sql .= ", busy";
5331 $sql .= ", mandatory";
5332 $sql .= ") VALUES (";
5333 $sql .= ((int) $resource_id);
5334 $sql .= ", '".$this->db->escape($resource_type)."'";
5335 $sql .= ", '".$this->db->escape($this->id)."'";
5336 $sql .= ", '".$this->db->escape($this->element)."'";
5337 $sql .= ", '".$this->db->escape($busy)."'";
5338 $sql .= ", '".$this->db->escape($mandatory)."'";
5339 $sql .= ")";
5340
5341 dol_syslog(get_class($this)."::add_element_resource", LOG_DEBUG);
5342 if ($this->db->query($sql)) {
5343 $this->db->commit();
5344 return 1;
5345 } else {
5346 $this->error = $this->db->lasterror();
5347 $this->db->rollback();
5348 return 0;
5349 }
5350 }
5351
5352 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5361 public function delete_resource($rowid, $element, $notrigger = 0)
5362 {
5363 // phpcs:enable
5364 global $user;
5365
5366 $this->db->begin();
5367
5368 $sql = "DELETE FROM ".$this->db->prefix()."element_resources";
5369 $sql .= " WHERE rowid = ".((int) $rowid);
5370
5371 dol_syslog(get_class($this)."::delete_resource", LOG_DEBUG);
5372
5373 $resql = $this->db->query($sql);
5374 if (!$resql) {
5375 $this->error = $this->db->lasterror();
5376 $this->db->rollback();
5377 return -1;
5378 } else {
5379 if (!$notrigger) {
5380 $result = $this->call_trigger(strtoupper($element).'_DELETE_RESOURCE', $user);
5381 if ($result < 0) {
5382 $this->db->rollback();
5383 return -1;
5384 }
5385 }
5386 $this->db->commit();
5387 return 1;
5388 }
5389 }
5390
5391
5397 public function __clone()
5398 {
5399 // Force a copy of this->lines, otherwise it will point to same object.
5400 if (isset($this->lines) && is_array($this->lines)) {
5401 $nboflines = count($this->lines);
5402 for ($i = 0; $i < $nboflines; $i++) {
5403 if (is_object($this->lines[$i])) {
5404 $this->lines[$i] = clone $this->lines[$i];
5405 }
5406 }
5407 }
5408 }
5409
5423 protected function commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams = null)
5424 {
5425 global $conf, $langs, $user, $hookmanager, $action;
5426
5427 $srctemplatepath = '';
5428
5429 $parameters = array('modelspath'=>$modelspath, 'modele'=>$modele, 'outputlangs'=>$outputlangs, 'hidedetails'=>$hidedetails, 'hidedesc'=>$hidedesc, 'hideref'=>$hideref, 'moreparams'=>$moreparams);
5430 $reshook = $hookmanager->executeHooks('commonGenerateDocument', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
5431
5432 if (!empty($reshook)) {
5433 return $reshook;
5434 }
5435
5436 dol_syslog("commonGenerateDocument modele=".$modele." outputlangs->defaultlang=".(is_object($outputlangs) ? $outputlangs->defaultlang : 'null'));
5437
5438 if (empty($modele)) {
5439 $this->error = 'BadValueForParameterModele';
5440 return -1;
5441 }
5442
5443 // Increase limit for PDF build
5444 $err = error_reporting();
5445 error_reporting(0);
5446 @set_time_limit(120);
5447 error_reporting($err);
5448
5449 // If selected model is a filename template (then $modele="modelname" or "modelname:filename")
5450 $tmp = explode(':', $modele, 2);
5451 if (!empty($tmp[1])) {
5452 $modele = $tmp[0];
5453 $srctemplatepath = $tmp[1];
5454 }
5455
5456 // Search template files
5457 $file = '';
5458 $classname = '';
5459 $filefound = '';
5460 $dirmodels = array('/');
5461 if (is_array($conf->modules_parts['models'])) {
5462 $dirmodels = array_merge($dirmodels, $conf->modules_parts['models']);
5463 }
5464 foreach ($dirmodels as $reldir) {
5465 foreach (array('doc', 'pdf') as $prefix) {
5466 if (in_array(get_class($this), array('Adherent'))) {
5467 // Member module use prefix_modele.class.php
5468 $file = $prefix."_".$modele.".class.php";
5469 } else {
5470 // Other module use prefix_modele.modules.php
5471 $file = $prefix."_".$modele.".modules.php";
5472 }
5473
5474 // On verifie l'emplacement du modele
5475 $file = dol_buildpath($reldir.$modelspath.$file, 0);
5476 if (file_exists($file)) {
5477 $filefound = $file;
5478 $classname = $prefix.'_'.$modele;
5479 break;
5480 }
5481 }
5482 if ($filefound) {
5483 break;
5484 }
5485 }
5486
5487 if (!$filefound) {
5488 $this->error = $langs->trans("Error").' Failed to load doc generator with modelpaths='.$modelspath.' - modele='.$modele;
5489 $this->errors[] = $this->error;
5490 dol_syslog($this->error, LOG_ERR);
5491 return -1;
5492 }
5493
5494 // If generator was found
5495 global $db; // Required to solve a conception default making an include of code using $db instead of $this->db just after.
5496
5497 require_once $file;
5498
5499 $obj = new $classname($this->db);
5500
5501 // If generator is ODT, we must have srctemplatepath defined, if not we set it.
5502 if ($obj->type == 'odt' && empty($srctemplatepath)) {
5503 $varfortemplatedir = $obj->scandir;
5504 if ($varfortemplatedir && !empty($conf->global->$varfortemplatedir)) {
5505 $dirtoscan = $conf->global->$varfortemplatedir;
5506
5507 $listoffiles = array();
5508
5509 // Now we add first model found in directories scanned
5510 $listofdir = explode(',', $dirtoscan);
5511 foreach ($listofdir as $key => $tmpdir) {
5512 $tmpdir = trim($tmpdir);
5513 $tmpdir = preg_replace('/DOL_DATA_ROOT/', DOL_DATA_ROOT, $tmpdir);
5514 if (!$tmpdir) {
5515 unset($listofdir[$key]);
5516 continue;
5517 }
5518 if (is_dir($tmpdir)) {
5519 $tmpfiles = dol_dir_list($tmpdir, 'files', 0, '\.od(s|t)$', '', 'name', SORT_ASC, 0);
5520 if (count($tmpfiles)) {
5521 $listoffiles = array_merge($listoffiles, $tmpfiles);
5522 }
5523 }
5524 }
5525
5526 if (count($listoffiles)) {
5527 foreach ($listoffiles as $record) {
5528 $srctemplatepath = $record['fullname'];
5529 break;
5530 }
5531 }
5532 }
5533
5534 if (empty($srctemplatepath)) {
5535 $this->error = 'ErrorGenerationAskedForOdtTemplateWithSrcFileNotDefined';
5536 return -1;
5537 }
5538 }
5539
5540 if ($obj->type == 'odt' && !empty($srctemplatepath)) {
5541 if (!dol_is_file($srctemplatepath)) {
5542 dol_syslog("Failed to locate template file ".$srctemplatepath, LOG_WARNING);
5543 $this->error = 'ErrorGenerationAskedForOdtTemplateWithSrcFileNotFound';
5544 return -1;
5545 }
5546 }
5547
5548 // We save charset_output to restore it because write_file can change it if needed for
5549 // output format that does not support UTF8.
5550 $sav_charset_output = empty($outputlangs->charset_output) ? '' : $outputlangs->charset_output;
5551
5552 if (in_array(get_class($this), array('Adherent'))) {
5553 $resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, 'member', 1, 'tmp_cards', $moreparams);
5554 } else {
5555 $resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, $hidedetails, $hidedesc, $hideref, $moreparams);
5556 }
5557 // After call of write_file $obj->result['fullpath'] is set with generated file. It will be used to update the ECM database index.
5558
5559 if ($resultwritefile > 0) {
5560 $outputlangs->charset_output = $sav_charset_output;
5561
5562 // We delete old preview
5563 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
5564 dol_delete_preview($this);
5565
5566 // Index file in database
5567 if (!empty($obj->result['fullpath'])) {
5568 $destfull = $obj->result['fullpath'];
5569
5570 // Update the last_main_doc field into main object (if document generator has property ->update_main_doc_field set)
5571 $update_main_doc_field = 0;
5572 if (!empty($obj->update_main_doc_field)) {
5573 $update_main_doc_field = 1;
5574 }
5575
5576 // Check that the file exists, before indexing it.
5577 // Hint: It does not exist, if we create a PDF and auto delete the ODT File
5578 if (dol_is_file($destfull)) {
5579 $this->indexFile($destfull, $update_main_doc_field);
5580 }
5581 } else {
5582 dol_syslog('Method ->write_file was called on object '.get_class($obj).' and return a success but the return array ->result["fullpath"] was not set.', LOG_WARNING);
5583 }
5584
5585 // Success in building document. We build meta file.
5586 dol_meta_create($this);
5587
5588 return 1;
5589 } else {
5590 $outputlangs->charset_output = $sav_charset_output;
5591 $this->error = $obj->error;
5592 $this->errors = $obj->errors;
5593 dol_syslog("Error generating document for ".__CLASS__.". Error: ".$obj->error, LOG_ERR);
5594 return -1;
5595 }
5596 }
5597
5607 public function indexFile($destfull, $update_main_doc_field)
5608 {
5609 global $conf, $user;
5610
5611 $upload_dir = dirname($destfull);
5612 $destfile = basename($destfull);
5613 $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $upload_dir);
5614
5615 if (!preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir)) { // If not a tmp dir
5616 $filename = basename($destfile);
5617 $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
5618 $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
5619
5620 include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
5621 $ecmfile = new EcmFiles($this->db);
5622 $result = $ecmfile->fetch(0, '', ($rel_dir ? $rel_dir.'/' : '').$filename);
5623
5624 // Set the public "share" key
5625 $setsharekey = false;
5626 if ($this->element == 'propal' || $this->element == 'proposal') {
5627 if (!isset($conf->global->PROPOSAL_ALLOW_ONLINESIGN) || !empty($conf->global->PROPOSAL_ALLOW_ONLINESIGN)) {
5628 $setsharekey = true; // feature to make online signature is not set or set to on (default)
5629 }
5630 if (!empty($conf->global->PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD)) {
5631 $setsharekey = true;
5632 }
5633 }
5634 if ($this->element == 'commande' && !empty($conf->global->ORDER_ALLOW_EXTERNAL_DOWNLOAD)) {
5635 $setsharekey = true;
5636 }
5637 if ($this->element == 'facture' && !empty($conf->global->INVOICE_ALLOW_EXTERNAL_DOWNLOAD)) {
5638 $setsharekey = true;
5639 }
5640 if ($this->element == 'bank_account' && !empty($conf->global->BANK_ACCOUNT_ALLOW_EXTERNAL_DOWNLOAD)) {
5641 $setsharekey = true;
5642 }
5643 if ($this->element == 'product' && !empty($conf->global->PRODUCT_ALLOW_EXTERNAL_DOWNLOAD)) {
5644 $setsharekey = true;
5645 }
5646 if ($this->element == 'contrat' && !empty($conf->global->CONTRACT_ALLOW_EXTERNAL_DOWNLOAD)) {
5647 $setsharekey = true;
5648 }
5649 if ($this->element == 'fichinter' && !empty($conf->global->FICHINTER_ALLOW_EXTERNAL_DOWNLOAD)) {
5650 $setsharekey = true;
5651 }
5652 if ($this->element == 'supplier_proposal' && !empty($conf->global->SUPPLIER_PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD)) {
5653 $setsharekey = true;
5654 }
5655
5656 if ($setsharekey) {
5657 if (empty($ecmfile->share)) { // Because object not found or share not set yet
5658 require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
5659 $ecmfile->share = getRandomPassword(true);
5660 }
5661 }
5662
5663 if ($result > 0) {
5664 $ecmfile->label = md5_file(dol_osencode($destfull)); // hash of file content
5665 $ecmfile->fullpath_orig = '';
5666 $ecmfile->gen_or_uploaded = 'generated';
5667 $ecmfile->description = ''; // indexed content
5668 $ecmfile->keywords = ''; // keyword content
5669 $result = $ecmfile->update($user);
5670 if ($result < 0) {
5671 setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
5672 return -1;
5673 }
5674 } else {
5675 $ecmfile->entity = $conf->entity;
5676 $ecmfile->filepath = $rel_dir;
5677 $ecmfile->filename = $filename;
5678 $ecmfile->label = md5_file(dol_osencode($destfull)); // hash of file content
5679 $ecmfile->fullpath_orig = '';
5680 $ecmfile->gen_or_uploaded = 'generated';
5681 $ecmfile->description = ''; // indexed content
5682 $ecmfile->keywords = ''; // keyword content
5683 $ecmfile->src_object_type = $this->table_element; // $this->table_name is 'myobject' or 'mymodule_myobject'.
5684 $ecmfile->src_object_id = $this->id;
5685
5686 $result = $ecmfile->create($user);
5687 if ($result < 0) {
5688 setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
5689 return -1;
5690 }
5691 }
5692
5693 /*$this->result['fullname']=$destfull;
5694 $this->result['filepath']=$ecmfile->filepath;
5695 $this->result['filename']=$ecmfile->filename;*/
5696 //var_dump($obj->update_main_doc_field);exit;
5697
5698 if ($update_main_doc_field && !empty($this->table_element)) {
5699 $sql = "UPDATE ".$this->db->prefix().$this->table_element." SET last_main_doc = '".$this->db->escape($ecmfile->filepath."/".$ecmfile->filename)."'";
5700 $sql .= " WHERE rowid = ".((int) $this->id);
5701
5702 $resql = $this->db->query($sql);
5703 if (!$resql) {
5704 dol_print_error($this->db);
5705 return -1;
5706 } else {
5707 $this->last_main_doc = $ecmfile->filepath.'/'.$ecmfile->filename;
5708 }
5709 }
5710 }
5711
5712 return 1;
5713 }
5714
5722 public function addThumbs($file)
5723 {
5724 $file_osencoded = dol_osencode($file);
5725
5726 if (file_exists($file_osencoded)) {
5727 require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
5728
5729 $tmparraysize = getDefaultImageSizes();
5730 $maxwidthsmall = $tmparraysize['maxwidthsmall'];
5731 $maxheightsmall = $tmparraysize['maxheightsmall'];
5732 $maxwidthmini = $tmparraysize['maxwidthmini'];
5733 $maxheightmini = $tmparraysize['maxheightmini'];
5734 //$quality = $tmparraysize['quality'];
5735 $quality = 50; // For thumbs, we force quality to 50
5736
5737 // Create small thumbs for company (Ratio is near 16/9)
5738 // Used on logon for example
5739 vignette($file_osencoded, $maxwidthsmall, $maxheightsmall, '_small', $quality);
5740
5741 // Create mini thumbs for company (Ratio is near 16/9)
5742 // Used on menu or for setup page for example
5743 vignette($file_osencoded, $maxwidthmini, $maxheightmini, '_mini', $quality);
5744 }
5745 }
5746
5754 public function delThumbs($file)
5755 {
5756 $imgThumbName = getImageFileNameForSize($file, '_small'); // Full path of thumb file
5757 dol_delete_file($imgThumbName);
5758 $imgThumbName = getImageFileNameForSize($file, '_mini'); // Full path of thumb file
5759 dol_delete_file($imgThumbName);
5760 }
5761
5762
5763 /* Functions common to commonobject and commonobjectline */
5764
5765 /* For default values */
5766
5780 public function getDefaultCreateValueFor($fieldname, $alternatevalue = null, $type = 'alphanohtml')
5781 {
5782 global $conf, $_POST;
5783
5784 // If param here has been posted, we use this value first.
5785 if (GETPOSTISSET($fieldname)) {
5786 return GETPOST($fieldname, $type, 3);
5787 }
5788
5789 if (isset($alternatevalue)) {
5790 return $alternatevalue;
5791 }
5792
5793 $newelement = $this->element;
5794 if ($newelement == 'facture') {
5795 $newelement = 'invoice';
5796 }
5797 if ($newelement == 'commande') {
5798 $newelement = 'order';
5799 }
5800 if (empty($newelement)) {
5801 dol_syslog("Ask a default value using common method getDefaultCreateValueForField on an object with no property ->element defined. Return empty string.", LOG_WARNING);
5802 return '';
5803 }
5804
5805 $keyforfieldname = strtoupper($newelement.'_DEFAULT_'.$fieldname);
5806 //var_dump($keyforfieldname);
5807 if (isset($conf->global->$keyforfieldname)) {
5808 return $conf->global->$keyforfieldname;
5809 }
5810
5811 // TODO Ad here a scan into table llx_overwrite_default with a filter on $this->element and $fieldname
5812 // store content into $conf->cache['overwrite_default']
5813
5814 return '';
5815 }
5816
5817
5818 /* For triggers */
5819
5820
5821 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5832 public function call_trigger($triggerName, $user)
5833 {
5834 // phpcs:enable
5835 global $langs, $conf;
5836 if (!empty(self::TRIGGER_PREFIX) && strpos($triggerName, self::TRIGGER_PREFIX . '_') !== 0) {
5837 dol_print_error('', 'The trigger "' . $triggerName . '" does not start with "' . self::TRIGGER_PREFIX . '_" as required.');
5838 exit;
5839 }
5840 if (!is_object($langs)) { // If lang was not defined, we set it. It is required by run_triggers.
5841 include_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php';
5842 $langs = new Translate('', $conf);
5843 }
5844
5845 include_once DOL_DOCUMENT_ROOT.'/core/class/interfaces.class.php';
5846 $interface = new Interfaces($this->db);
5847 $result = $interface->run_triggers($triggerName, $this, $user, $langs, $conf);
5848
5849 if ($result < 0) {
5850 if (!empty($this->errors)) {
5851 $this->errors = array_unique(array_merge($this->errors, $interface->errors)); // We use array_unique because when a trigger call another trigger on same object, this->errors is added twice.
5852 } else {
5853 $this->errors = $interface->errors;
5854 }
5855 }
5856 return $result;
5857 }
5858
5859
5860 /* Functions for data in other language */
5861
5862
5871 {
5872 // To avoid SQL errors. Probably not the better solution though
5873 if (!$this->element) {
5874 return 0;
5875 }
5876 if (!($this->id > 0)) {
5877 return 0;
5878 }
5879 if (is_array($this->array_languages)) {
5880 return 1;
5881 }
5882
5883 $this->array_languages = array();
5884
5885 $element = $this->element;
5886 if ($element == 'categorie') {
5887 $element = 'categories'; // For compatibility
5888 }
5889
5890 // Request to get translation values for object
5891 $sql = "SELECT rowid, property, lang , value";
5892 $sql .= " FROM ".$this->db->prefix()."object_lang";
5893 $sql .= " WHERE type_object = '".$this->db->escape($element)."'";
5894 $sql .= " AND fk_object = ".((int) $this->id);
5895
5896 //dol_syslog(get_class($this)."::fetch_optionals get extrafields data for ".$this->table_element, LOG_DEBUG); // Too verbose
5897 $resql = $this->db->query($sql);
5898 if ($resql) {
5899 $numrows = $this->db->num_rows($resql);
5900 if ($numrows) {
5901 $i = 0;
5902 while ($i < $numrows) {
5903 $obj = $this->db->fetch_object($resql);
5904 $key = $obj->property;
5905 $value = $obj->value;
5906 $codelang = $obj->lang;
5907 $type = $this->fields[$key]['type'];
5908
5909 // we can add this attribute to object
5910 if (preg_match('/date/', $type)) {
5911 $this->array_languages[$key][$codelang] = $this->db->jdate($value);
5912 } else {
5913 $this->array_languages[$key][$codelang] = $value;
5914 }
5915
5916 $i++;
5917 }
5918 }
5919
5920 $this->db->free($resql);
5921
5922 if ($numrows) {
5923 return $numrows;
5924 } else {
5925 return 0;
5926 }
5927 } else {
5928 dol_print_error($this->db);
5929 return -1;
5930 }
5931 }
5932
5939 public function setValuesForExtraLanguages($onlykey = '')
5940 {
5941 global $_POST, $langs;
5942
5943 // Get extra fields
5944 foreach ($_POST as $postfieldkey => $postfieldvalue) {
5945 $tmparray = explode('-', $postfieldkey);
5946 if ($tmparray[0] != 'field') {
5947 continue;
5948 }
5949
5950 $element = $tmparray[1];
5951 $key = $tmparray[2];
5952 $codelang = $tmparray[3];
5953 //var_dump("postfieldkey=".$postfieldkey." element=".$element." key=".$key." codelang=".$codelang);
5954
5955 if (!empty($onlykey) && $key != $onlykey) {
5956 continue;
5957 }
5958 if ($element != $this->element) {
5959 continue;
5960 }
5961
5962 $key_type = $this->fields[$key]['type'];
5963
5964 $enabled = 1;
5965 if (isset($this->fields[$key]['enabled'])) {
5966 $enabled = dol_eval($this->fields[$key]['enabled'], 1, 1, '1');
5967 }
5968 /*$perms = 1;
5969 if (isset($this->fields[$key]['perms']))
5970 {
5971 $perms = dol_eval($this->fields[$key]['perms'], 1, 1, '1');
5972 }*/
5973 if (empty($enabled)) {
5974 continue;
5975 }
5976 //if (empty($perms)) continue;
5977
5978 if (in_array($key_type, array('date'))) {
5979 // Clean parameters
5980 // TODO GMT date in memory must be GMT so we should add gm=true in parameters
5981 $value_key = dol_mktime(0, 0, 0, GETPOST($postfieldkey."month", 'int'), GETPOST($postfieldkey."day", 'int'), GETPOST($postfieldkey."year", 'int'));
5982 } elseif (in_array($key_type, array('datetime'))) {
5983 // Clean parameters
5984 // TODO GMT date in memory must be GMT so we should add gm=true in parameters
5985 $value_key = dol_mktime(GETPOST($postfieldkey."hour", 'int'), GETPOST($postfieldkey."min", 'int'), 0, GETPOST($postfieldkey."month", 'int'), GETPOST($postfieldkey."day", 'int'), GETPOST($postfieldkey."year", 'int'));
5986 } elseif (in_array($key_type, array('checkbox', 'chkbxlst'))) {
5987 $value_arr = GETPOST($postfieldkey, 'array'); // check if an array
5988 if (!empty($value_arr)) {
5989 $value_key = implode(',', $value_arr);
5990 } else {
5991 $value_key = '';
5992 }
5993 } elseif (in_array($key_type, array('price', 'double'))) {
5994 $value_arr = GETPOST($postfieldkey, 'alpha');
5995 $value_key = price2num($value_arr);
5996 } else {
5997 $value_key = GETPOST($postfieldkey);
5998 if (in_array($key_type, array('link')) && $value_key == '-1') {
5999 $value_key = '';
6000 }
6001 }
6002
6003 $this->array_languages[$key][$codelang] = $value_key;
6004
6005 /*if ($nofillrequired) {
6006 $langs->load('errors');
6007 setEventMessages($langs->trans('ErrorFieldsRequired').' : '.implode(', ', $error_field_required), null, 'errors');
6008 return -1;
6009 }*/
6010 }
6011
6012 return 1;
6013 }
6014
6015
6016 /* Functions for extrafields */
6017
6024 public function fetchNoCompute($id)
6025 {
6026 global $conf;
6027
6028 $savDisableCompute = $conf->disable_compute;
6029 $conf->disable_compute = 1;
6030
6031 $ret = $this->fetch($id);
6032
6033 $conf->disable_compute = $savDisableCompute;
6034
6035 return $ret;
6036 }
6037
6038 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6048 public function fetch_optionals($rowid = null, $optionsArray = null)
6049 {
6050 // phpcs:enable
6051 global $conf, $extrafields;
6052
6053 if (empty($rowid)) {
6054 $rowid = $this->id;
6055 }
6056 if (empty($rowid) && isset($this->rowid)) {
6057 $rowid = $this->rowid; // deprecated
6058 }
6059
6060 // To avoid SQL errors. Probably not the better solution though
6061 if (!$this->table_element) {
6062 return 0;
6063 }
6064
6065 $this->array_options = array();
6066
6067 if (!is_array($optionsArray)) {
6068 // If $extrafields is not a known object, we initialize it. Best practice is to have $extrafields defined into card.php or list.php page.
6069 if (!isset($extrafields) || !is_object($extrafields)) {
6070 require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
6071 $extrafields = new ExtraFields($this->db);
6072 }
6073
6074 // Load array of extrafields for elementype = $this->table_element
6075 if (empty($extrafields->attributes[$this->table_element]['loaded'])) {
6076 $extrafields->fetch_name_optionals_label($this->table_element);
6077 }
6078 $optionsArray = (!empty($extrafields->attributes[$this->table_element]['label']) ? $extrafields->attributes[$this->table_element]['label'] : null);
6079 } else {
6080 global $extrafields;
6081 dol_syslog("Warning: fetch_optionals was called with param optionsArray defined when you should pass null now", LOG_WARNING);
6082 }
6083
6084 $table_element = $this->table_element;
6085 if ($table_element == 'categorie') {
6086 $table_element = 'categories'; // For compatibility
6087 }
6088
6089 // Request to get complementary values
6090 if (is_array($optionsArray) && count($optionsArray) > 0) {
6091 $sql = "SELECT rowid";
6092 foreach ($optionsArray as $name => $label) {
6093 if (empty($extrafields->attributes[$this->table_element]['type'][$name]) || $extrafields->attributes[$this->table_element]['type'][$name] != 'separate') {
6094 $sql .= ", ".$name;
6095 }
6096 }
6097 $sql .= " FROM ".$this->db->prefix().$table_element."_extrafields";
6098 $sql .= " WHERE fk_object = ".((int) $rowid);
6099
6100 //dol_syslog(get_class($this)."::fetch_optionals get extrafields data for ".$this->table_element, LOG_DEBUG); // Too verbose
6101 $resql = $this->db->query($sql);
6102 if ($resql) {
6103 $numrows = $this->db->num_rows($resql);
6104 if ($numrows) {
6105 $tab = $this->db->fetch_array($resql);
6106
6107 foreach ($tab as $key => $value) {
6108 // Test fetch_array ! is_int($key) because fetch_array result is a mix table with Key as alpha and Key as int (depend db engine)
6109 if ($key != 'rowid' && $key != 'tms' && $key != 'fk_member' && !is_int($key)) {
6110 // we can add this attribute to object
6111 if (!empty($extrafields->attributes[$this->table_element]) && in_array($extrafields->attributes[$this->table_element]['type'][$key], array('date', 'datetime'))) {
6112 //var_dump($extrafields->attributes[$this->table_element]['type'][$key]);
6113 $this->array_options["options_".$key] = $this->db->jdate($value);
6114 } else {
6115 $this->array_options["options_".$key] = $value;
6116 }
6117
6118 //var_dump('key '.$key.' '.$value.' type='.$extrafields->attributes[$this->table_element]['type'][$key].' '.$this->array_options["options_".$key]);
6119 }
6120 }
6121 }
6122
6123 // If field is a computed field, value must become result of compute (regardless of whether a row exists
6124 // in the element's extrafields table)
6125 if (is_array($extrafields->attributes[$this->table_element]['label'])) {
6126 foreach ($extrafields->attributes[$this->table_element]['label'] as $key => $val) {
6127 if (!empty($extrafields->attributes[$this->table_element]) && !empty($extrafields->attributes[$this->table_element]['computed'][$key])) {
6128 //var_dump($conf->disable_compute);
6129 if (empty($conf->disable_compute)) {
6130 global $objectoffield; // We set a global variable to $objectoffield so
6131 $objectoffield = $this; // we can use it inside computed formula
6132 $this->array_options['options_' . $key] = dol_eval($extrafields->attributes[$this->table_element]['computed'][$key], 1, 0, '');
6133 }
6134 }
6135 }
6136 }
6137
6138 $this->db->free($resql);
6139
6140 if ($numrows) {
6141 return $numrows;
6142 } else {
6143 return 0;
6144 }
6145 } else {
6146 $this->errors[]=$this->db->lasterror;
6147 return -1;
6148 }
6149 }
6150 return 0;
6151 }
6152
6159 public function deleteExtraFields()
6160 {
6161 global $conf;
6162
6163 if (!empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) {
6164 return 0;
6165 }
6166
6167 $this->db->begin();
6168
6169 $table_element = $this->table_element;
6170 if ($table_element == 'categorie') {
6171 $table_element = 'categories'; // For compatibility
6172 }
6173
6174 dol_syslog(get_class($this)."::deleteExtraFields delete", LOG_DEBUG);
6175
6176 $sql_del = "DELETE FROM ".$this->db->prefix().$table_element."_extrafields WHERE fk_object = ".((int) $this->id);
6177
6178 $resql = $this->db->query($sql_del);
6179 if (!$resql) {
6180 $this->error = $this->db->lasterror();
6181 $this->db->rollback();
6182 return -1;
6183 } else {
6184 $this->db->commit();
6185 return 1;
6186 }
6187 }
6188
6199 public function insertExtraFields($trigger = '', $userused = null)
6200 {
6201 global $conf, $langs, $user;
6202
6203 if (!empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) {
6204 return 0;
6205 }
6206
6207 if (empty($userused)) {
6208 $userused = $user;
6209 }
6210
6211 $error = 0;
6212
6213 if (!empty($this->array_options)) {
6214 // Check parameters
6215 $langs->load('admin');
6216 require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
6217 $extrafields = new ExtraFields($this->db);
6218 $target_extrafields = $extrafields->fetch_name_optionals_label($this->table_element);
6219
6220 // Eliminate copied source object extra fields that do not exist in target object
6221 $new_array_options = array();
6222 foreach ($this->array_options as $key => $value) {
6223 if (in_array(substr($key, 8), array_keys($target_extrafields))) { // We remove the 'options_' from $key for test
6224 $new_array_options[$key] = $value;
6225 } elseif (in_array($key, array_keys($target_extrafields))) { // We test on $key that does not contain the 'options_' prefix
6226 $new_array_options['options_'.$key] = $value;
6227 }
6228 }
6229
6230 foreach ($new_array_options as $key => $value) {
6231 $attributeKey = substr($key, 8); // Remove 'options_' prefix
6232 $attributeType = $extrafields->attributes[$this->table_element]['type'][$attributeKey];
6233 $attributeLabel = $langs->transnoentities($extrafields->attributes[$this->table_element]['label'][$attributeKey]);
6234 $attributeParam = $extrafields->attributes[$this->table_element]['param'][$attributeKey];
6235 $attributeRequired = $extrafields->attributes[$this->table_element]['required'][$attributeKey];
6236 $attributeUnique = $extrafields->attributes[$this->table_element]['unique'][$attributeKey];
6237 $attrfieldcomputed = $extrafields->attributes[$this->table_element]['computed'][$attributeKey];
6238
6239 // If we clone, we have to clean unique extrafields to prevent duplicates.
6240 // This behaviour can be prevented by external code by changing $this->context['createfromclone'] value in createFrom hook
6241 if (!empty($this->context['createfromclone']) && $this->context['createfromclone'] == 'createfromclone' && !empty($attributeUnique)) {
6242 $new_array_options[$key] = null;
6243 }
6244
6245 // Similar code than into insertExtraFields
6246 if ($attributeRequired) {
6247 $mandatorypb = false;
6248 if ($attributeType == 'link' && $this->array_options[$key] == '-1') {
6249 $mandatorypb = true;
6250 }
6251 if ($this->array_options[$key] === '') {
6252 $mandatorypb = true;
6253 }
6254 if ($attributeType == 'sellist' && $this->array_options[$key] == '0') {
6255 $mandatorypb = true;
6256 }
6257 if ($mandatorypb) {
6258 $langs->load("errors");
6259 dol_syslog("Mandatory field '".$key."' is empty during create and set to required into definition of extrafields");
6260 $this->errors[] = $langs->trans('ErrorFieldRequired', $attributeLabel);
6261 return -1;
6262 }
6263 }
6264
6265 //dol_syslog("attributeLabel=".$attributeLabel, LOG_DEBUG);
6266 //dol_syslog("attributeType=".$attributeType, LOG_DEBUG);
6267
6268 if (!empty($attrfieldcomputed)) {
6269 if (!empty($conf->global->MAIN_STORE_COMPUTED_EXTRAFIELDS)) {
6270 $value = dol_eval($attrfieldcomputed, 1, 0, '');
6271 dol_syslog($langs->trans("Extrafieldcomputed")." sur ".$attributeLabel."(".$value.")", LOG_DEBUG);
6272 $new_array_options[$key] = $value;
6273 } else {
6274 $new_array_options[$key] = null;
6275 }
6276 }
6277
6278 switch ($attributeType) {
6279 case 'int':
6280 if (!is_numeric($value) && $value != '') {
6281 $this->errors[] = $langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
6282 return -1;
6283 } elseif ($value == '') {
6284 $new_array_options[$key] = null;
6285 }
6286 break;
6287 case 'price':
6288 case 'double':
6289 $value = price2num($value);
6290 if (!is_numeric($value) && $value != '') {
6291 dol_syslog($langs->trans("ExtraFieldHasWrongValue")." for ".$attributeLabel."(".$value."is not '".$attributeType."')", LOG_DEBUG);
6292 $this->errors[] = $langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
6293 return -1;
6294 } elseif ($value == '') {
6295 $value = null;
6296 }
6297 //dol_syslog("double value"." sur ".$attributeLabel."(".$value." is '".$attributeType."')", LOG_DEBUG);
6298 $new_array_options[$key] = $value;
6299 break;
6300 /*case 'select': // Not required, we chosed value='0' for undefined values
6301 if ($value=='-1')
6302 {
6303 $this->array_options[$key] = null;
6304 }
6305 break;*/
6306 case 'password':
6307 $algo = '';
6308 if ($this->array_options[$key] != '' && is_array($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options'])) {
6309 // If there is an encryption choice, we use it to crypt data before insert
6310 $tmparrays = array_keys($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options']);
6311 $algo = reset($tmparrays);
6312 if ($algo != '') {
6313 //global $action; // $action may be 'create', 'update', 'update_extras'...
6314 //var_dump($action);
6315 //var_dump($this->oldcopy);exit;
6316 if (is_object($this->oldcopy)) { // If this->oldcopy is not defined, we can't know if we change attribute or not, so we must keep value
6317 //var_dump($this->oldcopy->array_options[$key]); var_dump($this->array_options[$key]);
6318 if (isset($this->oldcopy->array_options[$key]) && $this->array_options[$key] == $this->oldcopy->array_options[$key]) { // If old value crypted in database is same than submited new value, it means we don't change it, so we don't update.
6319 $new_array_options[$key] = $this->array_options[$key]; // Value is kept
6320 } else {
6321 // var_dump($algo);
6322 $newvalue = dol_hash($this->array_options[$key], $algo);
6323 $new_array_options[$key] = $newvalue;
6324 }
6325 } else {
6326 $new_array_options[$key] = $this->array_options[$key]; // Value is kept
6327 }
6328 }
6329 } else // Common usage
6330 {
6331 $new_array_options[$key] = $this->array_options[$key];
6332 }
6333 break;
6334 case 'date':
6335 case 'datetime':
6336 // If data is a string instead of a timestamp, we convert it
6337 if (!is_numeric($this->array_options[$key]) || $this->array_options[$key] != intval($this->array_options[$key])) {
6338 $this->array_options[$key] = strtotime($this->array_options[$key]);
6339 }
6340 $new_array_options[$key] = $this->db->idate($this->array_options[$key]);
6341 break;
6342 case 'datetimegmt':
6343 // If data is a string instead of a timestamp, we convert it
6344 if (!is_numeric($this->array_options[$key]) || $this->array_options[$key] != intval($this->array_options[$key])) {
6345 $this->array_options[$key] = strtotime($this->array_options[$key]);
6346 }
6347 $new_array_options[$key] = $this->db->idate($this->array_options[$key], 'gmt');
6348 break;
6349 case 'link':
6350 $param_list = array_keys($attributeParam['options']);
6351 // 0 : ObjectName
6352 // 1 : classPath
6353 $InfoFieldList = explode(":", $param_list[0]);
6354 dol_include_once($InfoFieldList[1]);
6355 if ($InfoFieldList[0] && class_exists($InfoFieldList[0])) {
6356 if ($value == '-1') { // -1 is key for no defined in combo list of objects
6357 $new_array_options[$key] = '';
6358 } elseif ($value) {
6359 $object = new $InfoFieldList[0]($this->db);
6360 if (is_numeric($value)) {
6361 $res = $object->fetch($value); // Common case
6362 } else {
6363 $res = $object->fetch('', $value); // For compatibility
6364 }
6365
6366 if ($res > 0) {
6367 $new_array_options[$key] = $object->id;
6368 } else {
6369 $this->error = "Id/Ref '".$value."' for object '".$object->element."' not found";
6370 return -1;
6371 }
6372 }
6373 } else {
6374 dol_syslog('Error bad setup of extrafield', LOG_WARNING);
6375 }
6376 break;
6377 case 'checkbox':
6378 case 'chkbxlst':
6379 if (is_array($this->array_options[$key])) {
6380 $new_array_options[$key] = implode(',', $this->array_options[$key]);
6381 } else {
6382 $new_array_options[$key] = $this->array_options[$key];
6383 }
6384 break;
6385 }
6386 }
6387
6388 $this->db->begin();
6389
6390 $table_element = $this->table_element;
6391 if ($table_element == 'categorie') {
6392 $table_element = 'categories'; // For compatibility
6393 }
6394
6395 dol_syslog(get_class($this)."::insertExtraFields delete then insert", LOG_DEBUG);
6396
6397 $sql_del = "DELETE FROM ".$this->db->prefix().$table_element."_extrafields WHERE fk_object = ".((int) $this->id);
6398 $this->db->query($sql_del);
6399
6400 $sql = "INSERT INTO ".$this->db->prefix().$table_element."_extrafields (fk_object";
6401 foreach ($new_array_options as $key => $value) {
6402 $attributeKey = substr($key, 8); // Remove 'options_' prefix
6403 // Add field of attribut
6404 if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] != 'separate') { // Only for other type than separator
6405 $sql .= ",".$attributeKey;
6406 }
6407 }
6408 // We must insert a default value for fields for other entities that are mandatory to avoid not null error
6409 if (!empty($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities']) && is_array($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities'])) {
6410 foreach ($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities'] as $tmpkey => $tmpval) {
6411 if (!isset($extrafields->attributes[$this->table_element]['type'][$tmpkey])) { // If field not already added previously
6412 $sql .= ",".$tmpkey;
6413 }
6414 }
6415 }
6416 $sql .= ") VALUES (".$this->id;
6417
6418 foreach ($new_array_options as $key => $value) {
6419 $attributeKey = substr($key, 8); // Remove 'options_' prefix
6420 // Add field of attribute
6421 if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] != 'separate') { // Only for other type than separator)
6422 if ($new_array_options[$key] != '' || $new_array_options[$key] == '0') {
6423 $sql .= ",'".$this->db->escape($new_array_options[$key])."'";
6424 } else {
6425 $sql .= ",null";
6426 }
6427 }
6428 }
6429 // We must insert a default value for fields for other entities that are mandatory to avoid not null error
6430 if (!empty($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities']) && is_array($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities'])) {
6431 foreach ($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities'] as $tmpkey => $tmpval) {
6432 if (!isset($extrafields->attributes[$this->table_element]['type'][$tmpkey])) { // If field not already added previously
6433 if (in_array($tmpval, array('int', 'double', 'price'))) {
6434 $sql .= ", 0";
6435 } else {
6436 $sql .= ", ''";
6437 }
6438 }
6439 }
6440 }
6441
6442 $sql .= ")";
6443
6444 $resql = $this->db->query($sql);
6445 if (!$resql) {
6446 $this->error = $this->db->lasterror();
6447 $error++;
6448 }
6449
6450 if (!$error && $trigger) {
6451 // Call trigger
6452 $this->context = array('extrafieldaddupdate'=>1);
6453 $result = $this->call_trigger($trigger, $userused);
6454 if ($result < 0) {
6455 $error++;
6456 }
6457 // End call trigger
6458 }
6459
6460 if ($error) {
6461 $this->db->rollback();
6462 return -1;
6463 } else {
6464 $this->db->commit();
6465 return 1;
6466 }
6467 } else {
6468 return 0;
6469 }
6470 }
6471
6482 public function insertExtraLanguages($trigger = '', $userused = null)
6483 {
6484 global $conf, $langs, $user;
6485
6486 if (empty($userused)) {
6487 $userused = $user;
6488 }
6489
6490 $error = 0;
6491
6492 if (!empty($conf->global->MAIN_EXTRALANGUAGES_DISABLED)) {
6493 return 0; // For avoid conflicts if trigger used
6494 }
6495
6496 if (is_array($this->array_languages)) {
6497 $new_array_languages = $this->array_languages;
6498
6499 foreach ($new_array_languages as $key => $value) {
6500 $attributeKey = $key;
6501 $attributeType = $this->fields[$attributeKey]['type'];
6502 $attributeLabel = $this->fields[$attributeKey]['label'];
6503
6504 //dol_syslog("attributeLabel=".$attributeLabel, LOG_DEBUG);
6505 //dol_syslog("attributeType=".$attributeType, LOG_DEBUG);
6506
6507 switch ($attributeType) {
6508 case 'int':
6509 if (!is_numeric($value) && $value != '') {
6510 $this->errors[] = $langs->trans("ExtraLanguageHasWrongValue", $attributeLabel);
6511 return -1;
6512 } elseif ($value == '') {
6513 $new_array_languages[$key] = null;
6514 }
6515 break;
6516 case 'double':
6517 $value = price2num($value);
6518 if (!is_numeric($value) && $value != '') {
6519 dol_syslog($langs->trans("ExtraLanguageHasWrongValue")." sur ".$attributeLabel."(".$value."is not '".$attributeType."')", LOG_DEBUG);
6520 $this->errors[] = $langs->trans("ExtraLanguageHasWrongValue", $attributeLabel);
6521 return -1;
6522 } elseif ($value == '') {
6523 $new_array_languages[$key] = null;
6524 } else {
6525 $new_array_languages[$key] = $value;
6526 }
6527 break;
6528 /*case 'select': // Not required, we chosed value='0' for undefined values
6529 if ($value=='-1')
6530 {
6531 $this->array_options[$key] = null;
6532 }
6533 break;*/
6534 }
6535 }
6536
6537 $this->db->begin();
6538
6539 $table_element = $this->table_element;
6540 if ($table_element == 'categorie') {
6541 $table_element = 'categories'; // For compatibility
6542 }
6543
6544 dol_syslog(get_class($this)."::insertExtraLanguages delete then insert", LOG_DEBUG);
6545
6546 foreach ($new_array_languages as $key => $langcodearray) { // $key = 'name', 'town', ...
6547 foreach ($langcodearray as $langcode => $value) {
6548 $sql_del = "DELETE FROM ".$this->db->prefix()."object_lang";
6549 $sql_del .= " WHERE fk_object = ".((int) $this->id)." AND property = '".$this->db->escape($key)."' AND type_object = '".$this->db->escape($table_element)."'";
6550 $sql_del .= " AND lang = '".$this->db->escape($langcode)."'";
6551 $this->db->query($sql_del);
6552
6553 if ($value !== '') {
6554 $sql = "INSERT INTO ".$this->db->prefix()."object_lang (fk_object, property, type_object, lang, value";
6555 $sql .= ") VALUES (".$this->id.", '".$this->db->escape($key)."', '".$this->db->escape($table_element)."', '".$this->db->escape($langcode)."', '".$this->db->escape($value)."'";
6556 $sql .= ")";
6557
6558 $resql = $this->db->query($sql);
6559 if (!$resql) {
6560 $this->error = $this->db->lasterror();
6561 $error++;
6562 break;
6563 }
6564 }
6565 }
6566 }
6567
6568 if (!$error && $trigger) {
6569 // Call trigger
6570 $this->context = array('extralanguagesaddupdate'=>1);
6571 $result = $this->call_trigger($trigger, $userused);
6572 if ($result < 0) {
6573 $error++;
6574 }
6575 // End call trigger
6576 }
6577
6578 if ($error) {
6579 $this->db->rollback();
6580 return -1;
6581 } else {
6582 $this->db->commit();
6583 return 1;
6584 }
6585 } else {
6586 return 0;
6587 }
6588 }
6589
6600 public function updateExtraField($key, $trigger = null, $userused = null)
6601 {
6602 global $conf, $langs, $user;
6603
6604 if (!empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) {
6605 return 0;
6606 }
6607
6608 if (empty($userused)) {
6609 $userused = $user;
6610 }
6611
6612 $error = 0;
6613
6614 if (!empty($this->array_options) && isset($this->array_options["options_".$key])) {
6615 // Check parameters
6616 $langs->load('admin');
6617 require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
6618 $extrafields = new ExtraFields($this->db);
6619 $extrafields->fetch_name_optionals_label($this->table_element);
6620
6621 $value = $this->array_options["options_".$key];
6622
6623 $attributeType = $extrafields->attributes[$this->table_element]['type'][$key];
6624 $attributeLabel = $extrafields->attributes[$this->table_element]['label'][$key];
6625 $attributeParam = $extrafields->attributes[$this->table_element]['param'][$key];
6626 $attributeRequired = $extrafields->attributes[$this->table_element]['required'][$key];
6627 $attrfieldcomputed = $extrafields->attributes[$this->table_element]['computed'][$key];
6628
6629 // Similar code than into insertExtraFields
6630 if ($attributeRequired) {
6631 $mandatorypb = false;
6632 if ($attributeType == 'link' && $this->array_options["options_".$key] == '-1') {
6633 $mandatorypb = true;
6634 }
6635 if ($this->array_options["options_".$key] === '') {
6636 $mandatorypb = true;
6637 }
6638 if ($mandatorypb) {
6639 $langs->load("errors");
6640 dol_syslog("Mandatory field 'options_".$key."' is empty during update and set to required into definition of extrafields");
6641 $this->errors[] = $langs->trans('ErrorFieldRequired', $attributeLabel);
6642 return -1;
6643 }
6644 }
6645
6646 //dol_syslog("attributeLabel=".$attributeLabel, LOG_DEBUG);
6647 //dol_syslog("attributeType=".$attributeType, LOG_DEBUG);
6648
6649 if (!empty($attrfieldcomputed)) {
6650 if (!empty($conf->global->MAIN_STORE_COMPUTED_EXTRAFIELDS)) {
6651 $value = dol_eval($attrfieldcomputed, 1, 0, '');
6652 dol_syslog($langs->trans("Extrafieldcomputed")." sur ".$attributeLabel."(".$value.")", LOG_DEBUG);
6653 $this->array_options["options_".$key] = $value;
6654 } else {
6655 $this->array_options["options_".$key] = null;
6656 }
6657 }
6658
6659 switch ($attributeType) {
6660 case 'int':
6661 if (!is_numeric($value) && $value != '') {
6662 $this->errors[] = $langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
6663 return -1;
6664 } elseif ($value === '') {
6665 $this->array_options["options_".$key] = null;
6666 }
6667 break;
6668 case 'price':
6669 case 'double':
6670 $value = price2num($value);
6671 if (!is_numeric($value) && $value != '') {
6672 dol_syslog($langs->trans("ExtraFieldHasWrongValue")." sur ".$attributeLabel."(".$value."is not '".$attributeType."')", LOG_DEBUG);
6673 $this->errors[] = $langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
6674 return -1;
6675 } elseif ($value === '') {
6676 $value = null;
6677 }
6678 //dol_syslog("double value"." sur ".$attributeLabel."(".$value." is '".$attributeType."')", LOG_DEBUG);
6679 $this->array_options["options_".$key] = $value;
6680 break;
6681 /*case 'select': // Not required, we chosed value='0' for undefined values
6682 if ($value=='-1')
6683 {
6684 $this->array_options[$key] = null;
6685 }
6686 break;*/
6687 case 'date':
6688 case 'datetime':
6689 if (empty($this->array_options["options_".$key])) {
6690 $this->array_options["options_".$key] = null;
6691 } else {
6692 $this->array_options["options_".$key] = $this->db->idate($this->array_options["options_".$key]);
6693 }
6694 break;
6695 case 'datetimegmt':
6696 if (empty($this->array_options["options_".$key])) {
6697 $this->array_options["options_".$key] = null;
6698 } else {
6699 $this->array_options["options_".$key] = $this->db->idate($this->array_options["options_".$key], 'gmt');
6700 }
6701 break;
6702 case 'boolean':
6703 if (empty($this->array_options["options_".$key])) {
6704 $this->array_options["options_".$key] = null;
6705 }
6706 break;
6707 case 'link':
6708 if ($this->array_options["options_".$key] === '') {
6709 $this->array_options["options_".$key] = null;
6710 }
6711 break;
6712 /*
6713 case 'link':
6714 $param_list = array_keys($attributeParam['options']);
6715 // 0 : ObjectName
6716 // 1 : classPath
6717 $InfoFieldList = explode(":", $param_list[0]);
6718 dol_include_once($InfoFieldList[1]);
6719 if ($InfoFieldList[0] && class_exists($InfoFieldList[0]))
6720 {
6721 if ($value == '-1') // -1 is key for no defined in combo list of objects
6722 {
6723 $new_array_options[$key] = '';
6724 } elseif ($value) {
6725 $object = new $InfoFieldList[0]($this->db);
6726 if (is_numeric($value)) $res = $object->fetch($value); // Common case
6727 else $res = $object->fetch('', $value); // For compatibility
6728
6729 if ($res > 0) $new_array_options[$key] = $object->id;
6730 else {
6731 $this->error = "Id/Ref '".$value."' for object '".$object->element."' not found";
6732 $this->db->rollback();
6733 return -1;
6734 }
6735 }
6736 } else {
6737 dol_syslog('Error bad setup of extrafield', LOG_WARNING);
6738 }
6739 break;
6740 */
6741 case 'checkbox':
6742 case 'chkbxlst':
6743 if (is_array($this->array_options[$key])) {
6744 $new_array_options[$key] = implode(',', $this->array_options[$key]);
6745 } else {
6746 $new_array_options[$key] = $this->array_options[$key];
6747 }
6748 break;
6749 }
6750
6751 $this->db->begin();
6752
6753 $linealreadyfound = 0;
6754
6755 // Check if there is already a line for this object (in most cases, it is, but sometimes it is not, for example when extra field has been created after), so we must keep this overload)
6756 $sql = "SELECT COUNT(rowid) as nb FROM ".$this->db->prefix().$this->table_element."_extrafields WHERE fk_object = ".((int) $this->id);
6757 $resql = $this->db->query($sql);
6758 if ($resql) {
6759 $tmpobj = $this->db->fetch_object($resql);
6760 if ($tmpobj) {
6761 $linealreadyfound = $tmpobj->nb;
6762 }
6763 }
6764
6765 if ($linealreadyfound) {
6766 if ($this->array_options["options_".$key] === null) {
6767 $sql = "UPDATE ".$this->db->prefix().$this->table_element."_extrafields SET ".$key." = null";
6768 } else {
6769 $sql = "UPDATE ".$this->db->prefix().$this->table_element."_extrafields SET ".$key." = '".$this->db->escape($this->array_options["options_".$key])."'";
6770 }
6771 $sql .= " WHERE fk_object = ".((int) $this->id);
6772 } else {
6773 $result = $this->insertExtraFields('', $user);
6774 if ($result < 0) {
6775 $error++;
6776 }
6777 }
6778
6779 $resql = $this->db->query($sql);
6780 if (!$resql) {
6781 $error++;
6782 $this->error = $this->db->lasterror();
6783 }
6784 if (!$error && $trigger) {
6785 // Call trigger
6786 $this->context = array('extrafieldupdate'=>1);
6787 $result = $this->call_trigger($trigger, $userused);
6788 if ($result < 0) {
6789 $error++;
6790 }
6791 // End call trigger
6792 }
6793
6794 if ($error) {
6795 dol_syslog(__METHOD__.$this->error, LOG_ERR);
6796 $this->db->rollback();
6797 return -1;
6798 } else {
6799 $this->db->commit();
6800 return 1;
6801 }
6802 } else {
6803 return 0;
6804 }
6805 }
6806
6817 public function updateExtraLanguages($key, $trigger = null, $userused = null)
6818 {
6819 global $conf, $langs, $user;
6820
6821 if (empty($userused)) {
6822 $userused = $user;
6823 }
6824
6825 $error = 0;
6826
6827 if (!empty($conf->global->MAIN_EXTRALANGUAGES_DISABLED)) {
6828 return 0; // For avoid conflicts if trigger used
6829 }
6830
6831 return 0;
6832 }
6833
6834
6849 public function showInputField($val, $key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = 0, $nonewbutton = 0)
6850 {
6851 global $conf, $langs, $form;
6852
6853 if (!is_object($form)) {
6854 require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
6855 $form = new Form($this->db);
6856 }
6857
6858 if (!empty($this->fields)) {
6859 $val = $this->fields[$key];
6860 }
6861
6862 // Validation tests and output
6863 $fieldValidationErrorMsg = '';
6864 $validationClass = '';
6865 $fieldValidationErrorMsg = $this->getFieldError($key);
6866 if (!empty($fieldValidationErrorMsg)) {
6867 $validationClass = ' --error'; // the -- is use as class state in css : .--error can't be be defined alone it must be define with another class like .my-class.--error or input.--error
6868 } else {
6869 $validationClass = ' --success'; // the -- is use as class state in css : .--success can't be be defined alone it must be define with another class like .my-class.--success or input.--success
6870 }
6871
6872 $out = '';
6873 $type = '';
6874 $isDependList = 0;
6875 $param = array();
6876 $param['options'] = array();
6877 $reg = array();
6878 $size = !empty($this->fields[$key]['size']) ? $this->fields[$key]['size'] : 0;
6879 // Because we work on extrafields
6880 if (preg_match('/^(integer|link):(.*):(.*):(.*):(.*)/i', $val['type'], $reg)) {
6881 $param['options'] = array($reg[2].':'.$reg[3].':'.$reg[4].':'.$reg[5] => 'N');
6882 $type = 'link';
6883 } elseif (preg_match('/^(integer|link):(.*):(.*):(.*)/i', $val['type'], $reg)) {
6884 $param['options'] = array($reg[2].':'.$reg[3].':'.$reg[4] => 'N');
6885 $type = 'link';
6886 } elseif (preg_match('/^(integer|link):(.*):(.*)/i', $val['type'], $reg)) {
6887 $param['options'] = array($reg[2].':'.$reg[3] => 'N');
6888 $type = 'link';
6889 } elseif (preg_match('/^(sellist):(.*):(.*):(.*):(.*)/i', $val['type'], $reg)) {
6890 $param['options'] = array($reg[2].':'.$reg[3].':'.$reg[4].':'.$reg[5] => 'N');
6891 $type = 'sellist';
6892 } elseif (preg_match('/^(sellist):(.*):(.*):(.*)/i', $val['type'], $reg)) {
6893 $param['options'] = array($reg[2].':'.$reg[3].':'.$reg[4] => 'N');
6894 $type = 'sellist';
6895 } elseif (preg_match('/^(sellist):(.*):(.*)/i', $val['type'], $reg)) {
6896 $param['options'] = array($reg[2].':'.$reg[3] => 'N');
6897 $type = 'sellist';
6898 } elseif (preg_match('/^chkbxlst:(.*)/i', $val['type'], $reg)) {
6899 $param['options'] = array($reg[1] => 'N');
6900 $type = 'chkbxlst';
6901 } elseif (preg_match('/varchar\‍((\d+)\‍)/', $val['type'], $reg)) {
6902 $param['options'] = array();
6903 $type = 'varchar';
6904 $size = $reg[1];
6905 } elseif (preg_match('/varchar/', $val['type'])) {
6906 $param['options'] = array();
6907 $type = 'varchar';
6908 } else {
6909 $param['options'] = array();
6910 $type = $this->fields[$key]['type'];
6911 }
6912
6913 // Special case that force options and type ($type can be integer, varchar, ...)
6914 if (!empty($this->fields[$key]['arrayofkeyval']) && is_array($this->fields[$key]['arrayofkeyval'])) {
6915 $param['options'] = $this->fields[$key]['arrayofkeyval'];
6916 $type = 'select';
6917 }
6918
6919 $label = $this->fields[$key]['label'];
6920 //$elementtype=$this->fields[$key]['elementtype']; // Seems not used
6921 $default = (!empty($this->fields[$key]['default']) ? $this->fields[$key]['default'] : '');
6922 $computed = (!empty($this->fields[$key]['computed']) ? $this->fields[$key]['computed'] : '');
6923 $unique = (!empty($this->fields[$key]['unique']) ? $this->fields[$key]['unique'] : 0);
6924 $required = (!empty($this->fields[$key]['required']) ? $this->fields[$key]['required'] : 0);
6925 $autofocusoncreate = (!empty($this->fields[$key]['autofocusoncreate']) ? $this->fields[$key]['autofocusoncreate'] : 0);
6926
6927 $langfile = (!empty($this->fields[$key]['langfile']) ? $this->fields[$key]['langfile'] : '');
6928 $list = (!empty($this->fields[$key]['list']) ? $this->fields[$key]['list'] : 0);
6929 $hidden = (in_array(abs($this->fields[$key]['visible']), array(0, 2)) ? 1 : 0);
6930
6931 $objectid = $this->id;
6932
6933 if ($computed) {
6934 if (!preg_match('/^search_/', $keyprefix)) {
6935 return '<span class="opacitymedium">'.$langs->trans("AutomaticallyCalculated").'</span>';
6936 } else {
6937 return '';
6938 }
6939 }
6940
6941 // Set value of $morecss. For this, we use in priority showsize from parameters, then $val['css'] then autodefine
6942 if (empty($morecss) && !empty($val['css'])) {
6943 $morecss = $val['css'];
6944 } elseif (empty($morecss)) {
6945 if ($type == 'date') {
6946 $morecss = 'minwidth100imp';
6947 } elseif ($type == 'datetime' || $type == 'link') { // link means an foreign key to another primary id
6948 $morecss = 'minwidth200imp';
6949 } elseif (in_array($type, array('int', 'integer', 'price')) || preg_match('/^double(\‍([0-9],[0-9]\‍)){0,1}/', $type)) {
6950 $morecss = 'maxwidth75';
6951 } elseif ($type == 'url') {
6952 $morecss = 'minwidth400';
6953 } elseif ($type == 'boolean') {
6954 $morecss = '';
6955 } else {
6956 if (round($size) < 12) {
6957 $morecss = 'minwidth100';
6958 } elseif (round($size) <= 48) {
6959 $morecss = 'minwidth200';
6960 } else {
6961 $morecss = 'minwidth400';
6962 }
6963 }
6964 }
6965
6966 // Add validation state class
6967 if (!empty($validationClass)) {
6968 $morecss.= $validationClass;
6969 }
6970
6971 if (in_array($type, array('date'))) {
6972 $tmp = explode(',', $size);
6973 $newsize = $tmp[0];
6974 $showtime = 0;
6975
6976 // Do not show current date when field not required (see selectDate() method)
6977 if (!$required && $value == '') {
6978 $value = '-1';
6979 }
6980
6981 // TODO Must also support $moreparam
6982 $out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1);
6983 } elseif (in_array($type, array('datetime'))) {
6984 $tmp = explode(',', $size);
6985 $newsize = $tmp[0];
6986 $showtime = 1;
6987
6988 // Do not show current date when field not required (see selectDate() method)
6989 if (!$required && $value == '') $value = '-1';
6990
6991 // TODO Must also support $moreparam
6992 $out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1, '', '', '', 1, '', '', 'tzuserrel');
6993 } elseif (in_array($type, array('duration'))) {
6994 $out = $form->select_duration($keyprefix.$key.$keysuffix, $value, 0, 'text', 0, 1);
6995 } elseif (in_array($type, array('int', 'integer'))) {
6996 $tmp = explode(',', $size);
6997 $newsize = $tmp[0];
6998 $out = '<input type="text" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'"'.($newsize > 0 ? ' maxlength="'.$newsize.'"' : '').' value="'.dol_escape_htmltag($value).'"'.($moreparam ? $moreparam : '').($autofocusoncreate ? ' autofocus' : '').'>';
6999 } elseif (in_array($type, array('real'))) {
7000 $out = '<input type="text" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'"'.($moreparam ? $moreparam : '').($autofocusoncreate ? ' autofocus' : '').'>';
7001 } elseif (preg_match('/varchar/', $type)) {
7002 $out = '<input type="text" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'"'.($size > 0 ? ' maxlength="'.$size.'"' : '').' value="'.dol_escape_htmltag($value).'"'.($moreparam ? $moreparam : '').($autofocusoncreate ? ' autofocus' : '').'>';
7003 } elseif (in_array($type, array('email', 'mail', 'phone', 'url', 'ip'))) {
7004 $out = '<input type="text" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').($autofocusoncreate ? ' autofocus' : '').'>';
7005 } elseif (preg_match('/^text/', $type)) {
7006 if (!preg_match('/search_/', $keyprefix)) { // If keyprefix is search_ or search_options_, we must just use a simple text field
7007 require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
7008 $doleditor = new DolEditor($keyprefix.$key.$keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, false, ROWS_5, '90%');
7009 $out = $doleditor->Create(1);
7010 } else {
7011 $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').'>';
7012 }
7013 } elseif (preg_match('/^html/', $type)) {
7014 if (!preg_match('/search_/', $keyprefix)) { // If keyprefix is search_ or search_options_, we must just use a simple text field
7015 require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
7016 $doleditor = new DolEditor($keyprefix.$key.$keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, isModEnabled('fckeditor') && $conf->global->FCKEDITOR_ENABLE_SOCIETE, ROWS_5, '90%');
7017 $out = $doleditor->Create(1, '', true, '', '', $moreparam, $morecss);
7018 } else {
7019 $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').'>';
7020 }
7021 } elseif ($type == 'boolean') {
7022 $checked = '';
7023 if (!empty($value)) {
7024 $checked = ' checked value="1" ';
7025 } else {
7026 $checked = ' value="1" ';
7027 }
7028 $out = '<input type="checkbox" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.$checked.' '.($moreparam ? $moreparam : '').'>';
7029 } elseif ($type == 'price') {
7030 if (!empty($value)) { // $value in memory is a php numeric, we format it into user number format.
7031 $value = price($value);
7032 }
7033 $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam ? $moreparam : '').'> '.$langs->getCurrencySymbol($conf->currency);
7034 } elseif (preg_match('/^double(\‍([0-9],[0-9]\‍)){0,1}/', $type)) {
7035 if (!empty($value)) { // $value in memory is a php numeric, we format it into user number format.
7036 $value = price($value);
7037 }
7038 $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam ? $moreparam : '').'> ';
7039 } elseif ($type == 'select') { // combo list
7040 $out = '';
7041 if (!empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_EXTRAFIELDS_DISABLE_SELECT2)) {
7042 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7043 $out .= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
7044 }
7045
7046 $out .= '<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam ? $moreparam : '').'>';
7047 if ((!isset($this->fields[$key]['default'])) || ($this->fields[$key]['notnull'] != 1)) {
7048 $out .= '<option value="0">&nbsp;</option>';
7049 }
7050 foreach ($param['options'] as $keyb => $valb) {
7051 if ((string) $keyb == '') {
7052 continue;
7053 }
7054 if (strpos($valb, "|") !== false) {
7055 list($valb, $parent) = explode('|', $valb);
7056 }
7057 $out .= '<option value="'.$keyb.'"';
7058 $out .= (((string) $value == (string) $keyb) ? ' selected' : '');
7059 $out .= (!empty($parent) ? ' parent="'.$parent.'"' : '');
7060 $out .= '>'.$valb.'</option>';
7061 }
7062 $out .= '</select>';
7063 } elseif ($type == 'sellist') {
7064 $out = '';
7065 if (!empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_EXTRAFIELDS_DISABLE_SELECT2)) {
7066 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7067 $out .= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
7068 }
7069
7070 $out .= '<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam ? $moreparam : '').'>';
7071 if (is_array($param['options'])) {
7072 $param_list = array_keys($param['options']);
7073 $InfoFieldList = explode(":", $param_list[0]);
7074 $parentName = '';
7075 $parentField = '';
7076 // 0 : tableName
7077 // 1 : label field name
7078 // 2 : key fields name (if differ of rowid)
7079 // 3 : key field parent (for dependent lists)
7080 // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
7081 // 5 : id category type
7082 // 6 : ids categories list separated by comma for category root
7083 $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2].' as rowid');
7084
7085 if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
7086 if (strpos($InfoFieldList[4], 'extra.') !== false) {
7087 $keyList = 'main.'.$InfoFieldList[2].' as rowid';
7088 } else {
7089 $keyList = $InfoFieldList[2].' as rowid';
7090 }
7091 }
7092 if (count($InfoFieldList) > 3 && !empty($InfoFieldList[3])) {
7093 list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
7094 $keyList .= ', '.$parentField;
7095 }
7096
7097 $filter_categorie = false;
7098 if (count($InfoFieldList) > 5) {
7099 if ($InfoFieldList[0] == 'categorie') {
7100 $filter_categorie = true;
7101 }
7102 }
7103
7104 if ($filter_categorie === false) {
7105 $fields_label = explode('|', $InfoFieldList[1]);
7106 if (is_array($fields_label)) {
7107 $keyList .= ', ';
7108 $keyList .= implode(', ', $fields_label);
7109 }
7110
7111 $sqlwhere = '';
7112 $sql = "SELECT " . $keyList;
7113 $sql .= " FROM " . $this->db->prefix() . $InfoFieldList[0];
7114 if (!empty($InfoFieldList[4])) {
7115 // can use SELECT request
7116 if (strpos($InfoFieldList[4], '$SEL$') !== false) {
7117 $InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]);
7118 }
7119
7120 // current object id can be use into filter
7121 if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) {
7122 $InfoFieldList[4] = str_replace('$ID$', $objectid, $InfoFieldList[4]);
7123 } else {
7124 $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
7125 }
7126
7127 //We have to join on extrafield table
7128 if (strpos($InfoFieldList[4], 'extra') !== false) {
7129 $sql .= " as main, " . $this->db->prefix() . $InfoFieldList[0] . "_extrafields as extra";
7130 $sqlwhere .= " WHERE extra.fk_object=main." . $InfoFieldList[2] . " AND " . $InfoFieldList[4];
7131 } else {
7132 $sqlwhere .= " WHERE " . $InfoFieldList[4];
7133 }
7134 } else {
7135 $sqlwhere .= ' WHERE 1=1';
7136 }
7137 // Some tables may have field, some other not. For the moment we disable it.
7138 if (in_array($InfoFieldList[0], array('tablewithentity'))) {
7139 $sqlwhere .= " AND entity = " . ((int) $conf->entity);
7140 }
7141 $sql .= $sqlwhere;
7142 //print $sql;
7143
7144 $sql .= ' ORDER BY ' . implode(', ', $fields_label);
7145
7146 dol_syslog(get_class($this) . '::showInputField type=sellist', LOG_DEBUG);
7147 $resql = $this->db->query($sql);
7148 if ($resql) {
7149 $out .= '<option value="0">&nbsp;</option>';
7150 $num = $this->db->num_rows($resql);
7151 $i = 0;
7152 while ($i < $num) {
7153 $labeltoshow = '';
7154 $obj = $this->db->fetch_object($resql);
7155
7156 // Several field into label (eq table:code|libelle:rowid)
7157 $notrans = false;
7158 $fields_label = explode('|', $InfoFieldList[1]);
7159 if (count($fields_label) > 1) {
7160 $notrans = true;
7161 foreach ($fields_label as $field_toshow) {
7162 $labeltoshow .= $obj->$field_toshow . ' ';
7163 }
7164 } else {
7165 $labeltoshow = $obj->{$InfoFieldList[1]};
7166 }
7167 $labeltoshow = dol_trunc($labeltoshow, 45);
7168
7169 if ($value == $obj->rowid) {
7170 foreach ($fields_label as $field_toshow) {
7171 $translabel = $langs->trans($obj->$field_toshow);
7172 if ($translabel != $obj->$field_toshow) {
7173 $labeltoshow = dol_trunc($translabel) . ' ';
7174 } else {
7175 $labeltoshow = dol_trunc($obj->$field_toshow) . ' ';
7176 }
7177 }
7178 $out .= '<option value="' . $obj->rowid . '" selected>' . $labeltoshow . '</option>';
7179 } else {
7180 if (!$notrans) {
7181 $translabel = $langs->trans($obj->{$InfoFieldList[1]});
7182 if ($translabel != $obj->{$InfoFieldList[1]}) {
7183 $labeltoshow = dol_trunc($translabel, 18);
7184 } else {
7185 $labeltoshow = dol_trunc($obj->{$InfoFieldList[1]});
7186 }
7187 }
7188 if (empty($labeltoshow)) {
7189 $labeltoshow = '(not defined)';
7190 }
7191 if ($value == $obj->rowid) {
7192 $out .= '<option value="' . $obj->rowid . '" selected>' . $labeltoshow . '</option>';
7193 }
7194
7195 if (!empty($InfoFieldList[3]) && $parentField) {
7196 $parent = $parentName . ':' . $obj->{$parentField};
7197 $isDependList = 1;
7198 }
7199
7200 $out .= '<option value="' . $obj->rowid . '"';
7201 $out .= ($value == $obj->rowid ? ' selected' : '');
7202 $out .= (!empty($parent) ? ' parent="' . $parent . '"' : '');
7203 $out .= '>' . $labeltoshow . '</option>';
7204 }
7205
7206 $i++;
7207 }
7208 $this->db->free($resql);
7209 } else {
7210 print 'Error in request ' . $sql . ' ' . $this->db->lasterror() . '. Check setup of extra parameters.<br>';
7211 }
7212 } else {
7213 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
7214 $data = $form->select_all_categories(Categorie::$MAP_ID_TO_CODE[$InfoFieldList[5]], '', 'parent', 64, $InfoFieldList[6], 1, 1);
7215 $out .= '<option value="0">&nbsp;</option>';
7216 foreach ($data as $data_key => $data_value) {
7217 $out .= '<option value="' . $data_key . '"';
7218 $out .= ($value == $data_key ? ' selected' : '');
7219 $out .= '>' . $data_value . '</option>';
7220 }
7221 }
7222 }
7223 $out .= '</select>';
7224 } elseif ($type == 'checkbox') {
7225 $value_arr = explode(',', $value);
7226 $out = $form->multiselectarray($keyprefix.$key.$keysuffix, (empty($param['options']) ?null:$param['options']), $value_arr, '', 0, $morecss, 0, '100%');
7227 } elseif ($type == 'radio') {
7228 $out = '';
7229 foreach ($param['options'] as $keyopt => $valopt) {
7230 $out .= '<input class="flat '.$morecss.'" type="radio" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam ? $moreparam : '');
7231 $out .= ' value="'.$keyopt.'"';
7232 $out .= ' id="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'"';
7233 $out .= ($value == $keyopt ? 'checked' : '');
7234 $out .= '/><label for="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'">'.$valopt.'</label><br>';
7235 }
7236 } elseif ($type == 'chkbxlst') {
7237 if (is_array($value)) {
7238 $value_arr = $value;
7239 } else {
7240 $value_arr = explode(',', $value);
7241 }
7242
7243 if (is_array($param['options'])) {
7244 $param_list = array_keys($param['options']);
7245 $InfoFieldList = explode(":", $param_list[0]);
7246 $parentName = '';
7247 $parentField = '';
7248 // 0 : tableName
7249 // 1 : label field name
7250 // 2 : key fields name (if differ of rowid)
7251 // 3 : key field parent (for dependent lists)
7252 // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
7253 // 5 : id category type
7254 // 6 : ids categories list separated by comma for category root
7255 $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2].' as rowid');
7256
7257 if (count($InfoFieldList) > 3 && !empty($InfoFieldList[3])) {
7258 list ($parentName, $parentField) = explode('|', $InfoFieldList[3]);
7259 $keyList .= ', '.$parentField;
7260 }
7261 if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
7262 if (strpos($InfoFieldList[4], 'extra.') !== false) {
7263 $keyList = 'main.'.$InfoFieldList[2].' as rowid';
7264 } else {
7265 $keyList = $InfoFieldList[2].' as rowid';
7266 }
7267 }
7268
7269 $filter_categorie = false;
7270 if (count($InfoFieldList) > 5) {
7271 if ($InfoFieldList[0] == 'categorie') {
7272 $filter_categorie = true;
7273 }
7274 }
7275
7276 if ($filter_categorie === false) {
7277 $fields_label = explode('|', $InfoFieldList[1]);
7278 if (is_array($fields_label)) {
7279 $keyList .= ', ';
7280 $keyList .= implode(', ', $fields_label);
7281 }
7282
7283 $sqlwhere = '';
7284 $sql = "SELECT " . $keyList;
7285 $sql .= ' FROM ' . $this->db->prefix() . $InfoFieldList[0];
7286 if (!empty($InfoFieldList[4])) {
7287 // can use SELECT request
7288 if (strpos($InfoFieldList[4], '$SEL$') !== false) {
7289 $InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]);
7290 }
7291
7292 // current object id can be use into filter
7293 if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) {
7294 $InfoFieldList[4] = str_replace('$ID$', $objectid, $InfoFieldList[4]);
7295 } else {
7296 $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
7297 }
7298
7299 // We have to join on extrafield table
7300 if (strpos($InfoFieldList[4], 'extra') !== false) {
7301 $sql .= ' as main, ' . $this->db->prefix() . $InfoFieldList[0] . '_extrafields as extra';
7302 $sqlwhere .= " WHERE extra.fk_object=main." . $InfoFieldList[2] . " AND " . $InfoFieldList[4];
7303 } else {
7304 $sqlwhere .= " WHERE " . $InfoFieldList[4];
7305 }
7306 } else {
7307 $sqlwhere .= ' WHERE 1=1';
7308 }
7309 // Some tables may have field, some other not. For the moment we disable it.
7310 if (in_array($InfoFieldList[0], array('tablewithentity'))) {
7311 $sqlwhere .= " AND entity = " . ((int) $conf->entity);
7312 }
7313 // $sql.=preg_replace('/^ AND /','',$sqlwhere);
7314 // print $sql;
7315
7316 $sql .= $sqlwhere;
7317 dol_syslog(get_class($this) . '::showInputField type=chkbxlst', LOG_DEBUG);
7318 $resql = $this->db->query($sql);
7319 if ($resql) {
7320 $num = $this->db->num_rows($resql);
7321 $i = 0;
7322
7323 $data = array();
7324
7325 while ($i < $num) {
7326 $labeltoshow = '';
7327 $obj = $this->db->fetch_object($resql);
7328
7329 $notrans = false;
7330 // Several field into label (eq table:code|libelle:rowid)
7331 $fields_label = explode('|', $InfoFieldList[1]);
7332 if (count($fields_label) > 1) {
7333 $notrans = true;
7334 foreach ($fields_label as $field_toshow) {
7335 $labeltoshow .= $obj->$field_toshow . ' ';
7336 }
7337 } else {
7338 $labeltoshow = $obj->{$InfoFieldList[1]};
7339 }
7340 $labeltoshow = dol_trunc($labeltoshow, 45);
7341
7342 if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
7343 foreach ($fields_label as $field_toshow) {
7344 $translabel = $langs->trans($obj->$field_toshow);
7345 if ($translabel != $obj->$field_toshow) {
7346 $labeltoshow = dol_trunc($translabel, 18) . ' ';
7347 } else {
7348 $labeltoshow = dol_trunc($obj->$field_toshow, 18) . ' ';
7349 }
7350 }
7351
7352 $data[$obj->rowid] = $labeltoshow;
7353 } else {
7354 if (!$notrans) {
7355 $translabel = $langs->trans($obj->{$InfoFieldList[1]});
7356 if ($translabel != $obj->{$InfoFieldList[1]}) {
7357 $labeltoshow = dol_trunc($translabel, 18);
7358 } else {
7359 $labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18);
7360 }
7361 }
7362 if (empty($labeltoshow)) {
7363 $labeltoshow = '(not defined)';
7364 }
7365
7366 if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
7367 $data[$obj->rowid] = $labeltoshow;
7368 }
7369
7370 if (!empty($InfoFieldList[3]) && $parentField) {
7371 $parent = $parentName . ':' . $obj->{$parentField};
7372 $isDependList = 1;
7373 }
7374
7375 $data[$obj->rowid] = $labeltoshow;
7376 }
7377
7378 $i++;
7379 }
7380 $this->db->free($resql);
7381
7382 $out = $form->multiselectarray($keyprefix . $key . $keysuffix, $data, $value_arr, '', 0, $morecss, 0, '100%');
7383 } else {
7384 print 'Error in request ' . $sql . ' ' . $this->db->lasterror() . '. Check setup of extra parameters.<br>';
7385 }
7386 } else {
7387 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
7388 $data = $form->select_all_categories(Categorie::$MAP_ID_TO_CODE[$InfoFieldList[5]], '', 'parent', 64, $InfoFieldList[6], 1, 1);
7389 $out = $form->multiselectarray($keyprefix . $key . $keysuffix, $data, $value_arr, '', 0, $morecss, 0, '100%');
7390 }
7391 }
7392 } elseif ($type == 'link') {
7393 $param_list = array_keys($param['options']); // $param_list='ObjectName:classPath[:AddCreateButtonOrNot[:Filter[:Sortfield]]]'
7394 $param_list_array = explode(':', $param_list[0]);
7395 $showempty = (($required && $default != '') ? 0 : 1);
7396
7397 if (!preg_match('/search_/', $keyprefix)) {
7398 if (!empty($param_list_array[2])) { // If the entry into $fields is set to add a create button
7399 if (!empty($this->fields[$key]['picto'])) {
7400 $morecss .= ' widthcentpercentminusxx';
7401 } else {
7402 $morecss .= ' widthcentpercentminusx';
7403 }
7404 } else {
7405 if (!empty($this->fields[$key]['picto'])) {
7406 $morecss .= ' widthcentpercentminusx';
7407 }
7408 }
7409 }
7410
7411 $out = $form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty, '', '', $morecss, $moreparam, 0, empty($val['disabled']) ? 0 : 1);
7412
7413 if (!empty($param_list_array[2])) { // If the entry into $fields is set, we must add a create button
7414 if ((!GETPOSTISSET('backtopage') || strpos(GETPOST('backtopage'), $_SERVER['PHP_SELF']) === 0) // // To avoid to open several times the 'Plus' button (we accept only one level)
7415 && empty($val['disabled']) && empty($nonewbutton)) { // and to avoid to show the button if the field is protected by a "disabled".
7416 list($class, $classfile) = explode(':', $param_list[0]);
7417 if (file_exists(dol_buildpath(dirname(dirname($classfile)).'/card.php'))) {
7418 $url_path = dol_buildpath(dirname(dirname($classfile)).'/card.php', 1);
7419 } else {
7420 $url_path = dol_buildpath(dirname(dirname($classfile)).'/'.strtolower($class).'_card.php', 1);
7421 }
7422 $paramforthenewlink = '';
7423 $paramforthenewlink .= (GETPOSTISSET('action') ? '&action='.GETPOST('action', 'aZ09') : '');
7424 $paramforthenewlink .= (GETPOSTISSET('id') ? '&id='.GETPOST('id', 'int') : '');
7425 $paramforthenewlink .= (GETPOSTISSET('origin') ? '&origin='.GETPOST('origin', 'aZ09') : '');
7426 $paramforthenewlink .= (GETPOSTISSET('originid') ? '&originid='.GETPOST('originid', 'int') : '');
7427 $paramforthenewlink .= '&fk_'.strtolower($class).'=--IDFORBACKTOPAGE--';
7428 // TODO Add Javascript code to add input fields already filled into $paramforthenewlink so we won't loose them when going back to main page
7429 $out .= '<a class="butActionNew" title="'.$langs->trans("New").'" href="'.$url_path.'?action=create&backtopage='.urlencode($_SERVER['PHP_SELF'].($paramforthenewlink ? '?'.$paramforthenewlink : '')).'"><span class="fa fa-plus-circle valignmiddle"></span></a>';
7430 }
7431 }
7432 } elseif ($type == 'password') {
7433 // If prefix is 'search_', field is used as a filter, we use a common text field.
7434 $out = '<input type="'.($keyprefix == 'search_' ? 'text' : 'password').'" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam ? $moreparam : '').'>';
7435 } elseif ($type == 'array') {
7436 $newval = $val;
7437 $newval['type'] = 'varchar(256)';
7438
7439 $out = '';
7440 if (!empty($value)) {
7441 foreach ($value as $option) {
7442 $out .= '<span><a class="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_del" href="javascript:;"><span class="fa fa-minus-circle valignmiddle"></span></a> ';
7443 $out .= $this->showInputField($newval, $keyprefix.$key.$keysuffix.'[]', $option, $moreparam, '', '', $morecss).'<br></span>';
7444 }
7445 }
7446 $out .= '<a id="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_add" href="javascript:;"><span class="fa fa-plus-circle valignmiddle"></span></a>';
7447
7448 $newInput = '<span><a class="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_del" href="javascript:;"><span class="fa fa-minus-circle valignmiddle"></span></a> ';
7449 $newInput .= $this->showInputField($newval, $keyprefix.$key.$keysuffix.'[]', '', $moreparam, '', '', $morecss).'<br></span>';
7450
7451 if (!empty($conf->use_javascript_ajax)) {
7452 $out .= '
7453 <script nonce="'.getNonce().'">
7454 $(document).ready(function() {
7455 $("a#'.dol_escape_js($keyprefix.$key.$keysuffix).'_add").click(function() {
7456 $("'.dol_escape_js($newInput).'").insertBefore(this);
7457 });
7458
7459 $(document).on("click", "a.'.dol_escape_js($keyprefix.$key.$keysuffix).'_del", function() {
7460 $(this).parent().remove();
7461 });
7462 });
7463 </script>';
7464 }
7465 }
7466 if (!empty($hidden)) {
7467 $out = '<input type="hidden" value="'.$value.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'"/>';
7468 }
7469
7470 if ($isDependList==1) {
7471 $out .= $this->getJSListDependancies('_common');
7472 }
7473 /* Add comments
7474 if ($type == 'date') $out.=' (YYYY-MM-DD)';
7475 elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)';
7476 */
7477
7478 // Display error message for field
7479 if (!empty($fieldValidationErrorMsg) && function_exists('getFieldErrorIcon')) {
7480 $out .= ' '.getFieldErrorIcon($fieldValidationErrorMsg);
7481 }
7482
7483 return $out;
7484 }
7485
7499 public function showOutputField($val, $key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = '')
7500 {
7501 global $conf, $langs, $form;
7502
7503 if (!is_object($form)) {
7504 require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
7505 $form = new Form($this->db);
7506 }
7507
7508 $label = empty($val['label']) ? '' : $val['label'];
7509 $type = empty($val['type']) ? '' : $val['type'];
7510 $size = empty($val['css']) ? '' : $val['css'];
7511 $reg = array();
7512
7513 // Convert var to be able to share same code than showOutputField of extrafields
7514 if (preg_match('/varchar\‍((\d+)\‍)/', $type, $reg)) {
7515 $type = 'varchar'; // convert varchar(xx) int varchar
7516 $size = $reg[1];
7517 } elseif (preg_match('/varchar/', $type)) {
7518 $type = 'varchar'; // convert varchar(xx) int varchar
7519 }
7520 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
7521 $type = 'select';
7522 }
7523 if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) {
7524 $type = 'link';
7525 }
7526
7527 $default = empty($val['default']) ? '' : $val['default'];
7528 $computed = empty($val['computed']) ? '' : $val['computed'];
7529 $unique = empty($val['unique']) ? '' : $val['unique'];
7530 $required = empty($val['required']) ? '' : $val['required'];
7531 $param = array();
7532 $param['options'] = array();
7533
7534 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
7535 $param['options'] = $val['arrayofkeyval'];
7536 }
7537 if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) {
7538 $type = 'link';
7539 $stringforoptions = $reg[1].':'.$reg[2];
7540 if ($reg[1] == 'User') {
7541 $stringforoptions .= ':-1';
7542 }
7543 $param['options'] = array($stringforoptions => $stringforoptions);
7544 } elseif (preg_match('/^sellist:(.*):(.*):(.*):(.*)/i', $val['type'], $reg)) {
7545 $param['options'] = array($reg[1].':'.$reg[2].':'.$reg[3].':'.$reg[4] => 'N');
7546 $type = 'sellist';
7547 } elseif (preg_match('/^sellist:(.*):(.*):(.*)/i', $val['type'], $reg)) {
7548 $param['options'] = array($reg[1].':'.$reg[2].':'.$reg[3] => 'N');
7549 $type = 'sellist';
7550 } elseif (preg_match('/^sellist:(.*):(.*)/i', $val['type'], $reg)) {
7551 $param['options'] = array($reg[1].':'.$reg[2] => 'N');
7552 $type = 'sellist';
7553 } elseif (preg_match('/^chkbxlst:(.*)/i', $val['type'], $reg)) {
7554 $param['options'] = array($reg[1] => 'N');
7555 $type = 'chkbxlst';
7556 }
7557
7558 $langfile = empty($val['langfile']) ? '' : $val['langfile'];
7559 $list = (empty($val['list']) ? '' : $val['list']);
7560 $help = (empty($val['help']) ? '' : $val['help']);
7561 $hidden = (($val['visible'] == 0) ? 1 : 0); // If zero, we are sure it is hidden, otherwise we show. If it depends on mode (view/create/edit form or list, this must be filtered by caller)
7562
7563 if ($hidden) {
7564 return '';
7565 }
7566
7567 // If field is a computed field, value must become result of compute
7568 if ($computed) {
7569 // Make the eval of compute string
7570 //var_dump($computed);
7571 $value = dol_eval($computed, 1, 0, '');
7572 }
7573
7574 if (empty($morecss)) {
7575 if ($type == 'date') {
7576 $morecss = 'minwidth100imp';
7577 } elseif ($type == 'datetime' || $type == 'timestamp') {
7578 $morecss = 'minwidth200imp';
7579 } elseif (in_array($type, array('int', 'double', 'price'))) {
7580 $morecss = 'maxwidth75';
7581 } elseif ($type == 'url') {
7582 $morecss = 'minwidth400';
7583 } elseif ($type == 'boolean') {
7584 $morecss = '';
7585 } else {
7586 if (is_numeric($size) && round($size) < 12) {
7587 $morecss = 'minwidth100';
7588 } elseif (is_numeric($size) && round($size) <= 48) {
7589 $morecss = 'minwidth200';
7590 } else {
7591 $morecss = 'minwidth400';
7592 }
7593 }
7594 }
7595
7596 // Format output value differently according to properties of field
7597 if (in_array($key, array('rowid', 'ref')) && method_exists($this, 'getNomUrl')) {
7598 if ($key != 'rowid' || empty($this->fields['ref'])) { // If we want ref field or if we want ID and there is no ref field, we show the link.
7599 $value = $this->getNomUrl(1, '', 0, '', 1);
7600 }
7601 } elseif ($key == 'status' && method_exists($this, 'getLibStatut')) {
7602 $value = $this->getLibStatut(3);
7603 } elseif ($type == 'date') {
7604 if (!empty($value)) {
7605 $value = dol_print_date($value, 'day'); // We suppose dates without time are always gmt (storage of course + output)
7606 } else {
7607 $value = '';
7608 }
7609 } elseif ($type == 'datetime' || $type == 'timestamp') {
7610 if (!empty($value)) {
7611 $value = dol_print_date($value, 'dayhour', 'tzuserrel');
7612 } else {
7613 $value = '';
7614 }
7615 } elseif ($type == 'duration') {
7616 include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
7617 if (!is_null($value) && $value !== '') {
7618 $value = convertSecondToTime($value, 'allhourmin');
7619 }
7620 } elseif ($type == 'double' || $type == 'real') {
7621 if (!is_null($value) && $value !== '') {
7622 $value = price($value);
7623 }
7624 } elseif ($type == 'boolean') {
7625 $checked = '';
7626 if (!empty($value)) {
7627 $checked = ' checked ';
7628 }
7629 $value = '<input type="checkbox" '.$checked.' '.($moreparam ? $moreparam : '').' readonly disabled>';
7630 } elseif ($type == 'mail' || $type == 'email') {
7631 $value = dol_print_email($value, 0, 0, 0, 64, 1, 1);
7632 } elseif ($type == 'url') {
7633 $value = dol_print_url($value, '_blank', 32, 1);
7634 } elseif ($type == 'phone') {
7635 $value = dol_print_phone($value, '', 0, 0, '', '&nbsp;', 'phone');
7636 } elseif ($type == 'ip') {
7637 $value = dol_print_ip($value, 0);
7638 } elseif ($type == 'price') {
7639 if (!is_null($value) && $value !== '') {
7640 $value = price($value, 0, $langs, 0, 0, -1, $conf->currency);
7641 }
7642 } elseif ($type == 'select') {
7643 $value = isset($param['options'][$value])?$param['options'][$value]:'';
7644 } elseif ($type == 'sellist') {
7645 $param_list = array_keys($param['options']);
7646 $InfoFieldList = explode(":", $param_list[0]);
7647
7648 $selectkey = "rowid";
7649 $keyList = 'rowid';
7650
7651 if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
7652 $selectkey = $InfoFieldList[2];
7653 $keyList = $InfoFieldList[2].' as rowid';
7654 }
7655
7656 $fields_label = explode('|', $InfoFieldList[1]);
7657 if (is_array($fields_label)) {
7658 $keyList .= ', ';
7659 $keyList .= implode(', ', $fields_label);
7660 }
7661
7662 $filter_categorie = false;
7663 if (count($InfoFieldList) > 5) {
7664 if ($InfoFieldList[0] == 'categorie') {
7665 $filter_categorie = true;
7666 }
7667 }
7668
7669 $sql = "SELECT ".$keyList;
7670 $sql .= ' FROM '.$this->db->prefix().$InfoFieldList[0];
7671 if (strpos($InfoFieldList[4], 'extra') !== false) {
7672 $sql .= ' as main';
7673 }
7674 if ($selectkey == 'rowid' && empty($value)) {
7675 $sql .= " WHERE ".$selectkey." = 0";
7676 } elseif ($selectkey == 'rowid') {
7677 $sql .= " WHERE ".$selectkey." = ".((int) $value);
7678 } else {
7679 $sql .= " WHERE ".$selectkey." = '".$this->db->escape($value)."'";
7680 }
7681
7682 //$sql.= ' AND entity = '.$conf->entity;
7683
7684 dol_syslog(get_class($this).':showOutputField:$type=sellist', LOG_DEBUG);
7685 $resql = $this->db->query($sql);
7686 if ($resql) {
7687 if ($filter_categorie === false) {
7688 $value = ''; // value was used, so now we reste it to use it to build final output
7689 $numrows = $this->db->num_rows($resql);
7690 if ($numrows) {
7691 $obj = $this->db->fetch_object($resql);
7692
7693 // Several field into label (eq table:code|libelle:rowid)
7694 $fields_label = explode('|', $InfoFieldList[1]);
7695
7696 if (is_array($fields_label) && count($fields_label) > 1) {
7697 foreach ($fields_label as $field_toshow) {
7698 $translabel = '';
7699 if (!empty($obj->$field_toshow)) {
7700 $translabel = $langs->trans($obj->$field_toshow);
7701 }
7702 if ($translabel != $field_toshow) {
7703 $value .= dol_trunc($translabel, 18) . ' ';
7704 } else {
7705 $value .= $obj->$field_toshow . ' ';
7706 }
7707 }
7708 } else {
7709 $translabel = '';
7710 if (!empty($obj->{$InfoFieldList[1]})) {
7711 $translabel = $langs->trans($obj->{$InfoFieldList[1]});
7712 }
7713 if ($translabel != $obj->{$InfoFieldList[1]}) {
7714 $value = dol_trunc($translabel, 18);
7715 } else {
7716 $value = $obj->{$InfoFieldList[1]};
7717 }
7718 }
7719 }
7720 } else {
7721 require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
7722
7723 $toprint = array();
7724 $obj = $this->db->fetch_object($resql);
7725 $c = new Categorie($this->db);
7726 $c->fetch($obj->rowid);
7727 $ways = $c->print_all_ways(); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
7728 foreach ($ways as $way) {
7729 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"' . ($c->color ? ' style="background: #' . $c->color . ';"' : ' style="background: #aaa"') . '>' . img_object('', 'category') . ' ' . $way . '</li>';
7730 }
7731 $value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
7732 }
7733 } else {
7734 dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
7735 }
7736 } elseif ($type == 'radio') {
7737 $value = $param['options'][$value];
7738 } elseif ($type == 'checkbox') {
7739 $value_arr = explode(',', $value);
7740 $value = '';
7741 if (is_array($value_arr) && count($value_arr) > 0) {
7742 $toprint = array();
7743 foreach ($value_arr as $keyval => $valueval) {
7744 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">'.$param['options'][$valueval].'</li>';
7745 }
7746 $value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
7747 }
7748 } elseif ($type == 'chkbxlst') {
7749 $value_arr = explode(',', $value);
7750
7751 $param_list = array_keys($param['options']);
7752 $InfoFieldList = explode(":", $param_list[0]);
7753
7754 $selectkey = "rowid";
7755 $keyList = 'rowid';
7756
7757 if (count($InfoFieldList) >= 3) {
7758 $selectkey = $InfoFieldList[2];
7759 $keyList = $InfoFieldList[2].' as rowid';
7760 }
7761
7762 $fields_label = explode('|', $InfoFieldList[1]);
7763 if (is_array($fields_label)) {
7764 $keyList .= ', ';
7765 $keyList .= implode(', ', $fields_label);
7766 }
7767
7768 $filter_categorie = false;
7769 if (count($InfoFieldList) > 5) {
7770 if ($InfoFieldList[0] == 'categorie') {
7771 $filter_categorie = true;
7772 }
7773 }
7774
7775 $sql = "SELECT ".$keyList;
7776 $sql .= ' FROM '.$this->db->prefix().$InfoFieldList[0];
7777 if (strpos($InfoFieldList[4], 'extra') !== false) {
7778 $sql .= ' as main';
7779 }
7780 // $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
7781 // $sql.= ' AND entity = '.$conf->entity;
7782
7783 dol_syslog(get_class($this).':showOutputField:$type=chkbxlst', LOG_DEBUG);
7784 $resql = $this->db->query($sql);
7785 if ($resql) {
7786 if ($filter_categorie === false) {
7787 $value = ''; // value was used, so now we reste it to use it to build final output
7788 $toprint = array();
7789 while ($obj = $this->db->fetch_object($resql)) {
7790 // Several field into label (eq table:code|libelle:rowid)
7791 $fields_label = explode('|', $InfoFieldList[1]);
7792 if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
7793 if (is_array($fields_label) && count($fields_label) > 1) {
7794 foreach ($fields_label as $field_toshow) {
7795 $translabel = '';
7796 if (!empty($obj->$field_toshow)) {
7797 $translabel = $langs->trans($obj->$field_toshow);
7798 }
7799 if ($translabel != $field_toshow) {
7800 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">' . dol_trunc($translabel, 18) . '</li>';
7801 } else {
7802 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">' . $obj->$field_toshow . '</li>';
7803 }
7804 }
7805 } else {
7806 $translabel = '';
7807 if (!empty($obj->{$InfoFieldList[1]})) {
7808 $translabel = $langs->trans($obj->{$InfoFieldList[1]});
7809 }
7810 if ($translabel != $obj->{$InfoFieldList[1]}) {
7811 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">' . dol_trunc($translabel, 18) . '</li>';
7812 } else {
7813 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">' . $obj->{$InfoFieldList[1]} . '</li>';
7814 }
7815 }
7816 }
7817 }
7818 } else {
7819 require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
7820
7821 $toprint = array();
7822 while ($obj = $this->db->fetch_object($resql)) {
7823 if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
7824 $c = new Categorie($this->db);
7825 $c->fetch($obj->rowid);
7826 $ways = $c->print_all_ways(); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
7827 foreach ($ways as $way) {
7828 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"' . ($c->color ? ' style="background: #' . $c->color . ';"' : ' style="background: #aaa"') . '>' . img_object('', 'category') . ' ' . $way . '</li>';
7829 }
7830 }
7831 }
7832 }
7833 $value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
7834 } else {
7835 dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
7836 }
7837 } elseif ($type == 'link') {
7838 $out = '';
7839
7840 // only if something to display (perf)
7841 if ($value) {
7842 $param_list = array_keys($param['options']); // Example: $param_list='ObjectName:classPath:-1::customer'
7843
7844 $InfoFieldList = explode(":", $param_list[0]);
7845 $classname = $InfoFieldList[0];
7846 $classpath = $InfoFieldList[1];
7847 $getnomurlparam = (empty($InfoFieldList[2]) ? 3 : $InfoFieldList[2]);
7848 $getnomurlparam2 = (empty($InfoFieldList[4]) ? '' : $InfoFieldList[4]);
7849 if (!empty($classpath)) {
7850 dol_include_once($InfoFieldList[1]);
7851 if ($classname && class_exists($classname)) {
7852 $object = new $classname($this->db);
7853 if ($object->element === 'product') { // Special cas for product because default valut of fetch are wrong
7854 $result = $object->fetch($value, '', '', '', 0, 1, 1);
7855 } else {
7856 $result = $object->fetch($value);
7857 }
7858 if ($result > 0) {
7859 if ($object->element === 'product') {
7860 $get_name_url_param_arr = array($getnomurlparam, $getnomurlparam2, 0, -1, 0, '', 0);
7861 if (isset($val['get_name_url_params'])) {
7862 $get_name_url_params = explode(':', $val['get_name_url_params']);
7863 if (!empty($get_name_url_params)) {
7864 $param_num_max = count($get_name_url_param_arr) - 1;
7865 foreach ($get_name_url_params as $param_num => $param_value) {
7866 if ($param_num > $param_num_max) {
7867 break;
7868 }
7869 $get_name_url_param_arr[$param_num] = $param_value;
7870 }
7871 }
7872 }
7873
7877 $value = $object->getNomUrl($get_name_url_param_arr[0], $get_name_url_param_arr[1], $get_name_url_param_arr[2], $get_name_url_param_arr[3], $get_name_url_param_arr[4], $get_name_url_param_arr[5], $get_name_url_param_arr[6]);
7878 } else {
7879 $value = $object->getNomUrl($getnomurlparam, $getnomurlparam2);
7880 }
7881 } else {
7882 $value = '';
7883 }
7884 }
7885 } else {
7886 dol_syslog('Error bad setup of extrafield', LOG_WARNING);
7887 return 'Error bad setup of extrafield';
7888 }
7889 } else {
7890 $value = '';
7891 }
7892 } elseif ($type == 'password') {
7893 $value = preg_replace('/./i', '*', $value);
7894 } elseif ($type == 'array') {
7895 $value = implode('<br>', $value);
7896 } else { // text|html|varchar
7897 $value = dol_htmlentitiesbr($value);
7898 }
7899
7900 //print $type.'-'.$size.'-'.$value;
7901 $out = $value;
7902
7903 return $out;
7904 }
7905
7912 public function clearFieldError($fieldKey)
7913 {
7914 $this->error = '';
7915 unset($this->validateFieldsErrors[$fieldKey]);
7916 }
7917
7925 public function setFieldError($fieldKey, $msg = '')
7926 {
7927 global $langs;
7928 if (empty($msg)) {
7929 $msg = $langs->trans("UnknowError");
7930 }
7931
7932 $this->error = $this->validateFieldsErrors[$fieldKey] = $msg;
7933 }
7934
7941 public function getFieldError($fieldKey)
7942 {
7943 if (!empty($this->validateFieldsErrors[$fieldKey])) {
7944 return $this->validateFieldsErrors[$fieldKey];
7945 }
7946 return '';
7947 }
7948
7957 public function validateField($fields, $fieldKey, $fieldValue)
7958 {
7959 global $langs;
7960
7961 if (!class_exists('Validate')) {
7962 require_once DOL_DOCUMENT_ROOT . '/core/class/validate.class.php';
7963 }
7964
7965 $this->clearFieldError($fieldKey);
7966
7967 if (!isset($fields[$fieldKey])) {
7968 $this->setFieldError($fieldKey, $langs->trans('FieldNotFoundInObject'));
7969 return false;
7970 }
7971
7972 $val = $fields[$fieldKey];
7973
7974 $param = array();
7975 $param['options'] = array();
7976 $type = $val['type'];
7977
7978 $required = false;
7979 if (isset($val['notnull']) && $val['notnull'] === 1) {
7980 // 'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
7981 $required = true;
7982 }
7983
7984 $maxSize = 0;
7985 $minSize = 0;
7986
7987 //
7988 // PREPARE Elements
7989 //
7990 $reg = array();
7991
7992 // Convert var to be able to share same code than showOutputField of extrafields
7993 if (preg_match('/varchar\‍((\d+)\‍)/', $type, $reg)) {
7994 $type = 'varchar'; // convert varchar(xx) int varchar
7995 $maxSize = $reg[1];
7996 } elseif (preg_match('/varchar/', $type)) {
7997 $type = 'varchar'; // convert varchar(xx) int varchar
7998 }
7999
8000 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
8001 $type = 'select';
8002 }
8003
8004 if (!empty($val['type']) && preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) {
8005 $type = 'link';
8006 }
8007
8008 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
8009 $param['options'] = $val['arrayofkeyval'];
8010 }
8011
8012 if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) {
8013 $type = 'link';
8014 $param['options'] = array($reg[1].':'.$reg[2]=>$reg[1].':'.$reg[2]);
8015 } elseif (preg_match('/^sellist:(.*):(.*):(.*):(.*)/i', $val['type'], $reg)) {
8016 $param['options'] = array($reg[1].':'.$reg[2].':'.$reg[3].':'.$reg[4] => 'N');
8017 $type = 'sellist';
8018 } elseif (preg_match('/^sellist:(.*):(.*):(.*)/i', $val['type'], $reg)) {
8019 $param['options'] = array($reg[1].':'.$reg[2].':'.$reg[3] => 'N');
8020 $type = 'sellist';
8021 } elseif (preg_match('/^sellist:(.*):(.*)/i', $val['type'], $reg)) {
8022 $param['options'] = array($reg[1].':'.$reg[2] => 'N');
8023 $type = 'sellist';
8024 }
8025
8026 //
8027 // TEST Value
8028 //
8029
8030 // Use Validate class to allow external Modules to use data validation part instead of concentrate all test here (factoring) or just for reuse
8031 $validate = new Validate($this->db, $langs);
8032
8033
8034 // little trick : to perform tests with good performances sort tests by quick to low
8035
8036 //
8037 // COMMON TESTS
8038 //
8039
8040 // Required test and empty value
8041 if ($required && !$validate->isNotEmptyString($fieldValue)) {
8042 $this->setFieldError($fieldKey, $validate->error);
8043 return false;
8044 } elseif (!$required && !$validate->isNotEmptyString($fieldValue)) {
8045 // if no value sent and the field is not mandatory, no need to perform tests
8046 return true;
8047 }
8048
8049 // MAX Size test
8050 if (!empty($maxSize) && !$validate->isMaxLength($fieldValue, $maxSize)) {
8051 $this->setFieldError($fieldKey, $validate->error);
8052 return false;
8053 }
8054
8055 // MIN Size test
8056 if (!empty($minSize) && !$validate->isMinLength($fieldValue, $minSize)) {
8057 $this->setFieldError($fieldKey, $validate->error);
8058 return false;
8059 }
8060
8061 //
8062 // TESTS for TYPE
8063 //
8064
8065 if (in_array($type, array('date', 'datetime', 'timestamp'))) {
8066 if (!$validate->isTimestamp($fieldValue)) {
8067 $this->setFieldError($fieldKey, $validate->error);
8068 return false;
8069 } else { return true; }
8070 } elseif ($type == 'duration') {
8071 if (!$validate->isDuration($fieldValue)) {
8072 $this->setFieldError($fieldKey, $validate->error);
8073 return false;
8074 } else { return true; }
8075 } elseif (in_array($type, array('double', 'real', 'price'))) {
8076 // is numeric
8077 if (!$validate->isNumeric($fieldValue)) {
8078 $this->setFieldError($fieldKey, $validate->error);
8079 return false;
8080 } else { return true; }
8081 } elseif ($type == 'boolean') {
8082 if (!$validate->isBool($fieldValue)) {
8083 $this->setFieldError($fieldKey, $validate->error);
8084 return false;
8085 } else { return true; }
8086 } elseif ($type == 'mail') {
8087 if (!$validate->isEmail($fieldValue)) {
8088 $this->setFieldError($fieldKey, $validate->error);
8089 return false;
8090 }
8091 } elseif ($type == 'url') {
8092 if (!$validate->isUrl($fieldValue)) {
8093 $this->setFieldError($fieldKey, $validate->error);
8094 return false;
8095 } else { return true; }
8096 } elseif ($type == 'phone') {
8097 if (!$validate->isPhone($fieldValue)) {
8098 $this->setFieldError($fieldKey, $validate->error);
8099 return false;
8100 } else { return true; }
8101 } elseif ($type == 'select' || $type == 'radio') {
8102 if (!isset($param['options'][$fieldValue])) {
8103 $this->error = $langs->trans('RequireValidValue');
8104 return false;
8105 } else { return true; }
8106 } elseif ($type == 'sellist' || $type == 'chkbxlst') {
8107 $param_list = array_keys($param['options']);
8108 $InfoFieldList = explode(":", $param_list[0]);
8109 $value_arr = explode(',', $fieldValue);
8110 $value_arr = array_map(array($this->db, 'escape'), $value_arr);
8111
8112 $selectkey = "rowid";
8113 if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
8114 $selectkey = $InfoFieldList[2];
8115 }
8116
8117 if (!$validate->isInDb($value_arr, $InfoFieldList[0], $selectkey)) {
8118 $this->setFieldError($fieldKey, $validate->error);
8119 return false;
8120 } else { return true; }
8121 } elseif ($type == 'link') {
8122 $param_list = array_keys($param['options']); // $param_list='ObjectName:classPath'
8123 $InfoFieldList = explode(":", $param_list[0]);
8124 $classname = $InfoFieldList[0];
8125 $classpath = $InfoFieldList[1];
8126 if (!$validate->isFetchable($fieldValue, $classname, $classpath)) {
8127 $this->setFieldError($fieldKey, $validate->error);
8128 return false;
8129 } else { return true; }
8130 }
8131
8132 // if no test failled all is ok
8133 return true;
8134 }
8135
8149 public function showOptionals($extrafields, $mode = 'view', $params = null, $keysuffix = '', $keyprefix = '', $onetrtd = 0, $display_type = 'card')
8150 {
8151 global $db, $conf, $langs, $action, $form, $hookmanager;
8152
8153 if (!is_object($form)) {
8154 $form = new Form($db);
8155 }
8156 if (!is_object($extrafields)) {
8157 dol_syslog('Bad parameter extrafields for showOptionals', LOG_ERR);
8158 return 'Bad parameter extrafields for showOptionals';
8159 }
8160 if (!is_array($extrafields->attributes[$this->table_element])) {
8161 dol_syslog("extrafields->attributes was not loaded with extrafields->fetch_name_optionals_label(table_element);", LOG_WARNING);
8162 }
8163
8164 $out = '';
8165
8166 $parameters = array('mode'=>$mode, 'params'=>$params, 'keysuffix'=>$keysuffix, 'keyprefix'=>$keyprefix, 'display_type'=>$display_type);
8167 $reshook = $hookmanager->executeHooks('showOptionals', $parameters, $this, $action); // Note that $action and $object may have been modified by hook
8168
8169 if (empty($reshook)) {
8170 if (is_array($extrafields->attributes[$this->table_element]) && key_exists('label', $extrafields->attributes[$this->table_element]) && is_array($extrafields->attributes[$this->table_element]['label']) && count($extrafields->attributes[$this->table_element]['label']) > 0) {
8171 $out .= "\n";
8172 $out .= '<!-- commonobject:showOptionals --> ';
8173 $out .= "\n";
8174
8175 $nbofextrafieldsshown = 0;
8176 $e = 0; // var to manage the modulo (odd/even)
8177
8178 $lastseparatorkeyfound = '';
8179 $extrafields_collapse_num = '';
8180 $extrafields_collapse_num_old = '';
8181 $i = 0;
8182
8183 foreach ($extrafields->attributes[$this->table_element]['label'] as $key => $label) {
8184 $i++;
8185
8186 // Show only the key field in params
8187 if (is_array($params) && array_key_exists('onlykey', $params) && $key != $params['onlykey']) {
8188 continue;
8189 }
8190
8191 // Test on 'enabled' ('enabled' is different than 'list' = 'visibility')
8192 $enabled = 1;
8193 if ($enabled && isset($extrafields->attributes[$this->table_element]['enabled'][$key])) {
8194 $enabled = dol_eval($extrafields->attributes[$this->table_element]['enabled'][$key], 1, 1, '2');
8195 }
8196 if (empty($enabled)) {
8197 continue;
8198 }
8199
8200 $visibility = 1;
8201 if ($visibility && isset($extrafields->attributes[$this->table_element]['list'][$key])) {
8202 $visibility = dol_eval($extrafields->attributes[$this->table_element]['list'][$key], 1, 1, '2');
8203 }
8204
8205 $perms = 1;
8206 if ($perms && isset($extrafields->attributes[$this->table_element]['perms'][$key])) {
8207 $perms = dol_eval($extrafields->attributes[$this->table_element]['perms'][$key], 1, 1, '2');
8208 }
8209
8210 if (($mode == 'create') && abs($visibility) != 1 && abs($visibility) != 3) {
8211 continue; // <> -1 and <> 1 and <> 3 = not visible on forms, only on list
8212 } elseif (($mode == 'edit') && abs($visibility) != 1 && abs($visibility) != 3 && abs($visibility) != 4) {
8213 // We need to make sure, that the values of hidden extrafields are also part of $_POST. Otherwise, they would be empty after an update of the object. See also getOptionalsFromPost
8214 $ef_name = 'options_' . $key;
8215 $ef_value = $this->array_options[$ef_name];
8216 $out .= '<input type="hidden" name="' . $ef_name . '" id="' . $ef_name . '" value="' . $ef_value . '" />' . "\n";
8217 continue; // <> -1 and <> 1 and <> 3 = not visible on forms, only on list and <> 4 = not visible at the creation
8218 } elseif ($mode == 'view' && empty($visibility)) {
8219 continue;
8220 }
8221 if (empty($perms)) {
8222 continue;
8223 }
8224
8225 // Load language if required
8226 if (!empty($extrafields->attributes[$this->table_element]['langfile'][$key])) {
8227 $langs->load($extrafields->attributes[$this->table_element]['langfile'][$key]);
8228 }
8229
8230 $colspan = 0;
8231 if (is_array($params) && count($params) > 0 && $display_type=='card') {
8232 if (array_key_exists('cols', $params)) {
8233 $colspan = $params['cols'];
8234 } elseif (array_key_exists('colspan', $params)) { // For backward compatibility. Use cols instead now.
8235 $reg = array();
8236 if (preg_match('/colspan="(\d+)"/', $params['colspan'], $reg)) {
8237 $colspan = $reg[1];
8238 } else {
8239 $colspan = $params['colspan'];
8240 }
8241 }
8242 }
8243 $colspan = intval($colspan);
8244
8245 switch ($mode) {
8246 case "view":
8247 $value = ((!empty($this->array_options) && array_key_exists("options_".$key.$keysuffix, $this->array_options)) ? $this->array_options["options_".$key.$keysuffix] : null); // Value may be cleaned or formated later
8248 break;
8249 case "create":
8250 case "edit":
8251 // We get the value of property found with GETPOST so it takes into account:
8252 // default values overwrite, restore back to list link, ... (but not 'default value in database' of field)
8253 $check = 'alphanohtml';
8254 if (in_array($extrafields->attributes[$this->table_element]['type'][$key], array('html', 'text'))) {
8255 $check = 'restricthtml';
8256 }
8257 $getposttemp = GETPOST($keyprefix.'options_'.$key.$keysuffix, $check, 3); // GETPOST can get value from GET, POST or setup of default values overwrite.
8258 // GETPOST("options_" . $key) can be 'abc' or array(0=>'abc')
8259 if (is_array($getposttemp) || $getposttemp != '' || GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix)) {
8260 if (is_array($getposttemp)) {
8261 // $getposttemp is an array but following code expects a comma separated string
8262 $value = implode(",", $getposttemp);
8263 } else {
8264 $value = $getposttemp;
8265 }
8266 } else {
8267 $value = (!empty($this->array_options["options_".$key]) ? $this->array_options["options_".$key] : ''); // No GET, no POST, no default value, so we take value of object.
8268 }
8269 //var_dump($keyprefix.' - '.$key.' - '.$keysuffix.' - '.$keyprefix.'options_'.$key.$keysuffix.' - '.$this->array_options["options_".$key.$keysuffix].' - '.$getposttemp.' - '.$value);
8270 break;
8271 }
8272
8273 $nbofextrafieldsshown++;
8274
8275 // Output value of the current field
8276 if ($extrafields->attributes[$this->table_element]['type'][$key] == 'separate') {
8277 $extrafields_collapse_num = $key;
8278 /*
8279 $extrafield_param = $extrafields->attributes[$this->table_element]['param'][$key];
8280 if (!empty($extrafield_param) && is_array($extrafield_param)) {
8281 $extrafield_param_list = array_keys($extrafield_param['options']);
8282
8283 if (count($extrafield_param_list) > 0) {
8284 $extrafield_collapse_display_value = intval($extrafield_param_list[0]);
8285
8286 if ($extrafield_collapse_display_value == 1 || $extrafield_collapse_display_value == 2) {
8287 //$extrafields_collapse_num = $extrafields->attributes[$this->table_element]['pos'][$key];
8288 $extrafields_collapse_num = $key;
8289 }
8290 }
8291 }
8292 */
8293
8294 // if colspan=0 or 1, the second column is not extended, so the separator must be on 2 columns
8295 $out .= $extrafields->showSeparator($key, $this, ($colspan ? $colspan + 1 : 2), $display_type, $mode);
8296
8297 $lastseparatorkeyfound = $key;
8298 } else {
8299 $collapse_group = $extrafields_collapse_num.(!empty($this->id) ? '_'.$this->id : '');
8300
8301 $class = (!empty($extrafields->attributes[$this->table_element]['hidden'][$key]) ? 'hideobject ' : '');
8302 $csstyle = '';
8303 if (is_array($params) && count($params) > 0) {
8304 if (array_key_exists('class', $params)) {
8305 $class .= $params['class'].' ';
8306 }
8307 if (array_key_exists('style', $params)) {
8308 $csstyle = $params['style'];
8309 }
8310 }
8311
8312 // add html5 elements
8313 $domData = ' data-element="extrafield"';
8314 $domData .= ' data-targetelement="'.$this->element.'"';
8315 $domData .= ' data-targetid="'.$this->id.'"';
8316
8317 $html_id = (empty($this->id) ? '' : 'extrarow-'.$this->element.'_'.$key.'_'.$this->id);
8318 if ($display_type=='card') {
8319 if (!empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && ($e % 2) == 0) {
8320 $colspan = 0;
8321 }
8322
8323 if ($action == 'selectlines') {
8324 $colspan++;
8325 }
8326 }
8327
8328 // Convert date into timestamp format (value in memory must be a timestamp)
8329 if (in_array($extrafields->attributes[$this->table_element]['type'][$key], array('date'))) {
8330 $datenotinstring = null;
8331 if (array_key_exists('options_'.$key, $this->array_options)) {
8332 $datenotinstring = $this->array_options['options_'.$key];
8333 if (!is_numeric($this->array_options['options_'.$key])) { // For backward compatibility
8334 $datenotinstring = $this->db->jdate($datenotinstring);
8335 }
8336 }
8337 $datekey = $keyprefix.'options_'.$key.$keysuffix;
8338 $value = (GETPOSTISSET($datekey) && $this->id == GETPOST('elrowid', 'int')) ? dol_mktime(12, 0, 0, GETPOST($datekey.'month', 'int', 3), GETPOST($datekey.'day', 'int', 3), GETPOST($datekey.'year', 'int', 3)) : $datenotinstring;
8339 }
8340 if (in_array($extrafields->attributes[$this->table_element]['type'][$key], array('datetime'))) {
8341 $datenotinstring = null;
8342 if (array_key_exists('options_'.$key, $this->array_options)) {
8343 $datenotinstring = $this->array_options['options_'.$key];
8344 if (!is_numeric($this->array_options['options_'.$key])) { // For backward compatibility
8345 $datenotinstring = $this->db->jdate($datenotinstring);
8346 }
8347 }
8348 $timekey = $keyprefix.'options_'.$key.$keysuffix;
8349 $value = (GETPOSTISSET($timekey)) ? dol_mktime(GETPOST($timekey.'hour', 'int', 3), GETPOST($timekey.'min', 'int', 3), GETPOST($timekey.'sec', 'int', 3), GETPOST($timekey.'month', 'int', 3), GETPOST($timekey.'day', 'int', 3), GETPOST($timekey.'year', 'int', 3), 'tzuserrel') : $datenotinstring;
8350 }
8351 // Convert float submited string into real php numeric (value in memory must be a php numeric)
8352 if (in_array($extrafields->attributes[$this->table_element]['type'][$key], array('price', 'double'))) {
8353 if (GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix) || $value) {
8354 $value = price2num($value);
8355 } elseif (isset($this->array_options['options_'.$key])) {
8356 $value = $this->array_options['options_'.$key];
8357 }
8358 }
8359
8360 // HTML, text, select, integer and varchar: take into account default value in database if in create mode
8361 if (in_array($extrafields->attributes[$this->table_element]['type'][$key], array('html', 'text', 'varchar', 'select', 'radio', 'int', 'boolean'))) {
8362 if ($action == 'create') {
8363 $value = (GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix) || $value) ? $value : $extrafields->attributes[$this->table_element]['default'][$key];
8364 }
8365 }
8366
8367 $labeltoshow = $langs->trans($label);
8368 $helptoshow = $langs->trans($extrafields->attributes[$this->table_element]['help'][$key]);
8369
8370 if ($display_type == 'card') {
8371 $out .= '<tr '.($html_id ? 'id="'.$html_id.'" ' : '').$csstyle.' class="field_options_'.$key.' '.$class.$this->element.'_extras_'.$key.' trextrafields_collapse'.$collapse_group.'" '.$domData.' >';
8372 if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER) && ($action == 'view' || $action == 'valid' || $action == 'editline' || $action == 'confirm_valid' || $action == 'confirm_cancel')) {
8373 $out .= '<td></td>';
8374 }
8375 $out .= '<td class="'.(empty($params['tdclass']) ? 'titlefieldcreate' : $params['tdclass']).' wordbreak';
8376 } elseif ($display_type == 'line') {
8377 $out .= '<div '.($html_id ? 'id="'.$html_id.'" ' : '').$csstyle.' class="fieldline_options_'.$key.' '.$class.$this->element.'_extras_'.$key.' trextrafields_collapse'.$collapse_group.'" '.$domData.' >';
8378 $out .= '<div style="display: inline-block; padding-right:4px" class="wordbreak';
8379 }
8380 //$out .= "titlefield";
8381 //if (GETPOST('action', 'restricthtml') == 'create') $out.='create';
8382 // BUG #11554 : For public page, use red dot for required fields, instead of bold label
8383 $tpl_context = isset($params["tpl_context"]) ? $params["tpl_context"] : "none";
8384 if ($tpl_context != "public") { // Public page : red dot instead of fieldrequired characters
8385 if ($mode != 'view' && !empty($extrafields->attributes[$this->table_element]['required'][$key])) {
8386 $out .= ' fieldrequired';
8387 }
8388 }
8389 $out .= '">';
8390 if ($tpl_context == "public") { // Public page : red dot instead of fieldrequired characters
8391 if (!empty($extrafields->attributes[$this->table_element]['help'][$key])) {
8392 $out .= $form->textwithpicto($labeltoshow, $helptoshow);
8393 } else {
8394 $out .= $labeltoshow;
8395 }
8396 if ($mode != 'view' && !empty($extrafields->attributes[$this->table_element]['required'][$key])) {
8397 $out .= '&nbsp;<span style="color: red">*</span>';
8398 }
8399 } else {
8400 if (!empty($extrafields->attributes[$this->table_element]['help'][$key])) {
8401 $out .= $form->textwithpicto($labeltoshow, $helptoshow);
8402 } else {
8403 $out .= $labeltoshow;
8404 }
8405 }
8406
8407 $out .= ($display_type == 'card' ? '</td>' : '</div>');
8408
8409 $html_id = !empty($this->id) ? $this->element.'_extras_'.$key.'_'.$this->id : '';
8410 if ($display_type == 'card') {
8411 // a first td column was already output (and may be another on before if MAIN_VIEW_LINE_NUMBER set), so this td is the next one
8412 $out .= '<td '.($html_id ? 'id="'.$html_id.'" ' : '').' class="valuefieldcreate '.$this->element.'_extras_'.$key.'" '.($colspan ? ' colspan="'.$colspan.'"' : '').'>';
8413 } elseif ($display_type == 'line') {
8414 $out .= '<div '.($html_id ? 'id="'.$html_id.'" ' : '').' style="display: inline-block" class="valuefieldcreate '.$this->element.'_extras_'.$key.' extra_inline_'.$extrafields->attributes[$this->table_element]['type'][$key].'">';
8415 }
8416
8417 switch ($mode) {
8418 case "view":
8419 $out .= $extrafields->showOutputField($key, $value, '', $this->table_element);
8420 break;
8421 case "create":
8422 $out .= $extrafields->showInputField($key, $value, '', $keysuffix, '', 0, $this->id, $this->table_element);
8423 break;
8424 case "edit":
8425 $out .= $extrafields->showInputField($key, $value, '', $keysuffix, '', 0, $this->id, $this->table_element);
8426 break;
8427 }
8428
8429 $out .= ($display_type=='card' ? '</td>' : '</div>');
8430
8431 if (!empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && (($e % 2) == 1)) {
8432 $out .= ($display_type=='card' ? '</tr>' : '</div>');
8433 } else {
8434 $out .= ($display_type=='card' ? '</tr>' : '</div>');
8435 }
8436
8437 $e++;
8438 }
8439 }
8440 $out .= "\n";
8441 // Add code to manage list depending on others
8442 if (!empty($conf->use_javascript_ajax)) {
8443 $out .= $this->getJSListDependancies();
8444 }
8445
8446 $out .= '<!-- commonobject:showOptionals end --> '."\n";
8447
8448 if (empty($nbofextrafieldsshown)) {
8449 $out = '';
8450 }
8451 }
8452 }
8453
8454 $out .= $hookmanager->resPrint;
8455
8456 return $out;
8457 }
8458
8463 public function getJSListDependancies($type = '_extra')
8464 {
8465 $out = '
8466 <script nonce="'.getNonce().'">
8467 jQuery(document).ready(function() {
8468 function showOptions'.$type.'(child_list, parent_list, orig_select)
8469 {
8470 var val = $("select[name=\""+parent_list+"\"]").val();
8471 var parentVal = parent_list + ":" + val;
8472 if(typeof val == "string"){
8473 if(val != "") {
8474 var options = orig_select.find("option[parent=\""+parentVal+"\"]").clone();
8475 $("select[name=\""+child_list+"\"] option[parent]").remove();
8476 $("select[name=\""+child_list+"\"]").append(options);
8477 } else {
8478 var options = orig_select.find("option[parent]").clone();
8479 $("select[name=\""+child_list+"\"] option[parent]").remove();
8480 $("select[name=\""+child_list+"\"]").append(options);
8481 }
8482 } else if(val > 0) {
8483 var options = orig_select.find("option[parent=\""+parentVal+"\"]").clone();
8484 $("select[name=\""+child_list+"\"] option[parent]").remove();
8485 $("select[name=\""+child_list+"\"]").append(options);
8486 } else {
8487 var options = orig_select.find("option[parent]").clone();
8488 $("select[name=\""+child_list+"\"] option[parent]").remove();
8489 $("select[name=\""+child_list+"\"]").append(options);
8490 }
8491 }
8492 function setListDependencies'.$type.'() {
8493 jQuery("select option[parent]").parent().each(function() {
8494 var orig_select = {};
8495 var child_list = $(this).attr("name");
8496 orig_select[child_list] = $(this).clone();
8497 var parent = $(this).find("option[parent]:first").attr("parent");
8498 var infos = parent.split(":");
8499 var parent_list = infos[0];
8500
8501 //Hide daughters lists
8502 if ($("#"+child_list).val() == 0 && $("#"+parent_list).val() == 0){
8503 $("#"+child_list).hide();
8504 //Show mother lists
8505 } else if ($("#"+parent_list).val() != 0){
8506 $("#"+parent_list).show();
8507 }
8508 //Show the child list if the parent list value is selected
8509 $("select[name=\""+parent_list+"\"]").click(function() {
8510 if ($(this).val() != 0){
8511 $("#"+child_list).show()
8512 }
8513 });
8514
8515 //When we change parent list
8516 $("select[name=\""+parent_list+"\"]").change(function() {
8517 showOptions'.$type.'(child_list, parent_list, orig_select[child_list]);
8518 //Select the value 0 on child list after a change on the parent list
8519 $("#"+child_list).val(0).trigger("change");
8520 //Hide child lists if the parent value is set to 0
8521 if ($(this).val() == 0){
8522 $("#"+child_list).hide();
8523 }
8524 });
8525 });
8526 }
8527
8528 setListDependencies'.$type.'();
8529 });
8530 </script>'."\n";
8531 return $out;
8532 }
8533
8539 public function getRights()
8540 {
8541 global $user;
8542
8543 $module = empty($this->module) ? '' : $this->module;
8544 $element = $this->element;
8545
8546 if ($element == 'facturerec') {
8547 $element = 'facture';
8548 } elseif ($element == 'invoice_supplier_rec') {
8549 return empty($user->rights->fournisseur->facture) ? null : $user->rights->fournisseur->facture;
8550 } elseif ($module && !empty($user->rights->$module->$element)) {
8551 // for modules built with ModuleBuilder
8552 return $user->rights->$module->$element;
8553 }
8554
8555 return $user->rights->$element;
8556 }
8557
8570 public static function commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors = 0)
8571 {
8572 foreach ($tables as $table) {
8573 $sql = 'UPDATE '.$dbs->prefix().$table.' SET fk_soc = '.((int) $dest_id).' WHERE fk_soc = '.((int) $origin_id);
8574
8575 if (!$dbs->query($sql)) {
8576 if ($ignoreerrors) {
8577 return true; // TODO Not enough. If there is A-B on kept thirdparty and B-C on old one, we must get A-B-C after merge. Not A-B.
8578 }
8579 //$this->errors = $db->lasterror();
8580 return false;
8581 }
8582 }
8583
8584 return true;
8585 }
8586
8599 public static function commonReplaceProduct(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors = 0)
8600 {
8601 foreach ($tables as $table) {
8602 $sql = 'UPDATE '.MAIN_DB_PREFIX.$table.' SET fk_product = '.((int) $dest_id).' WHERE fk_product = '.((int) $origin_id);
8603
8604 if (!$dbs->query($sql)) {
8605 if ($ignoreerrors) {
8606 return true; // TODO Not enough. If there is A-B on kept product and B-C on old one, we must get A-B-C after merge. Not A-B.
8607 }
8608 //$this->errors = $db->lasterror();
8609 return false;
8610 }
8611 }
8612
8613 return true;
8614 }
8615
8628 public function defineBuyPrice($unitPrice = 0.0, $discountPercent = 0.0, $fk_product = 0)
8629 {
8630 global $conf;
8631
8632 $buyPrice = 0;
8633
8634 if (($unitPrice > 0) && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull > 0)) {
8635 // When ForceBuyingPriceIfNull is set
8636 $buyPrice = $unitPrice * (1 - $discountPercent / 100);
8637 } else {
8638 // Get cost price for margin calculation
8639 if (!empty($fk_product) && $fk_product > 0) {
8640 if (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == 'costprice') {
8641 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
8642 $product = new Product($this->db);
8643 $result = $product->fetch($fk_product);
8644 if ($result <= 0) {
8645 $this->errors[] = 'ErrorProductIdDoesNotExists';
8646 return -1;
8647 }
8648 if ($product->cost_price > 0) {
8649 $buyPrice = $product->cost_price;
8650 } elseif ($product->pmp > 0) {
8651 $buyPrice = $product->pmp;
8652 }
8653 } elseif (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == 'pmp') {
8654 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
8655 $product = new Product($this->db);
8656 $result = $product->fetch($fk_product);
8657 if ($result <= 0) {
8658 $this->errors[] = 'ErrorProductIdDoesNotExists';
8659 return -1;
8660 }
8661 if ($product->pmp > 0) {
8662 $buyPrice = $product->pmp;
8663 }
8664 }
8665
8666 if (empty($buyPrice) && isset($conf->global->MARGIN_TYPE) && in_array($conf->global->MARGIN_TYPE, array('1', 'pmp', 'costprice'))) {
8667 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
8668 $productFournisseur = new ProductFournisseur($this->db);
8669 if (($result = $productFournisseur->find_min_price_product_fournisseur($fk_product)) > 0) {
8670 $buyPrice = $productFournisseur->fourn_unitprice;
8671 } elseif ($result < 0) {
8672 $this->errors[] = $productFournisseur->error;
8673 return -2;
8674 }
8675 }
8676 }
8677 }
8678 return $buyPrice;
8679 }
8680
8681 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
8701 public function show_photos($modulepart, $sdir, $size = 0, $nbmax = 0, $nbbyrow = 5, $showfilename = 0, $showaction = 0, $maxHeight = 120, $maxWidth = 160, $nolink = 0, $overwritetitle = 0, $usesharelink = 0, $cache = '', $addphotorefcss = 'photoref')
8702 {
8703 // phpcs:enable
8704 global $conf, $user, $langs;
8705
8706 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
8707 include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
8708
8709 $sortfield = 'position_name';
8710 $sortorder = 'asc';
8711
8712 $dir = $sdir.'/';
8713 $pdir = '/';
8714
8715 $dir .= get_exdir(0, 0, 0, 0, $this, $modulepart);
8716 $pdir .= get_exdir(0, 0, 0, 0, $this, $modulepart);
8717
8718 // For backward compatibility
8719 if ($modulepart == 'product') {
8720 if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
8721 $dir = $sdir.'/'.get_exdir($this->id, 2, 0, 0, $this, $modulepart).$this->id."/photos/";
8722 $pdir = '/'.get_exdir($this->id, 2, 0, 0, $this, $modulepart).$this->id."/photos/";
8723 }
8724 }
8725
8726 // Defined relative dir to DOL_DATA_ROOT
8727 $relativedir = '';
8728 if ($dir) {
8729 $relativedir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $dir);
8730 $relativedir = preg_replace('/^[\\/]/', '', $relativedir);
8731 $relativedir = preg_replace('/[\\/]$/', '', $relativedir);
8732 }
8733
8734 $dirthumb = $dir.'thumbs/';
8735 $pdirthumb = $pdir.'thumbs/';
8736
8737 $return = '<!-- Photo -->'."\n";
8738 $nbphoto = 0;
8739
8740 $filearray = dol_dir_list($dir, "files", 0, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder) == 'desc' ?SORT_DESC:SORT_ASC), 1);
8741
8742 /*if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) // For backward compatiblity, we scan also old dirs
8743 {
8744 $filearrayold=dol_dir_list($dirold,"files",0,'','(\.meta|_preview.*\.png)$',$sortfield,(strtolower($sortorder)=='desc'?SORT_DESC:SORT_ASC),1);
8745 $filearray=array_merge($filearray, $filearrayold);
8746 }*/
8747
8748 completeFileArrayWithDatabaseInfo($filearray, $relativedir);
8749
8750 if (count($filearray)) {
8751 if ($sortfield && $sortorder) {
8752 $filearray = dol_sort_array($filearray, $sortfield, $sortorder);
8753 }
8754
8755 foreach ($filearray as $key => $val) {
8756 $photo = '';
8757 $file = $val['name'];
8758
8759 //if (dol_is_file($dir.$file) && image_format_supported($file) >= 0)
8760 if (image_format_supported($file) >= 0) {
8761 $nbphoto++;
8762 $photo = $file;
8763 $viewfilename = $file;
8764
8765 if ($size == 1 || $size == 'small') { // Format vignette
8766 // Find name of thumb file
8767 $photo_vignette = basename(getImageFileNameForSize($dir.$file, '_small'));
8768 if (!dol_is_file($dirthumb.$photo_vignette)) {
8769 // The thumb does not exists, so we will use the original file
8770 $dirthumb = $dir;
8771 $pdirthumb = $pdir;
8772 $photo_vignette = basename($file);
8773 }
8774
8775 // Get filesize of original file
8776 $imgarray = dol_getImageSize($dir.$photo);
8777
8778 if ($nbbyrow > 0) {
8779 if ($nbphoto == 1) {
8780 $return .= '<table class="valigntop center centpercent" style="border: 0; padding: 2px; border-spacing: 2px; border-collapse: separate;">';
8781 }
8782
8783 if ($nbphoto % $nbbyrow == 1) {
8784 $return .= '<tr class="center valignmiddle" style="border: 1px">';
8785 }
8786 $return .= '<td style="width: '.ceil(100 / $nbbyrow).'%" class="photo">'."\n";
8787 } elseif ($nbbyrow < 0) {
8788 $return .= '<div class="inline-block">'."\n";
8789 }
8790
8791 $relativefile = preg_replace('/^\//', '', $pdir.$photo);
8792 if (empty($nolink)) {
8793 $urladvanced = getAdvancedPreviewUrl($modulepart, $relativefile, 0, 'entity='.$this->entity);
8794 if ($urladvanced) {
8795 $return .= '<a href="'.$urladvanced.'">';
8796 } else {
8797 $return .= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.'&file='.urlencode($pdir.$photo).'" class="aphoto" target="_blank" rel="noopener noreferrer">';
8798 }
8799 }
8800
8801 // Show image (width height=$maxHeight)
8802 // Si fichier vignette disponible et image source trop grande, on utilise la vignette, sinon on utilise photo origine
8803 $alt = $langs->transnoentitiesnoconv('File').': '.$relativefile;
8804 $alt .= ' - '.$langs->transnoentitiesnoconv('Size').': '.$imgarray['width'].'x'.$imgarray['height'];
8805 if ($overwritetitle) {
8806 if (is_numeric($overwritetitle)) {
8807 $alt = '';
8808 } else {
8809 $alt = $overwritetitle;
8810 }
8811 }
8812
8813 if ($usesharelink) {
8814 if ($val['share']) {
8815 if (empty($maxHeight) || ($photo_vignette && $imgarray['height'] > $maxHeight)) {
8816 $return .= '<!-- Show original file (thumb not yet available with shared links) -->';
8817 $return .= '<img class="photo photowithmargin'.($addphotorefcss ? ' '.$addphotorefcss : '').'"'.($maxHeight ?' height="'.$maxHeight.'"': '').' src="'.DOL_URL_ROOT.'/viewimage.php?hashp='.urlencode($val['share']).($cache ? '&cache='.urlencode($cache) : '').'" title="'.dol_escape_htmltag($alt).'">';
8818 } else {
8819 $return .= '<!-- Show original file -->';
8820 $return .= '<img class="photo photowithmargin'.($addphotorefcss ? ' '.$addphotorefcss : '').'" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/viewimage.php?hashp='.urlencode($val['share']).($cache ? '&cache='.urlencode($cache) : '').'" title="'.dol_escape_htmltag($alt).'">';
8821 }
8822 } else {
8823 $return .= '<!-- Show nophoto file (because file is not shared) -->';
8824 $return .= '<img class="photo photowithmargin'.($addphotorefcss ? ' '.$addphotorefcss : '').'" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/public/theme/common/nophoto.png" title="'.dol_escape_htmltag($alt).'">';
8825 }
8826 } else {
8827 if (empty($maxHeight) || ($photo_vignette && $imgarray['height'] > $maxHeight)) {
8828 $return .= '<!-- Show thumb -->';
8829 $return .= '<img class="photo photowithmargin'.($addphotorefcss ? ' '.$addphotorefcss : '').' maxwidth150onsmartphone maxwidth200"'.($maxHeight ?' height="'.$maxHeight.'"': '').' src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.($cache ? '&cache='.urlencode($cache) : '').'&file='.urlencode($pdirthumb.$photo_vignette).'" title="'.dol_escape_htmltag($alt).'">';
8830 } else {
8831 $return .= '<!-- Show original file -->';
8832 $return .= '<img class="photo photowithmargin'.($addphotorefcss ? ' '.$addphotorefcss : '').'" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.($cache ? '&cache='.urlencode($cache) : '').'&file='.urlencode($pdir.$photo).'" title="'.dol_escape_htmltag($alt).'">';
8833 }
8834 }
8835
8836 if (empty($nolink)) {
8837 $return .= '</a>';
8838 }
8839
8840 if ($showfilename) {
8841 $return .= '<br>'.$viewfilename;
8842 }
8843 if ($showaction) {
8844 $return .= '<br>';
8845 // On propose la generation de la vignette si elle n'existe pas et si la taille est superieure aux limites
8846 if ($photo_vignette && (image_format_supported($photo) > 0) && ($this->imgWidth > $maxWidth || $this->imgHeight > $maxHeight)) {
8847 $return .= '<a href="'.$_SERVER["PHP_SELF"].'?id='.$this->id.'&action=addthumb&token='.newToken().'&file='.urlencode($pdir.$viewfilename).'">'.img_picto($langs->trans('GenerateThumb'), 'refresh').'&nbsp;&nbsp;</a>';
8848 }
8849 // Special cas for product
8850 if ($modulepart == 'product' && ($user->hasRight('produit', 'creer') || $user->hasRight('service', 'creer'))) {
8851 // Link to resize
8852 $return .= '<a href="'.DOL_URL_ROOT.'/core/photos_resize.php?modulepart='.urlencode('produit|service').'&id='.$this->id.'&file='.urlencode($pdir.$viewfilename).'" title="'.dol_escape_htmltag($langs->trans("Resize")).'">'.img_picto($langs->trans("Resize"), 'resize', '').'</a> &nbsp; ';
8853
8854 // Link to delete
8855 $return .= '<a href="'.$_SERVER["PHP_SELF"].'?id='.$this->id.'&action=delete&token='.newToken().'&file='.urlencode($pdir.$viewfilename).'">';
8856 $return .= img_delete().'</a>';
8857 }
8858 }
8859 $return .= "\n";
8860
8861 if ($nbbyrow > 0) {
8862 $return .= '</td>';
8863 if (($nbphoto % $nbbyrow) == 0) {
8864 $return .= '</tr>';
8865 }
8866 } elseif ($nbbyrow < 0) {
8867 $return .= '</div>'."\n";
8868 }
8869 }
8870
8871 if (empty($size)) { // Format origine
8872 $return .= '<img class="photo photowithmargin" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.'&file='.urlencode($pdir.$photo).'">';
8873
8874 if ($showfilename) {
8875 $return .= '<br>'.$viewfilename;
8876 }
8877 if ($showaction) {
8878 // Special case for product
8879 if ($modulepart == 'product' && ($user->hasRight('produit', 'creer') || $user->hasRight('service', 'creer'))) {
8880 // Link to resize
8881 $return .= '<a href="'.DOL_URL_ROOT.'/core/photos_resize.php?modulepart='.urlencode('produit|service').'&id='.$this->id.'&file='.urlencode($pdir.$viewfilename).'" title="'.dol_escape_htmltag($langs->trans("Resize")).'">'.img_picto($langs->trans("Resize"), 'resize', '').'</a> &nbsp; ';
8882
8883 // Link to delete
8884 $return .= '<a href="'.$_SERVER["PHP_SELF"].'?id='.$this->id.'&action=delete&token='.newToken().'&file='.urlencode($pdir.$viewfilename).'">';
8885 $return .= img_delete().'</a>';
8886 }
8887 }
8888 }
8889
8890 // On continue ou on arrete de boucler ?
8891 if ($nbmax && $nbphoto >= $nbmax) {
8892 break;
8893 }
8894 }
8895 }
8896
8897 if ($size == 1 || $size == 'small') {
8898 if ($nbbyrow > 0) {
8899 // Ferme tableau
8900 while ($nbphoto % $nbbyrow) {
8901 $return .= '<td style="width: '.ceil(100 / $nbbyrow).'%">&nbsp;</td>';
8902 $nbphoto++;
8903 }
8904
8905 if ($nbphoto) {
8906 $return .= '</table>';
8907 }
8908 }
8909 }
8910 }
8911
8912 $this->nbphoto = $nbphoto;
8913
8914 return $return;
8915 }
8916
8917
8924 protected function isArray($info)
8925 {
8926 if (is_array($info)) {
8927 if (isset($info['type']) && $info['type'] == 'array') {
8928 return true;
8929 } else {
8930 return false;
8931 }
8932 }
8933 return false;
8934 }
8935
8942 public function isDate($info)
8943 {
8944 if (isset($info['type']) && ($info['type'] == 'date' || $info['type'] == 'datetime' || $info['type'] == 'timestamp')) {
8945 return true;
8946 }
8947 return false;
8948 }
8949
8956 public function isDuration($info)
8957 {
8958 if (is_array($info)) {
8959 if (isset($info['type']) && ($info['type'] == 'duration')) {
8960 return true;
8961 } else {
8962 return false;
8963 }
8964 } else {
8965 return false;
8966 }
8967 }
8968
8975 public function isInt($info)
8976 {
8977 if (is_array($info)) {
8978 if (isset($info['type']) && (preg_match('/(^int|int$)/i', $info['type']))) {
8979 return true;
8980 } else {
8981 return false;
8982 }
8983 } else {
8984 return false;
8985 }
8986 }
8987
8994 public function isFloat($info)
8995 {
8996 if (is_array($info)) {
8997 if (isset($info['type']) && (preg_match('/^(double|real|price)/i', $info['type']))) {
8998 return true;
8999 } else {
9000 return false;
9001 }
9002 }
9003 return false;
9004 }
9005
9012 public function isText($info)
9013 {
9014 if (is_array($info)) {
9015 if (isset($info['type']) && $info['type'] == 'text') {
9016 return true;
9017 } else {
9018 return false;
9019 }
9020 }
9021 return false;
9022 }
9023
9030 protected function canBeNull($info)
9031 {
9032 if (is_array($info)) {
9033 if (isset($info['notnull']) && $info['notnull'] != '1') {
9034 return true;
9035 } else {
9036 return false;
9037 }
9038 }
9039 return true;
9040 }
9041
9048 protected function isForcedToNullIfZero($info)
9049 {
9050 if (is_array($info)) {
9051 if (isset($info['notnull']) && $info['notnull'] == '-1') {
9052 return true;
9053 } else {
9054 return false;
9055 }
9056 }
9057 return false;
9058 }
9059
9066 protected function isIndex($info)
9067 {
9068 if (is_array($info)) {
9069 if (isset($info['index']) && $info['index'] == true) {
9070 return true;
9071 } else {
9072 return false;
9073 }
9074 }
9075 return false;
9076 }
9077
9078
9087 protected function setSaveQuery()
9088 {
9089 global $conf;
9090
9091 $queryarray = array();
9092 foreach ($this->fields as $field => $info) { // Loop on definition of fields
9093 // Depending on field type ('datetime', ...)
9094 if ($this->isDate($info)) {
9095 if (empty($this->{$field})) {
9096 $queryarray[$field] = null;
9097 } else {
9098 $queryarray[$field] = $this->db->idate($this->{$field});
9099 }
9100 } elseif ($this->isDuration($info)) {
9101 // $this->{$field} may be null, '', 0, '0', 123, '123'
9102 if ((isset($this->{$field}) && $this->{$field} != '') || !empty($info['notnull'])) {
9103 if (!isset($this->{$field})) {
9104 if (!empty($info['default'])) {
9105 $queryarray[$field] = $info['default'];
9106 } else {
9107 $queryarray[$field] = 0;
9108 }
9109 } else {
9110 $queryarray[$field] = (int) $this->{$field}; // If '0', it may be set to null later if $info['notnull'] == -1
9111 }
9112 } else {
9113 $queryarray[$field] = null;
9114 }
9115 } elseif ($this->isInt($info) || $this->isFloat($info)) {
9116 if ($field == 'entity' && is_null($this->{$field})) {
9117 $queryarray[$field] = ((int) $conf->entity);
9118 } else {
9119 // $this->{$field} may be null, '', 0, '0', 123, '123'
9120 if ((isset($this->{$field}) && $this->{$field} != '') || !empty($info['notnull'])) {
9121 if (!isset($this->{$field})) {
9122 $queryarray[$field] = 0;
9123 } elseif ($this->isInt($info)) {
9124 $queryarray[$field] = (int) $this->{$field}; // If '0', it may be set to null later if $info['notnull'] == -1
9125 } elseif ($this->isFloat($info)) {
9126 $queryarray[$field] = (double) $this->{$field}; // If '0', it may be set to null later if $info['notnull'] == -1
9127 }
9128 } else {
9129 $queryarray[$field] = null;
9130 }
9131 }
9132 } else {
9133 // Note: If $this->{$field} is not defined, it means there is a bug into definition of ->fields or a missing declaration of property
9134 // We should keep the warning generated by this because it is a bug somewhere else in code, not here.
9135 $queryarray[$field] = $this->{$field};
9136 }
9137
9138 if ($info['type'] == 'timestamp' && empty($queryarray[$field])) {
9139 unset($queryarray[$field]);
9140 }
9141 if (!empty($info['notnull']) && $info['notnull'] == -1 && empty($queryarray[$field])) {
9142 $queryarray[$field] = null; // May force 0 to null
9143 }
9144 }
9145
9146 return $queryarray;
9147 }
9148
9155 public function setVarsFromFetchObj(&$obj)
9156 {
9157 global $db;
9158
9159 foreach ($this->fields as $field => $info) {
9160 if ($this->isDate($info)) {
9161 if (!isset($obj->$field) || is_null($obj->$field) || $obj->$field === '' || $obj->$field === '0000-00-00 00:00:00' || $obj->$field === '1000-01-01 00:00:00') {
9162 $this->$field = '';
9163 } else {
9164 $this->$field = $db->jdate($obj->$field);
9165 }
9166 } elseif ($this->isInt($info)) {
9167 if ($field == 'rowid') {
9168 $this->id = (int) $obj->$field;
9169 } else {
9170 if ($this->isForcedToNullIfZero($info)) {
9171 if (empty($obj->$field)) {
9172 $this->$field = null;
9173 } else {
9174 $this->$field = (double) $obj->$field;
9175 }
9176 } else {
9177 if (isset($obj->$field) && (!is_null($obj->$field) || (isset($info['notnull']) && $info['notnull'] == 1))) {
9178 $this->$field = (int) $obj->$field;
9179 } else {
9180 $this->$field = null;
9181 }
9182 }
9183 }
9184 } elseif ($this->isFloat($info)) {
9185 if ($this->isForcedToNullIfZero($info)) {
9186 if (empty($obj->$field)) {
9187 $this->$field = null;
9188 } else {
9189 $this->$field = (double) $obj->$field;
9190 }
9191 } else {
9192 if (isset($obj->$field) && (!is_null($obj->$field) || (isset($info['notnull']) && $info['notnull'] == 1))) {
9193 $this->$field = (double) $obj->$field;
9194 } else {
9195 $this->$field = null;
9196 }
9197 }
9198 } else {
9199 $this->$field = isset($obj->$field) ? $obj->$field : null;
9200 }
9201 }
9202
9203 // If there is no 'ref' field, we force property ->ref to ->id for a better compatibility with common functions.
9204 if (!isset($this->fields['ref']) && isset($this->id)) {
9205 $this->ref = $this->id;
9206 }
9207 }
9208
9216 public function getFieldList($alias = '', $excludefields = array())
9217 {
9218 $keys = array_keys($this->fields);
9219 if (!empty($alias)) {
9220 $keys_with_alias = array();
9221 foreach ($keys as $fieldname) {
9222 if (!empty($excludefields)) {
9223 if (in_array($fieldname, $excludefields)) { // The field is excluded and must not be in output
9224 continue;
9225 }
9226 }
9227 $keys_with_alias[] = $alias . '.' . $fieldname;
9228 }
9229 return implode(',', $keys_with_alias);
9230 } else {
9231 return implode(',', $keys);
9232 }
9233 }
9234
9242 protected function quote($value, $fieldsentry)
9243 {
9244 if (is_null($value)) {
9245 return 'NULL';
9246 } elseif (preg_match('/^(int|double|real|price)/i', $fieldsentry['type'])) {
9247 return price2num("$value");
9248 } elseif (preg_match('/int$/i', $fieldsentry['type'])) {
9249 return (int) $value;
9250 } elseif ($fieldsentry['type'] == 'boolean') {
9251 if ($value) {
9252 return 'true';
9253 } else {
9254 return 'false';
9255 }
9256 } else {
9257 return "'".$this->db->escape($value)."'";
9258 }
9259 }
9260
9261
9269 public function createCommon(User $user, $notrigger = false)
9270 {
9271 global $langs;
9272 dol_syslog(get_class($this)."::createCommon create", LOG_DEBUG);
9273
9274 $error = 0;
9275
9276 $now = dol_now();
9277
9278 $fieldvalues = $this->setSaveQuery();
9279
9280 if (array_key_exists('date_creation', $fieldvalues) && empty($fieldvalues['date_creation'])) {
9281 $fieldvalues['date_creation'] = $this->db->idate($now);
9282 }
9283 if (array_key_exists('fk_user_creat', $fieldvalues) && !($fieldvalues['fk_user_creat'] > 0)) {
9284 $fieldvalues['fk_user_creat'] = $user->id;
9285 $this->fk_user_creat = $user->id;
9286 }
9287 if (array_key_exists('user_modification_id', $fieldvalues) && !($fieldvalues['user_modification_id'] > 0)) {
9288 $fieldvalues['user_modification_id'] = $user->id;
9289 $this->user_modification_id = $user->id;
9290 }
9291 unset($fieldvalues['rowid']); // The field 'rowid' is reserved field name for autoincrement field so we don't need it into insert.
9292 if (array_key_exists('ref', $fieldvalues)) {
9293 $fieldvalues['ref'] = dol_string_nospecial($fieldvalues['ref']); // If field is a ref, we sanitize data
9294 }
9295
9296 $keys = array();
9297 $values = array(); // Array to store string forged for SQL syntax
9298 foreach ($fieldvalues as $k => $v) {
9299 $keys[$k] = $k;
9300 $value = $this->fields[$k];
9301 $values[$k] = $this->quote($v, $value); // May return string 'NULL' if $value is null
9302 }
9303
9304 // Clean and check mandatory
9305 foreach ($keys as $key) {
9306 // If field is an implicit foreign key field (so type = 'integer:...')
9307 if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') {
9308 $values[$key] = '';
9309 }
9310 if (!empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') {
9311 $values[$key] = '';
9312 }
9313
9314 if (isset($this->fields[$key]['notnull']) && $this->fields[$key]['notnull'] == 1 && (!isset($values[$key]) || $values[$key] === 'NULL') && is_null($this->fields[$key]['default'])) {
9315 $error++;
9316 $langs->load("errors");
9317 dol_syslog("Mandatory field '".$key."' is empty and required into ->fields definition of class");
9318 $this->errors[] = $langs->trans("ErrorFieldRequired", $this->fields[$key]['label']);
9319 }
9320
9321 // If value is null and there is a default value for field
9322 if (isset($this->fields[$key]['notnull']) && $this->fields[$key]['notnull'] == 1 && (!isset($values[$key]) || $values[$key] === 'NULL') && !is_null($this->fields[$key]['default'])) {
9323 $values[$key] = $this->quote($this->fields[$key]['default'], $this->fields[$key]);
9324 }
9325
9326 // If field is an implicit foreign key field (so type = 'integer:...')
9327 if (preg_match('/^integer:/i', $this->fields[$key]['type']) && empty($values[$key])) {
9328 if (isset($this->fields[$key]['default'])) {
9329 $values[$key] = ((int) $this->fields[$key]['default']);
9330 } else {
9331 $values[$key] = 'null';
9332 }
9333 }
9334 if (!empty($this->fields[$key]['foreignkey']) && empty($values[$key])) {
9335 $values[$key] = 'null';
9336 }
9337 }
9338
9339 if ($error) {
9340 return -1;
9341 }
9342
9343 $this->db->begin();
9344
9345 if (!$error) {
9346 $sql = "INSERT INTO ".$this->db->prefix().$this->table_element;
9347 $sql .= " (".implode(", ", $keys).')';
9348 $sql .= " VALUES (".implode(", ", $values).")"; // $values can contains 'abc' or 123
9349
9350 $res = $this->db->query($sql);
9351 if (!$res) {
9352 $error++;
9353 if ($this->db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
9354 $this->errors[] = "ErrorRefAlreadyExists";
9355 } else {
9356 $this->errors[] = $this->db->lasterror();
9357 }
9358 }
9359 }
9360
9361 if (!$error) {
9362 $this->id = $this->db->last_insert_id($this->db->prefix().$this->table_element);
9363 }
9364
9365 // If we have a field ref with a default value of (PROV)
9366 if (!$error) {
9367 if (key_exists('ref', $this->fields) && $this->fields['ref']['notnull'] > 0 && key_exists('default', $this->fields['ref']) && $this->fields['ref']['default'] == '(PROV)') {
9368 $sql = "UPDATE ".$this->db->prefix().$this->table_element." SET ref = '(PROV".((int) $this->id).")' WHERE (ref = '(PROV)' OR ref = '') AND rowid = ".((int) $this->id);
9369 $resqlupdate = $this->db->query($sql);
9370
9371 if ($resqlupdate === false) {
9372 $error++;
9373 $this->errors[] = $this->db->lasterror();
9374 } else {
9375 $this->ref = '(PROV'.$this->id.')';
9376 }
9377 }
9378 }
9379
9380 // Create extrafields
9381 if (!$error) {
9382 $result = $this->insertExtraFields();
9383 if ($result < 0) {
9384 $error++;
9385 }
9386 }
9387
9388 // Create lines
9389 if (!empty($this->table_element_line) && !empty($this->fk_element)) {
9390 $num = (is_array($this->lines) ? count($this->lines) : 0);
9391 for ($i = 0; $i < $num; $i++) {
9392 $line = $this->lines[$i];
9393
9394 $keyforparent = $this->fk_element;
9395 $line->$keyforparent = $this->id;
9396
9397 // Test and convert into object this->lines[$i]. When coming from REST API, we may still have an array
9398 //if (! is_object($line)) $line=json_decode(json_encode($line), false); // convert recursively array into object.
9399 if (!is_object($line)) {
9400 $line = (object) $line;
9401 }
9402
9403 $result = 0;
9404 if (method_exists($line, 'insert')) {
9405 $result = $line->insert($user, 1);
9406 } elseif (method_exists($line, 'create')) {
9407 $result = $line->create($user, 1);
9408 }
9409 if ($result < 0) {
9410 $this->error = $line->error;
9411 $this->db->rollback();
9412 return -1;
9413 }
9414 }
9415 }
9416
9417 // Triggers
9418 if (!$error && !$notrigger) {
9419 // Call triggers
9420 $result = $this->call_trigger(strtoupper(get_class($this)).'_CREATE', $user);
9421 if ($result < 0) {
9422 $error++;
9423 }
9424 // End call triggers
9425 }
9426
9427 // Commit or rollback
9428 if ($error) {
9429 $this->db->rollback();
9430 return -1;
9431 } else {
9432 $this->db->commit();
9433 return $this->id;
9434 }
9435 }
9436
9437
9446 public function fetchCommon($id, $ref = null, $morewhere = '')
9447 {
9448 if (empty($id) && empty($ref) && empty($morewhere)) {
9449 return -1;
9450 }
9451
9452 $fieldlist = $this->getFieldList('t');
9453 if (empty($fieldlist)) {
9454 return 0;
9455 }
9456
9457 $sql = "SELECT ".$fieldlist;
9458 $sql .= " FROM ".$this->db->prefix().$this->table_element.' as t';
9459
9460 if (!empty($id)) {
9461 $sql .= ' WHERE t.rowid = '.((int) $id);
9462 } elseif (!empty($ref)) {
9463 $sql .= " WHERE t.ref = '".$this->db->escape($ref)."'";
9464 } else {
9465 $sql .= ' WHERE 1 = 1'; // usage with empty id and empty ref is very rare
9466 }
9467 if (empty($id) && isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
9468 $sql .= ' AND t.entity IN ('.getEntity($this->element).')';
9469 }
9470 if ($morewhere) {
9471 $sql .= $morewhere;
9472 }
9473 $sql .= ' LIMIT 1'; // This is a fetch, to be sure to get only one record
9474
9475 $res = $this->db->query($sql);
9476 if ($res) {
9477 $obj = $this->db->fetch_object($res);
9478 if ($obj) {
9479 $this->setVarsFromFetchObj($obj);
9480
9481 // Retrieve all extrafield
9482 // fetch optionals attributes and labels
9483 $this->fetch_optionals();
9484
9485 return $this->id;
9486 } else {
9487 return 0;
9488 }
9489 } else {
9490 $this->error = $this->db->lasterror();
9491 $this->errors[] = $this->error;
9492 return -1;
9493 }
9494 }
9495
9502 public function fetchLinesCommon($morewhere = '')
9503 {
9504 $objectlineclassname = get_class($this).'Line';
9505 if (!class_exists($objectlineclassname)) {
9506 $this->error = 'Error, class '.$objectlineclassname.' not found during call of fetchLinesCommon';
9507 return -1;
9508 }
9509
9510 $objectline = new $objectlineclassname($this->db);
9511
9512 $sql = "SELECT ".$objectline->getFieldList('l');
9513 $sql .= " FROM ".$this->db->prefix().$objectline->table_element." as l";
9514 $sql .= " WHERE l.fk_".$this->db->escape($this->element)." = ".((int) $this->id);
9515 if ($morewhere) {
9516 $sql .= $morewhere;
9517 }
9518 if (isset($objectline->fields['position'])) {
9519 $sql .= $this->db->order('position', 'ASC');
9520 }
9521
9522 $resql = $this->db->query($sql);
9523 if ($resql) {
9524 $num_rows = $this->db->num_rows($resql);
9525 $i = 0;
9526 $this->lines = array();
9527 while ($i < $num_rows) {
9528 $obj = $this->db->fetch_object($resql);
9529 if ($obj) {
9530 $newline = new $objectlineclassname($this->db);
9531 $newline->setVarsFromFetchObj($obj);
9532
9533 $this->lines[] = $newline;
9534 }
9535 $i++;
9536 }
9537
9538 return 1;
9539 } else {
9540 $this->error = $this->db->lasterror();
9541 $this->errors[] = $this->error;
9542 return -1;
9543 }
9544 }
9545
9553 public function updateCommon(User $user, $notrigger = false)
9554 {
9555 global $conf, $langs;
9556 dol_syslog(get_class($this)."::updateCommon update", LOG_DEBUG);
9557
9558 $error = 0;
9559
9560 $now = dol_now();
9561
9562 // $this->oldcopy should have been set by the caller of update
9563 //if (empty($this->oldcopy)) {
9564 // $this->oldcopy = dol_clone($this);
9565 //}
9566
9567 $fieldvalues = $this->setSaveQuery();
9568
9569 if (array_key_exists('date_modification', $fieldvalues) && empty($fieldvalues['date_modification'])) {
9570 $fieldvalues['date_modification'] = $this->db->idate($now);
9571 }
9572 if (array_key_exists('fk_user_modif', $fieldvalues) && !($fieldvalues['fk_user_modif'] > 0)) {
9573 $fieldvalues['fk_user_modif'] = $user->id;
9574 }
9575 unset($fieldvalues['rowid']); // The field 'rowid' is reserved field name for autoincrement field so we don't need it into update.
9576 if (array_key_exists('ref', $fieldvalues)) {
9577 $fieldvalues['ref'] = dol_string_nospecial($fieldvalues['ref']); // If field is a ref, we sanitize data
9578 }
9579
9580 // Add quotes and escape on fields with type string
9581 $keys = array();
9582 $values = array();
9583 $tmp = array();
9584 foreach ($fieldvalues as $k => $v) {
9585 $keys[$k] = $k;
9586 $value = $this->fields[$k];
9587 $values[$k] = $this->quote($v, $value);
9588 $tmp[] = $k.'='.$this->quote($v, $this->fields[$k]);
9589 }
9590
9591 // Clean and check mandatory fields
9592 foreach ($keys as $key) {
9593 if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') {
9594 $values[$key] = ''; // This is an implicit foreign key field
9595 }
9596 if (!empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') {
9597 $values[$key] = ''; // This is an explicit foreign key field
9598 }
9599
9600 //var_dump($key.'-'.$values[$key].'-'.($this->fields[$key]['notnull'] == 1));
9601 /*
9602 if ($this->fields[$key]['notnull'] == 1 && empty($values[$key]))
9603 {
9604 $error++;
9605 $this->errors[]=$langs->trans("ErrorFieldRequired", $this->fields[$key]['label']);
9606 }*/
9607 }
9608
9609 $sql = 'UPDATE '.$this->db->prefix().$this->table_element.' SET '.implode(', ', $tmp).' WHERE rowid='.((int) $this->id);
9610
9611 $this->db->begin();
9612
9613 if (!$error) {
9614 $res = $this->db->query($sql);
9615 if (!$res) {
9616 $error++;
9617 $this->errors[] = $this->db->lasterror();
9618 }
9619 }
9620
9621 // Update extrafield
9622 if (!$error) {
9623 $result = $this->insertExtraFields();
9624 if ($result < 0) {
9625 $error++;
9626 }
9627 }
9628
9629 // Triggers
9630 if (!$error && !$notrigger) {
9631 // Call triggers
9632 $result = $this->call_trigger(strtoupper(get_class($this)).'_MODIFY', $user);
9633 if ($result < 0) {
9634 $error++;
9635 } //Do also here what you must do to rollback action if trigger fail
9636 // End call triggers
9637 }
9638
9639 // Commit or rollback
9640 if ($error) {
9641 $this->db->rollback();
9642 return -1;
9643 } else {
9644 $this->db->commit();
9645 return $this->id;
9646 }
9647 }
9648
9657 public function deleteCommon(User $user, $notrigger = false, $forcechilddeletion = 0)
9658 {
9659 dol_syslog(get_class($this)."::deleteCommon delete", LOG_DEBUG);
9660
9661 $error = 0;
9662
9663 $this->db->begin();
9664
9665 if ($forcechilddeletion) { // Force also delete of childtables that should lock deletion in standard case when option force is off
9666 foreach ($this->childtables as $table) {
9667 $sql = "DELETE FROM ".$this->db->prefix().$table." WHERE ".$this->fk_element." = ".((int) $this->id);
9668 $resql = $this->db->query($sql);
9669 if (!$resql) {
9670 $this->error = $this->db->lasterror();
9671 $this->errors[] = $this->error;
9672 $this->db->rollback();
9673 return -1;
9674 }
9675 }
9676 } elseif (!empty($this->childtables)) { // If object has childs linked with a foreign key field, we check all child tables.
9677 $objectisused = $this->isObjectUsed($this->id);
9678 if (!empty($objectisused)) {
9679 dol_syslog(get_class($this)."::deleteCommon Can't delete record as it has some child", LOG_WARNING);
9680 $this->error = 'ErrorRecordHasChildren';
9681 $this->errors[] = $this->error;
9682 $this->db->rollback();
9683 return 0;
9684 }
9685 }
9686
9687 // Delete cascade first
9688 if (is_array($this->childtablesoncascade) && !empty($this->childtablesoncascade)) {
9689 foreach ($this->childtablesoncascade as $table) {
9690 $deleteFromObject = explode(':', $table);
9691 if (count($deleteFromObject) >= 2) {
9692 $className = str_replace('@', '', $deleteFromObject[0]);
9693 $filePath = $deleteFromObject[1];
9694 $columnName = $deleteFromObject[2];
9695 $TMoreSQL = array();
9696 $more_sql = $deleteFromObject[3];
9697 if (!empty($more_sql)) {
9698 $TMoreSQL['customsql'] = $more_sql;
9699 }
9700 if (dol_include_once($filePath)) {
9701 $childObject = new $className($this->db);
9702 if (method_exists($childObject, 'deleteByParentField')) {
9703 $result = $childObject->deleteByParentField($this->id, $columnName, $TMoreSQL);
9704 if ($result < 0) {
9705 $error++;
9706 $this->errors[] = $childObject->error;
9707 break;
9708 }
9709 } else {
9710 $error++;
9711 $this->errors[] = "You defined a cascade delete on an object $childObject but there is no method deleteByParentField for it";
9712 break;
9713 }
9714 } else {
9715 $error++;
9716 $this->errors[] = 'Cannot include child class file '.$filePath;
9717 break;
9718 }
9719 } else {
9720 // Delete record in child table
9721 $sql = "DELETE FROM ".$this->db->prefix().$table." WHERE ".$this->fk_element." = ".((int) $this->id);
9722
9723 $resql = $this->db->query($sql);
9724 if (!$resql) {
9725 $error++;
9726 $this->error = $this->db->lasterror();
9727 $this->errors[] = $this->error;
9728 break;
9729 }
9730 }
9731 }
9732 }
9733
9734 if (!$error) {
9735 if (!$notrigger) {
9736 // Call triggers
9737 $result = $this->call_trigger(strtoupper(get_class($this)).'_DELETE', $user);
9738 if ($result < 0) {
9739 $error++;
9740 } // Do also here what you must do to rollback action if trigger fail
9741 // End call triggers
9742 }
9743 }
9744
9745 // Delete llx_ecm_files
9746 if (!$error) {
9747 $res = $this->deleteEcmFiles(1); // Deleting files physically is done later with the dol_delete_dir_recursive
9748 if (!$res) {
9749 $error++;
9750 }
9751 }
9752
9753 // Delete linked object
9754 $res = $this->deleteObjectLinked();
9755 if ($res < 0) {
9756 $error++;
9757 }
9758
9759 if (!$error && !empty($this->isextrafieldmanaged)) {
9760 $result = $this->deleteExtraFields();
9761 if ($result < 0) {
9762 $error++;
9763 }
9764 }
9765
9766 if (!$error) {
9767 $sql = 'DELETE FROM '.$this->db->prefix().$this->table_element.' WHERE rowid='.((int) $this->id);
9768
9769 $resql = $this->db->query($sql);
9770 if (!$resql) {
9771 $error++;
9772 $this->errors[] = $this->db->lasterror();
9773 }
9774 }
9775
9776 // Commit or rollback
9777 if ($error) {
9778 $this->db->rollback();
9779 return -1;
9780 } else {
9781 $this->db->commit();
9782 return 1;
9783 }
9784 }
9785
9796 public function deleteByParentField($parentId = 0, $parentField = '', $filter = array(), $filtermode = "AND")
9797 {
9798 global $user;
9799
9800 $error = 0;
9801 $deleted = 0;
9802
9803 if (!empty($parentId) && !empty($parentField)) {
9804 $this->db->begin();
9805
9806 $sql = "SELECT rowid FROM ".$this->db->prefix().$this->table_element;
9807 $sql .= " WHERE ".$parentField." = ".(int) $parentId;
9808
9809 // Manage filters
9810 $sqlwhere = array();
9811 if (count($filter) > 0) {
9812 foreach ($filter as $key => $value) {
9813 if ($key == 'customsql') {
9814 $sqlwhere[] = $value;
9815 } elseif (strpos($value, '%') === false) {
9816 $sqlwhere[] = $key." IN (".$this->db->sanitize($this->db->escape($value)).")";
9817 } else {
9818 $sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'";
9819 }
9820 }
9821 }
9822 if (count($sqlwhere) > 0) {
9823 $sql .= " AND (".implode(" ".$filtermode." ", $sqlwhere).")";
9824 }
9825
9826 $resql = $this->db->query($sql);
9827 if (!$resql) {
9828 $this->errors[] = $this->db->lasterror();
9829 $error++;
9830 } else {
9831 while ($obj = $this->db->fetch_object($resql)) {
9832 $result = $this->fetch($obj->rowid);
9833 if ($result < 0) {
9834 $error++;
9835 $this->errors[] = $this->error;
9836 } else {
9837 if (get_class($this) == 'Contact') { // TODO special code because delete() for contact has not been standardized like other delete.
9838 $result = $this->delete();
9839 } else {
9840 $result = $this->delete($user);
9841 }
9842 if ($result < 0) {
9843 $error++;
9844 $this->errors[] = $this->error;
9845 } else {
9846 $deleted++;
9847 }
9848 }
9849 }
9850 }
9851
9852 if (empty($error)) {
9853 $this->db->commit();
9854 return $deleted;
9855 } else {
9856 $this->error = implode(', ', $this->errors);
9857 $this->db->rollback();
9858 return $error * -1;
9859 }
9860 }
9861
9862 return $deleted;
9863 }
9864
9873 public function deleteLineCommon(User $user, $idline, $notrigger = false)
9874 {
9875 global $conf;
9876
9877 $error = 0;
9878
9879 $tmpforobjectclass = get_class($this);
9880 $tmpforobjectlineclass = ucfirst($tmpforobjectclass).'Line';
9881
9882 $this->db->begin();
9883
9884 // Call trigger
9885 $result = $this->call_trigger('LINE'.strtoupper($tmpforobjectclass).'_DELETE', $user);
9886 if ($result < 0) {
9887 $error++;
9888 }
9889 // End call triggers
9890
9891 if (empty($error)) {
9892 $sql = "DELETE FROM ".$this->db->prefix().$this->table_element_line;
9893 $sql .= " WHERE rowid = ".((int) $idline);
9894
9895 $resql = $this->db->query($sql);
9896 if (!$resql) {
9897 $this->error = "Error ".$this->db->lasterror();
9898 $error++;
9899 }
9900 }
9901
9902 if (empty($error)) {
9903 // Remove extrafields
9904 $tmpobjectline = new $tmpforobjectlineclass($this->db);
9905 if (!isset($tmpobjectline->isextrafieldmanaged) || !empty($tmpobjectline->isextrafieldmanaged)) {
9906 $tmpobjectline->id = $idline;
9907 $result = $tmpobjectline->deleteExtraFields();
9908 if ($result < 0) {
9909 $error++;
9910 $this->error = "Error ".get_class($this)."::deleteLineCommon deleteExtraFields error -4 ".$tmpobjectline->error;
9911 }
9912 }
9913 }
9914
9915 if (empty($error)) {
9916 $this->db->commit();
9917 return 1;
9918 } else {
9919 dol_syslog(get_class($this)."::deleteLineCommon ERROR:".$this->error, LOG_ERR);
9920 $this->db->rollback();
9921 return -1;
9922 }
9923 }
9924
9925
9935 public function setStatusCommon($user, $status, $notrigger = 0, $triggercode = '')
9936 {
9937 $error = 0;
9938
9939 $this->db->begin();
9940
9941 $statusfield = 'status';
9942 if (in_array($this->element, array('don', 'donation', 'shipping'))) {
9943 $statusfield = 'fk_statut';
9944 }
9945
9946 $sql = "UPDATE ".$this->db->prefix().$this->table_element;
9947 $sql .= " SET ".$statusfield." = ".((int) $status);
9948 $sql .= " WHERE rowid = ".((int) $this->id);
9949
9950 if ($this->db->query($sql)) {
9951 if (!$error) {
9952 $this->oldcopy = clone $this;
9953 }
9954
9955 if (!$error && !$notrigger) {
9956 // Call trigger
9957 $result = $this->call_trigger($triggercode, $user);
9958 if ($result < 0) {
9959 $error++;
9960 }
9961 }
9962
9963 if (!$error) {
9964 $this->status = $status;
9965 $this->db->commit();
9966 return 1;
9967 } else {
9968 $this->db->rollback();
9969 return -1;
9970 }
9971 } else {
9972 $this->error = $this->db->error();
9973 $this->db->rollback();
9974 return -1;
9975 }
9976 }
9977
9978
9985 public function initAsSpecimenCommon()
9986 {
9987 global $user;
9988
9989 $this->id = 0;
9990 $this->specimen = 1;
9991 $fields = array(
9992 'label' => 'This is label',
9993 'ref' => 'ABCD1234',
9994 'description' => 'This is a description',
9995 'qty' => 123.12,
9996 'note_public' => 'Public note',
9997 'note_private' => 'Private note',
9998 'date_creation' => (dol_now() - 3600 * 48),
9999 'date_modification' => (dol_now() - 3600 * 24),
10000 'fk_user_creat' => $user->id,
10001 'fk_user_modif' => $user->id,
10002 'date' => dol_now(),
10003 );
10004 foreach ($fields as $key => $value) {
10005 if (array_key_exists($key, $this->fields)) {
10006 $this->{$key} = $value;
10007 }
10008 }
10009
10010 // Force values to default values when known
10011 if (property_exists($this, 'fields')) {
10012 foreach ($this->fields as $key => $value) {
10013 // If fields are already set, do nothing
10014 if (array_key_exists($key, $fields)) {
10015 continue;
10016 }
10017
10018 if (!empty($value['default'])) {
10019 $this->$key = $value['default'];
10020 }
10021 }
10022 }
10023
10024 return 1;
10025 }
10026
10027
10028 /* Part for comments */
10029
10034 public function fetchComments()
10035 {
10036 require_once DOL_DOCUMENT_ROOT.'/core/class/comment.class.php';
10037
10038 $comment = new Comment($this->db);
10039 $result = $comment->fetchAllFor($this->element, $this->id);
10040 if ($result < 0) {
10041 $this->errors = array_merge($this->errors, $comment->errors);
10042 return -1;
10043 } else {
10044 $this->comments = $comment->comments;
10045 }
10046 return count($this->comments);
10047 }
10048
10054 public function getNbComments()
10055 {
10056 return count($this->comments);
10057 }
10058
10065 public function trimParameters($parameters)
10066 {
10067 if (!is_array($parameters)) {
10068 return;
10069 }
10070 foreach ($parameters as $parameter) {
10071 if (isset($this->$parameter)) {
10072 $this->$parameter = trim($this->$parameter);
10073 }
10074 }
10075 }
10076
10077 /* Part for categories/tags */
10078
10089 public function getCategoriesCommon($type_categ)
10090 {
10091 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
10092
10093 // Get current categories
10094 $c = new Categorie($this->db);
10095 $existing = $c->containing($this->id, $type_categ, 'id');
10096
10097 return $existing;
10098 }
10099
10112 public function setCategoriesCommon($categories, $type_categ = '', $remove_existing = true)
10113 {
10114 // Handle single category
10115 if (!is_array($categories)) {
10116 $categories = array($categories);
10117 }
10118
10119 dol_syslog(get_class($this)."::setCategoriesCommon Oject Id:".$this->id.' type_categ:'.$type_categ.' nb tag add:'.count($categories), LOG_DEBUG);
10120
10121 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
10122
10123 if (empty($type_categ)) {
10124 dol_syslog(__METHOD__.': Type '.$type_categ.'is an unknown category type. Done nothing.', LOG_ERR);
10125 return -1;
10126 }
10127
10128 // Get current categories
10129 $c = new Categorie($this->db);
10130 $existing = $c->containing($this->id, $type_categ, 'id');
10131 if ($remove_existing) {
10132 // Diff
10133 if (is_array($existing)) {
10134 $to_del = array_diff($existing, $categories);
10135 $to_add = array_diff($categories, $existing);
10136 } else {
10137 $to_del = array(); // Nothing to delete
10138 $to_add = $categories;
10139 }
10140 } else {
10141 $to_del = array(); // Nothing to delete
10142 $to_add = array_diff($categories, $existing);
10143 }
10144
10145 $error = 0;
10146 $ok = 0;
10147
10148 // Process
10149 foreach ($to_del as $del) {
10150 if ($c->fetch($del) > 0) {
10151 $result=$c->del_type($this, $type_categ);
10152 if ($result < 0) {
10153 $error++;
10154 $this->error = $c->error;
10155 $this->errors = $c->errors;
10156 break;
10157 } else {
10158 $ok += $result;
10159 }
10160 }
10161 }
10162 foreach ($to_add as $add) {
10163 if ($c->fetch($add) > 0) {
10164 $result = $c->add_type($this, $type_categ);
10165 if ($result < 0) {
10166 $error++;
10167 $this->error = $c->error;
10168 $this->errors = $c->errors;
10169 break;
10170 } else {
10171 $ok += $result;
10172 }
10173 }
10174 }
10175
10176 return $error ? (-1 * $error) : $ok;
10177 }
10178
10187 public function cloneCategories($fromId, $toId, $type = '')
10188 {
10189 $this->db->begin();
10190
10191 if (empty($type)) {
10192 $type = $this->table_element;
10193 }
10194
10195 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
10196 $categorystatic = new Categorie($this->db);
10197
10198 $sql = "INSERT INTO ".$this->db->prefix()."categorie_".(empty($categorystatic->MAP_CAT_TABLE[$type]) ? $type : $categorystatic->MAP_CAT_TABLE[$type])." (fk_categorie, fk_product)";
10199 $sql .= " SELECT fk_categorie, $toId FROM ".$this->db->prefix()."categorie_".(empty($categorystatic->MAP_CAT_TABLE[$type]) ? $type : $categorystatic->MAP_CAT_TABLE[$type]);
10200 $sql .= " WHERE fk_product = ".((int) $fromId);
10201
10202 if (!$this->db->query($sql)) {
10203 $this->error = $this->db->lasterror();
10204 $this->db->rollback();
10205 return -1;
10206 }
10207
10208 $this->db->commit();
10209 return 1;
10210 }
10211
10218 public function deleteEcmFiles($mode = 0)
10219 {
10220 global $conf;
10221
10222 $this->db->begin();
10223
10224 // Delete in database with mode 0
10225 if ($mode == 0) {
10226 switch ($this->element) {
10227 case 'propal':
10228 $element = 'propale';
10229 break;
10230 case 'product':
10231 $element = 'produit';
10232 break;
10233 case 'order_supplier':
10234 $element = 'fournisseur/commande';
10235 break;
10236 case 'invoice_supplier':
10237 $element = 'fournisseur/facture/'.get_exdir($this->id, 2, 0, 1, $this, 'invoice_supplier');
10238 break;
10239 case 'shipping':
10240 $element = 'expedition/sending';
10241 break;
10242 default:
10243 $element = $this->element;
10244 }
10245
10246 // Delete ecm_files extrafields
10247 $sql = "DELETE FROM ".$this->db->prefix()."ecm_files_extrafields WHERE fk_object IN (";
10248 $sql .= " SELECT rowid FROM ".$this->db->prefix()."ecm_files WHERE filename LIKE '".$this->db->escape($this->ref)."%'";
10249 $sql .= " AND filepath = '".$this->db->escape($element)."/".$this->db->escape($this->ref)."' AND entity = ".((int) $conf->entity); // No need of getEntity here
10250 $sql .= ")";
10251
10252 if (!$this->db->query($sql)) {
10253 $this->error = $this->db->lasterror();
10254 $this->db->rollback();
10255 return false;
10256 }
10257
10258 // Delete ecm_files
10259 $sql = "DELETE FROM ".$this->db->prefix()."ecm_files";
10260 $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%'";
10261 $sql .= " AND filepath = '".$this->db->escape($element)."/".$this->db->escape($this->ref)."' AND entity = ".((int) $conf->entity); // No need of getEntity here
10262
10263 if (!$this->db->query($sql)) {
10264 $this->error = $this->db->lasterror();
10265 $this->db->rollback();
10266 return false;
10267 }
10268 }
10269
10270 // Delete in database with mode 1
10271 if ($mode == 1) {
10272 $sql = 'DELETE FROM '.$this->db->prefix()."ecm_files_extrafields";
10273 $sql .= " WHERE fk_object IN (SELECT rowid FROM ".$this->db->prefix()."ecm_files WHERE src_object_type = '".$this->db->escape($this->table_element.(empty($this->module) ? "" : "@".$this->module))."' AND src_object_id = ".((int) $this->id).")";
10274 $resql = $this->db->query($sql);
10275 if (!$resql) {
10276 $this->error = $this->db->lasterror();
10277 $this->db->rollback();
10278 return false;
10279 }
10280
10281 $sql = 'DELETE FROM '.$this->db->prefix()."ecm_files";
10282 $sql .= " WHERE src_object_type = '".$this->db->escape($this->table_element.(empty($this->module) ? "" : "@".$this->module))."' AND src_object_id = ".((int) $this->id);
10283 $resql = $this->db->query($sql);
10284 if (!$resql) {
10285 $this->error = $this->db->lasterror();
10286 $this->db->rollback();
10287 return false;
10288 }
10289 }
10290
10291 $this->db->commit();
10292 return true;
10293 }
10294}
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition ajax.lib.php:464
$object ref
Definition info.php:78
Class to manage categories.
Class to manage comment.
Parent class of all other business classes (invoices, contracts, proposals, orders,...
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
getCategoriesCommon($type_categ)
Sets object to given categories.
indexFile($destfull, $update_main_doc_field)
Index a file into the ECM database.
getFormatedSupplierRef($objref)
Return supplier ref for screen output.
line_order($renum=false, $rowidorder='ASC', $fk_parent_line=true)
Save a new position (field rang) for details lines.
clearFieldError($fieldKey)
clear validation message result for a field
deleteEcmFiles($mode=0)
Delete related files of object in database.
getLastMainDocLink($modulepart, $initsharekey=0, $relativelink=0)
Return the link of last main doc file for direct public download.
liste_type_contact($source='internal', $order='position', $option=0, $activeonly=0, $code='')
Return array with list of possible values for type of contacts.
getTooltipContent($params)
getTooltipContent
swapContactStatus($rowid)
Update status of a contact linked to object.
getFieldError($fieldKey)
get field error message
add_object_linked($origin=null, $origin_id=null, $f_user=null, $notrigger=0)
Add an object link into llx_element_element.
updateObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $f_user=null, $notrigger=0)
Update object linked of a current object.
defineBuyPrice($unitPrice=0.0, $discountPercent=0.0, $fk_product=0)
Get buy price to use for margin calculation.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
liste_contact($statusoflink=-1, $source='external', $list=0, $code='', $status=-1, $arrayoftcids=array())
Get array of all contacts for an object.
fetchObjectFrom($table, $field, $key, $element=null)
Load object from specific field.
fetch_thirdparty($force_thirdparty_id=0)
Load the third party of object, from id $this->socid or $this->fk_soc, into this->thirdparty.
deleteLineCommon(User $user, $idline, $notrigger=false)
Delete a line of object in database.
static deleteAllItemsLinkedByObjectID($fk_object_where, $field_where, $table_element)
Function used to remove all items linked to an object id in association table.
deleteByParentField($parentId=0, $parentField='', $filter=array(), $filtermode="AND")
Delete all child object from a parent ID.
setFieldError($fieldKey, $msg='')
set validation error message a field
validateField($fields, $fieldKey, $fieldValue)
Return validation test result for a field.
setMulticurrencyCode($code)
Change the multicurrency code.
add_element_resource($resource_id, $resource_type, $busy=0, $mandatory=0)
Add resources to the current object : add entry into llx_element_resources Need $this->element & $thi...
fetch_projet()
Load the project with id $this->fk_project into this->project.
getIdContact($source, $code, $status=0)
Return id of contacts for a source and a contact code.
setDocModel($user, $modelpdf)
Set last model used by doc generator.
updateExtraField($key, $trigger=null, $userused=null)
Update 1 extra field value for the current object.
setPaymentTerms($id, $deposit_percent=null)
Change the payments terms.
isFloat($info)
Function test if type is float.
setExtraParameters()
Set extra parameters.
setErrorsFromObject($object)
setErrorsFromObject
update_note_public($note)
Update public note (kept for backward compatibility)
getSpecialCode($lineid)
Get special code of a line.
fetchCommon($id, $ref=null, $morewhere='')
Load object in memory from the database.
clearObjectLinkedCache()
Clear the cache saying that all linked object were already loaded.
update_ref_ext($ref_ext)
Update external ref of element.
fetchOneLike($ref)
Looks for an object with ref matching the wildcard provided It does only work when $this->table_ref_f...
showOptionals($extrafields, $mode='view', $params=null, $keysuffix='', $keyprefix='', $onetrtd=0, $display_type='card')
Function to show lines of extrafields with output datas.
hasProductsOrServices($predefined=-1)
Function to say how many lines object contains.
static isExistingObject($element, $id, $ref='', $ref_ext='')
Check an object id/ref exists If you don't need/want to instantiate object and just need to know if o...
isObjectUsed($id=0, $entity=0)
Function to check if an object is used by others (by children).
createCommon(User $user, $notrigger=false)
Create object into database.
updateRangOfLine($rowid, $rang)
Update position of line (rang)
deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid='', $f_user=null, $notrigger=0)
Delete all links between an object $this.
getDefaultCreateValueFor($fieldname, $alternatevalue=null, $type='alphanohtml')
Return the default value to use for a field when showing the create form of object.
getTotalWeightVolume()
Return into unit=0, the calculated total of weight and volume of all lines * qty Calculate by adding ...
deleteCommon(User $user, $notrigger=false, $forcechilddeletion=0)
Delete object in database.
update_note($note, $suffix='', $notrigger=0)
Update note of element.
getFullAddress($withcountry=0, $sep="\n", $withregion=0, $extralangcode='')
Return full address of contact.
fetch_project()
Load the project with id $this->fk_project into this->project.
setStatut($status, $elementId=null, $elementType='', $trigkey='', $fieldstatus='fk_statut')
Set status of an object.
update_price($exclspec=0, $roundingadjust='none', $nodatabaseupdate=0, $seller=null)
Update total_ht, total_ttc, total_vat, total_localtax1, total_localtax2 for an object (sum of lines).
getFieldList($alias='', $excludefields=array())
Function to concat keys of fields.
getNbComments()
Return nb comments already posted.
setVarsFromFetchObj(&$obj)
Function to load data from a SQL pointer into properties of current object $this.
printObjectLines($action, $seller, $buyer, $selected=0, $dateSelector=0, $defaulttpldir='/core/tpl')
Return HTML table for object lines TODO Move this into an output class file (htmlline....
getChildrenOfLine($id, $includealltree=0)
Get children of line.
updateExtraLanguages($key, $trigger=null, $userused=null)
Update an extra language value for the current object.
deleteExtraFields()
Delete all extra fields values for the current object.
setStatusCommon($user, $status, $notrigger=0, $triggercode='')
Set to a status.
addThumbs($file)
Build thumb.
setSaveQuery()
Function to return the array of data key-value from the ->fields and all the ->properties of an objec...
setValuesForExtraLanguages($onlykey='')
Fill array_options property of object by extrafields value (using for data sent by forms)
insertExtraLanguages($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
setTransportMode($id)
Change the transport mode methods.
isArray($info)
Function test if type is array.
isInt($info)
Function test if type is integer.
fetchObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $clause='OR', $alsosametype=1, $orderby='sourcetype', $loadalsoobjects=1)
Fetch array of objects linked to current object (object of enabled modules only).
delete_contact($rowid, $notrigger=0)
Delete a link to contact line.
updateLineUp($rowid, $rang)
Update position of line up (rang)
fetch_user($userid)
Load the user with id $userid into this->user.
errorsToString()
Method to output saved errors.
setBankAccount($fk_account, $notrigger=false, $userused=null)
Change the bank account.
getListContactId($source='external')
Return list of id of contacts of object.
setWarehouse($warehouse_id)
Change the warehouse.
setDeliveryAddress($id)
Define delivery address.
getTotalDiscount()
Function that returns the total amount HT of discounts applied for all lines.
setShippingMethod($shipping_method_id, $notrigger=false, $userused=null)
Change the shipping method.
initAsSpecimenCommon()
Initialise object with example values Id must be 0 if object instance is a specimen.
printObjectLine($action, $line, $var, $num, $i, $dateSelector, $seller, $buyer, $selected=0, $extrafields=null, $defaulttpldir='/core/tpl')
Return HTML content of a detail line TODO Move this into an output class file (htmlline....
copy_linked_contact($objFrom, $source='internal')
Copy contact from one element to current.
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
getValueFrom($table, $id, $field)
Getter generic.
trimParameters($parameters)
Trim object parameters.
fetch_product()
Load the product with id $this->fk_product into this->product.
isIndex($info)
Function test if is indexed.
quote($value, $fieldsentry)
Add quote to field value if necessary.
formAddObjectLine($dateSelector, $seller, $buyer, $defaulttpldir='/core/tpl')
Show add free and predefined products/services form.
fetchComments()
Load comments linked with current task.
line_down($rowid, $fk_parent_line=true)
Update a line to have a higher rank.
setValueFrom($field, $value, $table='', $id=null, $format='', $id_field='', $fuser=null, $trigkey='', $fk_user_field='fk_user_modif')
Setter generic.
fetch_contact($contactid=null)
Load object contact with id=$this->contact_id into $this->contact.
setRetainedWarrantyPaymentTerms($id)
Change the retained warranty payments terms.
delThumbs($file)
Delete thumbs.
show_photos($modulepart, $sdir, $size=0, $nbmax=0, $nbbyrow=5, $showfilename=0, $showaction=0, $maxHeight=120, $maxWidth=160, $nolink=0, $overwritetitle=0, $usesharelink=0, $cache='', $addphotorefcss='photoref')
Show photos of an object (nbmax maximum), into several columns.
updateCommon(User $user, $notrigger=false)
Update object into database.
static commonReplaceProduct(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a product id with another one.
getRangOfLine($rowid)
Get position of line (rang)
showInputField($val, $key, $value, $moreparam='', $keysuffix='', $keyprefix='', $morecss=0, $nonewbutton=0)
Return HTML string to put an input field into a page Code very similar with showInputField of extra f...
delete_resource($rowid, $element, $notrigger=0)
Delete a link to resource line.
update_contact($rowid, $statut, $type_contact_id=0, $fk_socpeople=0)
Update a link to contact line.
load_previous_next_ref($filter, $fieldid, $nodbprefix=0)
Load properties id_previous and id_next by comparing $fieldid with $this->ref.
setCategoriesCommon($categories, $type_categ='', $remove_existing=true)
Sets object to given categories.
fetchValuesForExtraLanguages()
Function to get alternative languages of a data into $this->array_languages This method is NOT called...
fetchNoCompute($id)
Function to make a fetch but set environment to avoid to load computed values before.
line_max($fk_parent_line=0)
Get max value used for position of line (rang)
getJSListDependancies($type='_extra')
setProject($projectid, $notrigger=0)
Link element with a project.
isForcedToNullIfZero($info)
Function test if field is forced to null if zero or empty.
line_ajaxorder($rows)
Update position of line with ajax (rang)
printOriginLinesList($restrictlist='', $selectedLines=array())
Return HTML table table of source object lines TODO Move this and previous function into output html ...
fetchLinesCommon($morewhere='')
Load object in memory from the database.
fetch_origin()
Read linked origin object.
getIdOfLine($rang)
Get rowid of the line relative to its position.
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
static getAllItemsLinkedByObjectID($fk_object_where, $field_select, $field_where, $table_element)
Function used to get an array with all items linked to an object id in association table.
__clone()
Overwrite magic function to solve problem of cloning object that are kept as references.
setPaymentMethods($id)
Change the payments methods.
updateLineDown($rowid, $rang, $max)
Update position of line down (rang)
delete_linked_contact($source='', $code='')
Delete all links between an object $this and all its contacts in llx_element_contact.
getFormatedCustomerRef($objref)
Return customer ref for screen output.
getTooltipContentArray($params)
Return array of datas to show into a tooltip.
isText($info)
Function test if type is text.
isDate($info)
Function test if type is date.
printOriginLine($line, $var, $restrictlist='', $defaulttpldir='/core/tpl', $selectedLines=array())
Return HTML with a line of table array of source object lines TODO Move this and previous function in...
getCanvas($id=0, $ref='')
Load type of canvas of an object if it exists.
line_up($rowid, $fk_parent_line=true)
Update a line to have a lower rank.
isDuration($info)
Function test if type is duration.
canBeNull($info)
Function test if field can be null.
listeTypeContacts($source='internal', $option=0, $activeonly=0, $code='', $element='', $excludeelement='')
Return array with list of possible values for type of contacts.
call_trigger($triggerName, $user)
Call trigger based on this instance.
getRights()
Returns the rights used for this class.
add_contact($fk_socpeople, $type_contact, $source='external', $notrigger=0)
Add a link between element $this->element and a contact.
cloneCategories($fromId, $toId, $type='')
Copy related categories to another object.
fetch_barcode()
Load data for barcode into properties ->barcode_type* Properties ->barcode_type that is id of barcode...
Class to manage contact/addresses.
Class to manage absolute discounts.
Class to manage a WYSIWYG editor.
Class to manage Dolibarr database access.
Class to manage ECM files.
Class to manage standard extra fields.
Class to manage generation of HTML components Only common components must be here.
Class to manage triggers.
static getIdAndTxFromCode($dbs, $code, $date_document='')
Get id and rate of currency from code.
Class to manage predefined suppliers products.
Class to manage products or services.
const TYPE_SERVICE
Service.
Class to manage projects.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage translations.
Class to manage Dolibarr users.
Class toolbox to validate values.
print $langs trans("Ref").' m m m statut
Definition index.php:152
getCountry($searchkey, $withcode='', $dbtouse=0, $outputlangs='', $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
getState($id, $withcode='', $dbtouse=0, $withregion=0, $outputlangs='', $entconv=1)
Return state translated from an id.
convertSecondToTime($iSecond, $format='all', $lengthOfDay=86400, $lengthOfWeek=7)
Return, in clear text, value of a number of seconds in days, hours and minutes.
Definition date.lib.php:241
dol_meta_create($object)
Create a meta file with document file into same directory.
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
dol_is_file($pathoffile)
Return if path is a file.
dol_dir_list($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:62
completeFileArrayWithDatabaseInfo(&$filearray, $relativedir)
Complete $filearray with data from database.
dol_delete_preview($object)
Delete all preview files linked to object instance.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formated for view output Used into pdf and HTML pages.
dol_print_ip($ip, $mode=0)
Return an IP formated to be shown on screen.
img_delete($titlealt='default', $other='class="pictodelete"', $morecss='')
Show delete logo.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
get_date_range($date_start, $date_end, $format='', $outputlangs='', $withparenthesis=1)
Format output for start and end date.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
dol_format_address($object, $withcountry=0, $sep="\n", $outputlangs='', $mode=0, $extralangcode='')
Return a formated address (part address/zip/town/state) according to country rules.
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='', $keepspaces=0)
Clean a string from all punctuation characters to use it as a ref or login.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_print_email($email, $cid=0, $socid=0, $addlink=0, $max=64, $showinvalid=1, $withpicto=0)
Show EMail link formatted for HTML output.
dol_print_phone($phone, $countrycode='', $cid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0)
Format phone numbers according to country.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by second index function, which produces ascending (default) or descending output...
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
dol_eval($s, $returnvalue=0, $hideerrors=1, $onlysimplestring='1')
Replace eval function to add more security.
getImageFileNameForSize($file, $extName, $extImgTarget='')
Return the filename of file to get the thumbs.
getAdvancedPreviewUrl($modulepart, $relativepath, $alldata=0, $param='')
Return URL we can use for advanced preview links.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_print_url($url, $target='_blank', $max=32, $withpicto=0, $morecss='float')
Show Url link.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
getDictionaryValue($tablename, $field, $id, $checkentity=false, $rowidfield='rowid')
Return the value of a filed into a dictionary for the record $id.
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
vignette($file, $maxWidth=160, $maxHeight=120, $extName='_small', $quality=50, $outdir='thumbs', $targetformat=0)
Create a thumbnail from an image file (Supported extensions are gif, jpg, png and bmp).
getDefaultImageSizes()
Return default values for image sizes.
dol_getImageSize($file, $url=false)
Return size of image file on disk (Supported extensions are gif, jpg, png, bmp and webp)
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
query($query, $usesavepoint=0, $type='auto', $result_mode=0)
Execute a SQL request and return the resultset.
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall right right takeposterminal SELECT e rowid
Definition invoice.php:1632
calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $remise_percent_global, $price_base_type, $info_bits, $type, $seller='', $localtaxes_array='', $progress=100, $multicurrency_tx=1, $pu_devise=0, $multicurrency_code='')
Calculate totals (net, vat, ...) of a line.
Definition price.lib.php:86
$conf db user
Definition repair.php:124
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:120
getRandomPassword($generic=false, $replaceambiguouschars=null, $length=32)
Return a generated password using default module.
dol_hash($chain, $type='0')
Returns a hash (non reversible encryption) of a string.