dolibarr  7.0.0-beta
commonobject.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2006-2015 Laurent Destailleur <eldy@users.sourceforge.net>
3  * Copyright (C) 2005-2013 Regis Houssin <regis.houssin@capnetworks.com>
4  * Copyright (C) 2010-2013 Juanjo Menent <jmenent@2byte.es>
5  * Copyright (C) 2012 Christophe Battarel <christophe.battarel@altairis.fr>
6  * Copyright (C) 2010-2015 Juanjo Menent <jmenent@2byte.es>
7  * Copyright (C) 2012-2013 Christophe Battarel <christophe.battarel@altairis.fr>
8  * Copyright (C) 2011-2014 Philippe Grand <philippe.grand@atoo-net.com>
9  * Copyright (C) 2012-2015 Marcos García <marcosgdf@gmail.com>
10  * Copyright (C) 2012-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
11  * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
12  * Copyright (C) 2015 Alexandre Spangaro <aspangaro.dolibarr@gmail.com>
13  * Copyright (C) 2016 Bahfir abbes <dolipar@dolipar.org>
14  * Copyright (C) 2017 ATM Consulting <support@atm-consulting.fr>
15  * Copyright (C) 2017 Nicolas ZABOURI <info@inovea-conseil.com>
16  *
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program. If not, see <http://www.gnu.org/licenses/>.
29  */
30 
41 abstract class CommonObject
42 {
46  public $db;
50  public $id;
55  public $error;
59  public $errors=array();
63  public $element;
67  public $table_element;
71  public $table_element_line;
75  public $import_key;
79  public $array_options=array();
83  public $linkedObjectsIds;
87  public $linkedObjects;
91  public $oldcopy;
92 
96  protected $table_ref_field = '';
97 
98 
99 
100  // Following vars are used by some objects only. We keep this property here in CommonObject to be able to provide common method using them.
101 
105  public $context=array();
106 
110  public $canvas;
111 
116  public $project;
121  public $fk_project;
126  public $projet;
127 
132  public $contact;
137  public $contact_id;
138 
143  public $thirdparty;
144 
149  public $user;
150 
155  public $origin;
160  public $origin_id;
161 
165  public $ref;
169  public $ref_previous;
173  public $ref_next;
177  public $ref_ext;
178 
183  public $statut;
184 
189  public $country;
194  public $country_id;
199  public $country_code;
200 
205  public $barcode_type;
210  public $barcode_type_code;
215  public $barcode_type_label;
220  public $barcode_type_coder;
221 
226  public $mode_reglement_id;
227 
232  public $cond_reglement_id;
238  public $cond_reglement;
239 
245  public $fk_delivery_address;
246 
251  public $shipping_method_id;
252 
257  public $modelpdf;
258 
263  public $fk_account;
264 
269  public $note_public;
274  public $note_private;
279  public $note;
280 
285  public $total_ht;
290  public $total_tva;
295  public $total_localtax1;
300  public $total_localtax2;
305  public $total_ttc;
306 
310  public $lines;
311 
316  public $comments=array();
317 
322  public $fk_incoterms;
327  public $libelle_incoterms;
332  public $location_incoterms;
333 
334  public $name;
335  public $lastname;
336  public $firstname;
337  public $civility_id;
338 
339 
340  // No constructor as it is an abstract class
341 
352  static function isExistingObject($element, $id, $ref='', $ref_ext='')
353  {
354  global $db,$conf;
355 
356  $sql = "SELECT rowid, ref, ref_ext";
357  $sql.= " FROM ".MAIN_DB_PREFIX.$element;
358  $sql.= " WHERE entity IN (".getEntity($element).")" ;
359 
360  if ($id > 0) $sql.= " AND rowid = ".$db->escape($id);
361  else if ($ref) $sql.= " AND ref = '".$db->escape($ref)."'";
362  else if ($ref_ext) $sql.= " AND ref_ext = '".$db->escape($ref_ext)."'";
363  else {
364  $error='ErrorWrongParameters';
365  dol_print_error(get_class()."::isExistingObject ".$error, LOG_ERR);
366  return -1;
367  }
368  if ($ref || $ref_ext) $sql.= " AND entity = ".$conf->entity;
369 
370  dol_syslog(get_class()."::isExistingObject", LOG_DEBUG);
371  $resql = $db->query($sql);
372  if ($resql)
373  {
374  $num=$db->num_rows($resql);
375  if ($num > 0) return 1;
376  else return 0;
377  }
378  return -1;
379  }
380 
386  function errorsToString()
387  {
388  return $this->error.(is_array($this->errors)?(($this->error!=''?', ':'').join(', ',$this->errors)):'');
389  }
390 
400  function getFullName($langs,$option=0,$nameorder=-1,$maxlen=0)
401  {
402  //print "lastname=".$this->lastname." name=".$this->name." nom=".$this->nom."<br>\n";
403  $lastname=$this->lastname;
404  $firstname=$this->firstname;
405  if (empty($lastname)) $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:'')))));
406 
407  $ret='';
408  if ($option && $this->civility_id)
409  {
410  if ($langs->transnoentitiesnoconv("Civility".$this->civility_id)!="Civility".$this->civility_id) $ret.=$langs->transnoentitiesnoconv("Civility".$this->civility_id).' ';
411  else $ret.=$this->civility_id.' ';
412  }
413 
414  $ret.=dolGetFirstLastname($firstname, $lastname, $nameorder);
415 
416  return dol_trunc($ret,$maxlen);
417  }
418 
426  function getFullAddress($withcountry=0,$sep="\n")
427  {
428  if ($withcountry && $this->country_id && (empty($this->country_code) || empty($this->country)))
429  {
430  require_once DOL_DOCUMENT_ROOT .'/core/lib/company.lib.php';
431  $tmparray=getCountry($this->country_id,'all');
432  $this->country_code=$tmparray['code'];
433  $this->country =$tmparray['label'];
434  }
435 
436  return dol_format_address($this, $withcountry, $sep);
437  }
438 
439 
447  function getBannerAddress($htmlkey, $object)
448  {
449  global $conf, $langs;
450 
451  $countriesusingstate=array('AU','US','IN','GB','ES','UK','TR'); // See also option MAIN_FORCE_STATE_INTO_ADDRESS
452 
453  $contactid=0;
454  $thirdpartyid=0;
455  if ($this->element == 'societe')
456  {
457  $thirdpartyid=$this->id;
458  }
459  if ($this->element == 'contact')
460  {
461  $contactid=$this->id;
462  $thirdpartyid=$object->fk_soc;
463  }
464  if ($this->element == 'user')
465  {
466  $contactid=$this->contact_id;
467  $thirdpartyid=$object->fk_soc;
468  }
469 
470  $out='<!-- BEGIN part to show address block -->';
471 
472  $outdone=0;
473  $coords = $this->getFullAddress(1,', ');
474  if ($coords)
475  {
476  if (! empty($conf->use_javascript_ajax))
477  {
478  $namecoords = $this->getFullName($langs,1).'<br>'.$coords;
479  // hideonsmatphone because copyToClipboard call jquery dialog that does not work with jmobile
480  $out.='<a href="#" class="hideonsmartphone" onclick="return copyToClipboard(\''.dol_escape_js($namecoords).'\',\''.dol_escape_js($langs->trans("HelpCopyToClipboard")).'\');">';
481  $out.=img_picto($langs->trans("Address"), 'object_address.png');
482  $out.='</a> ';
483  }
484  $out.=dol_print_address($coords, 'address_'.$htmlkey.'_'.$this->id, $this->element, $this->id, 1, ', '); $outdone++;
485  $outdone++;
486  }
487 
488  if (! in_array($this->country_code,$countriesusingstate) && empty($conf->global->MAIN_FORCE_STATE_INTO_ADDRESS) // If MAIN_FORCE_STATE_INTO_ADDRESS is on, state is already returned previously with getFullAddress
489  && empty($conf->global->SOCIETE_DISABLE_STATE) && $this->state)
490  {
491  $out.=($outdone?' - ':'').$this->state;
492  $outdone++;
493  }
494 
495  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)) $out.=($outdone?'<br>':'');
496  if (! empty($this->phone) && empty($this->phone_pro)) { // For objects that store pro phone into ->phone
497  $out.=dol_print_phone($this->phone,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePro")); $outdone++;
498  }
499  if (! empty($this->phone_pro)) {
500  $out.=dol_print_phone($this->phone_pro,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePro")); $outdone++;
501  }
502  if (! empty($this->phone_mobile)) {
503  $out.=dol_print_phone($this->phone_mobile,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','mobile',$langs->trans("PhoneMobile")); $outdone++;
504  }
505  if (! empty($this->phone_perso)) {
506  $out.=dol_print_phone($this->phone_perso,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePerso")); $outdone++;
507  }
508  if (! empty($this->office_phone)) {
509  $out.=dol_print_phone($this->office_phone,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePro")); $outdone++;
510  }
511  if (! empty($this->user_mobile)) {
512  $out.=dol_print_phone($this->user_mobile,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','mobile',$langs->trans("PhoneMobile")); $outdone++;
513  }
514  if (! empty($this->fax)) {
515  $out.=dol_print_phone($this->fax,$this->country_code,$contactid,$thirdpartyid,'AC_FAX','&nbsp;','fax',$langs->trans("Fax")); $outdone++;
516  }
517  if (! empty($this->office_fax)) {
518  $out.=dol_print_phone($this->office_fax,$this->country_code,$contactid,$thirdpartyid,'AC_FAX','&nbsp;','fax',$langs->trans("Fax")); $outdone++;
519  }
520 
521  $out.='<div style="clear: both;"></div>';
522  $outdone=0;
523  if (! empty($this->email))
524  {
525  $out.=dol_print_email($this->email,$this->id,$object->id,'AC_EMAIL',0,0,1);
526  $outdone++;
527  }
528  if (! empty($this->url))
529  {
530  $out.=dol_print_url($this->url,'_goout',0,1);
531  $outdone++;
532  }
533  if (! empty($conf->skype->enabled))
534  {
535  $out.='<div style="clear: both;"></div>';
536  if ($this->skype) $out.=dol_print_skype($this->skype,$this->id,$object->id,'AC_SKYPE');
537  $outdone++;
538  }
539 
540  $out.='<!-- END Part to show address block -->';
541 
542  return $out;
543  }
544 
552  function getLastMainDocLink($modulepart, $initsharekey=0)
553  {
554  global $user, $dolibarr_main_url_root;
555 
556  if (empty($this->last_main_doc))
557  {
558  return ''; // No known last doc
559  }
560 
561  include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
562  $ecmfile=new EcmFiles($this->db);
563  $result = $ecmfile->fetch(0, '', $this->last_main_doc);
564  if ($result < 0)
565  {
566  $this->error = $ecmfile->error;
567  $this->errors = $ecmfile->errors;
568  return -1;
569  }
570 
571  if (empty($ecmfile->id))
572  {
573  // Add entry into index
574  if ($initsharekey)
575  {
576  require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
577  // TODO We can't, we dont' have full path of file, only last_main_doc adn ->element, so we must rebuild full path first
578  /*
579  $ecmfile->filepath = $rel_dir;
580  $ecmfile->filename = $filename;
581  $ecmfile->label = md5_file(dol_osencode($destfull)); // hash of file content
582  $ecmfile->fullpath_orig = '';
583  $ecmfile->gen_or_uploaded = 'generated';
584  $ecmfile->description = ''; // indexed content
585  $ecmfile->keyword = ''; // keyword content
586  $ecmfile->share = getRandomPassword(true);
587  $result = $ecmfile->create($user);
588  if ($result < 0)
589  {
590  $this->error = $ecmfile->error;
591  $this->errors = $ecmfile->errors;
592  }
593  */
594  }
595  else return '';
596  }
597  elseif (empty($ecmfile->share))
598  {
599  // Add entry into index
600  if ($initsharekey)
601  {
602  require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
603  $ecmfile->share = getRandomPassword(true);
604  $ecmfile->update($user);
605  }
606  else return '';
607  }
608 
609  // Define $urlwithroot
610  $urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($dolibarr_main_url_root));
611  $urlwithroot=$urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
612  //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
613 
614  $forcedownload=0;
615 
616  $paramlink='';
617  //if (! empty($modulepart)) $paramlink.=($paramlink?'&':'').'modulepart='.$modulepart; // For sharing with hash (so public files), modulepart is not required.
618  //if (! empty($ecmfile->entity)) $paramlink.='&entity='.$ecmfile->entity; // For sharing with hash (so public files), entity is not required.
619  //$paramlink.=($paramlink?'&':'').'file='.urlencode($filepath); // No need of name of file for public link, we will use the hash
620  if (! empty($ecmfile->share)) $paramlink.=($paramlink?'&':'').'hashp='.$ecmfile->share; // Hash for public share
621  if ($forcedownload) $paramlink.=($paramlink?'&':'').'attachment=1';
622 
623  $fulllink=$urlwithroot.'/document.php'.($paramlink?'?'.$paramlink:'');
624 
625  // Here $ecmfile->share is defined
626  return $fulllink;
627  }
628 
629 
639  function add_contact($fk_socpeople, $type_contact, $source='external',$notrigger=0)
640  {
641  global $user,$langs;
642 
643 
644  dol_syslog(get_class($this)."::add_contact $fk_socpeople, $type_contact, $source, $notrigger");
645 
646  // Check parameters
647  if ($fk_socpeople <= 0)
648  {
649  $langs->load("errors");
650  $this->error=$langs->trans("ErrorWrongValueForParameterX","1");
651  dol_syslog(get_class($this)."::add_contact ".$this->error,LOG_ERR);
652  return -1;
653  }
654  if (! $type_contact)
655  {
656  $langs->load("errors");
657  $this->error=$langs->trans("ErrorWrongValueForParameterX","2");
658  dol_syslog(get_class($this)."::add_contact ".$this->error,LOG_ERR);
659  return -2;
660  }
661 
662  $id_type_contact=0;
663  if (is_numeric($type_contact))
664  {
665  $id_type_contact=$type_contact;
666  }
667  else
668  {
669  // On recherche id type_contact
670  $sql = "SELECT tc.rowid";
671  $sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact as tc";
672  $sql.= " WHERE tc.element='".$this->db->escape($this->element)."'";
673  $sql.= " AND tc.source='".$this->db->escape($source)."'";
674  $sql.= " AND tc.code='".$this->db->escape($type_contact)."' AND tc.active=1";
675  //print $sql;
676  $resql=$this->db->query($sql);
677  if ($resql)
678  {
679  $obj = $this->db->fetch_object($resql);
680  if ($obj) $id_type_contact=$obj->rowid;
681  }
682  }
683 
684  if ($id_type_contact == 0)
685  {
686  $this->error='CODE_NOT_VALID_FOR_THIS_ELEMENT';
687  dol_syslog("CODE_NOT_VALID_FOR_THIS_ELEMENT");
688  return -3;
689  }
690 
691  $datecreate = dol_now();
692 
693  // Socpeople must have already been added by some a trigger, then we have to check it to avoid DB_ERROR_RECORD_ALREADY_EXISTS error
694  $TListeContacts=$this->liste_contact(-1, $source);
695  $already_added=false;
696  if(!empty($TListeContacts)) {
697  foreach($TListeContacts as $array_contact) {
698  if($array_contact['status'] == 4 && $array_contact['id'] == $fk_socpeople && $array_contact['fk_c_type_contact'] == $id_type_contact) {
699  $already_added=true;
700  break;
701  }
702  }
703  }
704 
705  if(!$already_added) {
706 
707  $this->db->begin();
708 
709  // Insertion dans la base
710  $sql = "INSERT INTO ".MAIN_DB_PREFIX."element_contact";
711  $sql.= " (element_id, fk_socpeople, datecreate, statut, fk_c_type_contact) ";
712  $sql.= " VALUES (".$this->id.", ".$fk_socpeople." , " ;
713  $sql.= "'".$this->db->idate($datecreate)."'";
714  $sql.= ", 4, ". $id_type_contact;
715  $sql.= ")";
716 
717  $resql=$this->db->query($sql);
718  if ($resql)
719  {
720  if (! $notrigger)
721  {
722  $result=$this->call_trigger(strtoupper($this->element).'_ADD_CONTACT', $user);
723  if ($result < 0)
724  {
725  $this->db->rollback();
726  return -1;
727  }
728  }
729 
730  $this->db->commit();
731  return 1;
732  }
733  else
734  {
735  if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS')
736  {
737  $this->error=$this->db->errno();
738  $this->db->rollback();
739  echo 'err rollback';
740  return -2;
741  }
742  else
743  {
744  $this->error=$this->db->error();
745  $this->db->rollback();
746  return -1;
747  }
748  }
749  } else return 0;
750  }
751 
759  function copy_linked_contact($objFrom, $source='internal')
760  {
761  $contacts = $objFrom->liste_contact(-1, $source);
762  foreach($contacts as $contact)
763  {
764  if ($this->add_contact($contact['id'], $contact['fk_c_type_contact'], $contact['source']) < 0)
765  {
766  $this->error=$this->db->lasterror();
767  return -1;
768  }
769  }
770  return 1;
771  }
772 
782  function update_contact($rowid, $statut, $type_contact_id=0, $fk_socpeople=0)
783  {
784  // Insertion dans la base
785  $sql = "UPDATE ".MAIN_DB_PREFIX."element_contact set";
786  $sql.= " statut = ".$statut;
787  if ($type_contact_id) $sql.= ", fk_c_type_contact = '".$type_contact_id ."'";
788  if ($fk_socpeople) $sql.= ", fk_socpeople = '".$fk_socpeople ."'";
789  $sql.= " where rowid = ".$rowid;
790  $resql=$this->db->query($sql);
791  if ($resql)
792  {
793  return 0;
794  }
795  else
796  {
797  $this->error=$this->db->lasterror();
798  return -1;
799  }
800  }
801 
809  function delete_contact($rowid, $notrigger=0)
810  {
811  global $user;
812 
813 
814  $this->db->begin();
815 
816  $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_contact";
817  $sql.= " WHERE rowid =".$rowid;
818 
819  dol_syslog(get_class($this)."::delete_contact", LOG_DEBUG);
820  if ($this->db->query($sql))
821  {
822  if (! $notrigger)
823  {
824  $result=$this->call_trigger(strtoupper($this->element).'_DELETE_CONTACT', $user);
825  if ($result < 0) { $this->db->rollback(); return -1; }
826  }
827 
828  $this->db->commit();
829  return 1;
830  }
831  else
832  {
833  $this->error=$this->db->lasterror();
834  $this->db->rollback();
835  return -1;
836  }
837  }
838 
846  function delete_linked_contact($source='',$code='')
847  {
848  $temp = array();
849  $typeContact = $this->liste_type_contact($source,'',0,0,$code);
850 
851  foreach($typeContact as $key => $value)
852  {
853  array_push($temp,$key);
854  }
855  $listId = implode(",", $temp);
856 
857  $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_contact";
858  $sql.= " WHERE element_id = ".$this->id;
859  if ($listId)
860  $sql.= " AND fk_c_type_contact IN (".$listId.")";
861 
862  dol_syslog(get_class($this)."::delete_linked_contact", LOG_DEBUG);
863  if ($this->db->query($sql))
864  {
865  return 1;
866  }
867  else
868  {
869  $this->error=$this->db->lasterror();
870  return -1;
871  }
872  }
873 
883  function liste_contact($statut=-1,$source='external',$list=0,$code='')
884  {
885  global $langs;
886 
887  $tab=array();
888 
889  $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
890  if ($source == 'internal') $sql.=", '-1' as socid, t.statut as statuscontact, t.login, t.photo";
891  if ($source == 'external' || $source == 'thirdparty') $sql.=", t.fk_soc as socid, t.statut as statuscontact";
892  $sql.= ", t.civility as civility, t.lastname as lastname, t.firstname, t.email";
893  $sql.= ", tc.source, tc.element, tc.code, tc.libelle";
894  $sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact tc";
895  $sql.= ", ".MAIN_DB_PREFIX."element_contact ec";
896  if ($source == 'internal') $sql.=" LEFT JOIN ".MAIN_DB_PREFIX."user t on ec.fk_socpeople = t.rowid";
897  if ($source == 'external'|| $source == 'thirdparty') $sql.=" LEFT JOIN ".MAIN_DB_PREFIX."socpeople t on ec.fk_socpeople = t.rowid";
898  $sql.= " WHERE ec.element_id =".$this->id;
899  $sql.= " AND ec.fk_c_type_contact=tc.rowid";
900  $sql.= " AND tc.element='".$this->db->escape($this->element)."'";
901  if ($code) $sql.= " AND tc.code = '".$this->db->escape($code)."'";
902  if ($source == 'internal') $sql.= " AND tc.source = 'internal'";
903  if ($source == 'external' || $source == 'thirdparty') $sql.= " AND tc.source = 'external'";
904  $sql.= " AND tc.active=1";
905  if ($statut >= 0) $sql.= " AND ec.statut = '".$statut."'";
906  $sql.=" ORDER BY t.lastname ASC";
907 
908  dol_syslog(get_class($this)."::liste_contact", LOG_DEBUG);
909  $resql=$this->db->query($sql);
910  if ($resql)
911  {
912  $num=$this->db->num_rows($resql);
913  $i=0;
914  while ($i < $num)
915  {
916  $obj = $this->db->fetch_object($resql);
917 
918  if (! $list)
919  {
920  $transkey="TypeContact_".$obj->element."_".$obj->source."_".$obj->code;
921  $libelle_type=($langs->trans($transkey)!=$transkey ? $langs->trans($transkey) : $obj->libelle);
922  $tab[$i]=array('source'=>$obj->source,'socid'=>$obj->socid,'id'=>$obj->id,
923  'nom'=>$obj->lastname, // For backward compatibility
924  'civility'=>$obj->civility, 'lastname'=>$obj->lastname, 'firstname'=>$obj->firstname, 'email'=>$obj->email, 'login'=>$obj->login, 'photo'=>$obj->photo, 'statuscontact'=>$obj->statuscontact,
925  'rowid'=>$obj->rowid, 'code'=>$obj->code, 'libelle'=>$libelle_type, 'status'=>$obj->statuslink, 'fk_c_type_contact'=>$obj->fk_c_type_contact);
926  }
927  else
928  {
929  $tab[$i]=$obj->id;
930  }
931 
932  $i++;
933  }
934 
935  return $tab;
936  }
937  else
938  {
939  $this->error=$this->db->lasterror();
940  dol_print_error($this->db);
941  return -1;
942  }
943  }
944 
945 
952  function swapContactStatus($rowid)
953  {
954  $sql = "SELECT ec.datecreate, ec.statut, ec.fk_socpeople, ec.fk_c_type_contact,";
955  $sql.= " tc.code, tc.libelle";
956  //$sql.= ", s.fk_soc";
957  $sql.= " FROM (".MAIN_DB_PREFIX."element_contact as ec, ".MAIN_DB_PREFIX."c_type_contact as tc)";
958  //$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople as s ON ec.fk_socpeople=s.rowid"; // Si contact de type external, alors il est lie a une societe
959  $sql.= " WHERE ec.rowid =".$rowid;
960  $sql.= " AND ec.fk_c_type_contact=tc.rowid";
961  $sql.= " AND tc.element = '".$this->db->escape($this->element)."'";
962 
963  dol_syslog(get_class($this)."::swapContactStatus", LOG_DEBUG);
964  $resql=$this->db->query($sql);
965  if ($resql)
966  {
967  $obj = $this->db->fetch_object($resql);
968  $newstatut = ($obj->statut == 4) ? 5 : 4;
969  $result = $this->update_contact($rowid, $newstatut);
970  $this->db->free($resql);
971  return $result;
972  }
973  else
974  {
975  $this->error=$this->db->error();
976  dol_print_error($this->db);
977  return -1;
978  }
979 
980  }
981 
992  function liste_type_contact($source='internal', $order='position', $option=0, $activeonly=0, $code='')
993  {
994  global $langs;
995 
996  if (empty($order)) $order='position';
997  if ($order == 'position') $order.=',code';
998 
999  $tab = array();
1000  $sql = "SELECT DISTINCT tc.rowid, tc.code, tc.libelle, tc.position";
1001  $sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact as tc";
1002  $sql.= " WHERE tc.element='".$this->db->escape($this->element)."'";
1003  if ($activeonly == 1) $sql.= " AND tc.active=1"; // only the active types
1004  if (! empty($source) && $source != 'all') $sql.= " AND tc.source='".$this->db->escape($source)."'";
1005  if (! empty($code)) $sql.= " AND tc.code='".$this->db->escape($code)."'";
1006  $sql.= $this->db->order($order,'ASC');
1007 
1008  //print "sql=".$sql;
1009  $resql=$this->db->query($sql);
1010  if ($resql)
1011  {
1012  $num=$this->db->num_rows($resql);
1013  $i=0;
1014  while ($i < $num)
1015  {
1016  $obj = $this->db->fetch_object($resql);
1017 
1018  $transkey="TypeContact_".$this->element."_".$source."_".$obj->code;
1019  $libelle_type=($langs->trans($transkey)!=$transkey ? $langs->trans($transkey) : $obj->libelle);
1020  if (empty($option)) $tab[$obj->rowid]=$libelle_type;
1021  else $tab[$obj->code]=$libelle_type;
1022  $i++;
1023  }
1024  return $tab;
1025  }
1026  else
1027  {
1028  $this->error=$this->db->lasterror();
1029  //dol_print_error($this->db);
1030  return null;
1031  }
1032  }
1033 
1045  function getIdContact($source,$code,$status=0)
1046  {
1047  global $conf;
1048 
1049  $result=array();
1050  $i=0;
1051  //cas particulier pour les expeditions
1052  if($this->element=='shipping' && $this->origin_id != 0) {
1053  $id=$this->origin_id;
1054  $element='commande';
1055  } else {
1056  $id=$this->id;
1057  $element=$this->element;
1058  }
1059 
1060  $sql = "SELECT ec.fk_socpeople";
1061  $sql.= " FROM ".MAIN_DB_PREFIX."element_contact as ec,";
1062  if ($source == 'internal') $sql.= " ".MAIN_DB_PREFIX."user as c,";
1063  if ($source == 'external') $sql.= " ".MAIN_DB_PREFIX."socpeople as c,";
1064  $sql.= " ".MAIN_DB_PREFIX."c_type_contact as tc";
1065  $sql.= " WHERE ec.element_id = ".$id;
1066  $sql.= " AND ec.fk_socpeople = c.rowid";
1067  if ($source == 'internal') $sql.= " AND c.entity IN (0,".$conf->entity.")";
1068  if ($source == 'external') $sql.= " AND c.entity IN (".getEntity('societe').")";
1069  $sql.= " AND ec.fk_c_type_contact = tc.rowid";
1070  $sql.= " AND tc.element = '".$element."'";
1071  $sql.= " AND tc.source = '".$source."'";
1072  $sql.= " AND tc.code = '".$code."'";
1073  $sql.= " AND tc.active = 1";
1074  if ($status) $sql.= " AND ec.statut = ".$status;
1075 
1076  dol_syslog(get_class($this)."::getIdContact", LOG_DEBUG);
1077  $resql=$this->db->query($sql);
1078  if ($resql)
1079  {
1080  while ($obj = $this->db->fetch_object($resql))
1081  {
1082  $result[$i]=$obj->fk_socpeople;
1083  $i++;
1084  }
1085  }
1086  else
1087  {
1088  $this->error=$this->db->error();
1089  return null;
1090  }
1091 
1092  return $result;
1093  }
1094 
1101  function fetch_contact($contactid=null)
1102  {
1103  if (empty($contactid)) $contactid=$this->contactid;
1104 
1105  if (empty($contactid)) return 0;
1106 
1107  require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1108  $contact = new Contact($this->db);
1109  $result=$contact->fetch($contactid);
1110  $this->contact = $contact;
1111  return $result;
1112  }
1113 
1120  function fetch_thirdparty($force_thirdparty_id=0)
1121  {
1122  global $conf;
1123 
1124  if (empty($this->socid) && empty($this->fk_soc) && empty($this->fk_thirdparty) && empty($force_thirdparty_id))
1125  return 0;
1126 
1127  require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
1128 
1129  $idtofetch = isset($this->socid) ? $this->socid : (isset($this->fk_soc) ? $this->fk_soc : $this->fk_thirdparty);
1130  if ($force_thirdparty_id)
1131  $idtofetch = $force_thirdparty_id;
1132 
1133  if ($idtofetch) {
1134  $thirdparty = new Societe($this->db);
1135  $result = $thirdparty->fetch($idtofetch);
1136  $this->thirdparty = $thirdparty;
1137 
1138  // Use first price level if level not defined for third party
1139  if (!empty($conf->global->PRODUIT_MULTIPRICES) && empty($this->thirdparty->price_level)) {
1140  $this->thirdparty->price_level = 1;
1141  }
1142 
1143  return $result;
1144  } else
1145  return -1;
1146  }
1147 
1148 
1156  public function fetchOneLike($ref)
1157  {
1158  if (!$this->table_ref_field) {
1159  return 0;
1160  }
1161 
1162  $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE '.$this->table_ref_field.' LIKE "'.$this->db->escape($ref).'" LIMIT 1';
1163 
1164  $query = $this->db->query($sql);
1165 
1166  if (!$this->db->num_rows($query)) {
1167  return 0;
1168  }
1169 
1170  $result = $this->db->fetch_object($query);
1171 
1172  return $this->fetch($result->rowid);
1173  }
1174 
1182  function fetch_barcode()
1183  {
1184  global $conf;
1185 
1186  dol_syslog(get_class($this).'::fetch_barcode this->element='.$this->element.' this->barcode_type='.$this->barcode_type);
1187 
1188  $idtype=$this->barcode_type;
1189  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
1190  {
1191  if ($this->element == 'product') $idtype = $conf->global->PRODUIT_DEFAULT_BARCODE_TYPE;
1192  else if ($this->element == 'societe') $idtype = $conf->global->GENBARCODE_BARCODETYPE_THIRDPARTY;
1193  else dol_syslog('Call fetch_barcode with barcode_type not defined and cant be guessed', LOG_WARNING);
1194  }
1195 
1196  if ($idtype > 0)
1197  {
1198  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
1199  {
1200  $sql = "SELECT rowid, code, libelle as label, coder";
1201  $sql.= " FROM ".MAIN_DB_PREFIX."c_barcode_type";
1202  $sql.= " WHERE rowid = ".$idtype;
1203  dol_syslog(get_class($this).'::fetch_barcode', LOG_DEBUG);
1204  $resql = $this->db->query($sql);
1205  if ($resql)
1206  {
1207  $obj = $this->db->fetch_object($resql);
1208  $this->barcode_type = $obj->rowid;
1209  $this->barcode_type_code = $obj->code;
1210  $this->barcode_type_label = $obj->label;
1211  $this->barcode_type_coder = $obj->coder;
1212  return 1;
1213  }
1214  else
1215  {
1216  dol_print_error($this->db);
1217  return -1;
1218  }
1219  }
1220  }
1221  return 0;
1222  }
1223 
1229  function fetch_projet()
1230  {
1231  include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
1232 
1233  if (empty($this->fk_project) && ! empty($this->fk_projet)) $this->fk_project = $this->fk_projet; // For backward compatibility
1234  if (empty($this->fk_project)) return 0;
1235 
1236  $project = new Project($this->db);
1237  $result = $project->fetch($this->fk_project);
1238 
1239  $this->projet = $project; // deprecated
1240  $this->project = $project;
1241  return $result;
1242  }
1243 
1250  function fetch_user($userid)
1251  {
1252  $user = new User($this->db);
1253  $result=$user->fetch($userid);
1254  $this->user = $user;
1255  return $result;
1256  }
1257 
1263  function fetch_origin()
1264  {
1265  if ($this->origin == 'shipping') $this->origin = 'expedition';
1266  if ($this->origin == 'delivery') $this->origin = 'livraison';
1267 
1268  $origin = $this->origin;
1269 
1270  $classname = ucfirst($origin);
1271  $this->$origin = new $classname($this->db);
1272  $this->$origin->fetch($this->origin_id);
1273  }
1274 
1283  function fetchObjectFrom($table,$field,$key)
1284  {
1285  global $conf;
1286 
1287  $result=false;
1288 
1289  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX.$table;
1290  $sql.= " WHERE ".$field." = '".$key."'";
1291  $sql.= " AND entity = ".$conf->entity;
1292 
1293  dol_syslog(get_class($this).'::fetchObjectFrom', LOG_DEBUG);
1294  $resql = $this->db->query($sql);
1295  if ($resql)
1296  {
1297  $row = $this->db->fetch_row($resql);
1298  $result = $this->fetch($row[0]);
1299  }
1300 
1301  return $result;
1302  }
1303 
1312  function getValueFrom($table, $id, $field)
1313  {
1314  $result=false;
1315  if (!empty($id) && !empty($field) && !empty($table)) {
1316  $sql = "SELECT ".$field." FROM ".MAIN_DB_PREFIX.$table;
1317  $sql.= " WHERE rowid = ".$id;
1318 
1319  dol_syslog(get_class($this).'::getValueFrom', LOG_DEBUG);
1320  $resql = $this->db->query($sql);
1321  if ($resql)
1322  {
1323  $row = $this->db->fetch_row($resql);
1324  $result = $row[0];
1325  }
1326  }
1327  return $result;
1328  }
1329 
1344  function setValueFrom($field, $value, $table='', $id=null, $format='', $id_field='', $fuser=null, $trigkey='')
1345  {
1346  global $user,$langs,$conf;
1347 
1348  if (empty($table)) $table=$this->table_element;
1349  if (empty($id)) $id=$this->id;
1350  if (empty($format)) $format='text';
1351  if (empty($id_field)) $id_field='rowid';
1352 
1353  $error=0;
1354 
1355  $this->db->begin();
1356 
1357  // Special case
1358  if ($table == 'product' && $field == 'note_private') $field='note';
1359 
1360  $sql = "UPDATE ".MAIN_DB_PREFIX.$table." SET ";
1361  if ($format == 'text') $sql.= $field." = '".$this->db->escape($value)."'";
1362  else if ($format == 'int') $sql.= $field." = ".$this->db->escape($value);
1363  else if ($format == 'date') $sql.= $field." = ".($value ? "'".$this->db->idate($value)."'" : "null");
1364  if (! empty($fuser) && is_object($fuser)) $sql.=", fk_user_modif = ".$fuser->id;
1365  elseif (empty($fuser) || $fuser != 'none') $sql.=", fk_user_modif = ".$user->id;
1366  $sql.= " WHERE ".$id_field." = ".$id;
1367 
1368  dol_syslog(get_class($this)."::".__FUNCTION__."", LOG_DEBUG);
1369  $resql = $this->db->query($sql);
1370  if ($resql)
1371  {
1372  if ($trigkey)
1373  {
1374  $result=$this->call_trigger($trigkey, (! empty($fuser) && is_object($fuser)) ? $fuser : $user); // This may set this->errors
1375  if ($result < 0) $error++;
1376  }
1377 
1378  if (! $error)
1379  {
1380  if (property_exists($this, $field)) $this->$field = $value;
1381  $this->db->commit();
1382  return 1;
1383  }
1384  else
1385  {
1386  $this->db->rollback();
1387  return -2;
1388  }
1389  }
1390  else
1391  {
1392  $this->error=$this->db->lasterror();
1393  $this->db->rollback();
1394  return -1;
1395  }
1396  }
1397 
1406  function load_previous_next_ref($filter, $fieldid, $nodbprefix=0)
1407  {
1408  global $user;
1409 
1410  if (! $this->table_element)
1411  {
1412  dol_print_error('',get_class($this)."::load_previous_next_ref was called on objet with property table_element not defined");
1413  return -1;
1414  }
1415  if ($fieldid == 'none') return 1;
1416 
1417  // Security on socid
1418  $socid = 0;
1419  if ($user->societe_id > 0) $socid = $user->societe_id;
1420 
1421  // this->ismultientitymanaged contains
1422  // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
1423  $alias = 's';
1424  if ($this->element == 'societe') $alias = 'te';
1425 
1426  $sql = "SELECT MAX(te.".$fieldid.")";
1427  $sql.= " FROM ".(empty($nodbprefix)?MAIN_DB_PREFIX:'').$this->table_element." as te";
1428  if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 2) $sql.= ", ".MAIN_DB_PREFIX."societe as s"; // If we need to link to societe to limit select to entity
1429  else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe as s"; // If we need to link to societe to limit select to socid
1430  else if ($this->restrictiononfksoc == 2 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON te.fk_soc = s.rowid"; // If we need to link to societe to limit select to socid
1431  if ($this->restrictiononfksoc && !$user->rights->societe->client->voir && !$socid) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON ".$alias.".rowid = sc.fk_soc";
1432  $sql.= " WHERE te.".$fieldid." < '".$this->db->escape($this->ref)."'"; // ->ref must always be defined (set to id if field does not exists)
1433  if ($this->restrictiononfksoc == 1 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND sc.fk_user = " .$user->id;
1434  if ($this->restrictiononfksoc == 2 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND (sc.fk_user = " .$user->id.' OR te.fk_soc IS NULL)';
1435  if (! empty($filter))
1436  {
1437  if (! preg_match('/^\s*AND/i', $filter)) $sql.=" AND "; // For backward compatibility
1438  $sql.=$filter;
1439  }
1440  if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 2) $sql.= ' AND te.fk_soc = s.rowid'; // If we need to link to societe to limit select to entity
1441  else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= ' AND te.fk_soc = s.rowid'; // If we need to link to societe to limit select to socid
1442  if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) $sql.= ' AND te.entity IN ('.getEntity($this->element).')';
1443  if ($this->restrictiononfksoc == 1 && $socid && $this->element != 'societe') $sql.= ' AND te.fk_soc = ' . $socid;
1444  if ($this->restrictiononfksoc == 2 && $socid && $this->element != 'societe') $sql.= ' AND (te.fk_soc = ' . $socid.' OR te.fk_soc IS NULL)';
1445  if ($this->restrictiononfksoc && $socid && $this->element == 'societe') $sql.= ' AND te.rowid = ' . $socid;
1446  //print 'socid='.$socid.' restrictiononfksoc='.$this->restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."<br>";
1447 
1448  $result = $this->db->query($sql);
1449  if (! $result)
1450  {
1451  $this->error=$this->db->lasterror();
1452  return -1;
1453  }
1454  $row = $this->db->fetch_row($result);
1455  $this->ref_previous = $row[0];
1456 
1457 
1458  $sql = "SELECT MIN(te.".$fieldid.")";
1459  $sql.= " FROM ".(empty($nodbprefix)?MAIN_DB_PREFIX:'').$this->table_element." as te";
1460  if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 2) $sql.= ", ".MAIN_DB_PREFIX."societe as s"; // If we need to link to societe to limit select to entity
1461  else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe as s"; // If we need to link to societe to limit select to socid
1462  else if ($this->restrictiononfksoc == 2 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON te.fk_soc = s.rowid"; // If we need to link to societe to limit select to socid
1463  if ($this->restrictiononfksoc && !$user->rights->societe->client->voir && !$socid) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON ".$alias.".rowid = sc.fk_soc";
1464  $sql.= " WHERE te.".$fieldid." > '".$this->db->escape($this->ref)."'"; // ->ref must always be defined (set to id if field does not exists)
1465  if ($this->restrictiononfksoc == 1 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND sc.fk_user = " .$user->id;
1466  if ($this->restrictiononfksoc == 2 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND (sc.fk_user = " .$user->id.' OR te.fk_soc IS NULL)';
1467  if (! empty($filter))
1468  {
1469  if (! preg_match('/^\s*AND/i', $filter)) $sql.=" AND "; // For backward compatibility
1470  $sql.=$filter;
1471  }
1472  if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 2) $sql.= ' AND te.fk_soc = s.rowid'; // If we need to link to societe to limit select to entity
1473  else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= ' AND te.fk_soc = s.rowid'; // If we need to link to societe to limit select to socid
1474  if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) $sql.= ' AND te.entity IN ('.getEntity($this->element).')';
1475  if ($this->restrictiononfksoc == 1 && $socid && $this->element != 'societe') $sql.= ' AND te.fk_soc = ' . $socid;
1476  if ($this->restrictiononfksoc == 2 && $socid && $this->element != 'societe') $sql.= ' AND (te.fk_soc = ' . $socid.' OR te.fk_soc IS NULL)';
1477  if ($this->restrictiononfksoc && $socid && $this->element == 'societe') $sql.= ' AND te.rowid = ' . $socid;
1478  //print 'socid='.$socid.' restrictiononfksoc='.$this->restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."<br>";
1479  // 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
1480 
1481  $result = $this->db->query($sql);
1482  if (! $result)
1483  {
1484  $this->error=$this->db->lasterror();
1485  return -2;
1486  }
1487  $row = $this->db->fetch_row($result);
1488  $this->ref_next = $row[0];
1489 
1490  return 1;
1491  }
1492 
1493 
1501  function getListContactId($source='external')
1502  {
1503  $contactAlreadySelected = array();
1504  $tab = $this->liste_contact(-1,$source);
1505  $num=count($tab);
1506  $i = 0;
1507  while ($i < $num)
1508  {
1509  if ($source == 'thirdparty') $contactAlreadySelected[$i] = $tab[$i]['socid'];
1510  else $contactAlreadySelected[$i] = $tab[$i]['id'];
1511  $i++;
1512  }
1513  return $contactAlreadySelected;
1514  }
1515 
1516 
1523  function setProject($projectid)
1524  {
1525  if (! $this->table_element)
1526  {
1527  dol_syslog(get_class($this)."::setProject was called on objet with property table_element not defined",LOG_ERR);
1528  return -1;
1529  }
1530 
1531  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1532  if ($this->table_element == 'actioncomm')
1533  {
1534  if ($projectid) $sql.= ' SET fk_project = '.$projectid;
1535  else $sql.= ' SET fk_project = NULL';
1536  $sql.= ' WHERE id = '.$this->id;
1537  }
1538  else
1539  {
1540  if ($projectid) $sql.= ' SET fk_projet = '.$projectid;
1541  else $sql.= ' SET fk_projet = NULL';
1542  $sql.= ' WHERE rowid = '.$this->id;
1543  }
1544 
1545  dol_syslog(get_class($this)."::setProject", LOG_DEBUG);
1546  if ($this->db->query($sql))
1547  {
1548  $this->fk_project = $projectid;
1549  return 1;
1550  }
1551  else
1552  {
1553  dol_print_error($this->db);
1554  return -1;
1555  }
1556  }
1557 
1564  function setPaymentMethods($id)
1565  {
1566  dol_syslog(get_class($this).'::setPaymentMethods('.$id.')');
1567  if ($this->statut >= 0 || $this->element == 'societe')
1568  {
1569  // TODO uniformize field name
1570  $fieldname = 'fk_mode_reglement';
1571  if ($this->element == 'societe') $fieldname = 'mode_reglement';
1572  if (get_class($this) == 'Fournisseur') $fieldname = 'mode_reglement_supplier';
1573 
1574  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1575  $sql .= ' SET '.$fieldname.' = '.$id;
1576  $sql .= ' WHERE rowid='.$this->id;
1577 
1578  if ($this->db->query($sql))
1579  {
1580  $this->mode_reglement_id = $id;
1581  // for supplier
1582  if (get_class($this) == 'Fournisseur') $this->mode_reglement_supplier_id = $id;
1583  return 1;
1584  }
1585  else
1586  {
1587  dol_syslog(get_class($this).'::setPaymentMethods Erreur '.$sql.' - '.$this->db->error());
1588  $this->error=$this->db->error();
1589  return -1;
1590  }
1591  }
1592  else
1593  {
1594  dol_syslog(get_class($this).'::setPaymentMethods, status of the object is incompatible');
1595  $this->error='Status of the object is incompatible '.$this->statut;
1596  return -2;
1597  }
1598  }
1599 
1606  function setMulticurrencyCode($code)
1607  {
1608  dol_syslog(get_class($this).'::setMulticurrencyCode('.$id.')');
1609  if ($this->statut >= 0 || $this->element == 'societe')
1610  {
1611  $fieldname = 'multicurrency_code';
1612 
1613  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1614  $sql .= ' SET '.$fieldname." = '".$this->db->escape($code)."'";
1615  $sql .= ' WHERE rowid='.$this->id;
1616 
1617  if ($this->db->query($sql))
1618  {
1619  $this->multicurrency_code = $code;
1620 
1621  list($fk_multicurrency, $rate) = MultiCurrency::getIdAndTxFromCode($this->db, $code);
1622  if ($rate) $this->setMulticurrencyRate($rate);
1623 
1624  return 1;
1625  }
1626  else
1627  {
1628  dol_syslog(get_class($this).'::setMulticurrencyCode Erreur '.$sql.' - '.$this->db->error());
1629  $this->error=$this->db->error();
1630  return -1;
1631  }
1632  }
1633  else
1634  {
1635  dol_syslog(get_class($this).'::setMulticurrencyCode, status of the object is incompatible');
1636  $this->error='Status of the object is incompatible '.$this->statut;
1637  return -2;
1638  }
1639  }
1640 
1648  function setMulticurrencyRate($rate, $mode=1)
1649  {
1650  dol_syslog(get_class($this).'::setMulticurrencyRate('.$id.')');
1651  if ($this->statut >= 0 || $this->element == 'societe')
1652  {
1653  $fieldname = 'multicurrency_tx';
1654 
1655  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1656  $sql .= ' SET '.$fieldname.' = '.$rate;
1657  $sql .= ' WHERE rowid='.$this->id;
1658 
1659  if ($this->db->query($sql))
1660  {
1661  $this->multicurrency_tx = $rate;
1662 
1663  // Update line price
1664  if (!empty($this->lines))
1665  {
1666  foreach ($this->lines as &$line)
1667  {
1668  if($mode == 1) {
1669  $line->subprice = 0;
1670  }
1671 
1672  switch ($this->element) {
1673  case 'propal':
1674  $this->updateline($line->id, $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, ($line->description?$line->description:$line->desc), 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line, $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice);
1675  break;
1676  case 'commande':
1677  $this->updateline($line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->date_start, $line->date_end, $line->product_type, $line->fk_parent_line, $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->fk_unit, $line->multicurrency_subprice);
1678  break;
1679  case 'facture':
1680  $this->updateline($line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent, $line->date_start, $line->date_end, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, $line->fk_parent_line, $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit, $line->multicurrency_subprice);
1681  break;
1682  case 'supplier_proposal':
1683  $this->updateline($line->id, $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, ($line->description?$line->description:$line->desc), 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line, $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->array_options, $line->ref_fourn, $line->multicurrency_subprice);
1684  break;
1685  case 'order_supplier':
1686  $this->updateline($line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, false, $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice);
1687  break;
1688  case 'invoice_supplier':
1689  $this->updateline($line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, $line->qty, 0, 'HT', $line->info_bits, $line->product_type, $line->remise_percent, false, $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice);
1690  break;
1691  default:
1692  dol_syslog(get_class($this).'::setMulticurrencyRate no updateline defined', LOG_DEBUG);
1693  break;
1694  }
1695 
1696  }
1697  }
1698 
1699  return 1;
1700  }
1701  else
1702  {
1703  dol_syslog(get_class($this).'::setMulticurrencyRate Erreur '.$sql.' - '.$this->db->error());
1704  $this->error=$this->db->error();
1705  return -1;
1706  }
1707  }
1708  else
1709  {
1710  dol_syslog(get_class($this).'::setMulticurrencyRate, status of the object is incompatible');
1711  $this->error='Status of the object is incompatible '.$this->statut;
1712  return -2;
1713  }
1714  }
1715 
1722  function setPaymentTerms($id)
1723  {
1724  dol_syslog(get_class($this).'::setPaymentTerms('.$id.')');
1725  if ($this->statut >= 0 || $this->element == 'societe')
1726  {
1727  // TODO uniformize field name
1728  $fieldname = 'fk_cond_reglement';
1729  if ($this->element == 'societe') $fieldname = 'cond_reglement';
1730  if (get_class($this) == 'Fournisseur') $fieldname = 'cond_reglement_supplier';
1731 
1732  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1733  $sql .= ' SET '.$fieldname.' = '.$id;
1734  $sql .= ' WHERE rowid='.$this->id;
1735 
1736  if ($this->db->query($sql))
1737  {
1738  $this->cond_reglement_id = $id;
1739  // for supplier
1740  if (get_class($this) == 'Fournisseur') $this->cond_reglement_supplier_id = $id;
1741  $this->cond_reglement = $id; // for compatibility
1742  return 1;
1743  }
1744  else
1745  {
1746  dol_syslog(get_class($this).'::setPaymentTerms Erreur '.$sql.' - '.$this->db->error());
1747  $this->error=$this->db->error();
1748  return -1;
1749  }
1750  }
1751  else
1752  {
1753  dol_syslog(get_class($this).'::setPaymentTerms, status of the object is incompatible');
1754  $this->error='Status of the object is incompatible '.$this->statut;
1755  return -2;
1756  }
1757  }
1758 
1766  function setDeliveryAddress($id)
1767  {
1768  $fieldname = 'fk_delivery_address';
1769  if ($this->element == 'delivery' || $this->element == 'shipping') $fieldname = 'fk_address';
1770 
1771  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET ".$fieldname." = ".$id;
1772  $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
1773 
1774  if ($this->db->query($sql))
1775  {
1776  $this->fk_delivery_address = $id;
1777  return 1;
1778  }
1779  else
1780  {
1781  $this->error=$this->db->error();
1782  dol_syslog(get_class($this).'::setDeliveryAddress Erreur '.$sql.' - '.$this->error);
1783  return -1;
1784  }
1785  }
1786 
1787 
1794  function setShippingMethod($shipping_method_id)
1795  {
1796  if (! $this->table_element) {
1797  dol_syslog(get_class($this)."::setShippingMethod was called on objet with property table_element not defined",LOG_ERR);
1798  return -1;
1799  }
1800  if ($shipping_method_id<0) $shipping_method_id='NULL';
1801  dol_syslog(get_class($this).'::setShippingMethod('.$shipping_method_id.')');
1802 
1803  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1804  $sql.= " SET fk_shipping_method = ".$shipping_method_id;
1805  $sql.= " WHERE rowid=".$this->id;
1806 
1807  if ($this->db->query($sql)) {
1808  $this->shipping_method_id = ($shipping_method_id=='NULL')?null:$shipping_method_id;
1809  return 1;
1810  } else {
1811  dol_syslog(get_class($this).'::setShippingMethod Error ', LOG_DEBUG);
1812  $this->error=$this->db->error();
1813  return 0;
1814  }
1815  }
1816 
1817 
1824  function setWarehouse($warehouse_id)
1825  {
1826  if (! $this->table_element) {
1827  dol_syslog(get_class($this)."::setWarehouse was called on objet with property table_element not defined",LOG_ERR);
1828  return -1;
1829  }
1830  if ($warehouse_id<0) $warehouse_id='NULL';
1831  dol_syslog(get_class($this).'::setWarehouse('.$warehouse_id.')');
1832 
1833  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1834  $sql.= " SET fk_warehouse = ".$warehouse_id;
1835  $sql.= " WHERE rowid=".$this->id;
1836 
1837  if ($this->db->query($sql)) {
1838  $this->warehouse_id = ($warehouse_id=='NULL')?null:$warehouse_id;
1839  return 1;
1840  } else {
1841  dol_syslog(get_class($this).'::setWarehouse Error ', LOG_DEBUG);
1842  $this->error=$this->db->error();
1843  return 0;
1844  }
1845  }
1846 
1847 
1855  function setDocModel($user, $modelpdf)
1856  {
1857  if (! $this->table_element)
1858  {
1859  dol_syslog(get_class($this)."::setDocModel was called on objet with property table_element not defined",LOG_ERR);
1860  return -1;
1861  }
1862 
1863  $newmodelpdf=dol_trunc($modelpdf,255);
1864 
1865  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1866  $sql.= " SET model_pdf = '".$this->db->escape($newmodelpdf)."'";
1867  $sql.= " WHERE rowid = ".$this->id;
1868  // if ($this->element == 'facture') $sql.= " AND fk_statut < 2";
1869  // if ($this->element == 'propal') $sql.= " AND fk_statut = 0";
1870 
1871  dol_syslog(get_class($this)."::setDocModel", LOG_DEBUG);
1872  $resql=$this->db->query($sql);
1873  if ($resql)
1874  {
1875  $this->modelpdf=$modelpdf;
1876  return 1;
1877  }
1878  else
1879  {
1880  dol_print_error($this->db);
1881  return 0;
1882  }
1883  }
1884 
1885 
1892  function setBankAccount($fk_account)
1893  {
1894  if (! $this->table_element) {
1895  dol_syslog(get_class($this)."::setBankAccount was called on objet with property table_element not defined",LOG_ERR);
1896  return -1;
1897  }
1898  if ($fk_account<0) $fk_account='NULL';
1899  dol_syslog(get_class($this).'::setBankAccount('.$fk_account.')');
1900 
1901  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1902  $sql.= " SET fk_account = ".$fk_account;
1903  $sql.= " WHERE rowid=".$this->id;
1904 
1905  if ($this->db->query($sql)) {
1906  $this->fk_account = ($fk_account=='NULL')?null:$fk_account;
1907  return 1;
1908  } else {
1909  dol_syslog(get_class($this).'::setBankAccount Error '.$sql.' - '.$this->db->error());
1910  $this->error=$this->db->error();
1911  return 0;
1912  }
1913  }
1914 
1915  // TODO: Move line related operations to CommonObjectLine?
1916 
1926  function line_order($renum=false, $rowidorder='ASC', $fk_parent_line=true)
1927  {
1928  if (! $this->table_element_line)
1929  {
1930  dol_syslog(get_class($this)."::line_order was called on objet with property table_element_line not defined",LOG_ERR);
1931  return -1;
1932  }
1933  if (! $this->fk_element)
1934  {
1935  dol_syslog(get_class($this)."::line_order was called on objet with property fk_element not defined",LOG_ERR);
1936  return -1;
1937  }
1938 
1939  // Count number of lines to reorder (according to choice $renum)
1940  $nl=0;
1941  $sql = 'SELECT count(rowid) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
1942  $sql.= ' WHERE '.$this->fk_element.'='.$this->id;
1943  if (! $renum) $sql.= ' AND rang = 0';
1944  if ($renum) $sql.= ' AND rang <> 0';
1945 
1946  dol_syslog(get_class($this)."::line_order", LOG_DEBUG);
1947  $resql = $this->db->query($sql);
1948  if ($resql)
1949  {
1950  $row = $this->db->fetch_row($resql);
1951  $nl = $row[0];
1952  }
1953  else dol_print_error($this->db);
1954  if ($nl > 0)
1955  {
1956  // The goal of this part is to reorder all lines, with all children lines sharing the same
1957  // counter that parents.
1958  $rows=array();
1959 
1960  // We first search all lines that are parent lines (for multilevel details lines)
1961  $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
1962  $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
1963  if ($fk_parent_line) $sql.= ' AND fk_parent_line IS NULL';
1964  $sql.= ' ORDER BY rang ASC, rowid '.$rowidorder;
1965 
1966  dol_syslog(get_class($this)."::line_order search all parent lines", LOG_DEBUG);
1967  $resql = $this->db->query($sql);
1968  if ($resql)
1969  {
1970  $i=0;
1971  $num = $this->db->num_rows($resql);
1972  while ($i < $num)
1973  {
1974  $row = $this->db->fetch_row($resql);
1975  $rows[] = $row[0]; // Add parent line into array rows
1976  $childrens = $this->getChildrenOfLine($row[0]);
1977  if (! empty($childrens))
1978  {
1979  foreach($childrens as $child)
1980  {
1981  array_push($rows, $child);
1982  }
1983  }
1984  $i++;
1985  }
1986 
1987  // Now we set a new number for each lines (parent and children with children included into parent tree)
1988  if (! empty($rows))
1989  {
1990  foreach($rows as $key => $row)
1991  {
1992  $this->updateRangOfLine($row, ($key+1));
1993  }
1994  }
1995  }
1996  else
1997  {
1998  dol_print_error($this->db);
1999  }
2000  }
2001  return 1;
2002  }
2003 
2010  function getChildrenOfLine($id)
2011  {
2012  $rows=array();
2013 
2014  $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2015  $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2016  $sql.= ' AND fk_parent_line = '.$id;
2017  $sql.= ' ORDER BY rang ASC';
2018 
2019  dol_syslog(get_class($this)."::getChildrenOfLine search children lines for line ".$id."", LOG_DEBUG);
2020  $resql = $this->db->query($sql);
2021  if ($resql)
2022  {
2023  $i=0;
2024  $num = $this->db->num_rows($resql);
2025  while ($i < $num)
2026  {
2027  $row = $this->db->fetch_row($resql);
2028  $rows[$i] = $row[0];
2029  $i++;
2030  }
2031  }
2032 
2033  return $rows;
2034  }
2035 
2043  function line_up($rowid, $fk_parent_line=true)
2044  {
2045  $this->line_order(false, 'ASC', $fk_parent_line);
2046 
2047  // Get rang of line
2048  $rang = $this->getRangOfLine($rowid);
2049 
2050  // Update position of line
2051  $this->updateLineUp($rowid, $rang);
2052  }
2053 
2061  function line_down($rowid, $fk_parent_line=true)
2062  {
2063  $this->line_order(false, 'ASC', $fk_parent_line);
2064 
2065  // Get rang of line
2066  $rang = $this->getRangOfLine($rowid);
2067 
2068  // Get max value for rang
2069  $max = $this->line_max();
2070 
2071  // Update position of line
2072  $this->updateLineDown($rowid, $rang, $max);
2073  }
2074 
2082  function updateRangOfLine($rowid,$rang)
2083  {
2084  $fieldposition = 'rang';
2085  if ($this->table_element_line == 'ecm_files') $fieldposition = 'position';
2086 
2087  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang;
2088  $sql.= ' WHERE rowid = '.$rowid;
2089 
2090  dol_syslog(get_class($this)."::updateRangOfLine", LOG_DEBUG);
2091  if (! $this->db->query($sql))
2092  {
2093  dol_print_error($this->db);
2094  }
2095  }
2096 
2103  function line_ajaxorder($rows)
2104  {
2105  $num = count($rows);
2106  for ($i = 0 ; $i < $num ; $i++)
2107  {
2108  $this->updateRangOfLine($rows[$i], ($i+1));
2109  }
2110  }
2111 
2119  function updateLineUp($rowid,$rang)
2120  {
2121  if ($rang > 1 )
2122  {
2123  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET rang = '.$rang ;
2124  $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2125  $sql.= ' AND rang = '.($rang - 1);
2126  if ($this->db->query($sql) )
2127  {
2128  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET rang = '.($rang - 1);
2129  $sql.= ' WHERE rowid = '.$rowid;
2130  if (! $this->db->query($sql) )
2131  {
2132  dol_print_error($this->db);
2133  }
2134  }
2135  else
2136  {
2137  dol_print_error($this->db);
2138  }
2139  }
2140  }
2141 
2150  function updateLineDown($rowid,$rang,$max)
2151  {
2152  if ($rang < $max)
2153  {
2154  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET rang = '.$rang;
2155  $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2156  $sql.= ' AND rang = '.($rang+1);
2157  if ($this->db->query($sql) )
2158  {
2159  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET rang = '.($rang+1);
2160  $sql.= ' WHERE rowid = '.$rowid;
2161  if (! $this->db->query($sql) )
2162  {
2163  dol_print_error($this->db);
2164  }
2165  }
2166  else
2167  {
2168  dol_print_error($this->db);
2169  }
2170  }
2171  }
2172 
2179  function getRangOfLine($rowid)
2180  {
2181  $sql = 'SELECT rang FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2182  $sql.= ' WHERE rowid ='.$rowid;
2183 
2184  dol_syslog(get_class($this)."::getRangOfLine", LOG_DEBUG);
2185  $resql = $this->db->query($sql);
2186  if ($resql)
2187  {
2188  $row = $this->db->fetch_row($resql);
2189  return $row[0];
2190  }
2191  }
2192 
2199  function getIdOfLine($rang)
2200  {
2201  $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2202  $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2203  $sql.= ' AND rang = '.$rang;
2204  $resql = $this->db->query($sql);
2205  if ($resql)
2206  {
2207  $row = $this->db->fetch_row($resql);
2208  return $row[0];
2209  }
2210  }
2211 
2218  function line_max($fk_parent_line=0)
2219  {
2220  // Search the last rang with fk_parent_line
2221  if ($fk_parent_line)
2222  {
2223  $sql = 'SELECT max(rang) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2224  $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2225  $sql.= ' AND fk_parent_line = '.$fk_parent_line;
2226 
2227  dol_syslog(get_class($this)."::line_max", LOG_DEBUG);
2228  $resql = $this->db->query($sql);
2229  if ($resql)
2230  {
2231  $row = $this->db->fetch_row($resql);
2232  if (! empty($row[0]))
2233  {
2234  return $row[0];
2235  }
2236  else
2237  {
2238  return $this->getRangOfLine($fk_parent_line);
2239  }
2240  }
2241  }
2242  // If not, search the last rang of element
2243  else
2244  {
2245  $sql = 'SELECT max(rang) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2246  $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2247 
2248  dol_syslog(get_class($this)."::line_max", LOG_DEBUG);
2249  $resql = $this->db->query($sql);
2250  if ($resql)
2251  {
2252  $row = $this->db->fetch_row($resql);
2253  return $row[0];
2254  }
2255  }
2256  }
2257 
2264  function update_ref_ext($ref_ext)
2265  {
2266  if (! $this->table_element)
2267  {
2268  dol_syslog(get_class($this)."::update_ref_ext was called on objet with property table_element not defined", LOG_ERR);
2269  return -1;
2270  }
2271 
2272  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2273  $sql.= " SET ref_ext = '".$this->db->escape($ref_ext)."'";
2274  $sql.= " WHERE ".(isset($this->table_rowid)?$this->table_rowid:'rowid')." = ". $this->id;
2275 
2276  dol_syslog(get_class($this)."::update_ref_ext", LOG_DEBUG);
2277  if ($this->db->query($sql))
2278  {
2279  $this->ref_ext = $ref_ext;
2280  return 1;
2281  }
2282  else
2283  {
2284  $this->error=$this->db->error();
2285  return -1;
2286  }
2287  }
2288 
2296  function update_note($note,$suffix='')
2297  {
2298  global $user;
2299 
2300  if (! $this->table_element)
2301  {
2302  dol_syslog(get_class($this)."::update_note was called on objet with property table_element not defined", LOG_ERR);
2303  return -1;
2304  }
2305  if (! in_array($suffix,array('','_public','_private')))
2306  {
2307  dol_syslog(get_class($this)."::update_note Parameter suffix must be empty, '_private' or '_public'", LOG_ERR);
2308  return -2;
2309  }
2310  // Special cas
2311  //var_dump($this->table_element);exit;
2312  if ($this->table_element == 'product') $suffix='';
2313 
2314  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2315  $sql.= " SET note".$suffix." = ".(!empty($note)?("'".$this->db->escape($note)."'"):"NULL");
2316  $sql.= " ,".(in_array($this->table_element, array('actioncomm', 'adherent', 'advtargetemailing', 'cronjob', 'establishment'))?"fk_user_mod":"fk_user_modif")." = ".$user->id;
2317  $sql.= " WHERE rowid =". $this->id;
2318 
2319  dol_syslog(get_class($this)."::update_note", LOG_DEBUG);
2320  if ($this->db->query($sql))
2321  {
2322  if ($suffix == '_public') $this->note_public = $note;
2323  else if ($suffix == '_private') $this->note_private = $note;
2324  else
2325  {
2326  $this->note = $note; // deprecated
2327  $this->note_private = $note;
2328  }
2329  return 1;
2330  }
2331  else
2332  {
2333  $this->error=$this->db->lasterror();
2334  return -1;
2335  }
2336  }
2337 
2346  function update_note_public($note)
2347  {
2348  return $this->update_note($note,'_public');
2349  }
2350 
2361  function update_price($exclspec=0,$roundingadjust='none',$nodatabaseupdate=0,$seller=null)
2362  {
2363  global $conf;
2364 
2365  // Some external module want no update price after a trigger because they have another method to calculate the total (ex: with an extrafield)
2366  $MODULE = "";
2367  if ($this->element == 'propal')
2368  $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_PROPOSAL";
2369  elseif ($this->element == 'order')
2370  $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_ORDER";
2371  elseif ($this->element == 'facture')
2372  $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_INVOICE";
2373  elseif ($this->element == 'facture_fourn')
2374  $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_INVOICE";
2375  elseif ($this->element == 'order_supplier')
2376  $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_ORDER";
2377  elseif ($this->element == 'supplier_proposal')
2378  $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_PROPOSAL";
2379 
2380  if (! empty($MODULE)) {
2381  if (! empty($conf->global->$MODULE)) {
2382  $modsactivated = explode(',', $conf->global->$MODULE);
2383  foreach ($modsactivated as $mod) {
2384  if ($conf->$mod->enabled)
2385  return 1; // update was disabled by specific setup
2386  }
2387  }
2388  }
2389 
2390  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2391 
2392  if ($roundingadjust == '-1') $roundingadjust='auto'; // For backward compatibility
2393 
2394  $forcedroundingmode=$roundingadjust;
2395  if ($forcedroundingmode == 'auto' && isset($conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND)) $forcedroundingmode=$conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND;
2396  elseif ($forcedroundingmode == 'auto') $forcedroundingmode='0';
2397 
2398  $error=0;
2399 
2400  $multicurrency_tx = !empty($this->multicurrency_tx) ? $this->multicurrency_tx : 1;
2401 
2402  // Define constants to find lines to sum
2403  $fieldtva='total_tva';
2404  $fieldlocaltax1='total_localtax1';
2405  $fieldlocaltax2='total_localtax2';
2406  $fieldup='subprice';
2407  if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier')
2408  {
2409  $fieldtva='tva';
2410  $fieldup='pu_ht';
2411  }
2412  if ($this->element == 'expensereport')
2413  {
2414  $fieldup='value_unit';
2415  }
2416 
2417  $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,';
2418  $sql.= ' tva_tx as vatrate, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, info_bits, product_type';
2419  if ($this->table_element_line == 'facturedet') $sql.= ', situation_percent';
2420  $sql.= ', multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
2421  $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2422  $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2423  if ($exclspec)
2424  {
2425  $product_field='product_type';
2426  if ($this->table_element_line == 'contratdet') $product_field=''; // contratdet table has no product_type field
2427  if ($product_field) $sql.= ' AND '.$product_field.' <> 9';
2428  }
2429  $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
2430 
2431  dol_syslog(get_class($this)."::update_price", LOG_DEBUG);
2432  $resql = $this->db->query($sql);
2433  if ($resql)
2434  {
2435  $this->total_ht = 0;
2436  $this->total_tva = 0;
2437  $this->total_localtax1 = 0;
2438  $this->total_localtax2 = 0;
2439  $this->total_ttc = 0;
2440  $total_ht_by_vats = array();
2441  $total_tva_by_vats = array();
2442  $total_ttc_by_vats = array();
2443  $this->multicurrency_total_ht = 0;
2444  $this->multicurrency_total_tva = 0;
2445  $this->multicurrency_total_ttc = 0;
2446 
2447  $num = $this->db->num_rows($resql);
2448  $i = 0;
2449  while ($i < $num)
2450  {
2451  $obj = $this->db->fetch_object($resql);
2452 
2453  // Note: There is no check on detail line and no check on total, if $forcedroundingmode = 'none'
2454  if ($forcedroundingmode == '0') // Check if data on line are consistent. This may solve lines that were not consistent because set with $forcedroundingmode='auto'
2455  {
2456  $localtax_array=array($obj->localtax1_type,$obj->localtax1_tx,$obj->localtax2_type,$obj->localtax2_tx);
2457  $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);
2458  $diff=price2num($tmpcal[1] - $obj->total_tva, 'MT', 1);
2459  if ($diff)
2460  {
2461  $sqlfix="UPDATE ".MAIN_DB_PREFIX.$this->table_element_line." SET ".$fieldtva." = ".$tmpcal[1].", total_ttc = ".$tmpcal[2]." WHERE rowid = ".$obj->rowid;
2462  dol_syslog('We found unconsistent data into detailed line (difference of '.$diff.') 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);
2463  $resqlfix=$this->db->query($sqlfix);
2464  if (! $resqlfix) dol_print_error($this->db,'Failed to update line');
2465  $obj->total_tva = $tmpcal[1];
2466  $obj->total_ttc = $tmpcal[2];
2467  //
2468  }
2469  }
2470 
2471  $this->total_ht += $obj->total_ht; // The field visible at end of line detail
2472  $this->total_tva += $obj->total_tva;
2473  $this->total_localtax1 += $obj->total_localtax1;
2474  $this->total_localtax2 += $obj->total_localtax2;
2475  $this->total_ttc += $obj->total_ttc;
2476  $this->multicurrency_total_ht += $obj->multicurrency_total_ht; // The field visible at end of line detail
2477  $this->multicurrency_total_tva += $obj->multicurrency_total_tva;
2478  $this->multicurrency_total_ttc += $obj->multicurrency_total_ttc;
2479 
2480  if (! isset($total_ht_by_vats[$obj->vatrate])) $total_ht_by_vats[$obj->vatrate]=0;
2481  if (! isset($total_tva_by_vats[$obj->vatrate])) $total_tva_by_vats[$obj->vatrate]=0;
2482  if (! isset($total_ttc_by_vats[$obj->vatrate])) $total_ttc_by_vats[$obj->vatrate]=0;
2483  $total_ht_by_vats[$obj->vatrate] += $obj->total_ht;
2484  $total_tva_by_vats[$obj->vatrate] += $obj->total_tva;
2485  $total_ttc_by_vats[$obj->vatrate] += $obj->total_ttc;
2486 
2487  if ($forcedroundingmode == '1') // Check if we need adjustement onto line for vat. TODO This works on the company currency but not on multicurrency
2488  {
2489  $tmpvat=price2num($total_ht_by_vats[$obj->vatrate] * $obj->vatrate / 100, 'MT', 1);
2490  $diff=price2num($total_tva_by_vats[$obj->vatrate]-$tmpvat, 'MT', 1);
2491  //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";
2492  if ($diff)
2493  {
2494  if (abs($diff) > 0.1) { dol_syslog('A rounding difference was detected into TOTAL but is too high to be corrected', LOG_WARNING); exit; }
2495  $sqlfix="UPDATE ".MAIN_DB_PREFIX.$this->table_element_line." SET ".$fieldtva." = ".($obj->total_tva - $diff).", total_ttc = ".($obj->total_ttc - $diff)." WHERE rowid = ".$obj->rowid;
2496  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);
2497  $resqlfix=$this->db->query($sqlfix);
2498  if (! $resqlfix) dol_print_error($this->db,'Failed to update line');
2499  $this->total_tva -= $diff;
2500  $this->total_ttc -= $diff;
2501  $total_tva_by_vats[$obj->vatrate] -= $diff;
2502  $total_ttc_by_vats[$obj->vatrate] -= $diff;
2503 
2504  }
2505  }
2506 
2507  $i++;
2508  }
2509 
2510  // Add revenue stamp to total
2511  $this->total_ttc += isset($this->revenuestamp)?$this->revenuestamp:0;
2512  $this->multicurrency_total_ttc += isset($this->revenuestamp)?($this->revenuestamp * $multicurrency_tx):0;
2513 
2514  // Situations totals
2515  if ($this->situation_cycle_ref && $this->situation_counter > 1 && method_exists($this, 'get_prev_sits'))
2516  {
2517  $prev_sits = $this->get_prev_sits();
2518 
2519  foreach ($prev_sits as $sit) { // $sit is an object Facture loaded with a fetch.
2520  $this->total_ht -= $sit->total_ht;
2521  $this->total_tva -= $sit->total_tva;
2522  $this->total_localtax1 -= $sit->total_localtax1;
2523  $this->total_localtax2 -= $sit->total_localtax2;
2524  $this->total_ttc -= $sit->total_ttc;
2525  $this->multicurrency_total_ht -= $sit->multicurrency_total_ht;
2526  $this->multicurrency_total_tva -= $sit->multicurrency_total_tva;
2527  $this->multicurrency_total_ttc -= $sit->multicurrency_total_ttc;
2528  }
2529  }
2530 
2531  $this->db->free($resql);
2532 
2533  // Now update global field total_ht, total_ttc and tva
2534  $fieldht='total_ht';
2535  $fieldtva='tva';
2536  $fieldlocaltax1='localtax1';
2537  $fieldlocaltax2='localtax2';
2538  $fieldttc='total_ttc';
2539  // Specific code for backward compatibility with old field names
2540  if ($this->element == 'facture' || $this->element == 'facturerec') $fieldht='total';
2541  if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') $fieldtva='total_tva';
2542  if ($this->element == 'propal') $fieldttc='total';
2543  if ($this->element == 'expensereport') $fieldtva='total_tva';
2544  if ($this->element == 'supplier_proposal') $fieldttc='total';
2545 
2546  if (empty($nodatabaseupdate))
2547  {
2548  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET';
2549  $sql .= " ".$fieldht."='".price2num($this->total_ht)."',";
2550  $sql .= " ".$fieldtva."='".price2num($this->total_tva)."',";
2551  $sql .= " ".$fieldlocaltax1."='".price2num($this->total_localtax1)."',";
2552  $sql .= " ".$fieldlocaltax2."='".price2num($this->total_localtax2)."',";
2553  $sql .= " ".$fieldttc."='".price2num($this->total_ttc)."'";
2554  $sql .= ", multicurrency_total_ht='".price2num($this->multicurrency_total_ht, 'MT', 1)."'";
2555  $sql .= ", multicurrency_total_tva='".price2num($this->multicurrency_total_tva, 'MT', 1)."'";
2556  $sql .= ", multicurrency_total_ttc='".price2num($this->multicurrency_total_ttc, 'MT', 1)."'";
2557  $sql .= ' WHERE rowid = '.$this->id;
2558 
2559  //print "xx".$sql;
2560  dol_syslog(get_class($this)."::update_price", LOG_DEBUG);
2561  $resql=$this->db->query($sql);
2562  if (! $resql)
2563  {
2564  $error++;
2565  $this->error=$this->db->lasterror();
2566  $this->errors[]=$this->db->lasterror();
2567  }
2568  }
2569 
2570  if (! $error)
2571  {
2572  return 1;
2573  }
2574  else
2575  {
2576  return -1;
2577  }
2578  }
2579  else
2580  {
2581  dol_print_error($this->db,'Bad request in update_price');
2582  return -1;
2583  }
2584  }
2585 
2594  function add_object_linked($origin=null, $origin_id=null)
2595  {
2596  $origin = (! empty($origin) ? $origin : $this->origin);
2597  $origin_id = (! empty($origin_id) ? $origin_id : $this->origin_id);
2598 
2599  // Special case
2600  if ($origin == 'order') $origin='commande';
2601  if ($origin == 'invoice') $origin='facture';
2602 
2603  $this->db->begin();
2604 
2605  $sql = "INSERT INTO ".MAIN_DB_PREFIX."element_element (";
2606  $sql.= "fk_source";
2607  $sql.= ", sourcetype";
2608  $sql.= ", fk_target";
2609  $sql.= ", targettype";
2610  $sql.= ") VALUES (";
2611  $sql.= $origin_id;
2612  $sql.= ", '".$this->db->escape($origin)."'";
2613  $sql.= ", ".$this->id;
2614  $sql.= ", '".$this->db->escape($this->element)."'";
2615  $sql.= ")";
2616 
2617  dol_syslog(get_class($this)."::add_object_linked", LOG_DEBUG);
2618  if ($this->db->query($sql))
2619  {
2620  $this->db->commit();
2621  return 1;
2622  }
2623  else
2624  {
2625  $this->error=$this->db->lasterror();
2626  $this->db->rollback();
2627  return 0;
2628  }
2629  }
2630 
2649  function fetchObjectLinked($sourceid=null,$sourcetype='',$targetid=null,$targettype='',$clause='OR',$alsosametype=1)
2650  {
2651  global $conf;
2652 
2653  $this->linkedObjectsIds=array();
2654  $this->linkedObjects=array();
2655 
2656  $justsource=false;
2657  $justtarget=false;
2658  $withtargettype=false;
2659  $withsourcetype=false;
2660 
2661  if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid))
2662  {
2663  $justsource=true; // the source (id and type) is a search criteria
2664  if (! empty($targettype)) $withtargettype=true;
2665  }
2666  if (! empty($targetid) && ! empty($targettype) && empty($sourceid))
2667  {
2668  $justtarget=true; // the target (id and type) is a search criteria
2669  if (! empty($sourcetype)) $withsourcetype=true;
2670  }
2671 
2672  $sourceid = (! empty($sourceid) ? $sourceid : $this->id);
2673  $targetid = (! empty($targetid) ? $targetid : $this->id);
2674  $sourcetype = (! empty($sourcetype) ? $sourcetype : $this->element);
2675  $targettype = (! empty($targettype) ? $targettype : $this->element);
2676 
2677  /*if (empty($sourceid) && empty($targetid))
2678  {
2679  dol_syslog('Bad usage of function. No source nor target id defined (nor as parameter nor as object id)', LOG_ERR);
2680  return -1;
2681  }*/
2682 
2683  // Links between objects are stored in table element_element
2684  $sql = 'SELECT rowid, fk_source, sourcetype, fk_target, targettype';
2685  $sql.= ' FROM '.MAIN_DB_PREFIX.'element_element';
2686  $sql.= " WHERE ";
2687  if ($justsource || $justtarget)
2688  {
2689  if ($justsource)
2690  {
2691  $sql.= "fk_source = ".$sourceid." AND sourcetype = '".$sourcetype."'";
2692  if ($withtargettype) $sql.= " AND targettype = '".$targettype."'";
2693  }
2694  else if ($justtarget)
2695  {
2696  $sql.= "fk_target = ".$targetid." AND targettype = '".$targettype."'";
2697  if ($withsourcetype) $sql.= " AND sourcetype = '".$sourcetype."'";
2698  }
2699  }
2700  else
2701  {
2702  $sql.= "(fk_source = ".$sourceid." AND sourcetype = '".$sourcetype."')";
2703  $sql.= " ".$clause." (fk_target = ".$targetid." AND targettype = '".$targettype."')";
2704  }
2705  $sql .= ' ORDER BY sourcetype';
2706  //print $sql;
2707 
2708  dol_syslog(get_class($this)."::fetchObjectLink", LOG_DEBUG);
2709  $resql = $this->db->query($sql);
2710  if ($resql)
2711  {
2712  $num = $this->db->num_rows($resql);
2713  $i = 0;
2714  while ($i < $num)
2715  {
2716  $obj = $this->db->fetch_object($resql);
2717  if ($justsource || $justtarget)
2718  {
2719  if ($justsource)
2720  {
2721  $this->linkedObjectsIds[$obj->targettype][$obj->rowid]=$obj->fk_target;
2722  }
2723  else if ($justtarget)
2724  {
2725  $this->linkedObjectsIds[$obj->sourcetype][$obj->rowid]=$obj->fk_source;
2726  }
2727  }
2728  else
2729  {
2730  if ($obj->fk_source == $sourceid && $obj->sourcetype == $sourcetype)
2731  {
2732  $this->linkedObjectsIds[$obj->targettype][$obj->rowid]=$obj->fk_target;
2733  }
2734  if ($obj->fk_target == $targetid && $obj->targettype == $targettype)
2735  {
2736  $this->linkedObjectsIds[$obj->sourcetype][$obj->rowid]=$obj->fk_source;
2737  }
2738  }
2739  $i++;
2740  }
2741 
2742  if (! empty($this->linkedObjectsIds))
2743  {
2744  foreach($this->linkedObjectsIds as $objecttype => $objectids) // $objecttype is a module name ('facture', 'mymodule', ...) or a module name with a suffix ('project_task', 'mymodule_myobj', ...)
2745  {
2746  // Parse element/subelement (ex: project_task, cabinetmed_consultation, ...)
2747  $module = $element = $subelement = $objecttype;
2748  if ($objecttype != 'supplier_proposal' && $objecttype != 'order_supplier' && $objecttype != 'invoice_supplier'
2749  && preg_match('/^([^_]+)_([^_]+)/i',$objecttype,$regs))
2750  {
2751  $module = $element = $regs[1];
2752  $subelement = $regs[2];
2753  }
2754 
2755  $classpath = $element.'/class';
2756  // To work with non standard classpath or module name
2757  if ($objecttype == 'facture') {
2758  $classpath = 'compta/facture/class';
2759  }
2760  else if ($objecttype == 'facturerec') {
2761  $classpath = 'compta/facture/class'; $module = 'facture';
2762  }
2763  else if ($objecttype == 'propal') {
2764  $classpath = 'comm/propal/class';
2765  }
2766  else if ($objecttype == 'supplier_proposal') {
2767  $classpath = 'supplier_proposal/class';
2768  }
2769  else if ($objecttype == 'shipping') {
2770  $classpath = 'expedition/class'; $subelement = 'expedition'; $module = 'expedition_bon';
2771  }
2772  else if ($objecttype == 'delivery') {
2773  $classpath = 'livraison/class'; $subelement = 'livraison'; $module = 'livraison_bon';
2774  }
2775  else if ($objecttype == 'invoice_supplier' || $objecttype == 'order_supplier') {
2776  $classpath = 'fourn/class'; $module = 'fournisseur';
2777  }
2778  else if ($objecttype == 'fichinter') {
2779  $classpath = 'fichinter/class'; $subelement = 'fichinter'; $module = 'ficheinter';
2780  }
2781  else if ($objecttype == 'subscription') {
2782  $classpath = 'adherents/class'; $module = 'adherent';
2783  }
2784 
2785  // Set classfile
2786  $classfile = strtolower($subelement); $classname = ucfirst($subelement);
2787 
2788  if ($objecttype == 'order') {
2789  $classfile = 'commande'; $classname = 'Commande';
2790  }
2791  else if ($objecttype == 'invoice_supplier') {
2792  $classfile = 'fournisseur.facture'; $classname = 'FactureFournisseur';
2793  }
2794  else if ($objecttype == 'order_supplier') {
2795  $classfile = 'fournisseur.commande'; $classname = 'CommandeFournisseur';
2796  }
2797  else if ($objecttype == 'supplier_proposal') {
2798  $classfile = 'supplier_proposal'; $classname = 'SupplierProposal';
2799  }
2800  else if ($objecttype == 'facturerec') {
2801  $classfile = 'facture-rec'; $classname = 'FactureRec';
2802  }
2803  else if ($objecttype == 'subscription') {
2804  $classfile = 'subscription'; $classname = 'Subscription';
2805  }
2806 
2807  // Here $module, $classfile and $classname are set
2808  if ($conf->$module->enabled && (($element != $this->element) || $alsosametype))
2809  {
2810  dol_include_once('/'.$classpath.'/'.$classfile.'.class.php');
2811  //print '/'.$classpath.'/'.$classfile.'.class.php '.class_exists($classname);
2812  if (class_exists($classname))
2813  {
2814  foreach($objectids as $i => $objectid) // $i is rowid into llx_element_element
2815  {
2816  $object = new $classname($this->db);
2817  $ret = $object->fetch($objectid);
2818  if ($ret >= 0)
2819  {
2820  $this->linkedObjects[$objecttype][$i] = $object;
2821  }
2822  }
2823  }
2824  }
2825  }
2826  }
2827  }
2828  else
2829  {
2830  dol_print_error($this->db);
2831  }
2832  }
2833 
2844  function updateObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='')
2845  {
2846  $updatesource=false;
2847  $updatetarget=false;
2848 
2849  if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid) && empty($targettype)) $updatesource=true;
2850  else if (empty($sourceid) && empty($sourcetype) && ! empty($targetid) && ! empty($targettype)) $updatetarget=true;
2851 
2852  $sql = "UPDATE ".MAIN_DB_PREFIX."element_element SET ";
2853  if ($updatesource)
2854  {
2855  $sql.= "fk_source = ".$sourceid;
2856  $sql.= ", sourcetype = '".$this->db->escape($sourcetype)."'";
2857  $sql.= " WHERE fk_target = ".$this->id;
2858  $sql.= " AND targettype = '".$this->db->escape($this->element)."'";
2859  }
2860  else if ($updatetarget)
2861  {
2862  $sql.= "fk_target = ".$targetid;
2863  $sql.= ", targettype = '".$this->db->escape($targettype)."'";
2864  $sql.= " WHERE fk_source = ".$this->id;
2865  $sql.= " AND sourcetype = '".$this->db->escape($this->element)."'";
2866  }
2867 
2868  dol_syslog(get_class($this)."::updateObjectLinked", LOG_DEBUG);
2869  if ($this->db->query($sql))
2870  {
2871  return 1;
2872  }
2873  else
2874  {
2875  $this->error=$this->db->lasterror();
2876  return -1;
2877  }
2878  }
2879 
2891  function deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid='')
2892  {
2893  $deletesource=false;
2894  $deletetarget=false;
2895 
2896  if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid) && empty($targettype)) $deletesource=true;
2897  else if (empty($sourceid) && empty($sourcetype) && ! empty($targetid) && ! empty($targettype)) $deletetarget=true;
2898 
2899  $sourceid = (! empty($sourceid) ? $sourceid : $this->id);
2900  $sourcetype = (! empty($sourcetype) ? $sourcetype : $this->element);
2901  $targetid = (! empty($targetid) ? $targetid : $this->id);
2902  $targettype = (! empty($targettype) ? $targettype : $this->element);
2903 
2904  $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_element";
2905  $sql.= " WHERE";
2906  if ($rowid > 0)
2907  {
2908  $sql.=" rowid = ".$rowid;
2909  }
2910  else
2911  {
2912  if ($deletesource)
2913  {
2914  $sql.= " fk_source = ".$sourceid." AND sourcetype = '".$this->db->escape($sourcetype)."'";
2915  $sql.= " AND fk_target = ".$this->id." AND targettype = '".$this->db->escape($this->element)."'";
2916  }
2917  else if ($deletetarget)
2918  {
2919  $sql.= " fk_target = ".$targetid." AND targettype = '".$this->db->escape($targettype)."'";
2920  $sql.= " AND fk_source = ".$this->id." AND sourcetype = '".$this->db->escape($this->element)."'";
2921  }
2922  else
2923  {
2924  $sql.= " (fk_source = ".$this->id." AND sourcetype = '".$this->db->escape($this->element)."')";
2925  $sql.= " OR";
2926  $sql.= " (fk_target = ".$this->id." AND targettype = '".$this->db->escape($this->element)."')";
2927  }
2928  }
2929 
2930  dol_syslog(get_class($this)."::deleteObjectLinked", LOG_DEBUG);
2931  if ($this->db->query($sql))
2932  {
2933  return 1;
2934  }
2935  else
2936  {
2937  $this->error=$this->db->lasterror();
2938  $this->errors[]=$this->error;
2939  return -1;
2940  }
2941  }
2942 
2951  function setStatut($status,$elementId=null,$elementType='')
2952  {
2953  global $user,$langs,$conf;
2954 
2955  $savElementId=$elementId; // To be used later to know if we were using the method using the id of this or not.
2956 
2957  $elementId = (!empty($elementId)?$elementId:$this->id);
2958  $elementTable = (!empty($elementType)?$elementType:$this->table_element);
2959 
2960  $this->db->begin();
2961 
2962  $fieldstatus="fk_statut";
2963  if ($elementTable == 'mailing') $fieldstatus="statut";
2964  if ($elementTable == 'user') $fieldstatus="statut";
2965  if ($elementTable == 'expensereport') $fieldstatus="fk_statut";
2966  if ($elementTable == 'commande_fournisseur_dispatch') $fieldstatus="status";
2967 
2968  $sql = "UPDATE ".MAIN_DB_PREFIX.$elementTable;
2969  $sql.= " SET ".$fieldstatus." = ".$status;
2970  // If status = 1 = validated, update also fk_user_valid
2971  if ($status == 1 && $elementTable == 'expensereport') $sql.=", fk_user_valid = ".$user->id;
2972  $sql.= " WHERE rowid=".$elementId;
2973 
2974  dol_syslog(get_class($this)."::setStatut", LOG_DEBUG);
2975  if ($this->db->query($sql))
2976  {
2977  $error = 0;
2978 
2979  $trigkey='';
2980  if ($this->element == 'supplier_proposal' && $status == 2) $trigkey='SUPPLIER_PROPOSAL_SIGN'; // 2 = SupplierProposal::STATUS_SIGNED. Can't use constant into this generic class
2981  if ($this->element == 'supplier_proposal' && $status == 3) $trigkey='SUPPLIER_PROPOSAL_REFUSE'; // 3 = SupplierProposal::STATUS_REFUSED. Can't use constant into this generic class
2982  if ($this->element == 'supplier_proposal' && $status == 4) $trigkey='SUPPLIER_PROPOSAL_CLOSE'; // 4 = SupplierProposal::STATUS_CLOSED. Can't use constant into this generic class
2983  if ($this->element == 'fichinter' && $status == 3) $trigkey='FICHINTER_CLASSIFY_DONE';
2984  if ($this->element == 'fichinter' && $status == 2) $trigkey='FICHINTER_CLASSIFY_BILLED';
2985  if ($this->element == 'fichinter' && $status == 1) $trigkey='FICHINTER_CLASSIFY_UNBILLED';
2986 
2987  if ($trigkey)
2988  {
2989  // Appel des triggers
2990  include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
2991  $interface=new Interfaces($this->db);
2992  $result=$interface->run_triggers($trigkey,$this,$user,$langs,$conf);
2993  if ($result < 0) {
2994  $error++; $this->errors=$interface->errors;
2995  }
2996  // Fin appel triggers
2997  }
2998 
2999  if (! $error)
3000  {
3001  $this->db->commit();
3002 
3003  if (empty($savElementId)) // If the element we update was $this (so $elementId is null)
3004  {
3005  $this->statut = $status;
3006  $this->status = $status;
3007  }
3008 
3009  return 1;
3010  }
3011  else
3012  {
3013  $this->db->rollback();
3014  dol_syslog(get_class($this)."::setStatus ".$this->error,LOG_ERR);
3015  return -1;
3016  }
3017  }
3018  else
3019  {
3020  $this->error=$this->db->lasterror();
3021  $this->db->rollback();
3022  return -1;
3023  }
3024  }
3025 
3026 
3034  function getCanvas($id=0,$ref='')
3035  {
3036  global $conf;
3037 
3038  if (empty($id) && empty($ref)) return 0;
3039  if (! empty($conf->global->MAIN_DISABLE_CANVAS)) return 0; // To increase speed. Not enabled by default.
3040 
3041  // Clean parameters
3042  $ref = trim($ref);
3043 
3044  $sql = "SELECT rowid, canvas";
3045  $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element;
3046  $sql.= " WHERE entity IN (".getEntity($this->element).")";
3047  if (! empty($id)) $sql.= " AND rowid = ".$id;
3048  if (! empty($ref)) $sql.= " AND ref = '".$this->db->escape($ref)."'";
3049 
3050  $resql = $this->db->query($sql);
3051  if ($resql)
3052  {
3053  $obj = $this->db->fetch_object($resql);
3054  if ($obj)
3055  {
3056  $this->canvas = $obj->canvas;
3057  return 1;
3058  }
3059  else return 0;
3060  }
3061  else
3062  {
3063  dol_print_error($this->db);
3064  return -1;
3065  }
3066  }
3067 
3068 
3075  function getSpecialCode($lineid)
3076  {
3077  $sql = 'SELECT special_code FROM '.MAIN_DB_PREFIX.$this->table_element_line;
3078  $sql.= ' WHERE rowid = '.$lineid;
3079  $resql = $this->db->query($sql);
3080  if ($resql)
3081  {
3082  $row = $this->db->fetch_row($resql);
3083  return $row[0];
3084  }
3085  }
3086 
3094  function isObjectUsed($id=0)
3095  {
3096  global $langs;
3097 
3098  if (empty($id)) $id=$this->id;
3099 
3100  // Check parameters
3101  if (! isset($this->childtables) || ! is_array($this->childtables) || count($this->childtables) == 0)
3102  {
3103  dol_print_error('Called isObjectUsed on a class with property this->childtables not defined');
3104  return -1;
3105  }
3106 
3107  $arraytoscan = $this->childtables;
3108  // For backward compatibility, we check if array is old format array('table1', 'table2', ...)
3109  $tmparray=array_keys($this->childtables);
3110  if (is_numeric($tmparray[0]))
3111  {
3112  $arraytoscan = array_flip($this->childtables);
3113  }
3114 
3115  // Test if child exists
3116  $haschild=0;
3117  foreach($arraytoscan as $table => $elementname)
3118  {
3119  //print $id.'-'.$table.'-'.$elementname.'<br>';
3120  // Check if third party can be deleted
3121  $sql = "SELECT COUNT(*) as nb from ".MAIN_DB_PREFIX.$table;
3122  $sql.= " WHERE ".$this->fk_element." = ".$id;
3123  $resql=$this->db->query($sql);
3124  if ($resql)
3125  {
3126  $obj=$this->db->fetch_object($resql);
3127  if ($obj->nb > 0)
3128  {
3129  $langs->load("errors");
3130  //print 'Found into table '.$table.', type '.$langs->transnoentitiesnoconv($elementname).', haschild='.$haschild;
3131  $haschild += $obj->nb;
3132  $this->errors[]=$langs->trans("ErrorRecordHasAtLeastOneChildOfType", $langs->transnoentitiesnoconv($elementname));
3133  break; // We found at least one, we stop here
3134  }
3135  }
3136  else
3137  {
3138  $this->errors[]=$this->db->lasterror();
3139  return -1;
3140  }
3141  }
3142  if ($haschild > 0)
3143  {
3144  $this->errors[]="ErrorRecordHasChildren";
3145  return $haschild;
3146  }
3147  else return 0;
3148  }
3149 
3156  function hasProductsOrServices($predefined=-1)
3157  {
3158  $nb=0;
3159 
3160  foreach($this->lines as $key => $val)
3161  {
3162  $qualified=0;
3163  if ($predefined == -1) $qualified=1;
3164  if ($predefined == 1 && $val->fk_product > 0) $qualified=1;
3165  if ($predefined == 0 && $val->fk_product <= 0) $qualified=1;
3166  if ($predefined == 2 && $val->fk_product > 0 && $val->product_type==0) $qualified=1;
3167  if ($predefined == 3 && $val->fk_product > 0 && $val->product_type==1) $qualified=1;
3168  if ($qualified) $nb++;
3169  }
3170  dol_syslog(get_class($this).'::hasProductsOrServices we found '.$nb.' qualified lines of products/servcies');
3171  return $nb;
3172  }
3173 
3179  function getTotalDiscount()
3180  {
3181  $total_discount=0.00;
3182 
3183  $sql = "SELECT subprice as pu_ht, qty, remise_percent, total_ht";
3184  $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element."det";
3185  $sql.= " WHERE ".$this->fk_element." = ".$this->id;
3186 
3187  dol_syslog(get_class($this).'::getTotalDiscount', LOG_DEBUG);
3188  $resql = $this->db->query($sql);
3189  if ($resql)
3190  {
3191  $num=$this->db->num_rows($resql);
3192  $i=0;
3193  while ($i < $num)
3194  {
3195  $obj = $this->db->fetch_object($resql);
3196 
3197  $pu_ht = $obj->pu_ht;
3198  $qty= $obj->qty;
3199  $total_ht = $obj->total_ht;
3200 
3201  $total_discount_line = floatval(price2num(($pu_ht * $qty) - $total_ht, 'MT'));
3202  $total_discount += $total_discount_line;
3203 
3204  $i++;
3205  }
3206  }
3207 
3208  //print $total_discount; exit;
3209  return price2num($total_discount);
3210  }
3211 
3212 
3219  function getTotalWeightVolume()
3220  {
3221  $totalWeight = 0;
3222  $totalVolume = 0;
3223  // defined for shipment only
3224  $totalOrdered = '';
3225  // defined for shipment only
3226  $totalToShip = '';
3227 
3228  foreach ($this->lines as $line)
3229  {
3230  if (isset($line->qty_asked))
3231  {
3232  if (empty($totalOrdered)) $totalOrdered=0; // Avoid warning because $totalOrdered is ''
3233  $totalOrdered+=$line->qty_asked; // defined for shipment only
3234  }
3235  if (isset($line->qty_shipped))
3236  {
3237  if (empty($totalToShip)) $totalToShip=0; // Avoid warning because $totalToShip is ''
3238  $totalToShip+=$line->qty_shipped; // defined for shipment only
3239  }
3240 
3241  // Define qty, weight, volume, weight_units, volume_units
3242  if ($this->element == 'shipping') {
3243  // for shipments
3244  $qty = $line->qty_shipped ? $line->qty_shipped : 0;
3245  }
3246  else {
3247  $qty = $line->qty ? $line->qty : 0;
3248  }
3249 
3250  $weight = $line->weight ? $line->weight : 0;
3251  $volume = $line->volume ? $line->volume : 0;
3252 
3253  $weight_units=$line->weight_units;
3254  $volume_units=$line->volume_units;
3255 
3256  $weightUnit=0;
3257  $volumeUnit=0;
3258  if (! empty($weight_units)) $weightUnit = $weight_units;
3259  if (! empty($volume_units)) $volumeUnit = $volume_units;
3260 
3261  if (empty($totalWeight)) $totalWeight=0; // Avoid warning because $totalWeight is ''
3262  if (empty($totalVolume)) $totalVolume=0; // Avoid warning because $totalVolume is ''
3263 
3264  //var_dump($line->volume_units);
3265  if ($weight_units < 50) // >50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch)
3266  {
3267  $trueWeightUnit=pow(10, $weightUnit);
3268  $totalWeight += $weight * $qty * $trueWeightUnit;
3269  }
3270  else {
3271  if ($weight_units == 99) {
3272  // conversion 1 Pound = 0.45359237 KG
3273  $trueWeightUnit = 0.45359237;
3274  $totalWeight += $weight * $qty * $trueWeightUnit;
3275  } elseif ($weight_units == 98) {
3276  // conversion 1 Ounce = 0.0283495 KG
3277  $trueWeightUnit = 0.0283495;
3278  $totalWeight += $weight * $qty * $trueWeightUnit;
3279  }
3280  else
3281  $totalWeight += $weight * $qty; // This may be wrong if we mix different units
3282  }
3283  if ($volume_units < 50) // >50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch)
3284  {
3285  //print $line->volume."x".$line->volume_units."x".($line->volume_units < 50)."x".$volumeUnit;
3286  $trueVolumeUnit=pow(10, $volumeUnit);
3287  //print $line->volume;
3288  $totalVolume += $volume * $qty * $trueVolumeUnit;
3289  }
3290  else
3291  {
3292  $totalVolume += $volume * $qty; // This may be wrong if we mix different units
3293  }
3294  }
3295 
3296  return array('weight'=>$totalWeight, 'volume'=>$totalVolume, 'ordered'=>$totalOrdered, 'toship'=>$totalToShip);
3297  }
3298 
3299 
3305  function setExtraParameters()
3306  {
3307  $this->db->begin();
3308 
3309  $extraparams = (! empty($this->extraparams) ? json_encode($this->extraparams) : null);
3310 
3311  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
3312  $sql.= " SET extraparams = ".(! empty($extraparams) ? "'".$this->db->escape($extraparams)."'" : "null");
3313  $sql.= " WHERE rowid = ".$this->id;
3314 
3315  dol_syslog(get_class($this)."::setExtraParameters", LOG_DEBUG);
3316  $resql = $this->db->query($sql);
3317  if (! $resql)
3318  {
3319  $this->error=$this->db->lasterror();
3320  $this->db->rollback();
3321  return -1;
3322  }
3323  else
3324  {
3325  $this->db->commit();
3326  return 1;
3327  }
3328  }
3329 
3330 
3337  function display_incoterms()
3338  {
3339  $out = '';
3340  $this->libelle_incoterms = '';
3341  if (!empty($this->fk_incoterms))
3342  {
3343  $sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms;
3344  $result = $this->db->query($sql);
3345  if ($result)
3346  {
3347  $res = $this->db->fetch_object($result);
3348  $out .= $res->code;
3349  }
3350  }
3351 
3352  $out .= (($res->code && $this->location_incoterms)?' - ':'').$this->location_incoterms;
3353 
3354  return $out;
3355  }
3356 
3362  function getIncotermsForPDF()
3363  {
3364  $sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms;
3365  $resql = $this->db->query($sql);
3366  if ($resql)
3367  {
3368  $num = $this->db->num_rows($resql);
3369  if ($num > 0)
3370  {
3371  $res = $this->db->fetch_object($resql);
3372  return 'Incoterm : '.$res->code.' - '.$this->location_incoterms;
3373  }
3374  else
3375  {
3376  return '';
3377  }
3378  }
3379  else
3380  {
3381  $this->errors[] = $this->db->lasterror();
3382  return false;
3383  }
3384  }
3385 
3393  function setIncoterms($id_incoterm, $location)
3394  {
3395  if ($this->id && $this->table_element)
3396  {
3397  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
3398  $sql.= " SET fk_incoterms = ".($id_incoterm > 0 ? $id_incoterm : "null");
3399  $sql.= ", location_incoterms = ".($id_incoterm > 0 ? "'".$this->db->escape($location)."'" : "null");
3400  $sql.= " WHERE rowid = " . $this->id;
3401  dol_syslog(get_class($this).'::setIncoterms', LOG_DEBUG);
3402  $resql=$this->db->query($sql);
3403  if ($resql)
3404  {
3405  $this->fk_incoterms = $id_incoterm;
3406  $this->location_incoterms = $location;
3407 
3408  $sql = 'SELECT libelle FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms;
3409  $res = $this->db->query($sql);
3410  if ($res)
3411  {
3412  $obj = $this->db->fetch_object($res);
3413  $this->libelle_incoterms = $obj->libelle;
3414  }
3415  return 1;
3416  }
3417  else
3418  {
3419  $this->errors[] = $this->db->lasterror();
3420  return -1;
3421  }
3422  }
3423  else return -1;
3424  }
3425 
3426 
3433  function isInEEC()
3434  {
3435  require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
3436  return isInEEC($this);
3437  }
3438 
3439 
3440  // --------------------
3441  // TODO: All functions here must be redesigned and moved as they are not business functions but output functions
3442  // --------------------
3443 
3444  /* This is to show add lines */
3445 
3454  function formAddObjectLine($dateSelector,$seller,$buyer)
3455  {
3456  global $conf,$user,$langs,$object,$hookmanager;
3457  global $form,$bcnd,$var;
3458 
3459  //Line extrafield
3460  require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
3461  $extrafieldsline = new ExtraFields($this->db);
3462  $extralabelslines=$extrafieldsline->fetch_name_optionals_label($this->table_element_line);
3463 
3464  // Output template part (modules that overwrite templates must declare this into descriptor)
3465  // Use global variables + $dateSelector + $seller and $buyer
3466  $dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
3467  foreach($dirtpls as $reldir)
3468  {
3469  $tpl = dol_buildpath($reldir.'/objectline_create.tpl.php');
3470  if (empty($conf->file->strict_mode)) {
3471  $res=@include $tpl;
3472  } else {
3473  $res=include $tpl; // for debug
3474  }
3475  if ($res) break;
3476  }
3477  }
3478 
3479 
3480 
3481  /* This is to show array of line of details */
3482 
3483 
3497  function printObjectLines($action, $seller, $buyer, $selected=0, $dateSelector=0)
3498  {
3499  global $conf, $hookmanager, $langs, $user;
3500  // TODO We should not use global var for this !
3501  global $inputalsopricewithtax, $usemargins, $disableedit, $disablemove, $disableremove, $outputalsopricetotalwithtax;
3502 
3503  // Define usemargins
3504  $usemargins=0;
3505  if (! empty($conf->margin->enabled) && ! empty($this->element) && in_array($this->element,array('facture','propal','commande'))) $usemargins=1;
3506 
3507  $num = count($this->lines);
3508 
3509  //Line extrafield
3510  require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
3511  $extrafieldsline = new ExtraFields($this->db);
3512  $extralabelslines=$extrafieldsline->fetch_name_optionals_label($this->table_element_line);
3513 
3514  $parameters = array('num'=>$num,'i'=>$i,'dateSelector'=>$dateSelector,'seller'=>$seller,'buyer'=>$buyer,'selected'=>$selected, 'extrafieldsline'=>$extrafieldsline);
3515  $reshook = $hookmanager->executeHooks('printObjectLineTitle', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3516  if (empty($reshook))
3517  {
3518  print '<tr class="liste_titre nodrag nodrop">';
3519 
3520  if (! empty($conf->global->MAIN_VIEW_LINE_NUMBER)) print '<td class="linecolnum" align="center" width="5">&nbsp;</td>';
3521 
3522  // Description
3523  print '<td class="linecoldescription">'.$langs->trans('Description').'</td>';
3524 
3525  if ($this->element == 'supplier_proposal' || $this->element == 'order_supplier' || $this->element == 'invoice_supplier')
3526  {
3527  print '<td class="linerefsupplier"><span id="title_fourn_ref">'.$langs->trans("SupplierRef").'</span></td>';
3528  }
3529 
3530  // VAT
3531  print '<td class="linecolvat" align="right" width="80">'.$langs->trans('VAT').'</td>';
3532 
3533  // Price HT
3534  print '<td class="linecoluht" align="right" width="80">'.$langs->trans('PriceUHT').'</td>';
3535 
3536  // Multicurrency
3537  if (!empty($conf->multicurrency->enabled)) print '<td class="linecoluht_currency" align="right" width="80">'.$langs->trans('PriceUHTCurrency', $this->multicurrency_code).'</td>';
3538 
3539  if ($inputalsopricewithtax) print '<td align="right" width="80">'.$langs->trans('PriceUTTC').'</td>';
3540 
3541  // Qty
3542  print '<td class="linecolqty" align="right">'.$langs->trans('Qty').'</td>';
3543 
3544  if($conf->global->PRODUCT_USE_UNITS)
3545  {
3546  print '<td class="linecoluseunit" align="left">'.$langs->trans('Unit').'</td>';
3547  }
3548 
3549  // Reduction short
3550  print '<td class="linecoldiscount" align="right">'.$langs->trans('ReductionShort').'</td>';
3551 
3552  if ($this->situation_cycle_ref) {
3553  print '<td class="linecolcycleref" align="right">' . $langs->trans('Progress') . '</td>';
3554  }
3555 
3556  if ($usemargins && ! empty($conf->margin->enabled) && empty($user->societe_id))
3557  {
3558  if (!empty($user->rights->margins->creer))
3559  {
3560  if ($conf->global->MARGIN_TYPE == "1")
3561  print '<td class="linecolmargin1 margininfos" align="right" width="80">'.$langs->trans('BuyingPrice').'</td>';
3562  else
3563  print '<td class="linecolmargin1 margininfos" align="right" width="80">'.$langs->trans('CostPrice').'</td>';
3564  }
3565 
3566  if (! empty($conf->global->DISPLAY_MARGIN_RATES) && $user->rights->margins->liretous)
3567  print '<td class="linecolmargin2 margininfos" align="right" width="50">'.$langs->trans('MarginRate').'</td>';
3568  if (! empty($conf->global->DISPLAY_MARK_RATES) && $user->rights->margins->liretous)
3569  print '<td class="linecolmargin2 margininfos" align="right" width="50">'.$langs->trans('MarkRate').'</td>';
3570  }
3571 
3572  // Total HT
3573  print '<td class="linecolht" align="right">'.$langs->trans('TotalHTShort').'</td>';
3574 
3575  // Multicurrency
3576  if (!empty($conf->multicurrency->enabled)) print '<td class="linecoltotalht_currency" align="right">'.$langs->trans('TotalHTShortCurrency', $this->multicurrency_code).'</td>';
3577 
3578  if ($outputalsopricetotalwithtax) print '<td align="right" width="80">'.$langs->trans('TotalTTCShort').'</td>';
3579 
3580  print '<td class="linecoledit"></td>'; // No width to allow autodim
3581 
3582  print '<td class="linecoldelete" width="10"></td>';
3583 
3584  print '<td class="linecolmove" width="10"></td>';
3585 
3586  print "</tr>\n";
3587  }
3588 
3589  $var = true;
3590  $i = 0;
3591 
3592  foreach ($this->lines as $line)
3593  {
3594  //Line extrafield
3595  $line->fetch_optionals($line->id,$extralabelslines);
3596 
3597 
3598 
3599  //if (is_object($hookmanager) && (($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line)))
3600  if (is_object($hookmanager)) // Old code is commented on preceding line.
3601  {
3602  if (empty($line->fk_parent_line))
3603  {
3604  $parameters = array('line'=>$line,'var'=>$var,'num'=>$num,'i'=>$i,'dateSelector'=>$dateSelector,'seller'=>$seller,'buyer'=>$buyer,'selected'=>$selected, 'extrafieldsline'=>$extrafieldsline);
3605  $reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3606  }
3607  else
3608  {
3609  $parameters = array('line'=>$line,'var'=>$var,'num'=>$num,'i'=>$i,'dateSelector'=>$dateSelector,'seller'=>$seller,'buyer'=>$buyer,'selected'=>$selected, 'extrafieldsline'=>$extrafieldsline, 'fk_parent_line'=>$line->fk_parent_line);
3610  $reshook = $hookmanager->executeHooks('printObjectSubLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3611  }
3612  }
3613  if (empty($reshook))
3614  {
3615  $this->printObjectLine($action,$line,$var,$num,$i,$dateSelector,$seller,$buyer,$selected,$extrafieldsline);
3616  }
3617 
3618  $i++;
3619  }
3620  }
3621 
3638  function printObjectLine($action,$line,$var,$num,$i,$dateSelector,$seller,$buyer,$selected=0,$extrafieldsline=0)
3639  {
3640  global $conf,$langs,$user,$object,$hookmanager;
3641  global $form,$bc,$bcdd;
3642  global $object_rights, $disableedit, $disablemove; // TODO We should not use global var for this !
3643 
3644  $object_rights = $this->getRights();
3645 
3646  $element=$this->element;
3647 
3648  $text=''; $description=''; $type=0;
3649 
3650  // Show product and description
3651  $type=(! empty($line->product_type)?$line->product_type:$line->fk_product_type);
3652  // Try to enhance type detection using date_start and date_end for free lines where type was not saved.
3653  if (! empty($line->date_start)) $type=1; // deprecated
3654  if (! empty($line->date_end)) $type=1; // deprecated
3655 
3656  // Ligne en mode visu
3657  if ($action != 'editline' || $selected != $line->id)
3658  {
3659  // Product
3660  if ($line->fk_product > 0)
3661  {
3662  $product_static = new Product($this->db);
3663  $product_static->fetch($line->fk_product);
3664 
3665  $product_static->ref = $line->ref; //can change ref in hook
3666  $product_static->label = $line->label; //can change label in hook
3667  $text=$product_static->getNomUrl(1);
3668 
3669  // Define output language and label
3670  if (! empty($conf->global->MAIN_MULTILANGS))
3671  {
3672  if (! is_object($this->thirdparty))
3673  {
3674  dol_print_error('','Error: Method printObjectLine was called on an object and object->fetch_thirdparty was not done before');
3675  return;
3676  }
3677 
3678  $prod = new Product($this->db);
3679  $prod->fetch($line->fk_product);
3680 
3681  $outputlangs = $langs;
3682  $newlang='';
3683  if (empty($newlang) && GETPOST('lang_id','aZ09')) $newlang=GETPOST('lang_id','aZ09');
3684  if (! empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE) && empty($newlang)) $newlang=$this->thirdparty->default_lang; // For language to language of customer
3685  if (! empty($newlang))
3686  {
3687  $outputlangs = new Translate("",$conf);
3688  $outputlangs->setDefaultLang($newlang);
3689  }
3690 
3691  $label = (! empty($prod->multilangs[$outputlangs->defaultlang]["label"])) ? $prod->multilangs[$outputlangs->defaultlang]["label"] : $line->product_label;
3692  }
3693  else
3694  {
3695  $label = $line->product_label;
3696  }
3697 
3698  $text.= ' - '.(! empty($line->label)?$line->label:$label);
3699  $description.=(! empty($conf->global->PRODUIT_DESC_IN_FORM)?'':dol_htmlentitiesbr($line->description)); // Description is what to show on popup. We shown nothing if already into desc.
3700  }
3701 
3702  $line->pu_ttc = price2num($line->subprice * (1 + ($line->tva_tx/100)), 'MU');
3703 
3704  // Output template part (modules that overwrite templates must declare this into descriptor)
3705  // Use global variables + $dateSelector + $seller and $buyer
3706  $dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
3707  foreach($dirtpls as $reldir)
3708  {
3709  $tpl = dol_buildpath($reldir.'/objectline_view.tpl.php');
3710  if (empty($conf->file->strict_mode)) {
3711  $res=@include $tpl;
3712  } else {
3713  $res=include $tpl; // for debug
3714  }
3715  if ($res) break;
3716  }
3717  }
3718 
3719  // Ligne en mode update
3720  if ($this->statut == 0 && $action == 'editline' && $selected == $line->id)
3721  {
3722  $label = (! empty($line->label) ? $line->label : (($line->fk_product > 0) ? $line->product_label : ''));
3723  $placeholder=' placeholder="'.$langs->trans("Label").'"';
3724 
3725  $line->pu_ttc = price2num($line->subprice * (1 + ($line->tva_tx/100)), 'MU');
3726 
3727  // Output template part (modules that overwrite templates must declare this into descriptor)
3728  // Use global variables + $dateSelector + $seller and $buyer
3729  $dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
3730  foreach($dirtpls as $reldir)
3731  {
3732  $tpl = dol_buildpath($reldir.'/objectline_edit.tpl.php');
3733  if (empty($conf->file->strict_mode)) {
3734  $res=@include $tpl;
3735  } else {
3736  $res=include $tpl; // for debug
3737  }
3738  if ($res) break;
3739  }
3740  }
3741  }
3742 
3743 
3744  /* This is to show array of line of details of source object */
3745 
3746 
3756  function printOriginLinesList($restrictlist='')
3757  {
3758  global $langs, $hookmanager, $conf;
3759 
3760  print '<tr class="liste_titre">';
3761  print '<td>'.$langs->trans('Ref').'</td>';
3762  print '<td>'.$langs->trans('Description').'</td>';
3763  print '<td align="right">'.$langs->trans('VATRate').'</td>';
3764  print '<td align="right">'.$langs->trans('PriceUHT').'</td>';
3765  if (!empty($conf->multicurrency->enabled)) print '<td align="right">'.$langs->trans('PriceUHTCurrency').'</td>';
3766  print '<td align="right">'.$langs->trans('Qty').'</td>';
3767  if($conf->global->PRODUCT_USE_UNITS)
3768  {
3769  print '<td align="left">'.$langs->trans('Unit').'</td>';
3770  }
3771  print '<td align="right">'.$langs->trans('ReductionShort').'</td></tr>';
3772 
3773  $var = true;
3774  $i = 0;
3775 
3776  foreach ($this->lines as $line)
3777  {
3778  if (is_object($hookmanager) && (($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line)))
3779  {
3780  if (empty($line->fk_parent_line))
3781  {
3782  $parameters=array('line'=>$line,'var'=>$var,'i'=>$i);
3783  $action='';
3784  $hookmanager->executeHooks('printOriginObjectLine',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks
3785  }
3786  }
3787  else
3788  {
3789  $this->printOriginLine($line, $var, $restrictlist);
3790  }
3791 
3792  $i++;
3793  }
3794  }
3795 
3807  function printOriginLine($line, $var, $restrictlist='')
3808  {
3809  global $langs, $conf;
3810 
3811  //var_dump($line);
3812  if (!empty($line->date_start))
3813  {
3814  $date_start=$line->date_start;
3815  }
3816  else
3817  {
3818  $date_start=$line->date_debut_prevue;
3819  if ($line->date_debut_reel) $date_start=$line->date_debut_reel;
3820  }
3821  if (!empty($line->date_end))
3822  {
3823  $date_end=$line->date_end;
3824  }
3825  else
3826  {
3827  $date_end=$line->date_fin_prevue;
3828  if ($line->date_fin_reel) $date_end=$line->date_fin_reel;
3829  }
3830 
3831  $this->tpl['label'] = '';
3832  if (! empty($line->fk_parent_line)) $this->tpl['label'].= img_picto('', 'rightarrow');
3833 
3834  if (($line->info_bits & 2) == 2) // TODO Not sure this is used for source object
3835  {
3836  $discount=new DiscountAbsolute($this->db);
3837  $discount->fk_soc = $this->socid;
3838  $this->tpl['label'].= $discount->getNomUrl(0,'discount');
3839  }
3840  else if (! empty($line->fk_product))
3841  {
3842  $productstatic = new Product($this->db);
3843  $productstatic->id = $line->fk_product;
3844  $productstatic->ref = $line->ref;
3845  $productstatic->type = $line->fk_product_type;
3846  $this->tpl['label'].= $productstatic->getNomUrl(1);
3847  $this->tpl['label'].= ' - '.(! empty($line->label)?$line->label:$line->product_label);
3848  // Dates
3849  if ($line->product_type == 1 && ($date_start || $date_end))
3850  {
3851  $this->tpl['label'].= get_date_range($date_start,$date_end);
3852  }
3853  }
3854  else
3855  {
3856  $this->tpl['label'].= ($line->product_type == -1 ? '&nbsp;' : ($line->product_type == 1 ? img_object($langs->trans(''),'service') : img_object($langs->trans(''),'product')));
3857  if (!empty($line->desc)) {
3858  $this->tpl['label'].=$line->desc;
3859  }else {
3860  $this->tpl['label'].= ($line->label ? '&nbsp;'.$line->label : '');
3861  }
3862  // Dates
3863  if ($line->product_type == 1 && ($date_start || $date_end))
3864  {
3865  $this->tpl['label'].= get_date_range($date_start,$date_end);
3866  }
3867  }
3868 
3869  if (! empty($line->desc))
3870  {
3871  if ($line->desc == '(CREDIT_NOTE)') // TODO Not sure this is used for source object
3872  {
3873  $discount=new DiscountAbsolute($this->db);
3874  $discount->fetch($line->fk_remise_except);
3875  $this->tpl['description'] = $langs->transnoentities("DiscountFromCreditNote",$discount->getNomUrl(0));
3876  }
3877  elseif ($line->desc == '(DEPOSIT)') // TODO Not sure this is used for source object
3878  {
3879  $discount=new DiscountAbsolute($this->db);
3880  $discount->fetch($line->fk_remise_except);
3881  $this->tpl['description'] = $langs->transnoentities("DiscountFromDeposit",$discount->getNomUrl(0));
3882  }
3883  elseif ($line->desc == '(EXCESS RECEIVED)')
3884  {
3885  $discount=new DiscountAbsolute($this->db);
3886  $discount->fetch($line->fk_remise_except);
3887  $this->tpl['description'] = $langs->transnoentities("DiscountFromExcessReceived",$discount->getNomUrl(0));
3888  }
3889  else
3890  {
3891  $this->tpl['description'] = dol_trunc($line->desc,60);
3892  }
3893  }
3894  else
3895  {
3896  $this->tpl['description'] = '&nbsp;';
3897  }
3898 
3899  // VAT Rate
3900  $this->tpl['vat_rate'] = vatrate($line->tva_tx, true);
3901  $this->tpl['vat_rate'] .= (($line->info_bits & 1) == 1) ? '*' : '';
3902  if (! empty($line->vat_src_code) && ! preg_match('/\(/', $this->tpl['vat_rate'])) $this->tpl['vat_rate'].=' ('.$line->vat_src_code.')';
3903 
3904  $this->tpl['price'] = price($line->subprice);
3905  $this->tpl['multicurrency_price'] = price($line->multicurrency_subprice);
3906  $this->tpl['qty'] = (($line->info_bits & 2) != 2) ? $line->qty : '&nbsp;';
3907  if ($conf->global->PRODUCT_USE_UNITS) $this->tpl['unit'] = $langs->transnoentities($line->getLabelOfUnit('long'));
3908  $this->tpl['remise_percent'] = (($line->info_bits & 2) != 2) ? vatrate($line->remise_percent, true) : '&nbsp;';
3909 
3910  // Is the line strike or not
3911  $this->tpl['strike']=0;
3912  if ($restrictlist == 'services' && $line->product_type != Product::TYPE_SERVICE) $this->tpl['strike']=1;
3913 
3914  // Output template part (modules that overwrite templates must declare this into descriptor)
3915  // Use global variables + $dateSelector + $seller and $buyer
3916  $dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
3917  foreach($dirtpls as $reldir)
3918  {
3919  $tpl = dol_buildpath($reldir.'/originproductline.tpl.php');
3920  if (empty($conf->file->strict_mode)) {
3921  $res=@include $tpl;
3922  } else {
3923  $res=include $tpl; // for debug
3924  }
3925  if ($res) break;
3926  }
3927  }
3928 
3929 
3940  function add_element_resource($resource_id, $resource_type, $busy=0, $mandatory=0)
3941  {
3942  $this->db->begin();
3943 
3944  $sql = "INSERT INTO ".MAIN_DB_PREFIX."element_resources (";
3945  $sql.= "resource_id";
3946  $sql.= ", resource_type";
3947  $sql.= ", element_id";
3948  $sql.= ", element_type";
3949  $sql.= ", busy";
3950  $sql.= ", mandatory";
3951  $sql.= ") VALUES (";
3952  $sql.= $resource_id;
3953  $sql.= ", '".$this->db->escape($resource_type)."'";
3954  $sql.= ", '".$this->db->escape($this->id)."'";
3955  $sql.= ", '".$this->db->escape($this->element)."'";
3956  $sql.= ", '".$this->db->escape($busy)."'";
3957  $sql.= ", '".$this->db->escape($mandatory)."'";
3958  $sql.= ")";
3959 
3960  dol_syslog(get_class($this)."::add_element_resource", LOG_DEBUG);
3961  if ($this->db->query($sql))
3962  {
3963  $this->db->commit();
3964  return 1;
3965  }
3966  else
3967  {
3968  $this->error=$this->db->lasterror();
3969  $this->db->rollback();
3970  return 0;
3971  }
3972  }
3973 
3982  function delete_resource($rowid, $element, $notrigger=0)
3983  {
3984  global $user;
3985 
3986  $this->db->begin();
3987 
3988  $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_resources";
3989  $sql.= " WHERE rowid=".$rowid;
3990 
3991  dol_syslog(get_class($this)."::delete_resource", LOG_DEBUG);
3992 
3993  $resql=$this->db->query($sql);
3994  if (! $resql)
3995  {
3996  $this->error=$this->db->lasterror();
3997  $this->db->rollback();
3998  return -1;
3999  }
4000  else
4001  {
4002  if (! $notrigger)
4003  {
4004  $result=$this->call_trigger(strtoupper($element).'_DELETE_RESOURCE', $user);
4005  if ($result < 0) { $this->db->rollback(); return -1; }
4006  }
4007  $this->db->commit();
4008  return 1;
4009  }
4010  }
4011 
4012 
4018  function __clone()
4019  {
4020  // Force a copy of this->lines, otherwise it will point to same object.
4021  if (isset($this->lines) && is_array($this->lines))
4022  {
4023  $nboflines=count($this->lines);
4024  for($i=0; $i < $nboflines; $i++)
4025  {
4026  $this->lines[$i] = clone $this->lines[$i];
4027  }
4028  }
4029  }
4030 
4043  protected function commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
4044  {
4045  global $conf, $langs, $user;
4046 
4047  $srctemplatepath='';
4048 
4049  // Increase limit for PDF build
4050  $err=error_reporting();
4051  error_reporting(0);
4052  @set_time_limit(120);
4053  error_reporting($err);
4054 
4055  // If selected model is a filename template (then $modele="modelname" or "modelname:filename")
4056  $tmp=explode(':',$modele,2);
4057  if (! empty($tmp[1]))
4058  {
4059  $modele=$tmp[0];
4060  $srctemplatepath=$tmp[1];
4061  }
4062 
4063  // Search template files
4064  $file=''; $classname=''; $filefound=0;
4065  $dirmodels=array('/');
4066  if (is_array($conf->modules_parts['models'])) $dirmodels=array_merge($dirmodels,$conf->modules_parts['models']);
4067  foreach($dirmodels as $reldir)
4068  {
4069  foreach(array('doc','pdf') as $prefix)
4070  {
4071  if (in_array(get_class($this), array('Adherent'))) $file = $prefix."_".$modele.".class.php"; // Member module use prefix_module.class.php
4072  else $file = $prefix."_".$modele.".modules.php";
4073 
4074  // On verifie l'emplacement du modele
4075  $file=dol_buildpath($reldir.$modelspath.$file,0);
4076  if (file_exists($file))
4077  {
4078  $filefound=1;
4079  $classname=$prefix.'_'.$modele;
4080  break;
4081  }
4082  }
4083  if ($filefound) break;
4084  }
4085 
4086  // If generator was found
4087  if ($filefound)
4088  {
4089  global $db; // Required to solve a conception default in commonstickergenerator.class.php making an include of code using $db
4090 
4091  require_once $file;
4092 
4093  $obj = new $classname($this->db);
4094 
4095  // If generator is ODT, we must have srctemplatepath defined, if not we set it.
4096  if ($obj->type == 'odt' && empty($srctemplatepath))
4097  {
4098  $varfortemplatedir=$obj->scandir;
4099  if ($varfortemplatedir && ! empty($conf->global->$varfortemplatedir))
4100  {
4101  $dirtoscan=$conf->global->$varfortemplatedir;
4102 
4103  $listoffiles=array();
4104 
4105  // Now we add first model found in directories scanned
4106  $listofdir=explode(',',$dirtoscan);
4107  foreach($listofdir as $key => $tmpdir)
4108  {
4109  $tmpdir=trim($tmpdir);
4110  $tmpdir=preg_replace('/DOL_DATA_ROOT/',DOL_DATA_ROOT,$tmpdir);
4111  if (! $tmpdir) { unset($listofdir[$key]); continue; }
4112  if (is_dir($tmpdir))
4113  {
4114  $tmpfiles=dol_dir_list($tmpdir,'files',0,'\.od(s|t)$','','name',SORT_ASC,0);
4115  if (count($tmpfiles)) $listoffiles=array_merge($listoffiles,$tmpfiles);
4116  }
4117  }
4118 
4119  if (count($listoffiles))
4120  {
4121  foreach($listoffiles as $record)
4122  {
4123  $srctemplatepath=$record['fullname'];
4124  break;
4125  }
4126  }
4127  }
4128 
4129  if (empty($srctemplatepath))
4130  {
4131  $this->error='ErrorGenerationAskedForOdtTemplateWithSrcFileNotDefined';
4132  return -1;
4133  }
4134  }
4135 
4136  if ($obj->type == 'odt' && ! empty($srctemplatepath))
4137  {
4138  if (! dol_is_file($srctemplatepath))
4139  {
4140  $this->error='ErrorGenerationAskedForOdtTemplateWithSrcFileNotFound';
4141  return -1;
4142  }
4143  }
4144 
4145  // We save charset_output to restore it because write_file can change it if needed for
4146  // output format that does not support UTF8.
4147  $sav_charset_output=$outputlangs->charset_output;
4148 
4149  if (in_array(get_class($this), array('Adherent')))
4150  {
4151  $arrayofrecords = array(); // The write_file of templates of adherent class need this var
4152  $resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, 'member', 1, $moreparams);
4153  }
4154  else
4155  {
4156  $resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, $hidedetails, $hidedesc, $hideref, $moreparams);
4157  }
4158  // After call of write_file $obj->result['fullpath'] is set with generated file. It will be used to update the ECM database index.
4159 
4160  if ($resultwritefile > 0)
4161  {
4162  $outputlangs->charset_output=$sav_charset_output;
4163 
4164  // We delete old preview
4165  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
4166  dol_delete_preview($this);
4167 
4168  // Index file in database
4169  if (! empty($obj->result['fullpath']))
4170  {
4171  $destfull = $obj->result['fullpath'];
4172  $upload_dir = dirname($destfull);
4173  $destfile = basename($destfull);
4174  $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $upload_dir);
4175 
4176  if (! preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir)) // If not a tmp dir
4177  {
4178  $filename = basename($destfile);
4179  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
4180  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
4181 
4182  include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
4183  $ecmfile=new EcmFiles($this->db);
4184  $result = $ecmfile->fetch(0, '', ($rel_dir?$rel_dir.'/':'').$filename);
4185 
4186  // Set the public "share" key
4187  $setsharekey = false;
4188  if ($this->element == 'propal')
4189  {
4190  $useonlinesignature = $conf->global->MAIN_FEATURES_LEVEL; // Replace this with 1 when feature to make online signature is ok
4191  if ($useonlinesignature) $setsharekey=true;
4192  if (! empty($conf->global->PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD)) $setsharekey=true;
4193  }
4194  if ($this->element == 'commande' && ! empty($conf->global->ORDER_ALLOW_EXTERNAL_DOWNLOAD)) $setsharekey=true;
4195  if ($this->element == 'facture' && ! empty($conf->global->INVOICE_ALLOW_EXTERNAL_DOWNLOAD)) $setsharekey=true;
4196  if ($setsharekey)
4197  {
4198  if (empty($ecmfile->share)) // Because object not found or share not set yet
4199  {
4200  require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
4201  $ecmfile->share = getRandomPassword(true);
4202  }
4203  }
4204 
4205  if ($result > 0)
4206  {
4207  $ecmfile->label = md5_file(dol_osencode($destfull)); // hash of file content
4208  $ecmfile->fullpath_orig = '';
4209  $ecmfile->gen_or_uploaded = 'generated';
4210  $ecmfile->description = ''; // indexed content
4211  $ecmfile->keyword = ''; // keyword content
4212  $result = $ecmfile->update($user);
4213  if ($result < 0)
4214  {
4215  setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
4216  }
4217  }
4218  else
4219  {
4220  $ecmfile->entity = $conf->entity;
4221  $ecmfile->filepath = $rel_dir;
4222  $ecmfile->filename = $filename;
4223  $ecmfile->label = md5_file(dol_osencode($destfull)); // hash of file content
4224  $ecmfile->fullpath_orig = '';
4225  $ecmfile->gen_or_uploaded = 'generated';
4226  $ecmfile->description = ''; // indexed content
4227  $ecmfile->keyword = ''; // keyword content
4228  $result = $ecmfile->create($user);
4229  if ($result < 0)
4230  {
4231  setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
4232  }
4233  }
4234 
4235  /*$this->result['fullname']=$destfull;
4236  $this->result['filepath']=$ecmfile->filepath;
4237  $this->result['filename']=$ecmfile->filename;*/
4238  //var_dump($obj->update_main_doc_field);exit;
4239 
4240  // Update the last_main_doc field into main object (if documenent generator has property ->update_main_doc_field set)
4241  $update_main_doc_field=0;
4242  if (! empty($obj->update_main_doc_field)) $update_main_doc_field=1;
4243  if ($update_main_doc_field && ! empty($this->table_element))
4244  {
4245  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element." SET last_main_doc = '".($ecmfile->filepath.'/'.$ecmfile->filename)."'";
4246  $sql.= ' WHERE rowid = '.$this->id;
4247  $resql = $this->db->query($sql);
4248  if (! $resql) dol_print_error($this->db);
4249  }
4250  }
4251  }
4252  else
4253  {
4254  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);
4255  }
4256 
4257  // Success in building document. We build meta file.
4258  dol_meta_create($this);
4259 
4260  return 1;
4261  }
4262  else
4263  {
4264  $outputlangs->charset_output=$sav_charset_output;
4265  dol_print_error($this->db, "Error generating document for ".__CLASS__.". Error: ".$obj->error, $obj->errors);
4266  return -1;
4267  }
4268 
4269  }
4270  else
4271  {
4272  $this->error=$langs->trans("Error")." ".$langs->trans("ErrorFileDoesNotExists",$file);
4273  dol_print_error('',$this->error);
4274  return -1;
4275  }
4276  }
4277 
4284  function addThumbs($file)
4285  {
4286  global $maxwidthsmall, $maxheightsmall, $maxwidthmini, $maxheightmini, $quality;
4287 
4288  require_once DOL_DOCUMENT_ROOT .'/core/lib/images.lib.php'; // This define also $maxwidthsmall, $quality, ...
4289 
4290  $file_osencoded=dol_osencode($file);
4291  if (file_exists($file_osencoded))
4292  {
4293  // Create small thumbs for company (Ratio is near 16/9)
4294  // Used on logon for example
4295  vignette($file_osencoded, $maxwidthsmall, $maxheightsmall, '_small', $quality);
4296 
4297  // Create mini thumbs for company (Ratio is near 16/9)
4298  // Used on menu or for setup page for example
4299  vignette($file_osencoded, $maxwidthmini, $maxheightmini, '_mini', $quality);
4300  }
4301  }
4302 
4303 
4304  /* Functions common to commonobject and commonobjectline */
4305 
4306  /* For default values */
4307 
4320  function getDefaultCreateValueFor($fieldname, $alternatevalue=null)
4321  {
4322  global $conf, $_POST;
4323 
4324  // If param here has been posted, we use this value first.
4325  if (isset($_POST[$fieldname])) return GETPOST($fieldname, 2);
4326 
4327  if (isset($alternatevalue)) return $alternatevalue;
4328 
4329  $newelement=$this->element;
4330  if ($newelement == 'facture') $newelement='invoice';
4331  if ($newelement == 'commande') $newelement='order';
4332  if (empty($newelement))
4333  {
4334  dol_syslog("Ask a default value using common method getDefaultCreateValueForField on an object with no property ->element defined. Return empty string.", LOG_WARNING);
4335  return '';
4336  }
4337 
4338  $keyforfieldname=strtoupper($newelement.'_DEFAULT_'.$fieldname);
4339  //var_dump($keyforfieldname);
4340  if (isset($conf->global->$keyforfieldname)) return $conf->global->$keyforfieldname;
4341 
4342  // TODO Ad here a scan into table llx_overwrite_default with a filter on $this->element and $fieldname
4343 
4344  }
4345 
4346 
4347  /* For triggers */
4348 
4349 
4360  function call_trigger($trigger_name, $user)
4361  {
4362  global $langs,$conf;
4363 
4364  include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
4365  $interface=new Interfaces($this->db);
4366  $result=$interface->run_triggers($trigger_name,$this,$user,$langs,$conf);
4367 
4368  if ($result < 0)
4369  {
4370  if (!empty($this->errors))
4371  {
4372  $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.
4373  }
4374  else
4375  {
4376  $this->errors=$interface->errors;
4377  }
4378  }
4379  return $result;
4380  }
4381 
4382 
4383  /* Functions for extrafields */
4384 
4385 
4394  function fetch_optionals($rowid=null,$optionsArray=null)
4395  {
4396  if (empty($rowid)) $rowid=$this->id;
4397 
4398  // To avoid SQL errors. Probably not the better solution though
4399  if (!$this->table_element) {
4400  return 0;
4401  }
4402 
4403  if (! is_array($optionsArray))
4404  {
4405  // If $extrafields is not a known object, we initialize it. Best practice is to have $extrafields defined into card.php or list.php page.
4406  // TODO Use of existing extrafield is not yet ready (must mutualize code that use extrafields in form first)
4407  // global $extrafields;
4408  //if (! is_object($extrafields))
4409  //{
4410  require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
4411  $extrafields = new ExtraFields($this->db);
4412  //}
4413 
4414  // Load array of extrafields for elementype = $this->table_element
4415  if (empty($extrafields->attributes[$this->table_element]['loaded']))
4416  {
4417  $extrafields->fetch_name_optionals_label($this->table_element);
4418  }
4419  $optionsArray = $extrafields->attributes[$this->table_element]['label'];
4420  }
4421 
4422  $table_element = $this->table_element;
4423  if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
4424 
4425  // Request to get complementary values
4426  if (is_array($optionsArray) && count($optionsArray) > 0)
4427  {
4428  $sql = "SELECT rowid";
4429  foreach ($optionsArray as $name => $label)
4430  {
4431  if (empty($extrafields->attributes[$this->table_element]['type'][$name]) || $extrafields->attributes[$this->table_element]['type'][$name] != 'separate')
4432  {
4433  $sql.= ", ".$name;
4434  }
4435  }
4436  $sql.= " FROM ".MAIN_DB_PREFIX.$table_element."_extrafields";
4437  $sql.= " WHERE fk_object = ".$rowid;
4438 
4439  dol_syslog(get_class($this)."::fetch_optionals get extrafields data for ".$this->table_element, LOG_DEBUG);
4440  $resql=$this->db->query($sql);
4441  if ($resql)
4442  {
4443  $numrows=$this->db->num_rows($resql);
4444  if ($numrows)
4445  {
4446  $tab = $this->db->fetch_array($resql);
4447 
4448  foreach ($tab as $key => $value)
4449  {
4450  // 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)
4451  if ($key != 'rowid' && $key != 'tms' && $key != 'fk_member' && ! is_int($key))
4452  {
4453  // we can add this attribute to object
4454  $this->array_options["options_".$key]=$value;
4455  }
4456  }
4457  }
4458 
4459  $this->db->free($resql);
4460 
4461  if ($numrows) return $numrows;
4462  else return 0;
4463  }
4464  else
4465  {
4466  dol_print_error($this->db);
4467  return -1;
4468  }
4469  }
4470  return 0;
4471  }
4472 
4478  function deleteExtraFields()
4479  {
4480  $this->db->begin();
4481 
4482  $table_element = $this->table_element;
4483  if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
4484 
4485  $sql_del = "DELETE FROM ".MAIN_DB_PREFIX.$table_element."_extrafields WHERE fk_object = ".$this->id;
4486  dol_syslog(get_class($this)."::deleteExtraFields delete", LOG_DEBUG);
4487  $resql=$this->db->query($sql_del);
4488  if (! $resql)
4489  {
4490  $this->error=$this->db->lasterror();
4491  $this->db->rollback();
4492  return -1;
4493  }
4494  else
4495  {
4496  $this->db->commit();
4497  return 1;
4498  }
4499  }
4500 
4510  function insertExtraFields($trigger='',$userused=null)
4511  {
4512  global $conf,$langs,$user;
4513 
4514  if (empty($userused)) $userused=$user;
4515 
4516  $error=0;
4517 
4518  if (! empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) return 0; // For avoid conflicts if trigger used
4519 
4520  if (! empty($this->array_options))
4521  {
4522  // Check parameters
4523  $langs->load('admin');
4524  require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
4525  $extrafields = new ExtraFields($this->db);
4526  $target_extrafields=$extrafields->fetch_name_optionals_label($this->table_element);
4527 
4528  //Eliminate copied source object extra_fields that do not exist in target object
4529  $new_array_options=array();
4530  foreach ($this->array_options as $key => $value) {
4531  if (in_array(substr($key,8), array_keys($target_extrafields))) // We remove the 'options_' from $key for test
4532  $new_array_options[$key] = $value;
4533  elseif (in_array($key, array_keys($target_extrafields))) // We test on $key that does not contains the 'options_' prefix
4534  $new_array_options['options_'.$key] = $value;
4535  }
4536 
4537  foreach($new_array_options as $key => $value)
4538  {
4539  $attributeKey = substr($key,8); // Remove 'options_' prefix
4540  $attributeType = $extrafields->attribute_type[$attributeKey];
4541  $attributeLabel = $extrafields->attribute_label[$attributeKey];
4542  $attributeParam = $extrafields->attribute_param[$attributeKey];
4543  switch ($attributeType)
4544  {
4545  case 'int':
4546  if (!is_numeric($value) && $value!='')
4547  {
4548  $this->errors[]=$langs->trans("ExtraFieldHasWrongValue",$attributeLabel);
4549  return -1;
4550  }
4551  elseif ($value=='')
4552  {
4553  $new_array_options[$key] = null;
4554  }
4555  break;
4556  /*case 'select': // Not required, we chosed value='0' for undefined values
4557  if ($value=='-1')
4558  {
4559  $this->array_options[$key] = null;
4560  }
4561  break;*/
4562  case 'price':
4563  $new_array_options[$key] = price2num($this->array_options[$key]);
4564  break;
4565  case 'date':
4566  $new_array_options[$key] = $this->db->idate($this->array_options[$key]);
4567  break;
4568  case 'datetime':
4569  $new_array_options[$key] = $this->db->idate($this->array_options[$key]);
4570  break;
4571  case 'link':
4572  $param_list=array_keys($attributeParam ['options']);
4573  // 0 : ObjectName
4574  // 1 : classPath
4575  $InfoFieldList = explode(":", $param_list[0]);
4576  dol_include_once($InfoFieldList[1]);
4577  if ($InfoFieldList[0] && class_exists($InfoFieldList[0]))
4578  {
4579  $object = new $InfoFieldList[0]($this->db);
4580  if ($value)
4581  {
4582  if (is_numeric($value)) $res=$object->fetch($value);
4583  else $res=$object->fetch('',$value);
4584 
4585  if ($res > 0) $new_array_options[$key]=$object->id;
4586  else
4587  {
4588  $this->error="Ref '".$value."' for object '".$object->element."' not found";
4589  $this->db->rollback();
4590  return -1;
4591  }
4592  }
4593  }
4594  else
4595  {
4596  dol_syslog('Error bad setup of extrafield', LOG_WARNING);
4597  }
4598  break;
4599  }
4600  }
4601  $this->db->begin();
4602 
4603  $table_element = $this->table_element;
4604  if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
4605 
4606  $sql_del = "DELETE FROM ".MAIN_DB_PREFIX.$table_element."_extrafields WHERE fk_object = ".$this->id;
4607  dol_syslog(get_class($this)."::insertExtraFields delete", LOG_DEBUG);
4608  $this->db->query($sql_del);
4609 
4610  $sql = "INSERT INTO ".MAIN_DB_PREFIX.$table_element."_extrafields (fk_object";
4611  foreach($new_array_options as $key => $value)
4612  {
4613  $attributeKey = substr($key,8); // Remove 'options_' prefix
4614  // Add field of attribut
4615  if ($extrafields->attribute_type[$attributeKey] != 'separate') // Only for other type of separate
4616  $sql.=",".$attributeKey;
4617  }
4618  $sql .= ") VALUES (".$this->id;
4619 
4620  foreach($new_array_options as $key => $value)
4621  {
4622  $attributeKey = substr($key,8); // Remove 'options_' prefix
4623  // Add field o fattribut
4624  if($extrafields->attribute_type[$attributeKey] != 'separate') // Only for other type of separate)
4625  {
4626  if ($new_array_options[$key] != '')
4627  {
4628  $sql.=",'".$this->db->escape($new_array_options[$key])."'";
4629  }
4630  else
4631  {
4632  $sql.=",null";
4633  }
4634  }
4635  }
4636  $sql.=")";
4637 
4638  dol_syslog(get_class($this)."::insertExtraFields insert", LOG_DEBUG);
4639  $resql = $this->db->query($sql);
4640  if (! $resql)
4641  {
4642  $this->error=$this->db->lasterror();
4643  $error++;
4644  }
4645  else
4646  {
4647  if ($trigger)
4648  {
4649  // Call trigger
4650  $this->context=array('extrafieldaddupdate'=>1);
4651  $result=$this->call_trigger($trigger, $userused);
4652  if ($result < 0) $error++;
4653  // End call trigger
4654  }
4655  }
4656 
4657  if ($error)
4658  {
4659  $this->db->rollback();
4660  return -1;
4661  }
4662  else
4663  {
4664  $this->db->commit();
4665  return 1;
4666  }
4667  }
4668  else return 0;
4669  }
4670 
4679  function updateExtraField($key)
4680  {
4681  global $conf,$langs;
4682 
4683  $error=0;
4684 
4685  if (! empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) return 0; // For avoid conflicts if trigger used
4686 
4687  if (! empty($this->array_options) && isset($this->array_options["options_".$key]))
4688  {
4689  // Check parameters
4690  $langs->load('admin');
4691  require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
4692  $extrafields = new ExtraFields($this->db);
4693  $target_extrafields=$extrafields->fetch_name_optionals_label($this->table_element);
4694 
4695  $value=$this->array_options["options_".$key];
4696  $attributeType = $extrafields->attribute_type[$key];
4697  $attributeLabel = $extrafields->attribute_label[$key];
4698  $attributeParam = $extrafields->attribute_param[$key];
4699  switch ($attributeType)
4700  {
4701  case 'int':
4702  if (!is_numeric($value) && $value!='')
4703  {
4704  $this->errors[]=$langs->trans("ExtraFieldHasWrongValue",$attributeLabel);
4705  return -1;
4706  }
4707  elseif ($value=='')
4708  {
4709  $this->array_options["options_".$key] = null;
4710  }
4711  break;
4712  /*case 'select': // Not required, we chosed value='0' for undefined values
4713  if ($value=='-1')
4714  {
4715  $this->array_options[$key] = null;
4716  }
4717  break;*/
4718  case 'price':
4719  $this->array_options["options_".$key] = price2num($this->array_options["options_".$key]);
4720  break;
4721  case 'date':
4722  $this->array_options["options_".$key]=$this->db->idate($this->array_options["options_".$key]);
4723  break;
4724  case 'datetime':
4725  $this->array_options["options_".$key]=$this->db->idate($this->array_options["options_".$key]);
4726  break;
4727  case 'link':
4728  $param_list=array_keys($attributeParam ['options']);
4729  // 0 : ObjectName
4730  // 1 : classPath
4731  $InfoFieldList = explode(":", $param_list[0]);
4732  dol_include_once($InfoFieldList[1]);
4733  $object = new $InfoFieldList[0]($this->db);
4734  if ($value)
4735  {
4736  $object->fetch(0,$value);
4737  $this->array_options["options_".$key]=$object->id;
4738  }
4739  break;
4740  }
4741 
4742  $this->db->begin();
4743  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element."_extrafields SET ".$key."='".$this->db->escape($this->array_options["options_".$key])."'";
4744  $sql .= " WHERE fk_object = ".$this->id;
4745  $resql = $this->db->query($sql);
4746  if (! $resql)
4747  {
4748  $this->error=$this->db->lasterror();
4749  $this->db->rollback();
4750  return -1;
4751  }
4752  else
4753  {
4754  $this->db->commit();
4755  return 1;
4756  }
4757  }
4758  else return 0;
4759  }
4760 
4761 
4775  function showInputField($val, $key, $value, $moreparam='', $keysuffix='', $keyprefix='', $showsize=0)
4776  {
4777  global $conf,$langs,$form;
4778 
4779  if (! is_object($form))
4780  {
4781  require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
4782  $form=new Form($this->db);
4783  }
4784 
4785  $objectid = $this->id;
4786 
4787  $label= $val['label'];
4788  $type = $val['type'];
4789  $size = $val['css'];
4790 
4791  // Convert var to be able to share same code than showInputField of extrafields
4792  if (preg_match('/varchar\((\d+)\)/', $type, $reg))
4793  {
4794  $type = 'varchar'; // convert varchar(xx) int varchar
4795  $size = $reg[1];
4796  }
4797  elseif (preg_match('/varchar/', $type)) $type = 'varchar'; // convert varchar(xx) int varchar
4798  if (is_array($val['arrayofkeyval'])) $type='select';
4799  if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) $type='link';
4800 
4801  //$elementtype=$this->attribute_elementtype[$key]; // seems to not be used
4802  $default=$val['default'];
4803  $computed=$val['computed'];
4804  $unique=$val['unique'];
4805  $required=$val['required'];
4806  $param=$val['param'];
4807  if (is_array($val['arrayofkeyval'])) $param['options'] = $val['arrayofkeyval'];
4808  if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg))
4809  {
4810  $type='link';
4811  $param['options']=array($reg[1].':'.$reg[2]=>$reg[1].':'.$reg[2]);
4812  }
4813  $langfile=$val['langfile'];
4814  $list=$val['list'];
4815  $hidden=(abs($val['visible'])!=1 ? 1 : 0);
4816  $help=$val['help'];
4817 
4818  if ($computed)
4819  {
4820  if (! preg_match('/^search_/', $keyprefix)) return '<span class="opacitymedium">'.$langs->trans("AutomaticallyCalculated").'</span>';
4821  else return '';
4822  }
4823 
4824  // Use in priorit showsize from parameters, then $val['css'] then autodefine
4825  if (empty($showsize) && ! empty($val['css']))
4826  {
4827  $showsize = $val['css'];
4828  }
4829  if (empty($showsize))
4830  {
4831  if ($type == 'date')
4832  {
4833  //$showsize=10;
4834  $showsize = 'minwidth100imp';
4835  }
4836  elseif ($type == 'datetime')
4837  {
4838  //$showsize=19;
4839  $showsize = 'minwidth200imp';
4840  }
4841  elseif (in_array($type,array('int','double','price')))
4842  {
4843  //$showsize=10;
4844  $showsize = 'maxwidth75';
4845  }
4846  elseif ($type == 'url')
4847  {
4848  $showsize='minwidth400';
4849  }
4850  elseif ($type == 'boolean')
4851  {
4852  $showsize='';
4853  }
4854  else
4855  {
4856  if (round($size) < 12)
4857  {
4858  $showsize = 'minwidth100';
4859  }
4860  else if (round($size) <= 48)
4861  {
4862  $showsize = 'minwidth200';
4863  }
4864  else
4865  {
4866  //$showsize=48;
4867  $showsize = 'minwidth400';
4868  }
4869  }
4870  }
4871  //var_dump($showsize.' '.$size);
4872 
4873  if (in_array($type,array('date','datetime')))
4874  {
4875  $tmp=explode(',',$size);
4876  $newsize=$tmp[0];
4877 
4878  $showtime = in_array($type,array('datetime')) ? 1 : 0;
4879 
4880  // Do not show current date when field not required (see select_date() method)
4881  if (!$required && $value == '') $value = '-1';
4882 
4883  // TODO Must also support $moreparam
4884  $out = $form->select_date($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, ($keyprefix != 'search_' ? 1 : 0), 1, 0, 1);
4885  }
4886  elseif (in_array($type,array('int','integer')))
4887  {
4888  $tmp=explode(',',$size);
4889  $newsize=$tmp[0];
4890  $out='<input type="text" class="flat '.$showsize.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" maxlength="'.$newsize.'" value="'.$value.'"'.($moreparam?$moreparam:'').'>';
4891  }
4892  elseif (preg_match('/varchar/', $type))
4893  {
4894  $out='<input type="text" class="flat '.$showsize.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" maxlength="'.$size.'" value="'.dol_escape_htmltag($value).'"'.($moreparam?$moreparam:'').'>';
4895  }
4896  elseif (in_array($type, array('mail', 'phone', 'url')))
4897  {
4898  $out='<input type="text" class="flat '.$showsize.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'>';
4899  }
4900  elseif ($type == 'text')
4901  {
4902  require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
4903  $doleditor=new DolEditor($keyprefix.$key.$keysuffix,$value,'',200,'dolibarr_notes','In',false,false,0,ROWS_5,'90%');
4904  $out=$doleditor->Create(1);
4905  }
4906  elseif ($type == 'html')
4907  {
4908  require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
4909  $doleditor=new DolEditor($keyprefix.$key.$keysuffix,$value,'',200,'dolibarr_notes','In',false,false,! empty($conf->fckeditor->enabled) && $conf->global->FCKEDITOR_ENABLE_SOCIETE,ROWS_5,'90%');
4910  $out=$doleditor->Create(1);
4911  }
4912  elseif ($type == 'boolean')
4913  {
4914  $checked='';
4915  if (!empty($value)) {
4916  $checked=' checked value="1" ';
4917  } else {
4918  $checked=' value="1" ';
4919  }
4920  $out='<input type="checkbox" class="flat '.$showsize.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.$checked.' '.($moreparam?$moreparam:'').'>';
4921  }
4922  elseif ($type == 'price')
4923  {
4924  if (!empty($value)) { // $value in memory is a php numeric, we format it into user number format.
4925  $value=price($value);
4926  }
4927  $out='<input type="text" class="flat '.$showsize.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'> '.$langs->getCurrencySymbol($conf->currency);
4928  }
4929  elseif ($type == 'double')
4930  {
4931  if (!empty($value)) { // $value in memory is a php numeric, we format it into user number format.
4932  $value=price($value);
4933  }
4934  $out='<input type="text" class="flat '.$showsize.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'> ';
4935  }
4936  elseif ($type == 'select')
4937  {
4938  $out = '';
4939  if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2))
4940  {
4941  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
4942  $out.= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
4943  }
4944 
4945  $out.='<select class="flat '.$showsize.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'').'>';
4946  if ((! isset($val['default'])) || ($val['notnull'] != 1)) $out.='<option value="0">&nbsp;</option>';
4947  foreach ($param['options'] as $key => $val)
4948  {
4949  if ((string) $key == '') continue;
4950  list($val, $parent) = explode('|', $val);
4951  $out.='<option value="'.$key.'"';
4952  $out.= (((string) $value == (string) $key)?' selected':'');
4953  $out.= (!empty($parent)?' parent="'.$parent.'"':'');
4954  $out.='>'.$val.'</option>';
4955  }
4956  $out.='</select>';
4957  }
4958  elseif ($type == 'sellist')
4959  {
4960  $out = '';
4961  if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2))
4962  {
4963  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
4964  $out.= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
4965  }
4966 
4967  $out.='<select class="flat '.$showsize.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'').'>';
4968  if (is_array($param['options']))
4969  {
4970  $param_list=array_keys($param['options']);
4971  $InfoFieldList = explode(":", $param_list[0]);
4972  // 0 : tableName
4973  // 1 : label field name
4974  // 2 : key fields name (if differ of rowid)
4975  // 3 : key field parent (for dependent lists)
4976  // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
4977  $keyList=(empty($InfoFieldList[2])?'rowid':$InfoFieldList[2].' as rowid');
4978 
4979 
4980  if (count($InfoFieldList) > 4 && ! empty($InfoFieldList[4]))
4981  {
4982  if (strpos($InfoFieldList[4], 'extra.') !== false)
4983  {
4984  $keyList='main.'.$InfoFieldList[2].' as rowid';
4985  } else {
4986  $keyList=$InfoFieldList[2].' as rowid';
4987  }
4988  }
4989  if (count($InfoFieldList) > 3 && ! empty($InfoFieldList[3]))
4990  {
4991  list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
4992  $keyList.= ', '.$parentField;
4993  }
4994 
4995  $fields_label = explode('|',$InfoFieldList[1]);
4996  if (is_array($fields_label))
4997  {
4998  $keyList .=', ';
4999  $keyList .= implode(', ', $fields_label);
5000  }
5001 
5002  $sqlwhere='';
5003  $sql = 'SELECT '.$keyList;
5004  $sql.= ' FROM '.MAIN_DB_PREFIX .$InfoFieldList[0];
5005  if (!empty($InfoFieldList[4]))
5006  {
5007  // can use SELECT request
5008  if (strpos($InfoFieldList[4], '$SEL$')!==false) {
5009  $InfoFieldList[4]=str_replace('$SEL$','SELECT',$InfoFieldList[4]);
5010  }
5011 
5012  // current object id can be use into filter
5013  if (strpos($InfoFieldList[4], '$ID$')!==false && !empty($objectid)) {
5014  $InfoFieldList[4]=str_replace('$ID$',$objectid,$InfoFieldList[4]);
5015  } else {
5016  $InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]);
5017  }
5018  //We have to join on extrafield table
5019  if (strpos($InfoFieldList[4], 'extra')!==false)
5020  {
5021  $sql.= ' as main, '.MAIN_DB_PREFIX .$InfoFieldList[0].'_extrafields as extra';
5022  $sqlwhere.= ' WHERE extra.fk_object=main.'.$InfoFieldList[2]. ' AND '.$InfoFieldList[4];
5023  }
5024  else
5025  {
5026  $sqlwhere.= ' WHERE '.$InfoFieldList[4];
5027  }
5028  }
5029  else
5030  {
5031  $sqlwhere.= ' WHERE 1=1';
5032  }
5033  // Some tables may have field, some other not. For the moment we disable it.
5034  if (in_array($InfoFieldList[0],array('tablewithentity')))
5035  {
5036  $sqlwhere.= ' AND entity = '.$conf->entity;
5037  }
5038  $sql.=$sqlwhere;
5039  //print $sql;
5040 
5041  $sql .= ' ORDER BY ' . implode(', ', $fields_label);
5042 
5043  dol_syslog(get_class($this).'::showInputField type=sellist', LOG_DEBUG);
5044  $resql = $this->db->query($sql);
5045  if ($resql)
5046  {
5047  $out.='<option value="0">&nbsp;</option>';
5048  $num = $this->db->num_rows($resql);
5049  $i = 0;
5050  while ($i < $num)
5051  {
5052  $labeltoshow='';
5053  $obj = $this->db->fetch_object($resql);
5054 
5055  // Several field into label (eq table:code|libelle:rowid)
5056  $fields_label = explode('|',$InfoFieldList[1]);
5057  if(is_array($fields_label))
5058  {
5059  $notrans = true;
5060  foreach ($fields_label as $field_toshow)
5061  {
5062  $labeltoshow.= $obj->$field_toshow.' ';
5063  }
5064  }
5065  else
5066  {
5067  $labeltoshow=$obj->{$InfoFieldList[1]};
5068  }
5069  $labeltoshow=dol_trunc($labeltoshow,45);
5070 
5071  if ($value==$obj->rowid)
5072  {
5073  foreach ($fields_label as $field_toshow)
5074  {
5075  $translabel=$langs->trans($obj->$field_toshow);
5076  if ($translabel!=$obj->$field_toshow) {
5077  $labeltoshow=dol_trunc($translabel,18).' ';
5078  }else {
5079  $labeltoshow=dol_trunc($obj->$field_toshow,18).' ';
5080  }
5081  }
5082  $out.='<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
5083  }
5084  else
5085  {
5086  if(!$notrans)
5087  {
5088  $translabel=$langs->trans($obj->{$InfoFieldList[1]});
5089  if ($translabel!=$obj->{$InfoFieldList[1]}) {
5090  $labeltoshow=dol_trunc($translabel,18);
5091  }
5092  else {
5093  $labeltoshow=dol_trunc($obj->{$InfoFieldList[1]},18);
5094  }
5095  }
5096  if (empty($labeltoshow)) $labeltoshow='(not defined)';
5097  if ($value==$obj->rowid)
5098  {
5099  $out.='<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
5100  }
5101 
5102  if (!empty($InfoFieldList[3]))
5103  {
5104  $parent = $parentName.':'.$obj->{$parentField};
5105  }
5106 
5107  $out.='<option value="'.$obj->rowid.'"';
5108  $out.= ($value==$obj->rowid?' selected':'');
5109  $out.= (!empty($parent)?' parent="'.$parent.'"':'');
5110  $out.='>'.$labeltoshow.'</option>';
5111  }
5112 
5113  $i++;
5114  }
5115  $this->db->free($resql);
5116  }
5117  else {
5118  print 'Error in request '.$sql.' '.$this->db->lasterror().'. Check setup of extra parameters.<br>';
5119  }
5120  }
5121  $out.='</select>';
5122  }
5123  elseif ($type == 'checkbox')
5124  {
5125  $value_arr=explode(',',$value);
5126  $out=$form->multiselectarray($keyprefix.$key.$keysuffix, (empty($param['options'])?null:$param['options']), $value_arr, '', 0, '', 0, '100%');
5127  }
5128  elseif ($type == 'radio')
5129  {
5130  $out='';
5131  foreach ($param['options'] as $keyopt => $val)
5132  {
5133  $out.='<input class="flat '.$showsize.'" type="radio" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'');
5134  $out.=' value="'.$keyopt.'"';
5135  $out.=' id="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'"';
5136  $out.= ($value==$keyopt?'checked':'');
5137  $out.='/><label for="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'">'.$val.'</label><br>';
5138  }
5139  }
5140  elseif ($type == 'chkbxlst')
5141  {
5142  if (is_array($value)) {
5143  $value_arr = $value;
5144  }
5145  else {
5146  $value_arr = explode(',', $value);
5147  }
5148 
5149  if (is_array($param['options'])) {
5150  $param_list = array_keys($param['options']);
5151  $InfoFieldList = explode(":", $param_list[0]);
5152  // 0 : tableName
5153  // 1 : label field name
5154  // 2 : key fields name (if differ of rowid)
5155  // 3 : key field parent (for dependent lists)
5156  // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
5157  $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2] . ' as rowid');
5158 
5159  if (count($InfoFieldList) > 3 && ! empty($InfoFieldList[3])) {
5160  list ( $parentName, $parentField ) = explode('|', $InfoFieldList[3]);
5161  $keyList .= ', ' . $parentField;
5162  }
5163  if (count($InfoFieldList) > 4 && ! empty($InfoFieldList[4])) {
5164  if (strpos($InfoFieldList[4], 'extra.') !== false) {
5165  $keyList = 'main.' . $InfoFieldList[2] . ' as rowid';
5166  } else {
5167  $keyList = $InfoFieldList[2] . ' as rowid';
5168  }
5169  }
5170 
5171  $fields_label = explode('|', $InfoFieldList[1]);
5172  if (is_array($fields_label)) {
5173  $keyList .= ', ';
5174  $keyList .= implode(', ', $fields_label);
5175  }
5176 
5177  $sqlwhere = '';
5178  $sql = 'SELECT ' . $keyList;
5179  $sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
5180  if (! empty($InfoFieldList[4])) {
5181 
5182  // can use SELECT request
5183  if (strpos($InfoFieldList[4], '$SEL$')!==false) {
5184  $InfoFieldList[4]=str_replace('$SEL$','SELECT',$InfoFieldList[4]);
5185  }
5186 
5187  // current object id can be use into filter
5188  if (strpos($InfoFieldList[4], '$ID$')!==false && !empty($objectid)) {
5189  $InfoFieldList[4]=str_replace('$ID$',$objectid,$InfoFieldList[4]);
5190  } else {
5191  $InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]);
5192  }
5193 
5194  // We have to join on extrafield table
5195  if (strpos($InfoFieldList[4], 'extra') !== false) {
5196  $sql .= ' as main, ' . MAIN_DB_PREFIX . $InfoFieldList[0] . '_extrafields as extra';
5197  $sqlwhere .= ' WHERE extra.fk_object=main.' . $InfoFieldList[2] . ' AND ' . $InfoFieldList[4];
5198  } else {
5199  $sqlwhere .= ' WHERE ' . $InfoFieldList[4];
5200  }
5201  } else {
5202  $sqlwhere .= ' WHERE 1=1';
5203  }
5204  // Some tables may have field, some other not. For the moment we disable it.
5205  if (in_array($InfoFieldList[0], array ('tablewithentity')))
5206  {
5207  $sqlwhere .= ' AND entity = ' . $conf->entity;
5208  }
5209  // $sql.=preg_replace('/^ AND /','',$sqlwhere);
5210  // print $sql;
5211 
5212  $sql .= $sqlwhere;
5213  dol_syslog(get_class($this) . '::showInputField type=chkbxlst',LOG_DEBUG);
5214  $resql = $this->db->query($sql);
5215  if ($resql) {
5216  $num = $this->db->num_rows($resql);
5217  $i = 0;
5218 
5219  $data=array();
5220 
5221  while ( $i < $num ) {
5222  $labeltoshow = '';
5223  $obj = $this->db->fetch_object($resql);
5224 
5225  // Several field into label (eq table:code|libelle:rowid)
5226  $fields_label = explode('|', $InfoFieldList[1]);
5227  if (is_array($fields_label)) {
5228  $notrans = true;
5229  foreach ( $fields_label as $field_toshow ) {
5230  $labeltoshow .= $obj->$field_toshow . ' ';
5231  }
5232  } else {
5233  $labeltoshow = $obj->{$InfoFieldList[1]};
5234  }
5235  $labeltoshow = dol_trunc($labeltoshow, 45);
5236 
5237  if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
5238  foreach ( $fields_label as $field_toshow ) {
5239  $translabel = $langs->trans($obj->$field_toshow);
5240  if ($translabel != $obj->$field_toshow) {
5241  $labeltoshow = dol_trunc($translabel, 18) . ' ';
5242  } else {
5243  $labeltoshow = dol_trunc($obj->$field_toshow, 18) . ' ';
5244  }
5245  }
5246 
5247  $data[$obj->rowid]=$labeltoshow;
5248 
5249  } else {
5250  if (! $notrans) {
5251  $translabel = $langs->trans($obj->{$InfoFieldList[1]});
5252  if ($translabel != $obj->{$InfoFieldList[1]}) {
5253  $labeltoshow = dol_trunc($translabel, 18);
5254  } else {
5255  $labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18);
5256  }
5257  }
5258  if (empty($labeltoshow))
5259  $labeltoshow = '(not defined)';
5260 
5261  if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
5262  $data[$obj->rowid]=$labeltoshow;
5263  }
5264 
5265  if (! empty($InfoFieldList[3])) {
5266  $parent = $parentName . ':' . $obj->{$parentField};
5267  }
5268 
5269  $data[$obj->rowid]=$labeltoshow;
5270  }
5271 
5272  $i ++;
5273  }
5274  $this->db->free($resql);
5275 
5276  $out=$form->multiselectarray($keyprefix.$key.$keysuffix, $data, $value_arr, '', 0, '', 0, '100%');
5277 
5278  } else {
5279  print 'Error in request ' . $sql . ' ' . $this->db->lasterror() . '. Check setup of extra parameters.<br>';
5280  }
5281  }
5282  $out .= '</select>';
5283  }
5284  elseif ($type == 'link')
5285  {
5286  $param_list=array_keys($param['options']); // $param_list='ObjectName:classPath'
5287  $showempty=(($val['notnull'] == 1 && $val['default'] != '')?0:1);
5288  $out=$form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty);
5289  }
5290  elseif ($type == 'password')
5291  {
5292  // If prefix is 'search_', field is used as a filter, we use a common text field.
5293  $out='<input type="'.($keyprefix=='search_'?'text':'password').'" class="flat '.$showsize.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'>';
5294  }
5295  if (!empty($hidden)) {
5296  $out='<input type="hidden" value="'.$value.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'"/>';
5297  }
5298  /* Add comments
5299  if ($type == 'date') $out.=' (YYYY-MM-DD)';
5300  elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)';
5301  */
5302  return $out;
5303  }
5304 
5305 
5319  function showOutputField($val, $key, $value, $moreparam='', $keysuffix='', $keyprefix='', $showsize=0)
5320  {
5321  global $conf,$langs,$form;
5322 
5323  if (! is_object($form))
5324  {
5325  require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
5326  $form=new Form($this->db);
5327  }
5328 
5329  $objectid = $this->id;
5330  $label = $val['label'];
5331  $type = $val['type'];
5332  $size = $val['css'];
5333 
5334  // Convert var to be able to share same code than showOutputField of extrafields
5335  if (preg_match('/varchar\((\d+)\)/', $type, $reg))
5336  {
5337  $type = 'varchar'; // convert varchar(xx) int varchar
5338  $size = $reg[1];
5339  }
5340  elseif (preg_match('/varchar/', $type)) $type = 'varchar'; // convert varchar(xx) int varchar
5341  if (is_array($val['arrayofkeyval'])) $type='select';
5342  if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) $type='link';
5343 
5344  //$elementtype=$this->attribute_elementtype[$key]; // seems to not be used
5345  $default=$val['default'];
5346  $computed=$val['computed'];
5347  $unique=$val['unique'];
5348  $required=$val['required'];
5349  $param=$val['param'];
5350  if (is_array($val['arrayofkeyval'])) $param['options'] = $val['arrayofkeyval'];
5351  if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg))
5352  {
5353  $type='link';
5354  $param['options']=array($reg[1].':'.$reg[2]=>$reg[1].':'.$reg[2]);
5355  }
5356  $langfile=$val['langfile'];
5357  $list=$val['list'];
5358  $help=$val['help'];
5359  $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)
5360 
5361  if ($hidden) return '';
5362 
5363  // If field is a computed field, value must become result of compute
5364  if ($computed)
5365  {
5366  // Make the eval of compute string
5367  //var_dump($computed);
5368  $value = dol_eval($computed, 1, 0);
5369  }
5370 
5371  if (empty($showsize))
5372  {
5373  if ($type == 'date')
5374  {
5375  //$showsize=10;
5376  $showsize = 'minwidth100imp';
5377  }
5378  elseif ($type == 'datetime')
5379  {
5380  //$showsize=19;
5381  $showsize = 'minwidth200imp';
5382  }
5383  elseif (in_array($type,array('int','double','price')))
5384  {
5385  //$showsize=10;
5386  $showsize = 'maxwidth75';
5387  }
5388  elseif ($type == 'url')
5389  {
5390  $showsize='minwidth400';
5391  }
5392  elseif ($type == 'boolean')
5393  {
5394  $showsize='';
5395  }
5396  else
5397  {
5398  if (round($size) < 12)
5399  {
5400  $showsize = 'minwidth100';
5401  }
5402  else if (round($size) <= 48)
5403  {
5404  $showsize = 'minwidth200';
5405  }
5406  else
5407  {
5408  //$showsize=48;
5409  $showsize = 'minwidth400';
5410  }
5411  }
5412  }
5413 
5414  // Format output value differently according to properties of field
5415  if ($key == 'ref' && method_exists($this, 'getNomUrl')) $value=$this->getNomUrl(1, '', 0, '', 1);
5416  elseif ($key == 'status' && method_exists($this, 'getLibStatut')) $value=$this->getLibStatut(3);
5417  elseif ($type == 'date')
5418  {
5419  $value=dol_print_date($value,'day');
5420  }
5421  elseif ($type == 'datetime')
5422  {
5423  $value=dol_print_date($value,'dayhour');
5424  }
5425  elseif ($type == 'double')
5426  {
5427  if (!empty($value)) {
5428  $value=price($value);
5429  }
5430  }
5431  elseif ($type == 'boolean')
5432  {
5433  $checked='';
5434  if (!empty($value)) {
5435  $checked=' checked ';
5436  }
5437  $value='<input type="checkbox" '.$checked.' '.($moreparam?$moreparam:'').' readonly disabled>';
5438  }
5439  elseif ($type == 'mail')
5440  {
5441  $value=dol_print_email($value,0,0,0,64,1,1);
5442  }
5443  elseif ($type == 'url')
5444  {
5445  $value=dol_print_url($value,'_blank',32,1);
5446  }
5447  elseif ($type == 'phone')
5448  {
5449  $value=dol_print_phone($value, '', 0, 0, '', '&nbsp;', 1);
5450  }
5451  elseif ($type == 'price')
5452  {
5453  $value=price($value,0,$langs,0,0,-1,$conf->currency);
5454  }
5455  elseif ($type == 'select')
5456  {
5457  $value=$param['options'][$value];
5458  }
5459  elseif ($type == 'sellist')
5460  {
5461  $param_list=array_keys($param['options']);
5462  $InfoFieldList = explode(":", $param_list[0]);
5463 
5464  $selectkey="rowid";
5465  $keyList='rowid';
5466 
5467  if (count($InfoFieldList)>=3)
5468  {
5469  $selectkey = $InfoFieldList[2];
5470  $keyList=$InfoFieldList[2].' as rowid';
5471  }
5472 
5473  $fields_label = explode('|',$InfoFieldList[1]);
5474  if(is_array($fields_label)) {
5475  $keyList .=', ';
5476  $keyList .= implode(', ', $fields_label);
5477  }
5478 
5479  $sql = 'SELECT '.$keyList;
5480  $sql.= ' FROM '.MAIN_DB_PREFIX .$InfoFieldList[0];
5481  if (strpos($InfoFieldList[4], 'extra')!==false)
5482  {
5483  $sql.= ' as main';
5484  }
5485  if ($selectkey=='rowid' && empty($value)) {
5486  $sql.= " WHERE ".$selectkey."=0";
5487  } elseif ($selectkey=='rowid') {
5488  $sql.= " WHERE ".$selectkey."=".$this->db->escape($value);
5489  }else {
5490  $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
5491  }
5492 
5493  //$sql.= ' AND entity = '.$conf->entity;
5494 
5495  dol_syslog(get_class($this).':showOutputField:$type=sellist', LOG_DEBUG);
5496  $resql = $this->db->query($sql);
5497  if ($resql)
5498  {
5499  $value=''; // value was used, so now we reste it to use it to build final output
5500 
5501  $obj = $this->db->fetch_object($resql);
5502 
5503  // Several field into label (eq table:code|libelle:rowid)
5504  $fields_label = explode('|',$InfoFieldList[1]);
5505 
5506  if(is_array($fields_label) && count($fields_label)>1)
5507  {
5508  foreach ($fields_label as $field_toshow)
5509  {
5510  $translabel='';
5511  if (!empty($obj->$field_toshow)) {
5512  $translabel=$langs->trans($obj->$field_toshow);
5513  }
5514  if ($translabel!=$field_toshow) {
5515  $value.=dol_trunc($translabel,18).' ';
5516  }else {
5517  $value.=$obj->$field_toshow.' ';
5518  }
5519  }
5520  }
5521  else
5522  {
5523  $translabel='';
5524  if (!empty($obj->{$InfoFieldList[1]})) {
5525  $translabel=$langs->trans($obj->{$InfoFieldList[1]});
5526  }
5527  if ($translabel!=$obj->{$InfoFieldList[1]}) {
5528  $value=dol_trunc($translabel,18);
5529  }else {
5530  $value=$obj->{$InfoFieldList[1]};
5531  }
5532  }
5533  }
5534  else dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
5535  }
5536  elseif ($type == 'radio')
5537  {
5538  $value=$param['options'][$value];
5539  }
5540  elseif ($type == 'checkbox')
5541  {
5542  $value_arr=explode(',',$value);
5543  $value='';
5544  if (is_array($value_arr))
5545  {
5546  foreach ($value_arr as $keyval=>$valueval) {
5547  $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$param['options'][$valueval].'</li>';
5548  }
5549  }
5550  $value='<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
5551  }
5552  elseif ($type == 'chkbxlst')
5553  {
5554  $value_arr = explode(',', $value);
5555 
5556  $param_list = array_keys($param['options']);
5557  $InfoFieldList = explode(":", $param_list[0]);
5558 
5559  $selectkey = "rowid";
5560  $keyList = 'rowid';
5561 
5562  if (count($InfoFieldList) >= 3) {
5563  $selectkey = $InfoFieldList[2];
5564  $keyList = $InfoFieldList[2] . ' as rowid';
5565  }
5566 
5567  $fields_label = explode('|', $InfoFieldList[1]);
5568  if (is_array($fields_label)) {
5569  $keyList .= ', ';
5570  $keyList .= implode(', ', $fields_label);
5571  }
5572 
5573  $sql = 'SELECT ' . $keyList;
5574  $sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
5575  if (strpos($InfoFieldList[4], 'extra') !== false) {
5576  $sql .= ' as main';
5577  }
5578  // $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
5579  // $sql.= ' AND entity = '.$conf->entity;
5580 
5581  dol_syslog(get_class($this) . ':showOutputField:$type=chkbxlst',LOG_DEBUG);
5582  $resql = $this->db->query($sql);
5583  if ($resql) {
5584  $value = ''; // value was used, so now we reste it to use it to build final output
5585  $toprint=array();
5586  while ( $obj = $this->db->fetch_object($resql) ) {
5587 
5588  // Several field into label (eq table:code|libelle:rowid)
5589  $fields_label = explode('|', $InfoFieldList[1]);
5590  if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
5591  if (is_array($fields_label) && count($fields_label) > 1) {
5592  foreach ( $fields_label as $field_toshow ) {
5593  $translabel = '';
5594  if (! empty($obj->$field_toshow)) {
5595  $translabel = $langs->trans($obj->$field_toshow);
5596  }
5597  if ($translabel != $field_toshow) {
5598  $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.dol_trunc($translabel, 18).'</li>';
5599  } else {
5600  $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$obj->$field_toshow.'</li>';
5601  }
5602  }
5603  } else {
5604  $translabel = '';
5605  if (! empty($obj->{$InfoFieldList[1]})) {
5606  $translabel = $langs->trans($obj->{$InfoFieldList[1]});
5607  }
5608  if ($translabel != $obj->{$InfoFieldList[1]}) {
5609  $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.dol_trunc($translabel, 18).'</li>';
5610  } else {
5611  $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$obj->{$InfoFieldList[1]}.'</li>';
5612  }
5613  }
5614  }
5615  }
5616  $value='<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
5617 
5618  } else {
5619  dol_syslog(get_class($this) . '::showOutputField error ' . $this->db->lasterror(), LOG_WARNING);
5620  }
5621  }
5622  elseif ($type == 'link')
5623  {
5624  $out='';
5625 
5626  // only if something to display (perf)
5627  if ($value)
5628  {
5629  $param_list=array_keys($param['options']); // $param_list='ObjectName:classPath'
5630 
5631  $InfoFieldList = explode(":", $param_list[0]);
5632  $classname=$InfoFieldList[0];
5633  $classpath=$InfoFieldList[1];
5634  if (! empty($classpath))
5635  {
5636  dol_include_once($InfoFieldList[1]);
5637  if ($classname && class_exists($classname))
5638  {
5639  $object = new $classname($this->db);
5640  $object->fetch($value);
5641  $value=$object->getNomUrl(3);
5642  }
5643  }
5644  else
5645  {
5646  dol_syslog('Error bad setup of extrafield', LOG_WARNING);
5647  return 'Error bad setup of extrafield';
5648  }
5649  }
5650  }
5651  elseif ($type == 'text' || $type == 'html')
5652  {
5653  $value=dol_htmlentitiesbr($value);
5654  }
5655  elseif ($type == 'password')
5656  {
5657  $value=preg_replace('/./i','*',$value);
5658  }
5659 
5660  //print $type.'-'.$size;
5661  $out=$value;
5662 
5663  return $out;
5664  }
5665 
5666 
5678  function showOptionals($extrafields, $mode='view', $params=null, $keysuffix='', $keyprefix='')
5679  {
5680  global $_POST, $conf, $langs, $action;
5681 
5682  $out = '';
5683 
5684  if (count($extrafields->attribute_label) > 0)
5685  {
5686  $out .= "\n";
5687  $out .= '<!-- showOptionalsInput --> ';
5688  $out .= "\n";
5689 
5690  $e = 0;
5691  foreach($extrafields->attribute_label as $key=>$label)
5692  {
5693  if (empty($extrafields->attribute_list[$key])) continue; // 0 = Never visible field
5694  if (($mode == 'create' || $mode == 'edit') && abs($extrafields->attribute_list[$key]) != 1 && abs($extrafields->attribute_list[$key]) != 3) continue; // <> -1 and <> 1 and <> 3 = not visible on forms, only on list
5695 
5696  // Load language if required
5697  if (! empty($extrafields->attributes[$this->table_element]['langfile'][$key])) $langs->load($extrafields->attributes[$this->table_element]['langfile'][$key]);
5698 
5699  if (is_array($params) && count($params)>0) {
5700  if (array_key_exists('colspan',$params)) {
5701  $colspan=$params['colspan'];
5702  }
5703  }else {
5704  $colspan='3';
5705  }
5706 
5707  switch($mode) {
5708  case "view":
5709  $value=$this->array_options["options_".$key.$keysuffix];
5710  break;
5711  case "edit":
5712  $getposttemp = GETPOST($keyprefix.'options_'.$key.$keysuffix, 'none'); // GETPOST can get value from GET, POST or setup of default values.
5713  // GETPOST("options_" . $key) can be 'abc' or array(0=>'abc')
5714  if (is_array($getposttemp) || $getposttemp != '' || GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix))
5715  {
5716  if (is_array($getposttemp)) {
5717  // $getposttemp is an array but following code expects a comma separated string
5718  $value = implode(",", $getposttemp);
5719  } else {
5720  $value = $getposttemp;
5721  }
5722  } else {
5723  $value = $this->array_options["options_" . $key]; // No GET, no POST, no default value, so we take value of object.
5724  }
5725  break;
5726  }
5727  //var_dump($value);
5728 
5729  if ($extrafields->attribute_type[$key] == 'separate')
5730  {
5731  $out .= $extrafields->showSeparator($key);
5732  }
5733  else
5734  {
5735  $csstyle='';
5736  $class=(!empty($extrafields->attribute_hidden[$key]) ? 'class="hideobject" ' : '');
5737  if (is_array($params) && count($params)>0) {
5738  if (array_key_exists('style',$params)) {
5739  $csstyle=$params['style'];
5740  }
5741  }
5742  if ( !empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && ($e % 2) == 0)
5743  {
5744  $out .= '<tr '.$class.$csstyle.' class="'.$this->element.'_extras_'.$key.'">';
5745  $colspan='0';
5746  }
5747  else
5748  {
5749  $out .= '<tr '.$class.$csstyle.' class="'.$this->element.'_extras_'.$key.'">';
5750  }
5751  // Convert date into timestamp format (value in memory must be a timestamp)
5752  if (in_array($extrafields->attribute_type[$key],array('date','datetime')))
5753  {
5754  $value = GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix)?dol_mktime(GETPOST($keyprefix.'options_'.$key.$keysuffix."hour",'int',3), GETPOST($keyprefix.'options_'.$key.$keysuffix."min",'int',3), 0, GETPOST($keyprefix.'options_'.$key.$keysuffix."month",'int',3), GETPOST($keyprefix.'options_'.$key.$keysuffix."day",'int',3), GETPOST($keyprefix.'options_'.$key.$keysuffix."year",'int',3)):$this->db->jdate($this->array_options['options_'.$key]);
5755  }
5756  // Convert float submited string into real php numeric (value in memory must be a php numeric)
5757  if (in_array($extrafields->attribute_type[$key],array('price','double')))
5758  {
5759  $value = GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix)?price2num(GETPOST($keyprefix.'options_'.$key.$keysuffix,'int',3)):$this->array_options['options_'.$key];
5760  }
5761 
5762  $labeltoshow = $langs->trans($label);
5763 
5764  if($extrafields->attribute_required[$key])
5765  {
5766  $labeltoshow = '<span'.($mode != 'view' ? ' class="fieldrequired"':'').'>'.$labeltoshow.'</span>';
5767  }
5768  $out .= '<td>'.$labeltoshow.'</td>';
5769 
5770  $html_id = !empty($this->id) ? $this->element.'_extras_'.$key.'_'.$this->id : '';
5771  $out .='<td id="'.$html_id.'" class="'.$this->element.'_extras_'.$key.'" '.($colspan?' colspan="'.$colspan.'"':'').'>';
5772 
5773  switch($mode) {
5774  case "view":
5775  $out .= $extrafields->showOutputField($key, $value);
5776  break;
5777  case "edit":
5778  $out .= $extrafields->showInputField($key, $value, '', $keysuffix, '', 0, $this->id);
5779  break;
5780  }
5781 
5782  $out .= '</td>';
5783 
5784  if (! empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && (($e % 2) == 1)) $out .= '</tr>';
5785  else $out .= '</tr>';
5786  $e++;
5787  }
5788  }
5789  $out .= "\n";
5790  // Add code to manage list depending on others
5791  if (! empty($conf->use_javascript_ajax)) {
5792  $out .= '
5793  <script type="text/javascript">
5794  jQuery(document).ready(function() {
5795  function showOptions(child_list, parent_list)
5796  {
5797  var val = $("select[name=\"options_"+parent_list+"\"]").val();
5798  var parentVal = parent_list + ":" + val;
5799  if(val > 0) {
5800  $("select[name=\""+child_list+"\"] option[parent]").hide();
5801  $("select[name=\""+child_list+"\"] option[parent=\""+parentVal+"\"]").show();
5802  } else {
5803  $("select[name=\""+child_list+"\"] option").show();
5804  }
5805  }
5806  function setListDependencies() {
5807  jQuery("select option[parent]").parent().each(function() {
5808  var child_list = $(this).attr("name");
5809  var parent = $(this).find("option[parent]:first").attr("parent");
5810  var infos = parent.split(":");
5811  var parent_list = infos[0];
5812  $("select[name=\""+parent_list+"\"]").change(function() {
5813  showOptions(child_list, parent_list);
5814  });
5815  });
5816  }
5817 
5818  setListDependencies();
5819  });
5820  </script>'."\n";
5821  $out .= '<!-- /showOptionalsInput --> '."\n";
5822  }
5823  }
5824  return $out;
5825  }
5826 
5827 
5832  public function getRights()
5833  {
5834  global $user;
5835 
5836  $element = $this->element;
5837  if ($element == 'facturerec') $element='facture';
5838 
5839  return $user->rights->{$element};
5840  }
5841 
5854  public static function commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
5855  {
5856  foreach ($tables as $table)
5857  {
5858  $sql = 'UPDATE '.MAIN_DB_PREFIX.$table.' SET fk_soc = '.$dest_id.' WHERE fk_soc = '.$origin_id;
5859 
5860  if (! $db->query($sql))
5861  {
5862  if ($ignoreerrors) return true; // TODO Not enough. If there is A-B on kept thirdarty and B-C on old one, we must get A-B-C after merge. Not A-B.
5863  //$this->errors = $db->lasterror();
5864  return false;
5865  }
5866  }
5867 
5868  return true;
5869  }
5870 
5883  public function defineBuyPrice($unitPrice = 0.0, $discountPercent = 0.0, $fk_product = 0)
5884  {
5885  global $conf;
5886 
5887  $buyPrice = 0;
5888 
5889  if (($unitPrice > 0) && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1)) // In most cases, test here is false
5890  {
5891  $buyPrice = $unitPrice * (1 - $discountPercent / 100);
5892  }
5893  else
5894  {
5895  // Get cost price for margin calculation
5896  if (! empty($fk_product))
5897  {
5898  if (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == 'costprice')
5899  {
5900  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
5901  $product = new Product($this->db);
5902  $result = $product->fetch($fk_product);
5903  if ($result <= 0)
5904  {
5905  $this->errors[] = 'ErrorProductIdDoesNotExists';
5906  return -1;
5907  }
5908  if ($product->cost_price > 0)
5909  {
5910  $buyPrice = $product->cost_price;
5911  }
5912  else if ($product->pmp > 0)
5913  {
5914  $buyPrice = $product->pmp;
5915  }
5916  }
5917  else if (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == 'pmp')
5918  {
5919  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
5920  $product = new Product($this->db);
5921  $result = $product->fetch($fk_product);
5922  if ($result <= 0)
5923  {
5924  $this->errors[] = 'ErrorProductIdDoesNotExists';
5925  return -1;
5926  }
5927  if ($product->pmp > 0)
5928  {
5929  $buyPrice = $product->pmp;
5930  }
5931  }
5932 
5933  if (empty($buyPrice) && isset($conf->global->MARGIN_TYPE) && in_array($conf->global->MARGIN_TYPE, array('1','pmp','costprice')))
5934  {
5935  require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
5936  $productFournisseur = new ProductFournisseur($this->db);
5937  if (($result = $productFournisseur->find_min_price_product_fournisseur($fk_product)) > 0)
5938  {
5939  $buyPrice = $productFournisseur->fourn_unitprice;
5940  }
5941  else if ($result < 0)
5942  {
5943  $this->errors[] = $productFournisseur->error;
5944  return -2;
5945  }
5946  }
5947  }
5948  }
5949  return $buyPrice;
5950  }
5951 
5952 
5953 
5960  protected function isArray($info)
5961  {
5962  if(is_array($info))
5963  {
5964  if(isset($info['type']) && $info['type']=='array') return true;
5965  else return false;
5966  }
5967  else return false;
5968  }
5969 
5976  protected function isNull($info)
5977  {
5978  if(is_array($info))
5979  {
5980  if(isset($info['type']) && $info['type']=='null') return true;
5981  else return false;
5982  }
5983  else return false;
5984  }
5985 
5986 
5993  public function isDate($info)
5994  {
5995  if(isset($info['type']) && ($info['type']=='date' || $info['type']=='datetime' || $info['type']=='timestamp')) return true;
5996  else return false;
5997  }
5998 
6005  public function isInt($info)
6006  {
6007  if(is_array($info))
6008  {
6009  if(isset($info['type']) && ($info['type']=='int' || $info['type']=='integer' )) return true;
6010  else return false;
6011  }
6012  else return false;
6013  }
6014 
6021  public function isFloat($info)
6022  {
6023  if(is_array($info))
6024  {
6025  if (isset($info['type']) && (preg_match('/^(double|real)/i', $info['type']))) return true;
6026  else return false;
6027  }
6028  else return false;
6029  }
6030 
6037  public function isText($info)
6038  {
6039  if(is_array($info))
6040  {
6041  if(isset($info['type']) && $info['type']=='text') return true;
6042  else return false;
6043  }
6044  else return false;
6045  }
6046 
6053  protected function isIndex($info)
6054  {
6055  if(is_array($info))
6056  {
6057  if(isset($info['index']) && $info['index']==true) return true;
6058  else return false;
6059  }
6060  else return false;
6061  }
6062 
6069  private function set_save_query()
6070  {
6071  global $conf;
6072 
6073  $queryarray=array();
6074  foreach ($this->fields as $field=>$info) // Loop on definition of fields
6075  {
6076  // Depending on field type ('datetime', ...)
6077  if($this->isDate($info))
6078  {
6079  if(empty($this->{$field}))
6080  {
6081  $queryarray[$field] = NULL;
6082  }
6083  else
6084  {
6085  $queryarray[$field] = $this->db->idate($this->{$field});
6086  }
6087  }
6088  else if($this->isArray($info))
6089  {
6090  $queryarray[$field] = serialize($this->{$field});
6091  }
6092  else if($this->isInt($info))
6093  {
6094  if ($field == 'entity' && is_null($this->{$field})) $queryarray[$field]=$conf->entity;
6095  else
6096  {
6097  $queryarray[$field] = (int) price2num($this->{$field});
6098  if (empty($queryarray[$field])) $queryarray[$field]=0; // May be reset to null later if property 'notnull' is -1 for this field.
6099  }
6100  }
6101  else if($this->isFloat($info))
6102  {
6103  $queryarray[$field] = (double) price2num($this->{$field});
6104  if (empty($queryarray[$field])) $queryarray[$field]=0;
6105  }
6106  else
6107  {
6108  $queryarray[$field] = $this->{$field};
6109  }
6110 
6111  if ($info['type'] == 'timestamp' && empty($queryarray[$field])) unset($queryarray[$field]);
6112  if (! empty($info['notnull']) && $info['notnull'] == -1 && empty($queryarray[$field])) $queryarray[$field] = null;
6113  }
6114 
6115  return $queryarray;
6116  }
6117 
6123  private function setVarsFromFetchObj(&$obj)
6124  {
6125  foreach ($this->fields as $field => $info)
6126  {
6127  if($this->isDate($info))
6128  {
6129  if(empty($obj->{$field}) || $obj->{$field} === '0000-00-00 00:00:00' || $obj->{$field} === '1000-01-01 00:00:00') $this->{$field} = 0;
6130  else $this->{$field} = strtotime($obj->{$field});
6131  }
6132  elseif($this->isArray($info))
6133  {
6134  $this->{$field} = @unserialize($obj->{$field});
6135  // Hack for data not in UTF8
6136  if($this->{$field } === FALSE) @unserialize(utf8_decode($obj->{$field}));
6137  }
6138  elseif($this->isInt($info))
6139  {
6140  if ($field == 'rowid') $this->id = (int) $obj->{$field};
6141  else $this->{$field} = (int) $obj->{$field};
6142  }
6143  elseif($this->isFloat($info))
6144  {
6145  $this->{$field} = (double) $obj->{$field};
6146  }
6147  elseif($this->isNull($info))
6148  {
6149  $val = $obj->{$field};
6150  // zero is not null
6151  $this->{$field} = (is_null($val) || (empty($val) && $val!==0 && $val!=='0') ? null : $val);
6152  }
6153  else
6154  {
6155  $this->{$field} = $obj->{$field};
6156  }
6157  }
6158 
6159  // If there is no 'ref' field, we force property ->ref to ->id for a better compatibility with common functions.
6160  if (! isset($this->fields['ref']) && isset($this->id)) $this->ref = $this->id;
6161  }
6162 
6168  private function get_field_list()
6169  {
6170  $keys = array_keys($this->fields);
6171  return implode(',', $keys);
6172  }
6173 
6181  protected function quote($value, $fieldsentry) {
6182  if (is_null($value)) return 'NULL';
6183  else if (preg_match('/^(int|double|real)/i', $fieldsentry['type'])) return $this->db->escape("$value");
6184  else return "'".$this->db->escape($value)."'";
6185  }
6186 
6187 
6195  public function createCommon(User $user, $notrigger = false)
6196  {
6197  global $langs;
6198 
6199  $error = 0;
6200 
6201  $now=dol_now();
6202 
6203  $fieldvalues = $this->set_save_query();
6204  if (array_key_exists('date_creation', $fieldvalues) && empty($fieldvalues['date_creation'])) $fieldvalues['date_creation']=$this->db->idate($now);
6205  if (array_key_exists('fk_user_creat', $fieldvalues) && ! ($fieldvalues['fk_user_creat'] > 0)) $fieldvalues['fk_user_creat']=$user->id;
6206  unset($fieldvalues['rowid']); // The field 'rowid' is reserved field name for autoincrement field so we don't need it into insert.
6207 
6208  $keys=array();
6209  $values = array();
6210  foreach ($fieldvalues as $k => $v) {
6211  $keys[$k] = $k;
6212  $value = $this->fields[$k];
6213  $values[$k] = $this->quote($v, $value);
6214  }
6215 
6216  // Clean and check mandatory
6217  foreach($keys as $key)
6218  {
6219  // If field is an implicit foreign key field
6220  if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') $values[$key]='';
6221  if (! empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') $values[$key]='';
6222 
6223  //var_dump($key.'-'.$values[$key].'-'.($this->fields[$key]['notnull'] == 1));
6224  if ($this->fields[$key]['notnull'] == 1 && ! isset($values[$key]))
6225  {
6226  $error++;
6227  $this->errors[]=$langs->trans("ErrorFieldRequired", $this->fields[$key]['label']);
6228  }
6229 
6230  // If field is an implicit foreign key field
6231  if (preg_match('/^integer:/i', $this->fields[$key]['type']) && empty($values[$key])) $values[$key]='null';
6232  if (! empty($this->fields[$key]['foreignkey']) && empty($values[$key])) $values[$key]='null';
6233  }
6234 
6235  if ($error) return -1;
6236 
6237  $this->db->begin();
6238 
6239  if (! $error)
6240  {
6241  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element;
6242  $sql.= ' ('.implode( ", ", $keys ).')';
6243  $sql.= ' VALUES ('.implode( ", ", $values ).')';
6244 
6245  $res = $this->db->query($sql);
6246  if ($res===false) {
6247  $error++;
6248  $this->errors[] = $this->db->lasterror();
6249  }
6250  }
6251 
6252  if (! $error)
6253  {
6254  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element);
6255  }
6256 
6257  if (! $error)
6258  {
6259  $result=$this->insertExtraFields();
6260  if ($result < 0) $error++;
6261  }
6262 
6263  if (! $error && ! $notrigger)
6264  {
6265  // Call triggers
6266  $result=$this->call_trigger(strtoupper(get_class($this)).'_CREATE',$user);
6267  if ($result < 0) { $error++; }
6268  // End call triggers
6269  }
6270 
6271  // Commit or rollback
6272  if ($error) {
6273  $this->db->rollback();
6274  return -1;
6275  } else {
6276  $this->db->commit();
6277  return $this->id;
6278  }
6279  }
6280 
6281 
6289  public function fetchCommon($id, $ref = null)
6290  {
6291  if (empty($id) && empty($ref)) return false;
6292 
6293  $sql = 'SELECT '.$this->get_field_list();
6294  $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element;
6295 
6296  if(!empty($id)) $sql.= ' WHERE rowid = '.$id;
6297  else $sql.= " WHERE ref = ".$this->quote($ref, $this->fields['ref']);
6298 
6299  $res = $this->db->query($sql);
6300  if ($res)
6301  {
6302  $obj = $this->db->fetch_object($res);
6303  if ($obj)
6304  {
6305  $this->setVarsFromFetchObj($obj);
6306  return $this->id;
6307  }
6308  else
6309  {
6310  return 0;
6311  }
6312  }
6313  else
6314  {
6315  $this->error = $this->db->lasterror();
6316  $this->errors[] = $this->error;
6317  return -1;
6318  }
6319  }
6320 
6328  public function updateCommon(User $user, $notrigger = false)
6329  {
6330  global $langs;
6331 
6332  $error = 0;
6333 
6334  $now=dol_now();
6335 
6336  $fieldvalues = $this->set_save_query();
6337  if (array_key_exists('date_modification', $fieldvalues) && empty($fieldvalues['date_modification'])) $fieldvalues['date_modification']=$this->db->idate($now);
6338  if (array_key_exists('fk_user_modif', $fieldvalues) && ! ($fieldvalues['fk_user_modif'] > 0)) $fieldvalues['fk_user_modif']=$user->id;
6339  unset($fieldvalues['rowid']); // The field 'rowid' is reserved field name for autoincrement field so we don't need it into update.
6340 
6341  $keys=array();
6342  $values = array();
6343  foreach ($fieldvalues as $k => $v) {
6344  $keys[$k] = $k;
6345  $value = $this->fields[$k];
6346  $values[$k] = $this->quote($v, $value);
6347  $tmp[] = $k.'='.$this->quote($v, $this->fields[$k]);
6348  }
6349 
6350  // Clean and check mandatory
6351  foreach($keys as $key)
6352  {
6353  if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') $values[$key]=''; // This is an implicit foreign key field
6354  if (! empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') $values[$key]=''; // This is an explicit foreign key field
6355 
6356  //var_dump($key.'-'.$values[$key].'-'.($this->fields[$key]['notnull'] == 1));
6357  /*
6358  if ($this->fields[$key]['notnull'] == 1 && empty($values[$key]))
6359  {
6360  $error++;
6361  $this->errors[]=$langs->trans("ErrorFieldRequired", $this->fields[$key]['label']);
6362  }*/
6363  }
6364 
6365  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET '.implode( ',', $tmp ).' WHERE rowid='.$this->id ;
6366 
6367  $this->db->begin();
6368  if (! $error)
6369  {
6370  $res = $this->db->query($sql);
6371  if ($res===false)
6372  {
6373  $error++;
6374  $this->errors[] = $this->db->lasterror();
6375  }
6376  }
6377 
6378  if (! $error && ! $notrigger) {
6379  // Call triggers
6380  $result=$this->call_trigger(strtoupper(get_class($this)).'_MODIFY',$user);
6381  if ($result < 0) { $error++; } //Do also here what you must do to rollback action if trigger fail
6382  // End call triggers
6383  }
6384 
6385  // Commit or rollback
6386  if ($error) {
6387  $this->db->rollback();
6388  return -1;
6389  } else {
6390  $this->db->commit();
6391  return $this->id;
6392  }
6393  }
6394 
6402  public function deleteCommon(User $user, $notrigger = false)
6403  {
6404  $error=0;
6405 
6406  $this->db->begin();
6407 
6408  if (! $error) {
6409  if (! $notrigger) {
6410  // Call triggers
6411  $result=$this->call_trigger(strtoupper(get_class($this)).'_DELETE', $user);
6412  if ($result < 0) { $error++; } // Do also here what you must do to rollback action if trigger fail
6413  // End call triggers
6414  }
6415  }
6416 
6417  if (! $error)
6418  {
6419  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE rowid='.$this->id;
6420 
6421  $res = $this->db->query($sql);
6422  if($res===false) {
6423  $error++;
6424  $this->errors[] = $this->db->lasterror();
6425  }
6426  }
6427 
6428  // Commit or rollback
6429  if ($error) {
6430  $this->db->rollback();
6431  return -1;
6432  } else {
6433  $this->db->commit();
6434  return 1;
6435  }
6436  }
6437 
6444  public function initAsSpecimenCommon()
6445  {
6446  $this->id = 0;
6447 
6448  // TODO...
6449  }
6450 
6455  public function fetchComments()
6456  {
6457  require_once DOL_DOCUMENT_ROOT.'/core/class/comment.class.php';
6458 
6459  $comment = new Comment($this->db);
6460  $this->comments = Comment::fetchAllFor($this->element, $this->id);
6461  return 1;
6462  }
6463 
6469  public function getNbComments()
6470  {
6471  return count($this->comments);
6472  }
6473 
6474 }
setExtraParameters()
Set extra parameters.
setShippingMethod($shipping_method_id)
Change the shipping method.
getIdContact($source, $code, $status=0)
Return id of contacts for a source and a contact code.
static fetchAllFor($element_type, $fk_element)
Load comments linked with current task.
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.
getChildrenOfLine($id)
Get children of line.
setBankAccount($fk_account)
Change the bank account.
deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid='')
Delete all links between an object $this.
dol_format_address($object, $withcountry=0, $sep="\n", $outputlangs='', $mode=0)
Return a formated address (part address/zip/town/state) according to country rules.
updateRangOfLine($rowid, $rang)
Update position of line (rang)
Class to manage Dolibarr users.
Definition: user.class.php:39
setProject($projectid)
Link element with a project.
swapContactStatus($rowid)
Update status of a contact linked to object.
delete_resource($rowid, $element, $notrigger=0)
Delete a link to resource line.
quote($value, $fieldsentry)
Add quote to field value if necessary.
initAsSpecimenCommon()
Initialise object with example values Id must be 0 if object instance is a specimen.
dol_print_error($db='', $error='', $errors=null)
Affiche message erreur system avec toutes les informations pour faciliter le diagnostic et la remonte...
getCountry($searchkey, $withcode='', $dbtouse=0, $outputlangs='', $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
fetchCommon($id, $ref=null)
Load object in memory from the database.
getFullName($langs, $option=0, $nameorder=-1, $maxlen=0)
Return full name (civility+' '+name+' '+lastname)
setStatut($status, $elementId=null, $elementType='')
Set status of an object.
setVarsFromFetchObj(&$obj)
Function to load data from a SQL pointer into properties of current object $this. ...
getRangOfLine($rowid)
Get position of line (rang)
add_contact($fk_socpeople, $type_contact, $source='external', $notrigger=0)
Add a link between element $this->element and a contact.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='')
Write log message into outputs.
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
fetchComments()
Load comments linked with current task.
line_max($fk_parent_line=0)
Get max value used for position of line (rang)
load_previous_next_ref($filter, $fieldid, $nodbprefix=0)
Load properties id_previous and id_next by comparing $fieldid with $this->ref.
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...
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)...
delete_linked_contact($source='', $code='')
Delete all links between an object $this and all its contacts.
getBannerAddress($htmlkey, $object)
Return full address for banner.
$conf db user
Definition: repair.php:105
setWarehouse($warehouse_id)
Change the warehouse.
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...
deleteExtraFields()
Delete all extra fields values for the current object.
updateCommon(User $user, $notrigger=false)
Update object into database.
liste_contact($statut=-1, $source='external', $list=0, $code='')
Get array of all contacts for an object.
update_note($note, $suffix='')
Update note of element.
dol_now($mode='gmt')
Return date for now.
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...
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition: repair.php:104
setDocModel($user, $modelpdf)
Set last model used by doc generator.
updateObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='')
Update object linked of a current object.
Class to manage comment.
getFullAddress($withcountry=0, $sep="\n")
Return full address of contact.
if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if(!empty($conf->fournisseur->enabled)&&$user->rights->fournisseur->facture->lire) if(!empty($conf->don->enabled)&&$user->rights->societe->lire) if(!empty($conf->tax->enabled)&&$user->rights->tax->charges->lire) if(!empty($conf->facture->enabled)&&!empty($conf->commande->enabled)&&$user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if(!empty($conf->fournisseur->enabled)&&$user->rights->fournisseur->facture->lire) $resql
Social contributions to pay.
Definition: index.php:1013
line_order($renum=false, $rowidorder='ASC', $fk_parent_line=true)
Save a new position (field rang) for details lines.
deleteCommon(User $user, $notrigger=false)
Delete object in database.
update_ref_ext($ref_ext)
Update external ref of element.
set_save_query()
Function to prepare the values to insert.
getNbComments()
Return nb comments already posted.
call_trigger($trigger_name, $user)
Call trigger based on this instance.
add_object_linked($origin=null, $origin_id=null)
Add objects linked in llx_element_element.
errorsToString()
Method to output saved errors.
type
Definition: viewcat.php:283
Class to manage addresses.
delete_contact($rowid, $notrigger=0)
Delete a link to contact line.
Parent class of all other business classes (invoices, contracts, proposals, orders, ...)
dolGetFirstLastname($firstname, $lastname, $nameorder=-1)
Return firstname and lastname in correct order.