46 const TRIGGER_PREFIX =
'';
76 public $errors = array();
81 private $validateFieldsErrors = array();
92 public $element_for_permission;
97 public $table_element;
102 public $table_element_line =
'';
112 public $array_options = array();
117 public $array_languages =
null;
122 public $contacts_ids;
127 public $linked_objects;
132 public $linkedObjectsIds;
137 public $linkedObjects;
142 private $linkedObjectsFullLoaded = array();
152 protected $table_ref_field =
'';
157 public $restrictiononfksoc = 0;
165 public $context = array();
245 public $ref_previous;
286 public $country_code;
329 public $barcode_type;
335 public $barcode_type_code;
341 public $barcode_type_label;
347 public $barcode_type_coder;
353 public $mode_reglement_id;
359 public $cond_reglement_id;
364 public $demand_reason_id;
370 public $transport_mode_id;
377 public $cond_reglement;
384 public $fk_delivery_address;
390 public $shipping_method_id;
409 public $last_main_doc;
439 public $note_private;
463 public $total_localtax1;
469 public $total_localtax2;
486 public $comments = array();
512 public $date_creation;
517 public $date_validation;
522 public $date_modification;
527 public $date_cloture;
538 public $user_creation;
542 public $user_creation_id;
553 public $user_validation;
557 public $user_validation_id;
561 public $user_closing_id;
567 public $user_modification;
571 public $user_modification_id;
578 public $fk_user_creat;
584 public $fk_user_modif;
587 public $next_prev_filter;
592 public $specimen = 0;
605 protected $labelStatus;
606 protected $labelStatusShort;
612 protected $childtables = array();
619 protected $childtablesoncascade = array();
639 $sql =
"SELECT rowid, ref, ref_ext";
640 $sql .=
" FROM ".$db->prefix().$element;
641 $sql .=
" WHERE entity IN (".getEntity($element).
")";
644 $sql .=
" AND rowid = ".((int) $id);
646 $sql .=
" AND ref = '".$db->escape($ref).
"'";
647 } elseif ($ref_ext) {
648 $sql .=
" AND ref_ext = '".$db->escape($ref_ext).
"'";
650 $error =
'ErrorWrongParameters';
654 if ($ref || $ref_ext) {
655 $sql .=
" AND entity = ".((int) $conf->entity);
658 dol_syslog(get_class().
"::isExistingObject", LOG_DEBUG);
659 $resql = $db->query($sql);
661 $num = $db->num_rows(
$resql);
679 return $this->error.(is_array($this->errors) ? (($this->error !=
'' ?
', ' :
'').join(
', ', $this->errors)) :
'');
693 $parameters = array(
'objref'=>$objref);
695 $reshook = $hookmanager->executeHooks(
'getFormatedCustomerRef', $parameters, $this, $action);
697 return $hookmanager->resArray[
'objref'];
699 return $objref.(isset($hookmanager->resArray[
'objref']) ? $hookmanager->resArray[
'objref'] :
'');
712 $parameters = array(
'objref'=>$objref);
714 $reshook = $hookmanager->executeHooks(
'getFormatedSupplierRef', $parameters, $this, $action);
716 return $hookmanager->resArray[
'objref'];
718 return $objref.(isset($hookmanager->resArray[
'objref']) ? $hookmanager->resArray[
'objref'] :
'');
730 public function getFullName($langs, $option = 0, $nameorder = -1, $maxlen = 0)
733 $lastname = $this->lastname;
734 $firstname = $this->firstname;
735 if (empty($lastname)) {
736 $lastname = (isset($this->lastname) ? $this->lastname : (isset($this->
name) ? $this->
name : (isset($this->nom) ? $this->nom : (isset($this->societe) ? $this->societe : (isset($this->company) ? $this->company :
'')))));
740 if (!empty($option) && !empty($this->civility_code)) {
741 if ($langs->transnoentitiesnoconv(
"Civility".$this->civility_code) !=
"Civility".$this->civility_code) {
742 $ret .= $langs->transnoentitiesnoconv(
"Civility".$this->civility_code).
' ';
744 $ret .= $this->civility_code.
' ';
762 if (!empty($conf->global->MAIN_FIRST_TO_UPPER)) {
768 if (!empty($conf->global->MAIN_ALL_TO_UPPER)) {
773 if (!empty($conf->global->MAIN_ALL_TOWN_TO_UPPER)) {
777 if (isset($this->email)) {
780 if (isset($this->personal_email)) {
793 $return =
'<div class="box-flex-item box-flex-grow-zero">';
794 $return .=
'<div class="info-box info-box-sm">';
795 $return .=
'<span class="info-box-icon bg-infobox-action">';
797 $return .=
'</span>';
798 $return .=
'<div class="info-box-content">';
799 $return .=
'<span class="info-box-ref">'.(method_exists($this,
'getNomUrl') ? $this->getNomUrl() : $this->ref).
'</span>';
800 if (property_exists($this,
'label')) {
801 $return .=
'<br><span class="info-box-label opacitymedium">'.$this->label.
'</span>';
803 if (method_exists($this,
'getLibStatut')) {
804 $return .=
'<br><div class="info-box-status margintoponly">'.$this->getLibStatut(5).
'</div>';
822 public function getFullAddress($withcountry = 0, $sep =
"\n", $withregion = 0, $extralangcode =
'')
824 if ($withcountry && $this->country_id && (empty($this->country_code) || empty($this->country))) {
825 require_once DOL_DOCUMENT_ROOT.
'/core/lib/company.lib.php';
826 $tmparray =
getCountry($this->country_id,
'all');
827 $this->country_code = $tmparray[
'code'];
828 $this->country = $tmparray[
'label'];
831 if ($withregion && $this->state_id && (empty($this->state_code) || empty($this->state) || empty($this->region) || empty($this->region_code))) {
832 require_once DOL_DOCUMENT_ROOT.
'/core/lib/company.lib.php';
833 $tmparray =
getState($this->state_id,
'all', 0, 1);
834 $this->state_code = $tmparray[
'code'];
835 $this->state = $tmparray[
'label'];
836 $this->region_code = $tmparray[
'region_code'];
837 $this->region = $tmparray[
'region'];
853 global $conf, $langs,
$form, $extralanguages;
855 $countriesusingstate = array(
'AU',
'US',
'IN',
'GB',
'ES',
'UK',
'TR');
859 $elementforaltlanguage = $this->element;
860 if ($this->element ==
'societe') {
861 $thirdpartyid = $this->id;
863 if ($this->element ==
'contact') {
864 $contactid = $this->id;
865 $thirdpartyid = empty($this->fk_soc) ? 0 : $this->fk_soc;
867 if ($this->element ==
'user') {
868 $contactid = $this->contact_id;
869 $thirdpartyid = empty($object->fk_soc) ? 0 : $object->fk_soc;
875 $coords = $this->
getFullAddress(1,
', ', (!empty($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT) ? $conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT : 0));
877 if (!empty($conf->use_javascript_ajax)) {
880 if ($this->element ==
'contact' && !empty($conf->global->MAIN_SHOW_COMPANY_NAME_IN_BANNER_ADDRESS)) {
881 $namecoords .= $object->name.
'<br>';
883 $namecoords .= $this->
getFullName($langs, 1).
'<br>'.$coords;
885 $out .=
'<a href="#" class="hideonsmartphone" onclick="return copyToClipboard(\''.dol_escape_js($namecoords).
'\',\
''.dol_escape_js($langs->trans(
"HelpCopyToClipboard")).
'\');
">';
886 $out .= img_picto($langs->trans("Address
"), 'map-marker-alt');
889 $address = dol_print_address($coords, 'address_'.$htmlkey.'_'.$this->id, $this->element, $this->id, 1, ', ');
896 // List of extra languages
897 $arrayoflangcode = array();
898 if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) {
899 $arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE;
902 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
903 if (!is_object($extralanguages)) {
904 include_once DOL_DOCUMENT_ROOT.'/core/class/extralanguages.class.php';
905 $extralanguages = new ExtraLanguages($this->db);
907 $extralanguages->fetch_name_extralanguages($elementforaltlanguage);
909 if (!empty($extralanguages->attributes[$elementforaltlanguage]['address']) || !empty($extralanguages->attributes[$elementforaltlanguage]['town'])) {
910 $out .= "<!-- alternatelanguage
for '".$elementforaltlanguage."' set to fields
'".join(',
', $extralanguages->attributes[$elementforaltlanguage])."' -->\n
";
911 $this->fetchValuesForExtraLanguages();
912 if (!is_object($form)) {
913 $form = new Form($this->db);
916 // If there is extra languages
917 foreach ($arrayoflangcode as $extralangcode) {
918 $s = picto_from_langcode($extralangcode, 'class="pictoforlang paddingright
"');
919 // This also call dol_format_address()
920 $coords = $this->getFullAddress(1, ', ', $conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT, $extralangcode);
921 $htmltext .= $s.dol_print_address($coords, 'address_'.$htmlkey.'_'.$this->id, $this->element, $this->id, 1, ', ');
923 $out .= $form->textwithpicto('', $htmltext, -1, 'language', 'opacitymedium paddingleft');
928 // If MAIN_FORCE_STATE_INTO_ADDRESS is on, state is already returned previously with getFullAddress
929 if (!in_array($this->country_code, $countriesusingstate) && empty($conf->global->MAIN_FORCE_STATE_INTO_ADDRESS)
930 && empty($conf->global->SOCIETE_DISABLE_STATE) && $this->state) {
931 if (!empty($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT) && $conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 1 && $this->region) {
932 $out .= ($outdone ? ' - ' : '').$this->region.' - '.$this->state;
934 $out .= ($outdone ? ' - ' : '').$this->state;
940 $out = '<div class="address
inline-block
">'.$out.'</div>';
943 if (!empty($this->phone) || !empty($this->phone_pro) || !empty($this->phone_mobile) || !empty($this->phone_perso) || !empty($this->fax) || !empty($this->office_phone) || !empty($this->user_mobile) || !empty($this->office_fax)) {
944 $out .= ($outdone ? '<br>' : '');
946 if (!empty($this->phone) && empty($this->phone_pro)) { // For objects that store pro phone into ->phone
947 $out .= dol_print_phone($this->phone, $this->country_code, $contactid, $thirdpartyid, 'AC_TEL', ' ', 'phone', $langs->trans("PhonePro
"));
950 if (!empty($this->phone_pro)) {
951 $out .= dol_print_phone($this->phone_pro, $this->country_code, $contactid, $thirdpartyid, 'AC_TEL', ' ', 'phone', $langs->trans("PhonePro
"));
954 if (!empty($this->phone_mobile)) {
955 $out .= dol_print_phone($this->phone_mobile, $this->country_code, $contactid, $thirdpartyid, 'AC_TEL', ' ', 'mobile', $langs->trans("PhoneMobile
"));
958 if (!empty($this->phone_perso)) {
959 $out .= dol_print_phone($this->phone_perso, $this->country_code, $contactid, $thirdpartyid, 'AC_TEL', ' ', 'phone', $langs->trans("PhonePerso
"));
962 if (!empty($this->office_phone)) {
963 $out .= dol_print_phone($this->office_phone, $this->country_code, $contactid, $thirdpartyid, 'AC_TEL', ' ', 'phone', $langs->trans("PhonePro
"));
966 if (!empty($this->user_mobile)) {
967 $out .= dol_print_phone($this->user_mobile, $this->country_code, $contactid, $thirdpartyid, 'AC_TEL', ' ', 'mobile', $langs->trans("PhoneMobile
"));
970 if (!empty($this->fax)) {
971 $out .= dol_print_phone($this->fax, $this->country_code, $contactid, $thirdpartyid, 'AC_FAX', ' ', 'fax', $langs->trans("Fax
"));
974 if (!empty($this->office_fax)) {
975 $out .= dol_print_phone($this->office_fax, $this->country_code, $contactid, $thirdpartyid, 'AC_FAX', ' ', 'fax', $langs->trans("Fax
"));
980 $out .= '<div style="clear: both;
"></div>';
983 if (!empty($this->email)) {
984 $out .= dol_print_email($this->email, $this->id, $object->id, 'AC_EMAIL', 0, 0, 1);
987 if (!empty($this->url)) {
988 //$out.=dol_print_url($this->url,'_goout',0,1);//steve changed to blank
989 $out .= dol_print_url($this->url, '_blank', 0, 1);
993 if (isModEnabled('socialnetworks')) {
994 $outsocialnetwork = '';
996 if (!empty($this->socialnetworks) && is_array($this->socialnetworks) && count($this->socialnetworks) > 0) {
997 $socialnetworksdict = getArrayOfSocialNetworks();
998 foreach ($this->socialnetworks as $key => $value) {
1000 $outsocialnetwork .= dol_print_socialnetworks($value, $this->id, $object->id, $key, $socialnetworksdict);
1004 } else { // Old code to remove
1005 if (!empty($this->skype)) {
1006 $outsocialnetwork .= dol_print_socialnetworks($this->skype, $this->id, $object->id, 'skype');
1009 if (!empty($this->jabberid)) {
1010 $outsocialnetwork .= dol_print_socialnetworks($this->jabberid, $this->id, $object->id, 'jabber');
1013 if (!empty($this->twitter)) {
1014 $outsocialnetwork .= dol_print_socialnetworks($this->twitter, $this->id, $object->id, 'twitter');
1017 if (!empty($this->facebook)) {
1018 $outsocialnetwork .= dol_print_socialnetworks($this->facebook, $this->id, $object->id, 'facebook');
1021 if (!empty($this->linkedin)) {
1022 $outsocialnetwork .= dol_print_socialnetworks($this->linkedin, $this->id, $object->id, 'linkedin');
1027 if ($outsocialnetwork) {
1028 $out .= '<div style="clear: both;
">'.$outsocialnetwork.'</div>';
1033 return '<!-- BEGIN part to show address block -->'."\n
".$out.'<!-- END Part to show address block -->'."\n
";
1047 public function getLastMainDocLink($modulepart, $initsharekey = 0, $relativelink = 0)
1049 global $user, $dolibarr_main_url_root;
1051 if (empty($this->last_main_doc)) {
1052 return ''; // No way to known which document name to use
1055 include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
1056 $ecmfile = new EcmFiles($this->db);
1057 $result = $ecmfile->fetch(0, '', $this->last_main_doc);
1059 $this->error = $ecmfile->error;
1060 $this->errors = $ecmfile->errors;
1064 if (empty($ecmfile->id)) {
1065 // Add entry into index
1066 if ($initsharekey) {
1067 require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
1069 // 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
1071 $ecmfile->filepath = $rel_dir;
1072 $ecmfile->filename = $filename;
1073 $ecmfile->label = md5_file(dol_osencode($destfull)); // hash of file content
1074 $ecmfile->fullpath_orig = '';
1075 $ecmfile->gen_or_uploaded = 'generated';
1076 $ecmfile->description = ''; // indexed content
1077 $ecmfile->keywords = ''; // keyword content
1078 $ecmfile->share = getRandomPassword(true);
1079 $result = $ecmfile->create($user);
1082 $this->error = $ecmfile->error;
1083 $this->errors = $ecmfile->errors;
1089 } elseif (empty($ecmfile->share)) {
1090 // Add entry into index
1091 if ($initsharekey) {
1092 require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
1093 $ecmfile->share = getRandomPassword(true);
1094 $ecmfile->update($user);
1099 // Define $urlwithroot
1100 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
1101 // This is to use external domain name found into config file
1102 //if (DOL_URL_ROOT && ! preg_match('/\/$/', $urlwithouturlroot) && ! preg_match('/^\//', DOL_URL_ROOT)) $urlwithroot=$urlwithouturlroot.'/'.DOL_URL_ROOT;
1104 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT;
1105 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
1110 //if (!empty($modulepart)) $paramlink.=($paramlink?'&':'').'modulepart='.$modulepart; // For sharing with hash (so public files), modulepart is not required.
1111 //if (!empty($ecmfile->entity)) $paramlink.='&entity='.$ecmfile->entity; // For sharing with hash (so public files), entity is not required.
1112 //$paramlink.=($paramlink?'&':'').'file='.urlencode($filepath); // No need of name of file for public link, we will use the hash
1113 if (!empty($ecmfile->share)) {
1114 $paramlink .= ($paramlink ? '&' : '').'hashp='.$ecmfile->share; // Hash for public share
1116 if ($forcedownload) {
1117 $paramlink .= ($paramlink ? '&' : '').'attachment=1';
1120 if ($relativelink) {
1121 $linktoreturn = 'document.php'.($paramlink ? '?'.$paramlink : '');
1123 $linktoreturn = $urlwithroot.'/document.php'.($paramlink ? '?'.$paramlink : '');
1126 // Here $ecmfile->share is defined
1127 return $linktoreturn;
1131 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1141 public function add_contact($fk_socpeople, $type_contact, $source = 'external', $notrigger = 0)
1144 global $user, $langs;
1147 dol_syslog(get_class($this)."::add_contact $fk_socpeople, $type_contact, $source, $notrigger
");
1150 if ($fk_socpeople <= 0) {
1151 $langs->load("errors
");
1152 $this->error = $langs->trans("ErrorWrongValueForParameterX
", "1
");
1153 dol_syslog(get_class($this)."::add_contact ".$this->error, LOG_ERR);
1156 if (!$type_contact) {
1157 $langs->load("errors
");
1158 $this->error = $langs->trans("ErrorWrongValueForParameterX
", "2
");
1159 dol_syslog(get_class($this)."::add_contact ".$this->error, LOG_ERR);
1163 $id_type_contact = 0;
1164 if (is_numeric($type_contact)) {
1165 $id_type_contact = $type_contact;
1167 // We look for id type_contact
1168 $sql = "SELECT tc.rowid
";
1169 $sql .= " FROM
".$this->db->prefix()."c_type_contact as tc
";
1170 $sql .= " WHERE tc.element=
'".$this->db->escape($this->element)."'";
1171 $sql .= " AND tc.source=
'".$this->db->escape($source)."'";
1172 $sql .= " AND tc.code=
'".$this->db->escape($type_contact)."' AND tc.active=1
";
1174 $resql = $this->db->query($sql);
1176 $obj = $this->db->fetch_object($resql);
1178 $id_type_contact = $obj->rowid;
1183 if ($id_type_contact == 0) {
1184 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
");
1188 $datecreate = dol_now();
1190 // Socpeople must have already been added by some trigger, then we have to check it to avoid DB_ERROR_RECORD_ALREADY_EXISTS error
1191 $TListeContacts = $this->liste_contact(-1, $source);
1192 $already_added = false;
1193 if (is_array($TListeContacts) && !empty($TListeContacts)) {
1194 foreach ($TListeContacts as $array_contact) {
1195 if ($array_contact['status'] == 4 && $array_contact['id'] == $fk_socpeople && $array_contact['fk_c_type_contact'] == $id_type_contact) {
1196 $already_added = true;
1202 if (!$already_added) {
1205 // Insert into database
1206 $sql = "INSERT INTO
".$this->db->prefix()."element_contact
";
1207 $sql .= " (element_id, fk_socpeople, datecreate, statut, fk_c_type_contact)
";
1208 $sql .= " VALUES (
".$this->id.",
".((int) $fk_socpeople)." ,
";
1209 $sql .= "'".$this->db->idate($datecreate)."'";
1210 $sql .= ", 4,
".((int) $id_type_contact);
1213 $resql = $this->db->query($sql);
1216 $result = $this->call_trigger(strtoupper($this->element).'_ADD_CONTACT', $user);
1218 $this->db->rollback();
1223 $this->db->commit();
1226 if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
1227 $this->error = $this->db->errno();
1228 $this->db->rollback();
1231 $this->error = $this->db->lasterror();
1232 $this->db->rollback();
1241 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1249 public function copy_linked_contact($objFrom, $source = 'internal')
1252 $contacts = $objFrom->liste_contact(-1, $source);
1253 foreach ($contacts as $contact) {
1254 if ($this->add_contact($contact['id'], $contact['fk_c_type_contact'], $contact['source']) < 0) {
1261 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1271 public function update_contact($rowid, $statut, $type_contact_id = 0, $fk_socpeople = 0)
1274 // Insert into database
1275 $sql = "UPDATE
".$this->db->prefix()."element_contact
set";
1276 $sql .= " statut =
".$statut;
1277 if ($type_contact_id) {
1278 $sql .= ", fk_c_type_contact =
".((int) $type_contact_id);
1280 if ($fk_socpeople) {
1281 $sql .= ", fk_socpeople =
".((int) $fk_socpeople);
1283 $sql .= " where
rowid =
".((int) $rowid);
1284 $resql = $this->db->query($sql);
1288 $this->error = $this->db->lasterror();
1293 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1301 public function delete_contact($rowid, $notrigger = 0)
1310 if (!$error && empty($notrigger)) {
1312 $this->context['contact_id'] = ((int) $rowid);
1313 $result = $this->call_trigger(strtoupper($this->element).'_DELETE_CONTACT', $user);
1317 // End call triggers
1323 $sql = "DELETE FROM
".MAIN_DB_PREFIX."element_contact
";
1324 $sql .= " WHERE
rowid =
".((int) $rowid);
1326 $result = $this->db->query($sql);
1329 $this->errors[] = $this->db->lasterror();
1334 $this->db->commit();
1337 $this->error = $this->db->lasterror();
1338 $this->db->rollback();
1343 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1351 public function delete_linked_contact($source = '', $code = '')
1356 $typeContact = $this->liste_type_contact($source, '', 0, 0, $code);
1358 if (!empty($typeContact)) {
1359 foreach ($typeContact as $key => $value) {
1360 array_push($temp, $key);
1362 $listId = implode(",
", $temp);
1365 // If $listId is empty, we have not criteria on fk_c_type_contact so we will delete record on element_id for
1366 // any type or record instead of only the ones of the current object. So we do nothing in such a case.
1367 if (empty($listId)) {
1371 $sql = "DELETE FROM
".$this->db->prefix()."element_contact
";
1372 $sql .= " WHERE element_id =
".((int) $this->id);
1373 $sql .= " AND fk_c_type_contact IN (
".$this->db->sanitize($listId).")
";
1376 if ($this->db->query($sql)) {
1379 $this->error = $this->db->lasterror();
1384 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1396 public function liste_contact($statusoflink = -1, $source = 'external', $list = 0, $code = '', $status = -1, $arrayoftcids = array())
1403 $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
1404 if ($source == 'internal') {
1405 $sql .= ",
'-1' as socid, t.statut as statuscontact, t.login, t.photo
";
1407 if ($source == 'external' || $source == 'thirdparty') {
1408 $sql .= ", t.fk_soc as socid, t.statut as statuscontact
";
1410 $sql .= ", t.civility as civility, t.lastname as lastname, t.firstname, t.email
";
1411 $sql .= ", tc.source, tc.element, tc.code, tc.libelle
";
1412 $sql .= " FROM
".$this->db->prefix()."c_type_contact tc
";
1413 $sql .= ",
".$this->db->prefix()."element_contact ec
";
1414 if ($source == 'internal') { // internal contact (user)
1415 $sql .= " LEFT JOIN
".$this->db->prefix()."user t on ec.fk_socpeople = t.rowid
";
1417 if ($source == 'external' || $source == 'thirdparty') { // external contact (socpeople)
1418 $sql .= " LEFT JOIN
".$this->db->prefix()."socpeople t on ec.fk_socpeople = t.rowid
";
1420 $sql .= " WHERE ec.element_id =
".((int) $this->id);
1421 $sql .= " AND ec.fk_c_type_contact = tc.rowid
";
1422 $sql .= " AND tc.element =
'".$this->db->escape($this->element)."'";
1424 $sql .= " AND tc.code =
'".$this->db->escape($code)."'";
1426 if ($source == 'internal') {
1427 $sql .= " AND tc.source =
'internal'";
1429 $sql .= " AND t.statut =
".((int) $status);
1432 if ($source == 'external' || $source == 'thirdparty') {
1433 $sql .= " AND tc.source =
'external'";
1435 $sql .= " AND t.statut =
".((int) $status); // t is llx_socpeople
1438 $sql .= " AND tc.active = 1
";
1439 if ($statusoflink >= 0) {
1440 $sql .= " AND ec.statut =
".((int) $statusoflink);
1442 $sql .= " ORDER BY t.lastname ASC
";
1445 $resql = $this->db->query($sql);
1447 $num = $this->db->num_rows($resql);
1450 $obj = $this->db->fetch_object($resql);
1453 $transkey = "TypeContact_
".$obj->element."_
".$obj->source."_
".$obj->code;
1454 $libelle_type = ($langs->trans($transkey) != $transkey ? $langs->trans($transkey) : $obj->libelle);
1456 'source' => $obj->source,
1457 'socid' => $obj->socid,
1459 'nom' => $obj->lastname, // For backward compatibility
1460 'civility' => $obj->civility,
1461 'lastname' => $obj->lastname,
1462 'firstname' => $obj->firstname,
1463 'email'=>$obj->email,
1464 'login'=> (empty($obj->login) ? '' : $obj->login),
1465 'photo' => (empty($obj->photo) ? '' : $obj->photo),
1466 'statuscontact' => $obj->statuscontact,
1467 'rowid' => $obj->rowid,
1468 'code' => $obj->code,
1469 'libelle' => $libelle_type,
1470 'status' => $obj->statuslink,
1471 'fk_c_type_contact' => $obj->fk_c_type_contact
1474 $tab[$i] = $obj->id;
1482 $this->error = $this->db->lasterror();
1483 dol_print_error($this->db);
1495 public function swapContactStatus($rowid)
1497 $sql = "SELECT ec.datecreate, ec.statut, ec.fk_socpeople, ec.fk_c_type_contact,
";
1498 $sql .= " tc.code, tc.libelle
";
1499 $sql .= " FROM (
".$this->db->prefix()."element_contact as ec,
".$this->db->prefix()."c_type_contact as tc)
";
1500 $sql .= " WHERE ec.rowid =
".((int) $rowid);
1501 $sql .= " AND ec.fk_c_type_contact=tc.rowid
";
1502 $sql .= " AND tc.element =
'".$this->db->escape($this->element)."'";
1505 $resql = $this->db->query($sql);
1507 $obj = $this->db->fetch_object($resql);
1508 $newstatut = ($obj->statut == 4) ? 5 : 4;
1509 $result = $this->update_contact($rowid, $newstatut);
1510 $this->db->free($resql);
1513 $this->error = $this->db->error();
1514 dol_print_error($this->db);
1519 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1530 public function liste_type_contact($source = 'internal', $order = 'position', $option = 0, $activeonly = 0, $code = '')
1535 if (empty($order)) {
1536 $order = 'position';
1538 if ($order == 'position') {
1543 $sql = "SELECT DISTINCT tc.rowid, tc.code, tc.libelle, tc.position
";
1544 $sql .= " FROM
".$this->db->prefix()."c_type_contact as tc
";
1545 $sql .= " WHERE tc.element=
'".$this->db->escape($this->element)."'";
1546 if ($activeonly == 1) {
1547 $sql .= " AND tc.active=1
"; // only the active types
1549 if (!empty($source) && $source != 'all') {
1550 $sql .= " AND tc.source=
'".$this->db->escape($source)."'";
1552 if (!empty($code)) {
1553 $sql .= " AND tc.code=
'".$this->db->escape($code)."'";
1555 $sql .= $this->db->order($order, 'ASC');
1557 //print "sql=
".$sql;
1558 $resql = $this->db->query($sql);
1560 $num = $this->db->num_rows($resql);
1563 $obj = $this->db->fetch_object($resql);
1565 $transkey = "TypeContact_
".$this->element."_
".$source."_
".$obj->code;
1566 $libelle_type = ($langs->trans($transkey) != $transkey ? $langs->trans($transkey) : $obj->libelle);
1567 if (empty($option)) {
1568 $tab[$obj->rowid] = $libelle_type;
1570 $tab[$obj->code] = $libelle_type;
1576 $this->error = $this->db->lasterror();
1577 //dol_print_error($this->db);
1593 public function listeTypeContacts($source = 'internal', $option = 0, $activeonly = 0, $code = '', $element = '', $excludeelement = '')
1595 global $langs, $conf;
1597 $langs->loadLangs(array('bills', 'contracts', 'interventions', 'orders', 'projects', 'propal', 'ticket', 'agenda'));
1601 $sql = "SELECT DISTINCT tc.rowid, tc.code, tc.libelle, tc.position, tc.element
";
1602 $sql .= " FROM
".$this->db->prefix()."c_type_contact as tc
";
1604 $sqlWhere = array();
1605 if (!empty($element)) {
1606 $sqlWhere[] = " tc.element=
'".$this->db->escape($element)."'";
1608 if (!empty($excludeelement)) {
1609 $sqlWhere[] = " tc.element <>
'".$this->db->escape($excludeelement)."'";
1612 if ($activeonly == 1) {
1613 $sqlWhere[] = " tc.active=1
"; // only the active types
1616 if (!empty($source) && $source != 'all') {
1617 $sqlWhere[] = " tc.source=
'".$this->db->escape($source)."'";
1620 if (!empty($code)) {
1621 $sqlWhere[] = " tc.code=
'".$this->db->escape($code)."'";
1624 if (count($sqlWhere) > 0) {
1625 $sql .= " WHERE
".implode(' AND ', $sqlWhere);
1628 $sql .= $this->db->order('tc.element, tc.position', 'ASC');
1630 dol_syslog(__METHOD__, LOG_DEBUG);
1631 $resql = $this->db->query($sql);
1633 $num = $this->db->num_rows($resql);
1635 $langs->loadLangs(array("propal
", "orders
", "bills
", "suppliers
", "contracts
", "supplier_proposal
"));
1637 while ($obj = $this->db->fetch_object($resql)) {
1638 $modulename = $obj->element;
1639 if (strpos($obj->element, 'project') !== false) {
1640 $modulename = 'projet';
1641 } elseif ($obj->element == 'contrat') {
1642 $element = 'contract';
1643 } elseif ($obj->element == 'action') {
1644 $modulename = 'agenda';
1645 } elseif (strpos($obj->element, 'supplier') !== false && $obj->element != 'supplier_proposal') {
1646 $modulename = 'fournisseur';
1647 } elseif (strpos($obj->element, 'supplier') !== false && $obj->element != 'supplier_proposal') {
1648 $modulename = 'fournisseur';
1650 if (!empty($conf->{$modulename}->enabled)) {
1651 $libelle_element = $langs->trans('ContactDefault_'.$obj->element);
1652 $tmpelement = $obj->element;
1653 $transkey = "TypeContact_
".$tmpelement."_
".$source."_
".$obj->code;
1654 $libelle_type = ($langs->trans($transkey) != $transkey ? $langs->trans($transkey) : $obj->libelle);
1655 if (empty($option)) {
1656 $tab[$obj->rowid] = $libelle_element.' - '.$libelle_type;
1658 $tab[$obj->rowid] = $libelle_element.' - '.$libelle_type;
1665 $this->error = $this->db->lasterror();
1681 public function getIdContact($source, $code, $status = 0)
1687 //cas particulier pour les expeditions
1688 if ($this->element == 'shipping' && $this->origin_id != 0) {
1689 $id = $this->origin_id;
1690 $element = 'commande';
1691 } elseif ($this->element == 'reception' && $this->origin_id != 0) {
1692 $id = $this->origin_id;
1693 $element = 'order_supplier';
1696 $element = $this->element;
1699 $sql = "SELECT ec.fk_socpeople
";
1700 $sql .= " FROM
".$this->db->prefix()."element_contact as ec,
";
1701 if ($source == 'internal') {
1702 $sql .= " ".$this->db->prefix()."user as c,
";
1704 if ($source == 'external') {
1705 $sql .= " ".$this->db->prefix()."socpeople as c,
";
1707 $sql .= " ".$this->db->prefix()."c_type_contact as tc
";
1708 $sql .= " WHERE ec.element_id =
".((int) $id);
1709 $sql .= " AND ec.fk_socpeople = c.rowid
";
1710 if ($source == 'internal') {
1711 $sql .= " AND c.entity IN (
".getEntity('user').")
";
1713 if ($source == 'external') {
1714 $sql .= " AND c.entity IN (
".getEntity('societe').")
";
1716 $sql .= " AND ec.fk_c_type_contact = tc.rowid
";
1717 $sql .= " AND tc.element =
'".$this->db->escape($element)."'";
1718 $sql .= " AND tc.source =
'".$this->db->escape($source)."'";
1720 $sql .= " AND tc.code =
'".$this->db->escape($code)."'";
1722 $sql .= " AND tc.active = 1
";
1724 $sql .= " AND ec.statut =
".((int) $status);
1728 $resql = $this->db->query($sql);
1730 while ($obj = $this->db->fetch_object($resql)) {
1731 $result[$i] = $obj->fk_socpeople;
1735 $this->error = $this->db->error();
1742 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1749 public function fetch_contact($contactid = null)
1752 if (empty($contactid)) {
1753 $contactid = $this->contact_id;
1756 if (empty($contactid)) {
1760 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1761 $contact = new Contact($this->db);
1762 $result = $contact->fetch($contactid);
1763 $this->contact = $contact;
1767 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1774 public function fetch_thirdparty($force_thirdparty_id = 0)
1779 if (empty($this->socid) && empty($this->fk_soc) && empty($force_thirdparty_id)) {
1783 require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
1785 $idtofetch = isset($this->socid) ? $this->socid : (isset($this->fk_soc) ? $this->fk_soc : 0);
1786 if ($force_thirdparty_id) {
1787 $idtofetch = $force_thirdparty_id;
1791 $thirdparty = new Societe($this->db);
1792 $result = $thirdparty->fetch($idtofetch);
1794 $this->errors=array_merge($this->errors, $thirdparty->errors);
1796 $this->thirdparty = $thirdparty;
1798 // Use first price level if level not defined for third party
1799 if (!empty($conf->global->PRODUIT_MULTIPRICES) && empty($this->thirdparty->price_level)) {
1800 $this->thirdparty->price_level = 1;
1817 public function fetchOneLike($ref)
1819 if (!$this->table_ref_field) {
1823 $sql = "SELECT
rowid FROM
".$this->db->prefix().$this->table_element." WHERE
".$this->table_ref_field." LIKE
'".$this->db->escape($ref)."' LIMIT 1
";
1825 $query = $this->db->query($sql);
1827 if (!$this->db->num_rows($query)) {
1831 $result = $this->db->fetch_object($query);
1833 return $this->fetch($result->rowid);
1836 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1844 public function fetch_barcode()
1849 dol_syslog(get_class($this).'::fetch_barcode this->element='.$this->element.' this->barcode_type='.$this->barcode_type);
1851 $idtype = $this->barcode_type;
1852 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
1853 if ($this->element == 'product' && !empty($conf->global->PRODUIT_DEFAULT_BARCODE_TYPE)) {
1854 $idtype = $conf->global->PRODUIT_DEFAULT_BARCODE_TYPE;
1855 } elseif ($this->element == 'societe') {
1856 $idtype = $conf->global->GENBARCODE_BARCODETYPE_THIRDPARTY;
1858 dol_syslog('Call fetch_barcode with barcode_type not defined and cant be guessed', LOG_WARNING);
1863 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
1864 $sql = "SELECT
rowid,
code, libelle as label, coder
";
1865 $sql .= " FROM
".$this->db->prefix()."c_barcode_type
";
1866 $sql .= " WHERE
rowid =
".((int) $idtype);
1867 dol_syslog(get_class($this).'::fetch_barcode', LOG_DEBUG);
1868 $resql = $this->db->query($sql);
1870 $obj = $this->db->fetch_object($resql);
1871 $this->barcode_type = $obj->rowid;
1872 $this->barcode_type_code = $obj->code;
1873 $this->barcode_type_label = $obj->label;
1874 $this->barcode_type_coder = $obj->coder;
1877 dol_print_error($this->db);
1885 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1891 public function fetch_project()
1894 return $this->fetch_projet();
1897 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1903 public function fetch_projet()
1906 include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
1908 if (empty($this->fk_project) && !empty($this->fk_projet)) {
1909 $this->fk_project = $this->fk_projet; // For backward compatibility
1911 if (empty($this->fk_project)) {
1915 $project = new Project($this->db);
1916 $result = $project->fetch($this->fk_project);
1918 $this->projet = $project; // deprecated
1919 $this->project = $project;
1923 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1929 public function fetch_product()
1932 include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
1934 if (empty($this->fk_product)) {
1938 $product = new Product($this->db);
1939 $result = $product->fetch($this->fk_product);
1941 $this->product = $product;
1945 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1952 public function fetch_user($userid)
1955 $user = new User($this->db);
1956 $result = $user->fetch($userid);
1957 $this->user = $user;
1961 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1967 public function fetch_origin()
1970 if ($this->origin == 'shipping') {
1971 $this->origin = 'expedition';
1973 if ($this->origin == 'delivery') {
1974 $this->origin = 'livraison';
1976 if ($this->origin == 'order_supplier') {
1977 $this->origin = 'commandeFournisseur';
1980 $origin = $this->origin;
1982 $classname = ucfirst($origin);
1983 $this->$origin = new $classname($this->db);
1984 $this->$origin->fetch($this->origin_id);
1996 public function fetchObjectFrom($table, $field, $key, $element = null)
2002 $sql = "SELECT
rowid FROM
".$this->db->prefix().$table;
2003 $sql .= " WHERE
".$field." =
'".$this->db->escape($key)."'";
2004 if (!empty($element)) {
2005 $sql .= " AND entity IN (
".getEntity($element).")
";
2007 $sql .= " AND entity =
".((int) $conf->entity);
2010 dol_syslog(get_class($this).'::fetchObjectFrom', LOG_DEBUG);
2011 $resql = $this->db->query($sql);
2013 $row = $this->db->fetch_row($resql);
2014 // Test for avoid error -1
2016 $result = $this->fetch($row[0]);
2031 public function getValueFrom($table, $id, $field)
2034 if (!empty($id) && !empty($field) && !empty($table)) {
2035 $sql = "SELECT
".$field." FROM
".$this->db->prefix().$table;
2036 $sql .= " WHERE
rowid =
".((int) $id);
2038 dol_syslog(get_class($this).'::getValueFrom', LOG_DEBUG);
2039 $resql = $this->db->query($sql);
2041 $row = $this->db->fetch_row($resql);
2064 public function setValueFrom($field, $value, $table = '', $id = null, $format = '', $id_field = '', $fuser = null, $trigkey = '', $fk_user_field = 'fk_user_modif')
2066 global $user, $langs, $conf;
2068 if (empty($table)) {
2069 $table = $this->table_element;
2074 if (empty($format)) {
2077 if (empty($id_field)) {
2078 $id_field = 'rowid';
2086 if ($table == 'product' && $field == 'note_private') {
2089 if (in_array($table, array('actioncomm', 'adherent', 'advtargetemailing', 'cronjob', 'establishment'))) {
2090 $fk_user_field = 'fk_user_mod';
2093 $sql = "UPDATE
".$this->db->prefix().$table." SET
";
2095 if ($format == 'text') {
2096 $sql .= $field." =
'".$this->db->escape($value)."'";
2097 } elseif ($format == 'int') {
2098 $sql .= $field." =
".((int) $value);
2099 } elseif ($format == 'date') {
2100 $sql .= $field." =
".($value ? "'".$this->db->idate($value)."'" : "null");
2103 if ($fk_user_field) {
2104 if (!empty($fuser) && is_object($fuser)) {
2105 $sql .= ",
".$fk_user_field." =
".((int) $fuser->id);
2106 } elseif (empty($fuser) || $fuser != 'none') {
2107 $sql .= ",
".$fk_user_field." =
".((int) $user->id);
2111 $sql .= " WHERE
".$id_field." =
".((int) $id);
2113 dol_syslog(__METHOD__."", LOG_DEBUG);
2114 $resql = $this->db->query($sql);
2117 // call trigger with updated object values
2118 if (method_exists($this, 'fetch')) {
2119 $result = $this->fetch($id);
2121 $result = $this->fetchCommon($id);
2124 $result = $this->call_trigger($trigkey, (!empty($fuser) && is_object($fuser)) ? $fuser : $user); // This may set this->errors
2132 if (property_exists($this, $field)) {
2133 $this->$field = $value;
2135 $this->db->commit();
2138 $this->db->rollback();
2142 if ($this->db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
2143 $this->error = 'DB_ERROR_RECORD_ALREADY_EXISTS';
2145 $this->error = $this->db->lasterror();
2147 $this->db->rollback();
2152 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2161 public function load_previous_next_ref($filter, $fieldid, $nodbprefix = 0)
2164 global $conf, $user;
2166 if (!$this->table_element) {
2167 dol_print_error('', get_class($this)."::load_previous_next_ref was called on objet with
property table_element not defined
");
2170 if ($fieldid == 'none') {
2174 // For backward compatibility
2175 if (in_array($this->table_element, array('facture_rec', 'facture_fourn_rec')) && $fieldid == 'title') {
2179 // Security on socid
2181 if ($user->socid > 0) {
2182 $socid = $user->socid;
2185 // this->ismultientitymanaged contains
2186 // 0=No test on entity, 1=Test with field entity, 'field@table'=Test with link by field@table
2187 $aliastablesociete = 's';
2188 if ($this->element == 'societe') {
2189 $aliastablesociete = 'te'; // te as table_element
2191 $restrictiononfksoc = empty($this->restrictiononfksoc) ? 0 : $this->restrictiononfksoc;
2192 $sql = "SELECT MAX(te.
".$fieldid.")
";
2193 $sql .= " FROM
".(empty($nodbprefix) ?$this->db->prefix():'').$this->table_element." as te
";
2194 if ($this->element == 'user' && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
2195 $sql .= ",
".$this->db->prefix()."usergroup_user as ug
";
2197 if (isset($this->ismultientitymanaged) && !is_numeric($this->ismultientitymanaged)) {
2198 $tmparray = explode('@', $this->ismultientitymanaged);
2199 $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
2200 } elseif ($restrictiononfksoc == 1 && $this->element != 'societe' && empty($user->rights->societe->client->voir) && !$socid) {
2201 $sql .= ",
".$this->db->prefix()."societe as s
"; // If we need to link to societe to limit select to socid
2202 } elseif ($restrictiononfksoc == 2 && $this->element != 'societe' && empty($user->rights->societe->client->voir) && !$socid) {
2203 $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
2205 if ($restrictiononfksoc && empty($user->rights->societe->client->voir) && !$socid) {
2206 $sql .= " LEFT JOIN
".$this->db->prefix()."societe_commerciaux as sc ON
".$aliastablesociete.".rowid = sc.fk_soc
";
2208 $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)
2209 if ($restrictiononfksoc == 1 && empty($user->rights->societe->client->voir) && !$socid) {
2210 $sql .= " AND sc.fk_user =
".((int) $user->id);
2212 if ($restrictiononfksoc == 2 && empty($user->rights->societe->client->voir) && !$socid) {
2213 $sql .= " AND (sc.fk_user =
".((int) $user->id).' OR te.fk_soc IS NULL)';
2215 if (!empty($filter)) {
2216 if (!preg_match('/^\s*AND/i', $filter)) {
2217 $sql .= " AND
"; // For backward compatibility
2221 if (isset($this->ismultientitymanaged) && !is_numeric($this->ismultientitymanaged)) {
2222 $tmparray = explode('@', $this->ismultientitymanaged);
2223 $sql .= " AND te.
".$tmparray[0]." =
".($tmparray[1] == "societe
" ? "s
" : "parenttable
").".rowid
"; // If we need to link to this table to limit select to entity
2224 } elseif ($restrictiononfksoc == 1 && $this->element != 'societe' && empty($user->rights->societe->client->voir) && !$socid) {
2225 $sql .= ' AND te.fk_soc = s.rowid'; // If we need to link to societe to limit select to socid
2227 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
2228 if ($this->element == 'user' && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
2229 if (!empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
2230 $sql .= " AND te.entity IS NOT NULL
"; // Show all users
2232 $sql .= " AND ug.fk_user = te.rowid
";
2233 $sql .= " AND ug.entity IN (
".getEntity('usergroup').")
";
2236 $sql .= ' AND te.entity IN ('.getEntity($this->element).')';
2239 if (isset($this->ismultientitymanaged) && !is_numeric($this->ismultientitymanaged) && $this->element != 'societe') {
2240 $tmparray = explode('@', $this->ismultientitymanaged);
2241 $sql .= ' AND parenttable.entity IN ('.getEntity($tmparray[1]).')';
2243 if ($restrictiononfksoc == 1 && $socid && $this->element != 'societe') {
2244 $sql .= ' AND te.fk_soc = '.((int) $socid);
2246 if ($restrictiononfksoc == 2 && $socid && $this->element != 'societe') {
2247 $sql .= ' AND (te.fk_soc = '.((int) $socid).' OR te.fk_soc IS NULL)';
2249 if ($restrictiononfksoc && $socid && $this->element == 'societe') {
2250 $sql .= ' AND te.rowid = '.((int) $socid);
2252 //print 'socid='.$socid.' restrictiononfksoc='.$restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."<br>
";
2254 $result = $this->db->query($sql);
2256 $this->error = $this->db->lasterror();
2259 $row = $this->db->fetch_row($result);
2260 $this->ref_previous = $row[0];
2262 $sql = "SELECT MIN(te.
".$fieldid.")
";
2263 $sql .= " FROM
".(empty($nodbprefix) ?$this->db->prefix():'').$this->table_element." as te
";
2264 if ($this->element == 'user' && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
2265 $sql .= ",
".$this->db->prefix()."usergroup_user as ug
";
2267 if (isset($this->ismultientitymanaged) && !is_numeric($this->ismultientitymanaged)) {
2268 $tmparray = explode('@', $this->ismultientitymanaged);
2269 $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
2270 } elseif ($restrictiononfksoc == 1 && $this->element != 'societe' && empty($user->rights->societe->client->voir) && !$socid) {
2271 $sql .= ",
".$this->db->prefix()."societe as s
"; // If we need to link to societe to limit select to socid
2272 } elseif ($restrictiononfksoc == 2 && $this->element != 'societe' && empty($user->rights->societe->client->voir) && !$socid) {
2273 $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
2275 if ($restrictiononfksoc && empty($user->rights->societe->client->voir) && !$socid) {
2276 $sql .= " LEFT JOIN
".$this->db->prefix()."societe_commerciaux as sc ON
".$aliastablesociete.".rowid = sc.fk_soc
";
2278 $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)
2279 if ($restrictiononfksoc == 1 && empty($user->rights->societe->client->voir) && !$socid) {
2280 $sql .= " AND sc.fk_user =
".((int) $user->id);
2282 if ($restrictiononfksoc == 2 && empty($user->rights->societe->client->voir) && !$socid) {
2283 $sql .= " AND (sc.fk_user =
".((int) $user->id).' OR te.fk_soc IS NULL)';
2285 if (!empty($filter)) {
2286 if (!preg_match('/^\s*AND/i', $filter)) {
2287 $sql .= " AND
"; // For backward compatibility
2291 if (isset($this->ismultientitymanaged) && !is_numeric($this->ismultientitymanaged)) {
2292 $tmparray = explode('@', $this->ismultientitymanaged);
2293 $sql .= " AND te.
".$tmparray[0]." =
".($tmparray[1] == "societe
" ? "s
" : "parenttable
").".rowid
"; // If we need to link to this table to limit select to entity
2294 } elseif ($restrictiononfksoc == 1 && $this->element != 'societe' && empty($user->rights->societe->client->voir) && !$socid) {
2295 $sql .= ' AND te.fk_soc = s.rowid'; // If we need to link to societe to limit select to socid
2297 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
2298 if ($this->element == 'user' && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
2299 if (!empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
2300 $sql .= " AND te.entity IS NOT NULL
"; // Show all users
2302 $sql .= " AND ug.fk_user = te.rowid
";
2303 $sql .= " AND ug.entity IN (
".getEntity('usergroup').")
";
2306 $sql .= ' AND te.entity IN ('.getEntity($this->element).')';
2309 if (isset($this->ismultientitymanaged) && !is_numeric($this->ismultientitymanaged) && $this->element != 'societe') {
2310 $tmparray = explode('@', $this->ismultientitymanaged);
2311 $sql .= ' AND parenttable.entity IN ('.getEntity($tmparray[1]).')';
2313 if ($restrictiononfksoc == 1 && $socid && $this->element != 'societe') {
2314 $sql .= ' AND te.fk_soc = '.((int) $socid);
2316 if ($restrictiononfksoc == 2 && $socid && $this->element != 'societe') {
2317 $sql .= ' AND (te.fk_soc = '.((int) $socid).' OR te.fk_soc IS NULL)';
2319 if ($restrictiononfksoc && $socid && $this->element == 'societe') {
2320 $sql .= ' AND te.rowid = '.((int) $socid);
2322 //print 'socid='.$socid.' restrictiononfksoc='.$restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."<br>
";
2323 // 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
2325 $result = $this->db->query($sql);
2327 $this->error = $this->db->lasterror();
2330 $row = $this->db->fetch_row($result);
2331 $this->ref_next = $row[0];
2344 public function getListContactId($source = 'external')
2346 $contactAlreadySelected = array();
2347 $tab = $this->liste_contact(-1, $source);
2351 if ($source == 'thirdparty') {
2352 $contactAlreadySelected[$i] = $tab[$i]['socid'];
2354 $contactAlreadySelected[$i] = $tab[$i]['id'];
2358 return $contactAlreadySelected;
2369 public function setProject($projectid, $notrigger = 0)
2374 if (!$this->table_element) {
2375 dol_syslog(get_class($this)."::
setProject was called on objet with property table_element not defined
", LOG_ERR);
2379 $sql = "UPDATE
".$this->db->prefix().$this->table_element;
2380 if (!empty($this->fields['fk_project'])) { // Common case
2382 $sql .= " SET fk_project =
".((int) $projectid);
2384 $sql .= " SET fk_project = NULL
";
2386 $sql .= ' WHERE rowid = '.((int) $this->id);
2387 } elseif ($this->table_element == 'actioncomm') { // Special case for actioncomm
2389 $sql .= " SET fk_project =
".((int) $projectid);
2391 $sql .= " SET fk_project = NULL
";
2393 $sql .= ' WHERE id = '.((int) $this->id);
2394 } else // Special case for old architecture objects
2397 $sql .= ' SET fk_projet = '.((int) $projectid);
2399 $sql .= ' SET fk_projet = NULL';
2401 $sql .= " WHERE
rowid =
".((int) $this->id);
2406 dol_syslog(get_class($this)."::
setProject", LOG_DEBUG);
2407 if ($this->db->query($sql)) {
2408 $this->fk_project = ((int) $projectid);
2410 dol_print_error($this->db);
2415 if (!$error && !$notrigger) {
2417 $result = $this->call_trigger(strtoupper($this->element) . '_MODIFY', $user);
2420 } //Do also here what you must do to rollback action if trigger fail
2421 // End call triggers
2424 // Commit or rollback
2426 $this->db->rollback();
2429 $this->db->commit();
2440 public function setPaymentMethods($id)
2444 $error = 0; $notrigger = 0;
2446 dol_syslog(get_class($this).'::setPaymentMethods('.$id.')');
2448 if ($this->statut >= 0 || $this->element == 'societe') {
2449 // TODO uniformize field name
2450 $fieldname = 'fk_mode_reglement';
2451 if ($this->element == 'societe') {
2452 $fieldname = 'mode_reglement';
2454 if (get_class($this) == 'Fournisseur') {
2455 $fieldname = 'mode_reglement_supplier';
2457 if (get_class($this) == 'Tva') {
2458 $fieldname = 'fk_typepayment';
2460 if (get_class($this) == 'Salary') {
2461 $fieldname = 'fk_typepayment';
2464 $sql = "UPDATE
".$this->db->prefix().$this->table_element;
2465 $sql .= " SET
".$fieldname." =
".(($id > 0 || $id == '0') ? ((int) $id) : 'NULL');
2466 $sql .= ' WHERE rowid='.((int) $this->id);
2468 if ($this->db->query($sql)) {
2469 $this->mode_reglement_id = $id;
2471 if (get_class($this) == 'Fournisseur') {
2472 $this->mode_reglement_supplier_id = $id;
2475 if (!$error && !$notrigger) {
2477 if (get_class($this) == 'Commande') {
2478 $result = $this->call_trigger('ORDER_MODIFY', $user);
2480 $result = $this->call_trigger(strtoupper(get_class($this)).'_MODIFY', $user);
2485 // End call triggers
2489 dol_syslog(get_class($this).'::setPaymentMethods Error '.$this->db->error());
2490 $this->error = $this->db->error();
2494 dol_syslog(get_class($this).'::setPaymentMethods, status of the object is incompatible');
2495 $this->error = 'Status of the object is incompatible '.$this->statut;
2506 public function setMulticurrencyCode($code)
2508 dol_syslog(get_class($this).'::setMulticurrencyCode('.$code.')');
2509 if ($this->statut >= 0 || $this->element == 'societe') {
2510 $fieldname = 'multicurrency_code';
2512 $sql = 'UPDATE '.$this->db->prefix().$this->table_element;
2513 $sql .= " SET
".$fieldname." =
'".$this->db->escape($code)."'";
2514 $sql .= ' WHERE rowid='.((int) $this->id);
2516 if ($this->db->query($sql)) {
2517 $this->multicurrency_code = $code;
2519 list($fk_multicurrency, $rate) = MultiCurrency::getIdAndTxFromCode($this->db, $code);
2521 $this->setMulticurrencyRate($rate, 2);
2526 dol_syslog(get_class($this).'::setMulticurrencyCode Error '.$sql.' - '.$this->db->error());
2527 $this->error = $this->db->error();
2531 dol_syslog(get_class($this).'::setMulticurrencyCode, status of the object is incompatible');
2532 $this->error = 'Status of the object is incompatible '.$this->statut;
2544 public function setMulticurrencyRate($rate, $mode = 1)
2546 dol_syslog(get_class($this).'::setMulticurrencyRate('.$rate.','.$mode.')');
2547 if ($this->statut >= 0 || $this->element == 'societe') {
2548 $fieldname = 'multicurrency_tx';
2550 $sql = 'UPDATE '.$this->db->prefix().$this->table_element;
2551 $sql .= " SET
".$fieldname." =
".((float) $rate);
2552 $sql .= ' WHERE rowid='.((int) $this->id);
2554 if ($this->db->query($sql)) {
2555 $this->multicurrency_tx = $rate;
2557 // Update line price
2558 if (!empty($this->lines)) {
2559 foreach ($this->lines as &$line) {
2560 // Amounts in company currency will be recalculated
2562 $line->subprice = 0;
2565 // Amounts in foreign currency will be recalculated
2567 $line->multicurrency_subprice = 0;
2570 switch ($this->element) {
2576 $line->remise_percent,
2578 $line->localtax1_tx,
2579 $line->localtax2_tx,
2580 ($line->description ? $line->description : $line->desc),
2583 $line->special_code,
2584 $line->fk_parent_line,
2585 $line->skip_update_total,
2586 $line->fk_fournprice,
2589 $line->product_type,
2592 $line->array_options,
2594 $line->multicurrency_subprice
2600 ($line->description ? $line->description : $line->desc),
2603 $line->remise_percent,
2605 $line->localtax1_tx,
2606 $line->localtax2_tx,
2611 $line->product_type,
2612 $line->fk_parent_line,
2613 $line->skip_update_total,
2614 $line->fk_fournprice,
2617 $line->special_code,
2618 $line->array_options,
2620 $line->multicurrency_subprice
2626 ($line->description ? $line->description : $line->desc),
2629 $line->remise_percent,
2633 $line->localtax1_tx,
2634 $line->localtax2_tx,
2637 $line->product_type,
2638 $line->fk_parent_line,
2639 $line->skip_update_total,
2640 $line->fk_fournprice,
2643 $line->special_code,
2644 $line->array_options,
2645 $line->situation_percent,
2647 $line->multicurrency_subprice
2650 case 'supplier_proposal':
2655 $line->remise_percent,
2657 $line->localtax1_tx,
2658 $line->localtax2_tx,
2659 ($line->description ? $line->description : $line->desc),
2662 $line->special_code,
2663 $line->fk_parent_line,
2664 $line->skip_update_total,
2665 $line->fk_fournprice,
2668 $line->product_type,
2669 $line->array_options,
2671 $line->multicurrency_subprice
2674 case 'order_supplier':
2677 ($line->description ? $line->description : $line->desc),
2680 $line->remise_percent,
2682 $line->localtax1_tx,
2683 $line->localtax2_tx,
2686 $line->product_type,
2690 $line->array_options,
2692 $line->multicurrency_subprice,
2696 case 'invoice_supplier':
2699 ($line->description ? $line->description : $line->desc),
2702 $line->localtax1_tx,
2703 $line->localtax2_tx,
2708 $line->product_type,
2709 $line->remise_percent,
2713 $line->array_options,
2715 $line->multicurrency_subprice,
2720 dol_syslog(get_class($this).'::setMulticurrencyRate no updateline defined', LOG_DEBUG);
2728 dol_syslog(get_class($this).'::setMulticurrencyRate Error '.$sql.' - '.$this->db->error());
2729 $this->error = $this->db->error();
2733 dol_syslog(get_class($this).'::setMulticurrencyRate, status of the object is incompatible');
2734 $this->error = 'Status of the object is incompatible '.$this->statut;
2746 public function setPaymentTerms($id, $deposit_percent = null)
2748 dol_syslog(get_class($this).'::setPaymentTerms('.$id.', '.var_export($deposit_percent, true).')');
2749 if ($this->statut >= 0 || $this->element == 'societe') {
2750 // TODO uniformize field name
2751 $fieldname = 'fk_cond_reglement';
2752 if ($this->element == 'societe') {
2753 $fieldname = 'cond_reglement';
2755 if (get_class($this) == 'Fournisseur') {
2756 $fieldname = 'cond_reglement_supplier';
2759 if (empty($deposit_percent) || $deposit_percent < 0) {
2760 $deposit_percent = getDictionaryValue('c_payment_term', 'deposit_percent', $id);
2763 if ($deposit_percent > 100) {
2764 $deposit_percent = 100;
2767 $sql = 'UPDATE '.$this->db->prefix().$this->table_element;
2768 $sql .= " SET
".$fieldname." =
".(($id > 0 || $id == '0') ? ((int) $id) : 'NULL');
2769 if (in_array($this->table_element, array('propal', 'commande', 'societe'))) {
2770 $sql .= " , deposit_percent =
" . (empty($deposit_percent) ? 'NULL' : "'".$this->db->escape($deposit_percent)."'");
2772 $sql .= ' WHERE rowid='.((int) $this->id);
2774 if ($this->db->query($sql)) {
2775 $this->cond_reglement_id = $id;
2777 if (get_class($this) == 'Fournisseur') {
2778 $this->cond_reglement_supplier_id = $id;
2780 $this->cond_reglement = $id; // for compatibility
2781 $this->deposit_percent = $deposit_percent;
2784 dol_syslog(get_class($this).'::setPaymentTerms Error '.$sql.' - '.$this->db->error());
2785 $this->error = $this->db->error();
2789 dol_syslog(get_class($this).'::setPaymentTerms, status of the object is incompatible');
2790 $this->error = 'Status of the object is incompatible '.$this->statut;
2801 public function setTransportMode($id)
2803 dol_syslog(get_class($this).'::setTransportMode('.$id.')');
2804 if ($this->statut >= 0 || $this->element == 'societe') {
2805 $fieldname = 'fk_transport_mode';
2806 if ($this->element == 'societe') {
2807 $fieldname = 'transport_mode';
2809 if (get_class($this) == 'Fournisseur') {
2810 $fieldname = 'transport_mode_supplier';
2813 $sql = 'UPDATE '.$this->db->prefix().$this->table_element;
2814 $sql .= " SET
".$fieldname." =
".(($id > 0 || $id == '0') ? ((int) $id) : 'NULL');
2815 $sql .= ' WHERE rowid='.((int) $this->id);
2817 if ($this->db->query($sql)) {
2818 $this->transport_mode_id = $id;
2820 if (get_class($this) == 'Fournisseur') {
2821 $this->transport_mode_supplier_id = $id;
2825 dol_syslog(get_class($this).'::setTransportMode Error '.$sql.' - '.$this->db->error());
2826 $this->error = $this->db->error();
2830 dol_syslog(get_class($this).'::setTransportMode, status of the object is incompatible');
2831 $this->error = 'Status of the object is incompatible '.$this->statut;
2842 public function setRetainedWarrantyPaymentTerms($id)
2844 dol_syslog(get_class($this).'::setRetainedWarrantyPaymentTerms('.$id.')');
2845 if ($this->statut >= 0 || $this->element == 'societe') {
2846 $fieldname = 'retained_warranty_fk_cond_reglement';
2848 $sql = 'UPDATE '.$this->db->prefix().$this->table_element;
2849 $sql .= " SET
".$fieldname." =
".((int) $id);
2850 $sql .= ' WHERE rowid='.((int) $this->id);
2852 if ($this->db->query($sql)) {
2853 $this->retained_warranty_fk_cond_reglement = $id;
2856 dol_syslog(get_class($this).'::setRetainedWarrantyPaymentTerms Error '.$sql.' - '.$this->db->error());
2857 $this->error = $this->db->error();
2861 dol_syslog(get_class($this).'::setRetainedWarrantyPaymentTerms, status of the object is incompatible');
2862 $this->error = 'Status of the object is incompatible '.$this->statut;
2874 public function setDeliveryAddress($id)
2876 $fieldname = 'fk_delivery_address';
2877 if ($this->element == 'delivery' || $this->element == 'shipping') {
2878 $fieldname = 'fk_address';
2881 $sql = "UPDATE
".$this->db->prefix().$this->table_element." SET
".$fieldname." =
".((int) $id);
2882 $sql .= " WHERE
rowid =
".((int) $this->id)." AND fk_statut = 0
";
2884 if ($this->db->query($sql)) {
2885 $this->fk_delivery_address = $id;
2888 $this->error = $this->db->error();
2889 dol_syslog(get_class($this).'::setDeliveryAddress Error '.$this->error);
2904 public function setShippingMethod($shipping_method_id, $notrigger = false, $userused = null)
2908 if (empty($userused)) {
2914 if (!$this->table_element) {
2915 dol_syslog(get_class($this)."::
setShippingMethod was called on objet with property table_element not defined
", LOG_ERR);
2921 if ($shipping_method_id < 0) {
2922 $shipping_method_id = 'NULL';
2924 dol_syslog(get_class($this).'::setShippingMethod('.$shipping_method_id.')');
2926 $sql = "UPDATE
".$this->db->prefix().$this->table_element;
2927 $sql .= " SET fk_shipping_method =
".((int) $shipping_method_id);
2928 $sql .= " WHERE
rowid=
".((int) $this->id);
2929 $resql = $this->db->query($sql);
2931 dol_syslog(get_class($this).'::setShippingMethod Error ', LOG_DEBUG);
2932 $this->error = $this->db->lasterror();
2937 $this->context = array('shippingmethodupdate'=>1);
2938 $result = $this->call_trigger(strtoupper(get_class($this)).'_MODIFY', $userused);
2946 $this->db->rollback();
2949 $this->shipping_method_id = ($shipping_method_id == 'NULL') ?null:$shipping_method_id;
2950 $this->db->commit();
2962 public function setWarehouse($warehouse_id)
2964 if (!$this->table_element) {
2965 dol_syslog(get_class($this)."::
setWarehouse was called on objet with property table_element not defined
", LOG_ERR);
2968 if ($warehouse_id < 0) {
2969 $warehouse_id = 'NULL';
2971 dol_syslog(get_class($this).'::setWarehouse('.$warehouse_id.')');
2973 $sql = "UPDATE
".$this->db->prefix().$this->table_element;
2974 $sql .= " SET fk_warehouse =
".((int) $warehouse_id);
2975 $sql .= " WHERE
rowid=
".((int) $this->id);
2977 if ($this->db->query($sql)) {
2978 $this->warehouse_id = ($warehouse_id == 'NULL') ?null:$warehouse_id;
2981 dol_syslog(get_class($this).'::setWarehouse Error ', LOG_DEBUG);
2982 $this->error = $this->db->error();
2995 public function setDocModel($user, $modelpdf)
2997 if (!$this->table_element) {
2998 dol_syslog(get_class($this)."::
setDocModel was called on objet with property table_element not defined
", LOG_ERR);
3002 $newmodelpdf = dol_trunc($modelpdf, 255);
3004 $sql = "UPDATE
".$this->db->prefix().$this->table_element;
3005 $sql .= " SET model_pdf =
'".$this->db->escape($newmodelpdf)."'";
3006 $sql .= " WHERE
rowid =
".((int) $this->id);
3008 dol_syslog(get_class($this)."::
setDocModel", LOG_DEBUG);
3009 $resql = $this->db->query($sql);
3011 $this->model_pdf = $modelpdf;
3012 $this->modelpdf = $modelpdf; // For bakward compatibility
3015 dol_print_error($this->db);
3029 public function setBankAccount($fk_account, $notrigger = false, $userused = null)
3033 if (empty($userused)) {
3039 if (!$this->table_element) {
3040 dol_syslog(get_class($this)."::
setBankAccount was called on objet with property table_element not defined
", LOG_ERR);
3045 if ($fk_account < 0) {
3046 $fk_account = 'NULL';
3048 dol_syslog(get_class($this).'::setBankAccount('.$fk_account.')');
3050 $sql = "UPDATE
".$this->db->prefix().$this->table_element;
3051 $sql .= " SET fk_account =
".((int) $fk_account);
3052 $sql .= " WHERE
rowid=
".((int) $this->id);
3054 $resql = $this->db->query($sql);
3056 dol_syslog(get_class($this).'::setBankAccount Error '.$sql.' - '.$this->db->error());
3057 $this->error = $this->db->lasterror();
3062 $this->context = array('bankaccountupdate'=>1);
3063 $result = $this->call_trigger(strtoupper(get_class($this)).'_MODIFY', $userused);
3071 $this->db->rollback();
3074 $this->fk_account = ($fk_account == 'NULL') ?null:$fk_account;
3075 $this->db->commit();
3081 // TODO: Move line related operations to CommonObjectLine?
3083 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3093 public function line_order($renum = false, $rowidorder = 'ASC', $fk_parent_line = true)
3096 if (!$this->table_element_line) {
3097 dol_syslog(get_class($this)."::
line_order was called on objet with property table_element_line not defined
", LOG_ERR);
3100 if (!$this->fk_element) {
3101 dol_syslog(get_class($this)."::
line_order was called on objet with property fk_element not defined
", LOG_ERR);
3105 $fieldposition = 'rang'; // @todo Rename 'rang' into 'position'
3106 if (in_array($this->table_element_line, array('bom_bomline', 'ecm_files', 'emailcollector_emailcollectoraction', 'product_attribute_value'))) {
3107 $fieldposition = 'position';
3110 // Count number of lines to reorder (according to choice $renum)
3112 $sql = "SELECT count(
rowid) FROM
".$this->db->prefix().$this->table_element_line;
3113 $sql .= " WHERE
".$this->fk_element." =
".((int) $this->id);
3115 $sql .= " AND
" . $fieldposition . " = 0
";
3118 $sql .= " AND
" . $fieldposition . " <> 0
";
3121 dol_syslog(get_class($this)."::
line_order", LOG_DEBUG);
3122 $resql = $this->db->query($sql);
3124 $row = $this->db->fetch_row($resql);
3127 dol_print_error($this->db);
3130 // The goal of this part is to reorder all lines, with all children lines sharing the same counter that parents.
3133 // We first search all lines that are parent lines (for multilevel details lines)
3134 $sql = "SELECT
rowid FROM
".$this->db->prefix().$this->table_element_line;
3135 $sql .= " WHERE
".$this->fk_element." =
".((int) $this->id);
3136 if ($fk_parent_line) {
3137 $sql .= ' AND fk_parent_line IS NULL';
3139 $sql .= " ORDER BY
" . $fieldposition . " ASC,
rowid " . $rowidorder;
3141 dol_syslog(get_class($this)."::
line_order search all parent lines
", LOG_DEBUG);
3142 $resql = $this->db->query($sql);
3145 $num = $this->db->num_rows($resql);
3147 $row = $this->db->fetch_row($resql);
3148 $rows[] = $row[0]; // Add parent line into array rows
3149 $childrens = $this->getChildrenOfLine($row[0]);
3150 if (!empty($childrens)) {
3151 foreach ($childrens as $child) {
3152 array_push($rows, $child);
3158 // Now we set a new number for each lines (parent and children with children included into parent tree)
3159 if (!empty($rows)) {
3160 foreach ($rows as $key => $row) {
3161 $this->updateRangOfLine($row, ($key + 1));
3165 dol_print_error($this->db);
3178 public function getChildrenOfLine($id, $includealltree = 0)
3180 $fieldposition = 'rang'; // @todo Rename 'rang' into 'position'
3181 if (in_array($this->table_element_line, array('bom_bomline', 'ecm_files', 'emailcollector_emailcollectoraction', 'product_attribute_value'))) {
3182 $fieldposition = 'position';
3187 $sql = "SELECT
rowid FROM
".$this->db->prefix().$this->table_element_line;
3188 $sql .= " WHERE
".$this->fk_element." =
".((int) $this->id);
3189 $sql .= ' AND fk_parent_line = '.((int) $id);
3190 $sql .= " ORDER BY
" . $fieldposition . " ASC
";
3192 dol_syslog(get_class($this)."::
getChildrenOfLine search children lines
for line
".$id, LOG_DEBUG);
3193 $resql = $this->db->query($sql);
3195 if ($this->db->num_rows($resql) > 0) {
3196 while ($row = $this->db->fetch_row($resql)) {
3198 if (!empty($includealltree)) {
3199 $rows = array_merge($rows, $this->getChildrenOfLine($row[0]), $includealltree);
3207 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3215 public function line_up($rowid, $fk_parent_line = true)
3218 $this->line_order(false, 'ASC', $fk_parent_line);
3221 $rang = $this->getRangOfLine($rowid);
3223 // Update position of line
3224 $this->updateLineUp($rowid, $rang);
3227 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3235 public function line_down($rowid, $fk_parent_line = true)
3238 $this->line_order(false, 'ASC', $fk_parent_line);
3241 $rang = $this->getRangOfLine($rowid);
3243 // Get max value for rang
3244 $max = $this->line_max();
3246 // Update position of line
3247 $this->updateLineDown($rowid, $rang, $max);
3257 public function updateRangOfLine($rowid, $rang)
3259 global $hookmanager;
3260 $fieldposition = 'rang'; // @todo Rename 'rang' into 'position'
3261 if (in_array($this->table_element_line, array('bom_bomline', 'ecm_files', 'emailcollector_emailcollectoraction', 'product_attribute_value'))) {
3262 $fieldposition = 'position';
3265 $sql = "UPDATE
".$this->db->prefix().$this->table_element_line." SET
".$fieldposition." =
".((int) $rang);
3266 $sql .= ' WHERE rowid = '.((int) $rowid);
3269 if (!$this->db->query($sql)) {
3270 dol_print_error($this->db);
3273 $parameters=array('rowid'=>$rowid, 'rang'=>$rang, 'fieldposition' => $fieldposition);
3275 $reshook = $hookmanager->executeHooks('afterRankOfLineUpdate', $parameters, $this, $action);
3280 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3287 public function line_ajaxorder($rows)
3290 $num = count($rows);
3291 for ($i = 0; $i < $num; $i++) {
3292 $this->updateRangOfLine($rows[$i], ($i + 1));
3303 public function updateLineUp($rowid, $rang)
3306 $fieldposition = 'rang';
3307 if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction', 'product_attribute_value'))) {
3308 $fieldposition = 'position';
3311 $sql = "UPDATE
".$this->db->prefix().$this->table_element_line." SET
".$fieldposition." =
".((int) $rang);
3312 $sql .= " WHERE
".$this->fk_element." =
".((int) $this->id);
3313 $sql .= " AND
" . $fieldposition . " =
" . ((int) ($rang - 1));
3314 if ($this->db->query($sql)) {
3315 $sql = "UPDATE
".$this->db->prefix().$this->table_element_line." SET
".$fieldposition." =
".((int) ($rang - 1));
3316 $sql .= ' WHERE rowid = '.((int) $rowid);
3317 if (!$this->db->query($sql)) {
3318 dol_print_error($this->db);
3321 dol_print_error($this->db);
3334 public function updateLineDown($rowid, $rang, $max)
3337 $fieldposition = 'rang';
3338 if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction', 'product_attribute_value'))) {
3339 $fieldposition = 'position';
3342 $sql = "UPDATE
".$this->db->prefix().$this->table_element_line." SET
".$fieldposition." =
".((int) $rang);
3343 $sql .= " WHERE
".$this->fk_element." =
".((int) $this->id);
3344 $sql .= " AND
" . $fieldposition . " =
" . ((int) ($rang + 1));
3345 if ($this->db->query($sql)) {
3346 $sql = "UPDATE
".$this->db->prefix().$this->table_element_line." SET
".$fieldposition." =
".((int) ($rang + 1));
3347 $sql .= ' WHERE rowid = '.((int) $rowid);
3348 if (!$this->db->query($sql)) {
3349 dol_print_error($this->db);
3352 dol_print_error($this->db);
3363 public function getRangOfLine($rowid)
3365 $fieldposition = 'rang';
3366 if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction', 'product_attribute_value'))) {
3367 $fieldposition = 'position';
3370 $sql = "SELECT
" . $fieldposition . " FROM
".$this->db->prefix().$this->table_element_line;
3371 $sql .= " WHERE
rowid =
".((int) $rowid);
3374 $resql = $this->db->query($sql);
3376 $row = $this->db->fetch_row($resql);
3387 public function getIdOfLine($rang)
3389 $fieldposition = 'rang';
3390 if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction', 'product_attribute_value'))) {
3391 $fieldposition = 'position';
3394 $sql = "SELECT
rowid FROM
".$this->db->prefix().$this->table_element_line;
3395 $sql .= " WHERE
".$this->fk_element." =
".((int) $this->id);
3396 $sql .= " AND
" . $fieldposition . " =
".((int) $rang);
3397 $resql = $this->db->query($sql);
3399 $row = $this->db->fetch_row($resql);
3404 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3411 public function line_max($fk_parent_line = 0)
3414 $positionfield = 'rang';
3415 if (in_array($this->table_element, array('bom_bom', 'product_attribute'))) {
3416 $positionfield = 'position';
3419 // Search the last rang with fk_parent_line
3420 if ($fk_parent_line) {
3421 $sql = "SELECT max(
".$positionfield.") FROM
".$this->db->prefix().$this->table_element_line;
3422 $sql .= " WHERE
".$this->fk_element." =
".((int) $this->id);
3423 $sql .= " AND fk_parent_line =
".((int) $fk_parent_line);
3425 dol_syslog(get_class($this)."::
line_max", LOG_DEBUG);
3426 $resql = $this->db->query($sql);
3428 $row = $this->db->fetch_row($resql);
3429 if (!empty($row[0])) {
3432 return $this->getRangOfLine($fk_parent_line);
3436 // If not, search the last rang of element
3437 $sql = "SELECT max(
".$positionfield.") FROM
".$this->db->prefix().$this->table_element_line;
3438 $sql .= " WHERE
".$this->fk_element." =
".((int) $this->id);
3440 dol_syslog(get_class($this)."::
line_max", LOG_DEBUG);
3441 $resql = $this->db->query($sql);
3443 $row = $this->db->fetch_row($resql);
3449 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3456 public function update_ref_ext($ref_ext)
3459 if (!$this->table_element) {
3460 dol_syslog(get_class($this)."::
update_ref_ext was called on objet with property table_element not defined
", LOG_ERR);
3464 $sql = "UPDATE
".$this->db->prefix().$this->table_element;
3465 $sql .= " SET ref_ext =
'".$this->db->escape($ref_ext)."'";
3466 $sql .= " WHERE
".(isset($this->table_rowid) ? $this->table_rowid : 'rowid')." =
".((int) $this->id);
3469 if ($this->db->query($sql)) {
3470 $this->ref_ext = $ref_ext;
3473 $this->error = $this->db->error();
3478 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3486 public function update_note($note, $suffix = '')
3491 if (!$this->table_element) {
3492 $this->error = 'update_note was called on objet with property table_element not defined';
3493 dol_syslog(get_class($this)."::
update_note was called on objet with property table_element not defined
", LOG_ERR);
3496 if (!in_array($suffix, array('', '_public', '_private'))) {
3497 $this->error = 'update_note Parameter suffix must be empty, \'_private\' or \'_public\'';
3498 dol_syslog(get_class($this)."::
update_note Parameter suffix must be empty,
'_private' or
'_public'", LOG_ERR);
3502 $newsuffix = $suffix;
3505 if ($this->table_element == 'product' && $newsuffix == '_private') {
3508 if (in_array($this->table_element, array('actioncomm', 'adherent', 'advtargetemailing', 'cronjob', 'establishment'))) {
3509 $fieldusermod = "fk_user_mod
";
3510 } elseif ($this->table_element == 'ecm_files') {
3511 $fieldusermod = "fk_user_m
";
3513 $fieldusermod = "fk_user_modif
";
3515 $sql = "UPDATE
".$this->db->prefix().$this->table_element;
3516 $sql .= " SET note
".$newsuffix." =
".(!empty($note) ? ("'".$this->db->escape($note)."'") : "NULL
");
3517 $sql .= ",
".$fieldusermod." =
".((int) $user->id);
3518 $sql .= " WHERE
rowid =
".((int) $this->id);
3520 dol_syslog(get_class($this)."::
update_note", LOG_DEBUG);
3521 if ($this->db->query($sql)) {
3522 if ($suffix == '_public') {
3523 $this->note_public = $note;
3524 } elseif ($suffix == '_private') {
3525 $this->note_private = $note;
3527 $this->note = $note; // deprecated
3528 $this->note_private = $note;
3532 $this->error = $this->db->lasterror();
3537 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3546 public function update_note_public($note)
3549 return $this->update_note($note, '_public');
3552 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3563 public function update_price($exclspec = 0, $roundingadjust = 'none', $nodatabaseupdate = 0, $seller = null)
3566 global $conf, $hookmanager, $action;
3568 $parameters = array('exclspec' => $exclspec, 'roundingadjust' => $roundingadjust, 'nodatabaseupdate' => $nodatabaseupdate, 'seller' => $seller);
3569 $reshook = $hookmanager->executeHooks('updateTotalPrice', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3571 return 1; // replacement code
3572 } elseif ($reshook < 0) {
3573 return -1; // failure
3574 } // reshook = 0 => execute normal code
3576 // Some external module want no update price after a trigger because they have another method to calculate the total (ex: with an extrafield)
3578 if ($this->element == 'propal') {
3579 $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_PROPOSAL
";
3580 } elseif ($this->element == 'commande' || $this->element == 'order') {
3581 $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_ORDER
";
3582 } elseif ($this->element == 'facture' || $this->element == 'invoice') {
3583 $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_INVOICE
";
3584 } elseif ($this->element == 'facture_fourn' || $this->element == 'supplier_invoice' || $this->element == 'invoice_supplier' || $this->element == 'invoice_supplier_rec') {
3585 $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_INVOICE
";
3586 } elseif ($this->element == 'order_supplier' || $this->element == 'supplier_order') {
3587 $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_ORDER
";
3588 } elseif ($this->element == 'supplier_proposal') {
3589 $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_PROPOSAL
";
3592 if (!empty($MODULE)) {
3593 if (!empty($conf->global->$MODULE)) {
3594 $modsactivated = explode(',', $conf->global->$MODULE);
3595 foreach ($modsactivated as $mod) {
3596 if (isModEnabled($mod)) {
3597 return 1; // update was disabled by specific setup
3603 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
3605 $forcedroundingmode = $roundingadjust;
3606 if ($forcedroundingmode == 'auto' && isset($conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND)) {
3607 $forcedroundingmode = getDolGlobalString('MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND');
3608 } elseif ($forcedroundingmode == 'auto') {
3609 $forcedroundingmode = '0';
3614 $multicurrency_tx = !empty($this->multicurrency_tx) ? $this->multicurrency_tx : 1;
3616 // Define constants to find lines to sum (field name int the table_element_line not into table_element)
3617 $fieldtva = 'total_tva';
3618 $fieldlocaltax1 = 'total_localtax1';
3619 $fieldlocaltax2 = 'total_localtax2';
3620 $fieldup = 'subprice';
3621 if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') {
3625 if ($this->element == 'invoice_supplier_rec') {
3628 if ($this->element == 'expensereport') {
3629 $fieldup = 'value_unit';
3632 $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,
";
3633 $sql .= ' tva_tx as vatrate, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, info_bits, product_type';
3634 if ($this->table_element_line == 'facturedet') {
3635 $sql .= ', situation_percent';
3637 $sql .= ', multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
3638 $sql .= " FROM
".$this->db->prefix().$this->table_element_line;
3639 $sql .= " WHERE
".$this->fk_element." =
".((int) $this->id);
3641 $product_field = 'product_type';
3642 if ($this->table_element_line == 'contratdet') {
3643 $product_field = ''; // contratdet table has no product_type field
3645 if ($product_field) {
3646 $sql .= " AND
".$product_field." <> 9
";
3649 $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
3651 dol_syslog(get_class($this)."::
update_price", LOG_DEBUG);
3653 $resql = $this->db->query($sql);
3655 $this->total_ht = 0;
3656 $this->total_tva = 0;
3657 $this->total_localtax1 = 0;
3658 $this->total_localtax2 = 0;
3659 $this->total_ttc = 0;
3660 $total_ht_by_vats = array();
3661 $total_tva_by_vats = array();
3662 $total_ttc_by_vats = array();
3663 $this->multicurrency_total_ht = 0;
3664 $this->multicurrency_total_tva = 0;
3665 $this->multicurrency_total_ttc = 0;
3667 $num = $this->db->num_rows($resql);
3670 $obj = $this->db->fetch_object($resql);
3672 // Note: There is no check on detail line and no check on total, if $forcedroundingmode = 'none'
3673 $parameters = array('fk_element' => $obj->rowid);
3674 $reshook = $hookmanager->executeHooks('changeRoundingMode', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3676 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'
3677 // This part of code is to fix data. We should not call it too often.
3678 $localtax_array = array($obj->localtax1_type, $obj->localtax1_tx, $obj->localtax2_type, $obj->localtax2_tx);
3679 $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);
3681 $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.
3682 $diff_on_current_total = price2num($obj->total_ttc - $obj->total_ht - $obj->total_tva - $obj->total_localtax1 - $obj->total_localtax2, 'MT', 1);
3683 //var_dump($obj->total_ht.' '.$obj->total_tva.' '.$obj->total_localtax1.' '.$obj->total_localtax2.' => '.$obj->total_ttc);
3684 //var_dump($diff_when_using_price_ht.' '.$diff_on_current_total);
3686 if ($diff_on_current_total) {
3687 // This should not happen, we should always have in table: total_ttc = total_ht + total_vat + total_localtax1 + total_localtax2
3688 $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);
3689 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);
3690 $resqlfix = $this->db->query($sqlfix);
3692 dol_print_error($this->db, 'Failed to update line');
3694 $obj->total_tva = $tmpcal[1];
3695 $obj->total_ttc = $tmpcal[2];
3696 } elseif ($diff_when_using_price_ht && $roundingadjust == '0') {
3697 // After calculation from HT, total is consistent but we have found a difference between VAT part in calculation and into database and
3698 // we ask to force the use of rounding on line (like done on calculation) so we force update of line
3699 $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);
3700 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);
3701 $resqlfix = $this->db->query($sqlfix);
3703 dol_print_error($this->db, 'Failed to update line');
3705 $obj->total_tva = $tmpcal[1];
3706 $obj->total_ttc = $tmpcal[2];
3710 $this->total_ht += $obj->total_ht; // The field visible at end of line detail
3711 $this->total_tva += $obj->total_tva;
3712 $this->total_localtax1 += $obj->total_localtax1;
3713 $this->total_localtax2 += $obj->total_localtax2;
3714 $this->total_ttc += $obj->total_ttc;
3715 $this->multicurrency_total_ht += $obj->multicurrency_total_ht; // The field visible at end of line detail
3716 $this->multicurrency_total_tva += $obj->multicurrency_total_tva;
3717 $this->multicurrency_total_ttc += $obj->multicurrency_total_ttc;
3719 if (!isset($total_ht_by_vats[$obj->vatrate])) {
3720 $total_ht_by_vats[$obj->vatrate] = 0;
3722 if (!isset($total_tva_by_vats[$obj->vatrate])) {
3723 $total_tva_by_vats[$obj->vatrate] = 0;
3725 if (!isset($total_ttc_by_vats[$obj->vatrate])) {
3726 $total_ttc_by_vats[$obj->vatrate] = 0;
3728 $total_ht_by_vats[$obj->vatrate] += $obj->total_ht;
3729 $total_tva_by_vats[$obj->vatrate] += $obj->total_tva;
3730 $total_ttc_by_vats[$obj->vatrate] += $obj->total_ttc;
3732 if ($forcedroundingmode == '1') { // Check if we need adjustement onto line for vat. TODO This works on the company currency but not on multicurrency
3733 $tmpvat = price2num($total_ht_by_vats[$obj->vatrate] * $obj->vatrate / 100, 'MT', 1);
3734 $diff = price2num($total_tva_by_vats[$obj->vatrate] - $tmpvat, 'MT', 1);
3735 //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
";
3737 if (abs($diff) > (10 * pow(10, -1 * getDolGlobalInt('MAIN_MAX_DECIMALS_TOT', 0)))) {
3738 // If error is more than 10 times the accurancy of rounding. This should not happen.
3739 $errmsg = 'A rounding difference was detected into TOTAL but is too high to be corrected. Some data in your line may be corrupted. Try to edit each line manually.';
3740 dol_syslog($errmsg, LOG_WARNING);
3741 dol_print_error('', $errmsg);
3744 $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);
3745 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);
3747 $resqlfix = $this->db->query($sqlfix);
3750 dol_print_error($this->db, 'Failed to update line');
3753 $this->total_tva = (float) price2num($this->total_tva - $diff, '', 1);
3754 $this->total_ttc = (float) price2num($this->total_ttc - $diff, '', 1);
3755 $total_tva_by_vats[$obj->vatrate] = (float) price2num($total_tva_by_vats[$obj->vatrate] - $diff, '', 1);
3756 $total_ttc_by_vats[$obj->vatrate] = (float) price2num($total_ttc_by_vats[$obj->vatrate] - $diff, '', 1);
3763 // Add revenue stamp to total
3764 $this->total_ttc += isset($this->revenuestamp) ? $this->revenuestamp : 0;
3765 $this->multicurrency_total_ttc += isset($this->revenuestamp) ? ($this->revenuestamp * $multicurrency_tx) : 0;
3767 // Situations totals
3768 if (!empty($this->situation_cycle_ref) && $this->situation_counter > 1 && method_exists($this, 'get_prev_sits') && $this->type != $this::TYPE_CREDIT_NOTE) {
3769 $prev_sits = $this->get_prev_sits();
3771 foreach ($prev_sits as $sit) { // $sit is an object Facture loaded with a fetch.
3772 $this->total_ht -= $sit->total_ht;
3773 $this->total_tva -= $sit->total_tva;
3774 $this->total_localtax1 -= $sit->total_localtax1;
3775 $this->total_localtax2 -= $sit->total_localtax2;
3776 $this->total_ttc -= $sit->total_ttc;
3777 $this->multicurrency_total_ht -= $sit->multicurrency_total_ht;
3778 $this->multicurrency_total_tva -= $sit->multicurrency_total_tva;
3779 $this->multicurrency_total_ttc -= $sit->multicurrency_total_ttc;
3784 $this->total_ht = (float) price2num($this->total_ht);
3785 $this->total_tva = (float) price2num($this->total_tva);
3786 $this->total_localtax1 = (float) price2num($this->total_localtax1);
3787 $this->total_localtax2 = (float) price2num($this->total_localtax2);
3788 $this->total_ttc = (float) price2num($this->total_ttc);
3790 $this->db->free($resql);
3792 // Now update global fields total_ht, total_ttc, total_tva, total_localtax1, total_localtax2, multicurrency_total_* of main object
3793 $fieldht = 'total_ht';
3795 $fieldlocaltax1 = 'localtax1';
3796 $fieldlocaltax2 = 'localtax2';
3797 $fieldttc = 'total_ttc';
3798 // Specific code for backward compatibility with old field names
3799 if (in_array($this->element, array('propal', 'commande', 'facture', 'facturerec', 'supplier_proposal', 'order_supplier', 'facture_fourn', 'invoice_supplier', 'invoice_supplier_rec', 'expensereport'))) {
3800 $fieldtva = 'total_tva';
3803 if (empty($nodatabaseupdate)) {
3804 $sql = "UPDATE
".$this->db->prefix().$this->table_element.' SET';
3805 $sql .= " ".$fieldht." =
".((float) price2num($this->total_ht, 'MT', 1)).",
";
3806 $sql .= " ".$fieldtva." =
".((float) price2num($this->total_tva, 'MT', 1)).",
";
3807 $sql .= " ".$fieldlocaltax1." =
".((float) price2num($this->total_localtax1, 'MT', 1)).",
";
3808 $sql .= " ".$fieldlocaltax2." =
".((float) price2num($this->total_localtax2, 'MT', 1)).",
";
3809 $sql .= " ".$fieldttc." =
".((float) price2num($this->total_ttc, 'MT', 1));
3810 $sql .= ", multicurrency_total_ht =
".((float) price2num($this->multicurrency_total_ht, 'MT', 1));
3811 $sql .= ", multicurrency_total_tva =
".((float) price2num($this->multicurrency_total_tva, 'MT', 1));
3812 $sql .= ", multicurrency_total_ttc =
".((float) price2num($this->multicurrency_total_ttc, 'MT', 1));
3813 $sql .= " WHERE
rowid =
".((int) $this->id);
3815 dol_syslog(get_class($this)."::
update_price", LOG_DEBUG);
3816 $resql = $this->db->query($sql);
3820 $this->error = $this->db->lasterror();
3821 $this->errors[] = $this->db->lasterror();
3831 dol_print_error($this->db, 'Bad request in update_price');
3836 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3847 public function add_object_linked($origin = null, $origin_id = null, $f_user = null, $notrigger = 0)
3850 global $user, $hookmanager, $action;
3851 $origin = (!empty($origin) ? $origin : $this->origin);
3852 $origin_id = (!empty($origin_id) ? $origin_id : $this->origin_id);
3853 $f_user = isset($f_user) ? $f_user : $user;
3856 if ($origin == 'order') {
3857 $origin = 'commande';
3859 if ($origin == 'invoice') {
3860 $origin = 'facture';
3862 if ($origin == 'invoice_template') {
3863 $origin = 'facturerec';
3865 if ($origin == 'supplierorder') {
3866 $origin = 'order_supplier';
3869 // 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.
3870 // 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.
3871 $coremodule = array('knowledgemanagement', 'partnership', 'workstation', 'ticket', 'recruitment', 'eventorganization', 'asset');
3872 // Add module part to target type if object has $module property and isn't in core modules.
3873 $targettype = ((!empty($this->module) && ! in_array($this->module, $coremodule)) ? $this->module.'_' : '').$this->element;
3875 $parameters = array('targettype'=>$targettype);
3876 // Hook for explicitly set the targettype if it must be differtent than $this->element
3877 $reshook = $hookmanager->executeHooks('setLinkedObjectSourceTargetType', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3879 if (!empty($hookmanager->resArray['targettype'])) $targettype = $hookmanager->resArray['targettype'];
3885 $sql = "INSERT INTO
" . $this->db->prefix() . "element_element (
";
3886 $sql .= "fk_source
";
3887 $sql .= ", sourcetype
";
3888 $sql .= ", fk_target
";
3889 $sql .= ", targettype
";
3890 $sql .= ") VALUES (
";
3891 $sql .= ((int) $origin_id);
3892 $sql .= ",
'" . $this->db->escape($origin) . "'";
3893 $sql .= ",
" . ((int) $this->id);
3894 $sql .= ",
'" . $this->db->escape($targettype) . "'";
3898 if ($this->db->query($sql)) {
3901 $this->context['link_origin'] = $origin;
3902 $this->context['link_origin_id'] = $origin_id;
3903 $result = $this->call_trigger('OBJECT_LINK_INSERT', $f_user);
3907 // End call triggers
3910 $this->error = $this->db->lasterror();
3915 $this->db->commit();
3918 $this->db->rollback();
3945 public function fetchObjectLinked($sourceid = null, $sourcetype = '', $targetid = null, $targettype = '', $clause = 'OR', $alsosametype = 1, $orderby = 'sourcetype', $loadalsoobjects = 1)
3947 global $conf, $hookmanager, $action;
3949 // Important for pdf generation time reduction
3950 // This boolean is true if $this->linkedObjects has already been loaded with all objects linked without filter
3951 if ($this->id > 0 && !empty($this->linkedObjectsFullLoaded[$this->id])) {
3955 $this->linkedObjectsIds = array();
3956 $this->linkedObjects = array();
3958 $justsource = false;
3959 $justtarget = false;
3960 $withtargettype = false;
3961 $withsourcetype = false;
3963 $parameters = array('sourcetype'=>$sourcetype, 'sourceid'=>$sourceid, 'targettype'=>$targettype, 'targetid'=>$targetid);
3964 // Hook for explicitly set the targettype if it must be differtent than $this->element
3965 $reshook = $hookmanager->executeHooks('setLinkedObjectSourceTargetType', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3967 if (!empty($hookmanager->resArray['sourcetype'])) $sourcetype = $hookmanager->resArray['sourcetype'];
3968 if (!empty($hookmanager->resArray['sourceid'])) $sourceid = $hookmanager->resArray['sourceid'];
3969 if (!empty($hookmanager->resArray['targettype'])) $targettype = $hookmanager->resArray['targettype'];
3970 if (!empty($hookmanager->resArray['targetid'])) $targetid = $hookmanager->resArray['targetid'];
3973 if (!empty($sourceid) && !empty($sourcetype) && empty($targetid)) {
3974 $justsource = true; // the source (id and type) is a search criteria
3975 if (!empty($targettype)) {
3976 $withtargettype = true;
3979 if (!empty($targetid) && !empty($targettype) && empty($sourceid)) {
3980 $justtarget = true; // the target (id and type) is a search criteria
3981 if (!empty($sourcetype)) {
3982 $withsourcetype = true;
3986 $sourceid = (!empty($sourceid) ? $sourceid : $this->id);
3987 $targetid = (!empty($targetid) ? $targetid : $this->id);
3988 $sourcetype = (!empty($sourcetype) ? $sourcetype : $this->element);
3989 $targettype = (!empty($targettype) ? $targettype : $this->element);
3991 /*if (empty($sourceid) && empty($targetid))
3993 dol_syslog('Bad usage of function. No source nor target id defined (nor as parameter nor as object id)', LOG_ERR);
3997 // Links between objects are stored in table element_element
3998 $sql = "SELECT
rowid, fk_source, sourcetype, fk_target, targettype
";
3999 $sql .= " FROM
".$this->db->prefix()."element_element
";
4001 if ($justsource || $justtarget) {
4003 $sql .= "fk_source =
".((int) $sourceid)." AND sourcetype =
'".$this->db->escape($sourcetype)."'";
4004 if ($withtargettype) {
4005 $sql .= " AND targettype =
'".$this->db->escape($targettype)."'";
4007 } elseif ($justtarget) {
4008 $sql .= "fk_target =
".((int) $targetid)." AND targettype =
'".$this->db->escape($targettype)."'";
4009 if ($withsourcetype) {
4010 $sql .= " AND sourcetype =
'".$this->db->escape($sourcetype)."'";
4014 $sql .= "(fk_source =
".((int) $sourceid)." AND sourcetype =
'".$this->db->escape($sourcetype)."')
";
4015 $sql .= " ".$clause." (fk_target =
".((int) $targetid)." AND targettype =
'".$this->db->escape($targettype)."')
";
4016 if ($loadalsoobjects && $this->id > 0 && $sourceid == $this->id && $sourcetype == $this->element && $targetid == $this->id && $targettype == $this->element && $clause == 'OR') {
4017 $this->linkedObjectsFullLoaded[$this->id] = true;
4020 $sql .= " ORDER BY
".$orderby;
4022 dol_syslog(get_class($this)."::fetchObjectLink
", LOG_DEBUG);
4023 $resql = $this->db->query($sql);
4025 $num = $this->db->num_rows($resql);
4028 $obj = $this->db->fetch_object($resql);
4029 if ($justsource || $justtarget) {
4031 $this->linkedObjectsIds[$obj->targettype][$obj->rowid] = $obj->fk_target;
4032 } elseif ($justtarget) {
4033 $this->linkedObjectsIds[$obj->sourcetype][$obj->rowid] = $obj->fk_source;
4036 if ($obj->fk_source == $sourceid && $obj->sourcetype == $sourcetype) {
4037 $this->linkedObjectsIds[$obj->targettype][$obj->rowid] = $obj->fk_target;
4039 if ($obj->fk_target == $targetid && $obj->targettype == $targettype) {
4040 $this->linkedObjectsIds[$obj->sourcetype][$obj->rowid] = $obj->fk_source;
4046 if (!empty($this->linkedObjectsIds)) {
4047 $tmparray = $this->linkedObjectsIds;
4048 foreach ($tmparray as $objecttype => $objectids) { // $objecttype is a module name ('facture', 'mymodule', ...) or a module name with a suffix ('project_task', 'mymodule_myobj', ...)
4049 // Parse element/subelement (ex: project_task, cabinetmed_consultation, ...)
4050 $module = $element = $subelement = $objecttype;
4052 if ($objecttype != 'supplier_proposal' && $objecttype != 'order_supplier' && $objecttype != 'invoice_supplier'
4053 && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
4054 $module = $element = $regs[1];
4055 $subelement = $regs[2];
4058 $classpath = $element.'/class';
4059 // To work with non standard classpath or module name
4060 if ($objecttype == 'facture') {
4061 $classpath = 'compta/facture/class';
4062 } elseif ($objecttype == 'facturerec') {
4063 $classpath = 'compta/facture/class';
4064 $module = 'facture';
4065 } elseif ($objecttype == 'propal') {
4066 $classpath = 'comm/propal/class';
4067 } elseif ($objecttype == 'supplier_proposal') {
4068 $classpath = 'supplier_proposal/class';
4069 } elseif ($objecttype == 'shipping') {
4070 $classpath = 'expedition/class';
4071 $subelement = 'expedition';
4072 $module = 'expedition_bon';
4073 } elseif ($objecttype == 'delivery') {
4074 $classpath = 'delivery/class';
4075 $subelement = 'delivery';
4076 $module = 'delivery_note';
4077 } elseif ($objecttype == 'invoice_supplier' || $objecttype == 'order_supplier') {
4078 $classpath = 'fourn/class';
4079 $module = 'fournisseur';
4080 } elseif ($objecttype == 'fichinter') {
4081 $classpath = 'fichinter/class';
4082 $subelement = 'fichinter';
4083 $module = 'ficheinter';
4084 } elseif ($objecttype == 'subscription') {
4085 $classpath = 'adherents/class';
4086 $module = 'adherent';
4087 } elseif ($objecttype == 'contact') {
4088 $module = 'societe';
4091 $classfile = strtolower($subelement);
4092 $classname = ucfirst($subelement);
4094 if ($objecttype == 'order') {
4095 $classfile = 'commande';
4096 $classname = 'Commande';
4097 } elseif ($objecttype == 'invoice_supplier') {
4098 $classfile = 'fournisseur.facture';
4099 $classname = 'FactureFournisseur';
4100 } elseif ($objecttype == 'order_supplier') {
4101 $classfile = 'fournisseur.commande';
4102 $classname = 'CommandeFournisseur';
4103 } elseif ($objecttype == 'supplier_proposal') {
4104 $classfile = 'supplier_proposal';
4105 $classname = 'SupplierProposal';
4106 } elseif ($objecttype == 'facturerec') {
4107 $classfile = 'facture-rec';
4108 $classname = 'FactureRec';
4109 } elseif ($objecttype == 'subscription') {
4110 $classfile = 'subscription';
4111 $classname = 'Subscription';
4112 } elseif ($objecttype == 'project' || $objecttype == 'projet') {
4113 $classpath = 'projet/class';
4114 $classfile = 'project';
4115 $classname = 'Project';
4116 } elseif ($objecttype == 'conferenceorboothattendee') {
4117 $classpath = 'eventorganization/class';
4118 $classfile = 'conferenceorboothattendee';
4119 $classname = 'ConferenceOrBoothAttendee';
4120 $module = 'eventorganization';
4121 } elseif ($objecttype == 'conferenceorbooth') {
4122 $classpath = 'eventorganization/class';
4123 $classfile = 'conferenceorbooth';
4124 $classname = 'ConferenceOrBooth';
4125 $module = 'eventorganization';
4126 } elseif ($objecttype == 'mo') {
4127 $classpath = 'mrp/class';
4133 // Here $module, $classfile and $classname are set, we can use them.
4134 if (isModEnabled($module) && (($element != $this->element) || $alsosametype)) {
4135 if ($loadalsoobjects && (is_numeric($loadalsoobjects) || ($loadalsoobjects === $objecttype))) {
4136 dol_include_once('/'.$classpath.'/'.$classfile.'.class.php');
4137 //print '/'.$classpath.'/'.$classfile.'.class.php '.class_exists($classname);
4138 if (class_exists($classname)) {
4139 foreach ($objectids as $i => $objectid) { // $i is rowid into llx_element_element
4140 $object = new $classname($this->db);
4141 $ret = $object->fetch($objectid);
4143 $this->linkedObjects[$objecttype][$i] = $object;
4149 unset($this->linkedObjectsIds[$objecttype]);
4155 dol_print_error($this->db);
4166 public function clearObjectLinkedCache()
4168 if ($this->id > 0 && !empty($this->linkedObjectsFullLoaded[$this->id])) {
4169 unset($this->linkedObjectsFullLoaded[$this->id]);
4187 public function updateObjectLinked($sourceid = null, $sourcetype = '', $targetid = null, $targettype = '', $f_user = null, $notrigger = 0)
4190 $updatesource = false;
4191 $updatetarget = false;
4192 $f_user = isset($f_user) ? $f_user : $user;
4194 if (!empty($sourceid) && !empty($sourcetype) && empty($targetid) && empty($targettype)) {
4195 $updatesource = true;
4196 } elseif (empty($sourceid) && empty($sourcetype) && !empty($targetid) && !empty($targettype)) {
4197 $updatetarget = true;
4203 $sql = "UPDATE
" . $this->db->prefix() . "element_element SET
";
4204 if ($updatesource) {
4205 $sql .= "fk_source =
" . ((int) $sourceid);
4206 $sql .= ", sourcetype =
'" . $this->db->escape($sourcetype) . "'";
4207 $sql .= " WHERE fk_target =
" . ((int) $this->id);
4208 $sql .= " AND targettype =
'" . $this->db->escape($this->element) . "'";
4209 } elseif ($updatetarget) {
4210 $sql .= "fk_target =
" . ((int) $targetid);
4211 $sql .= ", targettype =
'" . $this->db->escape($targettype) . "'";
4212 $sql .= " WHERE fk_source =
" . ((int) $this->id);
4213 $sql .= " AND sourcetype =
'" . $this->db->escape($this->element) . "'";
4217 if ($this->db->query($sql)) {
4220 $this->context['link_source_id'] = $sourceid;
4221 $this->context['link_source_type'] = $sourcetype;
4222 $this->context['link_target_id'] = $targetid;
4223 $this->context['link_target_type'] = $targettype;
4224 $result = $this->call_trigger('OBJECT_LINK_MODIFY', $f_user);
4228 // End call triggers
4231 $this->error = $this->db->lasterror();
4236 $this->db->commit();
4239 $this->db->rollback();
4257 public function deleteObjectLinked($sourceid = null, $sourcetype = '', $targetid = null, $targettype = '', $rowid = '', $f_user = null, $notrigger = 0)
4260 $deletesource = false;
4261 $deletetarget = false;
4262 $f_user = isset($f_user) ? $f_user : $user;
4264 if (!empty($sourceid) && !empty($sourcetype) && empty($targetid) && empty($targettype)) {
4265 $deletesource = true;
4266 } elseif (empty($sourceid) && empty($sourcetype) && !empty($targetid) && !empty($targettype)) {
4267 $deletetarget = true;
4270 $sourceid = (!empty($sourceid) ? $sourceid : $this->id);
4271 $sourcetype = (!empty($sourcetype) ? $sourcetype : $this->element);
4272 $targetid = (!empty($targetid) ? $targetid : $this->id);
4273 $targettype = (!empty($targettype) ? $targettype : $this->element);
4279 $this->context['link_id'] = $rowid;
4280 $this->context['link_source_id'] = $sourceid;
4281 $this->context['link_source_type'] = $sourcetype;
4282 $this->context['link_target_id'] = $targetid;
4283 $this->context['link_target_type'] = $targettype;
4284 $result = $this->call_trigger('OBJECT_LINK_DELETE', $f_user);
4288 // End call triggers
4292 $sql = "DELETE FROM
" . $this->db->prefix() . "element_element
";
4295 $sql .= " rowid =
" . ((int) $rowid);
4297 if ($deletesource) {
4298 $sql .= " fk_source =
" . ((int) $sourceid) . " AND sourcetype =
'" . $this->db->escape($sourcetype) . "'";
4299 $sql .= " AND fk_target =
" . ((int) $this->id) . " AND targettype =
'" . $this->db->escape($this->element) . "'";
4300 } elseif ($deletetarget) {
4301 $sql .= " fk_target =
" . ((int) $targetid) . " AND targettype =
'" . $this->db->escape($targettype) . "'";
4302 $sql .= " AND fk_source =
" . ((int) $this->id) . " AND sourcetype =
'" . $this->db->escape($this->element) . "'";
4304 $sql .= " (fk_source =
" . ((int) $this->id) . " AND sourcetype =
'" . $this->db->escape($this->element) . "')
";
4306 $sql .= " (fk_target =
" . ((int) $this->id) . " AND targettype =
'" . $this->db->escape($this->element) . "')
";
4311 if (!$this->db->query($sql)) {
4312 $this->error = $this->db->lasterror();
4313 $this->errors[] = $this->error;
4319 $this->db->commit();
4322 $this->db->rollback();
4336 public static function getAllItemsLinkedByObjectID($fk_object_where, $field_select, $field_where, $table_element)
4338 if (empty($fk_object_where) || empty($field_where) || empty($table_element)) {
4344 $sql = "SELECT
".$field_select." FROM
".$db->prefix().$table_element." WHERE
".$field_where." =
".((int) $fk_object_where);
4345 $resql = $db->query($sql);
4348 if (!empty($resql)) {
4349 while ($res = $db->fetch_object($resql)) {
4350 $TRes[] = $res->{$field_select};
4365 public static function deleteAllItemsLinkedByObjectID($fk_object_where, $field_where, $table_element)
4367 if (empty($fk_object_where) || empty($field_where) || empty($table_element)) {
4373 $sql = "DELETE FROM
".$db->prefix().$table_element." WHERE
".$field_where." =
".((int) $fk_object_where);
4374 $resql = $db->query($sql);
4376 if (empty($resql)) {
4393 public function setStatut($status, $elementId = null, $elementType = '', $trigkey = '', $fieldstatus = 'fk_statut')
4395 global $user, $langs, $conf;
4397 $savElementId = $elementId; // To be used later to know if we were using the method using the id of this or not.
4399 $elementId = (!empty($elementId) ? $elementId : $this->id);
4400 $elementTable = (!empty($elementType) ? $elementType : $this->table_element);
4404 if ($elementTable == 'facture_rec') {
4405 $fieldstatus = "suspended
";
4407 if ($elementTable == 'mailing') {
4408 $fieldstatus = "statut
";
4410 if ($elementTable == 'cronjob') {
4411 $fieldstatus = "status
";
4413 if ($elementTable == 'user') {
4414 $fieldstatus = "statut
";
4416 if ($elementTable == 'expensereport') {
4417 $fieldstatus = "fk_statut
";
4419 if ($elementTable == 'commande_fournisseur_dispatch') {
4420 $fieldstatus = "status
";
4422 if (isset($this->fields) && is_array($this->fields) && array_key_exists('status', $this->fields)) {
4423 $fieldstatus = 'status';
4426 $sql = "UPDATE
".$this->db->prefix().$elementTable;
4427 $sql .= " SET
".$fieldstatus." =
".((int) $status);
4428 // If status = 1 = validated, update also fk_user_valid
4429 // TODO Replace the test on $elementTable by doing a test on existence of the field in $this->fields
4430 if ($status == 1 && in_array($elementTable, array('expensereport', 'inventory'))) {
4431 $sql .= ", fk_user_valid =
".((int) $user->id);
4433 if ($status == 1 && in_array($elementTable, array('expensereport'))) {
4434 $sql .= ", date_valid =
'".$this->db->idate(dol_now())."'";
4436 if ($status == 1 && in_array($elementTable, array('inventory'))) {
4437 $sql .= ", date_validation =
'".$this->db->idate(dol_now())."'";
4439 $sql .= " WHERE
rowid =
".((int) $elementId);
4440 $sql .= " AND
".$fieldstatus." <>
".((int) $status); // We avoid update if status already correct
4442 dol_syslog(get_class($this)."::
setStatut", LOG_DEBUG);
4443 $resql = $this->db->query($sql);
4447 $nb_rows_affected = $this->db->affected_rows($resql); // should be 1 or 0 if status was already correct
4449 if ($nb_rows_affected > 0) {
4450 if (empty($trigkey)) {
4451 // Try to guess trigkey (for backward compatibility, now we should have trigkey defined into the call of setStatus)
4452 if ($this->element == 'supplier_proposal' && $status == 2) {
4453 $trigkey = 'SUPPLIER_PROPOSAL_SIGN'; // 2 = SupplierProposal::STATUS_SIGNED. Can't use constant into this generic class
4455 if ($this->element == 'supplier_proposal' && $status == 3) {
4456 $trigkey = 'SUPPLIER_PROPOSAL_REFUSE'; // 3 = SupplierProposal::STATUS_REFUSED. Can't use constant into this generic class
4458 if ($this->element == 'supplier_proposal' && $status == 4) {
4459 $trigkey = 'SUPPLIER_PROPOSAL_CLOSE'; // 4 = SupplierProposal::STATUS_CLOSED. Can't use constant into this generic class
4461 if ($this->element == 'fichinter' && $status == 3) {
4462 $trigkey = 'FICHINTER_CLASSIFY_DONE';
4464 if ($this->element == 'fichinter' && $status == 2) {
4465 $trigkey = 'FICHINTER_CLASSIFY_BILLED';
4467 if ($this->element == 'fichinter' && $status == 1) {
4468 $trigkey = 'FICHINTER_CLASSIFY_UNBILLED';
4474 $result = $this->call_trigger($trigkey, $user);
4478 // End call triggers
4481 // The status was probably already good. We do nothing more, no triggers.
4485 $this->db->commit();
4487 if (empty($savElementId)) {
4488 // If the element we update is $this (so $elementId was provided as null)
4489 if ($fieldstatus == 'tosell') {
4490 $this->status = $status;
4491 } elseif ($fieldstatus == 'tobuy') {
4492 $this->status_buy = $status;
4494 $this->statut = $status;
4495 $this->status = $status;
4501 $this->db->rollback();
4502 dol_syslog(get_class($this)."::
setStatut ".$this->error, LOG_ERR);
4506 $this->error = $this->db->lasterror();
4507 $this->db->rollback();
4520 public function getCanvas($id = 0, $ref = '')
4524 if (empty($id) && empty($ref)) {
4527 if (!empty($conf->global->MAIN_DISABLE_CANVAS)) {
4528 return 0; // To increase speed. Not enabled by default.
4534 $sql = "SELECT
rowid, canvas
";
4535 $sql .= " FROM
".$this->db->prefix().$this->table_element;
4536 $sql .= " WHERE entity IN (
".getEntity($this->element).")
";
4538 $sql .= " AND
rowid =
".((int) $id);
4541 $sql .= " AND
ref =
'".$this->db->escape($ref)."'";
4544 $resql = $this->db->query($sql);
4546 $obj = $this->db->fetch_object($resql);
4548 $this->canvas = $obj->canvas;
4554 dol_print_error($this->db);
4566 public function getSpecialCode($lineid)
4568 $sql = "SELECT special_code FROM
".$this->db->prefix().$this->table_element_line;
4569 $sql .= " WHERE
rowid =
".((int) $lineid);
4570 $resql = $this->db->query($sql);
4572 $row = $this->db->fetch_row($resql);
4585 public function isObjectUsed($id = 0, $entity = 0)
4594 if (!isset($this->childtables) || !is_array($this->childtables) || count($this->childtables) == 0) {
4595 dol_print_error('Called isObjectUsed on a class with property this->childtables not defined');
4599 $arraytoscan = $this->childtables;
4600 // For backward compatibility, we check if array is old format array('table1', 'table2', ...)
4601 $tmparray = array_keys($this->childtables);
4602 if (is_numeric($tmparray[0])) {
4603 $arraytoscan = array_flip($this->childtables);
4606 // Test if child exists
4608 foreach ($arraytoscan as $table => $element) {
4609 //print $id.'-'.$table.'-'.$elementname.'<br>';
4610 // Check if element can be deleted
4611 $sql = "SELECT COUNT(*) as nb
";
4612 $sql.= " FROM
".$this->db->prefix().$table." as c
";
4613 if (!empty($element['parent']) && !empty($element['parentkey'])) {
4614 $sql.= ",
".$this->db->prefix().$element['parent']." as p
";
4616 $sql.= " WHERE c.
".$this->fk_element." =
".((int) $id);
4617 if (!empty($element['parent']) && !empty($element['parentkey'])) {
4618 $sql.= " AND c.
".$element['parentkey']." = p.rowid
";
4620 if (!empty($entity)) {
4621 if (!empty($element['parent']) && !empty($element['parentkey'])) {
4622 $sql.= " AND p.entity =
".((int) $entity);
4624 $sql.= " AND c.entity =
".((int) $entity);
4627 $resql = $this->db->query($sql);
4629 $obj = $this->db->fetch_object($resql);
4631 $langs->load("errors
");
4632 //print 'Found into table '.$table.', type '.$langs->transnoentitiesnoconv($elementname).', haschild='.$haschild;
4633 $haschild += $obj->nb;
4634 if (is_numeric($element)) { // very old usage array('table1', 'table2', ...)
4635 $this->errors[] = $langs->transnoentitiesnoconv("ErrorRecordHasAtLeastOneChildOfType
", method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref, $table);
4636 } elseif (is_string($element)) { // old usage array('table1' => 'TranslateKey1', 'table2' => 'TranslateKey2', ...)
4637 $this->errors[] = $langs->transnoentitiesnoconv("ErrorRecordHasAtLeastOneChildOfType
", method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref, $langs->transnoentitiesnoconv($element));
4638 } else { // new usage: $element['name']=Translation key
4639 $this->errors[] = $langs->transnoentitiesnoconv("ErrorRecordHasAtLeastOneChildOfType
", method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref, $langs->transnoentitiesnoconv($element['name']));
4641 break; // We found at least one, we stop here
4644 $this->errors[] = $this->db->lasterror();
4648 if ($haschild > 0) {
4649 $this->errors[] = "ErrorRecordHasChildren
";
4662 public function hasProductsOrServices($predefined = -1)
4666 foreach ($this->lines as $key => $val) {
4668 if ($predefined == -1) {
4671 if ($predefined == 1 && $val->fk_product > 0) {
4674 if ($predefined == 0 && $val->fk_product <= 0) {
4677 if ($predefined == 2 && $val->fk_product > 0 && $val->product_type == 0) {
4680 if ($predefined == 3 && $val->fk_product > 0 && $val->product_type == 1) {
4687 dol_syslog(get_class($this).'::hasProductsOrServices we found '.$nb.' qualified lines of products/servcies');
4696 public function getTotalDiscount()
4698 if (!empty($this->table_element_line) ) {
4699 $total_discount = 0.00;
4701 $sql = "SELECT subprice as pu_ht, qty, remise_percent, total_ht
";
4702 $sql .= " FROM
".$this->db->prefix().$this->table_element_line;
4703 $sql .= " WHERE
".$this->fk_element." =
".((int) $this->id);
4705 dol_syslog(get_class($this).'::getTotalDiscount', LOG_DEBUG);
4706 $resql = $this->db->query($sql);
4708 $num = $this->db->num_rows($resql);
4711 $obj = $this->db->fetch_object($resql);
4713 $pu_ht = $obj->pu_ht;
4715 $total_ht = $obj->total_ht;
4717 $total_discount_line = floatval(price2num(($pu_ht * $qty) - $total_ht, 'MT'));
4718 $total_discount += $total_discount_line;
4724 //print $total_discount; exit;
4725 return price2num($total_discount);
4738 public function getTotalWeightVolume()
4742 // defined for shipment only
4744 // defined for shipment only
4747 foreach ($this->lines as $line) {
4748 if (isset($line->qty_asked)) {
4749 if (empty($totalOrdered)) {
4750 $totalOrdered = 0; // Avoid warning because $totalOrdered is ''
4752 $totalOrdered += $line->qty_asked; // defined for shipment only
4754 if (isset($line->qty_shipped)) {
4755 if (empty($totalToShip)) {
4756 $totalToShip = 0; // Avoid warning because $totalToShip is ''
4758 $totalToShip += $line->qty_shipped; // defined for shipment only
4759 } elseif ($line->element == 'commandefournisseurdispatch' && isset($line->qty)) {
4760 if (empty($totalToShip)) {
4763 $totalToShip += $line->qty; // defined for reception only
4766 // Define qty, weight, volume, weight_units, volume_units
4767 if ($this->element == 'shipping') {
4769 $qty = $line->qty_shipped ? $line->qty_shipped : 0;
4771 $qty = $line->qty ? $line->qty : 0;
4774 $weight = !empty($line->weight) ? $line->weight : 0;
4775 ($weight == 0 && !empty($line->product->weight)) ? $weight = $line->product->weight : 0;
4776 $volume = !empty($line->volume) ? $line->volume : 0;
4777 ($volume == 0 && !empty($line->product->volume)) ? $volume = $line->product->volume : 0;
4779 $weight_units = !empty($line->weight_units) ? $line->weight_units : 0;
4780 ($weight_units == 0 && !empty($line->product->weight_units)) ? $weight_units = $line->product->weight_units : 0;
4781 $volume_units = !empty($line->volume_units) ? $line->volume_units : 0;
4782 ($volume_units == 0 && !empty($line->product->volume_units)) ? $volume_units = $line->product->volume_units : 0;
4786 if (!empty($weight_units)) {
4787 $weightUnit = $weight_units;
4789 if (!empty($volume_units)) {
4790 $volumeUnit = $volume_units;
4793 if (empty($totalWeight)) {
4794 $totalWeight = 0; // Avoid warning because $totalWeight is ''
4796 if (empty($totalVolume)) {
4797 $totalVolume = 0; // Avoid warning because $totalVolume is ''
4800 //var_dump($line->volume_units);
4801 if ($weight_units < 50) { // < 50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch)
4802 $trueWeightUnit = pow(10, $weightUnit);
4803 $totalWeight += $weight * $qty * $trueWeightUnit;
4805 if ($weight_units == 99) {
4806 // conversion 1 Pound = 0.45359237 KG
4807 $trueWeightUnit = 0.45359237;
4808 $totalWeight += $weight * $qty * $trueWeightUnit;
4809 } elseif ($weight_units == 98) {
4810 // conversion 1 Ounce = 0.0283495 KG
4811 $trueWeightUnit = 0.0283495;
4812 $totalWeight += $weight * $qty * $trueWeightUnit;
4814 $totalWeight += $weight * $qty; // This may be wrong if we mix different units
4817 if ($volume_units < 50) { // >50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch)
4818 //print $line->volume."x
".$line->volume_units."x
".($line->volume_units < 50)."x
".$volumeUnit;
4819 $trueVolumeUnit = pow(10, $volumeUnit);
4820 //print $line->volume;
4821 $totalVolume += $volume * $qty * $trueVolumeUnit;
4823 $totalVolume += $volume * $qty; // This may be wrong if we mix different units
4827 return array('weight'=>$totalWeight, 'volume'=>$totalVolume, 'ordered'=>$totalOrdered, 'toship'=>$totalToShip);
4836 public function setExtraParameters()
4840 $extraparams = (!empty($this->extraparams) ? json_encode($this->extraparams) : null);
4842 $sql = "UPDATE
".$this->db->prefix().$this->table_element;
4843 $sql .= " SET extraparams =
".(!empty($extraparams) ? "'".$this->db->escape($extraparams)."'" : "null");
4844 $sql .= " WHERE
rowid =
".((int) $this->id);
4847 $resql = $this->db->query($sql);
4849 $this->error = $this->db->lasterror();
4850 $this->db->rollback();
4853 $this->db->commit();
4859 // --------------------
4860 // TODO: All functions here must be redesigned and moved as they are not business functions but output functions
4861 // --------------------
4863 /* This is to show add lines */
4874 public function formAddObjectLine($dateSelector, $seller, $buyer, $defaulttpldir = '/core/tpl')
4876 global $conf, $user, $langs, $object, $hookmanager, $extrafields;
4880 if (!is_object($extrafields)) {
4881 require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
4882 $extrafields = new ExtraFields($this->db);
4884 $extrafields->fetch_name_optionals_label($this->table_element_line);
4886 // Output template part (modules that overwrite templates must declare this into descriptor)
4887 // Use global variables + $dateSelector + $seller and $buyer
4888 // Note: This is deprecated. If you need to overwrite the tpl file, use instead the hook 'formAddObjectLine'.
4889 $dirtpls = array_merge($conf->modules_parts['tpl'], array($defaulttpldir));
4890 foreach ($dirtpls as $module => $reldir) {
4891 if (!empty($module)) {
4892 $tpl = dol_buildpath($reldir.'/objectline_create.tpl.php');
4894 $tpl = DOL_DOCUMENT_ROOT.$reldir.'/objectline_create.tpl.php';
4897 if (empty($conf->file->strict_mode)) {
4898 $res = @include $tpl;
4900 $res = include $tpl; // for debug
4910 /* This is to show array of line of details */
4927 public function printObjectLines($action, $seller, $buyer, $selected = 0, $dateSelector = 0, $defaulttpldir = '/core/tpl')
4929 global $conf, $hookmanager, $langs, $user, $form, $extrafields, $object;
4930 // TODO We should not use global var for this
4931 global $inputalsopricewithtax, $usemargins, $disableedit, $disablemove, $disableremove, $outputalsopricetotalwithtax;
4933 // Define usemargins
4935 if (isModEnabled('margin') && !empty($this->element) && in_array($this->element, array('facture', 'facturerec', 'propal', 'commande'))) {
4939 $num = count($this->lines);
4942 if (!is_object($extrafields)) {
4943 require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
4944 $extrafields = new ExtraFields($this->db);
4946 $extrafields->fetch_name_optionals_label($this->table_element_line);
4948 $parameters = array('num'=>$num, 'dateSelector'=>$dateSelector, 'seller'=>$seller, 'buyer'=>$buyer, 'selected'=>$selected, 'table_element_line'=>$this->table_element_line);
4949 $reshook = $hookmanager->executeHooks('printObjectLineTitle', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
4950 if (empty($reshook)) {
4951 // Output template part (modules that overwrite templates must declare this into descriptor)
4952 // Use global variables + $dateSelector + $seller and $buyer
4953 // Note: This is deprecated. If you need to overwrite the tpl file, use instead the hook.
4954 $dirtpls = array_merge($conf->modules_parts['tpl'], array($defaulttpldir));
4955 foreach ($dirtpls as $module => $reldir) {
4957 if (!empty($module)) {
4958 $tpl = dol_buildpath($reldir.'/objectline_title.tpl.php');
4960 $tpl = DOL_DOCUMENT_ROOT.$reldir.'/objectline_title.tpl.php';
4962 if (file_exists($tpl)) {
4963 if (empty($conf->file->strict_mode)) {
4964 $res = @include $tpl;
4966 $res = include $tpl; // for debug
4978 foreach ($this->lines as $line) {
4980 $line->fetch_optionals();
4982 //if (is_object($hookmanager) && (($line->product_type == 9 && !empty($line->special_code)) || !empty($line->fk_parent_line)))
4983 if (is_object($hookmanager)) { // Old code is commented on preceding line.
4984 if (empty($line->fk_parent_line)) {
4985 $parameters = array('line'=>$line, 'num'=>$num, 'i'=>$i, 'dateSelector'=>$dateSelector, 'seller'=>$seller, 'buyer'=>$buyer, 'selected'=>$selected, 'table_element_line'=>$line->table_element);
4986 $reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
4988 $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);
4989 $reshook = $hookmanager->executeHooks('printObjectSubLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
4992 if (empty($reshook)) {
4993 $this->printObjectLine($action, $line, '', $num, $i, $dateSelector, $seller, $buyer, $selected, $extrafields, $defaulttpldir);
5018 public function printObjectLine($action, $line, $var, $num, $i, $dateSelector, $seller, $buyer, $selected = 0, $extrafields = null, $defaulttpldir = '/core/tpl')
5020 global $conf, $langs, $user, $object, $hookmanager;
5022 global $object_rights, $disableedit, $disablemove, $disableremove; // TODO We should not use global var for this !
5024 $object_rights = $this->getRights();
5026 $element = $this->element;
5031 // Line in view mode
5032 if ($action != 'editline' || $selected != $line->id) {
5034 if (!empty($line->fk_product) && $line->fk_product > 0) {
5035 $product_static = new Product($this->db);
5036 $product_static->fetch($line->fk_product);
5038 $product_static->ref = $line->ref; //can change ref in hook
5039 $product_static->label = !empty($line->label) ? $line->label : ""; //can change label in hook
5041 $text = $product_static->getNomUrl(1);
5043 // Define output language and label
5044 if (getDolGlobalInt('MAIN_MULTILANGS')) {
5045 if (property_exists($this, 'socid') && !is_object($this->thirdparty)) {
5046 dol_print_error('', 'Error: Method printObjectLine was called on an object and object->fetch_thirdparty was not done before');
5050 $prod = new Product($this->db);
5051 $prod->fetch($line->fk_product);
5053 $outputlangs = $langs;
5055 if (empty($newlang) && GETPOST('lang_id', 'aZ09')) {
5056 $newlang = GETPOST('lang_id', 'aZ09');
5058 if (!empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE) && empty($newlang) && is_object($this->thirdparty)) {
5059 $newlang = $this->thirdparty->default_lang; // To use language of customer
5061 if (!empty($newlang)) {
5062 $outputlangs = new Translate("", $conf);
5063 $outputlangs->setDefaultLang($newlang);
5066 $label = (!empty($prod->multilangs[$outputlangs->defaultlang]["label
"])) ? $prod->multilangs[$outputlangs->defaultlang]["label
"] : $line->product_label;
5068 $label = $line->product_label;
5071 $text .= ' - '.(!empty($line->label) ? $line->label : $label);
5072 $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.
5075 $line->pu_ttc = price2num((!empty($line->subprice) ? $line->subprice : 0) * (1 + ((!empty($line->tva_tx) ? $line->tva_tx : 0) / 100)), 'MU');
5077 // Output template part (modules that overwrite templates must declare this into descriptor)
5078 // Use global variables + $dateSelector + $seller and $buyer
5079 // Note: This is deprecated. If you need to overwrite the tpl file, use instead the hook printObjectLine and printObjectSubLine.
5080 $dirtpls = array_merge($conf->modules_parts['tpl'], array($defaulttpldir));
5081 foreach ($dirtpls as $module => $reldir) {
5083 if (!empty($module)) {
5084 $tpl = dol_buildpath($reldir.'/objectline_view.tpl.php');
5086 $tpl = DOL_DOCUMENT_ROOT.$reldir.'/objectline_view.tpl.php';
5088 if (file_exists($tpl)) {
5089 if (empty($conf->file->strict_mode)) {
5090 $res = @include $tpl;
5092 $res = include $tpl; // for debug
5101 // Line in update mode
5102 if ($this->statut == 0 && $action == 'editline' && $selected == $line->id) {
5103 $label = (!empty($line->label) ? $line->label : (($line->fk_product > 0) ? $line->product_label : ''));
5105 $line->pu_ttc = price2num($line->subprice * (1 + ($line->tva_tx / 100)), 'MU');
5107 // Output template part (modules that overwrite templates must declare this into descriptor)
5108 // Use global variables + $dateSelector + $seller and $buyer
5109 // Note: This is deprecated. If you need to overwrite the tpl file, use instead the hook printObjectLine and printObjectSubLine.
5110 $dirtpls = array_merge($conf->modules_parts['tpl'], array($defaulttpldir));
5111 foreach ($dirtpls as $module => $reldir) {
5112 if (!empty($module)) {
5113 $tpl = dol_buildpath($reldir.'/objectline_edit.tpl.php');
5115 $tpl = DOL_DOCUMENT_ROOT.$reldir.'/objectline_edit.tpl.php';
5118 if (empty($conf->file->strict_mode)) {
5119 $res = @include $tpl;
5121 $res = include $tpl; // for debug
5131 /* This is to show array of line of details of source object */
5144 public function printOriginLinesList($restrictlist = '', $selectedLines = array())
5146 global $langs, $hookmanager, $conf, $form, $action;
5148 print '<tr class="liste_titre
">';
5149 print '<td class="linecolref
">'.$langs->trans('Ref').'</td>';
5150 print '<td class="linecoldescription
">'.$langs->trans('Description').'</td>';
5151 print '<td class="linecolvat right
">'.$langs->trans('VATRate').'</td>';
5152 print '<td class="linecoluht right
">'.$langs->trans('PriceUHT').'</td>';
5153 if (isModEnabled("multicurrency
")) {
5154 print '<td class="linecoluht_currency right
">'.$langs->trans('PriceUHTCurrency').'</td>';
5156 print '<td class="linecolqty right
">'.$langs->trans('Qty').'</td>';
5157 if (!empty($conf->global->PRODUCT_USE_UNITS)) {
5158 print '<td class="linecoluseunit left
">'.$langs->trans('Unit').'</td>';
5160 print '<td class="linecoldiscount right
">'.$langs->trans('ReductionShort').'</td>';
5161 print '<td class="linecolht right
">'.$langs->trans('TotalHT').'</td>';
5162 print '<td class="center
">'.$form->showCheckAddButtons('checkforselect', 1).'</td>';
5166 if (!empty($this->lines)) {
5167 foreach ($this->lines as $line) {
5169 //if (is_object($hookmanager) && (($line->product_type == 9 && !empty($line->special_code)) || !empty($line->fk_parent_line))) {
5170 if (is_object($hookmanager)) { // Old code is commented on preceding line.
5171 $parameters = array('line'=>$line, 'i'=>$i, 'restrictlist'=>$restrictlist, 'selectedLines'=> $selectedLines);
5172 if (!empty($line->fk_parent_line)) { $parameters['fk_parent_line'] = $line->fk_parent_line; }
5173 $reshook = $hookmanager->executeHooks('printOriginObjectLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
5175 if (empty($reshook)) {
5176 $this->printOriginLine($line, '', $restrictlist, '/core/tpl', $selectedLines);
5197 public function printOriginLine($line, $var, $restrictlist = '', $defaulttpldir = '/core/tpl', $selectedLines = array())
5199 global $langs, $conf;
5202 if (!empty($line->date_start)) {
5203 $date_start = $line->date_start;
5205 $date_start = $line->date_debut_prevue;
5206 if ($line->date_debut_reel) {
5207 $date_start = $line->date_debut_reel;
5210 if (!empty($line->date_end)) {
5211 $date_end = $line->date_end;
5213 $date_end = $line->date_fin_prevue;
5214 if ($line->date_fin_reel) {
5215 $date_end = $line->date_fin_reel;
5219 $this->tpl['id'] = $line->id;
5221 $this->tpl['label'] = '';
5222 if (!empty($line->fk_parent_line)) {
5223 $this->tpl['label'] .= img_picto('', 'rightarrow');
5226 if (($line->info_bits & 2) == 2) { // TODO Not sure this is used for source object
5227 $discount = new DiscountAbsolute($this->db);
5228 $discount->fk_soc = $this->socid;
5229 $this->tpl['label'] .= $discount->getNomUrl(0, 'discount');
5230 } elseif (!empty($line->fk_product)) {
5231 $productstatic = new Product($this->db);
5232 $productstatic->id = $line->fk_product;
5233 $productstatic->ref = $line->ref;
5234 $productstatic->type = $line->fk_product_type;
5235 if (empty($productstatic->ref)) {
5236 $line->fetch_product();
5237 $productstatic = $line->product;
5240 $this->tpl['label'] .= $productstatic->getNomUrl(1);
5241 $this->tpl['label'] .= ' - '.(!empty($line->label) ? $line->label : $line->product_label);
5243 if ($line->product_type == 1 && ($date_start || $date_end)) {
5244 $this->tpl['label'] .= get_date_range($date_start, $date_end);
5247 $this->tpl['label'] .= ($line->product_type == -1 ? ' ' : ($line->product_type == 1 ? img_object($langs->trans(''), 'service') : img_object($langs->trans(''), 'product')));
5248 if (!empty($line->desc)) {
5249 $this->tpl['label'] .= $line->desc;
5251 $this->tpl['label'] .= ($line->label ? ' '.$line->label : '');
5255 if ($line->product_type == 1 && ($date_start || $date_end)) {
5256 $this->tpl['label'] .= get_date_range($date_start, $date_end);
5260 if (!empty($line->desc)) {
5261 if ($line->desc == '(CREDIT_NOTE)') { // TODO Not sure this is used for source object
5262 $discount = new DiscountAbsolute($this->db);
5263 $discount->fetch($line->fk_remise_except);
5264 $this->tpl['description'] = $langs->transnoentities("DiscountFromCreditNote
", $discount->getNomUrl(0));
5265 } elseif ($line->desc == '(DEPOSIT)') { // TODO Not sure this is used for source object
5266 $discount = new DiscountAbsolute($this->db);
5267 $discount->fetch($line->fk_remise_except);
5268 $this->tpl['description'] = $langs->transnoentities("DiscountFromDeposit
", $discount->getNomUrl(0));
5269 } elseif ($line->desc == '(EXCESS RECEIVED)') {
5270 $discount = new DiscountAbsolute($this->db);
5271 $discount->fetch($line->fk_remise_except);
5272 $this->tpl['description'] = $langs->transnoentities("DiscountFromExcessReceived
", $discount->getNomUrl(0));
5273 } elseif ($line->desc == '(EXCESS PAID)') {
5274 $discount = new DiscountAbsolute($this->db);
5275 $discount->fetch($line->fk_remise_except);
5276 $this->tpl['description'] = $langs->transnoentities("DiscountFromExcessPaid
", $discount->getNomUrl(0));
5278 $this->tpl['description'] = dol_trunc($line->desc, 60);
5281 $this->tpl['description'] = ' ';
5285 $this->tpl['vat_rate'] = vatrate($line->tva_tx, true);
5286 $this->tpl['vat_rate'] .= (($line->info_bits & 1) == 1) ? '*' : '';
5287 if (!empty($line->vat_src_code) && !preg_match('/\(/', $this->tpl['vat_rate'])) {
5288 $this->tpl['vat_rate'] .= ' ('.$line->vat_src_code.')';
5291 $this->tpl['price'] = price($line->subprice);
5292 $this->tpl['total_ht'] = price($line->total_ht);
5293 $this->tpl['multicurrency_price'] = price($line->multicurrency_subprice);
5294 $this->tpl['qty'] = (($line->info_bits & 2) != 2) ? $line->qty : ' ';
5295 if (!empty($conf->global->PRODUCT_USE_UNITS)) {
5296 $this->tpl['unit'] = $langs->transnoentities($line->getLabelOfUnit('long'));
5298 $this->tpl['remise_percent'] = (($line->info_bits & 2) != 2) ? vatrate($line->remise_percent, true) : ' ';
5300 // Is the line strike or not
5301 $this->tpl['strike'] = 0;
5302 if ($restrictlist == 'services' && $line->product_type != Product::TYPE_SERVICE) {
5303 $this->tpl['strike'] = 1;
5306 // Output template part (modules that overwrite templates must declare this into descriptor)
5307 // Use global variables + $dateSelector + $seller and $buyer
5308 $dirtpls = array_merge($conf->modules_parts['tpl'], array($defaulttpldir));
5309 foreach ($dirtpls as $module => $reldir) {
5310 if (!empty($module)) {
5311 $tpl = dol_buildpath($reldir.'/originproductline.tpl.php');
5313 $tpl = DOL_DOCUMENT_ROOT.$reldir.'/originproductline.tpl.php';
5316 if (empty($conf->file->strict_mode)) {
5317 $res = @include $tpl;
5319 $res = include $tpl; // for debug
5328 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5339 public function add_element_resource($resource_id, $resource_type, $busy = 0, $mandatory = 0)
5344 $sql = "INSERT INTO
".$this->db->prefix()."element_resources (
";
5345 $sql .= "resource_id
";
5346 $sql .= ", resource_type
";
5347 $sql .= ", element_id
";
5348 $sql .= ", element_type
";
5350 $sql .= ", mandatory
";
5351 $sql .= ") VALUES (
";
5352 $sql .= $resource_id;
5353 $sql .= ",
'".$this->db->escape($resource_type)."'";
5354 $sql .= ",
'".$this->db->escape($this->id)."'";
5355 $sql .= ",
'".$this->db->escape($this->element)."'";
5356 $sql .= ",
'".$this->db->escape($busy)."'";
5357 $sql .= ",
'".$this->db->escape($mandatory)."'";
5361 if ($this->db->query($sql)) {
5362 $this->db->commit();
5365 $this->error = $this->db->lasterror();
5366 $this->db->rollback();
5371 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5380 public function delete_resource($rowid, $element, $notrigger = 0)
5387 $sql = "DELETE FROM
".$this->db->prefix()."element_resources
";
5388 $sql .= " WHERE
rowid =
".((int) $rowid);
5392 $resql = $this->db->query($sql);
5394 $this->error = $this->db->lasterror();
5395 $this->db->rollback();
5399 $result = $this->call_trigger(strtoupper($element).'_DELETE_RESOURCE', $user);
5401 $this->db->rollback();
5405 $this->db->commit();
5416 public function __clone()
5418 // Force a copy of this->lines, otherwise it will point to same object.
5419 if (isset($this->lines) && is_array($this->lines)) {
5420 $nboflines = count($this->lines);
5421 for ($i = 0; $i < $nboflines; $i++) {
5422 $this->lines[$i] = clone $this->lines[$i];
5440 protected function commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams = null)
5442 global $conf, $langs, $user, $hookmanager, $action;
5444 $srctemplatepath = '';
5446 $parameters = array('modelspath'=>$modelspath, 'modele'=>$modele, 'outputlangs'=>$outputlangs, 'hidedetails'=>$hidedetails, 'hidedesc'=>$hidedesc, 'hideref'=>$hideref, 'moreparams'=>$moreparams);
5447 $reshook = $hookmanager->executeHooks('commonGenerateDocument', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
5449 if (empty($reshook)) {
5450 dol_syslog("commonGenerateDocument modele=
".$modele." outputlangs->defaultlang=
".(is_object($outputlangs) ? $outputlangs->defaultlang : 'null'));
5452 if (empty($modele)) {
5453 $this->error = 'BadValueForParameterModele';
5457 // Increase limit for PDF build
5458 $err = error_reporting();
5460 @set_time_limit(120);
5461 error_reporting($err);
5463 // If selected model is a filename template (then $modele="modelname
" or "modelname:filename
")
5464 $tmp = explode(':', $modele, 2);
5465 if (!empty($tmp[1])) {
5467 $srctemplatepath = $tmp[1];
5470 // Search template files
5474 $dirmodels = array('/');
5475 if (is_array($conf->modules_parts['models'])) {
5476 $dirmodels = array_merge($dirmodels, $conf->modules_parts['models']);
5478 foreach ($dirmodels as $reldir) {
5479 foreach (array('doc', 'pdf') as $prefix) {
5480 if (in_array(get_class($this), array('Adherent'))) {
5481 // Member module use prefix_modele.class.php
5482 $file = $prefix."_
".$modele.".class.php
";
5484 // Other module use prefix_modele.modules.php
5485 $file = $prefix."_
".$modele.".modules.php
";
5488 // On verifie l'emplacement du modele
5489 $file = dol_buildpath($reldir.$modelspath.$file, 0);
5490 if (file_exists($file)) {
5492 $classname = $prefix.'_'.$modele;
5501 // If generator was found
5503 global $db; // Required to solve a conception default making an include of code using $db instead of $this->db just after.
5507 $obj = new $classname($this->db);
5509 // If generator is ODT, we must have srctemplatepath defined, if not we set it.
5510 if ($obj->type == 'odt' && empty($srctemplatepath)) {
5511 $varfortemplatedir = $obj->scandir;
5512 if ($varfortemplatedir && !empty($conf->global->$varfortemplatedir)) {
5513 $dirtoscan = $conf->global->$varfortemplatedir;
5515 $listoffiles = array();
5517 // Now we add first model found in directories scanned
5518 $listofdir = explode(',', $dirtoscan);
5519 foreach ($listofdir as $key => $tmpdir) {
5520 $tmpdir = trim($tmpdir);
5521 $tmpdir = preg_replace('/DOL_DATA_ROOT/', DOL_DATA_ROOT, $tmpdir);
5523 unset($listofdir[$key]);
5526 if (is_dir($tmpdir)) {
5527 $tmpfiles = dol_dir_list($tmpdir, 'files', 0, '\.od(s|t)$', '', 'name', SORT_ASC, 0);
5528 if (count($tmpfiles)) {
5529 $listoffiles = array_merge($listoffiles, $tmpfiles);
5534 if (count($listoffiles)) {
5535 foreach ($listoffiles as $record) {
5536 $srctemplatepath = $record['fullname'];
5542 if (empty($srctemplatepath)) {
5543 $this->error = 'ErrorGenerationAskedForOdtTemplateWithSrcFileNotDefined';
5548 if ($obj->type == 'odt' && !empty($srctemplatepath)) {
5549 if (!dol_is_file($srctemplatepath)) {
5550 dol_syslog("Failed to locate
template file
".$srctemplatepath, LOG_WARNING);
5551 $this->error = 'ErrorGenerationAskedForOdtTemplateWithSrcFileNotFound';
5556 // We save charset_output to restore it because write_file can change it if needed for
5557 // output format that does not support UTF8.
5558 $sav_charset_output = empty($outputlangs->charset_output) ? '' : $outputlangs->charset_output;
5560 if (in_array(get_class($this), array('Adherent'))) {
5561 $resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, 'member', 1, 'tmp_cards', $moreparams);
5563 $resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, $hidedetails, $hidedesc, $hideref, $moreparams);
5565 // After call of write_file $obj->result['fullpath'] is set with generated file. It will be used to update the ECM database index.
5567 if ($resultwritefile > 0) {
5568 $outputlangs->charset_output = $sav_charset_output;
5570 // We delete old preview
5571 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
5572 dol_delete_preview($this);
5574 // Index file in database
5575 if (!empty($obj->result['fullpath'])) {
5576 $destfull = $obj->result['fullpath'];
5578 // Update the last_main_doc field into main object (if document generator has property ->update_main_doc_field set)
5579 $update_main_doc_field = 0;
5580 if (!empty($obj->update_main_doc_field)) {
5581 $update_main_doc_field = 1;
5584 $this->indexFile($destfull, $update_main_doc_field);
5586 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);
5589 // Success in building document. We build meta file.
5590 dol_meta_create($this);
5594 $outputlangs->charset_output = $sav_charset_output;
5595 $this->error = $obj->error;
5596 $this->errors = $obj->errors;
5597 dol_syslog("Error generating document
for ".__CLASS__.". Error:
".$obj->error, LOG_ERR);
5602 $this->error = $langs->trans("Error
").' Failed to load doc generator with modelpaths='.$modelspath.' - modele='.$modele;
5603 $this->errors[] = $this->error;
5604 dol_syslog($this->error, LOG_ERR);
5606 $this->error = $langs->trans("Error
")." ".$langs->trans("ErrorFileDoesNotExists
", $filefound);
5607 $this->errors[] = $this->error;
5608 dol_syslog($this->error, LOG_ERR);
5626 public function indexFile($destfull, $update_main_doc_field)
5628 global $conf, $user;
5630 $upload_dir = dirname($destfull);
5631 $destfile = basename($destfull);
5632 $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $upload_dir);
5634 if (!preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir)) { // If not a tmp dir
5635 $filename = basename($destfile);
5636 $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
5637 $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
5639 include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
5640 $ecmfile = new EcmFiles($this->db);
5641 $result = $ecmfile->fetch(0, '', ($rel_dir ? $rel_dir.'/' : '').$filename);
5643 // Set the public "share
" key
5644 $setsharekey = false;
5645 if ($this->element == 'propal' || $this->element == 'proposal') {
5646 if (!isset($conf->global->PROPOSAL_ALLOW_ONLINESIGN) || !empty($conf->global->PROPOSAL_ALLOW_ONLINESIGN)) {
5647 $setsharekey = true; // feature to make online signature is not set or set to on (default)
5649 if (!empty($conf->global->PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD)) {
5650 $setsharekey = true;
5653 if ($this->element == 'commande' && !empty($conf->global->ORDER_ALLOW_EXTERNAL_DOWNLOAD)) {
5654 $setsharekey = true;
5656 if ($this->element == 'facture' && !empty($conf->global->INVOICE_ALLOW_EXTERNAL_DOWNLOAD)) {
5657 $setsharekey = true;
5659 if ($this->element == 'bank_account' && !empty($conf->global->BANK_ACCOUNT_ALLOW_EXTERNAL_DOWNLOAD)) {
5660 $setsharekey = true;
5662 if ($this->element == 'product' && !empty($conf->global->PRODUCT_ALLOW_EXTERNAL_DOWNLOAD)) {
5663 $setsharekey = true;
5665 if ($this->element == 'contrat' && !empty($conf->global->CONTRACT_ALLOW_EXTERNAL_DOWNLOAD)) {
5666 $setsharekey = true;
5668 if ($this->element == 'fichinter' && !empty($conf->global->FICHINTER_ALLOW_EXTERNAL_DOWNLOAD)) {
5669 $setsharekey = true;
5671 if ($this->element == 'supplier_proposal' && !empty($conf->global->SUPPLIER_PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD)) {
5672 $setsharekey = true;
5676 if (empty($ecmfile->share)) { // Because object not found or share not set yet
5677 require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
5678 $ecmfile->share = getRandomPassword(true);
5683 $ecmfile->label = md5_file(dol_osencode($destfull)); // hash of file content
5684 $ecmfile->fullpath_orig = '';
5685 $ecmfile->gen_or_uploaded = 'generated';
5686 $ecmfile->description = ''; // indexed content
5687 $ecmfile->keywords = ''; // keyword content
5688 $result = $ecmfile->update($user);
5690 setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
5694 $ecmfile->entity = $conf->entity;
5695 $ecmfile->filepath = $rel_dir;
5696 $ecmfile->filename = $filename;
5697 $ecmfile->label = md5_file(dol_osencode($destfull)); // hash of file content
5698 $ecmfile->fullpath_orig = '';
5699 $ecmfile->gen_or_uploaded = 'generated';
5700 $ecmfile->description = ''; // indexed content
5701 $ecmfile->keywords = ''; // keyword content
5702 $ecmfile->src_object_type = $this->table_element; // $this->table_name is 'myobject' or 'mymodule_myobject'.
5703 $ecmfile->src_object_id = $this->id;
5705 $result = $ecmfile->create($user);
5707 setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
5712 /*$this->result['fullname']=$destfull;
5713 $this->result['filepath']=$ecmfile->filepath;
5714 $this->result['filename']=$ecmfile->filename;*/
5715 //var_dump($obj->update_main_doc_field);exit;
5717 if ($update_main_doc_field && !empty($this->table_element)) {
5718 $sql = "UPDATE
".$this->db->prefix().$this->table_element." SET last_main_doc =
'".$this->db->escape($ecmfile->filepath."/".$ecmfile->filename)."'";
5719 $sql .= " WHERE
rowid =
".((int) $this->id);
5721 $resql = $this->db->query($sql);
5723 dol_print_error($this->db);
5726 $this->last_main_doc = $ecmfile->filepath.'/'.$ecmfile->filename;
5741 public function addThumbs($file)
5743 require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
5745 $tmparraysize = getDefaultImageSizes();
5746 $maxwidthsmall = $tmparraysize['maxwidthsmall'];
5747 $maxheightsmall = $tmparraysize['maxheightsmall'];
5748 $maxwidthmini = $tmparraysize['maxwidthmini'];
5749 $maxheightmini = $tmparraysize['maxheightmini'];
5750 //$quality = $tmparraysize['quality'];
5751 $quality = 50; // For thumbs, we force quality to 50
5753 $file_osencoded = dol_osencode($file);
5754 if (file_exists($file_osencoded)) {
5755 // Create small thumbs for company (Ratio is near 16/9)
5756 // Used on logon for example
5757 vignette($file_osencoded, $maxwidthsmall, $maxheightsmall, '_small', $quality);
5759 // Create mini thumbs for company (Ratio is near 16/9)
5760 // Used on menu or for setup page for example
5761 vignette($file_osencoded, $maxwidthmini, $maxheightmini, '_mini', $quality);
5766 /* Functions common to commonobject and commonobjectline */
5768 /* For default values */
5782 public function getDefaultCreateValueFor($fieldname, $alternatevalue = null)
5784 global $conf, $_POST;
5786 // If param here has been posted, we use this value first.
5787 if (GETPOSTISSET($fieldname)) {
5788 return GETPOST($fieldname, 'alphanohtml', 3);
5791 if (isset($alternatevalue)) {
5792 return $alternatevalue;
5795 $newelement = $this->element;
5796 if ($newelement == 'facture') {
5797 $newelement = 'invoice';
5799 if ($newelement == 'commande') {
5800 $newelement = 'order';
5802 if (empty($newelement)) {
5803 dol_syslog("Ask a
default value
using common method getDefaultCreateValueForField on an
object with no property ->element defined. Return empty
string.
", LOG_WARNING);
5807 $keyforfieldname = strtoupper($newelement.'_DEFAULT_'.$fieldname);
5808 //var_dump($keyforfieldname);
5809 if (isset($conf->global->$keyforfieldname)) {
5810 return $conf->global->$keyforfieldname;
5813 // TODO Ad here a scan into table llx_overwrite_default with a filter on $this->element and $fieldname
5820 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5831 public function call_trigger($triggerName, $user)
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.');
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);
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);
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.
5852 $this->errors = $interface->errors;
5859 /* Functions for data in other language */
5869 public function fetchValuesForExtraLanguages()
5871 // To avoid SQL errors. Probably not the better solution though
5872 if (!$this->element) {
5875 if (!($this->id > 0)) {
5878 if (is_array($this->array_languages)) {
5882 $this->array_languages = array();
5884 $element = $this->element;
5885 if ($element == 'categorie') {
5886 $element = 'categories'; // For compatibility
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);
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);
5898 $numrows = $this->db->num_rows($resql);
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'];
5908 // we can add this attribute to object
5909 if (preg_match('/date/', $type)) {
5910 $this->array_languages[$key][$codelang] = $this->db->jdate($value);
5912 $this->array_languages[$key][$codelang] = $value;
5919 $this->db->free($resql);
5927 dol_print_error($this->db);
5938 public function setValuesForExtraLanguages($onlykey = '')
5940 global $_POST, $langs;
5943 foreach ($_POST as $postfieldkey => $postfieldvalue) {
5944 $tmparray = explode('-', $postfieldkey);
5945 if ($tmparray[0] != 'field') {
5949 $element = $tmparray[1];
5950 $key = $tmparray[2];
5951 $codelang = $tmparray[3];
5952 //var_dump("postfieldkey=
".$postfieldkey." element=
".$element." key=
".$key." codelang=
".$codelang);
5954 if (!empty($onlykey) && $key != $onlykey) {
5957 if ($element != $this->element) {
5961 $key_type = $this->fields[$key]['type'];
5964 if (isset($this->fields[$key]['enabled'])) {
5965 $enabled = dol_eval($this->fields[$key]['enabled'], 1, 1, '1');
5968 if (isset($this->fields[$key]['perms']))
5970 $perms = dol_eval($this->fields[$key]['perms'], 1, 1, '1');
5972 if (empty($enabled)) {
5975 //if (empty($perms)) continue;
5977 if (in_array($key_type, array('date'))) {
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'))) {
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);
5992 } elseif (in_array($key_type, array('price', 'double'))) {
5993 $value_arr = GETPOST($postfieldkey, 'alpha');
5994 $value_key = price2num($value_arr);
5996 $value_key = GETPOST($postfieldkey);
5997 if (in_array($key_type, array('link')) && $value_key == '-1') {
6002 $this->array_languages[$key][$codelang] = $value_key;
6004 /*if ($nofillrequired) {
6005 $langs->load('errors');
6006 setEventMessages($langs->trans('ErrorFieldsRequired').' : '.implode(', ', $error_field_required), null, 'errors');
6015 /* Functions for extrafields */
6023 public function fetchNoCompute($id)
6027 $savDisableCompute = $conf->disable_compute;
6028 $conf->disable_compute = 1;
6030 $ret = $this->fetch($id);
6032 $conf->disable_compute = $savDisableCompute;
6037 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6047 public function fetch_optionals($rowid = null, $optionsArray = null)
6050 global $conf, $extrafields;
6052 if (empty($rowid)) {
6055 if (empty($rowid) && isset($this->rowid)) {
6056 $rowid = $this->rowid; // deprecated
6059 // To avoid SQL errors. Probably not the better solution though
6060 if (!$this->table_element) {
6064 $this->array_options = array();
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);
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);
6077 $optionsArray = (!empty($extrafields->attributes[$this->table_element]['label']) ? $extrafields->attributes[$this->table_element]['label'] : null);
6079 global $extrafields;
6080 dol_syslog("Warning:
fetch_optionals was called with param optionsArray defined when you should pass
null now
", LOG_WARNING);
6083 $table_element = $this->table_element;
6084 if ($table_element == 'categorie') {
6085 $table_element = 'categories'; // For compatibility
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') {
6096 $sql .= " FROM
".$this->db->prefix().$table_element."_extrafields
";
6097 $sql .= " WHERE fk_object =
".((int) $rowid);
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);
6102 $numrows = $this->db->num_rows($resql);
6104 $tab = $this->db->fetch_array($resql);
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);
6114 $this->array_options["options_
".$key] = $value;
6117 //var_dump('key '.$key.' '.$value.' type='.$extrafields->attributes[$this->table_element]['type'][$key].' '.$this->array_options["options_
".$key]);
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, '');
6137 $this->db->free($resql);
6145 $this->errors[]=$this->db->lasterror;
6158 public function deleteExtraFields()
6162 if (!empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) {
6168 $table_element = $this->table_element;
6169 if ($table_element == 'categorie') {
6170 $table_element = 'categories'; // For compatibility
6175 $sql_del = "DELETE FROM
".$this->db->prefix().$table_element."_extrafields WHERE fk_object =
".((int) $this->id);
6177 $resql = $this->db->query($sql_del);
6179 $this->error = $this->db->lasterror();
6180 $this->db->rollback();
6183 $this->db->commit();
6198 public function insertExtraFields($trigger = '', $userused = null)
6200 global $conf, $langs, $user;
6202 if (!empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) {
6206 if (empty($userused)) {
6212 if (!empty($this->array_options)) {
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);
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 contains the 'options_' prefix
6225 $new_array_options['options_'.$key] = $value;
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 = $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];
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;
6244 // Similar code than into insertExtraFields
6245 if ($attributeRequired) {
6246 $mandatorypb = false;
6247 if ($attributeType == 'link' && $this->array_options[$key] == '-1') {
6248 $mandatorypb = true;
6250 if ($this->array_options[$key] === '') {
6251 $mandatorypb = true;
6253 if ($attributeType == 'sellist' && $this->array_options[$key] == '0') {
6254 $mandatorypb = true;
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);
6264 //dol_syslog("attributeLabel=
".$attributeLabel, LOG_DEBUG);
6265 //dol_syslog("attributeType=
".$attributeType, LOG_DEBUG);
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;
6273 $new_array_options[$key] = null;
6277 switch ($attributeType) {
6279 if (!is_numeric($value) && $value != '') {
6280 $this->errors[] = $langs->trans("ExtraFieldHasWrongValue
", $attributeLabel);
6282 } elseif ($value == '') {
6283 $new_array_options[$key] = null;
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);
6293 } elseif ($value == '') {
6296 //dol_syslog("double value
"." sur
".$attributeLabel."(
".$value." is
'".$attributeType."')
", LOG_DEBUG);
6297 $new_array_options[$key] = $value;
6299 /*case 'select': // Not required, we chosed value='0' for undefined values
6302 $this->array_options[$key] = null;
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);
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
6321 $newvalue = dol_hash($this->array_options[$key], $algo);
6322 $new_array_options[$key] = $newvalue;
6325 $new_array_options[$key] = $this->array_options[$key]; // Value is kept
6328 } else // Common usage
6330 $new_array_options[$key] = $this->array_options[$key];
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]);
6339 $new_array_options[$key] = $this->db->idate($this->array_options[$key]);
6342 $param_list = array_keys($attributeParam['options']);
6345 $InfoFieldList = explode(":
", $param_list[0]);
6346 dol_include_once($InfoFieldList[1]);
6347 if ($InfoFieldList[0] && class_exists($InfoFieldList[0])) {
6348 if ($value == '-1') { // -1 is key for no defined in combo list of objects
6349 $new_array_options[$key] = '';
6351 $object = new $InfoFieldList[0]($this->db);
6352 if (is_numeric($value)) {
6353 $res = $object->fetch($value); // Common case
6355 $res = $object->fetch('', $value); // For compatibility
6359 $new_array_options[$key] = $object->id;
6361 $this->error = "Id/Ref
'".$value."' for object '".$object->element."' not found
";
6366 dol_syslog('Error bad setup of extrafield', LOG_WARNING);
6374 $table_element = $this->table_element;
6375 if ($table_element == 'categorie') {
6376 $table_element = 'categories'; // For compatibility
6379 dol_syslog(get_class($this)."::
insertExtraFields delete then insert
", LOG_DEBUG);
6381 $sql_del = "DELETE FROM
".$this->db->prefix().$table_element."_extrafields WHERE fk_object =
".((int) $this->id);
6382 $this->db->query($sql_del);
6384 $sql = "INSERT INTO
".$this->db->prefix().$table_element."_extrafields (fk_object
";
6385 foreach ($new_array_options as $key => $value) {
6386 $attributeKey = substr($key, 8); // Remove 'options_' prefix
6387 // Add field of attribut
6388 if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] != 'separate') { // Only for other type than separator
6389 $sql .= ",
".$attributeKey;
6392 // We must insert a default value for fields for other entities that are mandatory to avoid not null error
6393 if (!empty($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities']) && is_array($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities'])) {
6394 foreach ($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities'] as $tmpkey => $tmpval) {
6395 if (!isset($extrafields->attributes[$this->table_element]['type'][$tmpkey])) { // If field not already added previously
6396 $sql .= ",
".$tmpkey;
6400 $sql .= ") VALUES (
".$this->id;
6402 foreach ($new_array_options as $key => $value) {
6403 $attributeKey = substr($key, 8); // Remove 'options_' prefix
6404 // Add field of attribute
6405 if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] != 'separate') { // Only for other type than separator)
6406 if ($new_array_options[$key] != '' || $new_array_options[$key] == '0') {
6407 $sql .= ",
'".$this->db->escape($new_array_options[$key])."'";
6413 // We must insert a default value for fields for other entities that are mandatory to avoid not null error
6414 if (!empty($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities']) && is_array($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities'])) {
6415 foreach ($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities'] as $tmpkey => $tmpval) {
6416 if (!isset($extrafields->attributes[$this->table_element]['type'][$tmpkey])) { // If field not already added previously
6417 if (in_array($tmpval, array('int', 'double', 'price'))) {
6428 $resql = $this->db->query($sql);
6430 $this->error = $this->db->lasterror();
6434 if (!$error && $trigger) {
6436 $this->context = array('extrafieldaddupdate'=>1);
6437 $result = $this->call_trigger($trigger, $userused);
6445 $this->db->rollback();
6448 $this->db->commit();
6466 public function insertExtraLanguages($trigger = '', $userused = null)
6468 global $conf, $langs, $user;
6470 if (empty($userused)) {
6476 if (!empty($conf->global->MAIN_EXTRALANGUAGES_DISABLED)) {
6477 return 0; // For avoid conflicts if trigger used
6480 if (is_array($this->array_languages)) {
6481 $new_array_languages = $this->array_languages;
6483 foreach ($new_array_languages as $key => $value) {
6484 $attributeKey = $key;
6485 $attributeType = $this->fields[$attributeKey]['type'];
6486 $attributeLabel = $this->fields[$attributeKey]['label'];
6488 //dol_syslog("attributeLabel=
".$attributeLabel, LOG_DEBUG);
6489 //dol_syslog("attributeType=
".$attributeType, LOG_DEBUG);
6491 switch ($attributeType) {
6493 if (!is_numeric($value) && $value != '') {
6494 $this->errors[] = $langs->trans("ExtraLanguageHasWrongValue
", $attributeLabel);
6496 } elseif ($value == '') {
6497 $new_array_languages[$key] = null;
6501 $value = price2num($value);
6502 if (!is_numeric($value) && $value != '') {
6503 dol_syslog($langs->trans("ExtraLanguageHasWrongValue
")." sur
".$attributeLabel."(
".$value."is not
'".$attributeType."')
", LOG_DEBUG);
6504 $this->errors[] = $langs->trans("ExtraLanguageHasWrongValue
", $attributeLabel);
6506 } elseif ($value == '') {
6507 $new_array_languages[$key] = null;
6509 //dol_syslog("double value
"." sur
".$attributeLabel."(
".$value." is
'".$attributeType."')
", LOG_DEBUG);
6510 $new_array_languages[$key] = $value;
6512 /*case 'select': // Not required, we chosed value='0' for undefined values
6515 $this->array_options[$key] = null;
6523 $table_element = $this->table_element;
6524 if ($table_element == 'categorie') {
6525 $table_element = 'categories'; // For compatibility
6530 foreach ($new_array_languages as $key => $langcodearray) { // $key = 'name', 'town', ...
6531 foreach ($langcodearray as $langcode => $value) {
6532 $sql_del = "DELETE FROM
".$this->db->prefix()."object_lang
";
6533 $sql_del .= " WHERE fk_object =
".((int) $this->id)." AND property =
'".$this->db->escape($key)."' AND type_object =
'".$this->db->escape($table_element)."'";
6534 $sql_del .= " AND lang =
'".$this->db->escape($langcode)."'";
6535 $this->db->query($sql_del);
6537 if ($value !== '') {
6538 $sql = "INSERT INTO
".$this->db->prefix()."object_lang (fk_object, property, type_object, lang, value
";
6539 $sql .= ") VALUES (
".$this->id.",
'".$this->db->escape($key)."',
'".$this->db->escape($table_element)."',
'".$this->db->escape($langcode)."',
'".$this->db->escape($value)."'";
6542 $resql = $this->db->query($sql);
6544 $this->error = $this->db->lasterror();
6552 if (!$error && $trigger) {
6554 $this->context = array('extralanguagesaddupdate'=>1);
6555 $result = $this->call_trigger($trigger, $userused);
6563 $this->db->rollback();
6566 $this->db->commit();
6584 public function updateExtraField($key, $trigger = null, $userused = null)
6586 global $conf, $langs, $user;
6588 if (!empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) {
6592 if (empty($userused)) {
6598 if (!empty($this->array_options) && isset($this->array_options["options_
".$key])) {
6600 $langs->load('admin');
6601 require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
6602 $extrafields = new ExtraFields($this->db);
6603 $extrafields->fetch_name_optionals_label($this->table_element);
6605 $value = $this->array_options["options_
".$key];
6607 $attributeType = $extrafields->attributes[$this->table_element]['type'][$key];
6608 $attributeLabel = $extrafields->attributes[$this->table_element]['label'][$key];
6609 $attributeParam = $extrafields->attributes[$this->table_element]['param'][$key];
6610 $attributeRequired = $extrafields->attributes[$this->table_element]['required'][$key];
6611 $attrfieldcomputed = $extrafields->attributes[$this->table_element]['computed'][$key];
6613 // Similar code than into insertExtraFields
6614 if ($attributeRequired) {
6615 $mandatorypb = false;
6616 if ($attributeType == 'link' && $this->array_options["options_
".$key] == '-1') {
6617 $mandatorypb = true;
6619 if ($this->array_options["options_
".$key] === '') {
6620 $mandatorypb = true;
6623 $langs->load("errors
");
6624 dol_syslog("Mandatory field
'options_".$key."' is empty during update and
set to required into definition of extrafields
");
6625 $this->errors[] = $langs->trans('ErrorFieldRequired', $attributeLabel);
6630 //dol_syslog("attributeLabel=
".$attributeLabel, LOG_DEBUG);
6631 //dol_syslog("attributeType=
".$attributeType, LOG_DEBUG);
6633 if (!empty($attrfieldcomputed)) {
6634 if (!empty($conf->global->MAIN_STORE_COMPUTED_EXTRAFIELDS)) {
6635 $value = dol_eval($attrfieldcomputed, 1, 0, '');
6636 dol_syslog($langs->trans("Extrafieldcomputed
")." sur
".$attributeLabel."(
".$value.")
", LOG_DEBUG);
6637 $this->array_options["options_
".$key] = $value;
6639 $this->array_options["options_
".$key] = null;
6643 switch ($attributeType) {
6645 if (!is_numeric($value) && $value != '') {
6646 $this->errors[] = $langs->trans("ExtraFieldHasWrongValue
", $attributeLabel);
6648 } elseif ($value === '') {
6649 $this->array_options["options_
".$key] = null;
6653 $value = price2num($value);
6654 if (!is_numeric($value) && $value != '') {
6655 dol_syslog($langs->trans("ExtraFieldHasWrongValue
")." sur
".$attributeLabel."(
".$value."is not
'".$attributeType."')
", LOG_DEBUG);
6656 $this->errors[] = $langs->trans("ExtraFieldHasWrongValue
", $attributeLabel);
6658 } elseif ($value === '') {
6661 //dol_syslog("double value
"." sur
".$attributeLabel."(
".$value." is
'".$attributeType."')
", LOG_DEBUG);
6662 $this->array_options["options_
".$key] = $value;
6664 /*case 'select': // Not required, we chosed value='0' for undefined values
6667 $this->array_options[$key] = null;
6671 $this->array_options["options_
".$key] = price2num($this->array_options["options_
".$key]);
6675 if (empty($this->array_options["options_
".$key])) {
6676 $this->array_options["options_
".$key] = null;
6678 $this->array_options["options_
".$key] = $this->db->idate($this->array_options["options_
".$key]);
6682 if (empty($this->array_options["options_
".$key])) {
6683 $this->array_options["options_
".$key] = null;
6687 if ($this->array_options["options_
".$key] === '') {
6688 $this->array_options["options_
".$key] = null;
6693 $param_list = array_keys($attributeParam['options']);
6696 $InfoFieldList = explode(":
", $param_list[0]);
6697 dol_include_once($InfoFieldList[1]);
6698 if ($InfoFieldList[0] && class_exists($InfoFieldList[0]))
6700 if ($value == '-1') // -1 is key for no defined in combo list of objects
6702 $new_array_options[$key] = '';
6704 $object = new $InfoFieldList[0]($this->db);
6705 if (is_numeric($value)) $res = $object->fetch($value); // Common case
6706 else $res = $object->fetch('', $value); // For compatibility
6708 if ($res > 0) $new_array_options[$key] = $object->id;
6710 $this->error = "Id/Ref
'".$value."' for object '".$object->element."' not found
";
6711 $this->db->rollback();
6716 dol_syslog('Error bad setup of extrafield', LOG_WARNING);
6724 $linealreadyfound = 0;
6726 // 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)
6727 $sql = "SELECT COUNT(
rowid) as nb FROM
".$this->db->prefix().$this->table_element."_extrafields WHERE fk_object =
".((int) $this->id);
6728 $resql = $this->db->query($sql);
6730 $tmpobj = $this->db->fetch_object($resql);
6732 $linealreadyfound = $tmpobj->nb;
6736 if ($linealreadyfound) {
6737 if ($this->array_options["options_
".$key] === null) {
6738 $sql = "UPDATE
".$this->db->prefix().$this->table_element."_extrafields SET
".$key." =
null";
6740 $sql = "UPDATE
".$this->db->prefix().$this->table_element."_extrafields SET
".$key." =
'".$this->db->escape($this->array_options["options_".$key])."'";
6742 $sql .= " WHERE fk_object =
".((int) $this->id);
6744 $result = $this->insertExtraFields('', $user);
6750 $resql = $this->db->query($sql);
6753 $this->error = $this->db->lasterror();
6755 if (!$error && $trigger) {
6757 $this->context = array('extrafieldupdate'=>1);
6758 $result = $this->call_trigger($trigger, $userused);
6766 dol_syslog(__METHOD__.$this->error, LOG_ERR);
6767 $this->db->rollback();
6770 $this->db->commit();
6788 public function updateExtraLanguages($key, $trigger = null, $userused = null)
6790 global $conf, $langs, $user;
6792 if (empty($userused)) {
6798 if (!empty($conf->global->MAIN_EXTRALANGUAGES_DISABLED)) {
6799 return 0; // For avoid conflicts if trigger used
6820 public function showInputField($val, $key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = 0, $nonewbutton = 0)
6822 global $conf, $langs, $form;
6824 if (!is_object($form)) {
6825 require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
6826 $form = new Form($this->db);
6829 if (!empty($this->fields)) {
6830 $val = $this->fields[$key];
6833 // Validation tests and output
6834 $fieldValidationErrorMsg = '';
6835 $validationClass = '';
6836 $fieldValidationErrorMsg = $this->getFieldError($key);
6837 if (!empty($fieldValidationErrorMsg)) {
6838 $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
6840 $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
6847 $param['options'] = array();
6849 $size = !empty($this->fields[$key]['size']) ? $this->fields[$key]['size'] : 0;
6850 // Because we work on extrafields
6851 if (preg_match('/^(integer|link):(.*):(.*):(.*):(.*)/i', $val['type'], $reg)) {
6852 $param['options'] = array($reg[2].':'.$reg[3].':'.$reg[4].':'.$reg[5] => 'N');
6854 } elseif (preg_match('/^(integer|link):(.*):(.*):(.*)/i', $val['type'], $reg)) {
6855 $param['options'] = array($reg[2].':'.$reg[3].':'.$reg[4] => 'N');
6857 } elseif (preg_match('/^(integer|link):(.*):(.*)/i', $val['type'], $reg)) {
6858 $param['options'] = array($reg[2].':'.$reg[3] => 'N');
6860 } elseif (preg_match('/^(sellist):(.*):(.*):(.*):(.*)/i', $val['type'], $reg)) {
6861 $param['options'] = array($reg[2].':'.$reg[3].':'.$reg[4].':'.$reg[5] => 'N');
6863 } elseif (preg_match('/^(sellist):(.*):(.*):(.*)/i', $val['type'], $reg)) {
6864 $param['options'] = array($reg[2].':'.$reg[3].':'.$reg[4] => 'N');
6866 } elseif (preg_match('/^(sellist):(.*):(.*)/i', $val['type'], $reg)) {
6867 $param['options'] = array($reg[2].':'.$reg[3] => 'N');
6869 } elseif (preg_match('/^chkbxlst:(.*)/i', $val['type'], $reg)) {
6870 $param['options'] = array($reg[1] => 'N');
6872 } elseif (preg_match('/varchar\((\d+)\)/', $val['type'], $reg)) {
6873 $param['options'] = array();
6876 } elseif (preg_match('/varchar/', $val['type'])) {
6877 $param['options'] = array();
6880 $param['options'] = array();
6881 $type = $this->fields[$key]['type'];
6884 // Special case that force options and type ($type can be integer, varchar, ...)
6885 if (!empty($this->fields[$key]['arrayofkeyval']) && is_array($this->fields[$key]['arrayofkeyval'])) {
6886 $param['options'] = $this->fields[$key]['arrayofkeyval'];
6890 $label = $this->fields[$key]['label'];
6891 //$elementtype=$this->fields[$key]['elementtype']; // Seems not used
6892 $default = (!empty($this->fields[$key]['default']) ? $this->fields[$key]['default'] : '');
6893 $computed = (!empty($this->fields[$key]['computed']) ? $this->fields[$key]['computed'] : '');
6894 $unique = (!empty($this->fields[$key]['unique']) ? $this->fields[$key]['unique'] : 0);
6895 $required = (!empty($this->fields[$key]['required']) ? $this->fields[$key]['required'] : 0);
6896 $autofocusoncreate = (!empty($this->fields[$key]['autofocusoncreate']) ? $this->fields[$key]['autofocusoncreate'] : 0);
6898 $langfile = (!empty($this->fields[$key]['langfile']) ? $this->fields[$key]['langfile'] : '');
6899 $list = (!empty($this->fields[$key]['list']) ? $this->fields[$key]['list'] : 0);
6900 $hidden = (in_array(abs($this->fields[$key]['visible']), array(0, 2)) ? 1 : 0);
6902 $objectid = $this->id;
6905 if (!preg_match('/^search_/', $keyprefix)) {
6906 return '<span class="opacitymedium
">'.$langs->trans("AutomaticallyCalculated
").'</span>';
6912 // Set value of $morecss. For this, we use in priority showsize from parameters, then $val['css'] then autodefine
6913 if (empty($morecss) && !empty($val['css'])) {
6914 $morecss = $val['css'];
6915 } elseif (empty($morecss)) {
6916 if ($type == 'date') {
6917 $morecss = 'minwidth100imp';
6918 } elseif ($type == 'datetime' || $type == 'link') { // link means an foreign key to another primary id
6919 $morecss = 'minwidth200imp';
6920 } elseif (in_array($type, array('int', 'integer', 'price')) || preg_match('/^double(\([0-9],[0-9]\)){0,1}/', $type)) {
6921 $morecss = 'maxwidth75';
6922 } elseif ($type == 'url') {
6923 $morecss = 'minwidth400';
6924 } elseif ($type == 'boolean') {
6927 if (round($size) < 12) {
6928 $morecss = 'minwidth100';
6929 } elseif (round($size) <= 48) {
6930 $morecss = 'minwidth200';
6932 $morecss = 'minwidth400';
6937 // Add validation state class
6938 if (!empty($validationClass)) {
6939 $morecss.= $validationClass;
6942 if (in_array($type, array('date'))) {
6943 $tmp = explode(',', $size);
6947 // Do not show current date when field not required (see selectDate() method)
6948 if (!$required && $value == '') {
6952 // TODO Must also support $moreparam
6953 $out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1);
6954 } elseif (in_array($type, array('datetime'))) {
6955 $tmp = explode(',', $size);
6959 // Do not show current date when field not required (see selectDate() method)
6960 if (!$required && $value == '') $value = '-1';
6962 // TODO Must also support $moreparam
6963 $out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1, '', '', '', 1, '', '', 'tzuserrel');
6964 } elseif (in_array($type, array('duration'))) {
6965 $out = $form->select_duration($keyprefix.$key.$keysuffix, $value, 0, 'text', 0, 1);
6966 } elseif (in_array($type, array('int', 'integer'))) {
6967 $tmp = explode(',', $size);
6969 $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' : '').'>';
6970 } elseif (in_array($type, array('real'))) {
6971 $out = '<input type="text
" class="flat
'.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'"'.($moreparam ? $moreparam : '').($autofocusoncreate ? ' autofocus' : '').'>';
6972 } elseif (preg_match('/varchar/', $type)) {
6973 $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' : '').'>';
6974 } elseif (in_array($type, array('email', 'mail', 'phone', 'url', 'ip'))) {
6975 $out = '<input type="text
" class="flat
'.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').($autofocusoncreate ? ' autofocus' : '').'>';
6976 } elseif (preg_match('/^text/', $type)) {
6977 if (!preg_match('/search_/', $keyprefix)) { // If keyprefix is search_ or search_options_, we must just use a simple text field
6978 require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
6979 $doleditor = new DolEditor($keyprefix.$key.$keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, false, ROWS_5, '90%');
6980 $out = $doleditor->Create(1);
6982 $out = '<input type="text
" class="flat
'.$morecss.' maxwidthonsmartphone
" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').'>';
6984 } elseif (preg_match('/^html/', $type)) {
6985 if (!preg_match('/search_/', $keyprefix)) { // If keyprefix is search_ or search_options_, we must just use a simple text field
6986 require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
6987 $doleditor = new DolEditor($keyprefix.$key.$keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, isModEnabled('fckeditor') && $conf->global->FCKEDITOR_ENABLE_SOCIETE, ROWS_5, '90%');
6988 $out = $doleditor->Create(1, '', true, '', '', $moreparam, $morecss);
6990 $out = '<input type="text
" class="flat
'.$morecss.' maxwidthonsmartphone
" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').'>';
6992 } elseif ($type == 'boolean') {
6994 if (!empty($value)) {
6995 $checked = ' checked value="1
" ';
6997 $checked = ' value="1
" ';
6999 $out = '<input type="checkbox
" class="flat
'.$morecss.' maxwidthonsmartphone
" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.$checked.' '.($moreparam ? $moreparam : '').'>';
7000 } elseif ($type == 'price') {
7001 if (!empty($value)) { // $value in memory is a php numeric, we format it into user number format.
7002 $value = price($value);
7004 $out = '<input type="text
" class="flat
'.$morecss.' maxwidthonsmartphone
" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam ? $moreparam : '').'> '.$langs->getCurrencySymbol($conf->currency);
7005 } elseif (preg_match('/^double(\([0-9],[0-9]\)){0,1}/', $type)) {
7006 if (!empty($value)) { // $value in memory is a php numeric, we format it into user number format.
7007 $value = price($value);
7009 $out = '<input type="text
" class="flat
'.$morecss.' maxwidthonsmartphone
" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam ? $moreparam : '').'> ';
7010 } elseif ($type == 'select') {
7012 if (!empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_EXTRAFIELDS_DISABLE_SELECT2)) {
7013 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7014 $out .= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
7017 $out .= '<select class="flat
'.$morecss.' maxwidthonsmartphone
" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam ? $moreparam : '').'>';
7018 if ((!isset($this->fields[$key]['default'])) || ($this->fields[$key]['notnull'] != 1)) {
7019 $out .= '<option value="0
"> </option>';
7021 foreach ($param['options'] as $keyb => $valb) {
7022 if ((string) $keyb == '') {
7025 if (strpos($valb, "|
") !== false) {
7026 list($valb, $parent) = explode('|', $valb);
7028 $out .= '<option value="'.$keyb.'"';
7029 $out .= (((string) $value == (string) $keyb) ? ' selected' : '');
7030 $out .= (!empty($parent) ? ' parent="'.$parent.'"' : '');
7031 $out .= '>'.$valb.'</option>';
7033 $out .= '</select>';
7034 } elseif ($type == 'sellist') {
7036 if (!empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_EXTRAFIELDS_DISABLE_SELECT2)) {
7037 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7038 $out .= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
7041 $out .= '<select class="flat
'.$morecss.' maxwidthonsmartphone
" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam ? $moreparam : '').'>';
7042 if (is_array($param['options'])) {
7043 $param_list = array_keys($param['options']);
7044 $InfoFieldList = explode(":
", $param_list[0]);
7048 // 1 : label field name
7049 // 2 : key fields name (if differ of rowid)
7050 // 3 : key field parent (for dependent lists)
7051 // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
7052 // 5 : id category type
7053 // 6 : ids categories list separated by comma for category root
7054 $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2].' as rowid');
7056 if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
7057 if (strpos($InfoFieldList[4], 'extra.') !== false) {
7058 $keyList = 'main.'.$InfoFieldList[2].' as rowid';
7060 $keyList = $InfoFieldList[2].' as rowid';
7063 if (count($InfoFieldList) > 3 && !empty($InfoFieldList[3])) {
7064 list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
7065 $keyList .= ', '.$parentField;
7068 $filter_categorie = false;
7069 if (count($InfoFieldList) > 5) {
7070 if ($InfoFieldList[0] == 'categorie') {
7071 $filter_categorie = true;
7075 if ($filter_categorie === false) {
7076 $fields_label = explode('|', $InfoFieldList[1]);
7077 if (is_array($fields_label)) {
7079 $keyList .= implode(', ', $fields_label);
7083 $sql = "SELECT
" . $keyList;
7084 $sql .= " FROM
" . $this->db->prefix() . $InfoFieldList[0];
7085 if (!empty($InfoFieldList[4])) {
7086 // can use SELECT request
7087 if (strpos($InfoFieldList[4], '$SEL$') !== false) {
7088 $InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]);
7091 // current object id can be use into filter
7092 if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) {
7093 $InfoFieldList[4] = str_replace('$ID$', $objectid, $InfoFieldList[4]);
7095 $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
7098 //We have to join on extrafield table
7099 if (strpos($InfoFieldList[4], 'extra') !== false) {
7100 $sql .= " as main,
" . $this->db->prefix() . $InfoFieldList[0] . "_extrafields as extra
";
7101 $sqlwhere .= " WHERE extra.fk_object=main.
" . $InfoFieldList[2] . " AND
" . $InfoFieldList[4];
7103 $sqlwhere .= " WHERE
" . $InfoFieldList[4];
7106 $sqlwhere .= ' WHERE 1=1';
7108 // Some tables may have field, some other not. For the moment we disable it.
7109 if (in_array($InfoFieldList[0], array('tablewithentity'))) {
7110 $sqlwhere .= " AND entity =
" . ((int) $conf->entity);
7115 $sql .= ' ORDER BY ' . implode(', ', $fields_label);
7117 dol_syslog(get_class($this) . '::showInputField type=sellist', LOG_DEBUG);
7118 $resql = $this->db->query($sql);
7120 $out .= '<option value="0
"> </option>';
7121 $num = $this->db->num_rows($resql);
7125 $obj = $this->db->fetch_object($resql);
7127 // Several field into label (eq table:code|libelle:rowid)
7129 $fields_label = explode('|', $InfoFieldList[1]);
7130 if (count($fields_label) > 1) {
7132 foreach ($fields_label as $field_toshow) {
7133 $labeltoshow .= $obj->$field_toshow . ' ';
7136 $labeltoshow = $obj->{$InfoFieldList[1]};
7138 $labeltoshow = dol_trunc($labeltoshow, 45);
7140 if ($value == $obj->rowid) {
7141 foreach ($fields_label as $field_toshow) {
7142 $translabel = $langs->trans($obj->$field_toshow);
7143 if ($translabel != $obj->$field_toshow) {
7144 $labeltoshow = dol_trunc($translabel) . ' ';
7146 $labeltoshow = dol_trunc($obj->$field_toshow) . ' ';
7149 $out .= '<option value="' . $obj->rowid . '" selected>' . $labeltoshow . '</option>';
7152 $translabel = $langs->trans($obj->{$InfoFieldList[1]});
7153 if ($translabel != $obj->{$InfoFieldList[1]}) {
7154 $labeltoshow = dol_trunc($translabel, 18);
7156 $labeltoshow = dol_trunc($obj->{$InfoFieldList[1]});
7159 if (empty($labeltoshow)) {
7160 $labeltoshow = '(not defined)';
7162 if ($value == $obj->rowid) {
7163 $out .= '<option value="' . $obj->rowid . '" selected>' . $labeltoshow . '</option>';
7166 if (!empty($InfoFieldList[3]) && $parentField) {
7167 $parent = $parentName . ':' . $obj->{$parentField};
7171 $out .= '<option value="' . $obj->rowid . '"';
7172 $out .= ($value == $obj->rowid ? ' selected' : '');
7173 $out .= (!empty($parent) ? ' parent="' . $parent . '"' : '');
7174 $out .= '>' . $labeltoshow . '</option>';
7179 $this->db->free($resql);
7181 print 'Error in request ' . $sql . ' ' . $this->db->lasterror() . '. Check setup of extra parameters.<br>';
7184 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
7185 $data = $form->select_all_categories(Categorie::$MAP_ID_TO_CODE[$InfoFieldList[5]], '', 'parent', 64, $InfoFieldList[6], 1, 1);
7186 $out .= '<option value="0
"> </option>';
7187 foreach ($data as $data_key => $data_value) {
7188 $out .= '<option value="' . $data_key . '"';
7189 $out .= ($value == $data_key ? ' selected' : '');
7190 $out .= '>' . $data_value . '</option>';
7194 $out .= '</select>';
7195 } elseif ($type == 'checkbox') {
7196 $value_arr = explode(',', $value);
7197 $out = $form->multiselectarray($keyprefix.$key.$keysuffix, (empty($param['options']) ?null:$param['options']), $value_arr, '', 0, $morecss, 0, '100%');
7198 } elseif ($type == 'radio') {
7200 foreach ($param['options'] as $keyopt => $valopt) {
7201 $out .= '<input class="flat
'.$morecss.'" type="radio
" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam ? $moreparam : '');
7202 $out .= ' value="'.$keyopt.'"';
7203 $out .= ' id="'.$keyprefix.$key.$keysuffix.'_
'.$keyopt.'"';
7204 $out .= ($value == $keyopt ? 'checked' : '');
7205 $out .= '/><label for="'.$keyprefix.$key.$keysuffix.'_
'.$keyopt.'">'.$valopt.'</label><br>';
7207 } elseif ($type == 'chkbxlst') {
7208 if (is_array($value)) {
7209 $value_arr = $value;
7211 $value_arr = explode(',', $value);
7214 if (is_array($param['options'])) {
7215 $param_list = array_keys($param['options']);
7216 $InfoFieldList = explode(":
", $param_list[0]);
7220 // 1 : label field name
7221 // 2 : key fields name (if differ of rowid)
7222 // 3 : key field parent (for dependent lists)
7223 // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
7224 // 5 : id category type
7225 // 6 : ids categories list separated by comma for category root
7226 $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2].' as rowid');
7228 if (count($InfoFieldList) > 3 && !empty($InfoFieldList[3])) {
7229 list ($parentName, $parentField) = explode('|', $InfoFieldList[3]);
7230 $keyList .= ', '.$parentField;
7232 if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
7233 if (strpos($InfoFieldList[4], 'extra.') !== false) {
7234 $keyList = 'main.'.$InfoFieldList[2].' as rowid';
7236 $keyList = $InfoFieldList[2].' as rowid';
7240 $filter_categorie = false;
7241 if (count($InfoFieldList) > 5) {
7242 if ($InfoFieldList[0] == 'categorie') {
7243 $filter_categorie = true;
7247 if ($filter_categorie === false) {
7248 $fields_label = explode('|', $InfoFieldList[1]);
7249 if (is_array($fields_label)) {
7251 $keyList .= implode(', ', $fields_label);
7255 $sql = "SELECT
" . $keyList;
7256 $sql .= ' FROM ' . $this->db->prefix() . $InfoFieldList[0];
7257 if (!empty($InfoFieldList[4])) {
7258 // can use SELECT request
7259 if (strpos($InfoFieldList[4], '$SEL$') !== false) {
7260 $InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]);
7263 // current object id can be use into filter
7264 if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) {
7265 $InfoFieldList[4] = str_replace('$ID$', $objectid, $InfoFieldList[4]);
7267 $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
7270 // We have to join on extrafield table
7271 if (strpos($InfoFieldList[4], 'extra') !== false) {
7272 $sql .= ' as main, ' . $this->db->prefix() . $InfoFieldList[0] . '_extrafields as extra';
7273 $sqlwhere .= " WHERE extra.fk_object=main.
" . $InfoFieldList[2] . " AND
" . $InfoFieldList[4];
7275 $sqlwhere .= " WHERE
" . $InfoFieldList[4];
7278 $sqlwhere .= ' WHERE 1=1';
7280 // Some tables may have field, some other not. For the moment we disable it.
7281 if (in_array($InfoFieldList[0], array('tablewithentity'))) {
7282 $sqlwhere .= " AND entity =
" . ((int) $conf->entity);
7284 // $sql.=preg_replace('/^ AND /','',$sqlwhere);
7288 dol_syslog(get_class($this) . '::showInputField type=chkbxlst', LOG_DEBUG);
7289 $resql = $this->db->query($sql);
7291 $num = $this->db->num_rows($resql);
7298 $obj = $this->db->fetch_object($resql);
7301 // Several field into label (eq table:code|libelle:rowid)
7302 $fields_label = explode('|', $InfoFieldList[1]);
7303 if (count($fields_label) > 1) {
7305 foreach ($fields_label as $field_toshow) {
7306 $labeltoshow .= $obj->$field_toshow . ' ';
7309 $labeltoshow = $obj->{$InfoFieldList[1]};
7311 $labeltoshow = dol_trunc($labeltoshow, 45);
7313 if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
7314 foreach ($fields_label as $field_toshow) {
7315 $translabel = $langs->trans($obj->$field_toshow);
7316 if ($translabel != $obj->$field_toshow) {
7317 $labeltoshow = dol_trunc($translabel, 18) . ' ';
7319 $labeltoshow = dol_trunc($obj->$field_toshow, 18) . ' ';
7323 $data[$obj->rowid] = $labeltoshow;
7326 $translabel = $langs->trans($obj->{$InfoFieldList[1]});
7327 if ($translabel != $obj->{$InfoFieldList[1]}) {
7328 $labeltoshow = dol_trunc($translabel, 18);
7330 $labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18);
7333 if (empty($labeltoshow)) {
7334 $labeltoshow = '(not defined)';
7337 if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
7338 $data[$obj->rowid] = $labeltoshow;
7341 if (!empty($InfoFieldList[3]) && $parentField) {
7342 $parent = $parentName . ':' . $obj->{$parentField};
7346 $data[$obj->rowid] = $labeltoshow;
7351 $this->db->free($resql);
7353 $out = $form->multiselectarray($keyprefix . $key . $keysuffix, $data, $value_arr, '', 0, $morecss, 0, '100%');
7355 print 'Error in request ' . $sql . ' ' . $this->db->lasterror() . '. Check setup of extra parameters.<br>';
7358 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
7359 $data = $form->select_all_categories(Categorie::$MAP_ID_TO_CODE[$InfoFieldList[5]], '', 'parent', 64, $InfoFieldList[6], 1, 1);
7360 $out = $form->multiselectarray($keyprefix . $key . $keysuffix, $data, $value_arr, '', 0, $morecss, 0, '100%');
7363 } elseif ($type == 'link') {
7364 $param_list = array_keys($param['options']); // $param_list='ObjectName:classPath[:AddCreateButtonOrNot[:Filter[:Sortfield]]]'
7365 $param_list_array = explode(':', $param_list[0]);
7366 $showempty = (($required && $default != '') ? 0 : 1);
7368 if (!preg_match('/search_/', $keyprefix)) {
7369 if (!empty($param_list_array[2])) { // If the entry into $fields is set to add a create button
7370 if (!empty($this->fields[$key]['picto'])) {
7371 $morecss .= ' widthcentpercentminusxx';
7373 $morecss .= ' widthcentpercentminusx';
7376 if (!empty($this->fields[$key]['picto'])) {
7377 $morecss .= ' widthcentpercentminusx';
7382 $out = $form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty, '', '', $morecss, $moreparam, 0, empty($val['disabled']) ? 0 : 1);
7384 if (!empty($param_list_array[2])) { // If the entry into $fields is set to add a create button
7385 if (!GETPOSTISSET('backtopage') && empty($val['disabled']) && empty($nonewbutton)) { // To avoid to open several times the 'Create Object' button and to avoid to have button if field is protected by a "disabled
".
7386 list($class, $classfile) = explode(':', $param_list[0]);
7387 if (file_exists(dol_buildpath(dirname(dirname($classfile)).'/card.php'))) {
7388 $url_path = dol_buildpath(dirname(dirname($classfile)).'/card.php', 1);
7390 $url_path = dol_buildpath(dirname(dirname($classfile)).'/'.strtolower($class).'_card.php', 1);
7392 $paramforthenewlink = '';
7393 $paramforthenewlink .= (GETPOSTISSET('action') ? '&action='.GETPOST('action', 'aZ09') : '');
7394 $paramforthenewlink .= (GETPOSTISSET('id') ? '&id='.GETPOST('id', 'int') : '');
7395 $paramforthenewlink .= (GETPOSTISSET('origin') ? '&origin='.GETPOST('origin', 'aZ09') : '');
7396 $paramforthenewlink .= (GETPOSTISSET('originid') ? '&originid='.GETPOST('originid', 'int') : '');
7397 $paramforthenewlink .= '&fk_'.strtolower($class).'=--IDFORBACKTOPAGE--';
7398 // TODO Add Javascript code to add input fields already filled into $paramforthenewlink so we won't loose them when going back to main page
7399 $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>';
7402 } elseif ($type == 'password') {
7403 // If prefix is 'search_', field is used as a filter, we use a common text field.
7404 $out = '<input type="'.($keyprefix == 'search_
' ? 'text
' : 'password
').'" class="flat
'.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam ? $moreparam : '').'>';
7405 } elseif ($type == 'array') {
7407 $newval['type'] = 'varchar(256)';
7410 if (!empty($value)) {
7411 foreach ($value as $option) {
7412 $out .= '<span><a class="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_del
" href="javascript:;
"><span class="fa fa-minus-circle valignmiddle
"></span></a> ';
7413 $out .= $this->showInputField($newval, $keyprefix.$key.$keysuffix.'[]', $option, $moreparam, '', '', $morecss).'<br></span>';
7416 $out .= '<a id="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_add
" href="javascript:;
"><span class="fa fa-plus-circle valignmiddle
"></span></a>';
7418 $newInput = '<span><a class="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_del
" href="javascript:;
"><span class="fa fa-minus-circle valignmiddle
"></span></a> ';
7419 $newInput .= $this->showInputField($newval, $keyprefix.$key.$keysuffix.'[]', '', $moreparam, '', '', $morecss).'<br></span>';
7421 if (!empty($conf->use_javascript_ajax)) {
7424 $(document).ready(function() {
7425 $("a#
'.dol_escape_js($keyprefix.$key.$keysuffix).'_add
").click(function() {
7426 $("'.dol_escape_js($newInput).'").insertBefore(this);
7429 $(document).on("click
", "a.
'.dol_escape_js($keyprefix.$key.$keysuffix).'_del
", function() {
7430 $(this).parent().remove();
7436 if (!empty($hidden)) {
7437 $out = '<input type="hidden
" value="'.$value.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'"/>';
7440 if ($isDependList==1) {
7441 $out .= $this->getJSListDependancies('_common');
7444 if ($type == 'date') $out.=' (YYYY-MM-DD)';
7445 elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)';
7448 // Display error message for field
7449 if (!empty($fieldValidationErrorMsg) && function_exists('getFieldErrorIcon')) {
7450 $out .= ' '.getFieldErrorIcon($fieldValidationErrorMsg);
7469 public function showOutputField($val, $key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = '')
7471 global $conf, $langs, $form;
7473 if (!is_object($form)) {
7474 require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
7475 $form = new Form($this->db);
7478 $objectid = $this->id; // Not used ???
7480 $label = empty($val['label']) ? '' : $val['label'];
7481 $type = empty($val['type']) ? '' : $val['type'];
7482 $size = empty($val['css']) ? '' : $val['css'];
7485 // Convert var to be able to share same code than showOutputField of extrafields
7486 if (preg_match('/varchar\((\d+)\)/', $type, $reg)) {
7487 $type = 'varchar'; // convert varchar(xx) int varchar
7489 } elseif (preg_match('/varchar/', $type)) {
7490 $type = 'varchar'; // convert varchar(xx) int varchar
7492 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
7495 if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) {
7499 $default = empty($val['default']) ? '' : $val['default'];
7500 $computed = empty($val['computed']) ? '' : $val['computed'];
7501 $unique = empty($val['unique']) ? '' : $val['unique'];
7502 $required = empty($val['required']) ? '' : $val['required'];
7504 $param['options'] = array();
7506 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
7507 $param['options'] = $val['arrayofkeyval'];
7509 if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) {
7511 $param['options'] = array($reg[1].':'.$reg[2]=>$reg[1].':'.$reg[2]);
7512 } elseif (preg_match('/^sellist:(.*):(.*):(.*):(.*)/i', $val['type'], $reg)) {
7513 $param['options'] = array($reg[1].':'.$reg[2].':'.$reg[3].':'.$reg[4] => 'N');
7515 } elseif (preg_match('/^sellist:(.*):(.*):(.*)/i', $val['type'], $reg)) {
7516 $param['options'] = array($reg[1].':'.$reg[2].':'.$reg[3] => 'N');
7518 } elseif (preg_match('/^sellist:(.*):(.*)/i', $val['type'], $reg)) {
7519 $param['options'] = array($reg[1].':'.$reg[2] => 'N');
7521 } elseif (preg_match('/^chkbxlst:(.*)/i', $val['type'], $reg)) {
7522 $param['options'] = array($reg[1] => 'N');
7526 $langfile = empty($val['langfile']) ? '' : $val['langfile'];
7527 $list = (empty($val['list']) ? '' : $val['list']);
7528 $help = (empty($val['help']) ? '' : $val['help']);
7529 $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)
7535 // If field is a computed field, value must become result of compute
7537 // Make the eval of compute string
7538 //var_dump($computed);
7539 $value = dol_eval($computed, 1, 0, '');
7542 if (empty($morecss)) {
7543 if ($type == 'date') {
7544 $morecss = 'minwidth100imp';
7545 } elseif ($type == 'datetime' || $type == 'timestamp') {
7546 $morecss = 'minwidth200imp';
7547 } elseif (in_array($type, array('int', 'double', 'price'))) {
7548 $morecss = 'maxwidth75';
7549 } elseif ($type == 'url') {
7550 $morecss = 'minwidth400';
7551 } elseif ($type == 'boolean') {
7554 if (is_numeric($size) && round($size) < 12) {
7555 $morecss = 'minwidth100';
7556 } elseif (is_numeric($size) && round($size) <= 48) {
7557 $morecss = 'minwidth200';
7559 $morecss = 'minwidth400';
7564 // Format output value differently according to properties of field
7565 if (in_array($key, array('rowid', 'ref')) && method_exists($this, 'getNomUrl')) {
7566 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.
7567 $value = $this->getNomUrl(1, '', 0, '', 1);
7569 } elseif ($key == 'status' && method_exists($this, 'getLibStatut')) {
7570 $value = $this->getLibStatut(3);
7571 } elseif ($type == 'date') {
7572 if (!empty($value)) {
7573 $value = dol_print_date($value, 'day'); // We suppose dates without time are always gmt (storage of course + output)
7577 } elseif ($type == 'datetime' || $type == 'timestamp') {
7578 if (!empty($value)) {
7579 $value = dol_print_date($value, 'dayhour', 'tzuserrel');
7583 } elseif ($type == 'duration') {
7584 include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
7585 if (!is_null($value) && $value !== '') {
7586 $value = convertSecondToTime($value, 'allhourmin');
7588 } elseif ($type == 'double' || $type == 'real') {
7589 if (!is_null($value) && $value !== '') {
7590 $value = price($value);
7592 } elseif ($type == 'boolean') {
7594 if (!empty($value)) {
7595 $checked = ' checked ';
7597 $value = '<input type="checkbox
" '.$checked.' '.($moreparam ? $moreparam : '').' readonly disabled>';
7598 } elseif ($type == 'mail' || $type == 'email') {
7599 $value = dol_print_email($value, 0, 0, 0, 64, 1, 1);
7600 } elseif ($type == 'url') {
7601 $value = dol_print_url($value, '_blank', 32, 1);
7602 } elseif ($type == 'phone') {
7603 $value = dol_print_phone($value, '', 0, 0, '', ' ', 'phone');
7604 } elseif ($type == 'ip') {
7605 $value = dol_print_ip($value, 0);
7606 } elseif ($type == 'price') {
7607 if (!is_null($value) && $value !== '') {
7608 $value = price($value, 0, $langs, 0, 0, -1, $conf->currency);
7610 } elseif ($type == 'select') {
7611 $value = isset($param['options'][$value])?$param['options'][$value]:'';
7612 } elseif ($type == 'sellist') {
7613 $param_list = array_keys($param['options']);
7614 $InfoFieldList = explode(":
", $param_list[0]);
7616 $selectkey = "rowid";
7619 if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
7620 $selectkey = $InfoFieldList[2];
7621 $keyList = $InfoFieldList[2].' as rowid';
7624 $fields_label = explode('|', $InfoFieldList[1]);
7625 if (is_array($fields_label)) {
7627 $keyList .= implode(', ', $fields_label);
7630 $filter_categorie = false;
7631 if (count($InfoFieldList) > 5) {
7632 if ($InfoFieldList[0] == 'categorie') {
7633 $filter_categorie = true;
7637 $sql = "SELECT
".$keyList;
7638 $sql .= ' FROM '.$this->db->prefix().$InfoFieldList[0];
7639 if (strpos($InfoFieldList[4], 'extra') !== false) {
7642 if ($selectkey == 'rowid' && empty($value)) {
7643 $sql .= " WHERE
".$selectkey." = 0
";
7644 } elseif ($selectkey == 'rowid') {
7645 $sql .= " WHERE
".$selectkey." =
".((int) $value);
7647 $sql .= " WHERE
".$selectkey." =
'".$this->db->escape($value)."'";
7650 //$sql.= ' AND entity = '.$conf->entity;
7652 dol_syslog(get_class($this).':showOutputField:$type=sellist', LOG_DEBUG);
7653 $resql = $this->db->query($sql);
7655 if ($filter_categorie === false) {
7656 $value = ''; // value was used, so now we reste it to use it to build final output
7657 $numrows = $this->db->num_rows($resql);
7659 $obj = $this->db->fetch_object($resql);
7661 // Several field into label (eq table:code|libelle:rowid)
7662 $fields_label = explode('|', $InfoFieldList[1]);
7664 if (is_array($fields_label) && count($fields_label) > 1) {
7665 foreach ($fields_label as $field_toshow) {
7667 if (!empty($obj->$field_toshow)) {
7668 $translabel = $langs->trans($obj->$field_toshow);
7670 if ($translabel != $field_toshow) {
7671 $value .= dol_trunc($translabel, 18) . ' ';
7673 $value .= $obj->$field_toshow . ' ';
7678 if (!empty($obj->{$InfoFieldList[1]})) {
7679 $translabel = $langs->trans($obj->{$InfoFieldList[1]});
7681 if ($translabel != $obj->{$InfoFieldList[1]}) {
7682 $value = dol_trunc($translabel, 18);
7684 $value = $obj->{$InfoFieldList[1]};
7689 require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
7692 $obj = $this->db->fetch_object($resql);
7693 $c = new Categorie($this->db);
7694 $c->fetch($obj->rowid);
7695 $ways = $c->print_all_ways(); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1
" with html formatted text
7696 foreach ($ways as $way) {
7697 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories
"' . ($c->color ? ' style="background: #
' . $c->color . ';
"' : ' style="background: #aaa
"') . '>' . img_object('', 'category') . ' ' . $way . '</li>';
7699 $value = '<div class="select2-container-multi-dolibarr
" style="width: 90%;
"><ul class="select2-choices-dolibarr
">'.implode(' ', $toprint).'</ul></div>';
7702 dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
7704 } elseif ($type == 'radio') {
7705 $value = $param['options'][$value];
7706 } elseif ($type == 'checkbox') {
7707 $value_arr = explode(',', $value);
7709 if (is_array($value_arr) && count($value_arr) > 0) {
7711 foreach ($value_arr as $keyval => $valueval) {
7712 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories
" style="background: #bbb
">'.$param['options'][$valueval].'</li>';
7714 $value = '<div class="select2-container-multi-dolibarr
" style="width: 90%;
"><ul class="select2-choices-dolibarr
">'.implode(' ', $toprint).'</ul></div>';
7716 } elseif ($type == 'chkbxlst') {
7717 $value_arr = explode(',', $value);
7719 $param_list = array_keys($param['options']);
7720 $InfoFieldList = explode(":
", $param_list[0]);
7722 $selectkey = "rowid";
7725 if (count($InfoFieldList) >= 3) {
7726 $selectkey = $InfoFieldList[2];
7727 $keyList = $InfoFieldList[2].' as rowid';
7730 $fields_label = explode('|', $InfoFieldList[1]);
7731 if (is_array($fields_label)) {
7733 $keyList .= implode(', ', $fields_label);
7736 $filter_categorie = false;
7737 if (count($InfoFieldList) > 5) {
7738 if ($InfoFieldList[0] == 'categorie') {
7739 $filter_categorie = true;
7743 $sql = "SELECT
".$keyList;
7744 $sql .= ' FROM '.$this->db->prefix().$InfoFieldList[0];
7745 if (strpos($InfoFieldList[4], 'extra') !== false) {
7748 // $sql.= " WHERE
".$selectkey."=
'".$this->db->escape($value)."'";
7749 // $sql.= ' AND entity = '.$conf->entity;
7751 dol_syslog(get_class($this).':showOutputField:$type=chkbxlst', LOG_DEBUG);
7752 $resql = $this->db->query($sql);
7754 if ($filter_categorie === false) {
7755 $value = ''; // value was used, so now we reste it to use it to build final output
7757 while ($obj = $this->db->fetch_object($resql)) {
7758 // Several field into label (eq table:code|libelle:rowid)
7759 $fields_label = explode('|', $InfoFieldList[1]);
7760 if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
7761 if (is_array($fields_label) && count($fields_label) > 1) {
7762 foreach ($fields_label as $field_toshow) {
7764 if (!empty($obj->$field_toshow)) {
7765 $translabel = $langs->trans($obj->$field_toshow);
7767 if ($translabel != $field_toshow) {
7768 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories
" style="background: #bbb
">' . dol_trunc($translabel, 18) . '</li>';
7770 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories
" style="background: #bbb
">' . $obj->$field_toshow . '</li>';
7775 if (!empty($obj->{$InfoFieldList[1]})) {
7776 $translabel = $langs->trans($obj->{$InfoFieldList[1]});
7778 if ($translabel != $obj->{$InfoFieldList[1]}) {
7779 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories
" style="background: #bbb
">' . dol_trunc($translabel, 18) . '</li>';
7781 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories
" style="background: #bbb
">' . $obj->{$InfoFieldList[1]} . '</li>';
7787 require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
7790 while ($obj = $this->db->fetch_object($resql)) {
7791 if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
7792 $c = new Categorie($this->db);
7793 $c->fetch($obj->rowid);
7794 $ways = $c->print_all_ways(); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1
" with html formatted text
7795 foreach ($ways as $way) {
7796 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories
"' . ($c->color ? ' style="background: #
' . $c->color . ';
"' : ' style="background: #aaa
"') . '>' . img_object('', 'category') . ' ' . $way . '</li>';
7801 $value = '<div class="select2-container-multi-dolibarr
" style="width: 90%;
"><ul class="select2-choices-dolibarr
">'.implode(' ', $toprint).'</ul></div>';
7803 dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
7805 } elseif ($type == 'link') {
7808 // only if something to display (perf)
7810 $param_list = array_keys($param['options']); // $param_list='ObjectName:classPath'
7812 $InfoFieldList = explode(":
", $param_list[0]);
7813 $classname = $InfoFieldList[0];
7814 $classpath = $InfoFieldList[1];
7815 $getnomurlparam = (empty($InfoFieldList[2]) ? 3 : $InfoFieldList[2]);
7816 $getnomurlparam2 = (empty($InfoFieldList[4]) ? '' : $InfoFieldList[4]);
7817 if (!empty($classpath)) {
7818 dol_include_once($InfoFieldList[1]);
7819 if ($classname && class_exists($classname)) {
7820 $object = new $classname($this->db);
7821 if ($object->element === 'product') { // Special cas for product because default valut of fetch are wrong
7822 $result = $object->fetch($value, '', '', '', 0, 1, 1);
7824 $result = $object->fetch($value);
7827 if ($object->element === 'product') {
7828 $get_name_url_param_arr = array($getnomurlparam, $getnomurlparam2, 0, -1, 0, '', 0);
7829 if (isset($val['get_name_url_params'])) {
7830 $get_name_url_params = explode(':', $val['get_name_url_params']);
7831 if (!empty($get_name_url_params)) {
7832 $param_num_max = count($get_name_url_param_arr) - 1;
7833 foreach ($get_name_url_params as $param_num => $param_value) {
7834 if ($param_num > $param_num_max) {
7837 $get_name_url_param_arr[$param_num] = $param_value;
7845 $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]);
7847 $value = $object->getNomUrl($getnomurlparam, $getnomurlparam2);
7854 dol_syslog('Error bad setup of extrafield', LOG_WARNING);
7855 return 'Error bad setup of extrafield';
7860 } elseif ($type == 'password') {
7861 $value = preg_replace('/./i', '*', $value);
7862 } elseif ($type == 'array') {
7863 $value = implode('<br>', $value);
7864 } else { // text|html|varchar
7865 $value = dol_htmlentitiesbr($value);
7868 //print $type.'-'.$size.'-'.$value;
7880 public function clearFieldError($fieldKey)
7883 unset($this->validateFieldsErrors[$fieldKey]);
7893 public function setFieldError($fieldKey, $msg = '')
7896 if (empty($msg)) { $msg = $langs->trans("UnknowError
"); }
7898 $this->error = $this->validateFieldsErrors[$fieldKey] = $msg;
7907 public function getFieldError($fieldKey)
7909 if (!empty($this->validateFieldsErrors[$fieldKey])) {
7910 return $this->validateFieldsErrors[$fieldKey];
7923 public function validateField($val, $fieldKey, $fieldValue)
7927 if (!class_exists('Validate')) { require_once DOL_DOCUMENT_ROOT . '/core/class/validate.class.php'; }
7929 $this->clearFieldError($fieldKey);
7931 if (!isset($val[$fieldKey])) {
7932 $this->setFieldError($fieldKey, $langs->trans('FieldNotFoundInObject'));
7937 $param['options'] = array();
7938 $type = $val[$fieldKey]['type'];
7941 if (isset($val[$fieldKey]['notnull']) && $val[$fieldKey]['notnull'] === 1) {
7942 // 'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
7953 // Convert var to be able to share same code than showOutputField of extrafields
7954 if (preg_match('/varchar\((\d+)\)/', $type, $reg)) {
7955 $type = 'varchar'; // convert varchar(xx) int varchar
7957 } elseif (preg_match('/varchar/', $type)) {
7958 $type = 'varchar'; // convert varchar(xx) int varchar
7961 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
7965 if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) {
7969 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
7970 $param['options'] = $val['arrayofkeyval'];
7973 if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) {
7975 $param['options'] = array($reg[1].':'.$reg[2]=>$reg[1].':'.$reg[2]);
7976 } elseif (preg_match('/^sellist:(.*):(.*):(.*):(.*)/i', $val['type'], $reg)) {
7977 $param['options'] = array($reg[1].':'.$reg[2].':'.$reg[3].':'.$reg[4] => 'N');
7979 } elseif (preg_match('/^sellist:(.*):(.*):(.*)/i', $val['type'], $reg)) {
7980 $param['options'] = array($reg[1].':'.$reg[2].':'.$reg[3] => 'N');
7982 } elseif (preg_match('/^sellist:(.*):(.*)/i', $val['type'], $reg)) {
7983 $param['options'] = array($reg[1].':'.$reg[2] => 'N');
7991 // Use Validate class to allow external Modules to use data validation part instead of concentrate all test here (factoring) or just for reuse
7992 $validate = new Validate($this->db, $langs);
7995 // little trick : to perform tests with good performances sort tests by quick to low
8001 // Required test and empty value
8002 if ($required && !$validate->isNotEmptyString($fieldValue)) {
8003 $this->setFieldError($fieldKey, $validate->error);
8005 } elseif (!$required && !$validate->isNotEmptyString($fieldValue)) {
8006 // if no value sent and the field is not mandatory, no need to perform tests
8011 if (!empty($maxSize) && !$validate->isMaxLength($fieldValue, $maxSize)) {
8012 $this->setFieldError($fieldKey, $validate->error);
8017 if (!empty($minSize) && !$validate->isMinLength($fieldValue, $minSize)) {
8018 $this->setFieldError($fieldKey, $validate->error);
8026 if (in_array($type, array('date', 'datetime', 'timestamp'))) {
8027 if (!$validate->isTimestamp($fieldValue)) {
8028 $this->setFieldError($fieldKey, $validate->error);
8030 } else { return true; }
8031 } elseif ($type == 'duration') {
8032 if (!$validate->isDuration($fieldValue)) {
8033 $this->setFieldError($fieldKey, $validate->error);
8035 } else { return true; }
8036 } elseif (in_array($type, array('double', 'real', 'price'))) {
8038 if (!$validate->isNumeric($fieldValue)) {
8039 $this->setFieldError($fieldKey, $validate->error);
8041 } else { return true; }
8042 } elseif ($type == 'boolean') {
8043 if (!$validate->isBool($fieldValue)) {
8044 $this->setFieldError($fieldKey, $validate->error);
8046 } else { return true; }
8047 } elseif ($type == 'mail') {
8048 if (!$validate->isEmail($fieldValue)) {
8049 $this->setFieldError($fieldKey, $validate->error);
8052 } elseif ($type == 'url') {
8053 if (!$validate->isUrl($fieldValue)) {
8054 $this->setFieldError($fieldKey, $validate->error);
8056 } else { return true; }
8057 } elseif ($type == 'phone') {
8058 if (!$validate->isPhone($fieldValue)) {
8059 $this->setFieldError($fieldKey, $validate->error);
8061 } else { return true; }
8062 } elseif ($type == 'select' || $type == 'radio') {
8063 if (!isset($param['options'][$fieldValue])) {
8064 $this->error = $langs->trans('RequireValidValue');
8066 } else { return true; }
8067 } elseif ($type == 'sellist' || $type == 'chkbxlst') {
8068 $param_list = array_keys($param['options']);
8069 $InfoFieldList = explode(":
", $param_list[0]);
8070 $value_arr = explode(',', $fieldValue);
8071 $value_arr = array_map(array($this->db, 'escape'), $value_arr);
8073 $selectkey = "rowid";
8074 if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
8075 $selectkey = $InfoFieldList[2];
8078 if (!$validate->isInDb($value_arr, $InfoFieldList[0], $selectkey)) {
8079 $this->setFieldError($fieldKey, $validate->error);
8081 } else { return true; }
8082 } elseif ($type == 'link') {
8083 $param_list = array_keys($param['options']); // $param_list='ObjectName:classPath'
8084 $InfoFieldList = explode(":
", $param_list[0]);
8085 $classname = $InfoFieldList[0];
8086 $classpath = $InfoFieldList[1];
8087 if (!$validate->isFetchable($fieldValue, $classname, $classpath)) {
8088 $this->setFieldError($fieldKey, $validate->error);
8090 } else { return true; }
8093 // if no test failled all is ok
8110 public function showOptionals($extrafields, $mode = 'view', $params = null, $keysuffix = '', $keyprefix = '', $onetrtd = 0, $display_type = 'card')
8112 global $db, $conf, $langs, $action, $form, $hookmanager;
8114 if (!is_object($form)) {
8115 $form = new Form($db);
8117 if (!is_object($extrafields)) {
8118 dol_syslog('Bad parameter extrafields for showOptionals', LOG_ERR);
8119 return 'Bad parameter extrafields for showOptionals';
8121 if (!is_array($extrafields->attributes[$this->table_element])) {
8122 dol_syslog("extrafields->attributes was not loaded with extrafields->fetch_name_optionals_label(table_element);
", LOG_WARNING);
8127 $parameters = array('mode'=>$mode, 'params'=>$params, 'keysuffix'=>$keysuffix, 'keyprefix'=>$keyprefix, 'display_type'=>$display_type);
8128 $reshook = $hookmanager->executeHooks('showOptionals', $parameters, $this, $action); // Note that $action and $object may have been modified by hook
8130 if (empty($reshook)) {
8131 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) {
8133 $out .= '<!-- commonobject:showOptionals --> ';
8136 $nbofextrafieldsshown = 0;
8137 $extrafields_collapse_num = '';
8138 $e = 0; // var to manage the modulo (odd/even)
8140 foreach ($extrafields->attributes[$this->table_element]['label'] as $key => $label) {
8141 // Show only the key field in params
8142 if (is_array($params) && array_key_exists('onlykey', $params) && $key != $params['onlykey']) {
8146 // Test on 'enabled' ('enabled' is different than 'list' = 'visibility')
8148 if ($enabled && isset($extrafields->attributes[$this->table_element]['enabled'][$key])) {
8149 $enabled = dol_eval($extrafields->attributes[$this->table_element]['enabled'][$key], 1, 1, '2');
8151 if (empty($enabled)) {
8156 if ($visibility && isset($extrafields->attributes[$this->table_element]['list'][$key])) {
8157 $visibility = dol_eval($extrafields->attributes[$this->table_element]['list'][$key], 1, 1, '2');
8161 if ($perms && isset($extrafields->attributes[$this->table_element]['perms'][$key])) {
8162 $perms = dol_eval($extrafields->attributes[$this->table_element]['perms'][$key], 1, 1, '2');
8165 if (($mode == 'create') && abs($visibility) != 1 && abs($visibility) != 3) {
8166 continue; // <> -1 and <> 1 and <> 3 = not visible on forms, only on list
8167 } elseif (($mode == 'edit') && abs($visibility) != 1 && abs($visibility) != 3 && abs($visibility) != 4) {
8168 continue; // <> -1 and <> 1 and <> 3 = not visible on forms, only on list and <> 4 = not visible at the creation
8169 } elseif ($mode == 'view' && empty($visibility)) {
8172 if (empty($perms)) {
8175 // Load language if required
8176 if (!empty($extrafields->attributes[$this->table_element]['langfile'][$key])) {
8177 $langs->load($extrafields->attributes[$this->table_element]['langfile'][$key]);
8181 if (is_array($params) && count($params) > 0 && $display_type=='card') {
8182 if (array_key_exists('cols', $params)) {
8183 $colspan = $params['cols'];
8184 } elseif (array_key_exists('colspan', $params)) { // For backward compatibility. Use cols instead now.
8186 if (preg_match('/colspan="(\d+)
"/', $params['colspan'], $reg)) {
8189 $colspan = $params['colspan'];
8193 $colspan = intval($colspan);
8197 $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
8201 // We get the value of property found with GETPOST so it takes into account:
8202 // default values overwrite, restore back to list link, ... (but not 'default value in database' of field)
8203 $check = 'alphanohtml';
8204 if (in_array($extrafields->attributes[$this->table_element]['type'][$key], array('html', 'text'))) {
8205 $check = 'restricthtml';
8207 $getposttemp = GETPOST($keyprefix.'options_'.$key.$keysuffix, $check, 3); // GETPOST can get value from GET, POST or setup of default values overwrite.
8208 // GETPOST("options_
" . $key) can be 'abc' or array(0=>'abc')
8209 if (is_array($getposttemp) || $getposttemp != '' || GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix)) {
8210 if (is_array($getposttemp)) {
8211 // $getposttemp is an array but following code expects a comma separated string
8212 $value = implode(",
", $getposttemp);
8214 $value = $getposttemp;
8217 $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.
8219 //var_dump($keyprefix.' - '.$key.' - '.$keysuffix.' - '.$keyprefix.'options_'.$key.$keysuffix.' - '.$this->array_options["options_
".$key.$keysuffix].' - '.$getposttemp.' - '.$value);
8223 $nbofextrafieldsshown++;
8225 // Output value of the current field
8226 if ($extrafields->attributes[$this->table_element]['type'][$key] == 'separate') {
8227 $extrafields_collapse_num = '';
8228 $extrafield_param = $extrafields->attributes[$this->table_element]['param'][$key];
8229 if (!empty($extrafield_param) && is_array($extrafield_param)) {
8230 $extrafield_param_list = array_keys($extrafield_param['options']);
8232 if (count($extrafield_param_list) > 0) {
8233 $extrafield_collapse_display_value = intval($extrafield_param_list[0]);
8235 if ($extrafield_collapse_display_value == 1 || $extrafield_collapse_display_value == 2) {
8236 $extrafields_collapse_num = $extrafields->attributes[$this->table_element]['pos'][$key];
8241 // if colspan=0 or 1, the second column is not extended, so the separator must be on 2 columns
8242 $out .= $extrafields->showSeparator($key, $this, ($colspan ? $colspan + 1 : 2), $display_type, $mode);
8244 $class = (!empty($extrafields->attributes[$this->table_element]['hidden'][$key]) ? 'hideobject ' : '');
8246 if (is_array($params) && count($params) > 0) {
8247 if (array_key_exists('class', $params)) {
8248 $class .= $params['class'].' ';
8250 if (array_key_exists('style', $params)) {
8251 $csstyle = $params['style'];
8255 // add html5 elements
8256 $domData = ' data-element="extrafield
"';
8257 $domData .= ' data-targetelement="'.$this->element.'"';
8258 $domData .= ' data-targetid="'.$this->id.'"';
8260 $html_id = (empty($this->id) ? '' : 'extrarow-'.$this->element.'_'.$key.'_'.$this->id);
8261 if ($display_type=='card') {
8262 if (!empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && ($e % 2) == 0) {
8266 if ($action == 'selectlines') {
8271 // Convert date into timestamp format (value in memory must be a timestamp)
8272 if (in_array($extrafields->attributes[$this->table_element]['type'][$key], array('date'))) {
8273 $datenotinstring = null;
8274 if (array_key_exists('options_'.$key, $this->array_options)) {
8275 $datenotinstring = $this->array_options['options_'.$key];
8276 if (!is_numeric($this->array_options['options_'.$key])) { // For backward compatibility
8277 $datenotinstring = $this->db->jdate($datenotinstring);
8280 $datekey = $keyprefix.'options_'.$key.$keysuffix;
8281 $value = (GETPOSTISSET($datekey)) ? dol_mktime(12, 0, 0, GETPOST($datekey.'month', 'int', 3), GETPOST($datekey.'day', 'int', 3), GETPOST($datekey.'year', 'int', 3)) : $datenotinstring;
8283 if (in_array($extrafields->attributes[$this->table_element]['type'][$key], array('datetime'))) {
8284 $datenotinstring = null;
8285 if (array_key_exists('options_'.$key, $this->array_options)) {
8286 $datenotinstring = $this->array_options['options_'.$key];
8287 if (!is_numeric($this->array_options['options_'.$key])) { // For backward compatibility
8288 $datenotinstring = $this->db->jdate($datenotinstring);
8291 $timekey = $keyprefix.'options_'.$key.$keysuffix;
8292 $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;
8294 // Convert float submited string into real php numeric (value in memory must be a php numeric)
8295 if (in_array($extrafields->attributes[$this->table_element]['type'][$key], array('price', 'double'))) {
8296 if (GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix) || $value) {
8297 $value = price2num($value);
8298 } elseif (isset($this->array_options['options_'.$key])) {
8299 $value = $this->array_options['options_'.$key];
8303 // HTML, text, select, integer and varchar: take into account default value in database if in create mode
8304 if (in_array($extrafields->attributes[$this->table_element]['type'][$key], array('html', 'text', 'varchar', 'select', 'radio', 'int', 'boolean'))) {
8305 if ($action == 'create') {
8306 $value = (GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix) || $value) ? $value : $extrafields->attributes[$this->table_element]['default'][$key];
8310 $labeltoshow = $langs->trans($label);
8311 $helptoshow = $langs->trans($extrafields->attributes[$this->table_element]['help'][$key]);
8313 if ($display_type == 'card') {
8314 $out .= '<tr '.($html_id ? 'id="'.$html_id.'" ' : '').$csstyle.' class="field_options_
'.$key.' '.$class.$this->element.'_extras_
'.$key.' trextrafields_collapse
'.$extrafields_collapse_num.(!empty($this->id)?'_
'.$this->id:'').'" '.$domData.' >';
8315 if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER) && ($action == 'view' || $action == 'valid' || $action == 'editline' || $action == 'confirm_valid' || $action == 'confirm_cancel')) {
8316 $out .= '<td></td>';
8318 $out .= '<td class="'.(empty($params['tdclass
']) ? 'titlefieldcreate
' : $params['tdclass
']).' wordbreak
';
8319 } elseif ($display_type == 'line
') {
8320 $out .= '<div
'.($html_id ? 'id=
"'.$html_id.'" ' : '').$csstyle.' class=
"fieldline_options_'.$key.' '.$class.$this->element.'_extras_'.$key.' trextrafields_collapse'.$extrafields_collapse_num.(!empty($this->id)?'_'.$this->id:'').'" '.$domData.' >
';
8321 $out .= '<div style=
"display: inline-block; padding-right:4px" class=
"wordbreak';
8323 //$out .= "titlefield
";
8324 //if (GETPOST('action', 'restricthtml') == 'create') $out.='create';
8325 // BUG #11554 : For public page, use red dot for required fields, instead of bold label
8326 $tpl_context = isset($params["tpl_context
"]) ? $params["tpl_context
"] : "none
";
8327 if ($tpl_context != "public") { // Public page : red dot instead of fieldrequired characters
8328 if ($mode != 'view' && !empty($extrafields->attributes[$this->table_element]['required'][$key])) {
8329 $out .= ' fieldrequired';
8333 if ($tpl_context == "public") { // Public page : red dot instead of fieldrequired characters
8334 if (!empty($extrafields->attributes[$this->table_element]['help
'][$key])) {
8335 $out .= $form->textwithpicto($labeltoshow, $helptoshow);
8337 $out .= $labeltoshow;
8339 if ($mode != 'view
' && !empty($extrafields->attributes[$this->table_element]['required
'][$key])) {
8340 $out .= ' <span style=
"color: red">*</span>
';
8343 if (!empty($extrafields->attributes[$this->table_element]['help
'][$key])) {
8344 $out .= $form->textwithpicto($labeltoshow, $helptoshow);
8346 $out .= $labeltoshow;
8350 $out .= ($display_type == 'card
' ? '</td>
' : '</div>
');
8352 $html_id = !empty($this->id) ? $this->element.'_extras_
'.$key.'_
'.$this->id : '';
8353 if ($display_type == 'card
') {
8354 // 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
8355 $out .= '<td
'.($html_id ? 'id=
"'.$html_id.'" ' : '').' class=
"valuefieldcreate '.$this->element.'_extras_'.$key.'" '.($colspan ? ' colspan=
"'.$colspan.'"' : '').'>
';
8356 } elseif ($display_type == 'line
') {
8357 $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].'">
';
8362 $out .= $extrafields->showOutputField($key, $value, '', $this->table_element);
8365 $out .= $extrafields->showInputField($key, $value, '', $keysuffix, '', 0, $this->id, $this->table_element);
8368 $out .= $extrafields->showInputField($key, $value, '', $keysuffix, '', 0, $this->id, $this->table_element);
8372 $out .= ($display_type=='card
' ? '</td>
' : '</div>
');
8374 if (!empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && (($e % 2) == 1)) {
8375 $out .= ($display_type=='card
' ? '</tr>
' : '</div>
');
8377 $out .= ($display_type=='card
' ? '</tr>
' : '</div>
');
8384 // Add code to manage list depending on others
8385 if (!empty($conf->use_javascript_ajax)) {
8386 $out .= $this->getJSListDependancies();
8391 if (empty($nbofextrafieldsshown)) {
8397 $out .= $hookmanager->resPrint;
8406 public function getJSListDependancies($type = '_extra
')
8410 jQuery(document).ready(
function() {
8411 function showOptions
'.$type.'(child_list, parent_list, orig_select)
8413 var val = $(
"select[name=\""+parent_list+
"\"]").val();
8414 var parentVal = parent_list +
":" + val;
8415 if(typeof val ==
"string"){
8417 var options = orig_select.find(
"option[parent=\""+parentVal+
"\"]").clone();
8418 $(
"select[name=\""+child_list+
"\"] option[parent]").
remove();
8419 $(
"select[name=\""+child_list+
"\"]").append(options);
8421 var options = orig_select.find(
"option[parent]").clone();
8422 $(
"select[name=\""+child_list+
"\"] option[parent]").
remove();
8423 $(
"select[name=\""+child_list+
"\"]").append(options);
8425 }
else if(val > 0) {
8426 var options = orig_select.find(
"option[parent=\""+parentVal+
"\"]").clone();
8427 $(
"select[name=\""+child_list+
"\"] option[parent]").
remove();
8428 $(
"select[name=\""+child_list+
"\"]").append(options);
8430 var options = orig_select.find(
"option[parent]").clone();
8431 $(
"select[name=\""+child_list+
"\"] option[parent]").
remove();
8432 $(
"select[name=\""+child_list+
"\"]").append(options);
8435 function setListDependencies
'.$type.'() {
8436 jQuery(
"select option[parent]").parent().each(
function() {
8437 var orig_select = {};
8438 var child_list = $(
this).attr(
"name");
8439 orig_select[child_list] = $(
this).clone();
8440 var parent = $(
this).find(
"option[parent]:first").attr(
"parent");
8441 var infos = parent.split(
":");
8442 var parent_list = infos[0];
8445 if ($(
"#"+child_list).val() == 0 && $(
"#"+parent_list).val() == 0){
8446 $(
"#"+child_list).hide();
8448 }
else if ($(
"#"+parent_list).val() != 0){
8449 $(
"#"+parent_list).show();
8452 $(
"select[name=\""+parent_list+
"\"]").click(
function() {
8453 if ($(
this).val() != 0){
8454 $(
"#"+child_list).show()
8459 $(
"select[name=\""+parent_list+
"\"]").change(
function() {
8460 showOptions
'.$type.'(child_list, parent_list, orig_select[child_list]);
8462 $(
"#"+child_list).val(0).trigger(
"change");
8464 if ($(
this).val() == 0){
8465 $(
"#"+child_list).hide();
8471 setListDependencies
'.$type.'();
8481 public function getRights()
8485 $module = empty($this->module) ? '' : $this->module;
8486 $element = $this->element;
8488 if ($element == 'facturerec
') {
8489 $element = 'facture
';
8490 } elseif ($element == 'invoice_supplier_rec
') {
8491 return empty($user->rights->fournisseur->facture) ? null : $user->rights->fournisseur->facture;
8492 } elseif ($module && !empty($user->rights->$module->$element)) {
8493 // for modules built with ModuleBuilder
8494 return $user->rights->$module->$element;
8497 return $user->rights->$element;
8512 public static function commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors = 0)
8514 foreach ($tables as $table) {
8515 $sql = 'UPDATE
'.$db->prefix().$table.' SET fk_soc =
'.((int) $dest_id).' WHERE fk_soc =
'.((int) $origin_id);
8517 if (!$db->query($sql)) {
8518 if ($ignoreerrors) {
8519 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.
8521 //$this->errors = $db->lasterror();
8541 public static function commonReplaceProduct(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors = 0)
8543 foreach ($tables as $table) {
8544 $sql = 'UPDATE
'.MAIN_DB_PREFIX.$table.' SET fk_product =
'.((int) $dest_id).' WHERE fk_product =
'.((int) $origin_id);
8546 if (!$db->query($sql)) {
8547 if ($ignoreerrors) {
8548 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.
8550 //$this->errors = $db->lasterror();
8570 public function defineBuyPrice($unitPrice = 0.0, $discountPercent = 0.0, $fk_product = 0)
8576 if (($unitPrice > 0) && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull > 0)) {
8577 // When ForceBuyingPriceIfNull is set
8578 $buyPrice = $unitPrice * (1 - $discountPercent / 100);
8580 // Get cost price for margin calculation
8581 if (!empty($fk_product) && $fk_product > 0) {
8582 if (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == 'costprice
') {
8583 require_once DOL_DOCUMENT_ROOT.'/product/
class/product.class.php
';
8584 $product = new Product($this->db);
8585 $result = $product->fetch($fk_product);
8587 $this->errors[] = 'ErrorProductIdDoesNotExists
';
8590 if ($product->cost_price > 0) {
8591 $buyPrice = $product->cost_price;
8592 } elseif ($product->pmp > 0) {
8593 $buyPrice = $product->pmp;
8595 } elseif (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == 'pmp
') {
8596 require_once DOL_DOCUMENT_ROOT.'/product/
class/product.class.php
';
8597 $product = new Product($this->db);
8598 $result = $product->fetch($fk_product);
8600 $this->errors[] = 'ErrorProductIdDoesNotExists
';
8603 if ($product->pmp > 0) {
8604 $buyPrice = $product->pmp;
8608 if (empty($buyPrice) && isset($conf->global->MARGIN_TYPE) && in_array($conf->global->MARGIN_TYPE, array('1
', 'pmp
', 'costprice
'))) {
8609 require_once DOL_DOCUMENT_ROOT.'/fourn/
class/fournisseur.product.class.php
';
8610 $productFournisseur = new ProductFournisseur($this->db);
8611 if (($result = $productFournisseur->find_min_price_product_fournisseur($fk_product)) > 0) {
8612 $buyPrice = $productFournisseur->fourn_unitprice;
8613 } elseif ($result < 0) {
8614 $this->errors[] = $productFournisseur->error;
8623 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
8641 public function show_photos($modulepart, $sdir, $size = 0, $nbmax = 0, $nbbyrow = 5, $showfilename = 0, $showaction = 0, $maxHeight = 120, $maxWidth = 160, $nolink = 0, $notitle = 0, $usesharelink = 0)
8644 global $conf, $user, $langs;
8646 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php
';
8647 include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php
';
8649 $sortfield = 'position_name
';
8655 $dir .= get_exdir(0, 0, 0, 0, $this, $modulepart);
8656 $pdir .= get_exdir(0, 0, 0, 0, $this, $modulepart);
8658 // For backward compatibility
8659 if ($modulepart == 'product
') {
8660 if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO
')) {
8661 $dir = $sdir.'/
'.get_exdir($this->id, 2, 0, 0, $this, $modulepart).$this->id."/photos/";
8662 $pdir = '/
'.get_exdir($this->id, 2, 0, 0, $this, $modulepart).$this->id."/photos/";
8666 // Defined relative dir to DOL_DATA_ROOT
8669 $relativedir = preg_replace('/^
'.preg_quote(DOL_DATA_ROOT, '/
').'/
', '', $dir);
8670 $relativedir = preg_replace('/^[\\/]/
', '', $relativedir);
8671 $relativedir = preg_replace('/[\\/]$/
', '', $relativedir);
8674 $dirthumb = $dir.'thumbs/
';
8675 $pdirthumb = $pdir.'thumbs/
';
8677 $return = '<!-- Photo -->
'."\n";
8680 $filearray = dol_dir_list($dir, "files", 0, '', '(\.meta|_preview.*\.png)$
', $sortfield, (strtolower($sortorder) == 'desc
' ?SORT_DESC:SORT_ASC), 1);
8682 /*if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO
')) // For backward compatiblity, we scan also old dirs
8684 $filearrayold=dol_dir_list($dirold,"files",0,'','(\.meta|_preview.*\.png)$
',$sortfield,(strtolower($sortorder)=='desc
'?SORT_DESC:SORT_ASC),1);
8685 $filearray=array_merge($filearray, $filearrayold);
8688 completeFileArrayWithDatabaseInfo($filearray, $relativedir);
8690 if (count($filearray)) {
8691 if ($sortfield && $sortorder) {
8692 $filearray = dol_sort_array($filearray, $sortfield, $sortorder);
8695 foreach ($filearray as $key => $val) {
8697 $file = $val['name'];
8699 //if (dol_is_file($dir.$file) && image_format_supported($file) >= 0)
8700 if (image_format_supported($file) >= 0) {
8703 $viewfilename = $file;
8705 if ($size == 1 || $size == 'small
') { // Format vignette
8706 // Find name of thumb file
8707 $photo_vignette = basename(getImageFileNameForSize($dir.$file, '_small
'));
8708 if (!dol_is_file($dirthumb.$photo_vignette)) {
8709 // The thumb does not exists, so we will use the original file
8712 $photo_vignette = basename($file);
8715 // Get filesize of original file
8716 $imgarray = dol_getImageSize($dir.$photo);
8719 if ($nbphoto == 1) {
8720 $return .= '<table
class=
"valigntop center centpercent" style=
"border: 0; padding: 2px; border-spacing: 2px; border-collapse: separate;">
';
8723 if ($nbphoto % $nbbyrow == 1) {
8724 $return .= '<tr
class=
"center valignmiddle" style=
"border: 1px">
';
8726 $return .= '<td style=
"width: '.ceil(100 / $nbbyrow).'%" class=
"photo">
';
8727 } elseif ($nbbyrow < 0) {
8728 $return .= '<div
class=
"inline-block">
';
8733 $relativefile = preg_replace('/^\
8734 if (empty($nolink)) {
8737 $return .=
'<a href="'.$urladvanced.
'">';
8739 $return .=
'<a href="'.DOL_URL_ROOT.
'/viewimage.php?modulepart='.$modulepart.
'&entity='.$this->entity.
'&file='.urlencode($pdir.$photo).
'" class="aphoto" target="_blank" rel="noopener noreferrer">';
8745 $alt = $langs->transnoentitiesnoconv(
'File').
': '.$relativefile;
8746 $alt .=
' - '.$langs->transnoentitiesnoconv(
'Size').
': '.$imgarray[
'width'].
'x'.$imgarray[
'height'];
8751 $addphotorefcss = 1;
8753 if ($usesharelink) {
8754 if ($val[
'share']) {
8755 if (empty($maxHeight) || ($photo_vignette && $imgarray[
'height'] > $maxHeight)) {
8756 $return .=
'<!-- Show original file (thumb not yet available with shared links) -->';
8757 $return .=
'<img class="photo photowithmargin'.($addphotorefcss ?
' photoref' :
'').
'"'.($maxHeight ?
' height="'.$maxHeight.
'"':
'').
' src="'.DOL_URL_ROOT.
'/viewimage.php?hashp='.urlencode($val[
'share']).
'" title="'.
dol_escape_htmltag($alt).
'">';
8759 $return .=
'<!-- Show original file -->';
8760 $return .=
'<img class="photo photowithmargin'.($addphotorefcss ?
' photoref' :
'').
'" height="'.$maxHeight.
'" src="'.DOL_URL_ROOT.
'/viewimage.php?hashp='.urlencode($val[
'share']).
'" title="'.
dol_escape_htmltag($alt).
'">';
8763 $return .=
'<!-- Show nophoto file (because file is not shared) -->';
8764 $return .=
'<img class="photo photowithmargin'.($addphotorefcss ?
' photoref' :
'').
'" height="'.$maxHeight.
'" src="'.DOL_URL_ROOT.
'/public/theme/common/nophoto.png" title="'.
dol_escape_htmltag($alt).
'">';
8767 if (empty($maxHeight) || ($photo_vignette && $imgarray[
'height'] > $maxHeight)) {
8768 $return .=
'<!-- Show thumb -->';
8769 $return .=
'<img class="photo photowithmargin'.($addphotorefcss ?
' photoref' :
'').
' maxwidth150onsmartphone maxwidth200"'.($maxHeight ?
' height="'.$maxHeight.
'"':
'').
' src="'.DOL_URL_ROOT.
'/viewimage.php?modulepart='.$modulepart.
'&entity='.$this->entity.
'&file='.urlencode($pdirthumb.$photo_vignette).
'" title="'.
dol_escape_htmltag($alt).
'">';
8771 $return .=
'<!-- Show original file -->';
8772 $return .=
'<img class="photo photowithmargin'.($addphotorefcss ?
' photoref' :
'').
'" height="'.$maxHeight.
'" src="'.DOL_URL_ROOT.
'/viewimage.php?modulepart='.$modulepart.
'&entity='.$this->entity.
'&file='.urlencode($pdir.$photo).
'" title="'.
dol_escape_htmltag($alt).
'">';
8776 if (empty($nolink)) {
8781 if ($showfilename) {
8782 $return .=
'<br>'.$viewfilename;
8787 if ($photo_vignette && (
image_format_supported($photo) > 0) && ($this->imgWidth > $maxWidth || $this->imgHeight > $maxHeight)) {
8788 $return .=
'<a href="'.$_SERVER[
"PHP_SELF"].
'?id='.$this->
id.
'&action=addthumb&token='.
newToken().
'&file='.urlencode($pdir.$viewfilename).
'">'.
img_picto($langs->trans(
'GenerateThumb'),
'refresh').
' </a>';
8791 if ($modulepart ==
'product' && ($user->rights->produit->creer || $user->rights->service->creer)) {
8793 $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> ';
8796 $return .=
'<a href="'.$_SERVER[
"PHP_SELF"].
'?id='.$this->
id.
'&action=delete&token='.
newToken().
'&file='.urlencode($pdir.$viewfilename).
'">';
8804 if (($nbphoto % $nbbyrow) == 0) {
8807 } elseif ($nbbyrow < 0) {
8808 $return .=
'</div>';
8813 $return .=
'<img class="photo photowithmargin" src="'.DOL_URL_ROOT.
'/viewimage.php?modulepart='.$modulepart.
'&entity='.$this->entity.
'&file='.urlencode($pdir.$photo).
'">';
8815 if ($showfilename) {
8816 $return .=
'<br>'.$viewfilename;
8820 if ($modulepart ==
'product' && ($user->rights->produit->creer || $user->rights->service->creer)) {
8822 $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> ';
8825 $return .=
'<a href="'.$_SERVER[
"PHP_SELF"].
'?id='.$this->
id.
'&action=delete&token='.
newToken().
'&file='.urlencode($pdir.$viewfilename).
'">';
8832 if ($nbmax && $nbphoto >= $nbmax) {
8838 if ($size == 1 || $size ==
'small') {
8841 while ($nbphoto % $nbbyrow) {
8842 $return .=
'<td style="width: '.ceil(100 / $nbbyrow).
'%"> </td>';
8847 $return .=
'</table>';
8853 $this->nbphoto = $nbphoto;
8867 if (is_array($info)) {
8868 if (isset($info[
'type']) && $info[
'type'] ==
'array') {
8885 if (isset($info[
'type']) && ($info[
'type'] ==
'date' || $info[
'type'] ==
'datetime' || $info[
'type'] ==
'timestamp')) {
8899 if (is_array($info)) {
8900 if (isset($info[
'type']) && ($info[
'type'] ==
'duration')) {
8918 if (is_array($info)) {
8919 if (isset($info[
'type']) && (preg_match(
'/(^int|int$)/i', $info[
'type']))) {
8937 if (is_array($info)) {
8938 if (isset($info[
'type']) && (preg_match(
'/^(double|real|price)/i', $info[
'type']))) {
8955 if (is_array($info)) {
8956 if (isset($info[
'type']) && $info[
'type'] ==
'text') {
8973 if (is_array($info)) {
8974 if (isset($info[
'notnull']) && $info[
'notnull'] !=
'1') {
8991 if (is_array($info)) {
8992 if (isset($info[
'notnull']) && $info[
'notnull'] ==
'-1') {
9009 if (is_array($info)) {
9010 if (isset($info[
'index']) && $info[
'index'] ==
true) {
9032 $queryarray = array();
9033 foreach ($this->fields as $field => $info) {
9035 if ($this->isDate($info)) {
9036 if (empty($this->{$field})) {
9037 $queryarray[$field] =
null;
9039 $queryarray[$field] = $this->
db->idate($this->{$field});
9041 } elseif ($this->isDuration($info)) {
9043 if ((isset($this->{$field}) && $this->{$field} !=
'') || !empty($info[
'notnull'])) {
9044 if (!isset($this->{$field})) {
9045 if (!empty($info[
'default'])) {
9046 $queryarray[$field] = $info[
'default'];
9048 $queryarray[$field] = 0;
9051 $queryarray[$field] = (int) $this->{$field};
9054 $queryarray[$field] =
null;
9056 } elseif ($this->isInt($info) || $this->isFloat($info)) {
9057 if ($field ==
'entity' && is_null($this->{$field})) {
9058 $queryarray[$field] = ((int) $conf->entity);
9061 if ((isset($this->{$field}) && $this->{$field} !=
'') || !empty($info[
'notnull'])) {
9062 if (!isset($this->{$field})) {
9063 $queryarray[$field] = 0;
9064 } elseif ($this->isInt($info)) {
9065 $queryarray[$field] = (int) $this->{$field};
9066 } elseif ($this->isFloat($info)) {
9067 $queryarray[$field] = (double) $this->{$field};
9070 $queryarray[$field] =
null;
9076 $queryarray[$field] = $this->{$field};
9079 if ($info[
'type'] ==
'timestamp' && empty($queryarray[$field])) {
9080 unset($queryarray[$field]);
9082 if (!empty($info[
'notnull']) && $info[
'notnull'] == -1 && empty($queryarray[$field])) {
9083 $queryarray[$field] =
null;
9100 foreach ($this->fields as $field => $info) {
9101 if ($this->isDate($info)) {
9102 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') {
9103 $this->{$field} =
'';
9105 $this->{$field} = $db->jdate($obj->{$field});
9107 } elseif ($this->isInt($info)) {
9108 if ($field ==
'rowid') {
9109 $this->
id = (int) $obj->{$field};
9111 if ($this->isForcedToNullIfZero($info)) {
9112 if (empty($obj->{$field})) {
9113 $this->{$field} =
null;
9115 $this->{$field} = (double) $obj->{$field};
9118 if (isset($obj->{$field}) && (!is_null($obj->{$field}) || (isset($info[
'notnull']) && $info[
'notnull'] == 1))) {
9119 $this->{$field} = (int) $obj->{$field};
9121 $this->{$field} =
null;
9125 } elseif ($this->isFloat($info)) {
9126 if ($this->isForcedToNullIfZero($info)) {
9127 if (empty($obj->{$field})) {
9128 $this->{$field} =
null;
9130 $this->{$field} = (double) $obj->{$field};
9133 if (isset($obj->{$field}) && (!is_null($obj->{$field}) || (isset($info[
'notnull']) && $info[
'notnull'] == 1))) {
9134 $this->{$field} = (double) $obj->{$field};
9136 $this->{$field} =
null;
9140 $this->{$field} = isset($obj->{$field}) ? $obj->{$field} :
null;
9145 if (!isset($this->fields[
'ref']) && isset($this->
id)) {
9146 $this->
ref = $this->id;
9158 $keys = array_keys($this->fields);
9159 if (!empty($alias)) {
9160 $keys_with_alias = array();
9161 foreach ($keys as $fieldname) {
9162 $keys_with_alias[] = $alias .
'.' . $fieldname;
9164 return implode(
',', $keys_with_alias);
9166 return implode(
',', $keys);
9177 protected function quote($value, $fieldsentry)
9179 if (is_null($value)) {
9181 } elseif (preg_match(
'/^(int|double|real|price)/i', $fieldsentry[
'type'])) {
9183 } elseif (preg_match(
'/int$/i', $fieldsentry[
'type'])) {
9184 return (
int) $value;
9185 } elseif ($fieldsentry[
'type'] ==
'boolean') {
9192 return "'".$this->db->escape($value).
"'";
9207 dol_syslog(get_class($this).
"::createCommon create", LOG_DEBUG);
9213 $fieldvalues = $this->setSaveQuery();
9215 if (array_key_exists(
'date_creation', $fieldvalues) && empty($fieldvalues[
'date_creation'])) {
9216 $fieldvalues[
'date_creation'] = $this->
db->idate($now);
9218 if (array_key_exists(
'fk_user_creat', $fieldvalues) && !($fieldvalues[
'fk_user_creat'] > 0)) {
9219 $fieldvalues[
'fk_user_creat'] = $user->id;
9220 $this->fk_user_creat = $user->id;
9222 if (array_key_exists(
'user_modification_id', $fieldvalues) && !($fieldvalues[
'user_modification_id'] > 0)) {
9223 $fieldvalues[
'user_modification_id'] = $user->id;
9224 $this->user_modification_id = $user->id;
9226 unset($fieldvalues[
'rowid']);
9227 if (array_key_exists(
'ref', $fieldvalues)) {
9233 foreach ($fieldvalues as $k => $v) {
9235 $value = $this->fields[$k];
9236 $values[$k] = $this->quote($v, $value);
9240 foreach ($keys as $key) {
9242 if (preg_match(
'/^integer:/i', $this->fields[$key][
'type']) && $values[$key] ==
'-1') {
9245 if (!empty($this->fields[$key][
'foreignkey']) && $values[$key] ==
'-1') {
9249 if (isset($this->fields[$key][
'notnull']) && $this->fields[$key][
'notnull'] == 1 && (!isset($values[$key]) || $values[$key] ===
'NULL') && is_null($this->fields[$key][
'default'])) {
9251 $langs->load(
"errors");
9252 dol_syslog(
"Mandatory field '".$key.
"' is empty and required into ->fields definition of class");
9253 $this->errors[] = $langs->trans(
"ErrorFieldRequired", $this->fields[$key][
'label']);
9257 if (isset($this->fields[$key][
'notnull']) && $this->fields[$key][
'notnull'] == 1 && (!isset($values[$key]) || $values[$key] ===
'NULL') && !is_null($this->fields[$key][
'default'])) {
9258 $values[$key] = $this->quote($this->fields[$key][
'default'], $this->fields[$key]);
9262 if (preg_match(
'/^integer:/i', $this->fields[$key][
'type']) && empty($values[$key])) {
9263 if (isset($this->fields[$key][
'default'])) {
9264 $values[$key] = ((int) $this->fields[$key][
'default']);
9266 $values[$key] =
'null';
9269 if (!empty($this->fields[$key][
'foreignkey']) && empty($values[$key])) {
9270 $values[$key] =
'null';
9281 $sql =
"INSERT INTO ".$this->db->prefix().$this->table_element;
9282 $sql .=
" (".implode(
", ", $keys).
')';
9283 $sql .=
" VALUES (".implode(
", ", $values).
")";
9285 $res = $this->
db->query($sql);
9288 if ($this->
db->lasterrno() ==
'DB_ERROR_RECORD_ALREADY_EXISTS') {
9289 $this->errors[] =
"ErrorRefAlreadyExists";
9291 $this->errors[] = $this->
db->lasterror();
9297 $this->
id = $this->
db->last_insert_id($this->
db->prefix().$this->table_element);
9302 if (key_exists(
'ref', $this->fields) && $this->fields[
'ref'][
'notnull'] > 0 && key_exists(
'default', $this->fields[
'ref']) && $this->fields[
'ref'][
'default'] ==
'(PROV)') {
9303 $sql =
"UPDATE ".$this->db->prefix().$this->table_element.
" SET ref = '(PROV".((int) $this->
id).
")' WHERE (ref = '(PROV)' OR ref = '') AND rowid = ".((int) $this->
id);
9304 $resqlupdate = $this->
db->query($sql);
9306 if ($resqlupdate ===
false) {
9308 $this->errors[] = $this->
db->lasterror();
9310 $this->
ref =
'(PROV'.$this->id.
')';
9317 $result = $this->insertExtraFields();
9324 if (!empty($this->table_element_line) && !empty($this->fk_element)) {
9325 $num = (is_array($this->lines) ? count($this->lines) : 0);
9326 for ($i = 0; $i < $num; $i++) {
9327 $line = $this->lines[$i];
9329 $keyforparent = $this->fk_element;
9330 $line->$keyforparent = $this->id;
9334 if (!is_object($line)) {
9335 $line = (object) $line;
9339 if (method_exists($line,
'insert')) {
9340 $result = $line->insert($user, 1);
9341 } elseif (method_exists($line,
'create')) {
9342 $result = $line->create($user, 1);
9345 $this->error = $line->error;
9346 $this->
db->rollback();
9353 if (!$error && !$notrigger) {
9355 $result = $this->call_trigger(strtoupper(get_class($this)).
'_CREATE', $user);
9364 $this->
db->rollback();
9367 $this->
db->commit();
9383 if (empty($id) && empty($ref) && empty($morewhere)) {
9387 $fieldlist = $this->getFieldList(
't');
9388 if (empty($fieldlist)) {
9392 $sql =
"SELECT ".$fieldlist;
9393 $sql .=
" FROM ".$this->db->prefix().$this->table_element.
' as t';
9396 $sql .=
' WHERE t.rowid = '.((int) $id);
9397 } elseif (!empty($ref)) {
9398 $sql .=
" WHERE t.ref = '".$this->db->escape($ref).
"'";
9400 $sql .=
' WHERE 1 = 1';
9402 if (empty($id) && isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
9403 $sql .=
' AND t.entity IN ('.getEntity($this->element).
')';
9410 $res = $this->
db->query($sql);
9412 $obj = $this->
db->fetch_object($res);
9414 $this->setVarsFromFetchObj($obj);
9418 $this->fetch_optionals();
9425 $this->error = $this->
db->lasterror();
9426 $this->errors[] = $this->error;
9439 $objectlineclassname = get_class($this).
'Line';
9440 if (!class_exists($objectlineclassname)) {
9441 $this->error =
'Error, class '.$objectlineclassname.
' not found during call of fetchLinesCommon';
9445 $objectline =
new $objectlineclassname($this->
db);
9447 $sql =
"SELECT ".$objectline->getFieldList(
'l');
9448 $sql .=
" FROM ".$this->db->prefix().$objectline->table_element.
" as l";
9449 $sql .=
" WHERE l.fk_".$this->db->escape($this->element).
" = ".((int) $this->
id);
9453 if (isset($objectline->fields[
'position'])) {
9454 $sql .= $this->
db->order(
'position',
'ASC');
9459 $num_rows = $this->
db->num_rows(
$resql);
9461 while ($i < $num_rows) {
9462 $obj = $this->
db->fetch_object(
$resql);
9464 $newline =
new $objectlineclassname($this->
db);
9465 $newline->setVarsFromFetchObj($obj);
9467 $this->lines[] = $newline;
9474 $this->error = $this->
db->lasterror();
9475 $this->errors[] = $this->error;
9489 global $conf, $langs;
9490 dol_syslog(get_class($this).
"::updateCommon update", LOG_DEBUG);
9501 $fieldvalues = $this->setSaveQuery();
9503 if (array_key_exists(
'date_modification', $fieldvalues) && empty($fieldvalues[
'date_modification'])) {
9504 $fieldvalues[
'date_modification'] = $this->
db->idate($now);
9506 if (array_key_exists(
'fk_user_modif', $fieldvalues) && !($fieldvalues[
'fk_user_modif'] > 0)) {
9507 $fieldvalues[
'fk_user_modif'] = $user->id;
9509 unset($fieldvalues[
'rowid']);
9510 if (array_key_exists(
'ref', $fieldvalues)) {
9518 foreach ($fieldvalues as $k => $v) {
9520 $value = $this->fields[$k];
9521 $values[$k] = $this->quote($v, $value);
9522 $tmp[] = $k.
'='.$this->quote($v, $this->fields[$k]);
9526 foreach ($keys as $key) {
9527 if (preg_match(
'/^integer:/i', $this->fields[$key][
'type']) && $values[$key] ==
'-1') {
9530 if (!empty($this->fields[$key][
'foreignkey']) && $values[$key] ==
'-1') {
9543 $sql =
'UPDATE '.$this->db->prefix().$this->table_element.
' SET '.implode(
', ', $tmp).
' WHERE rowid='.((int) $this->
id);
9548 $res = $this->
db->query($sql);
9551 $this->errors[] = $this->
db->lasterror();
9557 $result = $this->insertExtraFields();
9564 if (!$error && !$notrigger) {
9566 $result = $this->call_trigger(strtoupper(get_class($this)).
'_MODIFY', $user);
9575 $this->
db->rollback();
9578 $this->
db->commit();
9593 dol_syslog(get_class($this).
"::deleteCommon delete", LOG_DEBUG);
9599 if ($forcechilddeletion) {
9600 foreach ($this->childtables as $table) {
9601 $sql =
"DELETE FROM ".$this->db->prefix().$table.
" WHERE ".$this->fk_element.
" = ".((int) $this->
id);
9604 $this->error = $this->
db->lasterror();
9605 $this->errors[] = $this->error;
9606 $this->
db->rollback();
9610 } elseif (!empty($this->fk_element) && !empty($this->childtables)) {
9611 $objectisused = $this->isObjectUsed($this->
id);
9612 if (!empty($objectisused)) {
9613 dol_syslog(get_class($this).
"::deleteCommon Can't delete record as it has some child", LOG_WARNING);
9614 $this->error =
'ErrorRecordHasChildren';
9615 $this->errors[] = $this->error;
9616 $this->
db->rollback();
9622 if (is_array($this->childtablesoncascade) && !empty($this->childtablesoncascade)) {
9623 foreach ($this->childtablesoncascade as $table) {
9624 $deleteFromObject = explode(
':', $table);
9625 if (count($deleteFromObject) >= 2) {
9626 $className = str_replace(
'@',
'', $deleteFromObject[0]);
9627 $filePath = $deleteFromObject[1];
9628 $columnName = $deleteFromObject[2];
9629 $TMoreSQL = array();
9630 $more_sql = $deleteFromObject[3];
9631 if (!empty($more_sql)) {
9632 $TMoreSQL[
'customsql'] = $more_sql;
9635 $childObject =
new $className($this->
db);
9636 if (method_exists($childObject,
'deleteByParentField')) {
9637 $result = $childObject->deleteByParentField($this->
id, $columnName, $TMoreSQL);
9640 $this->errors[] = $childObject->error;
9645 $this->errors[] =
"You defined a cascade delete on an object $childObject but there is no method deleteByParentField for it";
9650 $this->errors[] =
'Cannot include child class file '.$filePath;
9655 $sql =
"DELETE FROM ".$this->db->prefix().$table.
" WHERE ".$this->fk_element.
" = ".((int) $this->
id);
9660 $this->error = $this->
db->lasterror();
9661 $this->errors[] = $this->error;
9671 $result = $this->call_trigger(strtoupper(get_class($this)).
'_DELETE', $user);
9681 $res = $this->deleteEcmFiles(1);
9688 $res = $this->deleteObjectLinked();
9693 if (!$error && !empty($this->isextrafieldmanaged)) {
9694 $result = $this->deleteExtraFields();
9701 $sql =
'DELETE FROM '.$this->db->prefix().$this->table_element.
' WHERE rowid='.((int) $this->
id);
9706 $this->errors[] = $this->
db->lasterror();
9712 $this->
db->rollback();
9715 $this->
db->commit();
9737 if (!empty($parentId) && !empty($parentField)) {
9740 $sql =
"SELECT rowid FROM ".$this->db->prefix().$this->table_element;
9741 $sql .=
" WHERE ".$parentField.
" = ".(int) $parentId;
9744 $sqlwhere = array();
9745 if (count($filter) > 0) {
9746 foreach ($filter as $key => $value) {
9747 if ($key ==
'customsql') {
9748 $sqlwhere[] = $value;
9749 } elseif (strpos($value,
'%') ===
false) {
9750 $sqlwhere[] = $key.
" IN (".$this->
db->sanitize($this->
db->escape($value)).
")";
9752 $sqlwhere[] = $key.
" LIKE '%".$this->
db->escape($value).
"%'";
9756 if (count($sqlwhere) > 0) {
9757 $sql .=
" AND (".implode(
" ".$filtermode.
" ", $sqlwhere).
")";
9762 $this->errors[] = $this->
db->lasterror();
9765 while ($obj = $this->
db->fetch_object(
$resql)) {
9766 $result = $this->fetch($obj->rowid);
9769 $this->errors[] = $this->error;
9771 if (get_class($this) ==
'Contact') {
9772 $result = $this->
delete();
9774 $result = $this->
delete($user);
9778 $this->errors[] = $this->error;
9786 if (empty($error)) {
9787 $this->
db->commit();
9790 $this->error = implode(
', ', $this->errors);
9791 $this->
db->rollback();
9813 $tmpforobjectclass = get_class($this);
9814 $tmpforobjectlineclass = ucfirst($tmpforobjectclass).
'Line';
9819 $result = $this->call_trigger(
'LINE'.strtoupper($tmpforobjectclass).
'_DELETE', $user);
9825 if (empty($error)) {
9826 $sql =
"DELETE FROM ".$this->db->prefix().$this->table_element_line;
9827 $sql .=
" WHERE rowid = ".((int) $idline);
9831 $this->error =
"Error ".$this->db->lasterror();
9836 if (empty($error)) {
9838 $tmpobjectline =
new $tmpforobjectlineclass($this->
db);
9839 if (!isset($tmpobjectline->isextrafieldmanaged) || !empty($tmpobjectline->isextrafieldmanaged)) {
9840 $tmpobjectline->id = $idline;
9841 $result = $tmpobjectline->deleteExtraFields();
9844 $this->error =
"Error ".get_class($this).
"::deleteLineCommon deleteExtraFields error -4 ".$tmpobjectline->error;
9849 if (empty($error)) {
9850 $this->
db->commit();
9853 dol_syslog(get_class($this).
"::deleteLineCommon ERROR:".$this->error, LOG_ERR);
9854 $this->
db->rollback();
9875 $statusfield =
'status';
9876 if ($this->element ==
'don' || $this->element ==
'donation') {
9877 $statusfield =
'fk_statut';
9880 $sql =
"UPDATE ".$this->db->prefix().$this->table_element;
9881 $sql .=
" SET ".$statusfield.
" = ".((int) $status);
9882 $sql .=
" WHERE rowid = ".((int) $this->
id);
9884 if ($this->
db->query($sql)) {
9886 $this->oldcopy = clone $this;
9889 if (!$error && !$notrigger) {
9891 $result = $this->call_trigger($triggercode, $user);
9898 $this->status = $status;
9899 $this->
db->commit();
9902 $this->
db->rollback();
9906 $this->error = $this->
db->error();
9907 $this->
db->rollback();
9924 $this->specimen = 1;
9926 'label' =>
'This is label',
9927 'ref' =>
'ABCD1234',
9928 'description' =>
'This is a description',
9930 'note_public' =>
'Public note',
9931 'note_private' =>
'Private note',
9932 'date_creation' => (
dol_now() - 3600 * 48),
9933 'date_modification' => (
dol_now() - 3600 * 24),
9934 'fk_user_creat' => $user->id,
9935 'fk_user_modif' => $user->id,
9938 foreach ($fields as $key => $value) {
9939 if (array_key_exists($key, $this->fields)) {
9940 $this->{$key} = $value;
9945 if (property_exists($this,
'fields')) {
9946 foreach ($this->fields as $key => $value) {
9948 if (array_key_exists($key, $fields)) {
9952 if (!empty($value[
'default'])) {
9953 $this->$key = $value[
'default'];
9970 require_once DOL_DOCUMENT_ROOT.
'/core/class/comment.class.php';
9973 $result = $comment->fetchAllFor($this->element, $this->
id);
9975 $this->errors = array_merge($this->errors, $comment->errors);
9978 $this->comments = $comment->comments;
9980 return count($this->comments);
9990 return count($this->comments);
10001 if (!is_array($parameters)) {
10004 foreach ($parameters as $parameter) {
10005 if (isset($this->$parameter)) {
10006 $this->$parameter = trim($this->$parameter);
10025 require_once DOL_DOCUMENT_ROOT.
'/categories/class/categorie.class.php';
10029 $existing = $c->containing($this->
id, $type_categ,
'id');
10049 if (!is_array($categories)) {
10050 $categories = array($categories);
10053 dol_syslog(get_class($this).
"::setCategoriesCommon Oject Id:".$this->
id.
' type_categ:'.$type_categ.
' nb tag add:'.count($categories), LOG_DEBUG);
10055 require_once DOL_DOCUMENT_ROOT.
'/categories/class/categorie.class.php';
10057 if (empty($type_categ)) {
10058 dol_syslog(__METHOD__.
': Type '.$type_categ.
'is an unknown category type. Done nothing.', LOG_ERR);
10064 $existing = $c->containing($this->
id, $type_categ,
'id');
10065 if ($remove_existing) {
10067 if (is_array($existing)) {
10068 $to_del = array_diff($existing, $categories);
10069 $to_add = array_diff($categories, $existing);
10072 $to_add = $categories;
10076 $to_add = array_diff($categories, $existing);
10083 foreach ($to_del as $del) {
10084 if ($c->fetch($del) > 0) {
10085 $result=$c->del_type($this, $type_categ);
10088 $this->error = $c->error;
10089 $this->errors = $c->errors;
10096 foreach ($to_add as $add) {
10097 if ($c->fetch($add) > 0) {
10098 $result = $c->add_type($this, $type_categ);
10101 $this->error = $c->error;
10102 $this->errors = $c->errors;
10110 return $error ? (-1 * $error) : $ok;
10123 $this->
db->begin();
10125 if (empty($type)) {
10126 $type = $this->table_element;
10129 require_once DOL_DOCUMENT_ROOT.
'/categories/class/categorie.class.php';
10132 $sql =
"INSERT INTO ".$this->db->prefix().
"categorie_".(empty($categorystatic->MAP_CAT_TABLE[$type]) ? $type : $categorystatic->MAP_CAT_TABLE[$type]).
" (fk_categorie, fk_product)";
10133 $sql .=
" SELECT fk_categorie, $toId FROM ".$this->db->prefix().
"categorie_".(empty($categorystatic->MAP_CAT_TABLE[$type]) ? $type : $categorystatic->MAP_CAT_TABLE[$type]);
10134 $sql .=
" WHERE fk_product = ".((int) $fromId);
10136 if (!$this->
db->query($sql)) {
10137 $this->error = $this->
db->lasterror();
10138 $this->
db->rollback();
10142 $this->
db->commit();
10156 $this->
db->begin();
10160 switch ($this->element) {
10162 $element =
'propale';
10165 $element =
'produit';
10167 case 'order_supplier':
10168 $element =
'fournisseur/commande';
10170 case 'invoice_supplier':
10171 $element =
'fournisseur/facture/'.get_exdir($this->
id, 2, 0, 1, $this,
'invoice_supplier');
10174 $element =
'expedition/sending';
10177 $element = $this->element;
10181 $sql =
"DELETE FROM ".$this->db->prefix().
"ecm_files_extrafields WHERE fk_object IN (";
10182 $sql .=
" SELECT rowid FROM ".$this->db->prefix().
"ecm_files WHERE filename LIKE '".$this->
db->escape($this->
ref).
"%'";
10183 $sql .=
" AND filepath = '".$this->db->escape($element).
"/".$this->
db->escape($this->
ref).
"' AND entity = ".((int) $conf->entity);
10186 if (!$this->
db->query($sql)) {
10187 $this->error = $this->
db->lasterror();
10188 $this->
db->rollback();
10193 $sql =
"DELETE FROM ".$this->db->prefix().
"ecm_files";
10194 $sql .=
" WHERE filename LIKE '".$this->db->escape($this->
ref).
"%'";
10195 $sql .=
" AND filepath = '".$this->db->escape($element).
"/".$this->
db->escape($this->
ref).
"' AND entity = ".((int) $conf->entity);
10197 if (!$this->
db->query($sql)) {
10198 $this->error = $this->
db->lasterror();
10199 $this->
db->rollback();
10206 $sql =
'DELETE FROM '.$this->db->prefix().
"ecm_files_extrafields";
10207 $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).
")";
10210 $this->error = $this->
db->lasterror();
10211 $this->
db->rollback();
10215 $sql =
'DELETE FROM '.$this->db->prefix().
"ecm_files";
10216 $sql .=
" WHERE src_object_type = '".$this->db->escape($this->table_element.(empty($this->module) ?
"" :
"@".$this->module)).
"' AND src_object_id = ".((int) $this->
id);
10219 $this->error = $this->
db->lasterror();
10220 $this->
db->rollback();
10225 $this->
db->commit();
Class to manage categories.
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.
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.
deleteEcmFiles($mode=0)
Delete related files of object in database.
getBannerAddress($htmlkey, $object)
Return full address for banner.
swapContactStatus($rowid)
Update status of a contact linked to object.
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.
setUpperOrLowerCase()
Set to upper or ucwords/lower if needed.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
deleteLineCommon(User $user, $idline, $notrigger=false)
Delete a line of object in database.
deleteByParentField($parentId=0, $parentField='', $filter=array(), $filtermode="AND")
Delete all child object from a parent ID.
getFieldList($alias='')
Function to concat keys of fields.
getFullName($langs, $option=0, $nameorder=-1, $maxlen=0)
Return full name (civility+' '+name+' '+lastname)
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...
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.
isFloat($info)
Function test if type is float.
setExtraParameters()
Set extra parameters.
fetchCommon($id, $ref=null, $morewhere='')
Load object in memory from the database.
update_ref_ext($ref_ext)
Update external ref of element.
showOptionals($extrafields, $mode='view', $params=null, $keysuffix='', $keyprefix='', $onetrtd=0, $display_type='card')
Function to show lines of extrafields with output datas.
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...
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.
deleteCommon(User $user, $notrigger=false, $forcechilddeletion=0)
Delete object in database.
getFullAddress($withcountry=0, $sep="\n", $withregion=0, $extralangcode='')
Return full address of contact.
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).
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.
deleteExtraFields()
Delete all extra fields values for the current object.
setStatusCommon($user, $status, $notrigger=0, $triggercode='')
Set to a status.
setSaveQuery()
Function to return the array of data key-value from the ->fields and all the ->properties of an objec...
insertExtraLanguages($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
isArray($info)
Function test if type is array.
isInt($info)
Function test if type is integer.
delete_contact($rowid, $notrigger=0)
Delete a link to contact line.
errorsToString()
Method to output saved errors.
setBankAccount($fk_account, $notrigger=false, $userused=null)
Change the bank account.
setWarehouse($warehouse_id)
Change the warehouse.
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.
trimParameters($parameters)
Trim object parameters.
isIndex($info)
Function test if is indexed.
quote($value, $fieldsentry)
Add quote to field value if necessary.
fetchComments()
Load comments linked with current task.
updateCommon(User $user, $notrigger=false)
Update object into database.
getRangOfLine($rowid)
Get position of line (rang)
delete_resource($rowid, $element, $notrigger=0)
Delete a link to resource line.
update_note($note, $suffix='')
Update note of element.
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.
line_max($fk_parent_line=0)
Get max value used for position of line (rang)
setProject($projectid, $notrigger=0)
Link element with a project.
isForcedToNullIfZero($info)
Function test if field is forced to null if zero or empty.
liste_contact($statusoflink=-1, $source='external', $list=0, $code='', $status=-1, $arrayoftcids=array())
Get array of all contacts for an object.
getKanbanView($option='')
Return clicable link of object (with eventually picto)
fetchLinesCommon($morewhere='')
Load object in memory from the database.
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
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.
isText($info)
Function test if type is text.
isDate($info)
Function test if type is date.
isDuration($info)
Function test if type is duration.
canBeNull($info)
Function test if field can be null.
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.
Class to manage Dolibarr users.
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.
if(isModEnabled('facture') &&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') &&!empty($user->rights->don->lire)) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $resql
Social contributions to pay.
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
print *****$script_file(".$version.") pid c cd cd cd description as p label as s rowid
dol_strtolower($string, $encoding="UTF-8")
Convert a string to lower.
img_delete($titlealt='default', $other='class="pictodelete"', $morecss='')
Show delete logo.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
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.
if(!function_exists('dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
dol_now($mode='auto')
Return date for now.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dolGetFirstLastname($firstname, $lastname, $nameorder=-1)
Return firstname and lastname in correct order.
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='')
Clean a string from all punctuation characters to use it as a ref or login.
dol_strtoupper($string, $encoding="UTF-8")
Convert a string to upper.
getAdvancedPreviewUrl($modulepart, $relativepath, $alldata=0, $param='')
Return URL we can use for advanced preview links.
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_ucwords($string, $encoding="UTF-8")
Convert first character of all the words of a string to upper.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
$conf db name
Only used if Module[ID]Name translation string is not found.
$conf db
API class for accounts.
print *****$script_file(".$version.") pid code
! Closing after partial payment: discount_vat, badcustomer or badsupplier, bankcharge,...