| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372 | <?php/** * Define a client. * @author Charles DUBOIS * @category Plugin * @license MIT */class Client extends Entity{	public $id;	public $label; //Libellé (Texte)	public $name; //Libellé (Texte)	public $firstname; //Libellé (Texte)	public $state; //Etat (Liste classique)	public $pseudonym; //Pseudonyme, Acronyme... (Texte)	public $code; //Code client (Texte)	public $category; //Categorie client (Liste configurable)	public $siret; //N° SIRET (Texte)	public $comment; //Commentaire (Texte Long)	public $slug; //Identifiant unique (Texte)	public $type; //Type (Particulier ou Entreprise) (Liste classique)	public $condition; //Condition (prospect ou client) (Liste classique)	public $parent; //Client parent (Entier)	public $job; //Métier (Texte)	public $meta; //Meta (JSON)	public $firm; //Etablissement (Entier)		protected $TABLE_NAME = 'client';	public $entityLabel = 'Client';	public $fields = array(		'id' => array('type'=>'key', 'label' => 'Identifiant'),		'label' => array('type'=>'text', 'label' => 'Libellé'),		'name' => array('type'=>'text', 'label' => 'Nom'),		'firstname' => array('type'=>'text', 'label' => 'Prénom'),		'state' => array('type'=>'list', 'label' => 'Etat'),		'pseudonym' => array('type'=>'text', 'label' => 'Pseudonyme'),		'code' => array('type'=>'text', 'label' => 'Code client'),		'category' => array('type'=>'dictionary', 'label' => 'Catégorie','link'=>'class/Dictionary.class.php'),		'siret' => array('type'=>'text', 'label' => 'N° SIRET'),		'comment' => array('type'=>'textarea', 'label' => 'Commentaire'),		'slug' => array('type'=>'text', 'label' => 'Slug'),		'type' => array('type'=>'list', 'label' => 'Type (Particulier ou Entreprise)'),		'condition' => array('type'=>'list', 'label' => 'Condition (prospect ou client)'),		'parent' => array('type'=>'int', 'label' => 'Id client parent','link'=>'plugin/client/Client.class.php'),		'meta' => array('type'=>'textarea', 'label' => 'Meta'),		'job' => array('type'=>'text', 'label' => 'Métier'),		'firm' => array('type'=>'int', 'label' => 'Etablissement','link'=>'class/Firm.class.php')	);		//Colonnes indexées	public $indexes = array('parent','category','type','firm');	public function __construct(){		parent::__construct();		$this->state = self::ACTIVE;	}	public function save(){		if(empty($this->slug)){			$this->slug = slugify($this->label);			for($i = 2;$i<1000;$i++){				if(self::rowCount(array('slug'=>$this->slug)) == 0) break;				$this->slug = slugify($this->label).'-'.$i;			}		}		parent::save();		if(empty($this->code)){			$this->code = self::code($this);			for($i = 2;$i<1000;$i++){				if(self::rowCount(array('code'=>$this->code)) == 0) break;				$this->code = self::code($this).'-'.$i;			}			$this->save();		}	}	public function meta($key=null,$value=null){		$meta = json_decode($this->meta,true);		$meta = !$meta ? array(): $meta ;		if(!isset($key) && !isset($value)) return $meta;		if(!isset($value)) return isset($meta[$key])?$meta[$key]:'';		$meta[$key] = $value;		$this->meta = json_encode($meta);	}	public function condition(){		return self::conditions($this->condition);	}	public function type(){		return self::types($this->type);	}		public function dir(){		return File::dir().'client'.SLASH.$this->id.SLASH;	}	public function logo($returnPath = false){		$mask = $this->dir().'logo.*';		$files = glob($mask);		if($returnPath) return isset($files[0]) ? $files[0] : __DIR__.SLASH.'img'.SLASH.'default-logo.png';		return isset($files[0]) ? 'action.php?action=client_assets_load&type=logo&client='.$this->id : 'action.php?action=client_assets_load&type=logo';	}	public function cover($returnPath = false){		$mask = $this->dir().'cover.*';		$files = glob($mask);		if($returnPath) return isset($files[0]) ? $files[0] : __DIR__.SLASH.'img'.SLASH.'default-cover.jpg';		return isset($files[0]) ? 'action.php?action=client_assets_load&type=cover&client='.$this->id : 'action.php?action=client_assets_load&type=cover';	}	//Vérification des doublons par libellés	public static function check_duplicate($field,$label,$omitId = null){		$rows = array();		switch($field){			case 'label':				$query = 'SELECT * FROM {{table}} WHERE (soundex(?) = soundex(label) OR label=? OR label like ?)';				$data = array($label,$label,$label);				if(isset($omitId)){					$query .= ' AND id!=?';					$data[] = $omitId;				}				$regex = '/\s(d(es?|u)|l(a|es?)|une?|à)\s/i';				$rows = self::staticQuery($query,$data,true);				foreach ($rows as $key => $row) {					$rows[$key] = $rows[$key]->toArray();					//supression des articles définis/indefinis pour plus de pertinence					$new = preg_replace($regex,' ',mb_strtolower($label));					$existing =  preg_replace($regex,'',mb_strtolower($rows[$key]['label']));					$rows[$key]['levenshtein'] =  levenshtein($existing,$new);					if($rows[$key]['levenshtein']>3) unset($rows[$key]);				}				//tri par levenstein				usort($rows,function($a,$b){					return $a['levenshtein'] > $b['levenshtein'];				});			break;			case 'mail':			case 'phone':				$type = $field == 'mail' ? Contact::PROFESSIONAL_MAIL : Contact::MOBILE;				foreach(Contact::loadAll(array(					'type' => $type,					'state' => Contact::ACTIVE,					'value' => trim($label),					'scope' => 'client'				)) as $item){					$client = Client::getById($item->uid);					$row = $client->toArray();					$row['levenshtein'] = 1;					$rows[] = $row;				}			break;						case 'siret':				foreach(Client::loadAll(array(					'siret' => trim($label),					'state' => Contact::ACTIVE				)) as $item){					$row = $item->toArray();					$row['levenshtein'] = 1;					$rows[] = $row;				}			break;			default:				return;			break;		}				return $rows;	}	//Fusionne le client spécifié avec l'instance de client depuis lequel est appellé la méthode	// le tableau keeping définis quel coté écrase l'autre dans le cas ou les deux clients sont renseignés (left = instance, right = parametre client)	public function merge($client,$keeping = array()){		$logs = array('Fusion du client '.$client->label().' (#'.$client->id.') sur '.$this->label().' (#'.$this->id.')  ');		Plugin::callHook('client_merge',array($this,$client,&$logs));		foreach ($keeping as $key => $value) {			if(!empty($this->$key) && empty($client->$key)){				$logs[] = $key.' origine : renseigné, fusionné : non renseigné';				continue;			}			if($this->$key == $client->$key){				$logs[] = $key.' origine et fusionné identiques';				continue;			}			if(empty($this->$key) && !empty($client->$key)){				$this->$key = $client->$key;				$logs[] = $key.' origine : non renseigné, fusionné : renseigné';				continue;			}			if(!empty($this->$key) && !empty($client->$key)){				$logs[] = $key.' origine :  renseigné, fusionné : renseigné, utilisation du tableau d\'ecrasement';				if($value == 'left') continue;				if($value == 'right') $this->$key = $client->$key;			}		}		$logs[] = 'Sauvegarde du client d\'origine';		$this->save();		$logs[] = 'Suppression du client fusionné';		self::delete(array('id'=>$client->id));		return $logs;	}	public static function conditions($key = null){		global $conf;		$conditions = array(			'prospect' => array('label' =>'Prospect'),			'client' => array('label' => ucFirst($conf->get('client_label_singular'))),		);		if(!isset($key)) return $conditions;		return isset($conditions[$key]) ? $conditions[$key] : array('label' =>'Inconnu');	}	public static function types($key = null){		$types = array(			'individual' => array('label' =>'Personne'),			'firm' => array('label' =>'Structure'),		);		if(!isset($key)) return $types;		return isset($types[$key]) ? $types[$key] : array('label' =>'Inconnu');	}	public static function addressType($key = null){		$types = array(			'global' => array('label' =>'Général','icon'=>'far fa-building'),			'invoice' => array('label' =>'Facturation','icon'=>'fas fa-file-invoice-dollar'),			'shipping' => array('label' =>'Livraison','icon'=>'fas fa-shipping-fast')		);		Plugin::callHook('client_address_type',array($types) );		if(!isset($key)) return $types;		return isset($types[$key]) ? $types[$key] : array('label' =>'Inconnu');	}	public static function internals($key = null){		$internals = array(			'commercial' => array('label' =>'Commercial'),			'technician' => array('label' =>'Technicien')		);		if(!isset($key)) return $internals;		return isset($internals[$key]) ? $internals[$key] : array('label' =>'Inconnu');	}	public static function code($client){		global $conf;				$mask = empty($conf->get('client_code_mask')) ? '{{label[2]}}-{{Y}}{{M}}-{{id}}' : $conf->get('client_code_mask');		$data = $client->toArray();			$data['label'] = $client->label();		$data['M'] = date('m');		$data['m'] = date('m');		$data['Y'] = date('Y');		$data['y'] = date('y');				$mask = preg_replace_callback('/{{label\[([0-9]*)\]}}/is', function($matches) use ($client){			if(count($matches)>=1){				return strlen($client->label>=$matches[1]) ? substr($client->label, 0,$matches[1]) : $client->label;			}else{				return $matches[0];			}		}, $mask);		$mask = preg_replace_callback('/{{rand\(([0-9]*),([0-9]*)\)}}/is', function($matches){			if(count($matches)>=2){				return mt_rand($matches[1],$matches[2]);			}else{				return $matches[0];			}		}, $mask);		$value = template($mask,$data,true);		return strtoupper(slugify($value));	}	//Récupere les adresses du client, de son parent, de ses enfants et de ses frêres	public function addresses($type = null,$order='zip',$limit = null, $parent = false, $siblings = false, $childs = false){		$queryFilters = '';		$data = array();		if ($parent) {			$queryFilters .= ' OR id=(SELECT parent FROM client WHERE id=?) ';			$data[] = $this->id;		}		if ($siblings) {			$queryFilters .= ' OR parent = (SELECT parent FROM client WHERE id=?) ';			$data[] = $this->id;		}		if ($childs) {			$queryFilters .= ' OR parent = ? ';			$data[] = $this->id;		}		$query = 'SELECT address.*, client.label FROM `address`				LEFT JOIN client ON address.uid = client.id				WHERE uid IN (SELECT id FROM client WHERE id = ? '.$queryFilters.' ) AND scope="client" ';		$data[] = $this->id;		if(isset($type))			$query.= ' AND address.type ="'.$type.'" ';		if(isset($order))			$query.= ' ORDER BY '.$order;		if(isset($limit))			$query.= ' LIMIT '.$limit;		//todo gérer  + de 1 niveau		$address = Address::staticQuery($query,$data,true);		if (isset($order) && $order == 'fullname') {			usort($address,function($a,$b){				if($a->fullName() == $b->fullName()) return 0;				return $a->fullName() > $b->fullName() ? 1 :-1 ;			});		}		return $address;	}	public function contacts($key=null){		$contacts = array();		$filters = array('uid'=>$this->id,'scope'=>'client') ;		if(isset($key)) $filters['type'] = $key;				foreach(Contact::loadAll($filters) as $contact){			$contacts[$contact->type] = $contact;		}		if(!isset($key)) return $contacts;		return isset($contacts[$key]) ? $contacts[$key] : new Contact();	}	public function subsites(){		return $this->id!=0 ? Client::loadAll(array('parent'=>$this->id)) : array();	}	public function holding(){		return $this->id!=0 && $this->parent!=0 ? Client::getById($this->parent) : new Client();	}	public function label(){		return $this->type=='individual' ? $this->firstname.' '.$this->name : $this->label;	}	public function remove($recursive = false){		$this->state = Client::INACTIVE;		$this->save();		if($recursive){			foreach(Client::loadAll(array('parent'=>$this->id,'state:!='=>Client::INACTIVE)) as $subclient){				$subclient->remove();			} 		}		global $myFirm;		//Gestion des champs dynamiques		if($myFirm->has_plugin('fr.core.dynamicform')){			Plugin::need('dynamicform/DynamicForm');			Dynamicform::remove('client-sheet-custom',array(				'scope'=>'client',				'uid'=>$this->id			));		}		ContactPerson::change(array('state'=>Client::INACTIVE),array('scope'=>'client','uid'=>$this->id));		Address::delete(array('scope'=>'client','uid'=>$this->id));	}}?>
 |