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)); } } ?>