dolibarr 18.0.8
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 public $next_prev_filter;
635
639 public $specimen = 0;
640
644 public $sendtoid;
645
649 public $alreadypaid;
650
651
652 public $labelStatus;
653 protected $labelStatusShort;
654
658 public $showphoto_on_popup;
659
663 public $nb = array();
664
668 public $output;
669
673 public $extraparams = array();
674
678 protected $childtables = array();
679
685 protected $childtablesoncascade = array();
686
687
688 // No constructor as it is an abstract class
689
690
701 public static function isExistingObject($element, $id, $ref = '', $ref_ext = '')
702 {
703 global $db, $conf;
704
705 $sql = "SELECT rowid, ref, ref_ext";
706 $sql .= " FROM ".$db->prefix().$element;
707 $sql .= " WHERE entity IN (".getEntity($element).")";
708
709 if ($id > 0) {
710 $sql .= " AND rowid = ".((int) $id);
711 } elseif ($ref) {
712 $sql .= " AND ref = '".$db->escape($ref)."'";
713 } elseif ($ref_ext) {
714 $sql .= " AND ref_ext = '".$db->escape($ref_ext)."'";
715 } else {
716 $error = 'ErrorWrongParameters';
717 dol_print_error(get_class()."::isExistingObject ".$error, LOG_ERR);
718 return -1;
719 }
720 if ($ref || $ref_ext) { // Because the same ref can exists in 2 different entities, we force the current one in priority
721 $sql .= " AND entity = ".((int) $conf->entity);
722 }
723
724 dol_syslog(get_class()."::isExistingObject", LOG_DEBUG);
725 $resql = $db->query($sql);
726 if ($resql) {
727 $num = $db->num_rows($resql);
728 if ($num > 0) {
729 return 1;
730 } else {
731 return 0;
732 }
733 }
734 return -1;
735 }
736
743 public function setErrorsFromObject($object)
744 {
745 if (!empty($object->error)) {
746 $this->error = $object->error;
747 }
748 if (!empty($object->errors)) {
749 $this->errors = array_merge($this->errors, $object->errors);
750 }
751 }
752
760 public function getTooltipContentArray($params)
761 {
762 return [];
763 }
764
772 public function getTooltipContent($params)
773 {
774 global $action, $extrafields, $langs, $hookmanager;
775
776 // If there is too much extrafields, we do not include them into tooltip
777 $MAX_EXTRAFIELDS_TO_SHOW_IN_TOOLTIP = getDolGlobalInt('MAX_EXTRAFIELDS_TO_SHOW_IN_TOOLTIP', 3);
778
779 $datas = $this->getTooltipContentArray($params);
780 $count = 0;
781
782 // Add extrafields
783 if (!empty($extrafields->attributes[$this->table_element]['label'])) {
784 foreach ($extrafields->attributes[$this->table_element]['label'] as $key => $val) {
785 if ($extrafields->attributes[$this->table_element]['type'][$key] == 'separate') {
786 continue;
787 }
788 if ($count >= abs($MAX_EXTRAFIELDS_TO_SHOW_IN_TOOLTIP)) {
789 $datas['more_extrafields'] = '<br>...';
790 break;
791 }
792 $enabled = 1;
793 if ($enabled && isset($extrafields->attributes[$this->table_element]['enabled'][$key])) {
794 $enabled = dol_eval($extrafields->attributes[$this->table_element]['enabled'][$key], 1, 1, '2');
795 }
796 if ($enabled && isset($extrafields->attributes[$this->table_element]['list'][$key])) {
797 $enabled = dol_eval($extrafields->attributes[$this->table_element]['list'][$key], 1, 1, '2');
798 }
799 $perms = 1;
800 if ($perms && isset($extrafields->attributes[$this->table_element]['perms'][$key])) {
801 $perms = dol_eval($extrafields->attributes[$this->table_element]['perms'][$key], 1, 1, '2');
802 }
803 if (empty($enabled)) {
804 continue; // 0 = Never visible field
805 }
806 if (abs($enabled) != 1 && abs($enabled) != 3 && abs($enabled) != 5 && abs($enabled) != 4) {
807 continue; // <> -1 and <> 1 and <> 3 = not visible on forms, only on list <> 4 = not visible at the creation
808 }
809 if (empty($perms)) {
810 continue; // 0 = Not visible
811 }
812 if (!empty($extrafields->attributes[$this->table_element]['langfile'][$key])) {
813 $langs->load($extrafields->attributes[$this->table_element]['langfile'][$key]);
814 }
815 $labelextra = $langs->trans((string) $extrafields->attributes[$this->table_element]['label'][$key]);
816 if ($extrafields->attributes[$this->table_element]['type'][$key] == 'separate') {
817 $datas[$key]= '<br><b><u>'. $labelextra . '</u></b>';
818 } else {
819 $value = (empty($this->array_options['options_' . $key]) ? '' : $this->array_options['options_' . $key]);
820 $datas[$key]= '<br><b>'. $labelextra . ':</b> ' . $extrafields->showOutputField($key, $value, '', $this->table_element);
821 $count++;
822 }
823 }
824 }
825
826 $hookmanager->initHooks(array($this->element . 'dao'));
827 $parameters = array(
828 'tooltipcontentarray' => &$datas,
829 'params' => $params,
830 );
831 // Note that $action and $object may have been modified by some hooks
832 $hookmanager->executeHooks('getTooltipContent', $parameters, $this, $action);
833
834 //var_dump($datas);
835 $label = implode($datas);
836
837 return $label;
838 }
839
840
846 public function errorsToString()
847 {
848 return $this->error.(is_array($this->errors) ? (($this->error != '' ? ', ' : '').join(', ', $this->errors)) : '');
849 }
850
851
858 public function getFormatedCustomerRef($objref)
859 {
860 global $hookmanager;
861
862 $parameters = array('objref'=>$objref);
863 $action = '';
864 $reshook = $hookmanager->executeHooks('getFormatedCustomerRef', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
865 if ($reshook > 0) {
866 return $hookmanager->resArray['objref'];
867 }
868 return $objref.(isset($hookmanager->resArray['objref']) ? $hookmanager->resArray['objref'] : '');
869 }
870
877 public function getFormatedSupplierRef($objref)
878 {
879 global $hookmanager;
880
881 $parameters = array('objref'=>$objref);
882 $action = '';
883 $reshook = $hookmanager->executeHooks('getFormatedSupplierRef', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
884 if ($reshook > 0) {
885 return $hookmanager->resArray['objref'];
886 }
887 return $objref.(isset($hookmanager->resArray['objref']) ? $hookmanager->resArray['objref'] : '');
888 }
889
899 public function getFullAddress($withcountry = 0, $sep = "\n", $withregion = 0, $extralangcode = '')
900 {
901 if ($withcountry && $this->country_id && (empty($this->country_code) || empty($this->country))) {
902 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
903 $tmparray = getCountry($this->country_id, 'all');
904 $this->country_code = $tmparray['code'];
905 $this->country = $tmparray['label'];
906 }
907
908 if ($withregion && $this->state_id && (empty($this->state_code) || empty($this->state) || empty($this->region) || empty($this->region_code))) {
909 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
910 $tmparray = getState($this->state_id, 'all', 0, 1);
911 $this->state_code = $tmparray['code'];
912 $this->state = $tmparray['label'];
913 $this->region_code = $tmparray['region_code'];
914 $this->region = $tmparray['region'];
915 }
916
917 return dol_format_address($this, $withcountry, $sep, '', 0, $extralangcode);
918 }
919
920
929 public function getLastMainDocLink($modulepart, $initsharekey = 0, $relativelink = 0)
930 {
931 global $user, $dolibarr_main_url_root;
932
933 if (empty($this->last_main_doc)) {
934 return ''; // No way to known which document name to use
935 }
936
937 include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
938 $ecmfile = new EcmFiles($this->db);
939 $result = $ecmfile->fetch(0, '', $this->last_main_doc);
940 if ($result < 0) {
941 $this->error = $ecmfile->error;
942 $this->errors = $ecmfile->errors;
943 return -1;
944 }
945
946 if (empty($ecmfile->id)) {
947 // Add entry into index
948 if ($initsharekey) {
949 require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
950
951 // 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
952 /*
953 $ecmfile->filepath = $rel_dir;
954 $ecmfile->filename = $filename;
955 $ecmfile->label = md5_file(dol_osencode($destfull)); // hash of file content
956 $ecmfile->fullpath_orig = '';
957 $ecmfile->gen_or_uploaded = 'generated';
958 $ecmfile->description = ''; // indexed content
959 $ecmfile->keywords = ''; // keyword content
960 $ecmfile->share = getRandomPassword(true);
961 $result = $ecmfile->create($user);
962 if ($result < 0)
963 {
964 $this->error = $ecmfile->error;
965 $this->errors = $ecmfile->errors;
966 }
967 */
968 } else {
969 return '';
970 }
971 } elseif (empty($ecmfile->share)) {
972 // Add entry into index
973 if ($initsharekey) {
974 require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
975 $ecmfile->share = getRandomPassword(true);
976 $ecmfile->update($user);
977 } else {
978 return '';
979 }
980 }
981 // Define $urlwithroot
982 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
983 // This is to use external domain name found into config file
984 //if (DOL_URL_ROOT && ! preg_match('/\/$/', $urlwithouturlroot) && ! preg_match('/^\//', DOL_URL_ROOT)) $urlwithroot=$urlwithouturlroot.'/'.DOL_URL_ROOT;
985 //else
986 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT;
987 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
988
989 $forcedownload = 0;
990
991 $paramlink = '';
992 //if (!empty($modulepart)) $paramlink.=($paramlink?'&':'').'modulepart='.$modulepart; // For sharing with hash (so public files), modulepart is not required.
993 //if (!empty($ecmfile->entity)) $paramlink.='&entity='.$ecmfile->entity; // For sharing with hash (so public files), entity is not required.
994 //$paramlink.=($paramlink?'&':'').'file='.urlencode($filepath); // No need of name of file for public link, we will use the hash
995 if (!empty($ecmfile->share)) {
996 $paramlink .= ($paramlink ? '&' : '').'hashp='.$ecmfile->share; // Hash for public share
997 }
998 if ($forcedownload) {
999 $paramlink .= ($paramlink ? '&' : '').'attachment=1';
1000 }
1001
1002 if ($relativelink) {
1003 $linktoreturn = 'document.php'.($paramlink ? '?'.$paramlink : '');
1004 } else {
1005 $linktoreturn = $urlwithroot.'/document.php'.($paramlink ? '?'.$paramlink : '');
1006 }
1007
1008 // Here $ecmfile->share is defined
1009 return $linktoreturn;
1010 }
1011
1012
1013 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1023 public function add_contact($fk_socpeople, $type_contact, $source = 'external', $notrigger = 0)
1024 {
1025 // phpcs:enable
1026 global $user, $langs;
1027
1028
1029 dol_syslog(get_class($this)."::add_contact $fk_socpeople, $type_contact, $source, $notrigger");
1030
1031 // Check parameters
1032 if ($fk_socpeople <= 0) {
1033 $langs->load("errors");
1034 $this->error = $langs->trans("ErrorWrongValueForParameterX", "1");
1035 dol_syslog(get_class($this)."::add_contact ".$this->error, LOG_ERR);
1036 return -1;
1037 }
1038 if (!$type_contact) {
1039 $langs->load("errors");
1040 $this->error = $langs->trans("ErrorWrongValueForParameterX", "2");
1041 dol_syslog(get_class($this)."::add_contact ".$this->error, LOG_ERR);
1042 return -2;
1043 }
1044
1045 $id_type_contact = 0;
1046 if (is_numeric($type_contact)) {
1047 $id_type_contact = $type_contact;
1048 } else {
1049 // We look for id type_contact
1050 $sql = "SELECT tc.rowid";
1051 $sql .= " FROM ".$this->db->prefix()."c_type_contact as tc";
1052 $sql .= " WHERE tc.element='".$this->db->escape($this->element)."'";
1053 $sql .= " AND tc.source='".$this->db->escape($source)."'";
1054 $sql .= " AND tc.code='".$this->db->escape($type_contact)."' AND tc.active=1";
1055 //print $sql;
1056 $resql = $this->db->query($sql);
1057 if ($resql) {
1058 $obj = $this->db->fetch_object($resql);
1059 if ($obj) {
1060 $id_type_contact = $obj->rowid;
1061 }
1062 }
1063 }
1064
1065 if ($id_type_contact == 0) {
1066 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");
1067 return 0;
1068 }
1069
1070 $datecreate = dol_now();
1071
1072 // Socpeople must have already been added by some trigger, then we have to check it to avoid DB_ERROR_RECORD_ALREADY_EXISTS error
1073 $TListeContacts = $this->liste_contact(-1, $source);
1074 $already_added = false;
1075 if (is_array($TListeContacts) && !empty($TListeContacts)) {
1076 foreach ($TListeContacts as $array_contact) {
1077 if ($array_contact['status'] == 4 && $array_contact['id'] == $fk_socpeople && $array_contact['fk_c_type_contact'] == $id_type_contact) {
1078 $already_added = true;
1079 break;
1080 }
1081 }
1082 }
1083
1084 if (!$already_added) {
1085 $this->db->begin();
1086
1087 // Insert into database
1088 $sql = "INSERT INTO ".$this->db->prefix()."element_contact";
1089 $sql .= " (element_id, fk_socpeople, datecreate, statut, fk_c_type_contact) ";
1090 $sql .= " VALUES (".$this->id.", ".((int) $fk_socpeople)." , ";
1091 $sql .= "'".$this->db->idate($datecreate)."'";
1092 $sql .= ", 4, ".((int) $id_type_contact);
1093 $sql .= ")";
1094
1095 $resql = $this->db->query($sql);
1096 if ($resql) {
1097 if (!$notrigger) {
1098 $result = $this->call_trigger(strtoupper($this->element).'_ADD_CONTACT', $user);
1099 if ($result < 0) {
1100 $this->db->rollback();
1101 return -1;
1102 }
1103 }
1104
1105 $this->db->commit();
1106 return 1;
1107 } else {
1108 if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
1109 $this->error = $this->db->errno();
1110 $this->db->rollback();
1111 return -2;
1112 } else {
1113 $this->error = $this->db->lasterror();
1114 $this->db->rollback();
1115 return -1;
1116 }
1117 }
1118 } else {
1119 return 0;
1120 }
1121 }
1122
1123 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1131 public function copy_linked_contact($objFrom, $source = 'internal')
1132 {
1133 // phpcs:enable
1134 $contacts = $objFrom->liste_contact(-1, $source);
1135 foreach ($contacts as $contact) {
1136 if ($this->add_contact($contact['id'], $contact['fk_c_type_contact'], $contact['source']) < 0) {
1137 return -1;
1138 }
1139 }
1140 return 1;
1141 }
1142
1143 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1153 public function update_contact($rowid, $statut, $type_contact_id = 0, $fk_socpeople = 0)
1154 {
1155 // phpcs:enable
1156 // Insert into database
1157 $sql = "UPDATE ".$this->db->prefix()."element_contact set";
1158 $sql .= " statut = ".$statut;
1159 if ($type_contact_id) {
1160 $sql .= ", fk_c_type_contact = ".((int) $type_contact_id);
1161 }
1162 if ($fk_socpeople) {
1163 $sql .= ", fk_socpeople = ".((int) $fk_socpeople);
1164 }
1165 $sql .= " where rowid = ".((int) $rowid);
1166 $resql = $this->db->query($sql);
1167 if ($resql) {
1168 return 0;
1169 } else {
1170 $this->error = $this->db->lasterror();
1171 return -1;
1172 }
1173 }
1174
1175 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1183 public function delete_contact($rowid, $notrigger = 0)
1184 {
1185 // phpcs:enable
1186 global $user;
1187
1188 $error = 0;
1189
1190 $this->db->begin();
1191
1192 if (!$error && empty($notrigger)) {
1193 // Call trigger
1194 $this->context['contact_id'] = ((int) $rowid);
1195 $result = $this->call_trigger(strtoupper($this->element).'_DELETE_CONTACT', $user);
1196 if ($result < 0) {
1197 $error++;
1198 }
1199 // End call triggers
1200 }
1201
1202 if (!$error) {
1203 dol_syslog(get_class($this)."::delete_contact", LOG_DEBUG);
1204
1205 $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_contact";
1206 $sql .= " WHERE rowid = ".((int) $rowid);
1207
1208 $result = $this->db->query($sql);
1209 if (!$result) {
1210 $error++;
1211 $this->errors[] = $this->db->lasterror();
1212 }
1213 }
1214
1215 if (!$error) {
1216 $this->db->commit();
1217 return 1;
1218 } else {
1219 $this->error = $this->db->lasterror();
1220 $this->db->rollback();
1221 return -1;
1222 }
1223 }
1224
1225 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1233 public function delete_linked_contact($source = '', $code = '')
1234 {
1235 // phpcs:enable
1236 $listId = '';
1237 $temp = array();
1238 $typeContact = $this->liste_type_contact($source, '', 0, 0, $code);
1239
1240 if (!empty($typeContact)) {
1241 foreach ($typeContact as $key => $value) {
1242 array_push($temp, $key);
1243 }
1244 $listId = implode(",", $temp);
1245 }
1246
1247 // If $listId is empty, we have not criteria on fk_c_type_contact so we will delete record on element_id for
1248 // any type or record instead of only the ones of the current object. So we do nothing in such a case.
1249 if (empty($listId)) {
1250 return 0;
1251 }
1252
1253 $sql = "DELETE FROM ".$this->db->prefix()."element_contact";
1254 $sql .= " WHERE element_id = ".((int) $this->id);
1255 $sql .= " AND fk_c_type_contact IN (".$this->db->sanitize($listId).")";
1256
1257 dol_syslog(get_class($this)."::delete_linked_contact", LOG_DEBUG);
1258 if ($this->db->query($sql)) {
1259 return 1;
1260 } else {
1261 $this->error = $this->db->lasterror();
1262 return -1;
1263 }
1264 }
1265
1266 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1278 public function liste_contact($statusoflink = -1, $source = 'external', $list = 0, $code = '', $status = -1, $arrayoftcids = array())
1279 {
1280 // phpcs:enable
1281 global $langs;
1282
1283 $tab = array();
1284
1285 $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
1286 if ($source == 'internal') {
1287 $sql .= ", '-1' as socid, t.statut as statuscontact, t.login, t.photo";
1288 }
1289 if ($source == 'external' || $source == 'thirdparty') {
1290 $sql .= ", t.fk_soc as socid, t.statut as statuscontact";
1291 }
1292 $sql .= ", t.civility as civility, t.lastname as lastname, t.firstname, t.email";
1293 $sql .= ", tc.source, tc.element, tc.code, tc.libelle";
1294 $sql .= " FROM ".$this->db->prefix()."c_type_contact tc,";
1295 $sql .= " ".$this->db->prefix()."element_contact ec";
1296 if ($source == 'internal') { // internal contact (user)
1297 $sql .= " LEFT JOIN ".$this->db->prefix()."user t on ec.fk_socpeople = t.rowid";
1298 }
1299 if ($source == 'external' || $source == 'thirdparty') { // external contact (socpeople)
1300 $sql .= " LEFT JOIN ".$this->db->prefix()."socpeople t on ec.fk_socpeople = t.rowid";
1301 }
1302 $sql .= " WHERE ec.element_id = ".((int) $this->id);
1303 $sql .= " AND ec.fk_c_type_contact = tc.rowid";
1304 $sql .= " AND tc.element = '".$this->db->escape($this->element)."'";
1305 if ($code) {
1306 $sql .= " AND tc.code = '".$this->db->escape($code)."'";
1307 }
1308 if ($source == 'internal') {
1309 $sql .= " AND tc.source = 'internal'";
1310 if ($status >= 0) {
1311 $sql .= " AND t.statut = ".((int) $status);
1312 }
1313 }
1314 if ($source == 'external' || $source == 'thirdparty') {
1315 $sql .= " AND tc.source = 'external'";
1316 if ($status >= 0) {
1317 $sql .= " AND t.statut = ".((int) $status); // t is llx_socpeople
1318 }
1319 }
1320 $sql .= " AND tc.active = 1";
1321 if ($statusoflink >= 0) {
1322 $sql .= " AND ec.statut = ".((int) $statusoflink);
1323 }
1324 $sql .= " ORDER BY t.lastname ASC";
1325
1326 dol_syslog(get_class($this)."::liste_contact", LOG_DEBUG);
1327 $resql = $this->db->query($sql);
1328 if ($resql) {
1329 $num = $this->db->num_rows($resql);
1330 $i = 0;
1331 while ($i < $num) {
1332 $obj = $this->db->fetch_object($resql);
1333
1334 if (!$list) {
1335 $transkey = "TypeContact_".$obj->element."_".$obj->source."_".$obj->code;
1336 $libelle_type = ($langs->trans($transkey) != $transkey ? $langs->trans($transkey) : $obj->libelle);
1337 $tab[$i] = array(
1338 'parentId' => $this->id,
1339 'source' => $obj->source,
1340 'socid' => $obj->socid,
1341 'id' => $obj->id,
1342 'nom' => $obj->lastname, // For backward compatibility
1343 'civility' => $obj->civility,
1344 'lastname' => $obj->lastname,
1345 'firstname' => $obj->firstname,
1346 'email'=>$obj->email,
1347 'login'=> (empty($obj->login) ? '' : $obj->login),
1348 'photo' => (empty($obj->photo) ? '' : $obj->photo),
1349 'statuscontact' => $obj->statuscontact,
1350 'rowid' => $obj->rowid,
1351 'code' => $obj->code,
1352 'libelle' => $libelle_type,
1353 'status' => $obj->statuslink,
1354 'fk_c_type_contact' => $obj->fk_c_type_contact
1355 );
1356 } else {
1357 $tab[$i] = $obj->id;
1358 }
1359
1360 $i++;
1361 }
1362
1363 return $tab;
1364 } else {
1365 $this->error = $this->db->lasterror();
1366 dol_print_error($this->db);
1367 return -1;
1368 }
1369 }
1370
1371
1378 public function swapContactStatus($rowid)
1379 {
1380 $sql = "SELECT ec.datecreate, ec.statut, ec.fk_socpeople, ec.fk_c_type_contact,";
1381 $sql .= " tc.code, tc.libelle";
1382 $sql .= " FROM (".$this->db->prefix()."element_contact as ec, ".$this->db->prefix()."c_type_contact as tc)";
1383 $sql .= " WHERE ec.rowid =".((int) $rowid);
1384 $sql .= " AND ec.fk_c_type_contact=tc.rowid";
1385 $sql .= " AND tc.element = '".$this->db->escape($this->element)."'";
1386
1387 dol_syslog(get_class($this)."::swapContactStatus", LOG_DEBUG);
1388 $resql = $this->db->query($sql);
1389 if ($resql) {
1390 $obj = $this->db->fetch_object($resql);
1391 $newstatut = ($obj->statut == 4) ? 5 : 4;
1392 $result = $this->update_contact($rowid, $newstatut);
1393 $this->db->free($resql);
1394 return $result;
1395 } else {
1396 $this->error = $this->db->error();
1397 dol_print_error($this->db);
1398 return -1;
1399 }
1400 }
1401
1402 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1413 public function liste_type_contact($source = 'internal', $order = 'position', $option = 0, $activeonly = 0, $code = '')
1414 {
1415 // phpcs:enable
1416 global $langs;
1417
1418 if (empty($order)) {
1419 $order = 'position';
1420 }
1421 if ($order == 'position') {
1422 $order .= ',code';
1423 }
1424
1425 $tab = array();
1426 $sql = "SELECT DISTINCT tc.rowid, tc.code, tc.libelle, tc.position";
1427 $sql .= " FROM ".$this->db->prefix()."c_type_contact as tc";
1428 $sql .= " WHERE tc.element='".$this->db->escape($this->element)."'";
1429 if ($activeonly == 1) {
1430 $sql .= " AND tc.active=1"; // only the active types
1431 }
1432 if (!empty($source) && $source != 'all') {
1433 $sql .= " AND tc.source='".$this->db->escape($source)."'";
1434 }
1435 if (!empty($code)) {
1436 $sql .= " AND tc.code='".$this->db->escape($code)."'";
1437 }
1438 $sql .= $this->db->order($order, 'ASC');
1439
1440 //print "sql=".$sql;
1441 $resql = $this->db->query($sql);
1442 if ($resql) {
1443 $num = $this->db->num_rows($resql);
1444 $i = 0;
1445 while ($i < $num) {
1446 $obj = $this->db->fetch_object($resql);
1447
1448 $transkey = "TypeContact_".$this->element."_".$source."_".$obj->code;
1449 $libelle_type = ($langs->trans($transkey) != $transkey ? $langs->trans($transkey) : $obj->libelle);
1450 if (empty($option)) {
1451 $tab[$obj->rowid] = $libelle_type;
1452 } else {
1453 $tab[$obj->code] = $libelle_type;
1454 }
1455 $i++;
1456 }
1457 return $tab;
1458 } else {
1459 $this->error = $this->db->lasterror();
1460 //dol_print_error($this->db);
1461 return null;
1462 }
1463 }
1464
1476 public function listeTypeContacts($source = 'internal', $option = 0, $activeonly = 0, $code = '', $element = '', $excludeelement = '')
1477 {
1478 global $langs, $conf;
1479
1480 $langs->loadLangs(array('bills', 'contracts', 'interventions', 'orders', 'projects', 'propal', 'ticket', 'agenda'));
1481
1482 $tab = array();
1483
1484 $sql = "SELECT DISTINCT tc.rowid, tc.code, tc.libelle, tc.position, tc.element";
1485 $sql .= " FROM ".$this->db->prefix()."c_type_contact as tc";
1486
1487 $sqlWhere = array();
1488 if (!empty($element)) {
1489 $sqlWhere[] = " tc.element='".$this->db->escape($element)."'";
1490 }
1491 if (!empty($excludeelement)) {
1492 $sqlWhere[] = " tc.element <> '".$this->db->escape($excludeelement)."'";
1493 }
1494
1495 if ($activeonly == 1) {
1496 $sqlWhere[] = " tc.active=1"; // only the active types
1497 }
1498
1499 if (!empty($source) && $source != 'all') {
1500 $sqlWhere[] = " tc.source='".$this->db->escape($source)."'";
1501 }
1502
1503 if (!empty($code)) {
1504 $sqlWhere[] = " tc.code='".$this->db->escape($code)."'";
1505 }
1506
1507 if (count($sqlWhere) > 0) {
1508 $sql .= " WHERE ".implode(' AND ', $sqlWhere);
1509 }
1510
1511 $sql .= $this->db->order('tc.element, tc.position', 'ASC');
1512
1513 dol_syslog(__METHOD__, LOG_DEBUG);
1514 $resql = $this->db->query($sql);
1515 if ($resql) {
1516 $num = $this->db->num_rows($resql);
1517 if ($num > 0) {
1518 $langs->loadLangs(array("propal", "orders", "bills", "suppliers", "contracts", "supplier_proposal"));
1519
1520 while ($obj = $this->db->fetch_object($resql)) {
1521 $modulename = $obj->element;
1522 if (strpos($obj->element, 'project') !== false) {
1523 $modulename = 'projet';
1524 } elseif ($obj->element == 'contrat') {
1525 $element = 'contract';
1526 } elseif ($obj->element == 'action') {
1527 $modulename = 'agenda';
1528 } elseif (strpos($obj->element, 'supplier') !== false && $obj->element != 'supplier_proposal') {
1529 $modulename = 'fournisseur';
1530 } elseif (strpos($obj->element, 'supplier') !== false && $obj->element != 'supplier_proposal') {
1531 $modulename = 'fournisseur';
1532 }
1533 if (!empty($conf->{$modulename}->enabled)) {
1534 $libelle_element = $langs->trans('ContactDefault_'.$obj->element);
1535 $tmpelement = $obj->element;
1536 $transkey = "TypeContact_".$tmpelement."_".$source."_".$obj->code;
1537 $libelle_type = ($langs->trans($transkey) != $transkey ? $langs->trans($transkey) : $obj->libelle);
1538 if (empty($option)) {
1539 $tab[$obj->rowid] = $libelle_element.' - '.$libelle_type;
1540 } else {
1541 $tab[$obj->rowid] = $libelle_element.' - '.$libelle_type;
1542 }
1543 }
1544 }
1545 }
1546 return $tab;
1547 } else {
1548 $this->error = $this->db->lasterror();
1549 return null;
1550 }
1551 }
1552
1564 public function getIdContact($source, $code, $status = 0)
1565 {
1566 global $conf;
1567
1568 $result = array();
1569 $i = 0;
1570 //cas particulier pour les expeditions
1571 if ($this->element == 'shipping' && $this->origin_id != 0) {
1572 $id = $this->origin_id;
1573 $element = 'commande';
1574 } elseif ($this->element == 'reception' && $this->origin_id != 0) {
1575 $id = $this->origin_id;
1576 $element = 'order_supplier';
1577 } else {
1578 $id = $this->id;
1579 $element = $this->element;
1580 }
1581
1582 $sql = "SELECT ec.fk_socpeople";
1583 $sql .= " FROM ".$this->db->prefix()."element_contact as ec,";
1584 if ($source == 'internal') {
1585 $sql .= " ".$this->db->prefix()."user as c,";
1586 }
1587 if ($source == 'external') {
1588 $sql .= " ".$this->db->prefix()."socpeople as c,";
1589 }
1590 $sql .= " ".$this->db->prefix()."c_type_contact as tc";
1591 $sql .= " WHERE ec.element_id = ".((int) $id);
1592 $sql .= " AND ec.fk_socpeople = c.rowid";
1593 if ($source == 'internal') {
1594 $sql .= " AND c.entity IN (".getEntity('user').")";
1595 }
1596 if ($source == 'external') {
1597 $sql .= " AND c.entity IN (".getEntity('societe').")";
1598 }
1599 $sql .= " AND ec.fk_c_type_contact = tc.rowid";
1600 $sql .= " AND tc.element = '".$this->db->escape($element)."'";
1601 $sql .= " AND tc.source = '".$this->db->escape($source)."'";
1602 if ($code) {
1603 $sql .= " AND tc.code = '".$this->db->escape($code)."'";
1604 }
1605 $sql .= " AND tc.active = 1";
1606 if ($status) {
1607 $sql .= " AND ec.statut = ".((int) $status);
1608 }
1609
1610 dol_syslog(get_class($this)."::getIdContact", LOG_DEBUG);
1611 $resql = $this->db->query($sql);
1612 if ($resql) {
1613 while ($obj = $this->db->fetch_object($resql)) {
1614 $result[$i] = $obj->fk_socpeople;
1615 $i++;
1616 }
1617 } else {
1618 $this->error = $this->db->error();
1619 return null;
1620 }
1621
1622 return $result;
1623 }
1624
1625 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1632 public function fetch_contact($contactid = null)
1633 {
1634 // phpcs:enable
1635 if (empty($contactid)) {
1636 $contactid = $this->contact_id;
1637 }
1638
1639 if (empty($contactid)) {
1640 return 0;
1641 }
1642
1643 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1644 $contact = new Contact($this->db);
1645 $result = $contact->fetch($contactid);
1646 $this->contact = $contact;
1647 return $result;
1648 }
1649
1650 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1657 public function fetch_thirdparty($force_thirdparty_id = 0)
1658 {
1659 // phpcs:enable
1660 global $conf;
1661
1662 if (empty($this->socid) && empty($this->fk_soc) && empty($force_thirdparty_id)) {
1663 return 0;
1664 }
1665
1666 require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
1667
1668 $idtofetch = isset($this->socid) ? $this->socid : (isset($this->fk_soc) ? $this->fk_soc : 0);
1669 if ($force_thirdparty_id) {
1670 $idtofetch = $force_thirdparty_id;
1671 }
1672
1673 if ($idtofetch) {
1674 $thirdparty = new Societe($this->db);
1675 $result = $thirdparty->fetch($idtofetch);
1676 if ($result<0) {
1677 $this->errors=array_merge($this->errors, $thirdparty->errors);
1678 }
1679 $this->thirdparty = $thirdparty;
1680
1681 // Use first price level if level not defined for third party
1682 if (!empty($conf->global->PRODUIT_MULTIPRICES) && empty($this->thirdparty->price_level)) {
1683 $this->thirdparty->price_level = 1;
1684 }
1685
1686 return $result;
1687 } else {
1688 return -1;
1689 }
1690 }
1691
1692
1700 public function fetchOneLike($ref)
1701 {
1702 if (!$this->table_ref_field) {
1703 return 0;
1704 }
1705
1706 $sql = "SELECT rowid FROM ".$this->db->prefix().$this->table_element." WHERE ".$this->table_ref_field." LIKE '".$this->db->escape($ref)."' LIMIT 1";
1707
1708 $query = $this->db->query($sql);
1709
1710 if (!$this->db->num_rows($query)) {
1711 return 0;
1712 }
1713
1714 $result = $this->db->fetch_object($query);
1715
1716 return $this->fetch($result->rowid);
1717 }
1718
1719 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1727 public function fetch_barcode()
1728 {
1729 // phpcs:enable
1730 global $conf;
1731
1732 dol_syslog(get_class($this).'::fetch_barcode this->element='.$this->element.' this->barcode_type='.$this->barcode_type);
1733
1734 $idtype = $this->barcode_type;
1735 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
1736 if ($this->element == 'product' && !empty($conf->global->PRODUIT_DEFAULT_BARCODE_TYPE)) {
1737 $idtype = $conf->global->PRODUIT_DEFAULT_BARCODE_TYPE;
1738 } elseif ($this->element == 'societe') {
1739 $idtype = $conf->global->GENBARCODE_BARCODETYPE_THIRDPARTY;
1740 } else {
1741 dol_syslog('Call fetch_barcode with barcode_type not defined and cant be guessed', LOG_WARNING);
1742 }
1743 }
1744
1745 if ($idtype > 0) {
1746 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
1747 $sql = "SELECT rowid, code, libelle as label, coder";
1748 $sql .= " FROM ".$this->db->prefix()."c_barcode_type";
1749 $sql .= " WHERE rowid = ".((int) $idtype);
1750 dol_syslog(get_class($this).'::fetch_barcode', LOG_DEBUG);
1751 $resql = $this->db->query($sql);
1752 if ($resql) {
1753 $obj = $this->db->fetch_object($resql);
1754 $this->barcode_type = $obj->rowid;
1755 $this->barcode_type_code = $obj->code;
1756 $this->barcode_type_label = $obj->label;
1757 $this->barcode_type_coder = $obj->coder;
1758 return 1;
1759 } else {
1760 dol_print_error($this->db);
1761 return -1;
1762 }
1763 }
1764 }
1765 return 0;
1766 }
1767
1768 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1774 public function fetch_project()
1775 {
1776 // phpcs:enable
1777 return $this->fetch_projet();
1778 }
1779
1780 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1786 public function fetch_projet()
1787 {
1788 // phpcs:enable
1789 include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
1790
1791 if (empty($this->fk_project) && !empty($this->fk_projet)) {
1792 $this->fk_project = $this->fk_projet; // For backward compatibility
1793 }
1794 if (empty($this->fk_project)) {
1795 return 0;
1796 }
1797
1798 $project = new Project($this->db);
1799 $result = $project->fetch($this->fk_project);
1800
1801 $this->projet = $project; // deprecated
1802 $this->project = $project;
1803 return $result;
1804 }
1805
1806 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1812 public function fetch_product()
1813 {
1814 // phpcs:enable
1815 include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
1816
1817 if (empty($this->fk_product)) {
1818 return 0;
1819 }
1820
1821 $product = new Product($this->db);
1822 $result = $product->fetch($this->fk_product);
1823
1824 $this->product = $product;
1825 return $result;
1826 }
1827
1828 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1835 public function fetch_user($userid)
1836 {
1837 // phpcs:enable
1838 $user = new User($this->db);
1839 $result = $user->fetch($userid);
1840 $this->user = $user;
1841 return $result;
1842 }
1843
1844 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1850 public function fetch_origin()
1851 {
1852 // phpcs:enable
1853 if ($this->origin == 'shipping') {
1854 $this->origin = 'expedition';
1855 }
1856 if ($this->origin == 'delivery') {
1857 $this->origin = 'livraison';
1858 }
1859 if ($this->origin == 'order_supplier') {
1860 $this->origin = 'commandeFournisseur';
1861 }
1862
1863 $origin = $this->origin;
1864
1865 $classname = ucfirst($origin);
1866 $this->$origin = new $classname($this->db);
1867 $this->$origin->fetch($this->origin_id);
1868 }
1869
1879 public function fetchObjectFrom($table, $field, $key, $element = null)
1880 {
1881 global $conf;
1882
1883 $result = false;
1884
1885 $sql = "SELECT rowid FROM ".$this->db->prefix().$table;
1886 $sql .= " WHERE ".$field." = '".$this->db->escape($key)."'";
1887 if (!empty($element)) {
1888 $sql .= " AND entity IN (".getEntity($element).")";
1889 } else {
1890 $sql .= " AND entity = ".((int) $conf->entity);
1891 }
1892
1893 dol_syslog(get_class($this).'::fetchObjectFrom', LOG_DEBUG);
1894 $resql = $this->db->query($sql);
1895 if ($resql) {
1896 $row = $this->db->fetch_row($resql);
1897 // Test for avoid error -1
1898 if ($row[0] > 0) {
1899 $result = $this->fetch($row[0]);
1900 }
1901 }
1902
1903 return $result;
1904 }
1905
1914 public function getValueFrom($table, $id, $field)
1915 {
1916 $result = false;
1917 if (!empty($id) && !empty($field) && !empty($table)) {
1918 $sql = "SELECT ".$field." FROM ".$this->db->prefix().$table;
1919 $sql .= " WHERE rowid = ".((int) $id);
1920
1921 dol_syslog(get_class($this).'::getValueFrom', LOG_DEBUG);
1922 $resql = $this->db->query($sql);
1923 if ($resql) {
1924 $row = $this->db->fetch_row($resql);
1925 $result = $row[0];
1926 }
1927 }
1928 return $result;
1929 }
1930
1947 public function setValueFrom($field, $value, $table = '', $id = null, $format = '', $id_field = '', $fuser = null, $trigkey = '', $fk_user_field = 'fk_user_modif')
1948 {
1949 global $user;
1950
1951 if (empty($table)) {
1952 $table = $this->table_element;
1953 }
1954 if (empty($id)) {
1955 $id = $this->id;
1956 }
1957 if (empty($format)) {
1958 $format = 'text';
1959 }
1960 if (empty($id_field)) {
1961 $id_field = 'rowid';
1962 }
1963
1964 // Special case
1965 if ($table == 'product' && $field == 'note_private') {
1966 $field = 'note';
1967 }
1968
1969 if (in_array($table, array('actioncomm', 'adherent', 'advtargetemailing', 'cronjob', 'establishment'))) {
1970 $fk_user_field = 'fk_user_mod';
1971 }
1972 if (in_array($table, array('prelevement_bons'))) { // TODO Add a field fk_user_modif into llx_prelevement_bons
1973 $fk_user_field = '';
1974 }
1975
1976 if ($trigkey) {
1977 $oldvalue = null;
1978
1979 $sql = "SELECT " . $field;
1980 $sql .= " FROM " . MAIN_DB_PREFIX . $table;
1981 $sql .= " WHERE " . $id_field . " = " . ((int) $id);
1982
1983 $resql = $this->db->query($sql);
1984 if ($resql) {
1985 if ($obj = $this->db->fetch_object($resql)) {
1986 if ($format == 'date') {
1987 $oldvalue = $this->db->jdate($obj->$field);
1988 } else {
1989 $oldvalue = $obj->$field;
1990 }
1991 }
1992 } else {
1993 $this->error = $this->db->lasterror();
1994 return -1;
1995 }
1996 }
1997
1998 $error = 0;
1999
2000 dol_syslog(__METHOD__, LOG_DEBUG);
2001
2002 $this->db->begin();
2003
2004 $sql = "UPDATE ".$this->db->prefix().$table." SET ";
2005
2006 if ($format == 'text') {
2007 $sql .= $field." = '".$this->db->escape($value)."'";
2008 } elseif ($format == 'int') {
2009 $sql .= $field." = ".((int) $value);
2010 } elseif ($format == 'date') {
2011 $sql .= $field." = ".($value ? "'".$this->db->idate($value)."'" : "null");
2012 } elseif ($format == 'dategmt') {
2013 $sql .= $field." = ".($value ? "'".$this->db->idate($value, 'gmt')."'" : "null");
2014 }
2015
2016 if ($fk_user_field) {
2017 if (!empty($fuser) && is_object($fuser)) {
2018 $sql .= ", ".$fk_user_field." = ".((int) $fuser->id);
2019 } elseif (empty($fuser) || $fuser != 'none') {
2020 $sql .= ", ".$fk_user_field." = ".((int) $user->id);
2021 }
2022 }
2023
2024 $sql .= " WHERE ".$id_field." = ".((int) $id);
2025
2026 $resql = $this->db->query($sql);
2027 if ($resql) {
2028 if ($trigkey) {
2029 // call trigger with updated object values
2030 if (method_exists($this, 'fetch')) {
2031 $result = $this->fetch($id);
2032 } else {
2033 $result = $this->fetchCommon($id);
2034 }
2035 $this->oldcopy = clone $this;
2036 if (property_exists($this->oldcopy, $field)) {
2037 $this->oldcopy->$field = $oldvalue;
2038 }
2039
2040 if ($result >= 0) {
2041 $result = $this->call_trigger($trigkey, (!empty($fuser) && is_object($fuser)) ? $fuser : $user); // This may set this->errors
2042 }
2043 if ($result < 0) {
2044 $error++;
2045 }
2046 }
2047
2048 if (!$error) {
2049 if (property_exists($this, $field)) {
2050 $this->$field = $value;
2051 }
2052 $this->db->commit();
2053 return 1;
2054 } else {
2055 $this->db->rollback();
2056 return -2;
2057 }
2058 } else {
2059 if ($this->db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
2060 $this->error = 'DB_ERROR_RECORD_ALREADY_EXISTS';
2061 } else {
2062 $this->error = $this->db->lasterror();
2063 }
2064 $this->db->rollback();
2065 return -1;
2066 }
2067 }
2068
2069 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2079 public function load_previous_next_ref($filter, $fieldid, $nodbprefix = 0)
2080 {
2081 // phpcs:enable
2082 global $conf, $user;
2083
2084 if (!$this->table_element) {
2085 dol_print_error('', get_class($this)."::load_previous_next_ref was called on objet with property table_element not defined");
2086 return -1;
2087 }
2088 if ($fieldid == 'none') {
2089 return 1;
2090 }
2091
2092 // For backward compatibility
2093 if (in_array($this->table_element, array('facture_rec', 'facture_fourn_rec')) && $fieldid == 'title') {
2094 $fieldid = 'titre';
2095 }
2096
2097 // Security on socid
2098 $socid = 0;
2099 if ($user->socid > 0) {
2100 $socid = $user->socid;
2101 }
2102
2103 // this->ismultientitymanaged contains
2104 // 0=No test on entity, 1=Test with field entity, 'field@table'=Test with link by field@table
2105 $aliastablesociete = 's';
2106 if ($this->element == 'societe') {
2107 $aliastablesociete = 'te'; // te as table_element
2108 }
2109 $restrictiononfksoc = empty($this->restrictiononfksoc) ? 0 : $this->restrictiononfksoc;
2110 $sql = "SELECT MAX(te.".$fieldid.")";
2111 $sql .= " FROM ".(empty($nodbprefix) ?$this->db->prefix():'').$this->table_element." as te";
2112 if ($this->element == 'user' && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
2113 if (empty($user->admin) || !empty($user->entity) || $conf->entity != 1) {
2114 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."usergroup_user as ug ON ug.fk_user = te.rowid";
2115 }
2116 }
2117 if (isset($this->ismultientitymanaged) && !is_numeric($this->ismultientitymanaged)) {
2118 $tmparray = explode('@', $this->ismultientitymanaged);
2119 $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
2120 } elseif ($restrictiononfksoc == 1 && $this->element != 'societe' && empty($user->rights->societe->client->voir) && !$socid) {
2121 $sql .= ", ".$this->db->prefix()."societe as s"; // If we need to link to societe to limit select to socid
2122 } elseif ($restrictiononfksoc == 2 && $this->element != 'societe' && empty($user->rights->societe->client->voir) && !$socid) {
2123 $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
2124 }
2125 if ($restrictiononfksoc && empty($user->rights->societe->client->voir) && !$socid) {
2126 $sql .= " LEFT JOIN ".$this->db->prefix()."societe_commerciaux as sc ON ".$aliastablesociete.".rowid = sc.fk_soc";
2127 }
2128 $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)
2129 if ($restrictiononfksoc == 1 && empty($user->rights->societe->client->voir) && !$socid) {
2130 $sql .= " AND sc.fk_user = ".((int) $user->id);
2131 }
2132 if ($restrictiononfksoc == 2 && empty($user->rights->societe->client->voir) && !$socid) {
2133 $sql .= " AND (sc.fk_user = ".((int) $user->id).' OR te.fk_soc IS NULL)';
2134 }
2135 if (!empty($filter)) {
2136 if (!preg_match('/^\s*AND/i', $filter)) {
2137 $sql .= " AND ";
2138 }
2139 $sql .= $filter;
2140 }
2141 if (isset($this->ismultientitymanaged) && !is_numeric($this->ismultientitymanaged)) {
2142 $tmparray = explode('@', $this->ismultientitymanaged);
2143 $sql .= " AND te.".$tmparray[0]." = ".($tmparray[1] == "societe" ? "s" : "parenttable").".rowid"; // If we need to link to this table to limit select to entity
2144 } elseif ($restrictiononfksoc == 1 && $this->element != 'societe' && empty($user->rights->societe->client->voir) && !$socid) {
2145 $sql .= ' AND te.fk_soc = s.rowid'; // If we need to link to societe to limit select to socid
2146 }
2147 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
2148 if ($this->element == 'user' && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
2149 if (!empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
2150 $sql .= " AND te.entity IS NOT NULL"; // Show all users
2151 } else {
2152 $sql .= " AND ug.entity IN (".getEntity('usergroup').")";
2153 }
2154 } else {
2155 $sql .= ' AND te.entity IN ('.getEntity($this->element).')';
2156 }
2157 }
2158 if (isset($this->ismultientitymanaged) && !is_numeric($this->ismultientitymanaged) && $this->element != 'societe') {
2159 $tmparray = explode('@', $this->ismultientitymanaged);
2160 $sql .= ' AND parenttable.entity IN ('.getEntity($tmparray[1]).')';
2161 }
2162 if ($restrictiononfksoc == 1 && $socid && $this->element != 'societe') {
2163 $sql .= ' AND te.fk_soc = '.((int) $socid);
2164 }
2165 if ($restrictiononfksoc == 2 && $socid && $this->element != 'societe') {
2166 $sql .= ' AND (te.fk_soc = '.((int) $socid).' OR te.fk_soc IS NULL)';
2167 }
2168 if ($restrictiononfksoc && $socid && $this->element == 'societe') {
2169 $sql .= ' AND te.rowid = '.((int) $socid);
2170 }
2171 //print 'socid='.$socid.' restrictiononfksoc='.$restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."<br>";
2172
2173 $result = $this->db->query($sql);
2174 if (!$result) {
2175 $this->error = $this->db->lasterror();
2176 return -1;
2177 }
2178 $row = $this->db->fetch_row($result);
2179 $this->ref_previous = $row[0];
2180
2181 $sql = "SELECT MIN(te.".$fieldid.")";
2182 $sql .= " FROM ".(empty($nodbprefix) ?$this->db->prefix():'').$this->table_element." as te";
2183 if ($this->element == 'user' && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
2184 if (empty($user->admin) || !empty($user->entity) || $conf->entity != 1) {
2185 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."usergroup_user as ug ON ug.fk_user = te.rowid";
2186 }
2187 }
2188 if (isset($this->ismultientitymanaged) && !is_numeric($this->ismultientitymanaged)) {
2189 $tmparray = explode('@', $this->ismultientitymanaged);
2190 $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
2191 } elseif ($restrictiononfksoc == 1 && $this->element != 'societe' && empty($user->rights->societe->client->voir) && !$socid) {
2192 $sql .= ", ".$this->db->prefix()."societe as s"; // If we need to link to societe to limit select to socid
2193 } elseif ($restrictiononfksoc == 2 && $this->element != 'societe' && empty($user->rights->societe->client->voir) && !$socid) {
2194 $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
2195 }
2196 if ($restrictiononfksoc && empty($user->rights->societe->client->voir) && !$socid) {
2197 $sql .= " LEFT JOIN ".$this->db->prefix()."societe_commerciaux as sc ON ".$aliastablesociete.".rowid = sc.fk_soc";
2198 }
2199 $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)
2200 if ($restrictiononfksoc == 1 && empty($user->rights->societe->client->voir) && !$socid) {
2201 $sql .= " AND sc.fk_user = ".((int) $user->id);
2202 }
2203 if ($restrictiononfksoc == 2 && empty($user->rights->societe->client->voir) && !$socid) {
2204 $sql .= " AND (sc.fk_user = ".((int) $user->id).' OR te.fk_soc IS NULL)';
2205 }
2206 if (!empty($filter)) {
2207 if (!preg_match('/^\s*AND/i', $filter)) {
2208 $sql .= " AND "; // For backward compatibility
2209 }
2210 $sql .= $filter;
2211 }
2212 if (isset($this->ismultientitymanaged) && !is_numeric($this->ismultientitymanaged)) {
2213 $tmparray = explode('@', $this->ismultientitymanaged);
2214 $sql .= " AND te.".$tmparray[0]." = ".($tmparray[1] == "societe" ? "s" : "parenttable").".rowid"; // If we need to link to this table to limit select to entity
2215 } elseif ($restrictiononfksoc == 1 && $this->element != 'societe' && empty($user->rights->societe->client->voir) && !$socid) {
2216 $sql .= ' AND te.fk_soc = s.rowid'; // If we need to link to societe to limit select to socid
2217 }
2218 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
2219 if ($this->element == 'user' && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
2220 if (!empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
2221 $sql .= " AND te.entity IS NOT NULL"; // Show all users
2222 } else {
2223 $sql .= " AND ug.entity IN (".getEntity('usergroup').")";
2224 }
2225 } else {
2226 $sql .= ' AND te.entity IN ('.getEntity($this->element).')';
2227 }
2228 }
2229 if (isset($this->ismultientitymanaged) && !is_numeric($this->ismultientitymanaged) && $this->element != 'societe') {
2230 $tmparray = explode('@', $this->ismultientitymanaged);
2231 $sql .= ' AND parenttable.entity IN ('.getEntity($tmparray[1]).')';
2232 }
2233 if ($restrictiononfksoc == 1 && $socid && $this->element != 'societe') {
2234 $sql .= ' AND te.fk_soc = '.((int) $socid);
2235 }
2236 if ($restrictiononfksoc == 2 && $socid && $this->element != 'societe') {
2237 $sql .= ' AND (te.fk_soc = '.((int) $socid).' OR te.fk_soc IS NULL)';
2238 }
2239 if ($restrictiononfksoc && $socid && $this->element == 'societe') {
2240 $sql .= ' AND te.rowid = '.((int) $socid);
2241 }
2242 //print 'socid='.$socid.' restrictiononfksoc='.$restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."<br>";
2243 // 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
2244
2245 $result = $this->db->query($sql);
2246 if (!$result) {
2247 $this->error = $this->db->lasterror();
2248 return -2;
2249 }
2250 $row = $this->db->fetch_row($result);
2251 $this->ref_next = $row[0];
2252
2253 return 1;
2254 }
2255
2256
2264 public function getListContactId($source = 'external')
2265 {
2266 $contactAlreadySelected = array();
2267 $tab = $this->liste_contact(-1, $source);
2268 $num = count($tab);
2269 $i = 0;
2270 while ($i < $num) {
2271 if ($source == 'thirdparty') {
2272 $contactAlreadySelected[$i] = $tab[$i]['socid'];
2273 } else {
2274 $contactAlreadySelected[$i] = $tab[$i]['id'];
2275 }
2276 $i++;
2277 }
2278 return $contactAlreadySelected;
2279 }
2280
2281
2289 public function setProject($projectid, $notrigger = 0)
2290 {
2291 global $user;
2292 $error = 0;
2293
2294 if (!$this->table_element) {
2295 dol_syslog(get_class($this)."::setProject was called on objet with property table_element not defined", LOG_ERR);
2296 return -1;
2297 }
2298
2299 $sql = "UPDATE ".$this->db->prefix().$this->table_element;
2300 if (!empty($this->fields['fk_project'])) { // Common case
2301 if ($projectid) {
2302 $sql .= " SET fk_project = ".((int) $projectid);
2303 } else {
2304 $sql .= " SET fk_project = NULL";
2305 }
2306 $sql .= ' WHERE rowid = '.((int) $this->id);
2307 } elseif ($this->table_element == 'actioncomm') { // Special case for actioncomm
2308 if ($projectid) {
2309 $sql .= " SET fk_project = ".((int) $projectid);
2310 } else {
2311 $sql .= " SET fk_project = NULL";
2312 }
2313 $sql .= ' WHERE id = '.((int) $this->id);
2314 } else // Special case for old architecture objects
2315 {
2316 if ($projectid) {
2317 $sql .= ' SET fk_projet = '.((int) $projectid);
2318 } else {
2319 $sql .= ' SET fk_projet = NULL';
2320 }
2321 $sql .= " WHERE rowid = ".((int) $this->id);
2322 }
2323
2324 $this->db->begin();
2325
2326 dol_syslog(get_class($this)."::setProject", LOG_DEBUG);
2327 if ($this->db->query($sql)) {
2328 $this->fk_project = ((int) $projectid);
2329 } else {
2330 dol_print_error($this->db);
2331 $error++;
2332 }
2333
2334 // Triggers
2335 if (!$error && !$notrigger) {
2336 // Call triggers
2337 $result = $this->call_trigger(strtoupper($this->element) . '_MODIFY', $user);
2338 if ($result < 0) {
2339 $error++;
2340 } //Do also here what you must do to rollback action if trigger fail
2341 // End call triggers
2342 }
2343
2344 // Commit or rollback
2345 if ($error) {
2346 $this->db->rollback();
2347 return -1;
2348 } else {
2349 $this->db->commit();
2350 return 1;
2351 }
2352 }
2353
2360 public function setPaymentMethods($id)
2361 {
2362 global $user;
2363
2364 $error = 0; $notrigger = 0;
2365
2366 dol_syslog(get_class($this).'::setPaymentMethods('.$id.')');
2367
2368 if ($this->statut >= 0 || $this->element == 'societe') {
2369 // TODO uniformize field name
2370 $fieldname = 'fk_mode_reglement';
2371 if ($this->element == 'societe') {
2372 $fieldname = 'mode_reglement';
2373 }
2374 if (get_class($this) == 'Fournisseur') {
2375 $fieldname = 'mode_reglement_supplier';
2376 }
2377 if (get_class($this) == 'Tva') {
2378 $fieldname = 'fk_typepayment';
2379 }
2380 if (get_class($this) == 'Salary') {
2381 $fieldname = 'fk_typepayment';
2382 }
2383
2384 $sql = "UPDATE ".$this->db->prefix().$this->table_element;
2385 $sql .= " SET ".$fieldname." = ".(($id > 0 || $id == '0') ? ((int) $id) : 'NULL');
2386 $sql .= ' WHERE rowid='.((int) $this->id);
2387
2388 if ($this->db->query($sql)) {
2389 $this->mode_reglement_id = $id;
2390 // for supplier
2391 if (get_class($this) == 'Fournisseur') {
2392 $this->mode_reglement_supplier_id = $id;
2393 }
2394 // Triggers
2395 if (!$error && !$notrigger) {
2396 // Call triggers
2397 if (get_class($this) == 'Commande') {
2398 $result = $this->call_trigger('ORDER_MODIFY', $user);
2399 } else {
2400 $result = $this->call_trigger(strtoupper(get_class($this)).'_MODIFY', $user);
2401 }
2402 if ($result < 0) {
2403 $error++;
2404 }
2405 // End call triggers
2406 }
2407 return 1;
2408 } else {
2409 dol_syslog(get_class($this).'::setPaymentMethods Error '.$this->db->error());
2410 $this->error = $this->db->error();
2411 return -1;
2412 }
2413 } else {
2414 dol_syslog(get_class($this).'::setPaymentMethods, status of the object is incompatible');
2415 $this->error = 'Status of the object is incompatible '.$this->statut;
2416 return -2;
2417 }
2418 }
2419
2426 public function setMulticurrencyCode($code)
2427 {
2428 dol_syslog(get_class($this).'::setMulticurrencyCode('.$code.')');
2429 if ($this->statut >= 0 || $this->element == 'societe') {
2430 $fieldname = 'multicurrency_code';
2431
2432 $sql = 'UPDATE '.$this->db->prefix().$this->table_element;
2433 $sql .= " SET ".$fieldname." = '".$this->db->escape($code)."'";
2434 $sql .= ' WHERE rowid='.((int) $this->id);
2435
2436 if ($this->db->query($sql)) {
2437 $this->multicurrency_code = $code;
2438
2439 list($fk_multicurrency, $rate) = MultiCurrency::getIdAndTxFromCode($this->db, $code);
2440 if ($rate) {
2441 $this->setMulticurrencyRate($rate, 2);
2442 }
2443
2444 return 1;
2445 } else {
2446 dol_syslog(get_class($this).'::setMulticurrencyCode Error '.$sql.' - '.$this->db->error());
2447 $this->error = $this->db->error();
2448 return -1;
2449 }
2450 } else {
2451 dol_syslog(get_class($this).'::setMulticurrencyCode, status of the object is incompatible');
2452 $this->error = 'Status of the object is incompatible '.$this->statut;
2453 return -2;
2454 }
2455 }
2456
2464 public function setMulticurrencyRate($rate, $mode = 1)
2465 {
2466 dol_syslog(get_class($this).'::setMulticurrencyRate('.$rate.','.$mode.')');
2467 if ($this->statut >= 0 || $this->element == 'societe') {
2468 $fieldname = 'multicurrency_tx';
2469
2470 $sql = 'UPDATE '.$this->db->prefix().$this->table_element;
2471 $sql .= " SET ".$fieldname." = ".((float) $rate);
2472 $sql .= ' WHERE rowid='.((int) $this->id);
2473
2474 if ($this->db->query($sql)) {
2475 $this->multicurrency_tx = $rate;
2476
2477 // Update line price
2478 if (!empty($this->lines)) {
2479 foreach ($this->lines as &$line) {
2480 // Amounts in company currency will be recalculated
2481 if ($mode == 1) {
2482 $line->subprice = 0;
2483 }
2484
2485 // Amounts in foreign currency will be recalculated
2486 if ($mode == 2) {
2487 $line->multicurrency_subprice = 0;
2488 }
2489
2490 switch ($this->element) {
2491 case 'propal':
2494 $this->updateline(
2495 $line->id,
2496 $line->subprice,
2497 $line->qty,
2498 $line->remise_percent,
2499 $line->tva_tx,
2500 $line->localtax1_tx,
2501 $line->localtax2_tx,
2502 ($line->description ? $line->description : $line->desc),
2503 'HT',
2504 $line->info_bits,
2505 $line->special_code,
2506 $line->fk_parent_line,
2507 $line->skip_update_total,
2508 $line->fk_fournprice,
2509 $line->pa_ht,
2510 $line->label,
2511 $line->product_type,
2512 $line->date_start,
2513 $line->date_end,
2514 $line->array_options,
2515 $line->fk_unit,
2516 $line->multicurrency_subprice
2517 );
2518 break;
2519 case 'commande':
2522 $this->updateline(
2523 $line->id,
2524 ($line->description ? $line->description : $line->desc),
2525 $line->subprice,
2526 $line->qty,
2527 $line->remise_percent,
2528 $line->tva_tx,
2529 $line->localtax1_tx,
2530 $line->localtax2_tx,
2531 'HT',
2532 $line->info_bits,
2533 $line->date_start,
2534 $line->date_end,
2535 $line->product_type,
2536 $line->fk_parent_line,
2537 $line->skip_update_total,
2538 $line->fk_fournprice,
2539 $line->pa_ht,
2540 $line->label,
2541 $line->special_code,
2542 $line->array_options,
2543 $line->fk_unit,
2544 $line->multicurrency_subprice
2545 );
2546 break;
2547 case 'facture':
2550 $this->updateline(
2551 $line->id,
2552 ($line->description ? $line->description : $line->desc),
2553 $line->subprice,
2554 $line->qty,
2555 $line->remise_percent,
2556 $line->date_start,
2557 $line->date_end,
2558 $line->tva_tx,
2559 $line->localtax1_tx,
2560 $line->localtax2_tx,
2561 'HT',
2562 $line->info_bits,
2563 $line->product_type,
2564 $line->fk_parent_line,
2565 $line->skip_update_total,
2566 $line->fk_fournprice,
2567 $line->pa_ht,
2568 $line->label,
2569 $line->special_code,
2570 $line->array_options,
2571 $line->situation_percent,
2572 $line->fk_unit,
2573 $line->multicurrency_subprice
2574 );
2575 break;
2576 case 'supplier_proposal':
2579 $this->updateline(
2580 $line->id,
2581 $line->subprice,
2582 $line->qty,
2583 $line->remise_percent,
2584 $line->tva_tx,
2585 $line->localtax1_tx,
2586 $line->localtax2_tx,
2587 ($line->description ? $line->description : $line->desc),
2588 'HT',
2589 $line->info_bits,
2590 $line->special_code,
2591 $line->fk_parent_line,
2592 $line->skip_update_total,
2593 $line->fk_fournprice,
2594 $line->pa_ht,
2595 $line->label,
2596 $line->product_type,
2597 $line->array_options,
2598 $line->ref_fourn,
2599 $line->multicurrency_subprice
2600 );
2601 break;
2602 case 'order_supplier':
2605 $this->updateline(
2606 $line->id,
2607 ($line->description ? $line->description : $line->desc),
2608 $line->subprice,
2609 $line->qty,
2610 $line->remise_percent,
2611 $line->tva_tx,
2612 $line->localtax1_tx,
2613 $line->localtax2_tx,
2614 'HT',
2615 $line->info_bits,
2616 $line->product_type,
2617 false,
2618 $line->date_start,
2619 $line->date_end,
2620 $line->array_options,
2621 $line->fk_unit,
2622 $line->multicurrency_subprice,
2623 $line->ref_supplier
2624 );
2625 break;
2626 case 'invoice_supplier':
2629 $this->updateline(
2630 $line->id,
2631 ($line->description ? $line->description : $line->desc),
2632 $line->subprice,
2633 $line->tva_tx,
2634 $line->localtax1_tx,
2635 $line->localtax2_tx,
2636 $line->qty,
2637 0,
2638 'HT',
2639 $line->info_bits,
2640 $line->product_type,
2641 $line->remise_percent,
2642 false,
2643 $line->date_start,
2644 $line->date_end,
2645 $line->array_options,
2646 $line->fk_unit,
2647 $line->multicurrency_subprice,
2648 $line->ref_supplier
2649 );
2650 break;
2651 default:
2652 dol_syslog(get_class($this).'::setMulticurrencyRate no updateline defined', LOG_DEBUG);
2653 break;
2654 }
2655 }
2656 }
2657
2658 return 1;
2659 } else {
2660 dol_syslog(get_class($this).'::setMulticurrencyRate Error '.$sql.' - '.$this->db->error());
2661 $this->error = $this->db->error();
2662 return -1;
2663 }
2664 } else {
2665 dol_syslog(get_class($this).'::setMulticurrencyRate, status of the object is incompatible');
2666 $this->error = 'Status of the object is incompatible '.$this->statut;
2667 return -2;
2668 }
2669 }
2670
2678 public function setPaymentTerms($id, $deposit_percent = null)
2679 {
2680 dol_syslog(get_class($this).'::setPaymentTerms('.$id.', '.var_export($deposit_percent, true).')');
2681 if ($this->statut >= 0 || $this->element == 'societe') {
2682 // TODO uniformize field name
2683 $fieldname = 'fk_cond_reglement';
2684 if ($this->element == 'societe') {
2685 $fieldname = 'cond_reglement';
2686 }
2687 if (get_class($this) == 'Fournisseur') {
2688 $fieldname = 'cond_reglement_supplier';
2689 }
2690
2691 if (empty($deposit_percent) || $deposit_percent < 0) {
2692 $deposit_percent = getDictionaryValue('c_payment_term', 'deposit_percent', $id);
2693 }
2694
2695 if ($deposit_percent > 100) {
2696 $deposit_percent = 100;
2697 }
2698
2699 $sql = 'UPDATE '.$this->db->prefix().$this->table_element;
2700 $sql .= " SET ".$fieldname." = ".(($id > 0 || $id == '0') ? ((int) $id) : 'NULL');
2701 if (in_array($this->table_element, array('propal', 'commande', 'societe'))) {
2702 $sql .= " , deposit_percent = " . (empty($deposit_percent) ? 'NULL' : "'".$this->db->escape($deposit_percent)."'");
2703 }
2704 $sql .= ' WHERE rowid='.((int) $this->id);
2705
2706 if ($this->db->query($sql)) {
2707 $this->cond_reglement_id = $id;
2708 // for supplier
2709 if (get_class($this) == 'Fournisseur') {
2710 $this->cond_reglement_supplier_id = $id;
2711 }
2712 $this->cond_reglement = $id; // for compatibility
2713 $this->deposit_percent = $deposit_percent;
2714 return 1;
2715 } else {
2716 dol_syslog(get_class($this).'::setPaymentTerms Error '.$sql.' - '.$this->db->error());
2717 $this->error = $this->db->error();
2718 return -1;
2719 }
2720 } else {
2721 dol_syslog(get_class($this).'::setPaymentTerms, status of the object is incompatible');
2722 $this->error = 'Status of the object is incompatible '.$this->statut;
2723 return -2;
2724 }
2725 }
2726
2733 public function setTransportMode($id)
2734 {
2735 dol_syslog(get_class($this).'::setTransportMode('.$id.')');
2736 if ($this->statut >= 0 || $this->element == 'societe') {
2737 $fieldname = 'fk_transport_mode';
2738 if ($this->element == 'societe') {
2739 $fieldname = 'transport_mode';
2740 }
2741 if (get_class($this) == 'Fournisseur') {
2742 $fieldname = 'transport_mode_supplier';
2743 }
2744
2745 $sql = 'UPDATE '.$this->db->prefix().$this->table_element;
2746 $sql .= " SET ".$fieldname." = ".(($id > 0 || $id == '0') ? ((int) $id) : 'NULL');
2747 $sql .= ' WHERE rowid='.((int) $this->id);
2748
2749 if ($this->db->query($sql)) {
2750 $this->transport_mode_id = $id;
2751 // for supplier
2752 if (get_class($this) == 'Fournisseur') {
2753 $this->transport_mode_supplier_id = $id;
2754 }
2755 return 1;
2756 } else {
2757 dol_syslog(get_class($this).'::setTransportMode Error '.$sql.' - '.$this->db->error());
2758 $this->error = $this->db->error();
2759 return -1;
2760 }
2761 } else {
2762 dol_syslog(get_class($this).'::setTransportMode, status of the object is incompatible');
2763 $this->error = 'Status of the object is incompatible '.$this->statut;
2764 return -2;
2765 }
2766 }
2767
2775 {
2776 dol_syslog(get_class($this).'::setRetainedWarrantyPaymentTerms('.$id.')');
2777 if ($this->statut >= 0 || $this->element == 'societe') {
2778 $fieldname = 'retained_warranty_fk_cond_reglement';
2779
2780 $sql = 'UPDATE '.$this->db->prefix().$this->table_element;
2781 $sql .= " SET ".$fieldname." = ".((int) $id);
2782 $sql .= ' WHERE rowid='.((int) $this->id);
2783
2784 if ($this->db->query($sql)) {
2785 $this->retained_warranty_fk_cond_reglement = $id;
2786 return 1;
2787 } else {
2788 dol_syslog(get_class($this).'::setRetainedWarrantyPaymentTerms Error '.$sql.' - '.$this->db->error());
2789 $this->error = $this->db->error();
2790 return -1;
2791 }
2792 } else {
2793 dol_syslog(get_class($this).'::setRetainedWarrantyPaymentTerms, status of the object is incompatible');
2794 $this->error = 'Status of the object is incompatible '.$this->statut;
2795 return -2;
2796 }
2797 }
2798
2806 public function setDeliveryAddress($id)
2807 {
2808 $fieldname = 'fk_delivery_address';
2809 if ($this->element == 'delivery' || $this->element == 'shipping') {
2810 $fieldname = 'fk_address';
2811 }
2812
2813 $sql = "UPDATE ".$this->db->prefix().$this->table_element." SET ".$fieldname." = ".((int) $id);
2814 $sql .= " WHERE rowid = ".((int) $this->id)." AND fk_statut = 0";
2815
2816 if ($this->db->query($sql)) {
2817 $this->fk_delivery_address = $id;
2818 return 1;
2819 } else {
2820 $this->error = $this->db->error();
2821 dol_syslog(get_class($this).'::setDeliveryAddress Error '.$this->error);
2822 return -1;
2823 }
2824 }
2825
2826
2836 public function setShippingMethod($shipping_method_id, $notrigger = false, $userused = null)
2837 {
2838 global $user;
2839
2840 if (empty($userused)) {
2841 $userused = $user;
2842 }
2843
2844 $error = 0;
2845
2846 if (!$this->table_element) {
2847 dol_syslog(get_class($this)."::setShippingMethod was called on objet with property table_element not defined", LOG_ERR);
2848 return -1;
2849 }
2850
2851 $this->db->begin();
2852
2853 if ($shipping_method_id < 0) {
2854 $shipping_method_id = 'NULL';
2855 }
2856 dol_syslog(get_class($this).'::setShippingMethod('.$shipping_method_id.')');
2857
2858 $sql = "UPDATE ".$this->db->prefix().$this->table_element;
2859 $sql .= " SET fk_shipping_method = ".((int) $shipping_method_id);
2860 $sql .= " WHERE rowid=".((int) $this->id);
2861 $resql = $this->db->query($sql);
2862 if (!$resql) {
2863 dol_syslog(get_class($this).'::setShippingMethod Error ', LOG_DEBUG);
2864 $this->error = $this->db->lasterror();
2865 $error++;
2866 } else {
2867 if (!$notrigger) {
2868 // Call trigger
2869 $this->context = array('shippingmethodupdate'=>1);
2870 $result = $this->call_trigger(strtoupper(get_class($this)).'_MODIFY', $userused);
2871 if ($result < 0) {
2872 $error++;
2873 }
2874 // End call trigger
2875 }
2876 }
2877 if ($error) {
2878 $this->db->rollback();
2879 return -1;
2880 } else {
2881 $this->shipping_method_id = ($shipping_method_id == 'NULL') ?null:$shipping_method_id;
2882 $this->db->commit();
2883 return 1;
2884 }
2885 }
2886
2887
2894 public function setWarehouse($warehouse_id)
2895 {
2896 if (!$this->table_element) {
2897 dol_syslog(get_class($this)."::setWarehouse was called on objet with property table_element not defined", LOG_ERR);
2898 return -1;
2899 }
2900 if ($warehouse_id < 0) {
2901 $warehouse_id = 'NULL';
2902 }
2903 dol_syslog(get_class($this).'::setWarehouse('.$warehouse_id.')');
2904
2905 $sql = "UPDATE ".$this->db->prefix().$this->table_element;
2906 $sql .= " SET fk_warehouse = ".((int) $warehouse_id);
2907 $sql .= " WHERE rowid=".((int) $this->id);
2908
2909 if ($this->db->query($sql)) {
2910 $this->warehouse_id = ($warehouse_id == 'NULL') ?null:$warehouse_id;
2911 return 1;
2912 } else {
2913 dol_syslog(get_class($this).'::setWarehouse Error ', LOG_DEBUG);
2914 $this->error = $this->db->error();
2915 return 0;
2916 }
2917 }
2918
2919
2927 public function setDocModel($user, $modelpdf)
2928 {
2929 if (!$this->table_element) {
2930 dol_syslog(get_class($this)."::setDocModel was called on objet with property table_element not defined", LOG_ERR);
2931 return -1;
2932 }
2933
2934 $newmodelpdf = dol_trunc($modelpdf, 255);
2935
2936 $sql = "UPDATE ".$this->db->prefix().$this->table_element;
2937 $sql .= " SET model_pdf = '".$this->db->escape($newmodelpdf)."'";
2938 $sql .= " WHERE rowid = ".((int) $this->id);
2939
2940 dol_syslog(get_class($this)."::setDocModel", LOG_DEBUG);
2941 $resql = $this->db->query($sql);
2942 if ($resql) {
2943 $this->model_pdf = $modelpdf;
2944 $this->modelpdf = $modelpdf; // For bakward compatibility
2945 return 1;
2946 } else {
2947 dol_print_error($this->db);
2948 return 0;
2949 }
2950 }
2951
2952
2961 public function setBankAccount($fk_account, $notrigger = false, $userused = null)
2962 {
2963 global $user;
2964
2965 if (empty($userused)) {
2966 $userused = $user;
2967 }
2968
2969 $error = 0;
2970
2971 if (!$this->table_element) {
2972 dol_syslog(get_class($this)."::setBankAccount was called on objet with property table_element not defined", LOG_ERR);
2973 return -1;
2974 }
2975 $this->db->begin();
2976
2977 if ($fk_account < 0) {
2978 $fk_account = 'NULL';
2979 }
2980 dol_syslog(get_class($this).'::setBankAccount('.$fk_account.')');
2981
2982 $sql = "UPDATE ".$this->db->prefix().$this->table_element;
2983 $sql .= " SET fk_account = ".((int) $fk_account);
2984 $sql .= " WHERE rowid=".((int) $this->id);
2985
2986 $resql = $this->db->query($sql);
2987 if (!$resql) {
2988 dol_syslog(get_class($this).'::setBankAccount Error '.$sql.' - '.$this->db->error());
2989 $this->error = $this->db->lasterror();
2990 $error++;
2991 } else {
2992 if (!$notrigger) {
2993 // Call trigger
2994 $this->context = array('bankaccountupdate'=>1);
2995 $result = $this->call_trigger(strtoupper(get_class($this)).'_MODIFY', $userused);
2996 if ($result < 0) {
2997 $error++;
2998 }
2999 // End call trigger
3000 }
3001 }
3002 if ($error) {
3003 $this->db->rollback();
3004 return -1;
3005 } else {
3006 $this->fk_account = ($fk_account == 'NULL') ?null:$fk_account;
3007 $this->db->commit();
3008 return 1;
3009 }
3010 }
3011
3012
3013 // TODO: Move line related operations to CommonObjectLine?
3014
3015 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3025 public function line_order($renum = false, $rowidorder = 'ASC', $fk_parent_line = true)
3026 {
3027 // phpcs:enable
3028 if (!$this->table_element_line) {
3029 dol_syslog(get_class($this)."::line_order was called on objet with property table_element_line not defined", LOG_ERR);
3030 return -1;
3031 }
3032 if (!$this->fk_element) {
3033 dol_syslog(get_class($this)."::line_order was called on objet with property fk_element not defined", LOG_ERR);
3034 return -1;
3035 }
3036
3037 $fieldposition = 'rang'; // @todo Rename 'rang' into 'position'
3038 if (in_array($this->table_element_line, array('bom_bomline', 'ecm_files', 'emailcollector_emailcollectoraction', 'product_attribute_value'))) {
3039 $fieldposition = 'position';
3040 }
3041
3042 // Count number of lines to reorder (according to choice $renum)
3043 $nl = 0;
3044 $sql = "SELECT count(rowid) FROM ".$this->db->prefix().$this->table_element_line;
3045 $sql .= " WHERE ".$this->fk_element." = ".((int) $this->id);
3046 if (!$renum) {
3047 $sql .= " AND " . $fieldposition . " = 0";
3048 }
3049 if ($renum) {
3050 $sql .= " AND " . $fieldposition . " <> 0";
3051 }
3052
3053 dol_syslog(get_class($this)."::line_order", LOG_DEBUG);
3054 $resql = $this->db->query($sql);
3055 if ($resql) {
3056 $row = $this->db->fetch_row($resql);
3057 $nl = $row[0];
3058 } else {
3059 dol_print_error($this->db);
3060 }
3061 if ($nl > 0) {
3062 // The goal of this part is to reorder all lines, with all children lines sharing the same counter that parents.
3063 $rows = array();
3064
3065 // We first search all lines that are parent lines (for multilevel details lines)
3066 $sql = "SELECT rowid FROM ".$this->db->prefix().$this->table_element_line;
3067 $sql .= " WHERE ".$this->fk_element." = ".((int) $this->id);
3068 if ($fk_parent_line) {
3069 $sql .= ' AND fk_parent_line IS NULL';
3070 }
3071 $sql .= " ORDER BY " . $fieldposition . " ASC, rowid " . $rowidorder;
3072
3073 dol_syslog(get_class($this)."::line_order search all parent lines", LOG_DEBUG);
3074 $resql = $this->db->query($sql);
3075 if ($resql) {
3076 $i = 0;
3077 $num = $this->db->num_rows($resql);
3078 while ($i < $num) {
3079 $row = $this->db->fetch_row($resql);
3080 $rows[] = $row[0]; // Add parent line into array rows
3081 $childrens = $this->getChildrenOfLine($row[0]);
3082 if (!empty($childrens)) {
3083 foreach ($childrens as $child) {
3084 array_push($rows, $child);
3085 }
3086 }
3087 $i++;
3088 }
3089
3090 // Now we set a new number for each lines (parent and children with children included into parent tree)
3091 if (!empty($rows)) {
3092 foreach ($rows as $key => $row) {
3093 $this->updateRangOfLine($row, ($key + 1));
3094 }
3095 }
3096 } else {
3097 dol_print_error($this->db);
3098 }
3099 }
3100 return 1;
3101 }
3102
3110 public function getChildrenOfLine($id, $includealltree = 0)
3111 {
3112 $fieldposition = 'rang'; // @todo Rename 'rang' into 'position'
3113 if (in_array($this->table_element_line, array('bom_bomline', 'ecm_files', 'emailcollector_emailcollectoraction', 'product_attribute_value'))) {
3114 $fieldposition = 'position';
3115 }
3116
3117 $rows = array();
3118
3119 $sql = "SELECT rowid FROM ".$this->db->prefix().$this->table_element_line;
3120 $sql .= " WHERE ".$this->fk_element." = ".((int) $this->id);
3121 $sql .= ' AND fk_parent_line = '.((int) $id);
3122 $sql .= " ORDER BY " . $fieldposition . " ASC";
3123
3124 dol_syslog(get_class($this)."::getChildrenOfLine search children lines for line ".$id, LOG_DEBUG);
3125 $resql = $this->db->query($sql);
3126 if ($resql) {
3127 if ($this->db->num_rows($resql) > 0) {
3128 while ($row = $this->db->fetch_row($resql)) {
3129 $rows[] = $row[0];
3130 if (!empty($includealltree)) {
3131 $rows = array_merge($rows, $this->getChildrenOfLine($row[0], $includealltree));
3132 }
3133 }
3134 }
3135 }
3136 return $rows;
3137 }
3138
3139 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3147 public function line_up($rowid, $fk_parent_line = true)
3148 {
3149 // phpcs:enable
3150 $this->line_order(false, 'ASC', $fk_parent_line);
3151
3152 // Get rang of line
3153 $rang = $this->getRangOfLine($rowid);
3154
3155 // Update position of line
3156 $this->updateLineUp($rowid, $rang);
3157 }
3158
3159 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3167 public function line_down($rowid, $fk_parent_line = true)
3168 {
3169 // phpcs:enable
3170 $this->line_order(false, 'ASC', $fk_parent_line);
3171
3172 // Get rang of line
3173 $rang = $this->getRangOfLine($rowid);
3174
3175 // Get max value for rang
3176 $max = $this->line_max();
3177
3178 // Update position of line
3179 $this->updateLineDown($rowid, $rang, $max);
3180 }
3181
3189 public function updateRangOfLine($rowid, $rang)
3190 {
3191 global $hookmanager;
3192 $fieldposition = 'rang'; // @todo Rename 'rang' into 'position'
3193 if (in_array($this->table_element_line, array('bom_bomline', 'ecm_files', 'emailcollector_emailcollectoraction', 'product_attribute_value'))) {
3194 $fieldposition = 'position';
3195 }
3196
3197 $sql = "UPDATE ".$this->db->prefix().$this->table_element_line." SET ".$fieldposition." = ".((int) $rang);
3198 $sql .= ' WHERE rowid = '.((int) $rowid);
3199
3200 dol_syslog(get_class($this)."::updateRangOfLine", LOG_DEBUG);
3201 if (!$this->db->query($sql)) {
3202 dol_print_error($this->db);
3203 return -1;
3204 } else {
3205 $parameters=array('rowid'=>$rowid, 'rang'=>$rang, 'fieldposition' => $fieldposition);
3206 $action='';
3207 $reshook = $hookmanager->executeHooks('afterRankOfLineUpdate', $parameters, $this, $action);
3208 return 1;
3209 }
3210 }
3211
3212 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3219 public function line_ajaxorder($rows)
3220 {
3221 // phpcs:enable
3222 $num = count($rows);
3223 for ($i = 0; $i < $num; $i++) {
3224 $this->updateRangOfLine($rows[$i], ($i + 1));
3225 }
3226 }
3227
3235 public function updateLineUp($rowid, $rang)
3236 {
3237 if ($rang > 1) {
3238 $fieldposition = 'rang';
3239 if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction', 'product_attribute_value'))) {
3240 $fieldposition = 'position';
3241 }
3242
3243 $sql = "UPDATE ".$this->db->prefix().$this->table_element_line." SET ".$fieldposition." = ".((int) $rang);
3244 $sql .= " WHERE ".$this->fk_element." = ".((int) $this->id);
3245 $sql .= " AND " . $fieldposition . " = " . ((int) ($rang - 1));
3246 if ($this->db->query($sql)) {
3247 $sql = "UPDATE ".$this->db->prefix().$this->table_element_line." SET ".$fieldposition." = ".((int) ($rang - 1));
3248 $sql .= ' WHERE rowid = '.((int) $rowid);
3249 if (!$this->db->query($sql)) {
3250 dol_print_error($this->db);
3251 }
3252 } else {
3253 dol_print_error($this->db);
3254 }
3255 }
3256 }
3257
3266 public function updateLineDown($rowid, $rang, $max)
3267 {
3268 if ($rang < $max) {
3269 $fieldposition = 'rang';
3270 if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction', 'product_attribute_value'))) {
3271 $fieldposition = 'position';
3272 }
3273
3274 $sql = "UPDATE ".$this->db->prefix().$this->table_element_line." SET ".$fieldposition." = ".((int) $rang);
3275 $sql .= " WHERE ".$this->fk_element." = ".((int) $this->id);
3276 $sql .= " AND " . $fieldposition . " = " . ((int) ($rang + 1));
3277 if ($this->db->query($sql)) {
3278 $sql = "UPDATE ".$this->db->prefix().$this->table_element_line." SET ".$fieldposition." = ".((int) ($rang + 1));
3279 $sql .= ' WHERE rowid = '.((int) $rowid);
3280 if (!$this->db->query($sql)) {
3281 dol_print_error($this->db);
3282 }
3283 } else {
3284 dol_print_error($this->db);
3285 }
3286 }
3287 }
3288
3295 public function getRangOfLine($rowid)
3296 {
3297 $fieldposition = 'rang';
3298 if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction', 'product_attribute_value'))) {
3299 $fieldposition = 'position';
3300 }
3301
3302 $sql = "SELECT " . $fieldposition . " FROM ".$this->db->prefix().$this->table_element_line;
3303 $sql .= " WHERE rowid = ".((int) $rowid);
3304
3305 dol_syslog(get_class($this)."::getRangOfLine", LOG_DEBUG);
3306 $resql = $this->db->query($sql);
3307 if ($resql) {
3308 $row = $this->db->fetch_row($resql);
3309 return $row[0];
3310 }
3311
3312 return 0;
3313 }
3314
3321 public function getIdOfLine($rang)
3322 {
3323 $fieldposition = 'rang';
3324 if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction', 'product_attribute_value'))) {
3325 $fieldposition = 'position';
3326 }
3327
3328 $sql = "SELECT rowid FROM ".$this->db->prefix().$this->table_element_line;
3329 $sql .= " WHERE ".$this->fk_element." = ".((int) $this->id);
3330 $sql .= " AND " . $fieldposition . " = ".((int) $rang);
3331 $resql = $this->db->query($sql);
3332 if ($resql) {
3333 $row = $this->db->fetch_row($resql);
3334 return $row[0];
3335 }
3336
3337 return 0;
3338 }
3339
3340 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3347 public function line_max($fk_parent_line = 0)
3348 {
3349 // phpcs:enable
3350 $positionfield = 'rang';
3351 if (in_array($this->table_element, array('bom_bom', 'product_attribute'))) {
3352 $positionfield = 'position';
3353 }
3354
3355 // Search the last rang with fk_parent_line
3356 if ($fk_parent_line) {
3357 $sql = "SELECT max(".$positionfield.") FROM ".$this->db->prefix().$this->table_element_line;
3358 $sql .= " WHERE ".$this->fk_element." = ".((int) $this->id);
3359 $sql .= " AND fk_parent_line = ".((int) $fk_parent_line);
3360
3361 dol_syslog(get_class($this)."::line_max", LOG_DEBUG);
3362 $resql = $this->db->query($sql);
3363 if ($resql) {
3364 $row = $this->db->fetch_row($resql);
3365 if (!empty($row[0])) {
3366 return $row[0];
3367 } else {
3368 return $this->getRangOfLine($fk_parent_line);
3369 }
3370 }
3371 } else {
3372 // If not, search the last rang of element
3373 $sql = "SELECT max(".$positionfield.") FROM ".$this->db->prefix().$this->table_element_line;
3374 $sql .= " WHERE ".$this->fk_element." = ".((int) $this->id);
3375
3376 dol_syslog(get_class($this)."::line_max", LOG_DEBUG);
3377 $resql = $this->db->query($sql);
3378 if ($resql) {
3379 $row = $this->db->fetch_row($resql);
3380 return $row[0];
3381 }
3382 }
3383
3384 return 0;
3385 }
3386
3387 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3394 public function update_ref_ext($ref_ext)
3395 {
3396 // phpcs:enable
3397 if (!$this->table_element) {
3398 dol_syslog(get_class($this)."::update_ref_ext was called on objet with property table_element not defined", LOG_ERR);
3399 return -1;
3400 }
3401
3402 $sql = "UPDATE ".$this->db->prefix().$this->table_element;
3403 $sql .= " SET ref_ext = '".$this->db->escape($ref_ext)."'";
3404 $sql .= " WHERE ".(isset($this->table_rowid) ? $this->table_rowid : 'rowid')." = ".((int) $this->id);
3405
3406 dol_syslog(get_class($this)."::update_ref_ext", LOG_DEBUG);
3407 if ($this->db->query($sql)) {
3408 $this->ref_ext = $ref_ext;
3409 return 1;
3410 } else {
3411 $this->error = $this->db->error();
3412 return -1;
3413 }
3414 }
3415
3416 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3425 public function update_note($note, $suffix = '', $notrigger = 0)
3426 {
3427 // phpcs:enable
3428 global $user;
3429
3430 if (!$this->table_element) {
3431 $this->error = 'update_note was called on objet with property table_element not defined';
3432 dol_syslog(get_class($this)."::update_note was called on objet with property table_element not defined", LOG_ERR);
3433 return -1;
3434 }
3435 if (!in_array($suffix, array('', '_public', '_private'))) {
3436 $this->error = 'update_note Parameter suffix must be empty, \'_private\' or \'_public\'';
3437 dol_syslog(get_class($this)."::update_note Parameter suffix must be empty, '_private' or '_public'", LOG_ERR);
3438 return -2;
3439 }
3440
3441 $newsuffix = $suffix;
3442
3443 // Special cas
3444 if ($this->table_element == 'product' && $newsuffix == '_private') {
3445 $newsuffix = '';
3446 }
3447 if (in_array($this->table_element, array('actioncomm', 'adherent', 'advtargetemailing', 'cronjob', 'establishment'))) {
3448 $fieldusermod = "fk_user_mod";
3449 } elseif ($this->table_element == 'ecm_files') {
3450 $fieldusermod = "fk_user_m";
3451 } else {
3452 $fieldusermod = "fk_user_modif";
3453 }
3454 $sql = "UPDATE ".$this->db->prefix().$this->table_element;
3455 $sql .= " SET note".$newsuffix." = ".(!empty($note) ? ("'".$this->db->escape($note)."'") : "NULL");
3456 $sql .= ", ".$fieldusermod." = ".((int) $user->id);
3457 $sql .= " WHERE rowid = ".((int) $this->id);
3458
3459 dol_syslog(get_class($this)."::update_note", LOG_DEBUG);
3460 if ($this->db->query($sql)) {
3461 if ($suffix == '_public') {
3462 $this->note_public = $note;
3463 } elseif ($suffix == '_private') {
3464 $this->note_private = $note;
3465 } else {
3466 $this->note = $note; // deprecated
3467 $this->note_private = $note;
3468 }
3469 if (empty($notrigger)) {
3470 switch ($this->element) {
3471 case 'societe':
3472 $trigger_name = 'COMPANY_MODIFY';
3473 break;
3474 case 'commande':
3475 $trigger_name = 'ORDER_MODIFY';
3476 break;
3477 case 'facture':
3478 $trigger_name = 'BILL_MODIFY';
3479 break;
3480 case 'invoice_supplier':
3481 $trigger_name = 'BILL_SUPPLIER_MODIFY';
3482 break;
3483 case 'facturerec':
3484 $trigger_name = 'BILLREC_MODIFIY';
3485 break;
3486 case 'expensereport':
3487 $trigger_name = 'EXPENSE_REPORT_MODIFY';
3488 break;
3489 default:
3490 $trigger_name = strtoupper($this->element) . '_MODIFY';
3491 }
3492 $ret = $this->call_trigger($trigger_name, $user);
3493 if ($ret < 0) {
3494 return -1;
3495 }
3496 }
3497 return 1;
3498 } else {
3499 $this->error = $this->db->lasterror();
3500 return -1;
3501 }
3502 }
3503
3504 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3513 public function update_note_public($note)
3514 {
3515 // phpcs:enable
3516 return $this->update_note($note, '_public');
3517 }
3518
3519 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3530 public function update_price($exclspec = 0, $roundingadjust = 'none', $nodatabaseupdate = 0, $seller = null)
3531 {
3532 // phpcs:enable
3533 global $conf, $hookmanager, $action;
3534
3535 $parameters = array('exclspec' => $exclspec, 'roundingadjust' => $roundingadjust, 'nodatabaseupdate' => $nodatabaseupdate, 'seller' => $seller);
3536 $reshook = $hookmanager->executeHooks('updateTotalPrice', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3537 if ($reshook > 0) {
3538 return 1; // replacement code
3539 } elseif ($reshook < 0) {
3540 return -1; // failure
3541 } // reshook = 0 => execute normal code
3542
3543 // Some external module want no update price after a trigger because they have another method to calculate the total (ex: with an extrafield)
3544 $MODULE = "";
3545 if ($this->element == 'propal') {
3546 $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_PROPOSAL";
3547 } elseif ($this->element == 'commande' || $this->element == 'order') {
3548 $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_ORDER";
3549 } elseif ($this->element == 'facture' || $this->element == 'invoice') {
3550 $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_INVOICE";
3551 } elseif ($this->element == 'facture_fourn' || $this->element == 'supplier_invoice' || $this->element == 'invoice_supplier' || $this->element == 'invoice_supplier_rec') {
3552 $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_INVOICE";
3553 } elseif ($this->element == 'order_supplier' || $this->element == 'supplier_order') {
3554 $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_ORDER";
3555 } elseif ($this->element == 'supplier_proposal') {
3556 $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_PROPOSAL";
3557 }
3558
3559 if (!empty($MODULE)) {
3560 if (!empty($conf->global->$MODULE)) {
3561 $modsactivated = explode(',', $conf->global->$MODULE);
3562 foreach ($modsactivated as $mod) {
3563 if (isModEnabled($mod)) {
3564 return 1; // update was disabled by specific setup
3565 }
3566 }
3567 }
3568 }
3569
3570 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
3571
3572 $forcedroundingmode = $roundingadjust;
3573 if ($forcedroundingmode == 'auto' && isset($conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND)) {
3574 $forcedroundingmode = getDolGlobalString('MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND');
3575 } elseif ($forcedroundingmode == 'auto') {
3576 $forcedroundingmode = '0';
3577 }
3578
3579 $error = 0;
3580
3581 $multicurrency_tx = !empty($this->multicurrency_tx) ? $this->multicurrency_tx : 1;
3582
3583 // Define constants to find lines to sum (field name int the table_element_line not into table_element)
3584 $fieldtva = 'total_tva';
3585 $fieldlocaltax1 = 'total_localtax1';
3586 $fieldlocaltax2 = 'total_localtax2';
3587 $fieldup = 'subprice';
3588 if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') {
3589 $fieldtva = 'tva';
3590 $fieldup = 'pu_ht';
3591 }
3592 if ($this->element == 'invoice_supplier_rec') {
3593 $fieldup = 'pu_ht';
3594 }
3595 if ($this->element == 'expensereport') {
3596 $fieldup = 'value_unit';
3597 }
3598
3599 $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,";
3600 $sql .= ' tva_tx as vatrate, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, info_bits, product_type';
3601 if ($this->table_element_line == 'facturedet') {
3602 $sql .= ', situation_percent';
3603 }
3604 $sql .= ', multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
3605 $sql .= " FROM ".$this->db->prefix().$this->table_element_line;
3606 $sql .= " WHERE ".$this->fk_element." = ".((int) $this->id);
3607 if ($exclspec) {
3608 $product_field = 'product_type';
3609 if ($this->table_element_line == 'contratdet') {
3610 $product_field = ''; // contratdet table has no product_type field
3611 }
3612 if ($product_field) {
3613 $sql .= " AND ".$product_field." <> 9";
3614 }
3615 }
3616 $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
3617
3618 dol_syslog(get_class($this)."::update_price", LOG_DEBUG);
3619
3620 $resql = $this->db->query($sql);
3621 if ($resql) {
3622 $this->total_ht = 0;
3623 $this->total_tva = 0;
3624 $this->total_localtax1 = 0;
3625 $this->total_localtax2 = 0;
3626 $this->total_ttc = 0;
3627 $total_ht_by_vats = array();
3628 $total_tva_by_vats = array();
3629 $total_ttc_by_vats = array();
3630 $this->multicurrency_total_ht = 0;
3631 $this->multicurrency_total_tva = 0;
3632 $this->multicurrency_total_ttc = 0;
3633
3634 $this->db->begin();
3635
3636 $num = $this->db->num_rows($resql);
3637 $i = 0;
3638 while ($i < $num) {
3639 $obj = $this->db->fetch_object($resql);
3640
3641 // Note: There is no check on detail line and no check on total, if $forcedroundingmode = 'none'
3642 $parameters = array('fk_element' => $obj->rowid);
3643 $reshook = $hookmanager->executeHooks('changeRoundingMode', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3644
3645 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'
3646 // This part of code is to fix data. We should not call it too often.
3647 $localtax_array = array($obj->localtax1_type, $obj->localtax1_tx, $obj->localtax2_type, $obj->localtax2_tx);
3648 $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);
3649
3650 $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.
3651 $diff_on_current_total = price2num($obj->total_ttc - $obj->total_ht - $obj->total_tva - $obj->total_localtax1 - $obj->total_localtax2, 'MT', 1);
3652 //var_dump($obj->total_ht.' '.$obj->total_tva.' '.$obj->total_localtax1.' '.$obj->total_localtax2.' => '.$obj->total_ttc);
3653 //var_dump($diff_when_using_price_ht.' '.$diff_on_current_total);
3654
3655 if ($diff_on_current_total) {
3656 // This should not happen, we should always have in table: total_ttc = total_ht + total_vat + total_localtax1 + total_localtax2
3657 $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);
3658 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);
3659 $resqlfix = $this->db->query($sqlfix);
3660 if (!$resqlfix) {
3661 dol_print_error($this->db, 'Failed to update line');
3662 }
3663 $obj->total_tva = $tmpcal[1];
3664 $obj->total_ttc = $tmpcal[2];
3665 } elseif ($diff_when_using_price_ht && $roundingadjust == '0') {
3666 // After calculation from HT, total is consistent but we have found a difference between VAT part in calculation and into database and
3667 // we ask to force the use of rounding on line (like done on calculation) so we force update of line
3668 $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);
3669 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);
3670 $resqlfix = $this->db->query($sqlfix);
3671 if (!$resqlfix) {
3672 dol_print_error($this->db, 'Failed to update line');
3673 }
3674 $obj->total_tva = $tmpcal[1];
3675 $obj->total_ttc = $tmpcal[2];
3676 }
3677 }
3678
3679 $this->total_ht += $obj->total_ht; // The field visible at end of line detail
3680 $this->total_tva += $obj->total_tva;
3681 $this->total_localtax1 += $obj->total_localtax1;
3682 $this->total_localtax2 += $obj->total_localtax2;
3683 $this->total_ttc += $obj->total_ttc;
3684 $this->multicurrency_total_ht += $obj->multicurrency_total_ht; // The field visible at end of line detail
3685 $this->multicurrency_total_tva += $obj->multicurrency_total_tva;
3686 $this->multicurrency_total_ttc += $obj->multicurrency_total_ttc;
3687
3688 if (!isset($total_ht_by_vats[$obj->vatrate])) {
3689 $total_ht_by_vats[$obj->vatrate] = 0;
3690 }
3691 if (!isset($total_tva_by_vats[$obj->vatrate])) {
3692 $total_tva_by_vats[$obj->vatrate] = 0;
3693 }
3694 if (!isset($total_ttc_by_vats[$obj->vatrate])) {
3695 $total_ttc_by_vats[$obj->vatrate] = 0;
3696 }
3697 $total_ht_by_vats[$obj->vatrate] += $obj->total_ht;
3698 $total_tva_by_vats[$obj->vatrate] += $obj->total_tva;
3699 $total_ttc_by_vats[$obj->vatrate] += $obj->total_ttc;
3700
3701 if ($forcedroundingmode == '1') { // Check if we need adjustement onto line for vat. TODO This works on the company currency but not on foreign currency
3702 $tmpvat = price2num($total_ht_by_vats[$obj->vatrate] * $obj->vatrate / 100, 'MT', 1);
3703 $diff = price2num($total_tva_by_vats[$obj->vatrate] - $tmpvat, 'MT', 1);
3704 //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";
3705 if ($diff) {
3706 if (abs($diff) > (10 * pow(10, -1 * getDolGlobalInt('MAIN_MAX_DECIMALS_TOT', 0)))) {
3707 // If error is more than 10 times the accurancy of rounding. This should not happen.
3708 $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.';
3709 dol_syslog($errmsg, LOG_WARNING);
3710 $this->error = $errmsg;
3711 $error++;
3712 break;
3713 }
3714 $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);
3715 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);
3716
3717 $resqlfix = $this->db->query($sqlfix);
3718
3719 if (!$resqlfix) {
3720 dol_print_error($this->db, 'Failed to update line');
3721 }
3722
3723 $this->total_tva = (float) price2num($this->total_tva - $diff, '', 1);
3724 $this->total_ttc = (float) price2num($this->total_ttc - $diff, '', 1);
3725 $total_tva_by_vats[$obj->vatrate] = (float) price2num($total_tva_by_vats[$obj->vatrate] - $diff, '', 1);
3726 $total_ttc_by_vats[$obj->vatrate] = (float) price2num($total_ttc_by_vats[$obj->vatrate] - $diff, '', 1);
3727 }
3728 }
3729
3730 $i++;
3731 }
3732
3733 // Add revenue stamp to total
3734 $this->total_ttc += isset($this->revenuestamp) ? $this->revenuestamp : 0;
3735 $this->multicurrency_total_ttc += isset($this->revenuestamp) ? ($this->revenuestamp * $multicurrency_tx) : 0;
3736
3737 // Situations totals
3738 if (!empty($this->situation_cycle_ref) && $this->situation_counter > 1 && method_exists($this, 'get_prev_sits') && $this->type != $this::TYPE_CREDIT_NOTE) {
3739 $prev_sits = $this->get_prev_sits();
3740
3741 foreach ($prev_sits as $sit) { // $sit is an object Facture loaded with a fetch.
3742 $this->total_ht -= $sit->total_ht;
3743 $this->total_tva -= $sit->total_tva;
3744 $this->total_localtax1 -= $sit->total_localtax1;
3745 $this->total_localtax2 -= $sit->total_localtax2;
3746 $this->total_ttc -= $sit->total_ttc;
3747 $this->multicurrency_total_ht -= $sit->multicurrency_total_ht;
3748 $this->multicurrency_total_tva -= $sit->multicurrency_total_tva;
3749 $this->multicurrency_total_ttc -= $sit->multicurrency_total_ttc;
3750 }
3751 }
3752
3753 // Clean total
3754 $this->total_ht = (float) price2num($this->total_ht);
3755 $this->total_tva = (float) price2num($this->total_tva);
3756 $this->total_localtax1 = (float) price2num($this->total_localtax1);
3757 $this->total_localtax2 = (float) price2num($this->total_localtax2);
3758 $this->total_ttc = (float) price2num($this->total_ttc);
3759
3760 $this->db->free($resql);
3761
3762 // Now update global fields total_ht, total_ttc, total_tva, total_localtax1, total_localtax2, multicurrency_total_* of main object
3763 $fieldht = 'total_ht';
3764 $fieldtva = 'tva';
3765 $fieldlocaltax1 = 'localtax1';
3766 $fieldlocaltax2 = 'localtax2';
3767 $fieldttc = 'total_ttc';
3768 // Specific code for backward compatibility with old field names
3769 if (in_array($this->element, array('propal', 'commande', 'facture', 'facturerec', 'supplier_proposal', 'order_supplier', 'facture_fourn', 'invoice_supplier', 'invoice_supplier_rec', 'expensereport'))) {
3770 $fieldtva = 'total_tva';
3771 }
3772
3773 if (!$error && empty($nodatabaseupdate)) {
3774 $sql = "UPDATE ".$this->db->prefix().$this->table_element.' SET';
3775 $sql .= " ".$fieldht." = ".((float) price2num($this->total_ht, 'MT', 1)).",";
3776 $sql .= " ".$fieldtva." = ".((float) price2num($this->total_tva, 'MT', 1)).",";
3777 $sql .= " ".$fieldlocaltax1." = ".((float) price2num($this->total_localtax1, 'MT', 1)).",";
3778 $sql .= " ".$fieldlocaltax2." = ".((float) price2num($this->total_localtax2, 'MT', 1)).",";
3779 $sql .= " ".$fieldttc." = ".((float) price2num($this->total_ttc, 'MT', 1));
3780 $sql .= ", multicurrency_total_ht = ".((float) price2num($this->multicurrency_total_ht, 'MT', 1));
3781 $sql .= ", multicurrency_total_tva = ".((float) price2num($this->multicurrency_total_tva, 'MT', 1));
3782 $sql .= ", multicurrency_total_ttc = ".((float) price2num($this->multicurrency_total_ttc, 'MT', 1));
3783 $sql .= " WHERE rowid = ".((int) $this->id);
3784
3785 dol_syslog(get_class($this)."::update_price", LOG_DEBUG);
3786 $resql = $this->db->query($sql);
3787
3788 if (!$resql) {
3789 $error++;
3790 $this->error = $this->db->lasterror();
3791 $this->errors[] = $this->db->lasterror();
3792 }
3793 }
3794
3795 if (!$error) {
3796 $this->db->commit();
3797 return 1;
3798 } else {
3799 $this->db->rollback();
3800 return -1;
3801 }
3802 } else {
3803 dol_print_error($this->db, 'Bad request in update_price');
3804 return -1;
3805 }
3806 }
3807
3808 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3819 public function add_object_linked($origin = null, $origin_id = null, $f_user = null, $notrigger = 0)
3820 {
3821 // phpcs:enable
3822 global $user, $hookmanager, $action;
3823 $origin = (!empty($origin) ? $origin : $this->origin);
3824 $origin_id = (!empty($origin_id) ? $origin_id : $this->origin_id);
3825 $f_user = isset($f_user) ? $f_user : $user;
3826
3827 // Special case
3828 if ($origin == 'order') {
3829 $origin = 'commande';
3830 }
3831 if ($origin == 'invoice') {
3832 $origin = 'facture';
3833 }
3834 if ($origin == 'invoice_template') {
3835 $origin = 'facturerec';
3836 }
3837 if ($origin == 'supplierorder') {
3838 $origin = 'order_supplier';
3839 }
3840
3841 // 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.
3842 // 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.
3843 $coremodule = array('knowledgemanagement', 'partnership', 'workstation', 'ticket', 'recruitment', 'eventorganization', 'asset');
3844 // Add module part to target type if object has $module property and isn't in core modules.
3845 $targettype = ((!empty($this->module) && ! in_array($this->module, $coremodule)) ? $this->module.'_' : '').$this->element;
3846
3847 $parameters = array('targettype'=>$targettype);
3848 // Hook for explicitly set the targettype if it must be differtent than $this->element
3849 $reshook = $hookmanager->executeHooks('setLinkedObjectSourceTargetType', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3850 if ($reshook > 0) {
3851 if (!empty($hookmanager->resArray['targettype'])) $targettype = $hookmanager->resArray['targettype'];
3852 }
3853
3854 $this->db->begin();
3855 $error = 0;
3856
3857 $sql = "INSERT INTO " . $this->db->prefix() . "element_element (";
3858 $sql .= "fk_source";
3859 $sql .= ", sourcetype";
3860 $sql .= ", fk_target";
3861 $sql .= ", targettype";
3862 $sql .= ") VALUES (";
3863 $sql .= ((int) $origin_id);
3864 $sql .= ", '" . $this->db->escape($origin) . "'";
3865 $sql .= ", " . ((int) $this->id);
3866 $sql .= ", '" . $this->db->escape($targettype) . "'";
3867 $sql .= ")";
3868
3869 dol_syslog(get_class($this) . "::add_object_linked", LOG_DEBUG);
3870 if ($this->db->query($sql)) {
3871 if (!$notrigger) {
3872 // Call trigger
3873 $this->context['link_origin'] = $origin;
3874 $this->context['link_origin_id'] = $origin_id;
3875 $result = $this->call_trigger('OBJECT_LINK_INSERT', $f_user);
3876 if ($result < 0) {
3877 $error++;
3878 }
3879 // End call triggers
3880 }
3881 } else {
3882 $this->error = $this->db->lasterror();
3883 $error++;
3884 }
3885
3886 if (!$error) {
3887 $this->db->commit();
3888 return 1;
3889 } else {
3890 $this->db->rollback();
3891 return 0;
3892 }
3893 }
3894
3917 public function fetchObjectLinked($sourceid = null, $sourcetype = '', $targetid = null, $targettype = '', $clause = 'OR', $alsosametype = 1, $orderby = 'sourcetype', $loadalsoobjects = 1)
3918 {
3919 global $conf, $hookmanager, $action;
3920
3921 // Important for pdf generation time reduction
3922 // This boolean is true if $this->linkedObjects has already been loaded with all objects linked without filter
3923 if ($this->id > 0 && !empty($this->linkedObjectsFullLoaded[$this->id])) {
3924 return 1;
3925 }
3926
3927 $this->linkedObjectsIds = array();
3928 $this->linkedObjects = array();
3929
3930 $justsource = false;
3931 $justtarget = false;
3932 $withtargettype = false;
3933 $withsourcetype = false;
3934
3935 $parameters = array('sourcetype'=>$sourcetype, 'sourceid'=>$sourceid, 'targettype'=>$targettype, 'targetid'=>$targetid);
3936 // Hook for explicitly set the targettype if it must be differtent than $this->element
3937 $reshook = $hookmanager->executeHooks('setLinkedObjectSourceTargetType', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3938 if ($reshook > 0) {
3939 if (!empty($hookmanager->resArray['sourcetype'])) $sourcetype = $hookmanager->resArray['sourcetype'];
3940 if (!empty($hookmanager->resArray['sourceid'])) $sourceid = $hookmanager->resArray['sourceid'];
3941 if (!empty($hookmanager->resArray['targettype'])) $targettype = $hookmanager->resArray['targettype'];
3942 if (!empty($hookmanager->resArray['targetid'])) $targetid = $hookmanager->resArray['targetid'];
3943 }
3944
3945 if (!empty($sourceid) && !empty($sourcetype) && empty($targetid)) {
3946 $justsource = true; // the source (id and type) is a search criteria
3947 if (!empty($targettype)) {
3948 $withtargettype = true;
3949 }
3950 }
3951 if (!empty($targetid) && !empty($targettype) && empty($sourceid)) {
3952 $justtarget = true; // the target (id and type) is a search criteria
3953 if (!empty($sourcetype)) {
3954 $withsourcetype = true;
3955 }
3956 }
3957
3958 $sourceid = (!empty($sourceid) ? $sourceid : $this->id);
3959 $targetid = (!empty($targetid) ? $targetid : $this->id);
3960 $sourcetype = (!empty($sourcetype) ? $sourcetype : $this->element);
3961 $targettype = (!empty($targettype) ? $targettype : $this->element);
3962
3963 /*if (empty($sourceid) && empty($targetid))
3964 {
3965 dol_syslog('Bad usage of function. No source nor target id defined (nor as parameter nor as object id)', LOG_ERR);
3966 return -1;
3967 }*/
3968
3969 // Links between objects are stored in table element_element
3970 $sql = "SELECT rowid, fk_source, sourcetype, fk_target, targettype";
3971 $sql .= " FROM ".$this->db->prefix()."element_element";
3972 $sql .= " WHERE ";
3973 if ($justsource || $justtarget) {
3974 if ($justsource) {
3975 $sql .= "fk_source = ".((int) $sourceid)." AND sourcetype = '".$this->db->escape($sourcetype)."'";
3976 if ($withtargettype) {
3977 $sql .= " AND targettype = '".$this->db->escape($targettype)."'";
3978 }
3979 } elseif ($justtarget) {
3980 $sql .= "fk_target = ".((int) $targetid)." AND targettype = '".$this->db->escape($targettype)."'";
3981 if ($withsourcetype) {
3982 $sql .= " AND sourcetype = '".$this->db->escape($sourcetype)."'";
3983 }
3984 }
3985 } else {
3986 $sql .= "(fk_source = ".((int) $sourceid)." AND sourcetype = '".$this->db->escape($sourcetype)."')";
3987 $sql .= " ".$clause." (fk_target = ".((int) $targetid)." AND targettype = '".$this->db->escape($targettype)."')";
3988 if ($loadalsoobjects && $this->id > 0 && $sourceid == $this->id && $sourcetype == $this->element && $targetid == $this->id && $targettype == $this->element && $clause == 'OR') {
3989 $this->linkedObjectsFullLoaded[$this->id] = true;
3990 }
3991 }
3992 $sql .= " ORDER BY ".$orderby;
3993
3994 dol_syslog(get_class($this)."::fetchObjectLink", LOG_DEBUG);
3995 $resql = $this->db->query($sql);
3996 if ($resql) {
3997 $num = $this->db->num_rows($resql);
3998 $i = 0;
3999 while ($i < $num) {
4000 $obj = $this->db->fetch_object($resql);
4001 if ($justsource || $justtarget) {
4002 if ($justsource) {
4003 $this->linkedObjectsIds[$obj->targettype][$obj->rowid] = $obj->fk_target;
4004 } elseif ($justtarget) {
4005 $this->linkedObjectsIds[$obj->sourcetype][$obj->rowid] = $obj->fk_source;
4006 }
4007 } else {
4008 if ($obj->fk_source == $sourceid && $obj->sourcetype == $sourcetype) {
4009 $this->linkedObjectsIds[$obj->targettype][$obj->rowid] = $obj->fk_target;
4010 }
4011 if ($obj->fk_target == $targetid && $obj->targettype == $targettype) {
4012 $this->linkedObjectsIds[$obj->sourcetype][$obj->rowid] = $obj->fk_source;
4013 }
4014 }
4015 $i++;
4016 }
4017
4018 if (!empty($this->linkedObjectsIds)) {
4019 $tmparray = $this->linkedObjectsIds;
4020 foreach ($tmparray as $objecttype => $objectids) { // $objecttype is a module name ('facture', 'mymodule', ...) or a module name with a suffix ('project_task', 'mymodule_myobj', ...)
4021 // Parse element/subelement (ex: project_task, cabinetmed_consultation, ...)
4022 $module = $element = $subelement = $objecttype;
4023 $regs = array();
4024 if ($objecttype != 'supplier_proposal' && $objecttype != 'order_supplier' && $objecttype != 'invoice_supplier'
4025 && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
4026 $module = $element = $regs[1];
4027 $subelement = $regs[2];
4028 }
4029
4030 $classpath = $element.'/class';
4031 // To work with non standard classpath or module name
4032 if ($objecttype == 'facture') {
4033 $classpath = 'compta/facture/class';
4034 } elseif ($objecttype == 'facturerec') {
4035 $classpath = 'compta/facture/class';
4036 $module = 'facture';
4037 } elseif ($objecttype == 'propal') {
4038 $classpath = 'comm/propal/class';
4039 } elseif ($objecttype == 'supplier_proposal') {
4040 $classpath = 'supplier_proposal/class';
4041 } elseif ($objecttype == 'shipping') {
4042 $classpath = 'expedition/class';
4043 $subelement = 'expedition';
4044 $module = 'expedition';
4045 } elseif ($objecttype == 'delivery') {
4046 $classpath = 'delivery/class';
4047 $subelement = 'delivery';
4048 $module = 'delivery_note';
4049 } elseif ($objecttype == 'invoice_supplier' || $objecttype == 'order_supplier') {
4050 $classpath = 'fourn/class';
4051 $module = 'fournisseur';
4052 } elseif ($objecttype == 'fichinter') {
4053 $classpath = 'fichinter/class';
4054 $subelement = 'fichinter';
4055 $module = 'ficheinter';
4056 } elseif ($objecttype == 'subscription') {
4057 $classpath = 'adherents/class';
4058 $module = 'adherent';
4059 } elseif ($objecttype == 'contact') {
4060 $module = 'societe';
4061 } elseif ($objecttype == 'action') {
4062 $module = 'agenda';
4063 $subelement = 'actionComm';
4064 }
4065
4066 // Set classfile
4067 $classfile = strtolower($subelement);
4068 $classname = ucfirst($subelement);
4069
4070 if ($objecttype == 'order') {
4071 $classfile = 'commande';
4072 $classname = 'Commande';
4073 } elseif ($objecttype == 'invoice_supplier') {
4074 $classfile = 'fournisseur.facture';
4075 $classname = 'FactureFournisseur';
4076 } elseif ($objecttype == 'order_supplier') {
4077 $classfile = 'fournisseur.commande';
4078 $classname = 'CommandeFournisseur';
4079 } elseif ($objecttype == 'supplier_proposal') {
4080 $classfile = 'supplier_proposal';
4081 $classname = 'SupplierProposal';
4082 } elseif ($objecttype == 'facturerec') {
4083 $classfile = 'facture-rec';
4084 $classname = 'FactureRec';
4085 } elseif ($objecttype == 'subscription') {
4086 $classfile = 'subscription';
4087 $classname = 'Subscription';
4088 } elseif ($objecttype == 'project' || $objecttype == 'projet') {
4089 $classpath = 'projet/class';
4090 $classfile = 'project';
4091 $classname = 'Project';
4092 } elseif ($objecttype == 'conferenceorboothattendee') {
4093 $classpath = 'eventorganization/class';
4094 $classfile = 'conferenceorboothattendee';
4095 $classname = 'ConferenceOrBoothAttendee';
4096 $module = 'eventorganization';
4097 } elseif ($objecttype == 'conferenceorbooth') {
4098 $classpath = 'eventorganization/class';
4099 $classfile = 'conferenceorbooth';
4100 $classname = 'ConferenceOrBooth';
4101 $module = 'eventorganization';
4102 } elseif ($objecttype == 'mo') {
4103 $classpath = 'mrp/class';
4104 $classfile = 'mo';
4105 $classname = 'Mo';
4106 $module = 'mrp';
4107 }
4108
4109 // Here $module, $classfile and $classname are set, we can use them.
4110 if (isModEnabled($module) && (($element != $this->element) || $alsosametype)) {
4111 if ($loadalsoobjects && (is_numeric($loadalsoobjects) || ($loadalsoobjects === $objecttype))) {
4112 dol_include_once('/'.$classpath.'/'.$classfile.'.class.php');
4113 //print '/'.$classpath.'/'.$classfile.'.class.php '.class_exists($classname);
4114 if (class_exists($classname)) {
4115 foreach ($objectids as $i => $objectid) { // $i is rowid into llx_element_element
4116 $object = new $classname($this->db);
4117 $ret = $object->fetch($objectid);
4118 if ($ret >= 0) {
4119 $this->linkedObjects[$objecttype][$i] = $object;
4120 }
4121 }
4122 }
4123 }
4124 } else {
4125 unset($this->linkedObjectsIds[$objecttype]);
4126 }
4127 }
4128 }
4129 return 1;
4130 } else {
4131 dol_print_error($this->db);
4132 return -1;
4133 }
4134 }
4135
4142 public function clearObjectLinkedCache()
4143 {
4144 if ($this->id > 0 && !empty($this->linkedObjectsFullLoaded[$this->id])) {
4145 unset($this->linkedObjectsFullLoaded[$this->id]);
4146 }
4147
4148 return 1;
4149 }
4150
4163 public function updateObjectLinked($sourceid = null, $sourcetype = '', $targetid = null, $targettype = '', $f_user = null, $notrigger = 0)
4164 {
4165 global $user;
4166 $updatesource = false;
4167 $updatetarget = false;
4168 $f_user = isset($f_user) ? $f_user : $user;
4169
4170 if (!empty($sourceid) && !empty($sourcetype) && empty($targetid) && empty($targettype)) {
4171 $updatesource = true;
4172 } elseif (empty($sourceid) && empty($sourcetype) && !empty($targetid) && !empty($targettype)) {
4173 $updatetarget = true;
4174 }
4175
4176 $this->db->begin();
4177 $error = 0;
4178
4179 $sql = "UPDATE " . $this->db->prefix() . "element_element SET ";
4180 if ($updatesource) {
4181 $sql .= "fk_source = " . ((int) $sourceid);
4182 $sql .= ", sourcetype = '" . $this->db->escape($sourcetype) . "'";
4183 $sql .= " WHERE fk_target = " . ((int) $this->id);
4184 $sql .= " AND targettype = '" . $this->db->escape($this->element) . "'";
4185 } elseif ($updatetarget) {
4186 $sql .= "fk_target = " . ((int) $targetid);
4187 $sql .= ", targettype = '" . $this->db->escape($targettype) . "'";
4188 $sql .= " WHERE fk_source = " . ((int) $this->id);
4189 $sql .= " AND sourcetype = '" . $this->db->escape($this->element) . "'";
4190 }
4191
4192 dol_syslog(get_class($this) . "::updateObjectLinked", LOG_DEBUG);
4193 if ($this->db->query($sql)) {
4194 if (!$notrigger) {
4195 // Call trigger
4196 $this->context['link_source_id'] = $sourceid;
4197 $this->context['link_source_type'] = $sourcetype;
4198 $this->context['link_target_id'] = $targetid;
4199 $this->context['link_target_type'] = $targettype;
4200 $result = $this->call_trigger('OBJECT_LINK_MODIFY', $f_user);
4201 if ($result < 0) {
4202 $error++;
4203 }
4204 // End call triggers
4205 }
4206 } else {
4207 $this->error = $this->db->lasterror();
4208 $error++;
4209 }
4210
4211 if (!$error) {
4212 $this->db->commit();
4213 return 1;
4214 } else {
4215 $this->db->rollback();
4216 return -1;
4217 }
4218 }
4219
4233 public function deleteObjectLinked($sourceid = null, $sourcetype = '', $targetid = null, $targettype = '', $rowid = '', $f_user = null, $notrigger = 0)
4234 {
4235 global $user;
4236 $deletesource = false;
4237 $deletetarget = false;
4238 $f_user = isset($f_user) ? $f_user : $user;
4239
4240 if (!empty($sourceid) && !empty($sourcetype) && empty($targetid) && empty($targettype)) {
4241 $deletesource = true;
4242 } elseif (empty($sourceid) && empty($sourcetype) && !empty($targetid) && !empty($targettype)) {
4243 $deletetarget = true;
4244 }
4245
4246 $sourceid = (!empty($sourceid) ? $sourceid : $this->id);
4247 $sourcetype = (!empty($sourcetype) ? $sourcetype : $this->element);
4248 $targetid = (!empty($targetid) ? $targetid : $this->id);
4249 $targettype = (!empty($targettype) ? $targettype : $this->element);
4250 $this->db->begin();
4251 $error = 0;
4252
4253 if (!$notrigger) {
4254 // Call trigger
4255 $this->context['link_id'] = $rowid;
4256 $this->context['link_source_id'] = $sourceid;
4257 $this->context['link_source_type'] = $sourcetype;
4258 $this->context['link_target_id'] = $targetid;
4259 $this->context['link_target_type'] = $targettype;
4260 $result = $this->call_trigger('OBJECT_LINK_DELETE', $f_user);
4261 if ($result < 0) {
4262 $error++;
4263 }
4264 // End call triggers
4265 }
4266
4267 if (!$error) {
4268 $sql = "DELETE FROM " . $this->db->prefix() . "element_element";
4269 $sql .= " WHERE";
4270 if ($rowid > 0) {
4271 $sql .= " rowid = " . ((int) $rowid);
4272 } else {
4273 if ($deletesource) {
4274 $sql .= " fk_source = " . ((int) $sourceid) . " AND sourcetype = '" . $this->db->escape($sourcetype) . "'";
4275 $sql .= " AND fk_target = " . ((int) $this->id) . " AND targettype = '" . $this->db->escape($this->element) . "'";
4276 } elseif ($deletetarget) {
4277 $sql .= " fk_target = " . ((int) $targetid) . " AND targettype = '" . $this->db->escape($targettype) . "'";
4278 $sql .= " AND fk_source = " . ((int) $this->id) . " AND sourcetype = '" . $this->db->escape($this->element) . "'";
4279 } else {
4280 $sql .= " (fk_source = " . ((int) $this->id) . " AND sourcetype = '" . $this->db->escape($this->element) . "')";
4281 $sql .= " OR";
4282 $sql .= " (fk_target = " . ((int) $this->id) . " AND targettype = '" . $this->db->escape($this->element) . "')";
4283 }
4284 }
4285
4286 dol_syslog(get_class($this) . "::deleteObjectLinked", LOG_DEBUG);
4287 if (!$this->db->query($sql)) {
4288 $this->error = $this->db->lasterror();
4289 $this->errors[] = $this->error;
4290 $error++;
4291 }
4292 }
4293
4294 if (!$error) {
4295 $this->db->commit();
4296 return 1;
4297 } else {
4298 $this->db->rollback();
4299 return 0;
4300 }
4301 }
4302
4312 public static function getAllItemsLinkedByObjectID($fk_object_where, $field_select, $field_where, $table_element)
4313 {
4314 if (empty($fk_object_where) || empty($field_where) || empty($table_element)) {
4315 return -1;
4316 }
4317
4318 global $db;
4319
4320 $sql = "SELECT ".$field_select." FROM ".$db->prefix().$table_element." WHERE ".$field_where." = ".((int) $fk_object_where);
4321 $resql = $db->query($sql);
4322
4323 $TRes = array();
4324 if (!empty($resql)) {
4325 while ($res = $db->fetch_object($resql)) {
4326 $TRes[] = $res->{$field_select};
4327 }
4328 }
4329
4330 return $TRes;
4331 }
4332
4341 public static function deleteAllItemsLinkedByObjectID($fk_object_where, $field_where, $table_element)
4342 {
4343 if (empty($fk_object_where) || empty($field_where) || empty($table_element)) {
4344 return -1;
4345 }
4346
4347 global $db;
4348
4349 $sql = "DELETE FROM ".$db->prefix().$table_element." WHERE ".$field_where." = ".((int) $fk_object_where);
4350 $resql = $db->query($sql);
4351
4352 if (empty($resql)) {
4353 return 0;
4354 }
4355
4356 return 1;
4357 }
4358
4369 public function setStatut($status, $elementId = null, $elementType = '', $trigkey = '', $fieldstatus = 'fk_statut')
4370 {
4371 global $user, $langs, $conf;
4372
4373 $savElementId = $elementId; // To be used later to know if we were using the method using the id of this or not.
4374
4375 $elementId = (!empty($elementId) ? $elementId : $this->id);
4376 $elementTable = (!empty($elementType) ? $elementType : $this->table_element);
4377
4378 $this->db->begin();
4379
4380 if ($elementTable == 'facture_rec') {
4381 $fieldstatus = "suspended";
4382 }
4383 if ($elementTable == 'mailing') {
4384 $fieldstatus = "statut";
4385 }
4386 if ($elementTable == 'cronjob') {
4387 $fieldstatus = "status";
4388 }
4389 if ($elementTable == 'user') {
4390 $fieldstatus = "statut";
4391 }
4392 if ($elementTable == 'expensereport') {
4393 $fieldstatus = "fk_statut";
4394 }
4395 if ($elementTable == 'commande_fournisseur_dispatch') {
4396 $fieldstatus = "status";
4397 }
4398 if (isset($this->fields) && is_array($this->fields) && array_key_exists('status', $this->fields)) {
4399 $fieldstatus = 'status';
4400 }
4401
4402 $sql = "UPDATE ".$this->db->prefix().$elementTable;
4403 $sql .= " SET ".$fieldstatus." = ".((int) $status);
4404 // If status = 1 = validated, update also fk_user_valid
4405 // TODO Replace the test on $elementTable by doing a test on existence of the field in $this->fields
4406 if ($status == 1 && in_array($elementTable, array('expensereport', 'inventory'))) {
4407 $sql .= ", fk_user_valid = ".((int) $user->id);
4408 }
4409 if ($status == 1 && in_array($elementTable, array('expensereport'))) {
4410 $sql .= ", date_valid = '".$this->db->idate(dol_now())."'";
4411 }
4412 if ($status == 1 && in_array($elementTable, array('inventory'))) {
4413 $sql .= ", date_validation = '".$this->db->idate(dol_now())."'";
4414 }
4415 $sql .= " WHERE rowid = ".((int) $elementId);
4416 $sql .= " AND ".$fieldstatus." <> ".((int) $status); // We avoid update if status already correct
4417
4418 dol_syslog(get_class($this)."::setStatut", LOG_DEBUG);
4419 $resql = $this->db->query($sql);
4420 if ($resql) {
4421 $error = 0;
4422
4423 $nb_rows_affected = $this->db->affected_rows($resql); // should be 1 or 0 if status was already correct
4424
4425 if ($nb_rows_affected > 0) {
4426 if (empty($trigkey)) {
4427 // Try to guess trigkey (for backward compatibility, now we should have trigkey defined into the call of setStatus)
4428 if ($this->element == 'supplier_proposal' && $status == 2) {
4429 $trigkey = 'SUPPLIER_PROPOSAL_SIGN'; // 2 = SupplierProposal::STATUS_SIGNED. Can't use constant into this generic class
4430 }
4431 if ($this->element == 'supplier_proposal' && $status == 3) {
4432 $trigkey = 'SUPPLIER_PROPOSAL_REFUSE'; // 3 = SupplierProposal::STATUS_REFUSED. Can't use constant into this generic class
4433 }
4434 if ($this->element == 'supplier_proposal' && $status == 4) {
4435 $trigkey = 'SUPPLIER_PROPOSAL_CLOSE'; // 4 = SupplierProposal::STATUS_CLOSED. Can't use constant into this generic class
4436 }
4437 if ($this->element == 'fichinter' && $status == 3) {
4438 $trigkey = 'FICHINTER_CLASSIFY_DONE';
4439 }
4440 if ($this->element == 'fichinter' && $status == 2) {
4441 $trigkey = 'FICHINTER_CLASSIFY_BILLED';
4442 }
4443 if ($this->element == 'fichinter' && $status == 1) {
4444 $trigkey = 'FICHINTER_CLASSIFY_UNBILLED';
4445 }
4446 }
4447
4448 if ($trigkey) {
4449 // Call trigger
4450 $result = $this->call_trigger($trigkey, $user);
4451 if ($result < 0) {
4452 $error++;
4453 }
4454 // End call triggers
4455 }
4456 } else {
4457 // The status was probably already good. We do nothing more, no triggers.
4458 }
4459
4460 if (!$error) {
4461 $this->db->commit();
4462
4463 if (empty($savElementId)) {
4464 // If the element we update is $this (so $elementId was provided as null)
4465 if ($fieldstatus == 'tosell') {
4466 $this->status = $status;
4467 } elseif ($fieldstatus == 'tobuy') {
4468 $this->status_buy = $status;
4469 } else {
4470 $this->statut = $status;
4471 $this->status = $status;
4472 }
4473 }
4474
4475 return 1;
4476 } else {
4477 $this->db->rollback();
4478 dol_syslog(get_class($this)."::setStatut ".$this->error, LOG_ERR);
4479 return -1;
4480 }
4481 } else {
4482 $this->error = $this->db->lasterror();
4483 $this->db->rollback();
4484 return -1;
4485 }
4486 }
4487
4488
4496 public function getCanvas($id = 0, $ref = '')
4497 {
4498 global $conf;
4499
4500 if (empty($id) && empty($ref)) {
4501 return 0;
4502 }
4503 if (!empty($conf->global->MAIN_DISABLE_CANVAS)) {
4504 return 0; // To increase speed. Not enabled by default.
4505 }
4506
4507 // Clean parameters
4508 $ref = trim($ref);
4509
4510 $sql = "SELECT rowid, canvas";
4511 $sql .= " FROM ".$this->db->prefix().$this->table_element;
4512 $sql .= " WHERE entity IN (".getEntity($this->element).")";
4513 if (!empty($id)) {
4514 $sql .= " AND rowid = ".((int) $id);
4515 }
4516 if (!empty($ref)) {
4517 $sql .= " AND ref = '".$this->db->escape($ref)."'";
4518 }
4519
4520 $resql = $this->db->query($sql);
4521 if ($resql) {
4522 $obj = $this->db->fetch_object($resql);
4523 if ($obj) {
4524 $this->canvas = $obj->canvas;
4525 return 1;
4526 } else {
4527 return 0;
4528 }
4529 } else {
4530 dol_print_error($this->db);
4531 return -1;
4532 }
4533 }
4534
4535
4542 public function getSpecialCode($lineid)
4543 {
4544 $sql = "SELECT special_code FROM ".$this->db->prefix().$this->table_element_line;
4545 $sql .= " WHERE rowid = ".((int) $lineid);
4546 $resql = $this->db->query($sql);
4547 if ($resql) {
4548 $row = $this->db->fetch_row($resql);
4549 return (!empty($row[0]) ? $row[0] : 0);
4550 }
4551
4552 return 0;
4553 }
4554
4563 public function isObjectUsed($id = 0, $entity = 0)
4564 {
4565 global $langs;
4566
4567 if (empty($id)) {
4568 $id = $this->id;
4569 }
4570
4571 // Check parameters
4572 if (!isset($this->childtables) || !is_array($this->childtables) || count($this->childtables) == 0) {
4573 dol_print_error('Called isObjectUsed on a class with property this->childtables not defined');
4574 return -1;
4575 }
4576
4577 $arraytoscan = $this->childtables; // array('tablename'=>array('fk_element'=>'parentfield'), ...) or array('tablename'=>array('parent'=>table_parent, 'parentkey'=>'nameoffieldforparentfkkey'), ...)
4578 // For backward compatibility, we check if array is old format array('tablename1', 'tablename2', ...)
4579 $tmparray = array_keys($this->childtables);
4580 if (is_numeric($tmparray[0])) {
4581 $arraytoscan = array_flip($this->childtables);
4582 }
4583
4584 // Test if child exists
4585 $haschild = 0;
4586 foreach ($arraytoscan as $table => $element) {
4587 //print $id.'-'.$table.'-'.$elementname.'<br>';
4588 // Check if element can be deleted
4589 $sql = "SELECT COUNT(*) as nb";
4590 $sql.= " FROM ".$this->db->prefix().$table." as c";
4591 if (!empty($element['parent']) && !empty($element['parentkey'])) {
4592 $sql.= ", ".$this->db->prefix().$element['parent']." as p";
4593 }
4594 if (!empty($element['fk_element'])) {
4595 $sql.= " WHERE c.".$element['fk_element']." = ".((int) $id);
4596 } else {
4597 $sql.= " WHERE c.".$this->fk_element." = ".((int) $id);
4598 }
4599 if (!empty($element['parent']) && !empty($element['parentkey'])) {
4600 $sql.= " AND c.".$element['parentkey']." = p.rowid";
4601 }
4602 if (!empty($element['parent']) && !empty($element['parenttypefield']) && !empty($element['parenttypevalue'])) {
4603 $sql.= " AND c.".$element['parenttypefield']." = '".$this->db->escape($element['parenttypevalue'])."'";
4604 }
4605 if (!empty($entity)) {
4606 if (!empty($element['parent']) && !empty($element['parentkey'])) {
4607 $sql.= " AND p.entity = ".((int) $entity);
4608 } else {
4609 $sql.= " AND c.entity = ".((int) $entity);
4610 }
4611 }
4612
4613 $resql = $this->db->query($sql);
4614 if ($resql) {
4615 $obj = $this->db->fetch_object($resql);
4616 if ($obj->nb > 0) {
4617 $langs->load("errors");
4618 //print 'Found into table '.$table.', type '.$langs->transnoentitiesnoconv($elementname).', haschild='.$haschild;
4619 $haschild += $obj->nb;
4620 if (is_numeric($element)) { // very old usage array('table1', 'table2', ...)
4621 $this->errors[] = $langs->transnoentitiesnoconv("ErrorRecordHasAtLeastOneChildOfType", method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref, $table);
4622 } elseif (is_string($element)) { // old usage array('table1' => 'TranslateKey1', 'table2' => 'TranslateKey2', ...)
4623 $this->errors[] = $langs->transnoentitiesnoconv("ErrorRecordHasAtLeastOneChildOfType", method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref, $langs->transnoentitiesnoconv($element));
4624 } else { // new usage: $element['name']=Translation key
4625 $this->errors[] = $langs->transnoentitiesnoconv("ErrorRecordHasAtLeastOneChildOfType", method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref, $langs->transnoentitiesnoconv($element['name']));
4626 }
4627 break; // We found at least one, we stop here
4628 }
4629 } else {
4630 $this->errors[] = $this->db->lasterror();
4631 return -1;
4632 }
4633 }
4634 if ($haschild > 0) {
4635 $this->errors[] = "ErrorRecordHasChildren";
4636 return $haschild;
4637 } else {
4638 return 0;
4639 }
4640 }
4641
4648 public function hasProductsOrServices($predefined = -1)
4649 {
4650 $nb = 0;
4651
4652 foreach ($this->lines as $key => $val) {
4653 $qualified = 0;
4654 if ($predefined == -1) {
4655 $qualified = 1;
4656 }
4657 if ($predefined == 1 && $val->fk_product > 0) {
4658 $qualified = 1;
4659 }
4660 if ($predefined == 0 && $val->fk_product <= 0) {
4661 $qualified = 1;
4662 }
4663 if ($predefined == 2 && $val->fk_product > 0 && $val->product_type == 0) {
4664 $qualified = 1;
4665 }
4666 if ($predefined == 3 && $val->fk_product > 0 && $val->product_type == 1) {
4667 $qualified = 1;
4668 }
4669 if ($qualified) {
4670 $nb++;
4671 }
4672 }
4673 dol_syslog(get_class($this).'::hasProductsOrServices we found '.$nb.' qualified lines of products/servcies');
4674 return $nb;
4675 }
4676
4682 public function getTotalDiscount()
4683 {
4684 if (!empty($this->table_element_line) ) {
4685 $total_discount = 0.00;
4686
4687 $sql = "SELECT subprice as pu_ht, qty, remise_percent, total_ht";
4688 $sql .= " FROM ".$this->db->prefix().$this->table_element_line;
4689 $sql .= " WHERE ".$this->fk_element." = ".((int) $this->id);
4690
4691 dol_syslog(get_class($this).'::getTotalDiscount', LOG_DEBUG);
4692 $resql = $this->db->query($sql);
4693 if ($resql) {
4694 $num = $this->db->num_rows($resql);
4695 $i = 0;
4696 while ($i < $num) {
4697 $obj = $this->db->fetch_object($resql);
4698
4699 $pu_ht = $obj->pu_ht;
4700 $qty = $obj->qty;
4701 $total_ht = $obj->total_ht;
4702
4703 $total_discount_line = floatval(price2num(($pu_ht * $qty) - $total_ht, 'MT'));
4704 $total_discount += $total_discount_line;
4705
4706 $i++;
4707 }
4708 }
4709
4710 //print $total_discount; exit;
4711 return price2num($total_discount);
4712 }
4713
4714 return null;
4715 }
4716
4717
4724 public function getTotalWeightVolume()
4725 {
4726 $totalWeight = 0;
4727 $totalVolume = 0;
4728 // defined for shipment only
4729 $totalOrdered = '';
4730 // defined for shipment only
4731 $totalToShip = '';
4732
4733 foreach ($this->lines as $line) {
4734 if (isset($line->qty_asked)) {
4735 if (empty($totalOrdered)) {
4736 $totalOrdered = 0; // Avoid warning because $totalOrdered is ''
4737 }
4738 $totalOrdered += $line->qty_asked; // defined for shipment only
4739 }
4740 if (isset($line->qty_shipped)) {
4741 if (empty($totalToShip)) {
4742 $totalToShip = 0; // Avoid warning because $totalToShip is ''
4743 }
4744 $totalToShip += $line->qty_shipped; // defined for shipment only
4745 } elseif ($line->element == 'commandefournisseurdispatch' && isset($line->qty)) {
4746 if (empty($totalToShip)) {
4747 $totalToShip = 0;
4748 }
4749 $totalToShip += $line->qty; // defined for reception only
4750 }
4751
4752 // Define qty, weight, volume, weight_units, volume_units
4753 if ($this->element == 'shipping') {
4754 // for shipments
4755 $qty = $line->qty_shipped ? $line->qty_shipped : 0;
4756 } else {
4757 $qty = $line->qty ? $line->qty : 0;
4758 }
4759
4760 $weight = !empty($line->weight) ? $line->weight : 0;
4761 ($weight == 0 && !empty($line->product->weight)) ? $weight = $line->product->weight : 0;
4762 $volume = !empty($line->volume) ? $line->volume : 0;
4763 ($volume == 0 && !empty($line->product->volume)) ? $volume = $line->product->volume : 0;
4764
4765 $weight_units = !empty($line->weight_units) ? $line->weight_units : 0;
4766 ($weight_units == 0 && !empty($line->product->weight_units)) ? $weight_units = $line->product->weight_units : 0;
4767 $volume_units = !empty($line->volume_units) ? $line->volume_units : 0;
4768 ($volume_units == 0 && !empty($line->product->volume_units)) ? $volume_units = $line->product->volume_units : 0;
4769
4770 $weightUnit = 0;
4771 $volumeUnit = 0;
4772 if (!empty($weight_units)) {
4773 $weightUnit = $weight_units;
4774 }
4775 if (!empty($volume_units)) {
4776 $volumeUnit = $volume_units;
4777 }
4778
4779 if (empty($totalWeight)) {
4780 $totalWeight = 0; // Avoid warning because $totalWeight is ''
4781 }
4782 if (empty($totalVolume)) {
4783 $totalVolume = 0; // Avoid warning because $totalVolume is ''
4784 }
4785
4786 //var_dump($line->volume_units);
4787 if ($weight_units < 50) { // < 50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch)
4788 $trueWeightUnit = pow(10, $weightUnit);
4789 $totalWeight += $weight * $qty * $trueWeightUnit;
4790 } else {
4791 if ($weight_units == 99) {
4792 // conversion 1 Pound = 0.45359237 KG
4793 $trueWeightUnit = 0.45359237;
4794 $totalWeight += $weight * $qty * $trueWeightUnit;
4795 } elseif ($weight_units == 98) {
4796 // conversion 1 Ounce = 0.0283495 KG
4797 $trueWeightUnit = 0.0283495;
4798 $totalWeight += $weight * $qty * $trueWeightUnit;
4799 } else {
4800 $totalWeight += $weight * $qty; // This may be wrong if we mix different units
4801 }
4802 }
4803 if ($volume_units < 50) { // >50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch)
4804 //print $line->volume."x".$line->volume_units."x".($line->volume_units < 50)."x".$volumeUnit;
4805 $trueVolumeUnit = pow(10, $volumeUnit);
4806 //print $line->volume;
4807 $totalVolume += $volume * $qty * $trueVolumeUnit;
4808 } else {
4809 $totalVolume += $volume * $qty; // This may be wrong if we mix different units
4810 }
4811 }
4812
4813 return array('weight'=>$totalWeight, 'volume'=>$totalVolume, 'ordered'=>$totalOrdered, 'toship'=>$totalToShip);
4814 }
4815
4816
4822 public function setExtraParameters()
4823 {
4824 $this->db->begin();
4825
4826 $extraparams = (!empty($this->extraparams) ? json_encode($this->extraparams) : null);
4827
4828 $sql = "UPDATE ".$this->db->prefix().$this->table_element;
4829 $sql .= " SET extraparams = ".(!empty($extraparams) ? "'".$this->db->escape($extraparams)."'" : "null");
4830 $sql .= " WHERE rowid = ".((int) $this->id);
4831
4832 dol_syslog(get_class($this)."::setExtraParameters", LOG_DEBUG);
4833 $resql = $this->db->query($sql);
4834 if (!$resql) {
4835 $this->error = $this->db->lasterror();
4836 $this->db->rollback();
4837 return -1;
4838 } else {
4839 $this->db->commit();
4840 return 1;
4841 }
4842 }
4843
4844
4845 // --------------------
4846 // TODO: All functions here must be redesigned and moved as they are not business functions but output functions
4847 // --------------------
4848
4849 /* This is to show add lines */
4850
4860 public function formAddObjectLine($dateSelector, $seller, $buyer, $defaulttpldir = '/core/tpl')
4861 {
4862 global $conf, $user, $langs, $object, $hookmanager, $extrafields;
4863 global $form;
4864
4865 // Line extrafield
4866 if (!is_object($extrafields)) {
4867 require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
4868 $extrafields = new ExtraFields($this->db);
4869 }
4870 $extrafields->fetch_name_optionals_label($this->table_element_line);
4871
4872 // Output template part (modules that overwrite templates must declare this into descriptor)
4873 // Use global variables + $dateSelector + $seller and $buyer
4874 // Note: This is deprecated. If you need to overwrite the tpl file, use instead the hook 'formAddObjectLine'.
4875 $dirtpls = array_merge($conf->modules_parts['tpl'], array($defaulttpldir));
4876 foreach ($dirtpls as $module => $reldir) {
4877 if (!empty($module)) {
4878 $tpl = dol_buildpath($reldir.'/objectline_create.tpl.php');
4879 } else {
4880 $tpl = DOL_DOCUMENT_ROOT.$reldir.'/objectline_create.tpl.php';
4881 }
4882
4883 if (empty($conf->file->strict_mode)) {
4884 $res = @include $tpl;
4885 } else {
4886 $res = include $tpl; // for debug
4887 }
4888 if ($res) {
4889 break;
4890 }
4891 }
4892 }
4893
4894
4895
4896 /* This is to show array of line of details */
4897
4898
4913 public function printObjectLines($action, $seller, $buyer, $selected = 0, $dateSelector = 0, $defaulttpldir = '/core/tpl')
4914 {
4915 global $conf, $hookmanager, $langs, $user, $form, $extrafields, $object;
4916 // TODO We should not use global var for this
4917 global $inputalsopricewithtax, $usemargins, $disableedit, $disablemove, $disableremove, $outputalsopricetotalwithtax;
4918
4919 // Define usemargins
4920 $usemargins = 0;
4921 if (isModEnabled('margin') && !empty($this->element) && in_array($this->element, array('facture', 'facturerec', 'propal', 'commande'))) {
4922 $usemargins = 1;
4923 }
4924
4925 $num = count($this->lines);
4926
4927 // Line extrafield
4928 if (!is_object($extrafields)) {
4929 require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
4930 $extrafields = new ExtraFields($this->db);
4931 }
4932 $extrafields->fetch_name_optionals_label($this->table_element_line);
4933
4934 $parameters = array('num'=>$num, 'dateSelector'=>$dateSelector, 'seller'=>$seller, 'buyer'=>$buyer, 'selected'=>$selected, 'table_element_line'=>$this->table_element_line);
4935 $reshook = $hookmanager->executeHooks('printObjectLineTitle', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
4936 if (empty($reshook)) {
4937 // Output template part (modules that overwrite templates must declare this into descriptor)
4938 // Use global variables + $dateSelector + $seller and $buyer
4939 // Note: This is deprecated. If you need to overwrite the tpl file, use instead the hook.
4940 $dirtpls = array_merge($conf->modules_parts['tpl'], array($defaulttpldir));
4941 foreach ($dirtpls as $module => $reldir) {
4942 $res = 0;
4943 if (!empty($module)) {
4944 $tpl = dol_buildpath($reldir.'/objectline_title.tpl.php');
4945 } else {
4946 $tpl = DOL_DOCUMENT_ROOT.$reldir.'/objectline_title.tpl.php';
4947 }
4948 if (file_exists($tpl)) {
4949 if (empty($conf->file->strict_mode)) {
4950 $res = @include $tpl;
4951 } else {
4952 $res = include $tpl; // for debug
4953 }
4954 }
4955 if ($res) {
4956 break;
4957 }
4958 }
4959 }
4960
4961 $i = 0;
4962
4963 print "<!-- begin printObjectLines() --><tbody>\n";
4964 foreach ($this->lines as $line) {
4965 //Line extrafield
4966 $line->fetch_optionals();
4967
4968 //if (is_object($hookmanager) && (($line->product_type == 9 && !empty($line->special_code)) || !empty($line->fk_parent_line)))
4969 if (is_object($hookmanager)) { // Old code is commented on preceding line.
4970 if (empty($line->fk_parent_line)) {
4971 $parameters = array('line'=>$line, 'num'=>$num, 'i'=>$i, 'dateSelector'=>$dateSelector, 'seller'=>$seller, 'buyer'=>$buyer, 'selected'=>$selected, 'table_element_line'=>$line->table_element, 'defaulttpldir'=>$defaulttpldir);
4972 $reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
4973 } else {
4974 $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);
4975 $reshook = $hookmanager->executeHooks('printObjectSubLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
4976 }
4977 }
4978 if (empty($reshook)) {
4979 $this->printObjectLine($action, $line, '', $num, $i, $dateSelector, $seller, $buyer, $selected, $extrafields, $defaulttpldir);
4980 }
4981
4982 $i++;
4983 }
4984 print "</tbody><!-- end printObjectLines() -->\n";
4985 }
4986
5004 public function printObjectLine($action, $line, $var, $num, $i, $dateSelector, $seller, $buyer, $selected = 0, $extrafields = null, $defaulttpldir = '/core/tpl')
5005 {
5006 global $conf, $langs, $user, $object, $hookmanager;
5007 global $form;
5008 global $object_rights, $disableedit, $disablemove, $disableremove; // TODO We should not use global var for this !
5009
5010 $object_rights = $this->getRights();
5011
5012 $text = '';
5013 $description = '';
5014
5015 // Line in view mode
5016 if ($action != 'editline' || $selected != $line->id) {
5017 // Product
5018 if (!empty($line->fk_product) && $line->fk_product > 0) {
5019 $product_static = new Product($this->db);
5020 $product_static->fetch($line->fk_product);
5021
5022 $product_static->ref = $line->ref; //can change ref in hook
5023 $product_static->label = !empty($line->label) ? $line->label : ""; //can change label in hook
5024
5025 $text = $product_static->getNomUrl(1);
5026
5027 // Define output language and label
5028 if (getDolGlobalInt('MAIN_MULTILANGS')) {
5029 if (property_exists($this, 'socid') && !is_object($this->thirdparty)) {
5030 dol_print_error('', 'Error: Method printObjectLine was called on an object and object->fetch_thirdparty was not done before');
5031 return;
5032 }
5033
5034 $prod = new Product($this->db);
5035 $prod->fetch($line->fk_product);
5036
5037 $outputlangs = $langs;
5038 $newlang = '';
5039 if (empty($newlang) && GETPOST('lang_id', 'aZ09')) {
5040 $newlang = GETPOST('lang_id', 'aZ09');
5041 }
5042 if (!empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE) && empty($newlang) && is_object($this->thirdparty)) {
5043 $newlang = $this->thirdparty->default_lang; // To use language of customer
5044 }
5045 if (!empty($newlang)) {
5046 $outputlangs = new Translate("", $conf);
5047 $outputlangs->setDefaultLang($newlang);
5048 }
5049
5050 $label = (!empty($prod->multilangs[$outputlangs->defaultlang]["label"])) ? $prod->multilangs[$outputlangs->defaultlang]["label"] : $line->product_label;
5051 } else {
5052 $label = $line->product_label;
5053 }
5054
5055 $text .= ' - '.(!empty($line->label) ? $line->label : $label);
5056 $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.
5057 }
5058
5059 $line->pu_ttc = price2num((!empty($line->subprice) ? $line->subprice : 0) * (1 + ((!empty($line->tva_tx) ? $line->tva_tx : 0) / 100)), 'MU');
5060
5061 // Output template part (modules that overwrite templates must declare this into descriptor)
5062 // Use global variables + $dateSelector + $seller and $buyer
5063 // Note: This is deprecated. If you need to overwrite the tpl file, use instead the hook printObjectLine and printObjectSubLine.
5064 $dirtpls = array_merge($conf->modules_parts['tpl'], array($defaulttpldir));
5065 foreach ($dirtpls as $module => $reldir) {
5066 $res = 0;
5067 if (!empty($module)) {
5068 $tpl = dol_buildpath($reldir.'/objectline_view.tpl.php');
5069 } else {
5070 $tpl = DOL_DOCUMENT_ROOT.$reldir.'/objectline_view.tpl.php';
5071 }
5072 if (file_exists($tpl)) {
5073 if (empty($conf->file->strict_mode)) {
5074 $res = @include $tpl;
5075 } else {
5076 $res = include $tpl; // for debug
5077 }
5078 }
5079 if ($res) {
5080 break;
5081 }
5082 }
5083 }
5084
5085 // Line in update mode
5086 if ($this->statut == 0 && $action == 'editline' && $selected == $line->id) {
5087 $label = (!empty($line->label) ? $line->label : (($line->fk_product > 0) ? $line->product_label : ''));
5088
5089 $line->pu_ttc = price2num($line->subprice * (1 + ($line->tva_tx / 100)), 'MU');
5090
5091 // Output template part (modules that overwrite templates must declare this into descriptor)
5092 // Use global variables + $dateSelector + $seller and $buyer
5093 // Note: This is deprecated. If you need to overwrite the tpl file, use instead the hook printObjectLine and printObjectSubLine.
5094 $dirtpls = array_merge($conf->modules_parts['tpl'], array($defaulttpldir));
5095 foreach ($dirtpls as $module => $reldir) {
5096 if (!empty($module)) {
5097 $tpl = dol_buildpath($reldir.'/objectline_edit.tpl.php');
5098 } else {
5099 $tpl = DOL_DOCUMENT_ROOT.$reldir.'/objectline_edit.tpl.php';
5100 }
5101
5102 if (empty($conf->file->strict_mode)) {
5103 $res = @include $tpl;
5104 } else {
5105 $res = include $tpl; // for debug
5106 }
5107 if ($res) {
5108 break;
5109 }
5110 }
5111 }
5112 }
5113
5114
5115 /* This is to show array of line of details of source object */
5116
5117
5128 public function printOriginLinesList($restrictlist = '', $selectedLines = array())
5129 {
5130 global $langs, $hookmanager, $conf, $form, $action;
5131
5132 print '<tr class="liste_titre">';
5133 print '<td class="linecolref">'.$langs->trans('Ref').'</td>';
5134 print '<td class="linecoldescription">'.$langs->trans('Description').'</td>';
5135 print '<td class="linecolvat right">'.$langs->trans('VATRate').'</td>';
5136 print '<td class="linecoluht right">'.$langs->trans('PriceUHT').'</td>';
5137 if (isModEnabled("multicurrency")) {
5138 print '<td class="linecoluht_currency right">'.$langs->trans('PriceUHTCurrency').'</td>';
5139 }
5140 print '<td class="linecolqty right">'.$langs->trans('Qty').'</td>';
5141 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
5142 print '<td class="linecoluseunit left">'.$langs->trans('Unit').'</td>';
5143 }
5144 print '<td class="linecoldiscount right">'.$langs->trans('ReductionShort').'</td>';
5145 print '<td class="linecolht right">'.$langs->trans('TotalHT').'</td>';
5146 print '<td class="center">'.$form->showCheckAddButtons('checkforselect', 1).'</td>';
5147 print '</tr>';
5148 $i = 0;
5149
5150 if (!empty($this->lines)) {
5151 foreach ($this->lines as $line) {
5152 $reshook = 0;
5153 //if (is_object($hookmanager) && (($line->product_type == 9 && !empty($line->special_code)) || !empty($line->fk_parent_line))) {
5154 if (is_object($hookmanager)) { // Old code is commented on preceding line.
5155 $parameters = array('line'=>$line, 'i'=>$i, 'restrictlist'=>$restrictlist, 'selectedLines'=> $selectedLines);
5156 if (!empty($line->fk_parent_line)) { $parameters['fk_parent_line'] = $line->fk_parent_line; }
5157 $reshook = $hookmanager->executeHooks('printOriginObjectLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
5158 }
5159 if (empty($reshook)) {
5160 $this->printOriginLine($line, '', $restrictlist, '/core/tpl', $selectedLines);
5161 }
5162
5163 $i++;
5164 }
5165 }
5166 }
5167
5181 public function printOriginLine($line, $var, $restrictlist = '', $defaulttpldir = '/core/tpl', $selectedLines = array())
5182 {
5183 global $langs, $conf;
5184
5185 //var_dump($line);
5186 if (!empty($line->date_start)) {
5187 $date_start = $line->date_start;
5188 } else {
5189 $date_start = $line->date_debut_prevue;
5190 if ($line->date_debut_reel) {
5191 $date_start = $line->date_debut_reel;
5192 }
5193 }
5194 if (!empty($line->date_end)) {
5195 $date_end = $line->date_end;
5196 } else {
5197 $date_end = $line->date_fin_prevue;
5198 if ($line->date_fin_reel) {
5199 $date_end = $line->date_fin_reel;
5200 }
5201 }
5202
5203 $this->tpl['id'] = $line->id;
5204
5205 $this->tpl['label'] = '';
5206 if (!empty($line->fk_parent_line)) {
5207 $this->tpl['label'] .= img_picto('', 'rightarrow');
5208 }
5209
5210 if (($line->info_bits & 2) == 2) { // TODO Not sure this is used for source object
5211 $discount = new DiscountAbsolute($this->db);
5212 $discount->fk_soc = $this->socid;
5213 $this->tpl['label'] .= $discount->getNomUrl(0, 'discount');
5214 } elseif (!empty($line->fk_product)) {
5215 if (empty($line->product)) {
5216 $line->fetch_product();
5217 }
5218 $productstatic = $line->product;
5219
5220 $this->tpl['label'] .= (is_object($productstatic) ? $productstatic->getNomUrl(1) : $line->ref);
5221 $this->tpl['label'] .= ' - '.(!empty($line->label) ? $line->label : $line->product_label);
5222 // Dates
5223 if ($line->product_type == 1 && ($date_start || $date_end)) {
5224 $this->tpl['label'] .= get_date_range($date_start, $date_end);
5225 }
5226 } else {
5227 $this->tpl['label'] .= ($line->product_type == -1 ? '&nbsp;' : ($line->product_type == 1 ? img_object($langs->trans(''), 'service') : img_object($langs->trans(''), 'product')));
5228 if (!empty($line->desc)) {
5229 $this->tpl['label'] .= $line->desc;
5230 } else {
5231 $this->tpl['label'] .= ($line->label ? '&nbsp;'.$line->label : '');
5232 }
5233
5234 // Dates
5235 if ($line->product_type == 1 && ($date_start || $date_end)) {
5236 $this->tpl['label'] .= get_date_range($date_start, $date_end);
5237 }
5238 }
5239
5240 if (!empty($line->desc)) {
5241 if ($line->desc == '(CREDIT_NOTE)') { // TODO Not sure this is used for source object
5242 $discount = new DiscountAbsolute($this->db);
5243 $discount->fetch($line->fk_remise_except);
5244 $this->tpl['description'] = $langs->transnoentities("DiscountFromCreditNote", $discount->getNomUrl(0));
5245 } elseif ($line->desc == '(DEPOSIT)') { // TODO Not sure this is used for source object
5246 $discount = new DiscountAbsolute($this->db);
5247 $discount->fetch($line->fk_remise_except);
5248 $this->tpl['description'] = $langs->transnoentities("DiscountFromDeposit", $discount->getNomUrl(0));
5249 } elseif ($line->desc == '(EXCESS RECEIVED)') {
5250 $discount = new DiscountAbsolute($this->db);
5251 $discount->fetch($line->fk_remise_except);
5252 $this->tpl['description'] = $langs->transnoentities("DiscountFromExcessReceived", $discount->getNomUrl(0));
5253 } elseif ($line->desc == '(EXCESS PAID)') {
5254 $discount = new DiscountAbsolute($this->db);
5255 $discount->fetch($line->fk_remise_except);
5256 $this->tpl['description'] = $langs->transnoentities("DiscountFromExcessPaid", $discount->getNomUrl(0));
5257 } else {
5258 $this->tpl['description'] = dol_trunc($line->desc, 60);
5259 }
5260 } else {
5261 $this->tpl['description'] = '&nbsp;';
5262 }
5263
5264 // VAT Rate
5265 $this->tpl['vat_rate'] = vatrate($line->tva_tx, true);
5266 $this->tpl['vat_rate'] .= (($line->info_bits & 1) == 1) ? '*' : '';
5267 if (!empty($line->vat_src_code) && !preg_match('/\‍(/', $this->tpl['vat_rate'])) {
5268 $this->tpl['vat_rate'] .= ' ('.$line->vat_src_code.')';
5269 }
5270
5271 $this->tpl['price'] = price($line->subprice);
5272 $this->tpl['total_ht'] = price($line->total_ht);
5273 $this->tpl['multicurrency_price'] = price($line->multicurrency_subprice);
5274 $this->tpl['qty'] = (($line->info_bits & 2) != 2) ? $line->qty : '&nbsp;';
5275 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
5276 $this->tpl['unit'] = $langs->transnoentities($line->getLabelOfUnit('long'));
5277 }
5278 $this->tpl['remise_percent'] = (($line->info_bits & 2) != 2) ? vatrate($line->remise_percent, true) : '&nbsp;';
5279
5280 // Is the line strike or not
5281 $this->tpl['strike'] = 0;
5282 if ($restrictlist == 'services' && $line->product_type != Product::TYPE_SERVICE) {
5283 $this->tpl['strike'] = 1;
5284 }
5285
5286 // Output template part (modules that overwrite templates must declare this into descriptor)
5287 // Use global variables + $dateSelector + $seller and $buyer
5288 $dirtpls = array_merge($conf->modules_parts['tpl'], array($defaulttpldir));
5289 foreach ($dirtpls as $module => $reldir) {
5290 if (!empty($module)) {
5291 $tpl = dol_buildpath($reldir.'/originproductline.tpl.php');
5292 } else {
5293 $tpl = DOL_DOCUMENT_ROOT.$reldir.'/originproductline.tpl.php';
5294 }
5295
5296 if (empty($conf->file->strict_mode)) {
5297 $res = @include $tpl;
5298 } else {
5299 $res = include $tpl; // for debug
5300 }
5301 if ($res) {
5302 break;
5303 }
5304 }
5305 }
5306
5307
5308 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5319 public function add_element_resource($resource_id, $resource_type, $busy = 0, $mandatory = 0)
5320 {
5321 // phpcs:enable
5322 $this->db->begin();
5323
5324 $sql = "INSERT INTO ".$this->db->prefix()."element_resources (";
5325 $sql .= "resource_id";
5326 $sql .= ", resource_type";
5327 $sql .= ", element_id";
5328 $sql .= ", element_type";
5329 $sql .= ", busy";
5330 $sql .= ", mandatory";
5331 $sql .= ") VALUES (";
5332 $sql .= ((int) $resource_id);
5333 $sql .= ", '".$this->db->escape($resource_type)."'";
5334 $sql .= ", '".$this->db->escape($this->id)."'";
5335 $sql .= ", '".$this->db->escape($this->element)."'";
5336 $sql .= ", '".$this->db->escape($busy)."'";
5337 $sql .= ", '".$this->db->escape($mandatory)."'";
5338 $sql .= ")";
5339
5340 dol_syslog(get_class($this)."::add_element_resource", LOG_DEBUG);
5341 if ($this->db->query($sql)) {
5342 $this->db->commit();
5343 return 1;
5344 } else {
5345 $this->error = $this->db->lasterror();
5346 $this->db->rollback();
5347 return 0;
5348 }
5349 }
5350
5351 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5360 public function delete_resource($rowid, $element, $notrigger = 0)
5361 {
5362 // phpcs:enable
5363 global $user;
5364
5365 $this->db->begin();
5366
5367 $sql = "DELETE FROM ".$this->db->prefix()."element_resources";
5368 $sql .= " WHERE rowid = ".((int) $rowid);
5369
5370 dol_syslog(get_class($this)."::delete_resource", LOG_DEBUG);
5371
5372 $resql = $this->db->query($sql);
5373 if (!$resql) {
5374 $this->error = $this->db->lasterror();
5375 $this->db->rollback();
5376 return -1;
5377 } else {
5378 if (!$notrigger) {
5379 $result = $this->call_trigger(strtoupper($element).'_DELETE_RESOURCE', $user);
5380 if ($result < 0) {
5381 $this->db->rollback();
5382 return -1;
5383 }
5384 }
5385 $this->db->commit();
5386 return 1;
5387 }
5388 }
5389
5390
5396 public function __clone()
5397 {
5398 // Force a copy of this->lines, otherwise it will point to same object.
5399 if (isset($this->lines) && is_array($this->lines)) {
5400 $nboflines = count($this->lines);
5401 for ($i = 0; $i < $nboflines; $i++) {
5402 if (is_object($this->lines[$i])) {
5403 $this->lines[$i] = clone $this->lines[$i];
5404 }
5405 }
5406 }
5407 }
5408
5422 protected function commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams = null)
5423 {
5424 global $conf, $langs, $user, $hookmanager, $action;
5425
5426 $srctemplatepath = '';
5427
5428 $parameters = array('modelspath'=>$modelspath, 'modele'=>$modele, 'outputlangs'=>$outputlangs, 'hidedetails'=>$hidedetails, 'hidedesc'=>$hidedesc, 'hideref'=>$hideref, 'moreparams'=>$moreparams);
5429 $reshook = $hookmanager->executeHooks('commonGenerateDocument', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
5430
5431 if (!empty($reshook)) {
5432 return $reshook;
5433 }
5434
5435 dol_syslog("commonGenerateDocument modele=".$modele." outputlangs->defaultlang=".(is_object($outputlangs) ? $outputlangs->defaultlang : 'null'));
5436
5437 if (empty($modele)) {
5438 $this->error = 'BadValueForParameterModele';
5439 return -1;
5440 }
5441
5442 // Increase limit for PDF build
5443 $err = error_reporting();
5444 error_reporting(0);
5445 @set_time_limit(120);
5446 error_reporting($err);
5447
5448 // If selected model is a filename template (then $modele="modelname" or "modelname:filename")
5449 $tmp = explode(':', $modele, 2);
5450 if (!empty($tmp[1])) {
5451 $modele = $tmp[0];
5452 $srctemplatepath = $tmp[1];
5453 }
5454
5455 // Search template files
5456 $file = '';
5457 $classname = '';
5458 $filefound = '';
5459 $dirmodels = array('/');
5460 if (is_array($conf->modules_parts['models'])) {
5461 $dirmodels = array_merge($dirmodels, $conf->modules_parts['models']);
5462 }
5463 foreach ($dirmodels as $reldir) {
5464 foreach (array('doc', 'pdf') as $prefix) {
5465 if (in_array(get_class($this), array('Adherent'))) {
5466 // Member module use prefix_modele.class.php
5467 $file = $prefix."_".$modele.".class.php";
5468 } else {
5469 // Other module use prefix_modele.modules.php
5470 $file = $prefix."_".$modele.".modules.php";
5471 }
5472
5473 // On verifie l'emplacement du modele
5474 $file = dol_buildpath($reldir.$modelspath.$file, 0);
5475 if (file_exists($file)) {
5476 $filefound = $file;
5477 $classname = $prefix.'_'.$modele;
5478 break;
5479 }
5480 }
5481 if ($filefound) {
5482 break;
5483 }
5484 }
5485
5486 if (!$filefound) {
5487 $this->error = $langs->trans("Error").' Failed to load doc generator with modelpaths='.$modelspath.' - modele='.$modele;
5488 $this->errors[] = $this->error;
5489 dol_syslog($this->error, LOG_ERR);
5490 return -1;
5491 }
5492
5493 // If generator was found
5494 global $db; // Required to solve a conception default making an include of code using $db instead of $this->db just after.
5495
5496 require_once $file;
5497
5498 $obj = new $classname($this->db);
5499
5500 // If generator is ODT, we must have srctemplatepath defined, if not we set it.
5501 if ($obj->type == 'odt' && empty($srctemplatepath)) {
5502 $varfortemplatedir = $obj->scandir;
5503 if ($varfortemplatedir && !empty($conf->global->$varfortemplatedir)) {
5504 $dirtoscan = $conf->global->$varfortemplatedir;
5505
5506 $listoffiles = array();
5507
5508 // Now we add first model found in directories scanned
5509 $listofdir = explode(',', $dirtoscan);
5510 foreach ($listofdir as $key => $tmpdir) {
5511 $tmpdir = trim($tmpdir);
5512 $tmpdir = preg_replace('/DOL_DATA_ROOT/', DOL_DATA_ROOT, $tmpdir);
5513 if (!$tmpdir) {
5514 unset($listofdir[$key]);
5515 continue;
5516 }
5517 if (is_dir($tmpdir)) {
5518 $tmpfiles = dol_dir_list($tmpdir, 'files', 0, '\.od(s|t)$', '', 'name', SORT_ASC, 0);
5519 if (count($tmpfiles)) {
5520 $listoffiles = array_merge($listoffiles, $tmpfiles);
5521 }
5522 }
5523 }
5524
5525 if (count($listoffiles)) {
5526 foreach ($listoffiles as $record) {
5527 $srctemplatepath = $record['fullname'];
5528 break;
5529 }
5530 }
5531 }
5532
5533 if (empty($srctemplatepath)) {
5534 $this->error = 'ErrorGenerationAskedForOdtTemplateWithSrcFileNotDefined';
5535 return -1;
5536 }
5537 }
5538
5539 if ($obj->type == 'odt' && !empty($srctemplatepath)) {
5540 if (!dol_is_file($srctemplatepath)) {
5541 dol_syslog("Failed to locate template file ".$srctemplatepath, LOG_WARNING);
5542 $this->error = 'ErrorGenerationAskedForOdtTemplateWithSrcFileNotFound';
5543 return -1;
5544 }
5545 }
5546
5547 // We save charset_output to restore it because write_file can change it if needed for
5548 // output format that does not support UTF8.
5549 $sav_charset_output = empty($outputlangs->charset_output) ? '' : $outputlangs->charset_output;
5550
5551 if (in_array(get_class($this), array('Adherent'))) {
5552 $resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, 'member', 1, 'tmp_cards', $moreparams);
5553 } else {
5554 $resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, $hidedetails, $hidedesc, $hideref, $moreparams);
5555 }
5556 // After call of write_file $obj->result['fullpath'] is set with generated file. It will be used to update the ECM database index.
5557
5558 if ($resultwritefile > 0) {
5559 $outputlangs->charset_output = $sav_charset_output;
5560
5561 // We delete old preview
5562 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
5563 dol_delete_preview($this);
5564
5565 // Index file in database
5566 if (!empty($obj->result['fullpath'])) {
5567 $destfull = $obj->result['fullpath'];
5568
5569 // Update the last_main_doc field into main object (if document generator has property ->update_main_doc_field set)
5570 $update_main_doc_field = 0;
5571 if (!empty($obj->update_main_doc_field)) {
5572 $update_main_doc_field = 1;
5573 }
5574
5575 // Check that the file exists, before indexing it.
5576 // Hint: It does not exist, if we create a PDF and auto delete the ODT File
5577 if (dol_is_file($destfull)) {
5578 $this->indexFile($destfull, $update_main_doc_field);
5579 }
5580 } else {
5581 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);
5582 }
5583
5584 // Success in building document. We build meta file.
5585 dol_meta_create($this);
5586
5587 return 1;
5588 } else {
5589 $outputlangs->charset_output = $sav_charset_output;
5590 $this->error = $obj->error;
5591 $this->errors = $obj->errors;
5592 dol_syslog("Error generating document for ".__CLASS__.". Error: ".$obj->error, LOG_ERR);
5593 return -1;
5594 }
5595 }
5596
5606 public function indexFile($destfull, $update_main_doc_field)
5607 {
5608 global $conf, $user;
5609
5610 $upload_dir = dirname($destfull);
5611 $destfile = basename($destfull);
5612 $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $upload_dir);
5613
5614 if (!preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir)) { // If not a tmp dir
5615 $filename = basename($destfile);
5616 $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
5617 $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
5618
5619 include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
5620 $ecmfile = new EcmFiles($this->db);
5621 $result = $ecmfile->fetch(0, '', ($rel_dir ? $rel_dir.'/' : '').$filename);
5622
5623 // Set the public "share" key
5624 $setsharekey = false;
5625 if ($this->element == 'propal' || $this->element == 'proposal') {
5626 if (!isset($conf->global->PROPOSAL_ALLOW_ONLINESIGN) || !empty($conf->global->PROPOSAL_ALLOW_ONLINESIGN)) {
5627 $setsharekey = true; // feature to make online signature is not set or set to on (default)
5628 }
5629 if (!empty($conf->global->PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD)) {
5630 $setsharekey = true;
5631 }
5632 }
5633 if ($this->element == 'commande' && !empty($conf->global->ORDER_ALLOW_EXTERNAL_DOWNLOAD)) {
5634 $setsharekey = true;
5635 }
5636 if ($this->element == 'facture' && !empty($conf->global->INVOICE_ALLOW_EXTERNAL_DOWNLOAD)) {
5637 $setsharekey = true;
5638 }
5639 if ($this->element == 'bank_account' && !empty($conf->global->BANK_ACCOUNT_ALLOW_EXTERNAL_DOWNLOAD)) {
5640 $setsharekey = true;
5641 }
5642 if ($this->element == 'product' && !empty($conf->global->PRODUCT_ALLOW_EXTERNAL_DOWNLOAD)) {
5643 $setsharekey = true;
5644 }
5645 if ($this->element == 'contrat' && !empty($conf->global->CONTRACT_ALLOW_EXTERNAL_DOWNLOAD)) {
5646 $setsharekey = true;
5647 }
5648 if ($this->element == 'fichinter' && !empty($conf->global->FICHINTER_ALLOW_EXTERNAL_DOWNLOAD)) {
5649 $setsharekey = true;
5650 }
5651 if ($this->element == 'supplier_proposal' && !empty($conf->global->SUPPLIER_PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD)) {
5652 $setsharekey = true;
5653 }
5654
5655 if ($setsharekey) {
5656 if (empty($ecmfile->share)) { // Because object not found or share not set yet
5657 require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
5658 $ecmfile->share = getRandomPassword(true);
5659 }
5660 }
5661
5662 if ($result > 0) {
5663 $ecmfile->label = md5_file(dol_osencode($destfull)); // hash of file content
5664 $ecmfile->fullpath_orig = '';
5665 $ecmfile->gen_or_uploaded = 'generated';
5666 $ecmfile->description = ''; // indexed content
5667 $ecmfile->keywords = ''; // keyword content
5668 $result = $ecmfile->update($user);
5669 if ($result < 0) {
5670 setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
5671 return -1;
5672 }
5673 } else {
5674 $ecmfile->entity = $conf->entity;
5675 $ecmfile->filepath = $rel_dir;
5676 $ecmfile->filename = $filename;
5677 $ecmfile->label = md5_file(dol_osencode($destfull)); // hash of file content
5678 $ecmfile->fullpath_orig = '';
5679 $ecmfile->gen_or_uploaded = 'generated';
5680 $ecmfile->description = ''; // indexed content
5681 $ecmfile->keywords = ''; // keyword content
5682 $ecmfile->src_object_type = $this->table_element; // $this->table_name is 'myobject' or 'mymodule_myobject'.
5683 $ecmfile->src_object_id = $this->id;
5684
5685 $result = $ecmfile->create($user);
5686 if ($result < 0) {
5687 setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
5688 return -1;
5689 }
5690 }
5691
5692 /*$this->result['fullname']=$destfull;
5693 $this->result['filepath']=$ecmfile->filepath;
5694 $this->result['filename']=$ecmfile->filename;*/
5695 //var_dump($obj->update_main_doc_field);exit;
5696
5697 if ($update_main_doc_field && !empty($this->table_element)) {
5698 $sql = "UPDATE ".$this->db->prefix().$this->table_element." SET last_main_doc = '".$this->db->escape($ecmfile->filepath."/".$ecmfile->filename)."'";
5699 $sql .= " WHERE rowid = ".((int) $this->id);
5700
5701 $resql = $this->db->query($sql);
5702 if (!$resql) {
5703 dol_print_error($this->db);
5704 return -1;
5705 } else {
5706 $this->last_main_doc = $ecmfile->filepath.'/'.$ecmfile->filename;
5707 }
5708 }
5709 }
5710
5711 return 1;
5712 }
5713
5721 public function addThumbs($file)
5722 {
5723 $file_osencoded = dol_osencode($file);
5724
5725 if (file_exists($file_osencoded)) {
5726 require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
5727
5728 $tmparraysize = getDefaultImageSizes();
5729 $maxwidthsmall = $tmparraysize['maxwidthsmall'];
5730 $maxheightsmall = $tmparraysize['maxheightsmall'];
5731 $maxwidthmini = $tmparraysize['maxwidthmini'];
5732 $maxheightmini = $tmparraysize['maxheightmini'];
5733 //$quality = $tmparraysize['quality'];
5734 $quality = 50; // For thumbs, we force quality to 50
5735
5736 // Create small thumbs for company (Ratio is near 16/9)
5737 // Used on logon for example
5738 vignette($file_osencoded, $maxwidthsmall, $maxheightsmall, '_small', $quality);
5739
5740 // Create mini thumbs for company (Ratio is near 16/9)
5741 // Used on menu or for setup page for example
5742 vignette($file_osencoded, $maxwidthmini, $maxheightmini, '_mini', $quality);
5743 }
5744 }
5745
5753 public function delThumbs($file)
5754 {
5755 $imgThumbName = getImageFileNameForSize($file, '_small'); // Full path of thumb file
5756 dol_delete_file($imgThumbName);
5757 $imgThumbName = getImageFileNameForSize($file, '_mini'); // Full path of thumb file
5758 dol_delete_file($imgThumbName);
5759 }
5760
5761
5762 /* Functions common to commonobject and commonobjectline */
5763
5764 /* For default values */
5765
5779 public function getDefaultCreateValueFor($fieldname, $alternatevalue = null, $type = 'alphanohtml')
5780 {
5781 global $conf, $_POST;
5782
5783 // If param here has been posted, we use this value first.
5784 if (GETPOSTISSET($fieldname)) {
5785 return GETPOST($fieldname, $type, 3);
5786 }
5787
5788 if (isset($alternatevalue)) {
5789 return $alternatevalue;
5790 }
5791
5792 $newelement = $this->element;
5793 if ($newelement == 'facture') {
5794 $newelement = 'invoice';
5795 }
5796 if ($newelement == 'commande') {
5797 $newelement = 'order';
5798 }
5799 if (empty($newelement)) {
5800 dol_syslog("Ask a default value using common method getDefaultCreateValueForField on an object with no property ->element defined. Return empty string.", LOG_WARNING);
5801 return '';
5802 }
5803
5804 $keyforfieldname = strtoupper($newelement.'_DEFAULT_'.$fieldname);
5805 //var_dump($keyforfieldname);
5806 if (isset($conf->global->$keyforfieldname)) {
5807 return $conf->global->$keyforfieldname;
5808 }
5809
5810 // TODO Ad here a scan into table llx_overwrite_default with a filter on $this->element and $fieldname
5811 // store content into $conf->cache['overwrite_default']
5812
5813 return '';
5814 }
5815
5816
5817 /* For triggers */
5818
5819
5820 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5831 public function call_trigger($triggerName, $user)
5832 {
5833 // phpcs:enable
5834 global $langs, $conf;
5835 if (!empty(self::TRIGGER_PREFIX) && strpos($triggerName, self::TRIGGER_PREFIX . '_') !== 0) {
5836 dol_print_error('', 'The trigger "' . $triggerName . '" does not start with "' . self::TRIGGER_PREFIX . '_" as required.');
5837 exit;
5838 }
5839 if (!is_object($langs)) { // If lang was not defined, we set it. It is required by run_triggers.
5840 include_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php';
5841 $langs = new Translate('', $conf);
5842 }
5843
5844 include_once DOL_DOCUMENT_ROOT.'/core/class/interfaces.class.php';
5845 $interface = new Interfaces($this->db);
5846 $result = $interface->run_triggers($triggerName, $this, $user, $langs, $conf);
5847
5848 if ($result < 0) {
5849 if (!empty($this->errors)) {
5850 $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.
5851 } else {
5852 $this->errors = $interface->errors;
5853 }
5854 }
5855 return $result;
5856 }
5857
5858
5859 /* Functions for data in other language */
5860
5861
5870 {
5871 // To avoid SQL errors. Probably not the better solution though
5872 if (!$this->element) {
5873 return 0;
5874 }
5875 if (!($this->id > 0)) {
5876 return 0;
5877 }
5878 if (is_array($this->array_languages)) {
5879 return 1;
5880 }
5881
5882 $this->array_languages = array();
5883
5884 $element = $this->element;
5885 if ($element == 'categorie') {
5886 $element = 'categories'; // For compatibility
5887 }
5888
5889 // Request to get translation values for object
5890 $sql = "SELECT rowid, property, lang , value";
5891 $sql .= " FROM ".$this->db->prefix()."object_lang";
5892 $sql .= " WHERE type_object = '".$this->db->escape($element)."'";
5893 $sql .= " AND fk_object = ".((int) $this->id);
5894
5895 //dol_syslog(get_class($this)."::fetch_optionals get extrafields data for ".$this->table_element, LOG_DEBUG); // Too verbose
5896 $resql = $this->db->query($sql);
5897 if ($resql) {
5898 $numrows = $this->db->num_rows($resql);
5899 if ($numrows) {
5900 $i = 0;
5901 while ($i < $numrows) {
5902 $obj = $this->db->fetch_object($resql);
5903 $key = $obj->property;
5904 $value = $obj->value;
5905 $codelang = $obj->lang;
5906 $type = $this->fields[$key]['type'];
5907
5908 // we can add this attribute to object
5909 if (preg_match('/date/', $type)) {
5910 $this->array_languages[$key][$codelang] = $this->db->jdate($value);
5911 } else {
5912 $this->array_languages[$key][$codelang] = $value;
5913 }
5914
5915 $i++;
5916 }
5917 }
5918
5919 $this->db->free($resql);
5920
5921 if ($numrows) {
5922 return $numrows;
5923 } else {
5924 return 0;
5925 }
5926 } else {
5927 dol_print_error($this->db);
5928 return -1;
5929 }
5930 }
5931
5938 public function setValuesForExtraLanguages($onlykey = '')
5939 {
5940 global $_POST, $langs;
5941
5942 // Get extra fields
5943 foreach ($_POST as $postfieldkey => $postfieldvalue) {
5944 $tmparray = explode('-', $postfieldkey);
5945 if ($tmparray[0] != 'field') {
5946 continue;
5947 }
5948
5949 $element = $tmparray[1];
5950 $key = $tmparray[2];
5951 $codelang = $tmparray[3];
5952 //var_dump("postfieldkey=".$postfieldkey." element=".$element." key=".$key." codelang=".$codelang);
5953
5954 if (!empty($onlykey) && $key != $onlykey) {
5955 continue;
5956 }
5957 if ($element != $this->element) {
5958 continue;
5959 }
5960
5961 $key_type = $this->fields[$key]['type'];
5962
5963 $enabled = 1;
5964 if (isset($this->fields[$key]['enabled'])) {
5965 $enabled = dol_eval($this->fields[$key]['enabled'], 1, 1, '1');
5966 }
5967 /*$perms = 1;
5968 if (isset($this->fields[$key]['perms']))
5969 {
5970 $perms = dol_eval($this->fields[$key]['perms'], 1, 1, '1');
5971 }*/
5972 if (empty($enabled)) {
5973 continue;
5974 }
5975 //if (empty($perms)) continue;
5976
5977 if (in_array($key_type, array('date'))) {
5978 // Clean parameters
5979 // TODO GMT date in memory must be GMT so we should add gm=true in parameters
5980 $value_key = dol_mktime(0, 0, 0, GETPOST($postfieldkey."month", 'int'), GETPOST($postfieldkey."day", 'int'), GETPOST($postfieldkey."year", 'int'));
5981 } elseif (in_array($key_type, array('datetime'))) {
5982 // Clean parameters
5983 // TODO GMT date in memory must be GMT so we should add gm=true in parameters
5984 $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'));
5985 } elseif (in_array($key_type, array('checkbox', 'chkbxlst'))) {
5986 $value_arr = GETPOST($postfieldkey, 'array'); // check if an array
5987 if (!empty($value_arr)) {
5988 $value_key = implode(',', $value_arr);
5989 } else {
5990 $value_key = '';
5991 }
5992 } elseif (in_array($key_type, array('price', 'double'))) {
5993 $value_arr = GETPOST($postfieldkey, 'alpha');
5994 $value_key = price2num($value_arr);
5995 } else {
5996 $value_key = GETPOST($postfieldkey);
5997 if (in_array($key_type, array('link')) && $value_key == '-1') {
5998 $value_key = '';
5999 }
6000 }
6001
6002 $this->array_languages[$key][$codelang] = $value_key;
6003
6004 /*if ($nofillrequired) {
6005 $langs->load('errors');
6006 setEventMessages($langs->trans('ErrorFieldsRequired').' : '.implode(', ', $error_field_required), null, 'errors');
6007 return -1;
6008 }*/
6009 }
6010
6011 return 1;
6012 }
6013
6014
6015 /* Functions for extrafields */
6016
6023 public function fetchNoCompute($id)
6024 {
6025 global $conf;
6026
6027 $savDisableCompute = $conf->disable_compute;
6028 $conf->disable_compute = 1;
6029
6030 $ret = $this->fetch($id);
6031
6032 $conf->disable_compute = $savDisableCompute;
6033
6034 return $ret;
6035 }
6036
6037 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6047 public function fetch_optionals($rowid = null, $optionsArray = null)
6048 {
6049 // phpcs:enable
6050 global $conf, $extrafields;
6051
6052 if (empty($rowid)) {
6053 $rowid = $this->id;
6054 }
6055 if (empty($rowid) && isset($this->rowid)) {
6056 $rowid = $this->rowid; // deprecated
6057 }
6058
6059 // To avoid SQL errors. Probably not the better solution though
6060 if (!$this->table_element) {
6061 return 0;
6062 }
6063
6064 $this->array_options = array();
6065
6066 if (!is_array($optionsArray)) {
6067 // If $extrafields is not a known object, we initialize it. Best practice is to have $extrafields defined into card.php or list.php page.
6068 if (!isset($extrafields) || !is_object($extrafields)) {
6069 require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
6070 $extrafields = new ExtraFields($this->db);
6071 }
6072
6073 // Load array of extrafields for elementype = $this->table_element
6074 if (empty($extrafields->attributes[$this->table_element]['loaded'])) {
6075 $extrafields->fetch_name_optionals_label($this->table_element);
6076 }
6077 $optionsArray = (!empty($extrafields->attributes[$this->table_element]['label']) ? $extrafields->attributes[$this->table_element]['label'] : null);
6078 } else {
6079 global $extrafields;
6080 dol_syslog("Warning: fetch_optionals was called with param optionsArray defined when you should pass null now", LOG_WARNING);
6081 }
6082
6083 $table_element = $this->table_element;
6084 if ($table_element == 'categorie') {
6085 $table_element = 'categories'; // For compatibility
6086 }
6087
6088 // Request to get complementary values
6089 if (is_array($optionsArray) && count($optionsArray) > 0) {
6090 $sql = "SELECT rowid";
6091 foreach ($optionsArray as $name => $label) {
6092 if (empty($extrafields->attributes[$this->table_element]['type'][$name]) || $extrafields->attributes[$this->table_element]['type'][$name] != 'separate') {
6093 $sql .= ", ".$name;
6094 }
6095 }
6096 $sql .= " FROM ".$this->db->prefix().$table_element."_extrafields";
6097 $sql .= " WHERE fk_object = ".((int) $rowid);
6098
6099 //dol_syslog(get_class($this)."::fetch_optionals get extrafields data for ".$this->table_element, LOG_DEBUG); // Too verbose
6100 $resql = $this->db->query($sql);
6101 if ($resql) {
6102 $numrows = $this->db->num_rows($resql);
6103 if ($numrows) {
6104 $tab = $this->db->fetch_array($resql);
6105
6106 foreach ($tab as $key => $value) {
6107 // 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)
6108 if ($key != 'rowid' && $key != 'tms' && $key != 'fk_member' && !is_int($key)) {
6109 // we can add this attribute to object
6110 if (!empty($extrafields->attributes[$this->table_element]) && in_array($extrafields->attributes[$this->table_element]['type'][$key], array('date', 'datetime'))) {
6111 //var_dump($extrafields->attributes[$this->table_element]['type'][$key]);
6112 $this->array_options["options_".$key] = $this->db->jdate($value);
6113 } else {
6114 $this->array_options["options_".$key] = $value;
6115 }
6116
6117 //var_dump('key '.$key.' '.$value.' type='.$extrafields->attributes[$this->table_element]['type'][$key].' '.$this->array_options["options_".$key]);
6118 }
6119 }
6120 }
6121
6122 // If field is a computed field, value must become result of compute (regardless of whether a row exists
6123 // in the element's extrafields table)
6124 if (is_array($extrafields->attributes[$this->table_element]['label'])) {
6125 foreach ($extrafields->attributes[$this->table_element]['label'] as $key => $val) {
6126 if (!empty($extrafields->attributes[$this->table_element]) && !empty($extrafields->attributes[$this->table_element]['computed'][$key])) {
6127 //var_dump($conf->disable_compute);
6128 if (empty($conf->disable_compute)) {
6129 global $objectoffield; // We set a global variable to $objectoffield so
6130 $objectoffield = $this; // we can use it inside computed formula
6131 $this->array_options['options_' . $key] = dol_eval($extrafields->attributes[$this->table_element]['computed'][$key], 1, 0, '');
6132 }
6133 }
6134 }
6135 }
6136
6137 $this->db->free($resql);
6138
6139 if ($numrows) {
6140 return $numrows;
6141 } else {
6142 return 0;
6143 }
6144 } else {
6145 $this->errors[]=$this->db->lasterror;
6146 return -1;
6147 }
6148 }
6149 return 0;
6150 }
6151
6158 public function deleteExtraFields()
6159 {
6160 global $conf;
6161
6162 if (!empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) {
6163 return 0;
6164 }
6165
6166 $this->db->begin();
6167
6168 $table_element = $this->table_element;
6169 if ($table_element == 'categorie') {
6170 $table_element = 'categories'; // For compatibility
6171 }
6172
6173 dol_syslog(get_class($this)."::deleteExtraFields delete", LOG_DEBUG);
6174
6175 $sql_del = "DELETE FROM ".$this->db->prefix().$table_element."_extrafields WHERE fk_object = ".((int) $this->id);
6176
6177 $resql = $this->db->query($sql_del);
6178 if (!$resql) {
6179 $this->error = $this->db->lasterror();
6180 $this->db->rollback();
6181 return -1;
6182 } else {
6183 $this->db->commit();
6184 return 1;
6185 }
6186 }
6187
6198 public function insertExtraFields($trigger = '', $userused = null)
6199 {
6200 global $conf, $langs, $user;
6201
6202 if (!empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) {
6203 return 0;
6204 }
6205
6206 if (empty($userused)) {
6207 $userused = $user;
6208 }
6209
6210 $error = 0;
6211
6212 if (!empty($this->array_options)) {
6213 // Check parameters
6214 $langs->load('admin');
6215 require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
6216 $extrafields = new ExtraFields($this->db);
6217 $target_extrafields = $extrafields->fetch_name_optionals_label($this->table_element);
6218
6219 // Eliminate copied source object extra fields that do not exist in target object
6220 $new_array_options = array();
6221 foreach ($this->array_options as $key => $value) {
6222 if (in_array(substr($key, 8), array_keys($target_extrafields))) { // We remove the 'options_' from $key for test
6223 $new_array_options[$key] = $value;
6224 } elseif (in_array($key, array_keys($target_extrafields))) { // We test on $key that does not contain the 'options_' prefix
6225 $new_array_options['options_'.$key] = $value;
6226 }
6227 }
6228
6229 foreach ($new_array_options as $key => $value) {
6230 $attributeKey = substr($key, 8); // Remove 'options_' prefix
6231 $attributeType = $extrafields->attributes[$this->table_element]['type'][$attributeKey];
6232 $attributeLabel = $langs->transnoentities($extrafields->attributes[$this->table_element]['label'][$attributeKey]);
6233 $attributeParam = $extrafields->attributes[$this->table_element]['param'][$attributeKey];
6234 $attributeRequired = $extrafields->attributes[$this->table_element]['required'][$attributeKey];
6235 $attributeUnique = $extrafields->attributes[$this->table_element]['unique'][$attributeKey];
6236 $attrfieldcomputed = $extrafields->attributes[$this->table_element]['computed'][$attributeKey];
6237
6238 // If we clone, we have to clean unique extrafields to prevent duplicates.
6239 // This behaviour can be prevented by external code by changing $this->context['createfromclone'] value in createFrom hook
6240 if (!empty($this->context['createfromclone']) && $this->context['createfromclone'] == 'createfromclone' && !empty($attributeUnique)) {
6241 $new_array_options[$key] = null;
6242 }
6243
6244 // Similar code than into insertExtraFields
6245 if ($attributeRequired) {
6246 $mandatorypb = false;
6247 if ($attributeType == 'link' && $this->array_options[$key] == '-1') {
6248 $mandatorypb = true;
6249 }
6250 if ($this->array_options[$key] === '') {
6251 $mandatorypb = true;
6252 }
6253 if ($attributeType == 'sellist' && $this->array_options[$key] == '0') {
6254 $mandatorypb = true;
6255 }
6256 if ($mandatorypb) {
6257 $langs->load("errors");
6258 dol_syslog("Mandatory field '".$key."' is empty during create and set to required into definition of extrafields");
6259 $this->errors[] = $langs->trans('ErrorFieldRequired', $attributeLabel);
6260 return -1;
6261 }
6262 }
6263
6264 //dol_syslog("attributeLabel=".$attributeLabel, LOG_DEBUG);
6265 //dol_syslog("attributeType=".$attributeType, LOG_DEBUG);
6266
6267 if (!empty($attrfieldcomputed)) {
6268 if (!empty($conf->global->MAIN_STORE_COMPUTED_EXTRAFIELDS)) {
6269 $value = dol_eval($attrfieldcomputed, 1, 0, '');
6270 dol_syslog($langs->trans("Extrafieldcomputed")." sur ".$attributeLabel."(".$value.")", LOG_DEBUG);
6271 $new_array_options[$key] = $value;
6272 } else {
6273 $new_array_options[$key] = null;
6274 }
6275 }
6276
6277 switch ($attributeType) {
6278 case 'int':
6279 if (!is_numeric($value) && $value != '') {
6280 $this->errors[] = $langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
6281 return -1;
6282 } elseif ($value == '') {
6283 $new_array_options[$key] = null;
6284 }
6285 break;
6286 case 'price':
6287 case 'double':
6288 $value = price2num($value);
6289 if (!is_numeric($value) && $value != '') {
6290 dol_syslog($langs->trans("ExtraFieldHasWrongValue")." for ".$attributeLabel."(".$value."is not '".$attributeType."')", LOG_DEBUG);
6291 $this->errors[] = $langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
6292 return -1;
6293 } elseif ($value == '') {
6294 $value = null;
6295 }
6296 //dol_syslog("double value"." sur ".$attributeLabel."(".$value." is '".$attributeType."')", LOG_DEBUG);
6297 $new_array_options[$key] = $value;
6298 break;
6299 /*case 'select': // Not required, we chosed value='0' for undefined values
6300 if ($value=='-1')
6301 {
6302 $this->array_options[$key] = null;
6303 }
6304 break;*/
6305 case 'password':
6306 $algo = '';
6307 if ($this->array_options[$key] != '' && is_array($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options'])) {
6308 // If there is an encryption choice, we use it to crypt data before insert
6309 $tmparrays = array_keys($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options']);
6310 $algo = reset($tmparrays);
6311 if ($algo != '') {
6312 //global $action; // $action may be 'create', 'update', 'update_extras'...
6313 //var_dump($action);
6314 //var_dump($this->oldcopy);exit;
6315 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
6316 //var_dump($this->oldcopy->array_options[$key]); var_dump($this->array_options[$key]);
6317 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.
6318 $new_array_options[$key] = $this->array_options[$key]; // Value is kept
6319 } else {
6320 // var_dump($algo);
6321 $newvalue = dol_hash($this->array_options[$key], $algo);
6322 $new_array_options[$key] = $newvalue;
6323 }
6324 } else {
6325 $new_array_options[$key] = $this->array_options[$key]; // Value is kept
6326 }
6327 }
6328 } else // Common usage
6329 {
6330 $new_array_options[$key] = $this->array_options[$key];
6331 }
6332 break;
6333 case 'date':
6334 case 'datetime':
6335 // If data is a string instead of a timestamp, we convert it
6336 if (!is_numeric($this->array_options[$key]) || $this->array_options[$key] != intval($this->array_options[$key])) {
6337 $this->array_options[$key] = strtotime($this->array_options[$key]);
6338 }
6339 $new_array_options[$key] = $this->db->idate($this->array_options[$key]);
6340 break;
6341 case 'datetimegmt':
6342 // If data is a string instead of a timestamp, we convert it
6343 if (!is_numeric($this->array_options[$key]) || $this->array_options[$key] != intval($this->array_options[$key])) {
6344 $this->array_options[$key] = strtotime($this->array_options[$key]);
6345 }
6346 $new_array_options[$key] = $this->db->idate($this->array_options[$key], 'gmt');
6347 break;
6348 case 'link':
6349 $param_list = array_keys($attributeParam['options']);
6350 // 0 : ObjectName
6351 // 1 : classPath
6352 $InfoFieldList = explode(":", $param_list[0]);
6353 dol_include_once($InfoFieldList[1]);
6354 if ($InfoFieldList[0] && class_exists($InfoFieldList[0])) {
6355 if ($value == '-1') { // -1 is key for no defined in combo list of objects
6356 $new_array_options[$key] = '';
6357 } elseif ($value) {
6358 $object = new $InfoFieldList[0]($this->db);
6359 if (is_numeric($value)) {
6360 $res = $object->fetch($value); // Common case
6361 } else {
6362 $res = $object->fetch('', $value); // For compatibility
6363 }
6364
6365 if ($res > 0) {
6366 $new_array_options[$key] = $object->id;
6367 } else {
6368 $this->error = "Id/Ref '".$value."' for object '".$object->element."' not found";
6369 return -1;
6370 }
6371 }
6372 } else {
6373 dol_syslog('Error bad setup of extrafield', LOG_WARNING);
6374 }
6375 break;
6376 case 'checkbox':
6377 case 'chkbxlst':
6378 if (is_array($this->array_options[$key])) {
6379 $new_array_options[$key] = implode(',', $this->array_options[$key]);
6380 } else {
6381 $new_array_options[$key] = $this->array_options[$key];
6382 }
6383 break;
6384 }
6385 }
6386
6387 $this->db->begin();
6388
6389 $table_element = $this->table_element;
6390 if ($table_element == 'categorie') {
6391 $table_element = 'categories'; // For compatibility
6392 }
6393
6394 dol_syslog(get_class($this)."::insertExtraFields delete then insert", LOG_DEBUG);
6395
6396 $sql_del = "DELETE FROM ".$this->db->prefix().$table_element."_extrafields WHERE fk_object = ".((int) $this->id);
6397 $this->db->query($sql_del);
6398
6399 $sql = "INSERT INTO ".$this->db->prefix().$table_element."_extrafields (fk_object";
6400 foreach ($new_array_options as $key => $value) {
6401 $attributeKey = substr($key, 8); // Remove 'options_' prefix
6402 // Add field of attribut
6403 if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] != 'separate') { // Only for other type than separator
6404 $sql .= ",".$attributeKey;
6405 }
6406 }
6407 // We must insert a default value for fields for other entities that are mandatory to avoid not null error
6408 if (!empty($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities']) && is_array($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities'])) {
6409 foreach ($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities'] as $tmpkey => $tmpval) {
6410 if (!isset($extrafields->attributes[$this->table_element]['type'][$tmpkey])) { // If field not already added previously
6411 $sql .= ",".$tmpkey;
6412 }
6413 }
6414 }
6415 $sql .= ") VALUES (".$this->id;
6416
6417 foreach ($new_array_options as $key => $value) {
6418 $attributeKey = substr($key, 8); // Remove 'options_' prefix
6419 // Add field of attribute
6420 if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] != 'separate') { // Only for other type than separator)
6421 if ($new_array_options[$key] != '' || $new_array_options[$key] == '0') {
6422 $sql .= ",'".$this->db->escape($new_array_options[$key])."'";
6423 } else {
6424 $sql .= ",null";
6425 }
6426 }
6427 }
6428 // We must insert a default value for fields for other entities that are mandatory to avoid not null error
6429 if (!empty($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities']) && is_array($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities'])) {
6430 foreach ($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities'] as $tmpkey => $tmpval) {
6431 if (!isset($extrafields->attributes[$this->table_element]['type'][$tmpkey])) { // If field not already added previously
6432 if (in_array($tmpval, array('int', 'double', 'price'))) {
6433 $sql .= ", 0";
6434 } else {
6435 $sql .= ", ''";
6436 }
6437 }
6438 }
6439 }
6440
6441 $sql .= ")";
6442
6443 $resql = $this->db->query($sql);
6444 if (!$resql) {
6445 $this->error = $this->db->lasterror();
6446 $error++;
6447 }
6448
6449 if (!$error && $trigger) {
6450 // Call trigger
6451 $this->context = array('extrafieldaddupdate'=>1);
6452 $result = $this->call_trigger($trigger, $userused);
6453 if ($result < 0) {
6454 $error++;
6455 }
6456 // End call trigger
6457 }
6458
6459 if ($error) {
6460 $this->db->rollback();
6461 return -1;
6462 } else {
6463 $this->db->commit();
6464 return 1;
6465 }
6466 } else {
6467 return 0;
6468 }
6469 }
6470
6481 public function insertExtraLanguages($trigger = '', $userused = null)
6482 {
6483 global $conf, $langs, $user;
6484
6485 if (empty($userused)) {
6486 $userused = $user;
6487 }
6488
6489 $error = 0;
6490
6491 if (!empty($conf->global->MAIN_EXTRALANGUAGES_DISABLED)) {
6492 return 0; // For avoid conflicts if trigger used
6493 }
6494
6495 if (is_array($this->array_languages)) {
6496 $new_array_languages = $this->array_languages;
6497
6498 foreach ($new_array_languages as $key => $value) {
6499 $attributeKey = $key;
6500 $attributeType = $this->fields[$attributeKey]['type'];
6501 $attributeLabel = $this->fields[$attributeKey]['label'];
6502
6503 //dol_syslog("attributeLabel=".$attributeLabel, LOG_DEBUG);
6504 //dol_syslog("attributeType=".$attributeType, LOG_DEBUG);
6505
6506 switch ($attributeType) {
6507 case 'int':
6508 if (!is_numeric($value) && $value != '') {
6509 $this->errors[] = $langs->trans("ExtraLanguageHasWrongValue", $attributeLabel);
6510 return -1;
6511 } elseif ($value == '') {
6512 $new_array_languages[$key] = null;
6513 }
6514 break;
6515 case 'double':
6516 $value = price2num($value);
6517 if (!is_numeric($value) && $value != '') {
6518 dol_syslog($langs->trans("ExtraLanguageHasWrongValue")." sur ".$attributeLabel."(".$value."is not '".$attributeType."')", LOG_DEBUG);
6519 $this->errors[] = $langs->trans("ExtraLanguageHasWrongValue", $attributeLabel);
6520 return -1;
6521 } elseif ($value == '') {
6522 $new_array_languages[$key] = null;
6523 } else {
6524 $new_array_languages[$key] = $value;
6525 }
6526 break;
6527 /*case 'select': // Not required, we chosed value='0' for undefined values
6528 if ($value=='-1')
6529 {
6530 $this->array_options[$key] = null;
6531 }
6532 break;*/
6533 }
6534 }
6535
6536 $this->db->begin();
6537
6538 $table_element = $this->table_element;
6539 if ($table_element == 'categorie') {
6540 $table_element = 'categories'; // For compatibility
6541 }
6542
6543 dol_syslog(get_class($this)."::insertExtraLanguages delete then insert", LOG_DEBUG);
6544
6545 foreach ($new_array_languages as $key => $langcodearray) { // $key = 'name', 'town', ...
6546 foreach ($langcodearray as $langcode => $value) {
6547 $sql_del = "DELETE FROM ".$this->db->prefix()."object_lang";
6548 $sql_del .= " WHERE fk_object = ".((int) $this->id)." AND property = '".$this->db->escape($key)."' AND type_object = '".$this->db->escape($table_element)."'";
6549 $sql_del .= " AND lang = '".$this->db->escape($langcode)."'";
6550 $this->db->query($sql_del);
6551
6552 if ($value !== '') {
6553 $sql = "INSERT INTO ".$this->db->prefix()."object_lang (fk_object, property, type_object, lang, value";
6554 $sql .= ") VALUES (".$this->id.", '".$this->db->escape($key)."', '".$this->db->escape($table_element)."', '".$this->db->escape($langcode)."', '".$this->db->escape($value)."'";
6555 $sql .= ")";
6556
6557 $resql = $this->db->query($sql);
6558 if (!$resql) {
6559 $this->error = $this->db->lasterror();
6560 $error++;
6561 break;
6562 }
6563 }
6564 }
6565 }
6566
6567 if (!$error && $trigger) {
6568 // Call trigger
6569 $this->context = array('extralanguagesaddupdate'=>1);
6570 $result = $this->call_trigger($trigger, $userused);
6571 if ($result < 0) {
6572 $error++;
6573 }
6574 // End call trigger
6575 }
6576
6577 if ($error) {
6578 $this->db->rollback();
6579 return -1;
6580 } else {
6581 $this->db->commit();
6582 return 1;
6583 }
6584 } else {
6585 return 0;
6586 }
6587 }
6588
6599 public function updateExtraField($key, $trigger = null, $userused = null)
6600 {
6601 global $conf, $langs, $user;
6602
6603 if (!empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) {
6604 return 0;
6605 }
6606
6607 if (empty($userused)) {
6608 $userused = $user;
6609 }
6610
6611 $error = 0;
6612
6613 if (!empty($this->array_options) && isset($this->array_options["options_".$key])) {
6614 // Check parameters
6615 $langs->load('admin');
6616 require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
6617 $extrafields = new ExtraFields($this->db);
6618 $extrafields->fetch_name_optionals_label($this->table_element);
6619
6620 $value = $this->array_options["options_".$key];
6621
6622 $attributeType = $extrafields->attributes[$this->table_element]['type'][$key];
6623 $attributeLabel = $extrafields->attributes[$this->table_element]['label'][$key];
6624 $attributeParam = $extrafields->attributes[$this->table_element]['param'][$key];
6625 $attributeRequired = $extrafields->attributes[$this->table_element]['required'][$key];
6626 $attrfieldcomputed = $extrafields->attributes[$this->table_element]['computed'][$key];
6627
6628 // Similar code than into insertExtraFields
6629 if ($attributeRequired) {
6630 $mandatorypb = false;
6631 if ($attributeType == 'link' && $this->array_options["options_".$key] == '-1') {
6632 $mandatorypb = true;
6633 }
6634 if ($this->array_options["options_".$key] === '') {
6635 $mandatorypb = true;
6636 }
6637 if ($mandatorypb) {
6638 $langs->load("errors");
6639 dol_syslog("Mandatory field 'options_".$key."' is empty during update and set to required into definition of extrafields");
6640 $this->errors[] = $langs->trans('ErrorFieldRequired', $attributeLabel);
6641 return -1;
6642 }
6643 }
6644
6645 //dol_syslog("attributeLabel=".$attributeLabel, LOG_DEBUG);
6646 //dol_syslog("attributeType=".$attributeType, LOG_DEBUG);
6647
6648 if (!empty($attrfieldcomputed)) {
6649 if (!empty($conf->global->MAIN_STORE_COMPUTED_EXTRAFIELDS)) {
6650 $value = dol_eval($attrfieldcomputed, 1, 0, '');
6651 dol_syslog($langs->trans("Extrafieldcomputed")." sur ".$attributeLabel."(".$value.")", LOG_DEBUG);
6652 $this->array_options["options_".$key] = $value;
6653 } else {
6654 $this->array_options["options_".$key] = null;
6655 }
6656 }
6657
6658 switch ($attributeType) {
6659 case 'int':
6660 if (!is_numeric($value) && $value != '') {
6661 $this->errors[] = $langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
6662 return -1;
6663 } elseif ($value === '') {
6664 $this->array_options["options_".$key] = null;
6665 }
6666 break;
6667 case 'price':
6668 case 'double':
6669 $value = price2num($value);
6670 if (!is_numeric($value) && $value != '') {
6671 dol_syslog($langs->trans("ExtraFieldHasWrongValue")." sur ".$attributeLabel."(".$value."is not '".$attributeType."')", LOG_DEBUG);
6672 $this->errors[] = $langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
6673 return -1;
6674 } elseif ($value === '') {
6675 $value = null;
6676 }
6677 //dol_syslog("double value"." sur ".$attributeLabel."(".$value." is '".$attributeType."')", LOG_DEBUG);
6678 $this->array_options["options_".$key] = $value;
6679 break;
6680 /*case 'select': // Not required, we chosed value='0' for undefined values
6681 if ($value=='-1')
6682 {
6683 $this->array_options[$key] = null;
6684 }
6685 break;*/
6686 case 'date':
6687 case 'datetime':
6688 if (empty($this->array_options["options_".$key])) {
6689 $this->array_options["options_".$key] = null;
6690 } else {
6691 $this->array_options["options_".$key] = $this->db->idate($this->array_options["options_".$key]);
6692 }
6693 break;
6694 case 'datetimegmt':
6695 if (empty($this->array_options["options_".$key])) {
6696 $this->array_options["options_".$key] = null;
6697 } else {
6698 $this->array_options["options_".$key] = $this->db->idate($this->array_options["options_".$key], 'gmt');
6699 }
6700 break;
6701 case 'boolean':
6702 if (empty($this->array_options["options_".$key])) {
6703 $this->array_options["options_".$key] = null;
6704 }
6705 break;
6706 case 'link':
6707 if ($this->array_options["options_".$key] === '') {
6708 $this->array_options["options_".$key] = null;
6709 }
6710 break;
6711 /*
6712 case 'link':
6713 $param_list = array_keys($attributeParam['options']);
6714 // 0 : ObjectName
6715 // 1 : classPath
6716 $InfoFieldList = explode(":", $param_list[0]);
6717 dol_include_once($InfoFieldList[1]);
6718 if ($InfoFieldList[0] && class_exists($InfoFieldList[0]))
6719 {
6720 if ($value == '-1') // -1 is key for no defined in combo list of objects
6721 {
6722 $new_array_options[$key] = '';
6723 } elseif ($value) {
6724 $object = new $InfoFieldList[0]($this->db);
6725 if (is_numeric($value)) $res = $object->fetch($value); // Common case
6726 else $res = $object->fetch('', $value); // For compatibility
6727
6728 if ($res > 0) $new_array_options[$key] = $object->id;
6729 else {
6730 $this->error = "Id/Ref '".$value."' for object '".$object->element."' not found";
6731 $this->db->rollback();
6732 return -1;
6733 }
6734 }
6735 } else {
6736 dol_syslog('Error bad setup of extrafield', LOG_WARNING);
6737 }
6738 break;
6739 */
6740 case 'checkbox':
6741 case 'chkbxlst':
6742 if (is_array($this->array_options[$key])) {
6743 $new_array_options[$key] = implode(',', $this->array_options[$key]);
6744 } else {
6745 $new_array_options[$key] = $this->array_options[$key];
6746 }
6747 break;
6748 }
6749
6750 $this->db->begin();
6751
6752 $linealreadyfound = 0;
6753
6754 // 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)
6755 $sql = "SELECT COUNT(rowid) as nb FROM ".$this->db->prefix().$this->table_element."_extrafields WHERE fk_object = ".((int) $this->id);
6756 $resql = $this->db->query($sql);
6757 if ($resql) {
6758 $tmpobj = $this->db->fetch_object($resql);
6759 if ($tmpobj) {
6760 $linealreadyfound = $tmpobj->nb;
6761 }
6762 }
6763
6764 if ($linealreadyfound) {
6765 if ($this->array_options["options_".$key] === null) {
6766 $sql = "UPDATE ".$this->db->prefix().$this->table_element."_extrafields SET ".$key." = null";
6767 } else {
6768 $sql = "UPDATE ".$this->db->prefix().$this->table_element."_extrafields SET ".$key." = '".$this->db->escape($this->array_options["options_".$key])."'";
6769 }
6770 $sql .= " WHERE fk_object = ".((int) $this->id);
6771 } else {
6772 $result = $this->insertExtraFields('', $user);
6773 if ($result < 0) {
6774 $error++;
6775 }
6776 }
6777
6778 $resql = $this->db->query($sql);
6779 if (!$resql) {
6780 $error++;
6781 $this->error = $this->db->lasterror();
6782 }
6783 if (!$error && $trigger) {
6784 // Call trigger
6785 $this->context = array('extrafieldupdate'=>1);
6786 $result = $this->call_trigger($trigger, $userused);
6787 if ($result < 0) {
6788 $error++;
6789 }
6790 // End call trigger
6791 }
6792
6793 if ($error) {
6794 dol_syslog(__METHOD__.$this->error, LOG_ERR);
6795 $this->db->rollback();
6796 return -1;
6797 } else {
6798 $this->db->commit();
6799 return 1;
6800 }
6801 } else {
6802 return 0;
6803 }
6804 }
6805
6816 public function updateExtraLanguages($key, $trigger = null, $userused = null)
6817 {
6818 global $conf, $langs, $user;
6819
6820 if (empty($userused)) {
6821 $userused = $user;
6822 }
6823
6824 $error = 0;
6825
6826 if (!empty($conf->global->MAIN_EXTRALANGUAGES_DISABLED)) {
6827 return 0; // For avoid conflicts if trigger used
6828 }
6829
6830 return 0;
6831 }
6832
6833
6848 public function showInputField($val, $key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = 0, $nonewbutton = 0)
6849 {
6850 global $conf, $langs, $form;
6851
6852 if (!is_object($form)) {
6853 require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
6854 $form = new Form($this->db);
6855 }
6856
6857 if (!empty($this->fields)) {
6858 $val = $this->fields[$key];
6859 }
6860
6861 // Validation tests and output
6862 $fieldValidationErrorMsg = '';
6863 $validationClass = '';
6864 $fieldValidationErrorMsg = $this->getFieldError($key);
6865 if (!empty($fieldValidationErrorMsg)) {
6866 $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
6867 } else {
6868 $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
6869 }
6870
6871 $out = '';
6872 $type = '';
6873 $isDependList = 0;
6874 $param = array();
6875 $param['options'] = array();
6876 $reg = array();
6877 $size = !empty($this->fields[$key]['size']) ? $this->fields[$key]['size'] : 0;
6878 // Because we work on extrafields
6879 if (preg_match('/^(integer|link):(.*):(.*):(.*):(.*)/i', $val['type'], $reg)) {
6880 $param['options'] = array($reg[2].':'.$reg[3].':'.$reg[4].':'.$reg[5] => 'N');
6881 $type = 'link';
6882 } elseif (preg_match('/^(integer|link):(.*):(.*):(.*)/i', $val['type'], $reg)) {
6883 $param['options'] = array($reg[2].':'.$reg[3].':'.$reg[4] => 'N');
6884 $type = 'link';
6885 } elseif (preg_match('/^(integer|link):(.*):(.*)/i', $val['type'], $reg)) {
6886 $param['options'] = array($reg[2].':'.$reg[3] => 'N');
6887 $type = 'link';
6888 } elseif (preg_match('/^(sellist):(.*):(.*):(.*):(.*)/i', $val['type'], $reg)) {
6889 $param['options'] = array($reg[2].':'.$reg[3].':'.$reg[4].':'.$reg[5] => 'N');
6890 $type = 'sellist';
6891 } elseif (preg_match('/^(sellist):(.*):(.*):(.*)/i', $val['type'], $reg)) {
6892 $param['options'] = array($reg[2].':'.$reg[3].':'.$reg[4] => 'N');
6893 $type = 'sellist';
6894 } elseif (preg_match('/^(sellist):(.*):(.*)/i', $val['type'], $reg)) {
6895 $param['options'] = array($reg[2].':'.$reg[3] => 'N');
6896 $type = 'sellist';
6897 } elseif (preg_match('/^chkbxlst:(.*)/i', $val['type'], $reg)) {
6898 $param['options'] = array($reg[1] => 'N');
6899 $type = 'chkbxlst';
6900 } elseif (preg_match('/varchar\‍((\d+)\‍)/', $val['type'], $reg)) {
6901 $param['options'] = array();
6902 $type = 'varchar';
6903 $size = $reg[1];
6904 } elseif (preg_match('/varchar/', $val['type'])) {
6905 $param['options'] = array();
6906 $type = 'varchar';
6907 } else {
6908 $param['options'] = array();
6909 $type = $this->fields[$key]['type'];
6910 }
6911
6912 // Special case that force options and type ($type can be integer, varchar, ...)
6913 if (!empty($this->fields[$key]['arrayofkeyval']) && is_array($this->fields[$key]['arrayofkeyval'])) {
6914 $param['options'] = $this->fields[$key]['arrayofkeyval'];
6915 $type = 'select';
6916 }
6917
6918 $label = $this->fields[$key]['label'];
6919 //$elementtype=$this->fields[$key]['elementtype']; // Seems not used
6920 $default = (!empty($this->fields[$key]['default']) ? $this->fields[$key]['default'] : '');
6921 $computed = (!empty($this->fields[$key]['computed']) ? $this->fields[$key]['computed'] : '');
6922 $unique = (!empty($this->fields[$key]['unique']) ? $this->fields[$key]['unique'] : 0);
6923 $required = (!empty($this->fields[$key]['required']) ? $this->fields[$key]['required'] : 0);
6924 $autofocusoncreate = (!empty($this->fields[$key]['autofocusoncreate']) ? $this->fields[$key]['autofocusoncreate'] : 0);
6925
6926 $langfile = (!empty($this->fields[$key]['langfile']) ? $this->fields[$key]['langfile'] : '');
6927 $list = (!empty($this->fields[$key]['list']) ? $this->fields[$key]['list'] : 0);
6928 $hidden = (in_array(abs($this->fields[$key]['visible']), array(0, 2)) ? 1 : 0);
6929
6930 $objectid = $this->id;
6931
6932 if ($computed) {
6933 if (!preg_match('/^search_/', $keyprefix)) {
6934 return '<span class="opacitymedium">'.$langs->trans("AutomaticallyCalculated").'</span>';
6935 } else {
6936 return '';
6937 }
6938 }
6939
6940 // Set value of $morecss. For this, we use in priority showsize from parameters, then $val['css'] then autodefine
6941 if (empty($morecss) && !empty($val['css'])) {
6942 $morecss = $val['css'];
6943 } elseif (empty($morecss)) {
6944 if ($type == 'date') {
6945 $morecss = 'minwidth100imp';
6946 } elseif ($type == 'datetime' || $type == 'link') { // link means an foreign key to another primary id
6947 $morecss = 'minwidth200imp';
6948 } elseif (in_array($type, array('int', 'integer', 'price')) || preg_match('/^double(\‍([0-9],[0-9]\‍)){0,1}/', $type)) {
6949 $morecss = 'maxwidth75';
6950 } elseif ($type == 'url') {
6951 $morecss = 'minwidth400';
6952 } elseif ($type == 'boolean') {
6953 $morecss = '';
6954 } else {
6955 if (round($size) < 12) {
6956 $morecss = 'minwidth100';
6957 } elseif (round($size) <= 48) {
6958 $morecss = 'minwidth200';
6959 } else {
6960 $morecss = 'minwidth400';
6961 }
6962 }
6963 }
6964
6965 // Add validation state class
6966 if (!empty($validationClass)) {
6967 $morecss.= $validationClass;
6968 }
6969
6970 if (in_array($type, array('date'))) {
6971 $tmp = explode(',', $size);
6972 $newsize = $tmp[0];
6973 $showtime = 0;
6974
6975 // Do not show current date when field not required (see selectDate() method)
6976 if (!$required && $value == '') {
6977 $value = '-1';
6978 }
6979
6980 // TODO Must also support $moreparam
6981 $out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1);
6982 } elseif (in_array($type, array('datetime'))) {
6983 $tmp = explode(',', $size);
6984 $newsize = $tmp[0];
6985 $showtime = 1;
6986
6987 // Do not show current date when field not required (see selectDate() method)
6988 if (!$required && $value == '') $value = '-1';
6989
6990 // TODO Must also support $moreparam
6991 $out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1, '', '', '', 1, '', '', 'tzuserrel');
6992 } elseif (in_array($type, array('duration'))) {
6993 $out = $form->select_duration($keyprefix.$key.$keysuffix, $value, 0, 'text', 0, 1);
6994 } elseif (in_array($type, array('int', 'integer'))) {
6995 $tmp = explode(',', $size);
6996 $newsize = $tmp[0];
6997 $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' : '').'>';
6998 } elseif (in_array($type, array('real'))) {
6999 $out = '<input type="text" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'"'.($moreparam ? $moreparam : '').($autofocusoncreate ? ' autofocus' : '').'>';
7000 } elseif (preg_match('/varchar/', $type)) {
7001 $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' : '').'>';
7002 } elseif (in_array($type, array('email', 'mail', 'phone', 'url', 'ip'))) {
7003 $out = '<input type="text" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').($autofocusoncreate ? ' autofocus' : '').'>';
7004 } elseif (preg_match('/^text/', $type)) {
7005 if (!preg_match('/search_/', $keyprefix)) { // If keyprefix is search_ or search_options_, we must just use a simple text field
7006 require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
7007 $doleditor = new DolEditor($keyprefix.$key.$keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, false, ROWS_5, '90%');
7008 $out = $doleditor->Create(1);
7009 } else {
7010 $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').'>';
7011 }
7012 } elseif (preg_match('/^html/', $type)) {
7013 if (!preg_match('/search_/', $keyprefix)) { // If keyprefix is search_ or search_options_, we must just use a simple text field
7014 require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
7015 $doleditor = new DolEditor($keyprefix.$key.$keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, isModEnabled('fckeditor') && $conf->global->FCKEDITOR_ENABLE_SOCIETE, ROWS_5, '90%');
7016 $out = $doleditor->Create(1, '', true, '', '', $moreparam, $morecss);
7017 } else {
7018 $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').'>';
7019 }
7020 } elseif ($type == 'boolean') {
7021 $checked = '';
7022 if (!empty($value)) {
7023 $checked = ' checked value="1" ';
7024 } else {
7025 $checked = ' value="1" ';
7026 }
7027 $out = '<input type="checkbox" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.$checked.' '.($moreparam ? $moreparam : '').'>';
7028 } elseif ($type == 'price') {
7029 if (!empty($value)) { // $value in memory is a php numeric, we format it into user number format.
7030 $value = price($value);
7031 }
7032 $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam ? $moreparam : '').'> '.$langs->getCurrencySymbol($conf->currency);
7033 } elseif (preg_match('/^double(\‍([0-9],[0-9]\‍)){0,1}/', $type)) {
7034 if (!empty($value)) { // $value in memory is a php numeric, we format it into user number format.
7035 $value = price($value);
7036 }
7037 $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam ? $moreparam : '').'> ';
7038 } elseif ($type == 'select') { // combo list
7039 $out = '';
7040 if (!empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_EXTRAFIELDS_DISABLE_SELECT2)) {
7041 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7042 $out .= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
7043 }
7044
7045 $out .= '<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam ? $moreparam : '').'>';
7046 if ((!isset($this->fields[$key]['default'])) || empty($this->fields[$key]['notnull']) || ($this->fields[$key]['notnull'] != 1)) {
7047 $out .= '<option value="0">&nbsp;</option>';
7048 }
7049 foreach ($param['options'] as $keyb => $valb) {
7050 if ((string) $keyb == '') {
7051 continue;
7052 }
7053 if (strpos($valb, "|") !== false) {
7054 list($valb, $parent) = explode('|', $valb);
7055 }
7056 $out .= '<option value="'.$keyb.'"';
7057 $out .= (((string) $value == (string) $keyb) ? ' selected' : '');
7058 $out .= (!empty($parent) ? ' parent="'.$parent.'"' : '');
7059 $out .= '>'.$valb.'</option>';
7060 }
7061 $out .= '</select>';
7062 } elseif ($type == 'sellist') {
7063 $out = '';
7064 if (!empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_EXTRAFIELDS_DISABLE_SELECT2)) {
7065 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7066 $out .= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
7067 }
7068
7069 $out .= '<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam ? $moreparam : '').'>';
7070 if (is_array($param['options'])) {
7071 $param_list = array_keys($param['options']);
7072 $InfoFieldList = explode(":", $param_list[0]);
7073 $parentName = '';
7074 $parentField = '';
7075 // 0 : tableName
7076 // 1 : label field name
7077 // 2 : key fields name (if differ of rowid)
7078 // 3 : key field parent (for dependent lists)
7079 // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
7080 // 5 : id category type
7081 // 6 : ids categories list separated by comma for category root
7082 $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2].' as rowid');
7083
7084 if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
7085 if (strpos($InfoFieldList[4], 'extra.') !== false) {
7086 $keyList = 'main.'.$InfoFieldList[2].' as rowid';
7087 } else {
7088 $keyList = $InfoFieldList[2].' as rowid';
7089 }
7090 }
7091 if (count($InfoFieldList) > 3 && !empty($InfoFieldList[3])) {
7092 list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
7093 $keyList .= ', '.$parentField;
7094 }
7095
7096 $filter_categorie = false;
7097 if (count($InfoFieldList) > 5) {
7098 if ($InfoFieldList[0] == 'categorie') {
7099 $filter_categorie = true;
7100 }
7101 }
7102
7103 if ($filter_categorie === false) {
7104 $fields_label = explode('|', $InfoFieldList[1]);
7105 if (is_array($fields_label)) {
7106 $keyList .= ', ';
7107 $keyList .= implode(', ', $fields_label);
7108 }
7109
7110 $sqlwhere = '';
7111 $sql = "SELECT " . $keyList;
7112 $sql .= " FROM " . $this->db->prefix() . $InfoFieldList[0];
7113 if (!empty($InfoFieldList[4])) {
7114 // can use SELECT request
7115 if (strpos($InfoFieldList[4], '$SEL$') !== false) {
7116 $InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]);
7117 }
7118
7119 // current object id can be use into filter
7120 if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) {
7121 $InfoFieldList[4] = str_replace('$ID$', $objectid, $InfoFieldList[4]);
7122 } else {
7123 $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
7124 }
7125
7126 //We have to join on extrafield table
7127 if (strpos($InfoFieldList[4], 'extra') !== false) {
7128 $sql .= " as main, " . $this->db->prefix() . $InfoFieldList[0] . "_extrafields as extra";
7129 $sqlwhere .= " WHERE extra.fk_object=main." . $InfoFieldList[2] . " AND " . $InfoFieldList[4];
7130 } else {
7131 $sqlwhere .= " WHERE " . $InfoFieldList[4];
7132 }
7133 } else {
7134 $sqlwhere .= ' WHERE 1=1';
7135 }
7136 // Some tables may have field, some other not. For the moment we disable it.
7137 if (in_array($InfoFieldList[0], array('tablewithentity'))) {
7138 $sqlwhere .= " AND entity = " . ((int) $conf->entity);
7139 }
7140 $sql .= $sqlwhere;
7141 //print $sql;
7142
7143 $sql .= ' ORDER BY ' . implode(', ', $fields_label);
7144
7145 dol_syslog(get_class($this) . '::showInputField type=sellist', LOG_DEBUG);
7146 $resql = $this->db->query($sql);
7147 if ($resql) {
7148 $out .= '<option value="0">&nbsp;</option>';
7149 $num = $this->db->num_rows($resql);
7150 $i = 0;
7151 while ($i < $num) {
7152 $labeltoshow = '';
7153 $obj = $this->db->fetch_object($resql);
7154
7155 // Several field into label (eq table:code|libelle:rowid)
7156 $notrans = false;
7157 $fields_label = explode('|', $InfoFieldList[1]);
7158 if (count($fields_label) > 1) {
7159 $notrans = true;
7160 foreach ($fields_label as $field_toshow) {
7161 $labeltoshow .= $obj->$field_toshow . ' ';
7162 }
7163 } else {
7164 $labeltoshow = $obj->{$InfoFieldList[1]};
7165 }
7166 $labeltoshow = dol_trunc($labeltoshow, 45);
7167
7168 if ($value == $obj->rowid) {
7169 foreach ($fields_label as $field_toshow) {
7170 $translabel = $langs->trans($obj->$field_toshow);
7171 if ($translabel != $obj->$field_toshow) {
7172 $labeltoshow = dol_trunc($translabel) . ' ';
7173 } else {
7174 $labeltoshow = dol_trunc($obj->$field_toshow) . ' ';
7175 }
7176 }
7177 $out .= '<option value="' . $obj->rowid . '" selected>' . $labeltoshow . '</option>';
7178 } else {
7179 if (!$notrans) {
7180 $translabel = $langs->trans($obj->{$InfoFieldList[1]});
7181 if ($translabel != $obj->{$InfoFieldList[1]}) {
7182 $labeltoshow = dol_trunc($translabel, 18);
7183 } else {
7184 $labeltoshow = dol_trunc($obj->{$InfoFieldList[1]});
7185 }
7186 }
7187 if (empty($labeltoshow)) {
7188 $labeltoshow = '(not defined)';
7189 }
7190 if ($value == $obj->rowid) {
7191 $out .= '<option value="' . $obj->rowid . '" selected>' . $labeltoshow . '</option>';
7192 }
7193
7194 if (!empty($InfoFieldList[3]) && $parentField) {
7195 $parent = $parentName . ':' . $obj->{$parentField};
7196 $isDependList = 1;
7197 }
7198
7199 $out .= '<option value="' . $obj->rowid . '"';
7200 $out .= ($value == $obj->rowid ? ' selected' : '');
7201 $out .= (!empty($parent) ? ' parent="' . $parent . '"' : '');
7202 $out .= '>' . $labeltoshow . '</option>';
7203 }
7204
7205 $i++;
7206 }
7207 $this->db->free($resql);
7208 } else {
7209 print 'Error in request ' . $sql . ' ' . $this->db->lasterror() . '. Check setup of extra parameters.<br>';
7210 }
7211 } else {
7212 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
7213 $data = $form->select_all_categories(Categorie::$MAP_ID_TO_CODE[$InfoFieldList[5]], '', 'parent', 64, $InfoFieldList[6], 1, 1);
7214 $out .= '<option value="0">&nbsp;</option>';
7215 foreach ($data as $data_key => $data_value) {
7216 $out .= '<option value="' . $data_key . '"';
7217 $out .= ($value == $data_key ? ' selected' : '');
7218 $out .= '>' . $data_value . '</option>';
7219 }
7220 }
7221 }
7222 $out .= '</select>';
7223 } elseif ($type == 'checkbox') {
7224 $value_arr = explode(',', $value);
7225 $out = $form->multiselectarray($keyprefix.$key.$keysuffix, (empty($param['options']) ?null:$param['options']), $value_arr, '', 0, $morecss, 0, '100%');
7226 } elseif ($type == 'radio') {
7227 $out = '';
7228 foreach ($param['options'] as $keyopt => $valopt) {
7229 $out .= '<input class="flat '.$morecss.'" type="radio" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam ? $moreparam : '');
7230 $out .= ' value="'.$keyopt.'"';
7231 $out .= ' id="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'"';
7232 $out .= ($value == $keyopt ? 'checked' : '');
7233 $out .= '/><label for="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'">'.$valopt.'</label><br>';
7234 }
7235 } elseif ($type == 'chkbxlst') {
7236 if (is_array($value)) {
7237 $value_arr = $value;
7238 } else {
7239 $value_arr = explode(',', $value);
7240 }
7241
7242 if (is_array($param['options'])) {
7243 $param_list = array_keys($param['options']);
7244 $InfoFieldList = explode(":", $param_list[0]);
7245 $parentName = '';
7246 $parentField = '';
7247 // 0 : tableName
7248 // 1 : label field name
7249 // 2 : key fields name (if differ of rowid)
7250 // 3 : key field parent (for dependent lists)
7251 // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
7252 // 5 : id category type
7253 // 6 : ids categories list separated by comma for category root
7254 $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2].' as rowid');
7255
7256 if (count($InfoFieldList) > 3 && !empty($InfoFieldList[3])) {
7257 list ($parentName, $parentField) = explode('|', $InfoFieldList[3]);
7258 $keyList .= ', '.$parentField;
7259 }
7260 if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
7261 if (strpos($InfoFieldList[4], 'extra.') !== false) {
7262 $keyList = 'main.'.$InfoFieldList[2].' as rowid';
7263 } else {
7264 $keyList = $InfoFieldList[2].' as rowid';
7265 }
7266 }
7267
7268 $filter_categorie = false;
7269 if (count($InfoFieldList) > 5) {
7270 if ($InfoFieldList[0] == 'categorie') {
7271 $filter_categorie = true;
7272 }
7273 }
7274
7275 if ($filter_categorie === false) {
7276 $fields_label = explode('|', $InfoFieldList[1]);
7277 if (is_array($fields_label)) {
7278 $keyList .= ', ';
7279 $keyList .= implode(', ', $fields_label);
7280 }
7281
7282 $sqlwhere = '';
7283 $sql = "SELECT " . $keyList;
7284 $sql .= ' FROM ' . $this->db->prefix() . $InfoFieldList[0];
7285 if (!empty($InfoFieldList[4])) {
7286 // can use SELECT request
7287 if (strpos($InfoFieldList[4], '$SEL$') !== false) {
7288 $InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]);
7289 }
7290
7291 // current object id can be use into filter
7292 if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) {
7293 $InfoFieldList[4] = str_replace('$ID$', $objectid, $InfoFieldList[4]);
7294 } else {
7295 $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
7296 }
7297
7298 // We have to join on extrafield table
7299 if (strpos($InfoFieldList[4], 'extra') !== false) {
7300 $sql .= ' as main, ' . $this->db->prefix() . $InfoFieldList[0] . '_extrafields as extra';
7301 $sqlwhere .= " WHERE extra.fk_object=main." . $InfoFieldList[2] . " AND " . $InfoFieldList[4];
7302 } else {
7303 $sqlwhere .= " WHERE " . $InfoFieldList[4];
7304 }
7305 } else {
7306 $sqlwhere .= ' WHERE 1=1';
7307 }
7308 // Some tables may have field, some other not. For the moment we disable it.
7309 if (in_array($InfoFieldList[0], array('tablewithentity'))) {
7310 $sqlwhere .= " AND entity = " . ((int) $conf->entity);
7311 }
7312 // $sql.=preg_replace('/^ AND /','',$sqlwhere);
7313 // print $sql;
7314
7315 $sql .= $sqlwhere;
7316 dol_syslog(get_class($this) . '::showInputField type=chkbxlst', LOG_DEBUG);
7317 $resql = $this->db->query($sql);
7318 if ($resql) {
7319 $num = $this->db->num_rows($resql);
7320 $i = 0;
7321
7322 $data = array();
7323
7324 while ($i < $num) {
7325 $labeltoshow = '';
7326 $obj = $this->db->fetch_object($resql);
7327
7328 $notrans = false;
7329 // Several field into label (eq table:code|libelle:rowid)
7330 $fields_label = explode('|', $InfoFieldList[1]);
7331 if (count($fields_label) > 1) {
7332 $notrans = true;
7333 foreach ($fields_label as $field_toshow) {
7334 $labeltoshow .= $obj->$field_toshow . ' ';
7335 }
7336 } else {
7337 $labeltoshow = $obj->{$InfoFieldList[1]};
7338 }
7339 $labeltoshow = dol_trunc($labeltoshow, 45);
7340
7341 if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
7342 foreach ($fields_label as $field_toshow) {
7343 $translabel = $langs->trans($obj->$field_toshow);
7344 if ($translabel != $obj->$field_toshow) {
7345 $labeltoshow = dol_trunc($translabel, 18) . ' ';
7346 } else {
7347 $labeltoshow = dol_trunc($obj->$field_toshow, 18) . ' ';
7348 }
7349 }
7350
7351 $data[$obj->rowid] = $labeltoshow;
7352 } else {
7353 if (!$notrans) {
7354 $translabel = $langs->trans($obj->{$InfoFieldList[1]});
7355 if ($translabel != $obj->{$InfoFieldList[1]}) {
7356 $labeltoshow = dol_trunc($translabel, 18);
7357 } else {
7358 $labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18);
7359 }
7360 }
7361 if (empty($labeltoshow)) {
7362 $labeltoshow = '(not defined)';
7363 }
7364
7365 if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
7366 $data[$obj->rowid] = $labeltoshow;
7367 }
7368
7369 if (!empty($InfoFieldList[3]) && $parentField) {
7370 $parent = $parentName . ':' . $obj->{$parentField};
7371 $isDependList = 1;
7372 }
7373
7374 $data[$obj->rowid] = $labeltoshow;
7375 }
7376
7377 $i++;
7378 }
7379 $this->db->free($resql);
7380
7381 $out = $form->multiselectarray($keyprefix . $key . $keysuffix, $data, $value_arr, '', 0, $morecss, 0, '100%');
7382 } else {
7383 print 'Error in request ' . $sql . ' ' . $this->db->lasterror() . '. Check setup of extra parameters.<br>';
7384 }
7385 } else {
7386 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
7387 $data = $form->select_all_categories(Categorie::$MAP_ID_TO_CODE[$InfoFieldList[5]], '', 'parent', 64, $InfoFieldList[6], 1, 1);
7388 $out = $form->multiselectarray($keyprefix . $key . $keysuffix, $data, $value_arr, '', 0, $morecss, 0, '100%');
7389 }
7390 }
7391 } elseif ($type == 'link') {
7392 $param_list = array_keys($param['options']); // $param_list='ObjectName:classPath[:AddCreateButtonOrNot[:Filter[:Sortfield]]]'
7393 $param_list_array = explode(':', $param_list[0]);
7394 $showempty = (($required && $default != '') ? 0 : 1);
7395
7396 if (!preg_match('/search_/', $keyprefix)) {
7397 if (!empty($param_list_array[2])) { // If the entry into $fields is set to add a create button
7398 if (!empty($this->fields[$key]['picto'])) {
7399 $morecss .= ' widthcentpercentminusxx';
7400 } else {
7401 $morecss .= ' widthcentpercentminusx';
7402 }
7403 } else {
7404 if (!empty($this->fields[$key]['picto'])) {
7405 $morecss .= ' widthcentpercentminusx';
7406 }
7407 }
7408 }
7409
7410 $out = $form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty, '', '', $morecss, $moreparam, 0, empty($val['disabled']) ? 0 : 1);
7411
7412 if (!empty($param_list_array[2])) { // If the entry into $fields is set, we must add a create button
7413 if ((!GETPOSTISSET('backtopage') || strpos(GETPOST('backtopage'), $_SERVER['PHP_SELF']) === 0) // // To avoid to open several times the 'Plus' button (we accept only one level)
7414 && empty($val['disabled']) && empty($nonewbutton)) { // and to avoid to show the button if the field is protected by a "disabled".
7415 list($class, $classfile) = explode(':', $param_list[0]);
7416 if (file_exists(dol_buildpath(dirname(dirname($classfile)).'/card.php'))) {
7417 $url_path = dol_buildpath(dirname(dirname($classfile)).'/card.php', 1);
7418 } else {
7419 $url_path = dol_buildpath(dirname(dirname($classfile)).'/'.strtolower($class).'_card.php', 1);
7420 }
7421 $paramforthenewlink = '';
7422 $paramforthenewlink .= (GETPOSTISSET('action') ? '&action='.GETPOST('action', 'aZ09') : '');
7423 $paramforthenewlink .= (GETPOSTISSET('id') ? '&id='.GETPOST('id', 'int') : '');
7424 $paramforthenewlink .= (GETPOSTISSET('origin') ? '&origin='.GETPOST('origin', 'aZ09') : '');
7425 $paramforthenewlink .= (GETPOSTISSET('originid') ? '&originid='.GETPOST('originid', 'int') : '');
7426 $paramforthenewlink .= '&fk_'.strtolower($class).'=--IDFORBACKTOPAGE--';
7427 // TODO Add Javascript code to add input fields already filled into $paramforthenewlink so we won't loose them when going back to main page
7428 $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>';
7429 }
7430 }
7431 } elseif ($type == 'password') {
7432 // If prefix is 'search_', field is used as a filter, we use a common text field.
7433 $out = '<input type="'.($keyprefix == 'search_' ? 'text' : 'password').'" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam ? $moreparam : '').'>';
7434 } elseif ($type == 'array') {
7435 $newval = $val;
7436 $newval['type'] = 'varchar(256)';
7437
7438 $out = '';
7439 if (!empty($value)) {
7440 foreach ($value as $option) {
7441 $out .= '<span><a class="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_del" href="javascript:;"><span class="fa fa-minus-circle valignmiddle"></span></a> ';
7442 $out .= $this->showInputField($newval, $keyprefix.$key.$keysuffix.'[]', $option, $moreparam, '', '', $morecss).'<br></span>';
7443 }
7444 }
7445 $out .= '<a id="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_add" href="javascript:;"><span class="fa fa-plus-circle valignmiddle"></span></a>';
7446
7447 $newInput = '<span><a class="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_del" href="javascript:;"><span class="fa fa-minus-circle valignmiddle"></span></a> ';
7448 $newInput .= $this->showInputField($newval, $keyprefix.$key.$keysuffix.'[]', '', $moreparam, '', '', $morecss).'<br></span>';
7449
7450 if (!empty($conf->use_javascript_ajax)) {
7451 $out .= '
7452 <script nonce="'.getNonce().'">
7453 $(document).ready(function() {
7454 $("a#'.dol_escape_js($keyprefix.$key.$keysuffix).'_add").click(function() {
7455 $("'.dol_escape_js($newInput).'").insertBefore(this);
7456 });
7457
7458 $(document).on("click", "a.'.dol_escape_js($keyprefix.$key.$keysuffix).'_del", function() {
7459 $(this).parent().remove();
7460 });
7461 });
7462 </script>';
7463 }
7464 }
7465 if (!empty($hidden)) {
7466 $out = '<input type="hidden" value="'.$value.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'"/>';
7467 }
7468
7469 if ($isDependList==1) {
7470 $out .= $this->getJSListDependancies('_common');
7471 }
7472 /* Add comments
7473 if ($type == 'date') $out.=' (YYYY-MM-DD)';
7474 elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)';
7475 */
7476
7477 // Display error message for field
7478 if (!empty($fieldValidationErrorMsg) && function_exists('getFieldErrorIcon')) {
7479 $out .= ' '.getFieldErrorIcon($fieldValidationErrorMsg);
7480 }
7481
7482 return $out;
7483 }
7484
7498 public function showOutputField($val, $key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = '')
7499 {
7500 global $conf, $langs, $form;
7501
7502 if (!is_object($form)) {
7503 require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
7504 $form = new Form($this->db);
7505 }
7506
7507 $label = empty($val['label']) ? '' : $val['label'];
7508 $type = empty($val['type']) ? '' : $val['type'];
7509 $size = empty($val['css']) ? '' : $val['css'];
7510 $reg = array();
7511
7512 // Convert var to be able to share same code than showOutputField of extrafields
7513 if (preg_match('/varchar\‍((\d+)\‍)/', $type, $reg)) {
7514 $type = 'varchar'; // convert varchar(xx) int varchar
7515 $size = $reg[1];
7516 } elseif (preg_match('/varchar/', $type)) {
7517 $type = 'varchar'; // convert varchar(xx) int varchar
7518 }
7519 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
7520 $type = 'select';
7521 }
7522 if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) {
7523 $type = 'link';
7524 }
7525
7526 $default = empty($val['default']) ? '' : $val['default'];
7527 $computed = empty($val['computed']) ? '' : $val['computed'];
7528 $unique = empty($val['unique']) ? '' : $val['unique'];
7529 $required = empty($val['required']) ? '' : $val['required'];
7530 $param = array();
7531 $param['options'] = array();
7532
7533 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
7534 $param['options'] = $val['arrayofkeyval'];
7535 }
7536 if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) {
7537 $type = 'link';
7538 $stringforoptions = $reg[1].':'.$reg[2];
7539 if ($reg[1] == 'User') {
7540 $stringforoptions .= ':-1';
7541 }
7542 $param['options'] = array($stringforoptions => $stringforoptions);
7543 } elseif (preg_match('/^sellist:(.*):(.*):(.*):(.*)/i', $val['type'], $reg)) {
7544 $param['options'] = array($reg[1].':'.$reg[2].':'.$reg[3].':'.$reg[4] => 'N');
7545 $type = 'sellist';
7546 } elseif (preg_match('/^sellist:(.*):(.*):(.*)/i', $val['type'], $reg)) {
7547 $param['options'] = array($reg[1].':'.$reg[2].':'.$reg[3] => 'N');
7548 $type = 'sellist';
7549 } elseif (preg_match('/^sellist:(.*):(.*)/i', $val['type'], $reg)) {
7550 $param['options'] = array($reg[1].':'.$reg[2] => 'N');
7551 $type = 'sellist';
7552 } elseif (preg_match('/^chkbxlst:(.*)/i', $val['type'], $reg)) {
7553 $param['options'] = array($reg[1] => 'N');
7554 $type = 'chkbxlst';
7555 }
7556
7557 $langfile = empty($val['langfile']) ? '' : $val['langfile'];
7558 $list = (empty($val['list']) ? '' : $val['list']);
7559 $help = (empty($val['help']) ? '' : $val['help']);
7560 $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)
7561
7562 if ($hidden) {
7563 return '';
7564 }
7565
7566 // If field is a computed field, value must become result of compute
7567 if ($computed) {
7568 // Make the eval of compute string
7569 //var_dump($computed);
7570 $value = dol_eval($computed, 1, 0, '');
7571 }
7572
7573 if (empty($morecss)) {
7574 if ($type == 'date') {
7575 $morecss = 'minwidth100imp';
7576 } elseif ($type == 'datetime' || $type == 'timestamp') {
7577 $morecss = 'minwidth200imp';
7578 } elseif (in_array($type, array('int', 'double', 'price'))) {
7579 $morecss = 'maxwidth75';
7580 } elseif ($type == 'url') {
7581 $morecss = 'minwidth400';
7582 } elseif ($type == 'boolean') {
7583 $morecss = '';
7584 } else {
7585 if (is_numeric($size) && round($size) < 12) {
7586 $morecss = 'minwidth100';
7587 } elseif (is_numeric($size) && round($size) <= 48) {
7588 $morecss = 'minwidth200';
7589 } else {
7590 $morecss = 'minwidth400';
7591 }
7592 }
7593 }
7594
7595 // Format output value differently according to properties of field
7596 if (in_array($key, array('rowid', 'ref')) && method_exists($this, 'getNomUrl')) {
7597 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.
7598 $value = $this->getNomUrl(1, '', 0, '', 1);
7599 }
7600 } elseif ($key == 'status' && method_exists($this, 'getLibStatut')) {
7601 $value = $this->getLibStatut(3);
7602 } elseif ($type == 'date') {
7603 if (!empty($value)) {
7604 $value = dol_print_date($value, 'day'); // We suppose dates without time are always gmt (storage of course + output)
7605 } else {
7606 $value = '';
7607 }
7608 } elseif ($type == 'datetime' || $type == 'timestamp') {
7609 if (!empty($value)) {
7610 $value = dol_print_date($value, 'dayhour', 'tzuserrel');
7611 } else {
7612 $value = '';
7613 }
7614 } elseif ($type == 'duration') {
7615 include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
7616 if (!is_null($value) && $value !== '') {
7617 $value = convertSecondToTime($value, 'allhourmin');
7618 }
7619 } elseif ($type == 'double' || $type == 'real') {
7620 if (!is_null($value) && $value !== '') {
7621 $value = price($value);
7622 }
7623 } elseif ($type == 'boolean') {
7624 $checked = '';
7625 if (!empty($value)) {
7626 $checked = ' checked ';
7627 }
7628 $value = '<input type="checkbox" '.$checked.' '.($moreparam ? $moreparam : '').' readonly disabled>';
7629 } elseif ($type == 'mail' || $type == 'email') {
7630 $value = dol_print_email($value, 0, 0, 0, 64, 1, 1);
7631 } elseif ($type == 'url') {
7632 $value = dol_print_url($value, '_blank', 32, 1);
7633 } elseif ($type == 'phone') {
7634 $value = dol_print_phone($value, '', 0, 0, '', '&nbsp;', 'phone');
7635 } elseif ($type == 'ip') {
7636 $value = dol_print_ip($value, 0);
7637 } elseif ($type == 'price') {
7638 if (!is_null($value) && $value !== '') {
7639 $value = price($value, 0, $langs, 0, 0, -1, $conf->currency);
7640 }
7641 } elseif ($type == 'select') {
7642 $value = isset($param['options'][$value])?$param['options'][$value]:'';
7643 } elseif ($type == 'sellist') {
7644 $param_list = array_keys($param['options']);
7645 $InfoFieldList = explode(":", $param_list[0]);
7646
7647 $selectkey = "rowid";
7648 $keyList = 'rowid';
7649
7650 if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
7651 $selectkey = $InfoFieldList[2];
7652 $keyList = $InfoFieldList[2].' as rowid';
7653 }
7654
7655 $fields_label = explode('|', $InfoFieldList[1]);
7656 if (is_array($fields_label)) {
7657 $keyList .= ', ';
7658 $keyList .= implode(', ', $fields_label);
7659 }
7660
7661 $filter_categorie = false;
7662 if (count($InfoFieldList) > 5) {
7663 if ($InfoFieldList[0] == 'categorie') {
7664 $filter_categorie = true;
7665 }
7666 }
7667
7668 $sql = "SELECT ".$keyList;
7669 $sql .= ' FROM '.$this->db->prefix().$InfoFieldList[0];
7670 if (strpos($InfoFieldList[4], 'extra') !== false) {
7671 $sql .= ' as main';
7672 }
7673 if ($selectkey == 'rowid' && empty($value)) {
7674 $sql .= " WHERE ".$selectkey." = 0";
7675 } elseif ($selectkey == 'rowid') {
7676 $sql .= " WHERE ".$selectkey." = ".((int) $value);
7677 } else {
7678 $sql .= " WHERE ".$selectkey." = '".$this->db->escape($value)."'";
7679 }
7680
7681 //$sql.= ' AND entity = '.$conf->entity;
7682
7683 dol_syslog(get_class($this).':showOutputField:$type=sellist', LOG_DEBUG);
7684 $resql = $this->db->query($sql);
7685 if ($resql) {
7686 if ($filter_categorie === false) {
7687 $value = ''; // value was used, so now we reste it to use it to build final output
7688 $numrows = $this->db->num_rows($resql);
7689 if ($numrows) {
7690 $obj = $this->db->fetch_object($resql);
7691
7692 // Several field into label (eq table:code|libelle:rowid)
7693 $fields_label = explode('|', $InfoFieldList[1]);
7694
7695 if (is_array($fields_label) && count($fields_label) > 1) {
7696 foreach ($fields_label as $field_toshow) {
7697 $translabel = '';
7698 if (!empty($obj->$field_toshow)) {
7699 $translabel = $langs->trans($obj->$field_toshow);
7700 }
7701 if ($translabel != $field_toshow) {
7702 $value .= dol_trunc($translabel, 18) . ' ';
7703 } else {
7704 $value .= $obj->$field_toshow . ' ';
7705 }
7706 }
7707 } else {
7708 $translabel = '';
7709 if (!empty($obj->{$InfoFieldList[1]})) {
7710 $translabel = $langs->trans($obj->{$InfoFieldList[1]});
7711 }
7712 if ($translabel != $obj->{$InfoFieldList[1]}) {
7713 $value = dol_trunc($translabel, 18);
7714 } else {
7715 $value = $obj->{$InfoFieldList[1]};
7716 }
7717 }
7718 }
7719 } else {
7720 require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
7721
7722 $toprint = array();
7723 $obj = $this->db->fetch_object($resql);
7724 $c = new Categorie($this->db);
7725 $c->fetch($obj->rowid);
7726 $ways = $c->print_all_ways(); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
7727 foreach ($ways as $way) {
7728 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"' . ($c->color ? ' style="background: #' . $c->color . ';"' : ' style="background: #aaa"') . '>' . img_object('', 'category') . ' ' . $way . '</li>';
7729 }
7730 $value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
7731 }
7732 } else {
7733 dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
7734 }
7735 } elseif ($type == 'radio') {
7736 $value = $param['options'][$value];
7737 } elseif ($type == 'checkbox') {
7738 $value_arr = explode(',', $value);
7739 $value = '';
7740 if (is_array($value_arr) && count($value_arr) > 0) {
7741 $toprint = array();
7742 foreach ($value_arr as $keyval => $valueval) {
7743 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">'.$param['options'][$valueval].'</li>';
7744 }
7745 $value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
7746 }
7747 } elseif ($type == 'chkbxlst') {
7748 $value_arr = explode(',', $value);
7749
7750 $param_list = array_keys($param['options']);
7751 $InfoFieldList = explode(":", $param_list[0]);
7752
7753 $selectkey = "rowid";
7754 $keyList = 'rowid';
7755
7756 if (count($InfoFieldList) >= 3) {
7757 $selectkey = $InfoFieldList[2];
7758 $keyList = $InfoFieldList[2].' as rowid';
7759 }
7760
7761 $fields_label = explode('|', $InfoFieldList[1]);
7762 if (is_array($fields_label)) {
7763 $keyList .= ', ';
7764 $keyList .= implode(', ', $fields_label);
7765 }
7766
7767 $filter_categorie = false;
7768 if (count($InfoFieldList) > 5) {
7769 if ($InfoFieldList[0] == 'categorie') {
7770 $filter_categorie = true;
7771 }
7772 }
7773
7774 $sql = "SELECT ".$keyList;
7775 $sql .= ' FROM '.$this->db->prefix().$InfoFieldList[0];
7776 if (strpos($InfoFieldList[4], 'extra') !== false) {
7777 $sql .= ' as main';
7778 }
7779 // $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
7780 // $sql.= ' AND entity = '.$conf->entity;
7781
7782 dol_syslog(get_class($this).':showOutputField:$type=chkbxlst', LOG_DEBUG);
7783 $resql = $this->db->query($sql);
7784 if ($resql) {
7785 if ($filter_categorie === false) {
7786 $value = ''; // value was used, so now we reste it to use it to build final output
7787 $toprint = array();
7788 while ($obj = $this->db->fetch_object($resql)) {
7789 // Several field into label (eq table:code|libelle:rowid)
7790 $fields_label = explode('|', $InfoFieldList[1]);
7791 if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
7792 if (is_array($fields_label) && count($fields_label) > 1) {
7793 foreach ($fields_label as $field_toshow) {
7794 $translabel = '';
7795 if (!empty($obj->$field_toshow)) {
7796 $translabel = $langs->trans($obj->$field_toshow);
7797 }
7798 if ($translabel != $field_toshow) {
7799 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">' . dol_trunc($translabel, 18) . '</li>';
7800 } else {
7801 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">' . $obj->$field_toshow . '</li>';
7802 }
7803 }
7804 } else {
7805 $translabel = '';
7806 if (!empty($obj->{$InfoFieldList[1]})) {
7807 $translabel = $langs->trans($obj->{$InfoFieldList[1]});
7808 }
7809 if ($translabel != $obj->{$InfoFieldList[1]}) {
7810 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">' . dol_trunc($translabel, 18) . '</li>';
7811 } else {
7812 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">' . $obj->{$InfoFieldList[1]} . '</li>';
7813 }
7814 }
7815 }
7816 }
7817 } else {
7818 require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
7819
7820 $toprint = array();
7821 while ($obj = $this->db->fetch_object($resql)) {
7822 if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
7823 $c = new Categorie($this->db);
7824 $c->fetch($obj->rowid);
7825 $ways = $c->print_all_ways(); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
7826 foreach ($ways as $way) {
7827 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"' . ($c->color ? ' style="background: #' . $c->color . ';"' : ' style="background: #aaa"') . '>' . img_object('', 'category') . ' ' . $way . '</li>';
7828 }
7829 }
7830 }
7831 }
7832 $value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
7833 } else {
7834 dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
7835 }
7836 } elseif ($type == 'link') {
7837 $out = '';
7838
7839 // only if something to display (perf)
7840 if ($value) {
7841 $param_list = array_keys($param['options']); // Example: $param_list='ObjectName:classPath:-1::customer'
7842
7843 $InfoFieldList = explode(":", $param_list[0]);
7844 $classname = $InfoFieldList[0];
7845 $classpath = $InfoFieldList[1];
7846 $getnomurlparam = (empty($InfoFieldList[2]) ? 3 : $InfoFieldList[2]);
7847 $getnomurlparam2 = (empty($InfoFieldList[4]) ? '' : $InfoFieldList[4]);
7848 if (!empty($classpath)) {
7849 dol_include_once($InfoFieldList[1]);
7850 if ($classname && class_exists($classname)) {
7851 $object = new $classname($this->db);
7852 if ($object->element === 'product') { // Special cas for product because default valut of fetch are wrong
7853 $result = $object->fetch($value, '', '', '', 0, 1, 1);
7854 } else {
7855 $result = $object->fetch($value);
7856 }
7857 if ($result > 0) {
7858 if ($object->element === 'product') {
7859 $get_name_url_param_arr = array($getnomurlparam, $getnomurlparam2, 0, -1, 0, '', 0);
7860 if (isset($val['get_name_url_params'])) {
7861 $get_name_url_params = explode(':', $val['get_name_url_params']);
7862 if (!empty($get_name_url_params)) {
7863 $param_num_max = count($get_name_url_param_arr) - 1;
7864 foreach ($get_name_url_params as $param_num => $param_value) {
7865 if ($param_num > $param_num_max) {
7866 break;
7867 }
7868 $get_name_url_param_arr[$param_num] = $param_value;
7869 }
7870 }
7871 }
7872
7876 $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]);
7877 } else {
7878 $value = $object->getNomUrl($getnomurlparam, $getnomurlparam2);
7879 }
7880 } else {
7881 $value = '';
7882 }
7883 }
7884 } else {
7885 dol_syslog('Error bad setup of extrafield', LOG_WARNING);
7886 return 'Error bad setup of extrafield';
7887 }
7888 } else {
7889 $value = '';
7890 }
7891 } elseif ($type == 'password') {
7892 $value = preg_replace('/./i', '*', $value);
7893 } elseif ($type == 'array') {
7894 $value = implode('<br>', $value);
7895 } else { // text|html|varchar
7896 $value = dol_htmlentitiesbr($value);
7897 }
7898
7899 //print $type.'-'.$size.'-'.$value;
7900 $out = $value;
7901
7902 return $out;
7903 }
7904
7911 public function clearFieldError($fieldKey)
7912 {
7913 $this->error = '';
7914 unset($this->validateFieldsErrors[$fieldKey]);
7915 }
7916
7924 public function setFieldError($fieldKey, $msg = '')
7925 {
7926 global $langs;
7927 if (empty($msg)) {
7928 $msg = $langs->trans("UnknowError");
7929 }
7930
7931 $this->error = $this->validateFieldsErrors[$fieldKey] = $msg;
7932 }
7933
7940 public function getFieldError($fieldKey)
7941 {
7942 if (!empty($this->validateFieldsErrors[$fieldKey])) {
7943 return $this->validateFieldsErrors[$fieldKey];
7944 }
7945 return '';
7946 }
7947
7956 public function validateField($fields, $fieldKey, $fieldValue)
7957 {
7958 global $langs;
7959
7960 if (!class_exists('Validate')) {
7961 require_once DOL_DOCUMENT_ROOT . '/core/class/validate.class.php';
7962 }
7963
7964 $this->clearFieldError($fieldKey);
7965
7966 if (!isset($fields[$fieldKey])) {
7967 $this->setFieldError($fieldKey, $langs->trans('FieldNotFoundInObject'));
7968 return false;
7969 }
7970
7971 $val = $fields[$fieldKey];
7972
7973 $param = array();
7974 $param['options'] = array();
7975 $type = $val['type'];
7976
7977 $required = false;
7978 if (isset($val['notnull']) && $val['notnull'] === 1) {
7979 // 'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
7980 $required = true;
7981 }
7982
7983 $maxSize = 0;
7984 $minSize = 0;
7985
7986 //
7987 // PREPARE Elements
7988 //
7989 $reg = array();
7990
7991 // Convert var to be able to share same code than showOutputField of extrafields
7992 if (preg_match('/varchar\‍((\d+)\‍)/', $type, $reg)) {
7993 $type = 'varchar'; // convert varchar(xx) int varchar
7994 $maxSize = $reg[1];
7995 } elseif (preg_match('/varchar/', $type)) {
7996 $type = 'varchar'; // convert varchar(xx) int varchar
7997 }
7998
7999 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
8000 $type = 'select';
8001 }
8002
8003 if (!empty($val['type']) && preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) {
8004 $type = 'link';
8005 }
8006
8007 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
8008 $param['options'] = $val['arrayofkeyval'];
8009 }
8010
8011 if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) {
8012 $type = 'link';
8013 $param['options'] = array($reg[1].':'.$reg[2]=>$reg[1].':'.$reg[2]);
8014 } elseif (preg_match('/^sellist:(.*):(.*):(.*):(.*)/i', $val['type'], $reg)) {
8015 $param['options'] = array($reg[1].':'.$reg[2].':'.$reg[3].':'.$reg[4] => 'N');
8016 $type = 'sellist';
8017 } elseif (preg_match('/^sellist:(.*):(.*):(.*)/i', $val['type'], $reg)) {
8018 $param['options'] = array($reg[1].':'.$reg[2].':'.$reg[3] => 'N');
8019 $type = 'sellist';
8020 } elseif (preg_match('/^sellist:(.*):(.*)/i', $val['type'], $reg)) {
8021 $param['options'] = array($reg[1].':'.$reg[2] => 'N');
8022 $type = 'sellist';
8023 }
8024
8025 //
8026 // TEST Value
8027 //
8028
8029 // Use Validate class to allow external Modules to use data validation part instead of concentrate all test here (factoring) or just for reuse
8030 $validate = new Validate($this->db, $langs);
8031
8032
8033 // little trick : to perform tests with good performances sort tests by quick to low
8034
8035 //
8036 // COMMON TESTS
8037 //
8038
8039 // Required test and empty value
8040 if ($required && !$validate->isNotEmptyString($fieldValue)) {
8041 $this->setFieldError($fieldKey, $validate->error);
8042 return false;
8043 } elseif (!$required && !$validate->isNotEmptyString($fieldValue)) {
8044 // if no value sent and the field is not mandatory, no need to perform tests
8045 return true;
8046 }
8047
8048 // MAX Size test
8049 if (!empty($maxSize) && !$validate->isMaxLength($fieldValue, $maxSize)) {
8050 $this->setFieldError($fieldKey, $validate->error);
8051 return false;
8052 }
8053
8054 // MIN Size test
8055 if (!empty($minSize) && !$validate->isMinLength($fieldValue, $minSize)) {
8056 $this->setFieldError($fieldKey, $validate->error);
8057 return false;
8058 }
8059
8060 //
8061 // TESTS for TYPE
8062 //
8063
8064 if (in_array($type, array('date', 'datetime', 'timestamp'))) {
8065 if (!$validate->isTimestamp($fieldValue)) {
8066 $this->setFieldError($fieldKey, $validate->error);
8067 return false;
8068 } else { return true; }
8069 } elseif ($type == 'duration') {
8070 if (!$validate->isDuration($fieldValue)) {
8071 $this->setFieldError($fieldKey, $validate->error);
8072 return false;
8073 } else { return true; }
8074 } elseif (in_array($type, array('double', 'real', 'price'))) {
8075 // is numeric
8076 if (!$validate->isNumeric($fieldValue)) {
8077 $this->setFieldError($fieldKey, $validate->error);
8078 return false;
8079 } else { return true; }
8080 } elseif ($type == 'boolean') {
8081 if (!$validate->isBool($fieldValue)) {
8082 $this->setFieldError($fieldKey, $validate->error);
8083 return false;
8084 } else { return true; }
8085 } elseif ($type == 'mail') {
8086 if (!$validate->isEmail($fieldValue)) {
8087 $this->setFieldError($fieldKey, $validate->error);
8088 return false;
8089 }
8090 } elseif ($type == 'url') {
8091 if (!$validate->isUrl($fieldValue)) {
8092 $this->setFieldError($fieldKey, $validate->error);
8093 return false;
8094 } else { return true; }
8095 } elseif ($type == 'phone') {
8096 if (!$validate->isPhone($fieldValue)) {
8097 $this->setFieldError($fieldKey, $validate->error);
8098 return false;
8099 } else { return true; }
8100 } elseif ($type == 'select' || $type == 'radio') {
8101 if (!isset($param['options'][$fieldValue])) {
8102 $this->error = $langs->trans('RequireValidValue');
8103 return false;
8104 } else { return true; }
8105 } elseif ($type == 'sellist' || $type == 'chkbxlst') {
8106 $param_list = array_keys($param['options']);
8107 $InfoFieldList = explode(":", $param_list[0]);
8108 $value_arr = explode(',', $fieldValue);
8109 $value_arr = array_map(array($this->db, 'escape'), $value_arr);
8110
8111 $selectkey = "rowid";
8112 if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
8113 $selectkey = $InfoFieldList[2];
8114 }
8115
8116 if (!$validate->isInDb($value_arr, $InfoFieldList[0], $selectkey)) {
8117 $this->setFieldError($fieldKey, $validate->error);
8118 return false;
8119 } else { return true; }
8120 } elseif ($type == 'link') {
8121 $param_list = array_keys($param['options']); // $param_list='ObjectName:classPath'
8122 $InfoFieldList = explode(":", $param_list[0]);
8123 $classname = $InfoFieldList[0];
8124 $classpath = $InfoFieldList[1];
8125 if (!$validate->isFetchable($fieldValue, $classname, $classpath)) {
8126 $this->setFieldError($fieldKey, $validate->error);
8127 return false;
8128 } else { return true; }
8129 }
8130
8131 // if no test failled all is ok
8132 return true;
8133 }
8134
8148 public function showOptionals($extrafields, $mode = 'view', $params = null, $keysuffix = '', $keyprefix = '', $onetrtd = 0, $display_type = 'card')
8149 {
8150 global $db, $conf, $langs, $action, $form, $hookmanager;
8151
8152 if (!is_object($form)) {
8153 $form = new Form($db);
8154 }
8155 if (!is_object($extrafields)) {
8156 dol_syslog('Bad parameter extrafields for showOptionals', LOG_ERR);
8157 return 'Bad parameter extrafields for showOptionals';
8158 }
8159 if (!is_array($extrafields->attributes[$this->table_element])) {
8160 dol_syslog("extrafields->attributes was not loaded with extrafields->fetch_name_optionals_label(table_element);", LOG_WARNING);
8161 }
8162
8163 $out = '';
8164
8165 $parameters = array('mode'=>$mode, 'params'=>$params, 'keysuffix'=>$keysuffix, 'keyprefix'=>$keyprefix, 'display_type'=>$display_type);
8166 $reshook = $hookmanager->executeHooks('showOptionals', $parameters, $this, $action); // Note that $action and $object may have been modified by hook
8167
8168 if (empty($reshook)) {
8169 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) {
8170 $out .= "\n";
8171 $out .= '<!-- commonobject:showOptionals --> ';
8172 $out .= "\n";
8173
8174 $nbofextrafieldsshown = 0;
8175 $e = 0; // var to manage the modulo (odd/even)
8176
8177 $lastseparatorkeyfound = '';
8178 $extrafields_collapse_num = '';
8179 $extrafields_collapse_num_old = '';
8180 $i = 0;
8181
8182 foreach ($extrafields->attributes[$this->table_element]['label'] as $key => $label) {
8183 $i++;
8184
8185 // Show only the key field in params
8186 if (is_array($params) && array_key_exists('onlykey', $params) && $key != $params['onlykey']) {
8187 continue;
8188 }
8189
8190 // Test on 'enabled' ('enabled' is different than 'list' = 'visibility')
8191 $enabled = 1;
8192 if ($enabled && isset($extrafields->attributes[$this->table_element]['enabled'][$key])) {
8193 $enabled = dol_eval($extrafields->attributes[$this->table_element]['enabled'][$key], 1, 1, '2');
8194 }
8195 if (empty($enabled)) {
8196 continue;
8197 }
8198
8199 $visibility = 1;
8200 if ($visibility && isset($extrafields->attributes[$this->table_element]['list'][$key])) {
8201 $visibility = dol_eval($extrafields->attributes[$this->table_element]['list'][$key], 1, 1, '2');
8202 }
8203
8204 $perms = 1;
8205 if ($perms && isset($extrafields->attributes[$this->table_element]['perms'][$key])) {
8206 $perms = dol_eval($extrafields->attributes[$this->table_element]['perms'][$key], 1, 1, '2');
8207 }
8208
8209 if (($mode == 'create') && abs($visibility) != 1 && abs($visibility) != 3) {
8210 continue; // <> -1 and <> 1 and <> 3 = not visible on forms, only on list
8211 } elseif (($mode == 'edit') && abs($visibility) != 1 && abs($visibility) != 3 && abs($visibility) != 4) {
8212 // 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
8213 $ef_name = 'options_' . $key;
8214 $ef_value = $this->array_options[$ef_name];
8215 $out .= '<input type="hidden" name="' . $ef_name . '" id="' . $ef_name . '" value="' . $ef_value . '" />' . "\n";
8216 continue; // <> -1 and <> 1 and <> 3 = not visible on forms, only on list and <> 4 = not visible at the creation
8217 } elseif ($mode == 'view' && empty($visibility)) {
8218 continue;
8219 }
8220 if (empty($perms)) {
8221 continue;
8222 }
8223
8224 // Load language if required
8225 if (!empty($extrafields->attributes[$this->table_element]['langfile'][$key])) {
8226 $langs->load($extrafields->attributes[$this->table_element]['langfile'][$key]);
8227 }
8228
8229 $colspan = 0;
8230 if (is_array($params) && count($params) > 0 && $display_type=='card') {
8231 if (array_key_exists('cols', $params)) {
8232 $colspan = $params['cols'];
8233 } elseif (array_key_exists('colspan', $params)) { // For backward compatibility. Use cols instead now.
8234 $reg = array();
8235 if (preg_match('/colspan="(\d+)"/', $params['colspan'], $reg)) {
8236 $colspan = $reg[1];
8237 } else {
8238 $colspan = $params['colspan'];
8239 }
8240 }
8241 }
8242 $colspan = intval($colspan);
8243
8244 switch ($mode) {
8245 case "view":
8246 $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
8247 break;
8248 case "create":
8249 case "edit":
8250 // We get the value of property found with GETPOST so it takes into account:
8251 // default values overwrite, restore back to list link, ... (but not 'default value in database' of field)
8252 $check = 'alphanohtml';
8253 if (in_array($extrafields->attributes[$this->table_element]['type'][$key], array('html', 'text'))) {
8254 $check = 'restricthtml';
8255 }
8256 $getposttemp = GETPOST($keyprefix.'options_'.$key.$keysuffix, $check, 3); // GETPOST can get value from GET, POST or setup of default values overwrite.
8257 // GETPOST("options_" . $key) can be 'abc' or array(0=>'abc')
8258 if (is_array($getposttemp) || $getposttemp != '' || GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix)) {
8259 if (is_array($getposttemp)) {
8260 // $getposttemp is an array but following code expects a comma separated string
8261 $value = implode(",", $getposttemp);
8262 } else {
8263 $value = $getposttemp;
8264 }
8265 } else {
8266 $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.
8267 }
8268 //var_dump($keyprefix.' - '.$key.' - '.$keysuffix.' - '.$keyprefix.'options_'.$key.$keysuffix.' - '.$this->array_options["options_".$key.$keysuffix].' - '.$getposttemp.' - '.$value);
8269 break;
8270 }
8271
8272 $nbofextrafieldsshown++;
8273
8274 // Output value of the current field
8275 if ($extrafields->attributes[$this->table_element]['type'][$key] == 'separate') {
8276 $extrafields_collapse_num = $key;
8277 /*
8278 $extrafield_param = $extrafields->attributes[$this->table_element]['param'][$key];
8279 if (!empty($extrafield_param) && is_array($extrafield_param)) {
8280 $extrafield_param_list = array_keys($extrafield_param['options']);
8281
8282 if (count($extrafield_param_list) > 0) {
8283 $extrafield_collapse_display_value = intval($extrafield_param_list[0]);
8284
8285 if ($extrafield_collapse_display_value == 1 || $extrafield_collapse_display_value == 2) {
8286 //$extrafields_collapse_num = $extrafields->attributes[$this->table_element]['pos'][$key];
8287 $extrafields_collapse_num = $key;
8288 }
8289 }
8290 }
8291 */
8292
8293 // if colspan=0 or 1, the second column is not extended, so the separator must be on 2 columns
8294 $out .= $extrafields->showSeparator($key, $this, ($colspan ? $colspan + 1 : 2), $display_type, $mode);
8295
8296 $lastseparatorkeyfound = $key;
8297 } else {
8298 $collapse_group = $extrafields_collapse_num.(!empty($this->id) ? '_'.$this->id : '');
8299
8300 $class = (!empty($extrafields->attributes[$this->table_element]['hidden'][$key]) ? 'hideobject ' : '');
8301 $csstyle = '';
8302 if (is_array($params) && count($params) > 0) {
8303 if (array_key_exists('class', $params)) {
8304 $class .= $params['class'].' ';
8305 }
8306 if (array_key_exists('style', $params)) {
8307 $csstyle = $params['style'];
8308 }
8309 }
8310
8311 // add html5 elements
8312 $domData = ' data-element="extrafield"';
8313 $domData .= ' data-targetelement="'.$this->element.'"';
8314 $domData .= ' data-targetid="'.$this->id.'"';
8315
8316 $html_id = (empty($this->id) ? '' : 'extrarow-'.$this->element.'_'.$key.'_'.$this->id);
8317 if ($display_type=='card') {
8318 if (!empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && ($e % 2) == 0) {
8319 $colspan = 0;
8320 }
8321
8322 if ($action == 'selectlines') {
8323 $colspan++;
8324 }
8325 }
8326
8327 // Convert date into timestamp format (value in memory must be a timestamp)
8328 if (in_array($extrafields->attributes[$this->table_element]['type'][$key], array('date'))) {
8329 $datenotinstring = null;
8330 if (array_key_exists('options_'.$key, $this->array_options)) {
8331 $datenotinstring = $this->array_options['options_'.$key];
8332 if (!is_numeric($this->array_options['options_'.$key])) { // For backward compatibility
8333 $datenotinstring = $this->db->jdate($datenotinstring);
8334 }
8335 }
8336 $datekey = $keyprefix.'options_'.$key.$keysuffix;
8337 $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;
8338 }
8339 if (in_array($extrafields->attributes[$this->table_element]['type'][$key], array('datetime'))) {
8340 $datenotinstring = null;
8341 if (array_key_exists('options_'.$key, $this->array_options)) {
8342 $datenotinstring = $this->array_options['options_'.$key];
8343 if (!is_numeric($this->array_options['options_'.$key])) { // For backward compatibility
8344 $datenotinstring = $this->db->jdate($datenotinstring);
8345 }
8346 }
8347 $timekey = $keyprefix.'options_'.$key.$keysuffix;
8348 $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;
8349 }
8350 // Convert float submited string into real php numeric (value in memory must be a php numeric)
8351 if (in_array($extrafields->attributes[$this->table_element]['type'][$key], array('price', 'double'))) {
8352 if (GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix) || $value) {
8353 $value = price2num($value);
8354 } elseif (isset($this->array_options['options_'.$key])) {
8355 $value = $this->array_options['options_'.$key];
8356 }
8357 }
8358
8359 // HTML, text, select, integer and varchar: take into account default value in database if in create mode
8360 if (in_array($extrafields->attributes[$this->table_element]['type'][$key], array('html', 'text', 'varchar', 'select', 'radio', 'int', 'boolean'))) {
8361 if ($action == 'create') {
8362 $value = (GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix) || $value) ? $value : $extrafields->attributes[$this->table_element]['default'][$key];
8363 }
8364 }
8365
8366 $labeltoshow = $langs->trans($label);
8367 $helptoshow = $langs->trans($extrafields->attributes[$this->table_element]['help'][$key]);
8368
8369 if ($display_type == 'card') {
8370 $out .= '<tr '.($html_id ? 'id="'.$html_id.'" ' : '').$csstyle.' class="field_options_'.$key.' '.$class.$this->element.'_extras_'.$key.' trextrafields_collapse'.$collapse_group.'" '.$domData.' >';
8371 if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER) && ($action == 'view' || $action == 'valid' || $action == 'editline' || $action == 'confirm_valid' || $action == 'confirm_cancel')) {
8372 $out .= '<td></td>';
8373 }
8374 $out .= '<td class="'.(empty($params['tdclass']) ? 'titlefieldcreate' : $params['tdclass']).' wordbreak';
8375 } elseif ($display_type == 'line') {
8376 $out .= '<div '.($html_id ? 'id="'.$html_id.'" ' : '').$csstyle.' class="fieldline_options_'.$key.' '.$class.$this->element.'_extras_'.$key.' trextrafields_collapse'.$collapse_group.'" '.$domData.' >';
8377 $out .= '<div style="display: inline-block; padding-right:4px" class="wordbreak';
8378 }
8379 //$out .= "titlefield";
8380 //if (GETPOST('action', 'restricthtml') == 'create') $out.='create';
8381 // BUG #11554 : For public page, use red dot for required fields, instead of bold label
8382 $tpl_context = isset($params["tpl_context"]) ? $params["tpl_context"] : "none";
8383 if ($tpl_context != "public") { // Public page : red dot instead of fieldrequired characters
8384 if ($mode != 'view' && !empty($extrafields->attributes[$this->table_element]['required'][$key])) {
8385 $out .= ' fieldrequired';
8386 }
8387 }
8388 $out .= '">';
8389 if ($tpl_context == "public") { // Public page : red dot instead of fieldrequired characters
8390 if (!empty($extrafields->attributes[$this->table_element]['help'][$key])) {
8391 $out .= $form->textwithpicto($labeltoshow, $helptoshow);
8392 } else {
8393 $out .= $labeltoshow;
8394 }
8395 if ($mode != 'view' && !empty($extrafields->attributes[$this->table_element]['required'][$key])) {
8396 $out .= '&nbsp;<span style="color: red">*</span>';
8397 }
8398 } else {
8399 if (!empty($extrafields->attributes[$this->table_element]['help'][$key])) {
8400 $out .= $form->textwithpicto($labeltoshow, $helptoshow);
8401 } else {
8402 $out .= $labeltoshow;
8403 }
8404 }
8405
8406 $out .= ($display_type == 'card' ? '</td>' : '</div>');
8407
8408 $html_id = !empty($this->id) ? $this->element.'_extras_'.$key.'_'.$this->id : '';
8409 if ($display_type == 'card') {
8410 // 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
8411 $out .= '<td '.($html_id ? 'id="'.$html_id.'" ' : '').' class="valuefieldcreate '.$this->element.'_extras_'.$key.'" '.($colspan ? ' colspan="'.$colspan.'"' : '').'>';
8412 } elseif ($display_type == 'line') {
8413 $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].'">';
8414 }
8415
8416 switch ($mode) {
8417 case "view":
8418 $out .= $extrafields->showOutputField($key, $value, '', $this->table_element);
8419 break;
8420 case "create":
8421 $out .= $extrafields->showInputField($key, $value, '', $keysuffix, '', 0, $this->id, $this->table_element);
8422 break;
8423 case "edit":
8424 $out .= $extrafields->showInputField($key, $value, '', $keysuffix, '', 0, $this->id, $this->table_element);
8425 break;
8426 }
8427
8428 $out .= ($display_type=='card' ? '</td>' : '</div>');
8429
8430 if (!empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && (($e % 2) == 1)) {
8431 $out .= ($display_type=='card' ? '</tr>' : '</div>');
8432 } else {
8433 $out .= ($display_type=='card' ? '</tr>' : '</div>');
8434 }
8435
8436 $e++;
8437 }
8438 }
8439 $out .= "\n";
8440 // Add code to manage list depending on others
8441 if (!empty($conf->use_javascript_ajax)) {
8442 $out .= $this->getJSListDependancies();
8443 }
8444
8445 $out .= '<!-- commonobject:showOptionals end --> '."\n";
8446
8447 if (empty($nbofextrafieldsshown)) {
8448 $out = '';
8449 }
8450 }
8451 }
8452
8453 $out .= $hookmanager->resPrint;
8454
8455 return $out;
8456 }
8457
8462 public function getJSListDependancies($type = '_extra')
8463 {
8464 $out = '
8465 <script nonce="'.getNonce().'">
8466 jQuery(document).ready(function() {
8467 function showOptions'.$type.'(child_list, parent_list, orig_select)
8468 {
8469 var val = $("select[name=\""+parent_list+"\"]").val();
8470 var parentVal = parent_list + ":" + val;
8471 if(typeof val == "string"){
8472 if(val != "") {
8473 var options = orig_select.find("option[parent=\""+parentVal+"\"]").clone();
8474 $("select[name=\""+child_list+"\"] option[parent]").remove();
8475 $("select[name=\""+child_list+"\"]").append(options);
8476 } else {
8477 var options = orig_select.find("option[parent]").clone();
8478 $("select[name=\""+child_list+"\"] option[parent]").remove();
8479 $("select[name=\""+child_list+"\"]").append(options);
8480 }
8481 } else if(val > 0) {
8482 var options = orig_select.find("option[parent=\""+parentVal+"\"]").clone();
8483 $("select[name=\""+child_list+"\"] option[parent]").remove();
8484 $("select[name=\""+child_list+"\"]").append(options);
8485 } else {
8486 var options = orig_select.find("option[parent]").clone();
8487 $("select[name=\""+child_list+"\"] option[parent]").remove();
8488 $("select[name=\""+child_list+"\"]").append(options);
8489 }
8490 }
8491 function setListDependencies'.$type.'() {
8492 jQuery("select option[parent]").parent().each(function() {
8493 var orig_select = {};
8494 var child_list = $(this).attr("name");
8495 orig_select[child_list] = $(this).clone();
8496 var parent = $(this).find("option[parent]:first").attr("parent");
8497 var infos = parent.split(":");
8498 var parent_list = infos[0];
8499
8500 //Hide daughters lists
8501 if ($("#"+child_list).val() == 0 && $("#"+parent_list).val() == 0){
8502 $("#"+child_list).hide();
8503 //Show mother lists
8504 } else if ($("#"+parent_list).val() != 0){
8505 $("#"+parent_list).show();
8506 }
8507 //Show the child list if the parent list value is selected
8508 $("select[name=\""+parent_list+"\"]").click(function() {
8509 if ($(this).val() != 0){
8510 $("#"+child_list).show()
8511 }
8512 });
8513
8514 //When we change parent list
8515 $("select[name=\""+parent_list+"\"]").change(function() {
8516 showOptions'.$type.'(child_list, parent_list, orig_select[child_list]);
8517 //Select the value 0 on child list after a change on the parent list
8518 $("#"+child_list).val(0).trigger("change");
8519 //Hide child lists if the parent value is set to 0
8520 if ($(this).val() == 0){
8521 $("#"+child_list).hide();
8522 }
8523 });
8524 });
8525 }
8526
8527 setListDependencies'.$type.'();
8528 });
8529 </script>'."\n";
8530 return $out;
8531 }
8532
8538 public function getRights()
8539 {
8540 global $user;
8541
8542 $module = empty($this->module) ? '' : $this->module;
8543 $element = $this->element;
8544
8545 if ($element == 'facturerec') {
8546 $element = 'facture';
8547 } elseif ($element == 'invoice_supplier_rec') {
8548 return empty($user->rights->fournisseur->facture) ? null : $user->rights->fournisseur->facture;
8549 } elseif ($module && !empty($user->rights->$module->$element)) {
8550 // for modules built with ModuleBuilder
8551 return $user->rights->$module->$element;
8552 }
8553
8554 return $user->rights->$element;
8555 }
8556
8569 public static function commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors = 0)
8570 {
8571 foreach ($tables as $table) {
8572 $sql = 'UPDATE '.$dbs->prefix().$table.' SET fk_soc = '.((int) $dest_id).' WHERE fk_soc = '.((int) $origin_id);
8573
8574 if (!$dbs->query($sql)) {
8575 if ($ignoreerrors) {
8576 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.
8577 }
8578 //$this->errors = $db->lasterror();
8579 return false;
8580 }
8581 }
8582
8583 return true;
8584 }
8585
8598 public static function commonReplaceProduct(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors = 0)
8599 {
8600 foreach ($tables as $table) {
8601 $sql = 'UPDATE '.MAIN_DB_PREFIX.$table.' SET fk_product = '.((int) $dest_id).' WHERE fk_product = '.((int) $origin_id);
8602
8603 if (!$dbs->query($sql)) {
8604 if ($ignoreerrors) {
8605 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.
8606 }
8607 //$this->errors = $db->lasterror();
8608 return false;
8609 }
8610 }
8611
8612 return true;
8613 }
8614
8627 public function defineBuyPrice($unitPrice = 0.0, $discountPercent = 0.0, $fk_product = 0)
8628 {
8629 global $conf;
8630
8631 $buyPrice = 0;
8632
8633 if (($unitPrice > 0) && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull > 0)) {
8634 // When ForceBuyingPriceIfNull is set
8635 $buyPrice = $unitPrice * (1 - $discountPercent / 100);
8636 } else {
8637 // Get cost price for margin calculation
8638 if (!empty($fk_product) && $fk_product > 0) {
8639 if (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == 'costprice') {
8640 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
8641 $product = new Product($this->db);
8642 $result = $product->fetch($fk_product);
8643 if ($result <= 0) {
8644 $this->errors[] = 'ErrorProductIdDoesNotExists';
8645 return -1;
8646 }
8647 if ($product->cost_price > 0) {
8648 $buyPrice = $product->cost_price;
8649 } elseif ($product->pmp > 0) {
8650 $buyPrice = $product->pmp;
8651 }
8652 } elseif (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == 'pmp') {
8653 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
8654 $product = new Product($this->db);
8655 $result = $product->fetch($fk_product);
8656 if ($result <= 0) {
8657 $this->errors[] = 'ErrorProductIdDoesNotExists';
8658 return -1;
8659 }
8660 if ($product->pmp > 0) {
8661 $buyPrice = $product->pmp;
8662 }
8663 }
8664
8665 if (empty($buyPrice) && isset($conf->global->MARGIN_TYPE) && in_array($conf->global->MARGIN_TYPE, array('1', 'pmp', 'costprice'))) {
8666 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
8667 $productFournisseur = new ProductFournisseur($this->db);
8668 if (($result = $productFournisseur->find_min_price_product_fournisseur($fk_product)) > 0) {
8669 $buyPrice = $productFournisseur->fourn_unitprice;
8670 } elseif ($result < 0) {
8671 $this->errors[] = $productFournisseur->error;
8672 return -2;
8673 }
8674 }
8675 }
8676 }
8677 return $buyPrice;
8678 }
8679
8680 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
8700 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')
8701 {
8702 // phpcs:enable
8703 global $conf, $user, $langs;
8704
8705 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
8706 include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
8707
8708 $sortfield = 'position_name';
8709 $sortorder = 'asc';
8710
8711 $dir = $sdir.'/';
8712 $pdir = '/';
8713
8714 $dir .= get_exdir(0, 0, 0, 0, $this, $modulepart);
8715 $pdir .= get_exdir(0, 0, 0, 0, $this, $modulepart);
8716
8717 // For backward compatibility
8718 if ($modulepart == 'product') {
8719 if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
8720 $dir = $sdir.'/'.get_exdir($this->id, 2, 0, 0, $this, $modulepart).$this->id."/photos/";
8721 $pdir = '/'.get_exdir($this->id, 2, 0, 0, $this, $modulepart).$this->id."/photos/";
8722 }
8723 }
8724
8725 // Defined relative dir to DOL_DATA_ROOT
8726 $relativedir = '';
8727 if ($dir) {
8728 $relativedir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $dir);
8729 $relativedir = preg_replace('/^[\\/]/', '', $relativedir);
8730 $relativedir = preg_replace('/[\\/]$/', '', $relativedir);
8731 }
8732
8733 $dirthumb = $dir.'thumbs/';
8734 $pdirthumb = $pdir.'thumbs/';
8735
8736 $return = '<!-- Photo -->'."\n";
8737 $nbphoto = 0;
8738
8739 $filearray = dol_dir_list($dir, "files", 0, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder) == 'desc' ?SORT_DESC:SORT_ASC), 1);
8740
8741 /*if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) // For backward compatiblity, we scan also old dirs
8742 {
8743 $filearrayold=dol_dir_list($dirold,"files",0,'','(\.meta|_preview.*\.png)$',$sortfield,(strtolower($sortorder)=='desc'?SORT_DESC:SORT_ASC),1);
8744 $filearray=array_merge($filearray, $filearrayold);
8745 }*/
8746
8747 completeFileArrayWithDatabaseInfo($filearray, $relativedir);
8748
8749 if (count($filearray)) {
8750 if ($sortfield && $sortorder) {
8751 $filearray = dol_sort_array($filearray, $sortfield, $sortorder);
8752 }
8753
8754 foreach ($filearray as $key => $val) {
8755 $photo = '';
8756 $file = $val['name'];
8757
8758 //if (dol_is_file($dir.$file) && image_format_supported($file) >= 0)
8759 if (image_format_supported($file) >= 0) {
8760 $nbphoto++;
8761 $photo = $file;
8762 $viewfilename = $file;
8763
8764 if ($size == 1 || $size == 'small') { // Format vignette
8765 // Find name of thumb file
8766 $photo_vignette = basename(getImageFileNameForSize($dir.$file, '_small'));
8767 if (!dol_is_file($dirthumb.$photo_vignette)) {
8768 // The thumb does not exists, so we will use the original file
8769 $dirthumb = $dir;
8770 $pdirthumb = $pdir;
8771 $photo_vignette = basename($file);
8772 }
8773
8774 // Get filesize of original file
8775 $imgarray = dol_getImageSize($dir.$photo);
8776
8777 if ($nbbyrow > 0) {
8778 if ($nbphoto == 1) {
8779 $return .= '<table class="valigntop center centpercent" style="border: 0; padding: 2px; border-spacing: 2px; border-collapse: separate;">';
8780 }
8781
8782 if ($nbphoto % $nbbyrow == 1) {
8783 $return .= '<tr class="center valignmiddle" style="border: 1px">';
8784 }
8785 $return .= '<td style="width: '.ceil(100 / $nbbyrow).'%" class="photo">'."\n";
8786 } elseif ($nbbyrow < 0) {
8787 $return .= '<div class="inline-block">'."\n";
8788 }
8789
8790 $relativefile = preg_replace('/^\//', '', $pdir.$photo);
8791 if (empty($nolink)) {
8792 $urladvanced = getAdvancedPreviewUrl($modulepart, $relativefile, 0, 'entity='.$this->entity);
8793 if ($urladvanced) {
8794 $return .= '<a href="'.$urladvanced.'">';
8795 } else {
8796 $return .= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.'&file='.urlencode($pdir.$photo).'" class="aphoto" target="_blank" rel="noopener noreferrer">';
8797 }
8798 }
8799
8800 // Show image (width height=$maxHeight)
8801 // Si fichier vignette disponible et image source trop grande, on utilise la vignette, sinon on utilise photo origine
8802 $alt = $langs->transnoentitiesnoconv('File').': '.$relativefile;
8803 $alt .= ' - '.$langs->transnoentitiesnoconv('Size').': '.$imgarray['width'].'x'.$imgarray['height'];
8804 if ($overwritetitle) {
8805 if (is_numeric($overwritetitle)) {
8806 $alt = '';
8807 } else {
8808 $alt = $overwritetitle;
8809 }
8810 }
8811
8812 if ($usesharelink) {
8813 if ($val['share']) {
8814 if (empty($maxHeight) || ($photo_vignette && $imgarray['height'] > $maxHeight)) {
8815 $return .= '<!-- Show original file (thumb not yet available with shared links) -->';
8816 $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).'">';
8817 } else {
8818 $return .= '<!-- Show original file -->';
8819 $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).'">';
8820 }
8821 } else {
8822 $return .= '<!-- Show nophoto file (because file is not shared) -->';
8823 $return .= '<img class="photo photowithmargin'.($addphotorefcss ? ' '.$addphotorefcss : '').'" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/public/theme/common/nophoto.png" title="'.dol_escape_htmltag($alt).'">';
8824 }
8825 } else {
8826 if (empty($maxHeight) || ($photo_vignette && $imgarray['height'] > $maxHeight)) {
8827 $return .= '<!-- Show thumb -->';
8828 $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).'">';
8829 } else {
8830 $return .= '<!-- Show original file -->';
8831 $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).'">';
8832 }
8833 }
8834
8835 if (empty($nolink)) {
8836 $return .= '</a>';
8837 }
8838
8839 if ($showfilename) {
8840 $return .= '<br>'.$viewfilename;
8841 }
8842 if ($showaction) {
8843 $return .= '<br>';
8844 // On propose la generation de la vignette si elle n'existe pas et si la taille est superieure aux limites
8845 if ($photo_vignette && (image_format_supported($photo) > 0) && ($this->imgWidth > $maxWidth || $this->imgHeight > $maxHeight)) {
8846 $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>';
8847 }
8848 // Special cas for product
8849 if ($modulepart == 'product' && ($user->hasRight('produit', 'creer') || $user->hasRight('service', 'creer'))) {
8850 // Link to resize
8851 $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; ';
8852
8853 // Link to delete
8854 $return .= '<a href="'.$_SERVER["PHP_SELF"].'?id='.$this->id.'&action=delete&token='.newToken().'&file='.urlencode($pdir.$viewfilename).'">';
8855 $return .= img_delete().'</a>';
8856 }
8857 }
8858 $return .= "\n";
8859
8860 if ($nbbyrow > 0) {
8861 $return .= '</td>';
8862 if (($nbphoto % $nbbyrow) == 0) {
8863 $return .= '</tr>';
8864 }
8865 } elseif ($nbbyrow < 0) {
8866 $return .= '</div>'."\n";
8867 }
8868 }
8869
8870 if (empty($size)) { // Format origine
8871 $return .= '<img class="photo photowithmargin" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.'&file='.urlencode($pdir.$photo).'">';
8872
8873 if ($showfilename) {
8874 $return .= '<br>'.$viewfilename;
8875 }
8876 if ($showaction) {
8877 // Special case for product
8878 if ($modulepart == 'product' && ($user->hasRight('produit', 'creer') || $user->hasRight('service', 'creer'))) {
8879 // Link to resize
8880 $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; ';
8881
8882 // Link to delete
8883 $return .= '<a href="'.$_SERVER["PHP_SELF"].'?id='.$this->id.'&action=delete&token='.newToken().'&file='.urlencode($pdir.$viewfilename).'">';
8884 $return .= img_delete().'</a>';
8885 }
8886 }
8887 }
8888
8889 // On continue ou on arrete de boucler ?
8890 if ($nbmax && $nbphoto >= $nbmax) {
8891 break;
8892 }
8893 }
8894 }
8895
8896 if ($size == 1 || $size == 'small') {
8897 if ($nbbyrow > 0) {
8898 // Ferme tableau
8899 while ($nbphoto % $nbbyrow) {
8900 $return .= '<td style="width: '.ceil(100 / $nbbyrow).'%">&nbsp;</td>';
8901 $nbphoto++;
8902 }
8903
8904 if ($nbphoto) {
8905 $return .= '</table>';
8906 }
8907 }
8908 }
8909 }
8910
8911 $this->nbphoto = $nbphoto;
8912
8913 return $return;
8914 }
8915
8916
8923 protected function isArray($info)
8924 {
8925 if (is_array($info)) {
8926 if (isset($info['type']) && $info['type'] == 'array') {
8927 return true;
8928 } else {
8929 return false;
8930 }
8931 }
8932 return false;
8933 }
8934
8941 public function isDate($info)
8942 {
8943 if (isset($info['type']) && ($info['type'] == 'date' || $info['type'] == 'datetime' || $info['type'] == 'timestamp')) {
8944 return true;
8945 }
8946 return false;
8947 }
8948
8955 public function isDuration($info)
8956 {
8957 if (is_array($info)) {
8958 if (isset($info['type']) && ($info['type'] == 'duration')) {
8959 return true;
8960 } else {
8961 return false;
8962 }
8963 } else {
8964 return false;
8965 }
8966 }
8967
8974 public function isInt($info)
8975 {
8976 if (is_array($info)) {
8977 if (isset($info['type']) && (preg_match('/(^int|int$)/i', $info['type']))) {
8978 return true;
8979 } else {
8980 return false;
8981 }
8982 } else {
8983 return false;
8984 }
8985 }
8986
8993 public function isFloat($info)
8994 {
8995 if (is_array($info)) {
8996 if (isset($info['type']) && (preg_match('/^(double|real|price)/i', $info['type']))) {
8997 return true;
8998 } else {
8999 return false;
9000 }
9001 }
9002 return false;
9003 }
9004
9011 public function isText($info)
9012 {
9013 if (is_array($info)) {
9014 if (isset($info['type']) && $info['type'] == 'text') {
9015 return true;
9016 } else {
9017 return false;
9018 }
9019 }
9020 return false;
9021 }
9022
9029 protected function canBeNull($info)
9030 {
9031 if (is_array($info)) {
9032 if (isset($info['notnull']) && $info['notnull'] != '1') {
9033 return true;
9034 } else {
9035 return false;
9036 }
9037 }
9038 return true;
9039 }
9040
9047 protected function isForcedToNullIfZero($info)
9048 {
9049 if (is_array($info)) {
9050 if (isset($info['notnull']) && $info['notnull'] == '-1') {
9051 return true;
9052 } else {
9053 return false;
9054 }
9055 }
9056 return false;
9057 }
9058
9065 protected function isIndex($info)
9066 {
9067 if (is_array($info)) {
9068 if (isset($info['index']) && $info['index'] == true) {
9069 return true;
9070 } else {
9071 return false;
9072 }
9073 }
9074 return false;
9075 }
9076
9077
9086 protected function setSaveQuery()
9087 {
9088 global $conf;
9089
9090 $queryarray = array();
9091 foreach ($this->fields as $field => $info) { // Loop on definition of fields
9092 // Depending on field type ('datetime', ...)
9093 if ($this->isDate($info)) {
9094 if (empty($this->{$field})) {
9095 $queryarray[$field] = null;
9096 } else {
9097 $queryarray[$field] = $this->db->idate($this->{$field});
9098 }
9099 } elseif ($this->isDuration($info)) {
9100 // $this->{$field} may be null, '', 0, '0', 123, '123'
9101 if ((isset($this->{$field}) && $this->{$field} != '') || !empty($info['notnull'])) {
9102 if (!isset($this->{$field})) {
9103 if (!empty($info['default'])) {
9104 $queryarray[$field] = $info['default'];
9105 } else {
9106 $queryarray[$field] = 0;
9107 }
9108 } else {
9109 $queryarray[$field] = (int) $this->{$field}; // If '0', it may be set to null later if $info['notnull'] == -1
9110 }
9111 } else {
9112 $queryarray[$field] = null;
9113 }
9114 } elseif ($this->isInt($info) || $this->isFloat($info)) {
9115 if ($field == 'entity' && is_null($this->{$field})) {
9116 $queryarray[$field] = ((int) $conf->entity);
9117 } else {
9118 // $this->{$field} may be null, '', 0, '0', 123, '123'
9119 if ((isset($this->{$field}) && $this->{$field} != '') || !empty($info['notnull'])) {
9120 if (!isset($this->{$field})) {
9121 $queryarray[$field] = 0;
9122 } elseif ($this->isInt($info)) {
9123 $queryarray[$field] = (int) $this->{$field}; // If '0', it may be set to null later if $info['notnull'] == -1
9124 } elseif ($this->isFloat($info)) {
9125 $queryarray[$field] = (double) $this->{$field}; // If '0', it may be set to null later if $info['notnull'] == -1
9126 }
9127 } else {
9128 $queryarray[$field] = null;
9129 }
9130 }
9131 } else {
9132 // Note: If $this->{$field} is not defined, it means there is a bug into definition of ->fields or a missing declaration of property
9133 // We should keep the warning generated by this because it is a bug somewhere else in code, not here.
9134 $queryarray[$field] = $this->{$field};
9135 }
9136
9137 if ($info['type'] == 'timestamp' && empty($queryarray[$field])) {
9138 unset($queryarray[$field]);
9139 }
9140 if (!empty($info['notnull']) && $info['notnull'] == -1 && empty($queryarray[$field])) {
9141 $queryarray[$field] = null; // May force 0 to null
9142 }
9143 }
9144
9145 return $queryarray;
9146 }
9147
9154 public function setVarsFromFetchObj(&$obj)
9155 {
9156 global $db;
9157
9158 foreach ($this->fields as $field => $info) {
9159 if ($this->isDate($info)) {
9160 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') {
9161 $this->$field = '';
9162 } else {
9163 $this->$field = $db->jdate($obj->$field);
9164 }
9165 } elseif ($this->isInt($info)) {
9166 if ($field == 'rowid') {
9167 $this->id = (int) $obj->$field;
9168 } else {
9169 if ($this->isForcedToNullIfZero($info)) {
9170 if (empty($obj->$field)) {
9171 $this->$field = null;
9172 } else {
9173 $this->$field = (double) $obj->$field;
9174 }
9175 } else {
9176 if (isset($obj->$field) && (!is_null($obj->$field) || (isset($info['notnull']) && $info['notnull'] == 1))) {
9177 $this->$field = (int) $obj->$field;
9178 } else {
9179 $this->$field = null;
9180 }
9181 }
9182 }
9183 } elseif ($this->isFloat($info)) {
9184 if ($this->isForcedToNullIfZero($info)) {
9185 if (empty($obj->$field)) {
9186 $this->$field = null;
9187 } else {
9188 $this->$field = (double) $obj->$field;
9189 }
9190 } else {
9191 if (isset($obj->$field) && (!is_null($obj->$field) || (isset($info['notnull']) && $info['notnull'] == 1))) {
9192 $this->$field = (double) $obj->$field;
9193 } else {
9194 $this->$field = null;
9195 }
9196 }
9197 } else {
9198 $this->$field = isset($obj->$field) ? $obj->$field : null;
9199 }
9200 }
9201
9202 // If there is no 'ref' field, we force property ->ref to ->id for a better compatibility with common functions.
9203 if (!isset($this->fields['ref']) && isset($this->id)) {
9204 $this->ref = $this->id;
9205 }
9206 }
9207
9215 public function getFieldList($alias = '', $excludefields = array())
9216 {
9217 $keys = array_keys($this->fields);
9218 if (!empty($alias)) {
9219 $keys_with_alias = array();
9220 foreach ($keys as $fieldname) {
9221 if (!empty($excludefields)) {
9222 if (in_array($fieldname, $excludefields)) { // The field is excluded and must not be in output
9223 continue;
9224 }
9225 }
9226 $keys_with_alias[] = $alias . '.' . $fieldname;
9227 }
9228 return implode(',', $keys_with_alias);
9229 } else {
9230 return implode(',', $keys);
9231 }
9232 }
9233
9241 protected function quote($value, $fieldsentry)
9242 {
9243 if (is_null($value)) {
9244 return 'NULL';
9245 } elseif (preg_match('/^(int|double|real|price)/i', $fieldsentry['type'])) {
9246 return price2num("$value");
9247 } elseif (preg_match('/int$/i', $fieldsentry['type'])) {
9248 return (int) $value;
9249 } elseif ($fieldsentry['type'] == 'boolean') {
9250 if ($value) {
9251 return 'true';
9252 } else {
9253 return 'false';
9254 }
9255 } else {
9256 return "'".$this->db->escape($value)."'";
9257 }
9258 }
9259
9260
9268 public function createCommon(User $user, $notrigger = false)
9269 {
9270 global $langs;
9271 dol_syslog(get_class($this)."::createCommon create", LOG_DEBUG);
9272
9273 $error = 0;
9274
9275 $now = dol_now();
9276
9277 $fieldvalues = $this->setSaveQuery();
9278
9279 if (array_key_exists('date_creation', $fieldvalues) && empty($fieldvalues['date_creation'])) {
9280 $fieldvalues['date_creation'] = $this->db->idate($now);
9281 }
9282 if (array_key_exists('fk_user_creat', $fieldvalues) && !($fieldvalues['fk_user_creat'] > 0)) {
9283 $fieldvalues['fk_user_creat'] = $user->id;
9284 $this->fk_user_creat = $user->id;
9285 }
9286 if (array_key_exists('user_modification_id', $fieldvalues) && !($fieldvalues['user_modification_id'] > 0)) {
9287 $fieldvalues['user_modification_id'] = $user->id;
9288 $this->user_modification_id = $user->id;
9289 }
9290 unset($fieldvalues['rowid']); // The field 'rowid' is reserved field name for autoincrement field so we don't need it into insert.
9291 if (array_key_exists('ref', $fieldvalues)) {
9292 $fieldvalues['ref'] = dol_string_nospecial($fieldvalues['ref']); // If field is a ref, we sanitize data
9293 }
9294
9295 $keys = array();
9296 $values = array(); // Array to store string forged for SQL syntax
9297 foreach ($fieldvalues as $k => $v) {
9298 $keys[$k] = $k;
9299 $value = $this->fields[$k];
9300 $values[$k] = $this->quote($v, $value); // May return string 'NULL' if $value is null
9301 }
9302
9303 // Clean and check mandatory
9304 foreach ($keys as $key) {
9305 // If field is an implicit foreign key field (so type = 'integer:...')
9306 if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') {
9307 $values[$key] = '';
9308 }
9309 if (!empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') {
9310 $values[$key] = '';
9311 }
9312
9313 if (isset($this->fields[$key]['notnull']) && $this->fields[$key]['notnull'] == 1 && (!isset($values[$key]) || $values[$key] === 'NULL') && is_null($this->fields[$key]['default'])) {
9314 $error++;
9315 $langs->load("errors");
9316 dol_syslog("Mandatory field '".$key."' is empty and required into ->fields definition of class");
9317 $this->errors[] = $langs->trans("ErrorFieldRequired", $this->fields[$key]['label']);
9318 }
9319
9320 // If value is null and there is a default value for field
9321 if (isset($this->fields[$key]['notnull']) && $this->fields[$key]['notnull'] == 1 && (!isset($values[$key]) || $values[$key] === 'NULL') && !is_null($this->fields[$key]['default'])) {
9322 $values[$key] = $this->quote($this->fields[$key]['default'], $this->fields[$key]);
9323 }
9324
9325 // If field is an implicit foreign key field (so type = 'integer:...')
9326 if (preg_match('/^integer:/i', $this->fields[$key]['type']) && empty($values[$key])) {
9327 if (isset($this->fields[$key]['default'])) {
9328 $values[$key] = ((int) $this->fields[$key]['default']);
9329 } else {
9330 $values[$key] = 'null';
9331 }
9332 }
9333 if (!empty($this->fields[$key]['foreignkey']) && empty($values[$key])) {
9334 $values[$key] = 'null';
9335 }
9336 }
9337
9338 if ($error) {
9339 return -1;
9340 }
9341
9342 $this->db->begin();
9343
9344 if (!$error) {
9345 $sql = "INSERT INTO ".$this->db->prefix().$this->table_element;
9346 $sql .= " (".implode(", ", $keys).')';
9347 $sql .= " VALUES (".implode(", ", $values).")"; // $values can contains 'abc' or 123
9348
9349 $res = $this->db->query($sql);
9350 if (!$res) {
9351 $error++;
9352 if ($this->db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
9353 $this->errors[] = "ErrorRefAlreadyExists";
9354 } else {
9355 $this->errors[] = $this->db->lasterror();
9356 }
9357 }
9358 }
9359
9360 if (!$error) {
9361 $this->id = $this->db->last_insert_id($this->db->prefix().$this->table_element);
9362 }
9363
9364 // If we have a field ref with a default value of (PROV)
9365 if (!$error) {
9366 if (key_exists('ref', $this->fields) && $this->fields['ref']['notnull'] > 0 && key_exists('default', $this->fields['ref']) && $this->fields['ref']['default'] == '(PROV)') {
9367 $sql = "UPDATE ".$this->db->prefix().$this->table_element." SET ref = '(PROV".((int) $this->id).")' WHERE (ref = '(PROV)' OR ref = '') AND rowid = ".((int) $this->id);
9368 $resqlupdate = $this->db->query($sql);
9369
9370 if ($resqlupdate === false) {
9371 $error++;
9372 $this->errors[] = $this->db->lasterror();
9373 } else {
9374 $this->ref = '(PROV'.$this->id.')';
9375 }
9376 }
9377 }
9378
9379 // Create extrafields
9380 if (!$error) {
9381 $result = $this->insertExtraFields();
9382 if ($result < 0) {
9383 $error++;
9384 }
9385 }
9386
9387 // Create lines
9388 if (!empty($this->table_element_line) && !empty($this->fk_element)) {
9389 $num = (is_array($this->lines) ? count($this->lines) : 0);
9390 for ($i = 0; $i < $num; $i++) {
9391 $line = $this->lines[$i];
9392
9393 $keyforparent = $this->fk_element;
9394 $line->$keyforparent = $this->id;
9395
9396 // Test and convert into object this->lines[$i]. When coming from REST API, we may still have an array
9397 //if (! is_object($line)) $line=json_decode(json_encode($line), false); // convert recursively array into object.
9398 if (!is_object($line)) {
9399 $line = (object) $line;
9400 }
9401
9402 $result = 0;
9403 if (method_exists($line, 'insert')) {
9404 $result = $line->insert($user, 1);
9405 } elseif (method_exists($line, 'create')) {
9406 $result = $line->create($user, 1);
9407 }
9408 if ($result < 0) {
9409 $this->error = $line->error;
9410 $this->db->rollback();
9411 return -1;
9412 }
9413 }
9414 }
9415
9416 // Triggers
9417 if (!$error && !$notrigger) {
9418 // Call triggers
9419 $result = $this->call_trigger(strtoupper(get_class($this)).'_CREATE', $user);
9420 if ($result < 0) {
9421 $error++;
9422 }
9423 // End call triggers
9424 }
9425
9426 // Commit or rollback
9427 if ($error) {
9428 $this->db->rollback();
9429 return -1;
9430 } else {
9431 $this->db->commit();
9432 return $this->id;
9433 }
9434 }
9435
9436
9445 public function fetchCommon($id, $ref = null, $morewhere = '')
9446 {
9447 if (empty($id) && empty($ref) && empty($morewhere)) {
9448 return -1;
9449 }
9450
9451 $fieldlist = $this->getFieldList('t');
9452 if (empty($fieldlist)) {
9453 return 0;
9454 }
9455
9456 $sql = "SELECT ".$fieldlist;
9457 $sql .= " FROM ".$this->db->prefix().$this->table_element.' as t';
9458
9459 if (!empty($id)) {
9460 $sql .= ' WHERE t.rowid = '.((int) $id);
9461 } elseif (!empty($ref)) {
9462 $sql .= " WHERE t.ref = '".$this->db->escape($ref)."'";
9463 } else {
9464 $sql .= ' WHERE 1 = 1'; // usage with empty id and empty ref is very rare
9465 }
9466 if (empty($id) && isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
9467 $sql .= ' AND t.entity IN ('.getEntity($this->element).')';
9468 }
9469 if ($morewhere) {
9470 $sql .= $morewhere;
9471 }
9472 $sql .= ' LIMIT 1'; // This is a fetch, to be sure to get only one record
9473
9474 $res = $this->db->query($sql);
9475 if ($res) {
9476 $obj = $this->db->fetch_object($res);
9477 if ($obj) {
9478 $this->setVarsFromFetchObj($obj);
9479
9480 // Retrieve all extrafield
9481 // fetch optionals attributes and labels
9482 $this->fetch_optionals();
9483
9484 return $this->id;
9485 } else {
9486 return 0;
9487 }
9488 } else {
9489 $this->error = $this->db->lasterror();
9490 $this->errors[] = $this->error;
9491 return -1;
9492 }
9493 }
9494
9501 public function fetchLinesCommon($morewhere = '')
9502 {
9503 $objectlineclassname = get_class($this).'Line';
9504 if (!class_exists($objectlineclassname)) {
9505 $this->error = 'Error, class '.$objectlineclassname.' not found during call of fetchLinesCommon';
9506 return -1;
9507 }
9508
9509 $objectline = new $objectlineclassname($this->db);
9510
9511 $sql = "SELECT ".$objectline->getFieldList('l');
9512 $sql .= " FROM ".$this->db->prefix().$objectline->table_element." as l";
9513 $sql .= " WHERE l.fk_".$this->db->escape($this->element)." = ".((int) $this->id);
9514 if ($morewhere) {
9515 $sql .= $morewhere;
9516 }
9517 if (isset($objectline->fields['position'])) {
9518 $sql .= $this->db->order('position', 'ASC');
9519 }
9520
9521 $resql = $this->db->query($sql);
9522 if ($resql) {
9523 $num_rows = $this->db->num_rows($resql);
9524 $i = 0;
9525 $this->lines = array();
9526 while ($i < $num_rows) {
9527 $obj = $this->db->fetch_object($resql);
9528 if ($obj) {
9529 $newline = new $objectlineclassname($this->db);
9530 $newline->setVarsFromFetchObj($obj);
9531
9532 $this->lines[] = $newline;
9533 }
9534 $i++;
9535 }
9536
9537 return 1;
9538 } else {
9539 $this->error = $this->db->lasterror();
9540 $this->errors[] = $this->error;
9541 return -1;
9542 }
9543 }
9544
9552 public function updateCommon(User $user, $notrigger = false)
9553 {
9554 global $conf, $langs;
9555 dol_syslog(get_class($this)."::updateCommon update", LOG_DEBUG);
9556
9557 $error = 0;
9558
9559 $now = dol_now();
9560
9561 // $this->oldcopy should have been set by the caller of update
9562 //if (empty($this->oldcopy)) {
9563 // $this->oldcopy = dol_clone($this);
9564 //}
9565
9566 $fieldvalues = $this->setSaveQuery();
9567
9568 if (array_key_exists('date_modification', $fieldvalues) && empty($fieldvalues['date_modification'])) {
9569 $fieldvalues['date_modification'] = $this->db->idate($now);
9570 }
9571 if (array_key_exists('fk_user_modif', $fieldvalues) && !($fieldvalues['fk_user_modif'] > 0)) {
9572 $fieldvalues['fk_user_modif'] = $user->id;
9573 }
9574 unset($fieldvalues['rowid']); // The field 'rowid' is reserved field name for autoincrement field so we don't need it into update.
9575 if (array_key_exists('ref', $fieldvalues)) {
9576 $fieldvalues['ref'] = dol_string_nospecial($fieldvalues['ref']); // If field is a ref, we sanitize data
9577 }
9578
9579 // Add quotes and escape on fields with type string
9580 $keys = array();
9581 $values = array();
9582 $tmp = array();
9583 foreach ($fieldvalues as $k => $v) {
9584 $keys[$k] = $k;
9585 $value = $this->fields[$k];
9586 $values[$k] = $this->quote($v, $value);
9587 $tmp[] = $k.'='.$this->quote($v, $this->fields[$k]);
9588 }
9589
9590 // Clean and check mandatory fields
9591 foreach ($keys as $key) {
9592 if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') {
9593 $values[$key] = ''; // This is an implicit foreign key field
9594 }
9595 if (!empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') {
9596 $values[$key] = ''; // This is an explicit foreign key field
9597 }
9598
9599 //var_dump($key.'-'.$values[$key].'-'.($this->fields[$key]['notnull'] == 1));
9600 /*
9601 if ($this->fields[$key]['notnull'] == 1 && empty($values[$key]))
9602 {
9603 $error++;
9604 $this->errors[]=$langs->trans("ErrorFieldRequired", $this->fields[$key]['label']);
9605 }*/
9606 }
9607
9608 $sql = 'UPDATE '.$this->db->prefix().$this->table_element.' SET '.implode(', ', $tmp).' WHERE rowid='.((int) $this->id);
9609
9610 $this->db->begin();
9611
9612 if (!$error) {
9613 $res = $this->db->query($sql);
9614 if (!$res) {
9615 $error++;
9616 $this->errors[] = $this->db->lasterror();
9617 }
9618 }
9619
9620 // Update extrafield
9621 if (!$error) {
9622 $result = $this->insertExtraFields();
9623 if ($result < 0) {
9624 $error++;
9625 }
9626 }
9627
9628 // Triggers
9629 if (!$error && !$notrigger) {
9630 // Call triggers
9631 $result = $this->call_trigger(strtoupper(get_class($this)).'_MODIFY', $user);
9632 if ($result < 0) {
9633 $error++;
9634 } //Do also here what you must do to rollback action if trigger fail
9635 // End call triggers
9636 }
9637
9638 // Commit or rollback
9639 if ($error) {
9640 $this->db->rollback();
9641 return -1;
9642 } else {
9643 $this->db->commit();
9644 return $this->id;
9645 }
9646 }
9647
9656 public function deleteCommon(User $user, $notrigger = false, $forcechilddeletion = 0)
9657 {
9658 dol_syslog(get_class($this)."::deleteCommon delete", LOG_DEBUG);
9659
9660 $error = 0;
9661
9662 $this->db->begin();
9663
9664 if ($forcechilddeletion) { // Force also delete of childtables that should lock deletion in standard case when option force is off
9665 foreach ($this->childtables as $table) {
9666 $sql = "DELETE FROM ".$this->db->prefix().$table." WHERE ".$this->fk_element." = ".((int) $this->id);
9667 $resql = $this->db->query($sql);
9668 if (!$resql) {
9669 $this->error = $this->db->lasterror();
9670 $this->errors[] = $this->error;
9671 $this->db->rollback();
9672 return -1;
9673 }
9674 }
9675 } elseif (!empty($this->childtables)) { // If object has childs linked with a foreign key field, we check all child tables.
9676 $objectisused = $this->isObjectUsed($this->id);
9677 if (!empty($objectisused)) {
9678 dol_syslog(get_class($this)."::deleteCommon Can't delete record as it has some child", LOG_WARNING);
9679 $this->error = 'ErrorRecordHasChildren';
9680 $this->errors[] = $this->error;
9681 $this->db->rollback();
9682 return 0;
9683 }
9684 }
9685
9686 // Delete cascade first
9687 if (is_array($this->childtablesoncascade) && !empty($this->childtablesoncascade)) {
9688 foreach ($this->childtablesoncascade as $table) {
9689 $deleteFromObject = explode(':', $table);
9690 if (count($deleteFromObject) >= 2) {
9691 $className = str_replace('@', '', $deleteFromObject[0]);
9692 $filePath = $deleteFromObject[1];
9693 $columnName = $deleteFromObject[2];
9694 $TMoreSQL = array();
9695 $more_sql = $deleteFromObject[3];
9696 if (!empty($more_sql)) {
9697 $TMoreSQL['customsql'] = $more_sql;
9698 }
9699 if (dol_include_once($filePath)) {
9700 $childObject = new $className($this->db);
9701 if (method_exists($childObject, 'deleteByParentField')) {
9702 $result = $childObject->deleteByParentField($this->id, $columnName, $TMoreSQL);
9703 if ($result < 0) {
9704 $error++;
9705 $this->errors[] = $childObject->error;
9706 break;
9707 }
9708 } else {
9709 $error++;
9710 $this->errors[] = "You defined a cascade delete on an object $childObject but there is no method deleteByParentField for it";
9711 break;
9712 }
9713 } else {
9714 $error++;
9715 $this->errors[] = 'Cannot include child class file '.$filePath;
9716 break;
9717 }
9718 } else {
9719 // Delete record in child table
9720 $sql = "DELETE FROM ".$this->db->prefix().$table." WHERE ".$this->fk_element." = ".((int) $this->id);
9721
9722 $resql = $this->db->query($sql);
9723 if (!$resql) {
9724 $error++;
9725 $this->error = $this->db->lasterror();
9726 $this->errors[] = $this->error;
9727 break;
9728 }
9729 }
9730 }
9731 }
9732
9733 if (!$error) {
9734 if (!$notrigger) {
9735 // Call triggers
9736 $result = $this->call_trigger(strtoupper(get_class($this)).'_DELETE', $user);
9737 if ($result < 0) {
9738 $error++;
9739 } // Do also here what you must do to rollback action if trigger fail
9740 // End call triggers
9741 }
9742 }
9743
9744 // Delete llx_ecm_files
9745 if (!$error) {
9746 $res = $this->deleteEcmFiles(1); // Deleting files physically is done later with the dol_delete_dir_recursive
9747 if (!$res) {
9748 $error++;
9749 }
9750 }
9751
9752 // Delete linked object
9753 $res = $this->deleteObjectLinked();
9754 if ($res < 0) {
9755 $error++;
9756 }
9757
9758 if (!$error && !empty($this->isextrafieldmanaged)) {
9759 $result = $this->deleteExtraFields();
9760 if ($result < 0) {
9761 $error++;
9762 }
9763 }
9764
9765 if (!$error) {
9766 $sql = 'DELETE FROM '.$this->db->prefix().$this->table_element.' WHERE rowid='.((int) $this->id);
9767
9768 $resql = $this->db->query($sql);
9769 if (!$resql) {
9770 $error++;
9771 $this->errors[] = $this->db->lasterror();
9772 }
9773 }
9774
9775 // Commit or rollback
9776 if ($error) {
9777 $this->db->rollback();
9778 return -1;
9779 } else {
9780 $this->db->commit();
9781 return 1;
9782 }
9783 }
9784
9795 public function deleteByParentField($parentId = 0, $parentField = '', $filter = array(), $filtermode = "AND")
9796 {
9797 global $user;
9798
9799 $error = 0;
9800 $deleted = 0;
9801
9802 if (!empty($parentId) && !empty($parentField)) {
9803 $this->db->begin();
9804
9805 $sql = "SELECT rowid FROM ".$this->db->prefix().$this->table_element;
9806 $sql .= " WHERE ".$parentField." = ".(int) $parentId;
9807
9808 // Manage filters
9809 $sqlwhere = array();
9810 if (count($filter) > 0) {
9811 foreach ($filter as $key => $value) {
9812 if ($key == 'customsql') {
9813 $sqlwhere[] = $value;
9814 } elseif (strpos($value, '%') === false) {
9815 $sqlwhere[] = $key." IN (".$this->db->sanitize($this->db->escape($value)).")";
9816 } else {
9817 $sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'";
9818 }
9819 }
9820 }
9821 if (count($sqlwhere) > 0) {
9822 $sql .= " AND (".implode(" ".$filtermode." ", $sqlwhere).")";
9823 }
9824
9825 $resql = $this->db->query($sql);
9826 if (!$resql) {
9827 $this->errors[] = $this->db->lasterror();
9828 $error++;
9829 } else {
9830 while ($obj = $this->db->fetch_object($resql)) {
9831 $result = $this->fetch($obj->rowid);
9832 if ($result < 0) {
9833 $error++;
9834 $this->errors[] = $this->error;
9835 } else {
9836 if (get_class($this) == 'Contact') { // TODO special code because delete() for contact has not been standardized like other delete.
9837 $result = $this->delete();
9838 } else {
9839 $result = $this->delete($user);
9840 }
9841 if ($result < 0) {
9842 $error++;
9843 $this->errors[] = $this->error;
9844 } else {
9845 $deleted++;
9846 }
9847 }
9848 }
9849 }
9850
9851 if (empty($error)) {
9852 $this->db->commit();
9853 return $deleted;
9854 } else {
9855 $this->error = implode(', ', $this->errors);
9856 $this->db->rollback();
9857 return $error * -1;
9858 }
9859 }
9860
9861 return $deleted;
9862 }
9863
9872 public function deleteLineCommon(User $user, $idline, $notrigger = false)
9873 {
9874 global $conf;
9875
9876 $error = 0;
9877
9878 $tmpforobjectclass = get_class($this);
9879 $tmpforobjectlineclass = ucfirst($tmpforobjectclass).'Line';
9880
9881 $this->db->begin();
9882
9883 // Call trigger
9884 $result = $this->call_trigger('LINE'.strtoupper($tmpforobjectclass).'_DELETE', $user);
9885 if ($result < 0) {
9886 $error++;
9887 }
9888 // End call triggers
9889
9890 if (empty($error)) {
9891 $sql = "DELETE FROM ".$this->db->prefix().$this->table_element_line;
9892 $sql .= " WHERE rowid = ".((int) $idline);
9893
9894 $resql = $this->db->query($sql);
9895 if (!$resql) {
9896 $this->error = "Error ".$this->db->lasterror();
9897 $error++;
9898 }
9899 }
9900
9901 if (empty($error)) {
9902 // Remove extrafields
9903 $tmpobjectline = new $tmpforobjectlineclass($this->db);
9904 if (!isset($tmpobjectline->isextrafieldmanaged) || !empty($tmpobjectline->isextrafieldmanaged)) {
9905 $tmpobjectline->id = $idline;
9906 $result = $tmpobjectline->deleteExtraFields();
9907 if ($result < 0) {
9908 $error++;
9909 $this->error = "Error ".get_class($this)."::deleteLineCommon deleteExtraFields error -4 ".$tmpobjectline->error;
9910 }
9911 }
9912 }
9913
9914 if (empty($error)) {
9915 $this->db->commit();
9916 return 1;
9917 } else {
9918 dol_syslog(get_class($this)."::deleteLineCommon ERROR:".$this->error, LOG_ERR);
9919 $this->db->rollback();
9920 return -1;
9921 }
9922 }
9923
9924
9934 public function setStatusCommon($user, $status, $notrigger = 0, $triggercode = '')
9935 {
9936 $error = 0;
9937
9938 $this->db->begin();
9939
9940 $statusfield = 'status';
9941 if (in_array($this->element, array('don', 'donation', 'shipping'))) {
9942 $statusfield = 'fk_statut';
9943 }
9944
9945 $sql = "UPDATE ".$this->db->prefix().$this->table_element;
9946 $sql .= " SET ".$statusfield." = ".((int) $status);
9947 $sql .= " WHERE rowid = ".((int) $this->id);
9948
9949 if ($this->db->query($sql)) {
9950 if (!$error) {
9951 $this->oldcopy = clone $this;
9952 }
9953
9954 if (!$error && !$notrigger) {
9955 // Call trigger
9956 $result = $this->call_trigger($triggercode, $user);
9957 if ($result < 0) {
9958 $error++;
9959 }
9960 }
9961
9962 if (!$error) {
9963 $this->status = $status;
9964 $this->db->commit();
9965 return 1;
9966 } else {
9967 $this->db->rollback();
9968 return -1;
9969 }
9970 } else {
9971 $this->error = $this->db->error();
9972 $this->db->rollback();
9973 return -1;
9974 }
9975 }
9976
9977
9984 public function initAsSpecimenCommon()
9985 {
9986 global $user;
9987
9988 $this->id = 0;
9989 $this->specimen = 1;
9990 $fields = array(
9991 'label' => 'This is label',
9992 'ref' => 'ABCD1234',
9993 'description' => 'This is a description',
9994 'qty' => 123.12,
9995 'note_public' => 'Public note',
9996 'note_private' => 'Private note',
9997 'date_creation' => (dol_now() - 3600 * 48),
9998 'date_modification' => (dol_now() - 3600 * 24),
9999 'fk_user_creat' => $user->id,
10000 'fk_user_modif' => $user->id,
10001 'date' => dol_now(),
10002 );
10003 foreach ($fields as $key => $value) {
10004 if (array_key_exists($key, $this->fields)) {
10005 $this->{$key} = $value;
10006 }
10007 }
10008
10009 // Force values to default values when known
10010 if (property_exists($this, 'fields')) {
10011 foreach ($this->fields as $key => $value) {
10012 // If fields are already set, do nothing
10013 if (array_key_exists($key, $fields)) {
10014 continue;
10015 }
10016
10017 if (!empty($value['default'])) {
10018 $this->$key = $value['default'];
10019 }
10020 }
10021 }
10022
10023 return 1;
10024 }
10025
10026
10027 /* Part for comments */
10028
10033 public function fetchComments()
10034 {
10035 require_once DOL_DOCUMENT_ROOT.'/core/class/comment.class.php';
10036
10037 $comment = new Comment($this->db);
10038 $result = $comment->fetchAllFor($this->element, $this->id);
10039 if ($result < 0) {
10040 $this->errors = array_merge($this->errors, $comment->errors);
10041 return -1;
10042 } else {
10043 $this->comments = $comment->comments;
10044 }
10045 return count($this->comments);
10046 }
10047
10053 public function getNbComments()
10054 {
10055 return count($this->comments);
10056 }
10057
10064 public function trimParameters($parameters)
10065 {
10066 if (!is_array($parameters)) {
10067 return;
10068 }
10069 foreach ($parameters as $parameter) {
10070 if (isset($this->$parameter)) {
10071 $this->$parameter = trim($this->$parameter);
10072 }
10073 }
10074 }
10075
10076 /* Part for categories/tags */
10077
10088 public function getCategoriesCommon($type_categ)
10089 {
10090 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
10091
10092 // Get current categories
10093 $c = new Categorie($this->db);
10094 $existing = $c->containing($this->id, $type_categ, 'id');
10095
10096 return $existing;
10097 }
10098
10111 public function setCategoriesCommon($categories, $type_categ = '', $remove_existing = true)
10112 {
10113 // Handle single category
10114 if (!is_array($categories)) {
10115 $categories = array($categories);
10116 }
10117
10118 dol_syslog(get_class($this)."::setCategoriesCommon Oject Id:".$this->id.' type_categ:'.$type_categ.' nb tag add:'.count($categories), LOG_DEBUG);
10119
10120 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
10121
10122 if (empty($type_categ)) {
10123 dol_syslog(__METHOD__.': Type '.$type_categ.'is an unknown category type. Done nothing.', LOG_ERR);
10124 return -1;
10125 }
10126
10127 // Get current categories
10128 $c = new Categorie($this->db);
10129 $existing = $c->containing($this->id, $type_categ, 'id');
10130 if ($remove_existing) {
10131 // Diff
10132 if (is_array($existing)) {
10133 $to_del = array_diff($existing, $categories);
10134 $to_add = array_diff($categories, $existing);
10135 } else {
10136 $to_del = array(); // Nothing to delete
10137 $to_add = $categories;
10138 }
10139 } else {
10140 $to_del = array(); // Nothing to delete
10141 $to_add = array_diff($categories, $existing);
10142 }
10143
10144 $error = 0;
10145 $ok = 0;
10146
10147 // Process
10148 foreach ($to_del as $del) {
10149 if ($c->fetch($del) > 0) {
10150 $result=$c->del_type($this, $type_categ);
10151 if ($result < 0) {
10152 $error++;
10153 $this->error = $c->error;
10154 $this->errors = $c->errors;
10155 break;
10156 } else {
10157 $ok += $result;
10158 }
10159 }
10160 }
10161 foreach ($to_add as $add) {
10162 if ($c->fetch($add) > 0) {
10163 $result = $c->add_type($this, $type_categ);
10164 if ($result < 0) {
10165 $error++;
10166 $this->error = $c->error;
10167 $this->errors = $c->errors;
10168 break;
10169 } else {
10170 $ok += $result;
10171 }
10172 }
10173 }
10174
10175 return $error ? (-1 * $error) : $ok;
10176 }
10177
10186 public function cloneCategories($fromId, $toId, $type = '')
10187 {
10188 $this->db->begin();
10189
10190 if (empty($type)) {
10191 $type = $this->table_element;
10192 }
10193
10194 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
10195 $categorystatic = new Categorie($this->db);
10196
10197 $sql = "INSERT INTO ".$this->db->prefix()."categorie_".(empty($categorystatic->MAP_CAT_TABLE[$type]) ? $type : $categorystatic->MAP_CAT_TABLE[$type])." (fk_categorie, fk_product)";
10198 $sql .= " SELECT fk_categorie, $toId FROM ".$this->db->prefix()."categorie_".(empty($categorystatic->MAP_CAT_TABLE[$type]) ? $type : $categorystatic->MAP_CAT_TABLE[$type]);
10199 $sql .= " WHERE fk_product = ".((int) $fromId);
10200
10201 if (!$this->db->query($sql)) {
10202 $this->error = $this->db->lasterror();
10203 $this->db->rollback();
10204 return -1;
10205 }
10206
10207 $this->db->commit();
10208 return 1;
10209 }
10210
10217 public function deleteEcmFiles($mode = 0)
10218 {
10219 global $conf;
10220
10221 $this->db->begin();
10222
10223 // Delete in database with mode 0
10224 if ($mode == 0) {
10225 switch ($this->element) {
10226 case 'propal':
10227 $element = 'propale';
10228 break;
10229 case 'product':
10230 $element = 'produit';
10231 break;
10232 case 'order_supplier':
10233 $element = 'fournisseur/commande';
10234 break;
10235 case 'invoice_supplier':
10236 $element = 'fournisseur/facture/'.get_exdir($this->id, 2, 0, 1, $this, 'invoice_supplier');
10237 break;
10238 case 'shipping':
10239 $element = 'expedition/sending';
10240 break;
10241 default:
10242 $element = $this->element;
10243 }
10244
10245 // Delete ecm_files extrafields
10246 $sql = "DELETE FROM ".$this->db->prefix()."ecm_files_extrafields WHERE fk_object IN (";
10247 $sql .= " SELECT rowid FROM ".$this->db->prefix()."ecm_files WHERE filename LIKE '".$this->db->escape($this->ref)."%'";
10248 $sql .= " AND filepath = '".$this->db->escape($element)."/".$this->db->escape($this->ref)."' AND entity = ".((int) $conf->entity); // No need of getEntity here
10249 $sql .= ")";
10250
10251 if (!$this->db->query($sql)) {
10252 $this->error = $this->db->lasterror();
10253 $this->db->rollback();
10254 return false;
10255 }
10256
10257 // Delete ecm_files
10258 $sql = "DELETE FROM ".$this->db->prefix()."ecm_files";
10259 $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%'";
10260 $sql .= " AND filepath = '".$this->db->escape($element)."/".$this->db->escape($this->ref)."' AND entity = ".((int) $conf->entity); // No need of getEntity here
10261
10262 if (!$this->db->query($sql)) {
10263 $this->error = $this->db->lasterror();
10264 $this->db->rollback();
10265 return false;
10266 }
10267 }
10268
10269 // Delete in database with mode 1
10270 if ($mode == 1) {
10271 $sql = 'DELETE FROM '.$this->db->prefix()."ecm_files_extrafields";
10272 $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).")";
10273 $resql = $this->db->query($sql);
10274 if (!$resql) {
10275 $this->error = $this->db->lasterror();
10276 $this->db->rollback();
10277 return false;
10278 }
10279
10280 $sql = 'DELETE FROM '.$this->db->prefix()."ecm_files";
10281 $sql .= " WHERE src_object_type = '".$this->db->escape($this->table_element.(empty($this->module) ? "" : "@".$this->module))."' AND src_object_id = ".((int) $this->id);
10282 $resql = $this->db->query($sql);
10283 if (!$resql) {
10284 $this->error = $this->db->lasterror();
10285 $this->db->rollback();
10286 return false;
10287 }
10288 }
10289
10290 $this->db->commit();
10291 return true;
10292 }
10293}
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:1655
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.