action.php 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472
  1. <?php
  2. /** CLIENT **/
  3. //Récuperation d'une liste de client
  4. Action::register('client_client_search',function(&$response){
  5. global $myUser,$_,$myFirm;
  6. //on verifie que l'utilisateur a un read complet sur les client ou acces a au moins une fiche
  7. if(!$myUser->can('client','read') && !$myUser->can('client_sheet','read',0,array('contains'=>true))) throw new Exception("Permission non accordée");
  8. require_once(__DIR__.SLASH.'Client.class.php');
  9. // OPTIONS DE RECHERCHE, A ACTIVER POUR UNE RECHERCHE AVANCEE
  10. $query = 'SELECT DISTINCT main.*,phone.value as phone,mail.value as mail,parent.id parentId,parent.label parentLabel,address.street,address.complement,address.zip,address.city,'.Firm::joinString('fi').','.Dictionary::joinString('category').' FROM {{table}} main
  11. LEFT JOIN '.Client::tableName().' parent ON main.parent=parent.id
  12. LEFT JOIN '.Firm::tableName().' fi ON main.firm=fi.id
  13. LEFT JOIN '.Dictionary::tableName().' category ON main.category=category.id
  14. LEFT JOIN '.Contact::tableName().' phone ON phone.uid=main.id AND phone.scope="client" AND phone.type="mobile"
  15. LEFT JOIN '.Contact::tableName().' mail ON mail.uid=main.id AND mail.scope="client" AND mail.type="professional_mail"
  16. LEFT JOIN '.Address::tableName().' address ON address.uid=main.id AND address.scope="client" AND address.type="'.Address::MAIN.'"
  17. WHERE 1';
  18. $data = array();
  19. $allowedFields = array();
  20. $fields = array();
  21. $hasDynamicPlugin = $myFirm->has_plugin('fr.core.dynamicform') || ($myFirm->id==-1 && Plugin::is_active('fr.core.dynamicform'));
  22. //ajout des champs dynamiques dans la recherche
  23. if($hasDynamicPlugin){
  24. Plugin::need('dynamicform/DynamicForm');
  25. //le premier argument contient le slug du formulaire contenant toutes les colonnes possibles, le second les colonnes non choisies,la requete, l'alias si nécessaire
  26. $dynamicFields = DynamicForm::list('client-sheet-custom',array('firm'=>$myFirm->id));
  27. DynamicForm::query_column_add($dynamicFields,$query,'main');
  28. //On récupère les types de champs qui possèdent une propriété onLoad afin de l'appliquer si on a un champ dynamique
  29. $fieldTypes = array();
  30. $fieldCustom = array();
  31. foreach($dynamicFields as $field){
  32. $fieldTypes[$field['slug']] = $field['type'];
  33. $fieldCustom[$field['slug']] = $field;
  34. $allowedFields[] = 'dynamicField_'.$field['id'].'.value';
  35. }
  36. }
  37. //selection des colonnes à récuperer
  38. // le premier argument contient toutes les colonnes possibles, le second les colonnes non choisies
  39. column_secure_query(Client::fields(),$_,$query);
  40. //Recherche simple
  41. if(!empty($_['filters']['keyword'])){
  42. $query .= ' AND ( (main.type=? AND (main.label LIKE ? OR main.pseudonym LIKE ?) ) OR (main.type=? AND (main.name LIKE ? OR main.firstname LIKE ?)) OR main.comment LIKE ?)';
  43. $data[] = 'firm';
  44. $data[] = '%'.$_['filters']['keyword'].'%';
  45. $data[] = '%'.$_['filters']['keyword'].'%';
  46. $data[] = 'individual';
  47. $data[] = '%'.$_['filters']['keyword'].'%';
  48. $data[] = '%'.$_['filters']['keyword'].'%';
  49. $data[] = '%'.$_['filters']['keyword'].'%';
  50. }
  51. if(isset($_['selected'])){
  52. $query .= ' AND main.id IN ('.implode(',',array_fill(0, count($_['selected']), '?')).')';
  53. foreach ($_['selected'] as $selected)
  54. $data[] = $selected;
  55. }
  56. $query .= ' AND main.state != ?';
  57. $data[] = Client::INACTIVE;
  58. //on vérifie les droits spéciaux qui peuvent bypasser
  59. //récuperation des droits spéciaux sur les fiches
  60. //on initialise a 0 pour eviter le plantage si aucun droit
  61. $rights = array(0);
  62. if(isset($myUser->rights['client_sheet'][0])) $rights += $myUser->rights['client_sheet'][0];
  63. if(isset($myUser->rights['client_sheet'][$myFirm->id])) $rights += $myUser->rights['client_sheet'][$myFirm->id];
  64. //tableau des id deletables
  65. $deletableSheets = array();
  66. //var_dump($rights);
  67. foreach($rights as $uid => $right){
  68. $data[] = $uid;
  69. if(isset($right['delete']) && $right['delete']===true) $deletableSheets[] = $uid;
  70. }
  71. $query .= ' AND (main.id IN('.implode(',',array_fill(0, count($rights), '?')).') OR main.firm IN(?,?) ) ';
  72. $data[] = 0;
  73. $data[] = $myFirm->id;
  74. Plugin::callHook('client_search',array(&$query,&$data));
  75. //Recherche avancée
  76. if(isset($_['filters']['advanced'])){
  77. //traitement filtre custom pour recherche par contact interne
  78. $_['filters']['advanced'] = filter_alteration($_['filters']['advanced'],'internal_contact',function($filter) use(&$query,&$data){
  79. global $_;
  80. switch($filter['operator']){
  81. case '=':
  82. case '!=':
  83. $query.=' AND main.id '.($filter['operator']=='!='?' NOT ':'').' IN (SELECT uid FROM '.ContactPerson::tablename().' cp WHERE cp.scope="client" AND type="user" AND account=?) ';
  84. $data[] = $filter['value'][0];
  85. break;
  86. case 'null':
  87. case 'not null':
  88. $query.=' AND (SELECT count(id) FROM '.ContactPerson::tablename().' cp WHERE cp.scope="client" AND type="user" AND uid=main.id) '.($filter['operator']=='null'?'=':'!=').' 0 ';
  89. break;
  90. }
  91. return null;
  92. });
  93. filter_secure_query($_['filters']['advanced'],array_merge($allowedFields,array('main.id','main.label','address.city','address.zip','main.type','main.condition','main.creator','main.job','main.code','main.siret','main.created','mail.value','phone.value','main.comment','fi.id')),$query,$data);
  94. }
  95. //Tri des colonnes
  96. if(isset($_['sort'])) sort_secure_query($_['sort'],array_merge($allowedFields,array('main.label','main.condition','main.type','main.state','mail.value','address.city','phone.value','fi.label')),$query,$data);
  97. //Pagination
  98. $itemPerPage = 20;
  99. if($_['export'] == 'true') $itemPerPage = 5000;
  100. $response['pagination'] = Client::paginate($itemPerPage,(!empty($_['page'])?$_['page']:0),$query,$data,'main');
  101. $clients = Client::staticQuery($query,$data,true,1);
  102. $ids = array();
  103. foreach($clients as $client)
  104. $ids[]= $client->id;
  105. $subsites = array();
  106. if(!empty($ids)){
  107. foreach(Client::loadAll(array('parent:IN'=>$ids,'state'=>Client::ACTIVE)) as $subsite){
  108. if(!isset($subsites[$subsite->parent])) $subsites[$subsite->parent] = array();
  109. $subsites[$subsite->parent][] = $subsite->toArray();
  110. }
  111. }
  112. foreach($clients as $client){
  113. $row = $client->toArray();
  114. $row['deletable'] = true;
  115. if($myFirm->id!=$client->firm && !in_array($client->id, $deletableSheets)) $row['deletable'] = false;
  116. if(!$myUser->can('client','delete')) $row['deletable'] = false;
  117. $row['phone'] = $client->foreign('phone');
  118. $row['mail'] = $client->foreign('mail');
  119. $row['category'] = $client->join('category');
  120. $firm = $client->firm!= 0 ? $client->join('firm') : new Firm();
  121. $row['firm'] = $firm->toArray();
  122. $mainAddress = new Address();
  123. $mainAddress->street = $client->foreign('street');
  124. $mainAddress->complement = $client->foreign('complement');
  125. $mainAddress->zip = $client->foreign('zip');
  126. $mainAddress->city = $client->foreign('city');
  127. $row['address'] = $mainAddress->toArray();
  128. $row['address']['mapurl'] = $mainAddress->mapUrl();
  129. $row['type'] = $client->type();
  130. $row['condition'] = $client->condition();
  131. $row['logo'] = $client->logo();
  132. $row['holding'] = false;
  133. $row['affiliate'] = false;
  134. $row['meta'] = $client->meta();
  135. if($client->parent != 0){
  136. $holding = new Client();
  137. $holding->id = $client->foreign('parentId');
  138. $holding->label = $client->foreign('parentLabel');
  139. if($_['export'] == 'true'){
  140. $row['holding'] = $holding->toArray();
  141. }else{
  142. $row['parent'] = $holding->label;
  143. }
  144. }
  145. if($_['export'] == 'true'){
  146. $row['created'] = date('d-m-Y',$row['created']);
  147. $row['updated'] = date('d-m-Y',$row['updated']);
  148. $row['state'] = $row['state'] == Client::ACTIVE ? 'Actif' : 'Supprimé' ;
  149. }
  150. //Gestion des champs dynamiques
  151. if($hasDynamicPlugin){
  152. DynamicForm::search_values($row,array(
  153. 'slugs'=> $client->foreign(),
  154. 'types'=> $fieldTypes,
  155. 'scope' => 'client',
  156. 'force-raw' => $_['export'] == 'true'
  157. ));
  158. }
  159. if(isset($subsites[$client->id])){
  160. $row['affiliate']['rows'] = $subsites[$client->id];
  161. $row['affiliate']['count'] = count($subsites[$client->id]);
  162. }
  163. $response['rows']['client-'.$client->id] = $row;
  164. }
  165. /* Mode export */
  166. if($_['export'] == 'true'){
  167. $fieldsMapping = array();
  168. foreach (Client::fields(false) as $key => $value)
  169. $fieldsMapping[$value['label']] = $key ;
  170. if($myFirm->has_plugin('fr.core.dynamicform')){
  171. foreach ($fieldCustom as $slug => $value)
  172. $fieldsMapping[$value['label']] = $slug;
  173. }
  174. $fieldsMapping['E-mail'] = 'mail';
  175. $fieldsMapping['Téléphone'] = 'phone';
  176. $stream = Excel::exportArray($response['rows'],$fieldsMapping,'Export');
  177. File::downloadStream($stream,'export-clients-'.date('d-m-Y').'.xlsx');
  178. exit();
  179. }
  180. });
  181. Action::register('client_client_mail_copy',function(&$response){
  182. global $myUser,$_;
  183. if(!$myUser->can('client','read')) throw new Exception('Vous n\'avez pas la permission de copier cet e-mail');
  184. if(count($_['ids'])==0) return;
  185. $response['mails'] = array();
  186. foreach(Contact::loadAll(array('scope'=>'client','uid:IN'=>$_['ids'],'type'=>'professional_mail')) as $contact){
  187. $response['mails'][] = $contact->value;
  188. }
  189. });
  190. //Fusion de deux clients
  191. Action::register('client_client_merge',function(&$response){
  192. global $myUser,$_,$conf;
  193. User::check_access('client','configure');
  194. require_once(__DIR__.SLASH.'Client.class.php');
  195. $response['rows'] = array();
  196. if(empty($_['left'])) throw new Exception($conf->get('client_label_singular')." de base non définis");
  197. if(empty($_['right'])) throw new Exception($conf->get('client_label_singular')." a fusionner non définis");
  198. if($_['right'] == $_['left']) throw new Exception("Vous ne pouvez pas fusionner un ".$conf->get('client_label_singular')." avec lui même");
  199. $left = Client::getById($_['left']);
  200. $right = Client::getById($_['right']);
  201. if(empty($left->id)) throw new Exception($conf->get('client_label_singular')." de base introuvable");
  202. if(empty($right->id)) throw new Exception($conf->get('client_label_singular')." de a fusionner introuvable");
  203. if(empty($_['keep'])) throw new Exception("Tableau d'écrasement non définis");
  204. $response['logs'] = $left->merge($right,$_['keep']);
  205. });
  206. //Vérifie les duplicatas possibles avec les clients existants
  207. Action::register('client_client_check_duplicate',function(&$response){
  208. global $myUser,$_;
  209. if(!$myUser->can('client','read')) throw new Exception("Permission non accordée");
  210. require_once(__DIR__.SLASH.'Client.class.php');
  211. $response['rows'] = array();
  212. if(empty($_['label'])) return $response;
  213. if(!empty($_['id'])) return $response;
  214. $response['rows'] = Client::check_duplicate($_['field'],$_['label'], isset($_['id'])?$_['id']:null );
  215. });
  216. Action::register('client_relation_add',function(&$response){
  217. global $myUser,$_,$conf;
  218. if(!$myUser->can('client','read')) throw new Exception("Permission non accordée");
  219. require_once(__DIR__.SLASH.'Client.class.php');
  220. if(empty($_['id'])) throw new Exception($conf->get('client_label_singular')." non spécifié");
  221. if(empty($_['relation'])) throw new Exception("Relation non spécifiée");
  222. if(empty($_['level'])) throw new Exception("Type de relation non spécifiée");
  223. $site = Client::getById($_['id']);
  224. $relation = Client::getById($_['relation']);
  225. if(!$site || $site->id == 0) throw new Exception($conf->get('client_label_singular')." introuvable en base de donnée");
  226. if(!$relation || $relation->id == 0) throw new Exception($conf->get('client_label_singular')." à lier introuvable en base de donnée");
  227. if($_['level'] == 'holding'){
  228. if($relation->parent == $site->id) throw new Exception("Impossible d'ajouter en holding un établissement déjà filiale");
  229. $site->parent = $relation->id;
  230. $site->save();
  231. }else{
  232. if($site->parent == $relation->id) throw new Exception("Impossible d'ajouter en filiale un établissement déjà holding");
  233. $relation->parent = $site->id;
  234. $relation->save();
  235. }
  236. });
  237. Action::register('client_relation_delete',function(&$response){
  238. global $myUser,$_,$conf;
  239. User::check_access('client','read');
  240. require_once(__DIR__.SLASH.'Client.class.php');
  241. if(empty($_['id'])) throw new Exception($conf->get('client_label_singular')." non spécifié");
  242. if(empty($_['relation'])) throw new Exception("Relation non spécifiée");
  243. if(empty($_['level'])) throw new Exception("Type de relation non spécifiée");
  244. switch($_['level']){
  245. case 'holding':
  246. $site = Client::getById($_['id']);
  247. $relation = Client::getById($_['relation']);
  248. if(!$site || $site->id == 0) throw new Exception($conf->get('client_label_singular')." introuvable en base de donnée");
  249. if(!$relation || $relation->id == 0) throw new Exception($conf->get('client_label_singular')." à lier introuvable en base de donnée");
  250. $site->parent = null;
  251. $site->save();
  252. break;
  253. case 'subsite':
  254. $site = Client::getById($_['id']);
  255. $relation = Client::getById($_['relation']);
  256. if(!$site || $site->id == 0) throw new Exception($conf->get('client_label_singular')." introuvable en base de donnée");
  257. if(!$relation || $relation->id == 0) throw new Exception($conf->get('client_label_singular')." à lier introuvable en base de donnée");
  258. $relation->parent = null;
  259. $relation->save();
  260. break;
  261. case 'memberof':
  262. ContactPerson::remove($_['relation']);
  263. break;
  264. }
  265. });
  266. //Retourne la liste des relations (filiales et holding)
  267. Action::register('client_relation_search',function(&$response){
  268. global $myUser,$_,$myFirm;
  269. if(!$myUser->can('client','read') && $_['client']!=0 && !$myUser->can('client_sheet','read',$_['client'])) throw new Exception("Permission non accordée sur cette fiche");
  270. require_once(__DIR__.SLASH.'Client.class.php');
  271. $response['rows'] = array();
  272. if(empty($_['client'])) return $response['rows'];
  273. $filters = array('parent'=>$_['client'],'firm:IN'=>array(0,$myFirm->id),'state'=>Client::ACTIVE);
  274. //si l'user n'est pas en acces tout client, on ne lui affiche que les relation client auxquelles il a acces
  275. if(!$myUser->can('client','read')){
  276. $allowedSheets = array();
  277. foreach($myUser->rights['client_sheet'] as $firm => $rights){
  278. foreach($rights as $uid=>$right){
  279. if($right['read']) $allowedSheets[] = $uid;
  280. }
  281. }
  282. $filters['id:IN'] = $allowedSheets;
  283. }
  284. $clients = Client::loadAll($filters,array('label'));
  285. foreach($clients as $client){
  286. $row = $client->toArray();
  287. $addresses = $client->addresses('global');
  288. $row['address'] = isset($addresses[0]) ? $addresses[0] : new Address();
  289. $row['level'] = 'subsite';
  290. $response['rows'][] = $row;
  291. }
  292. $client = Client::getById($_['client']);
  293. if(!empty($client->parent)){
  294. $holdingObject = $client->holding();
  295. $holding = $holdingObject->toArray();
  296. $addresses = $holdingObject->addresses('global');
  297. $holding['address'] = isset($addresses[0]) ? $addresses[0] : new Address();
  298. $holding['level'] = 'holding';
  299. $response['rows'][] = $holding;
  300. }
  301. foreach(Client::staticQuery('SELECT c.*,cp.id as relation_id FROM '.ContactPerson::tablename().' cp LEFT JOIN {{table}} c ON c.id=cp.uid WHERE cp.account=? AND cp.scope=? and cp.type=?',array($_['client'],'client','client'),true) as $client){
  302. $row = $client->toArray();
  303. $addresses = $client->addresses('global');
  304. $row['address'] = isset($addresses[0]) ? $addresses[0] : new Address();
  305. $row['level'] = 'memberof';
  306. $row['id'] = $client->foreign('relation_id');
  307. $response['rows'][] = $row;
  308. }
  309. });
  310. Action::register('client_api_search',function(&$response){
  311. global $myUser,$_,$conf;
  312. if(!$myUser->can('client','read')) throw new Exception("Permission non accordée");
  313. require_once(__DIR__.SLASH.'Client.class.php');
  314. if(empty($conf->get('client_api_search_url'))) throw new Exception("L'api de recherche ".$conf->get('client_label_singular')." n'est pas configurée, merci de contacter un administrateur");
  315. //ex : https://entreprise.data.gouv.fr/api/sirene/v1/full_text/toxgen
  316. $url = str_replace('{{label}}',rawurlencode($_['label']),$conf->get('client_api_search_url'));
  317. $ch = curl_init();
  318. curl_setopt($ch, CURLOPT_URL, $url);
  319. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  320. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  321. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  322. $stream = curl_exec($ch);
  323. $info = curl_getinfo($ch);
  324. curl_close($ch);
  325. $json = json_decode($stream,true);
  326. if(!$json) throw new Exception("Impossible de contacter l'api de recherche ".$conf->get('client_label_singular'));
  327. if($info['http_code'] == 404 || !isset($json['etablissement']) || count($json['etablissement']) ==0 ) throw new Exception($conf->get('client_label_singular')." non trouvé avec ce libellé.");
  328. foreach ($json['etablissement'] as $row) {
  329. $line = array();
  330. $line['label'] = $row['nom_raison_sociale'];
  331. $line['siren'] = $row['siren'];
  332. $line['siret'] = $row['siret'];
  333. $line['created'] = $row['date_creation'];
  334. if(strlen($line['created'])== 8){
  335. $line['created'] = substr($line['created'], -2).'/'.substr($line['created'], -4,2).'/'.substr($line['created'], 0,4);
  336. }else{
  337. $line['created'] = '';
  338. }
  339. $line['street'] = $row['numero_voie'].' '.$row['type_voie'].' '.$row['libelle_voie'];
  340. $line['city'] = $row['libelle_commune'];
  341. $line['zip'] = $row['code_postal'];
  342. $line['size'] = $row['categorie_entreprise'];
  343. $line['status'] = $row['libelle_nature_juridique_entreprise'];
  344. $line['employees'] = $row['tranche_effectif_salarie'];
  345. $line['job'] = $row['libelle_activite_principale'];
  346. $response['rows'][] = $line;
  347. }
  348. });
  349. Action::register('client_tab_load',function(&$response){
  350. global $myUser,$_;
  351. if(!$myUser->can('client','read') && $_['id']!=0 && !$myUser->can('client_sheet','read',$_['id'])) throw new Exception("Permission non accordée sur cette fiche");
  352. $tab = $_['tab'];
  353. Plugin::callHook('client_page',array($tab));
  354. exit();
  355. });
  356. //Ajout ou modification d'élément client
  357. Action::register('client_client_save',function(&$response){
  358. global $myUser, $_, $conf,$myFirm;
  359. User::check_access('client','edit');
  360. require_once(__DIR__.SLASH.'Client.class.php');
  361. $item = Client::provide();
  362. $oldItem = clone $item;
  363. if($item->id!=0 && $item->firm!=$myFirm->id && !$myUser->can('client_sheet','edit',$item->id) ) throw new Exception("Vous n'avez pas la permission pour editer cette fiche");
  364. if(empty($_['label'])) throw new Exception("Libellé obligatoire");
  365. $item->label = $_['label'];
  366. if(isset($_['firstname']) && !empty($_['firstname'])) $item->firstname = ucfirst(mb_strtolower(trim($_['firstname'])));
  367. if(isset($_['name']) && !empty($_['name'])) $item->name = mb_strtoupper(trim($_['name']));
  368. if(isset($_['rate']) && !empty($_['rate'])) $item->rate = $_['rate'];
  369. if(isset($_['siret'])) $item->siret = $_['siret'];
  370. if(isset($_['comment'])) $item->comment = trim($_['comment']);
  371. if(isset($_['parent']) && !empty($_['parent'])) $item->parent = $_['parent'];
  372. if(isset($_['type']) && !empty($_['type'])) $item->type = $_['type'];
  373. if(!empty($conf->get('client_condition')) && $conf->get('client_condition')!='both'){
  374. $item->condition = $conf->get('client_condition');
  375. }else{
  376. if(isset($_['condition']) && !empty($_['condition'])) $item->condition = $_['condition'];
  377. }
  378. if(isset($_['category'])) $item->category = $_['category'];
  379. if(isset($_['job'])) $item->job = $_['job'];
  380. if(isset($_['pseudonym'])) $item->pseudonym = $_['pseudonym'];
  381. $item->state = Client::ACTIVE;
  382. $item->firm = $myFirm->id;
  383. Plugin::callHook('client_save',array(&$item,$oldItem));
  384. $item->save();
  385. Plugin::callHook('client_saved',array(&$item,$oldItem));
  386. //Gestion des champs dynamiques
  387. if($myFirm->has_plugin('fr.core.dynamicform')){
  388. Plugin::need('dynamicform/DynamicForm');
  389. Dynamicform::record('client-sheet-custom',array(
  390. 'scope'=>'client',
  391. 'uid'=>$item->id
  392. ),$_);
  393. }
  394. //trigger pour utilisation sur le workflow
  395. if($myFirm->has_plugin('fr.core.workflow')){
  396. Plugin::need('workflow/WorkflowEvent');
  397. WorkflowEvent::trigger('client-client-'.($oldItem->id==0?'create':'update'),array('old'=>$oldItem,'current'=>$item));
  398. }
  399. $history = new History();
  400. $history->scope = 'client';
  401. $history->uid = $item->id;
  402. if(empty($_['id'])){
  403. $history->comment = "Création ".$conf->get('client_label_singular');
  404. $history->save();
  405. }else{
  406. $history->comment = "Modification ".$conf->get('client_label_singular')." :";
  407. $differences = Entity::compare($oldItem,$item);
  408. $fields = Client::fields(false);
  409. foreach ($differences as $difference) {
  410. $field = $difference['field'];
  411. if(isset($fields[$difference['field']])) $field = $fields[$difference['field']]['label'];
  412. $history->comment.="\n".$field.' : de <code>'.truncate($difference['value1']).'</code> à <code>'.truncate($difference['value2'].'</code>');
  413. }
  414. if(count($differences)>0) $history->save();
  415. }
  416. if(!empty($_FILES['logo'])){
  417. //Suppression ancien logo
  418. foreach (glob($item->dir()."logo.*") as $filename)
  419. unlink($filename);
  420. $logo = File::upload('logo','client'.SLASH.$item->id.SLASH.'logo.{{ext}}',104857060,array('jpg','png','jpeg','gif'));
  421. Image::resize($logo['absolute'],150,150);
  422. }
  423. if(!empty($_FILES['cover'])){
  424. //Suppression ancienne bannière
  425. foreach (glob($item->dir()."cover.*") as $filename)
  426. unlink($filename);
  427. $cover = File::upload('cover','client'.SLASH.$item->id.SLASH.'cover.{{ext}}',104857060,array('jpg','png','jpeg','gif'));
  428. $path = Image::toJpg($cover['absolute']);
  429. Image::resize($path,500,500,true,false);
  430. }
  431. $response = $item->toArray();
  432. if(isset($_['phone']) || isset($_['mail'])){
  433. $contacts = $item->contacts();
  434. if(isset($_['phone'])){
  435. $phone = isset($contacts[Contact::MOBILE]) ? $contacts[Contact::MOBILE] : new Contact();
  436. if(empty($_['phone']) && $phone->id !=0){
  437. Contact::deleteById($phone->id);
  438. }else{
  439. $phone->type = Contact::MOBILE;
  440. $phone->state = Contact::ACTIVE;
  441. $phone->value = str_replace(' ', '', $_['phone']);
  442. $phone->uid = $item->id ;
  443. $phone->scope = 'client' ;
  444. $phone->save();
  445. }
  446. }
  447. if(isset($_['mail'])){
  448. $mail = isset($contacts[Contact::PROFESSIONAL_MAIL]) ? $contacts[Contact::PROFESSIONAL_MAIL] : new Contact();
  449. if(empty($_['mail']) && $mail->id !=0){
  450. Contact::deleteById($mail->id);
  451. }else{
  452. $mail->type = Contact::PROFESSIONAL_MAIL;
  453. $mail->state = Contact::ACTIVE;
  454. $mail->value = trim($_['mail']);
  455. $mail->uid = $item->id ;
  456. $mail->scope = 'client' ;
  457. $mail->save();
  458. }
  459. }
  460. }
  461. });
  462. //Ajout ou modification d'élément client
  463. Action::register('client_assets_load',function(&$response){
  464. global $myUser,$_;
  465. if(!$myUser->can('client','read') && !$myUser->can('client_sheet','read',0,array('contains'=>true))) throw new Exception("Permission non accordée");
  466. require_once(__DIR__.SLASH.'Client.class.php');
  467. switch($_['type']){
  468. case 'logo':
  469. $client = new Client;
  470. if(isset($_['client']) && !empty($_['client'])) $client->id = $_['client'];
  471. $path = $client->logo(true);
  472. break;
  473. case 'cover':
  474. $client = new Client;
  475. if(isset($_['client']) && !empty($_['client'])) $client->id = $_['client'];
  476. $path = $client->cover(true);
  477. break;
  478. case 'contact':
  479. $contact = ContactPerson::getById($_['contact']);
  480. $path = $contact->avatar();
  481. break;
  482. default:
  483. $path = '';
  484. break;
  485. }
  486. File::downloadFile($path);
  487. });
  488. //Suppression d'élement client
  489. Action::register('client_client_delete',function(&$response){
  490. global $myUser,$_,$myFirm;
  491. User::check_access('client','delete');
  492. require_once(__DIR__.SLASH.'Client.class.php');
  493. $client = Client::getById($_['id']);
  494. if($client->firm!=$myFirm->id && !$myUser->can('client_sheet','delete',$client->id) ) throw new Exception("Vous n'avez pas la permission pour supprimer cette fiche");
  495. $client->remove($_['recursive']==1);
  496. });
  497. //Sauvegarde des configurations de client
  498. Action::register('client_setting_save',function(&$response){
  499. global $myUser,$_,$conf;
  500. User::check_access('client','configure');
  501. //Si input file "multiple", possibilité de normlaiser le
  502. //tableau $_FILES récupéré avec la fonction => normalize_php_files();
  503. foreach(Configuration::setting('client') as $key=>$value){
  504. if(!is_array($value)) continue;
  505. $allowed[] = $key;
  506. }
  507. foreach ($_['fields'] as $key => $value) {
  508. if(in_array($key, $allowed))
  509. $conf->put($key,$value);
  510. }
  511. });
  512. /** CLIENTCONTACT **/
  513. //Récuperation d'une liste de clientcontact
  514. Action::register('client_contact_search',function(&$response){
  515. global $myUser,$_,$myFirm;
  516. require_once(__DIR__.SLASH.'Client.class.php');
  517. if(!$myUser->can('client','read') && $_['client']!=0 && !$myUser->can('client_sheet','read',$_['client'])) throw new Exception("Permission non accordée sur cette fiche");
  518. if(empty($_['client'])) return $response;
  519. $client = Client::getById($_['client']);
  520. //if($client->id!=0 && !in_array($client->firm,array(0,$myFirm->id))) throw new Exception("Ces contacts de fiche ne sont pas disponibles pour votre etablissement");
  521. //si l'user n'est pas en acces tout client, on ne lui affiche que les relation client auxquelles il a acces
  522. if(!$myUser->can('client','read')){
  523. $allowedSheets = array();
  524. foreach($myUser->rights['client_sheet'] as $firm => $rights){
  525. foreach($rights as $uid=>$right){
  526. if($right['read']) $allowedSheets[] = $uid;
  527. }
  528. }
  529. }
  530. foreach(ContactPerson::getAll(array('where'=>array('scope'=>'client','uid'=>$client->id))) as $clientcontact){
  531. if($clientcontact->type=="client" && isset($allowedSheets) && !in_array($clientcontact->account,$allowedSheets)) continue;
  532. $row = $clientcontact->toArray();
  533. $row['fullName'] = $clientcontact->fullName();
  534. $row['avatar'] = 'action.php?action=client_assets_load&type=contact&contact='.$clientcontact->id;
  535. $row['tag'] = $clientcontact->getTags();
  536. $row['hasTag'] = !empty($row['tag']);
  537. switch($clientcontact->type){
  538. case 'client':
  539. require_once(__DIR__.SLASH.'Client.class.php');
  540. $client = Client::getById($clientcontact->account);
  541. if(!$client) continue 2;
  542. $row['avatar'] = $client->logo();
  543. $row['fullName'] = $client->label();
  544. $row['link'] = 'index.php?module=client&page=sheet.client&id='.$row['account'];
  545. $contacts = $client->contacts();
  546. if(isset($contacts['professional_mail'])) $row['mail'] = $contacts['professional_mail']->value;
  547. if(isset($contacts['professional_mail'])) $row['mobile'] = $contacts['mobile']->value;
  548. if(!empty($client->job)) $row['job'] = $client->job;
  549. break;
  550. case 'user':
  551. $user = User::byLogin($clientcontact->account);
  552. $row['avatar'] = $user->getAvatar();
  553. $row['fullName'] = $user->fullName();
  554. $row['mobile'] = $user->mobile;
  555. $row['job'] = $user->function;
  556. $row['phone'] = $user->phone;
  557. $row['mail'] = $user->mail;
  558. break;
  559. }
  560. $response['rows'][] = $row;
  561. }
  562. });
  563. //Récuperation ou edition d'élément clientcontact
  564. Action::register('client_contact_edit',function(&$response){
  565. global $myUser,$_;
  566. User::check_access('client','edit');
  567. $contact = ContactPerson::provide();
  568. $contact->meta();
  569. $response = $contact->toArray();
  570. $response['tag'] = $contact->getTags();
  571. });
  572. //Ajout ou modification d'élément clientcontact
  573. Action::register('client_contact_save',function(&$response){
  574. global $myUser,$_,$conf;
  575. User::check_access('client','edit');
  576. Plugin::need('client/Client');
  577. $item = ContactPerson::provide();
  578. $oldItem = clone $item;
  579. $item->type = $_['type'];
  580. //Contact référent utilisteur ou client interne
  581. if(!empty($_['account'])) $item->account = $_['account'];
  582. if($item->type=='external'){
  583. if(empty($_['name']) && empty($_['firstname']) && empty($_['mail']) && empty($_['phone'])) throw new Exception("Au moins l'un des champs Prénom, Nom, Mail ou Téléphone est requis");
  584. $item->name = $_['name'];
  585. $item->firstname = $_['firstname'];
  586. $item->civility = $_['civility'];
  587. $item->meta['type'] = 'contact';
  588. if(!empty($_['mail']) && !check_mail(trim($_['mail']))) throw new Exception("Mail invalide");
  589. $item->mail = trim($_['mail']);
  590. if(!empty($_['phone']) && !check_phone_number($_['phone'])) throw new Exception("Téléphone invalide");
  591. $item->phone = normalize_phone_number($_['phone']);
  592. if(!empty($_['mobile']) && !check_phone_number($_['mobile'])) throw new Exception("Téléphone mobile invalide");
  593. $item->mobile = normalize_phone_number($_['mobile']);
  594. }
  595. $item->scope = 'client';
  596. $item->uid = $_['client'];
  597. $item->job = $_['job'];
  598. $item->comment = $_['comment'];
  599. $item->setTags($_['tag']);
  600. $item->state = ContactPerson::ACTIVE;
  601. $item->save_all();
  602. $history = new History();
  603. $history->scope = 'client';
  604. $history->uid = $_['client'];
  605. if(empty($_['id'])){
  606. $history->comment = "Création du contact ".$conf->get('client_label_singular')." ".$item->fullName();
  607. $history->save();
  608. }else{
  609. $history->comment = "Modification du contact ".$conf->get('client_label_singular')." ".$item->fullName().' : ';
  610. $differences = Entity::compare($oldItem,$item);
  611. $fields = Client::fields(false);
  612. foreach ($differences as $difference) {
  613. $field = $difference['field'];
  614. if(isset($fields[$difference['field']])) $field = $fields[$difference['field']]['label'];
  615. $history->comment.="\n".$field.' : de <code>'.truncate($difference['value1']).'</code> à <code>'.truncate($difference['value2'].'</code>');
  616. }
  617. if(count($differences)>0) $history->save();
  618. }
  619. });
  620. //Suppression d'élement clientcontact
  621. Action::register('client_contact_delete',function(&$response){
  622. global $myUser,$_,$conf;
  623. User::check_access('client','delete');
  624. $item = ContactPerson::provide();
  625. $history = new History();
  626. $history->scope = 'client';
  627. $history->uid = $item->uid;
  628. $history->comment = "Suppression du contact ".$conf->get('client_label_singular')." ".$item->fullName();
  629. $history->save();
  630. ContactPerson::remove($item->id);
  631. });
  632. //Récupération card d'un contact
  633. Action::register('client_card',function(&$response){
  634. global $myUser,$myFirm,$_;
  635. require_once(__DIR__.SLASH.'Client.class.php');
  636. $client = Client::provide();
  637. if(!$myUser->can('client','read') && $client->id!=0 && !$myUser->can('client_sheet','read',$client->id)) throw new Exception("Permission non accordée sur cette fiche");
  638. ob_start();
  639. require_once(__DIR__.SLASH.'card.client.php');
  640. $stream = ob_get_clean();
  641. $response['content'] = $stream;
  642. });
  643. //composant client
  644. Action::register('client_autocomplete',function(&$response){
  645. global $myUser,$_,$myFirm;
  646. require_once(__DIR__.SLASH.'Client.class.php');
  647. if (!$myUser->connected()) throw new Exception("Vous devez être connecté", 401);
  648. $response['rows'] = array();
  649. $data = array("%".$_['keyword']."%","%".$_['keyword']."%",Client::ACTIVE);
  650. //retourne en priorité les matchs à 100%, pour les match keyword%, puis les autres
  651. $query = 'SELECT c.*,(SELECT label FROM {{table}} p WHERE p.id=c.parent) parentLabel FROM {{table}} c WHERE (c.label LIKE ? OR pseudonym LIKE ?) AND c.state=? ';
  652. if(isset($_['data']['parent']) && !empty($_['data']['parent']) && is_numeric($_['data']['parent'])){
  653. $query .= ' AND c.parent=? ';
  654. $data[] = $_['data']['parent'];
  655. }
  656. $query .= ' AND c.firm=? ';
  657. if(isset($_['data']['firm']) && !empty($_['data']['firm']) && is_numeric($_['data']['firm'])){
  658. $data[] = $_['data']['firm'];
  659. }else{
  660. $data[] = $myFirm->id;
  661. }
  662. $query .= ' ORDER BY
  663. CASE
  664. WHEN c.label = ? THEN 1
  665. WHEN c.label LIKE ? THEN 2
  666. ELSE 3
  667. END
  668. LIMIT 10';
  669. $data[] = $_['keyword'];
  670. $data[] = '%'.$_['keyword'];
  671. $clients = Client::staticQuery($query,$data,true);
  672. foreach($clients as $client){
  673. $response['rows'][] = array(
  674. 'label'=>html_entity_decode($client->label, ENT_QUOTES).(!empty($client->pseudonym) ? ' ('.html_entity_decode($client->pseudonym, ENT_QUOTES).')' :''),
  675. 'parentLabel'=>html_entity_decode($client->foreign('parentLabel'), ENT_QUOTES),
  676. 'id'=>$client->id,
  677. 'logo' => $client->logo()
  678. );
  679. }
  680. if(isset($_['data']) && isset($_['data']['before']) && isset($_['data']['before'])!=''){
  681. $list = json_decode(html_entity_decode($_['data']['before']),true);
  682. if(is_array($list)){
  683. foreach ($list as $key=>$value) {
  684. if(preg_match('/'.$_['keyword'].'/i', $value))
  685. array_unshift($response['rows'],array('label'=>$value,'id'=>$key));
  686. }
  687. }
  688. }
  689. });
  690. Action::register('client_by_uid',function(&$response){
  691. global $myUser,$_;
  692. if (!$myUser->connected()) throw new Exception("Vous devez être connecté",401);
  693. require_once(__DIR__.SLASH.'Client.class.php');
  694. $response['items'] = array();
  695. $query = 'SELECT main.*,p.label as parentLabel FROM {{table}} main LEFT JOIN {{table}} p ON main.parent=p.id WHERE main.id IN(';
  696. $query .= implode(',', array_fill(0, count($_['items']), '?'));
  697. $query .= ')';
  698. foreach(Client::staticQuery($query,$_['items'],true) as $client) {
  699. $row = $client->toArray();
  700. unset($row['parent']);
  701. if(!empty($client->foreign('parentLabel'))) $row['parent'] = array('label'=>$client->foreign('parentLabel'));
  702. $row['label'] = html_entity_decode($row['label'], ENT_QUOTES);
  703. if(!empty($row['pseudonym'])) $row['label'].= ' ('.html_entity_decode($row['pseudonym'], ENT_QUOTES).')' ;
  704. $response['items'][$row['id']] = $row;
  705. }
  706. if(isset($_['before']) && $_['before']!=''){
  707. $list = json_decode(html_entity_decode($_['before']),true);
  708. if(is_array($list)){
  709. if(isset($list[$_['id']])) $response['items'][] = array('label' => $list[$_['id']], 'id'=>$_['id']);
  710. }
  711. }
  712. });
  713. //ADDRESSES
  714. //Récuperation d'une liste d'adresses
  715. Action::register('client_address_search',function(&$response){
  716. global $myUser,$_,$myFirm;
  717. require_once(__DIR__.SLASH.'Client.class.php');
  718. if(!$myUser->can('client','read') && $_['client']!=0 && !$myUser->can('client_sheet','read',$_['client'])) throw new Exception("Permission non accordée sur cette fiche");
  719. if(empty($_['client'])) return $response;
  720. $client = Client::getById($_['client']);
  721. //if($client->id!=0 && !in_array($client->firm,array(0,$myFirm->id))) throw new Exception("Ces addresses de fiche ne sont pas disponibles pour votre etablissement");
  722. $addresses = Address::loadAll(array('scope'=>'client','uid'=>$_['client']));
  723. foreach($addresses as $address){
  724. $row = $address->toArray();
  725. $row['type'] = Address::types($row['type']);
  726. $row['type']['slug'] = $address->type;
  727. $response['rows'][] = $row;
  728. }
  729. });
  730. //Récuperation ou edition d'élément addresse
  731. Action::register('client_address_edit',function(&$response){
  732. global $myUser,$_;
  733. User::check_access('client','edit');
  734. $address = Address::provide();
  735. if($address->id!=0 && $address->scope != 'client') throw new Exception("Entité non conforme");
  736. $response = $address->toArray();
  737. });
  738. //Ajout ou modification d'élément clientcontact
  739. Action::register('client_address_save',function(&$response){
  740. global $myUser,$_;
  741. require_once(__DIR__.SLASH.'Client.class.php');
  742. User::check_access('client','edit');
  743. if(empty($_['client'])) throw new Exception("Client non spécifié");
  744. if(empty($_['street']) && empty($_['zip']) && empty($_['city'])) throw new Exception("Vous devez spécifier au minimum une ville, un code postal ou une rue");
  745. $address = Address::provide();
  746. $address->fromArray($_);
  747. $address->scope = 'client' ;
  748. $address->uid = $_['client'] ;
  749. $address->save();
  750. //Enregistrement des coordonées gps dans les méta client si l'adresse est la principale
  751. if($address->type==Address::MAIN){
  752. $coordinates = $address->locationCoordinates();
  753. $client = Client::getById($address->uid);
  754. $client->meta('longitude', $coordinates['longitude']);
  755. $client->meta('latitude', $coordinates['latitude']);
  756. $client->save();
  757. }
  758. History::put('client',$_['client'],(empty($_['id']) ? 'Création ': ' Modification ' )." d'une adresse de type : ".Address::types($address->type)['label'].' : '.$address->fullName());
  759. });
  760. //Suppression d'élement clientcontact
  761. Action::register('client_address_delete',function(&$response){
  762. global $myUser,$_;
  763. User::check_access('client','delete');
  764. require_once(__DIR__.SLASH.'Client.class.php');
  765. $address = Address::getById($_['id']);
  766. if($address->scope!='client') throw new Exception("Entité spécifiée non conforme",403);
  767. Address::deleteById($address->id);
  768. History::put('client',$address->uid,"Suppression d'une adresse de type : ".Address::types($address->type)['label']);
  769. });
  770. /*WIDGET*/
  771. Action::register('client_widget_load',function(&$response){
  772. global $myUser,$_;
  773. if(!$myUser->can('client','read')) throw new Exception("Permission non accordée");
  774. Plugin::need('dashboard/DashboardWidget');
  775. $widget = DashboardWidget::current();
  776. $widget->title = 'Widget Client';
  777. ob_start();
  778. //Décommenter après avoir créé widget.php
  779. require_once(__DIR__.SLASH.'client.widget.php');
  780. $widget->content = ob_get_clean();
  781. echo json_encode($widget);
  782. exit;
  783. });
  784. /** HISTORY **/
  785. //Récuperation d'une liste de history
  786. Action::register('client_core_history_search',function(&$response){
  787. global $myUser,$_;
  788. if(!$myUser->can('client_history','read')) throw new Exception("Permission non accordée sur cette fiche");
  789. if(!$myUser->can('client','read') && $_['id']!=0 && !$myUser->can('client_sheet','read',$_['id'])) throw new Exception("Permission non accordée sur cette fiche");
  790. // OPTIONS DE RECHERCHE, A ACTIVER POUR UNE RECHERCHE AVANCEE
  791. $query = 'SELECT * FROM {{table}} WHERE 1';
  792. $data = array();
  793. //scopé sur le client
  794. $query .= ' AND scope = ? AND uid = ?';
  795. $data[] = 'client';
  796. $data[] = $_['id'];
  797. //Recherche simple
  798. if(!empty($_['filters']['keyword'])){
  799. $query .= ' AND comment LIKE ?';
  800. $data[] = '%'.$_['filters']['keyword'].'%';
  801. }
  802. //Recherche avancée
  803. if(isset($_['filters']['advanced'])) filter_secure_query($_['filters']['advanced'],array('comment','created','creator'),$query,$data);
  804. $query .= ' ORDER BY created DESC';
  805. //Pagination
  806. $response['pagination'] = History::paginate(20,(!empty($_['page'])?$_['page']:0),$query,$data);
  807. $historys = History::staticQuery($query,$data,true,0);
  808. foreach($historys as $history){
  809. $row = $history->toArray();
  810. $monthName = month_name(date('m',$history->created));
  811. $row['created'] = array(
  812. 'dayShortName' => day_name(date('N',$history->created)),
  813. 'day' => date('d',$history->created),
  814. 'monthName' => strlen($monthName)>4 ? substr(month_name(date('m',$history->created)), 0, 4).'.' : $monthName,
  815. 'time' => date('H:i',$history->created)
  816. );
  817. $row['comment'] = html_entity_decode($row['comment']);
  818. if($_['export'] == 'true'){
  819. $row['created'] = date('d-m-Y',$history->created);
  820. $row['updated'] = date('d-m-Y',$history->updated);
  821. }
  822. $creator = User::byLogin($row['creator']);
  823. $row['creator'] = $creator->toArray();
  824. $row['editable'] = $row['type'] == History::TYPE_COMMENT ;
  825. $row['creator']['fullName'] = $creator->fullName();
  826. $response['rows'][] = $row;
  827. }
  828. /* Mode export */
  829. if($_['export'] == 'true'){
  830. $fieldsMapping = array();
  831. foreach (History::fields(false) as $key => $value)
  832. $fieldsMapping[$value['label']] = $key ;
  833. $stream = Excel::exportArray($response['rows'],$fieldsMapping,'Export');
  834. File::downloadStream($stream,'historique-client-'.date('d-m-Y').'.xlsx');
  835. exit();
  836. }
  837. });
  838. Action::register('client_core_history_save',function(&$response){
  839. global $myUser,$_,$myFirm;
  840. User::check_access('client_history','edit');
  841. if(!isset($_['client'])) throw new Exception('Id client manquant');
  842. if(!isset($_['comment'])) throw new Exception('Message manquant');
  843. $history = History::provide();
  844. $history->scope = 'client';
  845. $history->uid = $_['client'];
  846. $history->comment = $_['comment'];
  847. $history->type = History::TYPE_COMMENT;
  848. $history->save();
  849. });
  850. Action::register('client_history_edit',function(&$response){
  851. global $myUser,$_,$myFirm;
  852. User::check_access('client_history','edit');
  853. require_once(__DIR__.SLASH.'Client.class.php');
  854. $history = History::getById($_['id']);
  855. if($history->scope!='client') throw new Exception('Vous ne pouvez editer ce type d\'historique');
  856. $response = $history->toArray();
  857. $response['comment'] = html_entity_decode($response['comment']);
  858. });
  859. Action::register('client_core_history_delete',function(&$response){
  860. global $myUser,$_,$myFirm;
  861. User::check_access('client_history','delete');
  862. require_once(__DIR__.SLASH.'Client.class.php');
  863. $history = History::getById($_['id']);
  864. if($history->scope!='client') throw new Exception('Vous ne pouvez supprimer ce type d\'historique');
  865. History::deleteById($history->id);
  866. });
  867. Action::register('client_import_component',function(&$response){
  868. global $myUser,$_;
  869. if(!$myUser->can('client','configure')) throw new Exception("Permission non accordée");
  870. File::handle_component(array(
  871. 'namespace' => 'client', //stockés dans file/client/*.*
  872. 'access' => 'client', // crud sur summary,
  873. 'size' => '1000000000', // taille max
  874. 'extension' => 'csv',
  875. 'storage' => 'client/import/*' //chemin complet vers le fichier stocké
  876. ),$response);
  877. });
  878. Action::register('client_import',function(&$response){
  879. global $myUser,$_,$myFirm;
  880. if(!$myUser->can('client','configure')) throw new Exception("Permission non accordée");
  881. if(count($_['attachments'])==0) throw new Exception("Merci d'envoyer un fichier au format csv avant d'appuyer sur le boutton import");
  882. if($_['attachments'][0]['extension']!='csv') throw new Exception("Extension invalide (accepté: csv)");
  883. if($_['attachments'][0]['size'] > 1000000000 ) throw new Exception("Taille trop importante (max accepté: 1Go)");
  884. require_once(__DIR__.SLASH.'Client.class.php');
  885. $clientManager = new Client();
  886. $keyLabelMap = array();
  887. foreach ($clientManager->fields as $key => $meta) {
  888. $keyLabelMap[$meta['label']] = $key;
  889. }
  890. $isDynamic = array();
  891. if($myFirm->has_plugin('fr.core.dynamicform')){
  892. Plugin::need('dynamicform/DynamicForm');
  893. foreach (DynamicForm::list('client-sheet-custom') as $key => $meta) {
  894. $keyLabelMap[$meta['label']] = $meta['slug'];
  895. $isDynamic[$meta['slug']] = $meta;
  896. }
  897. }
  898. $keyLabelMap['Contacts'] = 'contacts';
  899. $keyLabelMap['Adresses'] = 'addresses';
  900. $keyLabelMap['Client Parent'] = 'parent';
  901. $lines = explode("\r\n",utf8_encode(file_get_contents(File::temp().str_replace('/tmp/','',$_['attachments'][0]['path']))));
  902. if(count($lines)<2) throw new Exception("Le fichier d'import est vide");
  903. $headers = array_shift($lines);
  904. $headers = explode(';',$headers);
  905. $headersColumnMap = array();
  906. foreach($headers as $i => $header){
  907. if(!isset($keyLabelMap[$header])) continue;
  908. $headersColumnMap[$i] = $keyLabelMap[html_entity_decode($header)];
  909. }
  910. $response['warnings'] = array();
  911. $transformMapping = array();
  912. //convertion des types label -> bdd
  913. $typesLabel = array();
  914. foreach (Client::types() as $typeKey=>$type)
  915. $typesLabel[$type['label']] = $typeKey;
  916. $transformMapping['type'] = function($value,$client) use ($typesLabel){
  917. return isset($typesLabel[$value]) ? $typesLabel[$value] : '';
  918. };
  919. //convertion des conditions label -> bdd
  920. $conditionsLabel = array();
  921. foreach (Client::conditions() as $conditionKey=>$condition)
  922. $conditionsLabel[$condition['label']] = $conditionKey;
  923. $transformMapping['condition'] = function($value,$client) use ($conditionsLabel){
  924. return isset($conditionsLabel[$value])? $conditionsLabel[$value] : '';
  925. };
  926. //convertion des catégories label -> bdd
  927. $categoriesLabel = array();
  928. $categoriesDictionary = Dictionary::bySlug('client_category');
  929. foreach (Dictionary::slugToArray('client_category',true) as $categoryKey=>$category)
  930. $categoriesLabel[$category->label] = $categoryKey;
  931. //Convertion des adresses
  932. /*
  933. le format des adresse doit être le suivant dans le csv : add1\nadd2[:type], ex :
  934. "122 avenue de saint emilion 33600 Martignas sur jalles
  935. 344 rue frédéric sévène 33400 Talence:facturation"
  936. */
  937. $transformMapping['addresses'] = function($value,$client){
  938. //suppression des "" de chaque coté de la valeur si existants
  939. if(preg_match('/^"(.*)"$/si', $value,$match))
  940. $value = $match[1];
  941. foreach(explode("\n",$value) as $rawAddress){
  942. $address = new Address();
  943. $type = Address::MAIN;
  944. $rawAddress = explode(':',$rawAddress);
  945. if(isset($rawAddress[1])) $type = $rawAddress[1];
  946. $street = '';
  947. $zip = '';
  948. $city = '';
  949. $country = '';
  950. $complement = '';
  951. if(preg_match('/([0-9]*)? ?(.*) ([0-9]{5}) ([^,]*),?\s*(.*)?/i', $rawAddress[0],$match)){
  952. if(!empty($match[1]) || !empty($match[2])){
  953. $street = (!empty($match[1]) ? $match[1] : '').(!empty($match[2]) ? ' '.$match[2] : '');
  954. if(!empty($match[3])) $zip = $match[3];
  955. if(!empty($match[4])) $city = $match[4];
  956. if(!empty($match[5])) $country = $match[5];
  957. }
  958. }else{
  959. //Si on ne parviens pas a parser l'adresse
  960. //On essaye de récuperer le CP
  961. if(preg_match('/ ([0-9]{5}) /i', $rawAddress[0],$match)){
  962. $zip = $match[1];
  963. }
  964. //on stoque tout dans la rue
  965. $street = $rawAddress[0];
  966. }
  967. $address->scope = 'client';
  968. $address->label = '';
  969. $address->uid = $client->id;
  970. $address->type = $type;
  971. $address->street = $street;
  972. $address->complement = $complement;
  973. $address->city = $city;
  974. $address->zip = $zip;
  975. $address->country = $country;
  976. $address->state = Address::ACTIVE;
  977. //récuperation latitude et longitude
  978. //Enregistrement des coordonées gps dans les méta client si l'adresse est la principale
  979. if($address->type==Address::MAIN && isset($coordinates['longitude']) && isset($coordinates['latitude'])){
  980. $coordinates = $address->locationCoordinates();
  981. $client->meta('longitude', $coordinates['longitude']);
  982. $client->meta('latitude', $coordinates['latitude']);
  983. $client->save();
  984. }
  985. $address->save();
  986. }
  987. //on returne false pour indiquer de ne pas remplir l'objet client avec cette info
  988. return false;
  989. };
  990. //Convertion des contacts
  991. /*
  992. Exemple de format de contact dans la case du csv
  993. "jessica ALBA:jalba@alba.com:0681129753:0781129753:PDG:beauty,star
  994. angelina JOLIE:angie@jolie.com"
  995. */
  996. $transformMapping['contacts'] = function($value,$client){
  997. //suppression des "" de chaque coté de la valeur si existants
  998. if(preg_match('/^"(.*)"$/si', $value,$match))
  999. $value = $match[1];
  1000. foreach(explode("\n",$value) as $rawContact){
  1001. $contact = new ContactPerson();
  1002. $rawContact = explode(':',$rawContact);
  1003. if(isset($rawContact[1])) $type = $rawContact[1];
  1004. $nameFirstName = explode(' ',$rawContact[0]);
  1005. $contact->firstname = $nameFirstName[0];
  1006. if(isset($nameFirstName[1])) $contact->name = $nameFirstName[1];
  1007. if(!empty($rawContact[1])) $contact->mail = $rawContact[1];
  1008. if(!empty($rawContact[2])) $contact->phone = $rawContact[2];
  1009. if(!empty($rawContact[3])) $contact->mobile = $rawContact[3];
  1010. if(!empty($rawContact[4])) $contact->job = $rawContact[4];
  1011. if(!empty($rawContact[5])) $contact->tag = $rawContact[5];
  1012. $contact->scope = 'client';
  1013. $contact->uid = $client->id;
  1014. $contact->type = ContactPerson::TYPE_EXTERNAL;
  1015. $contact->state = ContactPerson::ACTIVE;
  1016. $contact->save();
  1017. }
  1018. //on returne false pour indiquer de ne pas remplir l'objet client avec cette info
  1019. return false;
  1020. };
  1021. //transformation du libellé parent en libellé enfant
  1022. $transformMapping['parent'] = function($value,$client){
  1023. if(empty($value)) return '';
  1024. $parent = Client::load(array('label'=>$value));
  1025. if(!$parent) return;
  1026. return $parent->id;
  1027. };
  1028. $transformMapping['category'] = function($value,$client) use ($categoriesLabel,$categoriesDictionary){
  1029. if(!isset($categoriesLabel[$value])){
  1030. $dictionary = new Dictionary();
  1031. $dictionary->label = $value;
  1032. $dictionary->state = Dictionary::ACTIVE;
  1033. $dictionary->slug = $categoriesDictionary->slug.'_'.slugify($value);
  1034. $dictionary->parent = $categoriesDictionary->id;
  1035. $dictionary->save();
  1036. $categoriesLabel[$value] = $dictionary->id;
  1037. }
  1038. return $categoriesLabel[$value];
  1039. };
  1040. foreach ($lines as $i=>$line) {
  1041. if(empty($line)) continue;
  1042. try{
  1043. $columns = explode(';',$line);
  1044. if(count($columns)==0) throw new Exception("Colonnes vides");
  1045. $newClient = new Client();
  1046. $newClient->save(); //on presave pour obtenir un id
  1047. foreach ($columns as $u=>$column) {
  1048. try{
  1049. if(!isset($headersColumnMap[$u])) throw new Exception("La colonne '".$headers[$u]."' ne correspond a rien dans l'erp");
  1050. $key = $headersColumnMap[$u];
  1051. if(isset($transformMapping[$key])){
  1052. $method = $transformMapping[$key];
  1053. $column = $method($column,$newClient);
  1054. //si false, ne pas remplir l'objet client avec cette info (info relationnelle)
  1055. if($column === false) continue;
  1056. }
  1057. if($myFirm->has_plugin('fr.core.dynamicform') && isset($isDynamic[$key]) ){
  1058. Plugin::need('dynamicform/DynamicValue');
  1059. $dynamicValue = new DynamicValue();
  1060. $dynamicValue->field = $isDynamic[$key]['id'];
  1061. if(property_exists($isDynamic[$key]['type'],"fromRawDisplay")){
  1062. $method = $isDynamic[$key]['type']->fromRawDisplay;
  1063. $options = array();
  1064. if($isDynamic[$key]['type']->slug =='dictionary'){
  1065. $parent = Dictionary::bySlug($isDynamic[$key]['meta']->slug);
  1066. $options['slug'] = $parent->id;
  1067. }
  1068. $column = $method($column,$options);
  1069. }
  1070. $dynamicValue->value= $column;
  1071. $dynamicValue->firm = $myFirm->id;
  1072. $dynamicValue->scope = 'client';
  1073. $dynamicValue->uid = $newClient->id;
  1074. $dynamicValue->save();
  1075. }else{
  1076. $newClient->$key = $column;
  1077. }
  1078. }catch(Exception $e){
  1079. $response['warnings'][] = 'L'.($i+1).' Col'.($u+1).':'.$e->getMessage();
  1080. }
  1081. if(empty($newClient->code)) $newClient->code = CLient::code($newClient);
  1082. if(empty($newClient->slug)) $newClient->slug = slugify($client->label);
  1083. $newClient->save();
  1084. }
  1085. }catch(Exception $e){
  1086. //si un pb sur la ligne on supprime le client qu'on a commencé a enregistrer en base
  1087. if($newClient->id!=0) Client::deleteById($newClient->id);
  1088. $response['warnings'][] = 'L'.($i+1).':'.$e->getMessage();
  1089. }
  1090. }
  1091. });
  1092. Action::register('client_import_model',function(&$response){
  1093. global $myUser,$_,$myFirm;
  1094. if(!$myUser->can('client','configure')) throw new Exception("Permission non accordée");
  1095. require_once(__DIR__.SLASH.'Client.class.php');
  1096. $client = new Client();
  1097. $stream = '';
  1098. foreach ($client->fields as $key => $meta) {
  1099. if( in_array($key, array('id','state','slug','meta'))) continue;
  1100. $stream .= $meta['label'].';';
  1101. }
  1102. $stream .= 'Contacts;';
  1103. $stream .= 'Adresses;';
  1104. $stream .= 'Client Parent;';
  1105. if($myFirm->has_plugin('fr.core.dynamicform')){
  1106. Plugin::need('dynamicform/DynamicForm');
  1107. foreach (DynamicForm::list('client-sheet-custom') as $key => $meta) {
  1108. $stream .= $meta['label'].';';
  1109. }
  1110. }
  1111. $stream .= PHP_EOL;
  1112. File::downloadStream(utf8_decode($stream),'Trame import client.csv', 'application/octet-stream');
  1113. exit();
  1114. });
  1115. ?>