class_sinapsRequest.inc 19.7 KB
Newer Older
1
2
3
<?php
/*
  This code is part of FusionDirectory (http://www.fusiondirectory.org/)
Côme Chilliet's avatar
Côme Chilliet committed
4
  Copyright (C) 2017-2019 FusionDirectory
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/

21
22
23
24
class sinapsRequestException extends Exception
{
}

25
26
27
28
29
30
31
class sinapsRequest
{
  protected $data;

  public function __construct($xml)
  {
    $this->data = new SimpleXMLElement($xml);
32
    if (!isset($this->data->domaine)) {
33
      throw new sinapsRequestException('XML content is missing "domaine" tag');
34
35
    }
    if (!isset($this->data->domaine['code'])) {
36
      throw new sinapsRequestException('"domaine" tag is missing "code" attribute');
37
38
    }
    if (!isset($this->data->domaine->donnees->operation)) {
39
      throw new sinapsRequestException('XML content is missing "domaine>donnees>operation" tag');
40
41
    }
    if (!isset($this->data->domaine->donnees->operation['codeOperation'])) {
42
      throw new sinapsRequestException('"operation" tag is missing "codeOperation" attribute');
43
44
    }
    if (!isset($this->data->domaine->identifiantTransaction)) {
45
      throw new sinapsRequestException('"identifiantTransaction" tag is missing from "domaine" tag');
46
    }
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
  }

  public function codeDomaine()
  {
    return $this->data->domaine['code'];
  }

  public function codeOperation()
  {
    return $this->data->domaine->donnees->operation['codeOperation'];
  }

  public function operationVersion()
  {
    return $this->data->domaine->donnees->operation['version'];
  }

  public function identifiantTransaction()
  {
    return $this->data->domaine->identifiantTransaction;
  }

  public function getOperationStructure()
  {
    return $this->data->domaine->donnees->operation->structure;
  }

74
75
76
77
78
  public function getOperationPersonne()
  {
    return $this->data->domaine->donnees->operation->personne;
  }

79
  public static function acquittementFonctionnel($responseCode = 200, $codeAcquittement = 0, $message = '', $identifiantObjApp = NULL, $synchrone = TRUE)
80
  {
81
82
83
84
85
86
87
88
    $xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?>
    <Acquittement xmlns:acq="http://referentiels.SINAPS.amue.fr/acquittementFonctionnel">
    </Acquittement>');
    $xml->addChild('ResponseCode', $responseCode);
    $xml->addChild('messageAcquittement', $message);
    $xml->addChild('codeAcquittement', $codeAcquittement);
    if ($identifiantObjApp) {
      $xml->addChild('identifiantObjApp', $identifiantObjApp);
89
90
    } else {
      $xml->addChild('identifiantObjApp');
91
92
    }

93
94
95
96
97
98
99
100
101
102
103
    if ($synchrone) {
      /* Hack because SINAPS API makes no sense and needs a prefix for Acquittement only for synchrone mode */
      return preg_replace(
        array('|<Acquittement |',   '|</Acquittement>$|'),
        array('<acq:Acquittement ', '</acq:Acquittement>'),
        $xml->asXML(),
        1
      );
    } else {
      return $xml->asXML();
    }
104
105
106
107
  }

  public function acquittementTechnique($responseCode = 200, $message = '')
  {
108
109
110
111
112
113
114
115
    $xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?>
    <WebServiceHTTPResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="acquittementTechnique.xsd">
    </WebServiceHTTPResponse>');
    $xml->addChild('IdentifiantTransaction', $this->identifiantTransaction());
    $xml->addChild('ResponseCode', $responseCode);
    $xml->addChild('ResponseMessage', $message);

    return $xml->asXML();
116
117
  }

118
  public function getSupannEntiteValues($identifiantApplication, $identifiantApplicationSync, $uuidPrefix, $ldapUuidToCodeEntiteCallback)
119
  {
120
121
    $structure  = $this->getOperationStructure();
    $now        = new DateTime();
122

123
    $mapping = array(
124
125
126
127
128
129
      'libelle20'         => array('entite','ou'),
      'descriptifLong'    => array('entite','description'),
      'codeStructure'     => array('entite','supannCodeEntite'),
      'codeSousType'      => array('entite','supannTypeEntite'),
      'dateDebutValidite' => array('supannStructureExt','fdSupannStartDate'),
      'dateFinValidite'   => array('supannStructureExt','fdSupannEndDate'),
130
131
    );
    $values = array(
132
      'entite' => array(
133
134
        'supannRefId'               => array(),
        'postalAddress'             => '',
135
        'supannCodeEntiteParent'    => array(),
136
      ),
137
138
    );

139
140
    $uuid = '';

141
    if (isset($structure->referenceCroisee->identifiantsExternes)) {
142
143
144
      foreach ($structure->referenceCroisee->identifiantsExternes as $ref) {
        if ($ref->identifiantApplication == $identifiantApplication) {
          $uuid = $ref->identifiantExterne;
145
        } elseif (in_array($ref->identifiantApplication, $identifiantApplicationSync)) {
146
147
          $values['entite']['supannRefId'][] = '{'.$ref->identifiantApplication.'}'.$ref->identifiantExterne;
        }
148
149
150
151
152
153
154
      }
    }

    if (empty($uuid)) {
      $uuid = static::genUUID();
    }

155
    array_unshift($values['entite']['supannRefId'], '{'.$uuidPrefix.'}'.$uuid);
156

157
    foreach ($mapping as $sinapsAttr => list($fdTab,$fdAttr)) {
158
      if (isset($structure->$sinapsAttr)) {
159
        $values[$fdTab][$fdAttr] = (string)$structure->$sinapsAttr;
160
161
      } else {
        $values[$fdTab][$fdAttr] = '';
162
163
164
      }
    }

165
    if (isset($structure->methodesDeContact->methodeDeContact)) {
166
      foreach ($structure->methodesDeContact->methodeDeContact as $method) {
167
168
        if (!$this->checkValidite($method, $now)) {
          continue;
169
        }
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
        switch ((string)$method->codeTypeMethodeContact) {
          case 'ADR':
            if ((string)$method->adresse->temoinAdressePrincipale != 'true') {
              trigger_error('Ignore adresse non principale');
              continue;
            }
            $adresse = $this->convertAddress($method->adresse);
            if ($adresse === FALSE) {
              trigger_error('Ignore adresse non FR non ETR');
              continue;
            }
            $values['entite']['postalAddress'] = $adresse;
            break;
          default:
            trigger_error('ignoring codeTypeMethodeContact '.$method->codeTypeMethodeContact);
        }
186
187
188
      }
    }

189
    if (isset($structure->liensStructure->lienStructure)) {
190
191
      foreach ($structure->liensStructure->lienStructure as $lienStructure) {
        if (((string)$lienStructure->codeTypeLien == 'HIE') && isset($lienStructure->codeStructureMere)) {
192
193
194
          if (!$this->checkValidite($lienStructure, $now)) {
            continue;
          }
195
196
          $mereUUID = $this->getUUIDFromReferenceCroisee($identifiantApplication, $lienStructure->referenceCroisee);
          if (!empty($mereUUID)) {
197
            $values['entite']['supannCodeEntiteParent'][] = $ldapUuidToCodeEntiteCallback($mereUUID)['supannCodeEntite'];
198
          }
199
        }
200
201
202
203
204
      }
    }

    return $values;
  }
205

206
  public function getUserValues($identifiantApplication, array $identifiantApplicationSync, $uuidPrefix, $ldapUuidToCodeEntiteCallback, array $userRoles)
207
  {
208
209
    $personne   = $this->getOperationPersonne();
    $now        = new DateTime();
210
211
212
213
214
215
216
217
    $mapping = array(
      'civilite'        => array('supannAccount','supannCivilite'),
      'nomUsage'        => array('user','sn'),
      'descriptifLong'  => array('user','description'),
      'dateNaissance'   => array('personalInfo','dateOfBirth'),
      'sexe'            => array('personalInfo','gender'),
    );
    $values = array(
218
      'lock'          => FALSE,
219
220
221
222
223
224
      'user'          => array(
        'homePhone'                 => '',
        'postalAddress'             => '',
        'homePostalAddress'         => '',
        'employeeNumber'            => '',
      ),
225
      'supannAccount' => array(
226
227
228
229
230
231
232
233
234
235
236
        'supannRefId'                       => array(),
        'supannEntiteAffectation'           => array(),
        'supannRoleGenerique'               => array(),
        'supannTypeEntiteAffectation'       => array(),
        'supannRoleEntite'                  => array(),
        'supannActivite'                    => array(),
        'supannEmpCorps'                    => '',
        'supannEntiteAffectationPrincipale' => '',
      ),
      'personalInfo'  => array(
        'fdPrivateMail' => array(),
237
      ),
238
239
    );

240
241
    $uuid = '';

242
    if (isset($personne->referenceCroisee->identifiantsExternes)) {
243
244
      foreach ($personne->referenceCroisee->identifiantsExternes as $ref) {
        if ($ref->identifiantApplication == $identifiantApplication) {
Côme Chilliet's avatar
Côme Chilliet committed
245
          $uuid = (string)$ref->identifiantExterne;
246
        } elseif (in_array($ref->identifiantApplication, $identifiantApplicationSync)) {
247
248
          $values['supannAccount']['supannRefId'][] = '{'.$ref->identifiantApplication.'}'.$ref->identifiantExterne;
        }
249
250
251
        if ($ref->identifiantApplication == 'SAP') {
          $values['user']['employeeNumber'] = $ref->identifiantExterne;
        }
252
253
254
255
256
257
258
      }
    }

    if (empty($uuid)) {
      $uuid = static::genUUID();
    }

259
    array_unshift($values['supannAccount']['supannRefId'], '{'.$uuidPrefix.'}'.$uuid);
260

261
262
263
    /* Check if the user still has at least one role which means he exists, otherwise this is a deletion */
    $userRoleExists = array();
    foreach ($userRoles as $typeRole) {
Côme Chilliet's avatar
Côme Chilliet committed
264
      if (preg_match('|^([^/]+)/(.+)$|', $typeRole, $m)) {
265
266
267
268
269
270
271
272
273
274
        $userRoleExists[$m[1]][] = $m[2];
      } else {
        $userRoleExists[$typeRole] = TRUE;
      }
    }
    $deletion = TRUE;
    if (isset($personne->rattachements->rattachement)) {
      foreach ($personne->rattachements->rattachement as $rattachement) {
        if (isset($rattachement->roles->role)) {
          foreach ($rattachement->roles->role as $role) {
Côme Chilliet's avatar
Côme Chilliet committed
275
276
            if (isset($userRoleExists[(string)$role->typeRole])) {
              if ($userRoleExists[(string)$role->typeRole] === TRUE) {
277
278
279
                $deletion = FALSE;
                break 2;
              }
Côme Chilliet's avatar
Côme Chilliet committed
280
              if (in_array_ics((string)$role->externe->typeExterne, $userRoleExists[(string)$role->typeRole])) {
281
282
283
284
285
286
287
288
289
                $deletion = FALSE;
                break 2;
              }
            }
          }
        }
      }
    }
    if ($deletion) {
290
291
292
293
294
295
296
297
298
299
300
301
302
      /* This is a deletion */
      /* Store current date as end of contract */
      $values['personalInfo']['fdContractEndDate'] = $now->format('d.m.Y');
      /* Lock the account */
      $values['lock'] = TRUE;
      /* Remove all contact info */
      $values['user']['telephoneNumber']          = '';
      $values['user']['facsimileTelephoneNumber'] = '';
      $values['user']['mobile']                   = '';
      $values['mailAccount']                      = FALSE;
      return $values;
    }

303
304
305
    foreach ($mapping as $sinapsAttr => list($fdTab,$fdAttr)) {
      if (isset($personne->$sinapsAttr)) {
        $values[$fdTab][$fdAttr] = (string)$personne->$sinapsAttr;
306
307
      } else {
        $values[$fdTab][$fdAttr] = '';
308
309
310
311
312
313
314
      }
    }

    if (isset($personne->prenoms)) {
      $values['user']['givenName'] = preg_replace('/;.*$/', '', $personne->prenoms);
    }

315
    if (isset($personne->methodesDeContact->methodeContact)) {
316
317
318
319
320
      foreach ($personne->methodesDeContact->methodeContact as $method) {
        if (!$this->checkValidite($method, $now)) {
          continue;
        }
        switch ((string)$method->typeMethodeContact) {
321
322
          case 'TELPERSO':
            $values['user']['homePhone'] = (string)$method->valeur;
323
324
            break;
          case 'MAILPERSO':
325
            $values['personalInfo']['fdPrivateMail'][] = (string)$method->valeur;
326
327
328
329
330
331
332
333
334
335
336
            break;
          case 'ADR':
            if ((string)$method->adresse->temoinAdressePrincipale != 'true') {
              trigger_error('Ignore adresse non principale');
              continue;
            }
            $adresse = $this->convertAddress($method->adresse);
            if ($adresse === FALSE) {
              trigger_error('Ignore adresse non FR non ETR');
              continue;
            }
Côme Chilliet's avatar
Côme Chilliet committed
337
            if ((string)$method->adresse->codeTypeAdresse == 'ADRPERSO') {
338
339
340
341
342
343
344
345
              $values['user']['homePostalAddress'] = $adresse;
            } else {
              $values['user']['postalAddress'] = $adresse;
            }
            break;
          default:
            trigger_error('ignoring codeTypeMethodeContact '.$method->typeMethodeContact);
        }
346
347
348
      }
    }

349
    if (isset($personne->rattachements->rattachement)) {
350
351
352
353
      foreach ($personne->rattachements->rattachement as $rattachement) {
        if (!$this->checkValidite($rattachement, $now)) {
          continue;
        }
354

355
        if (isset($rattachement->roles->role)) {
356
357
358
359
360
361
362
          foreach ($rattachement->roles->role as $role) {
            if (!$this->checkValidite($role, $now)) {
              continue;
            }
            if ($role->typeRole != 'PR') {
              continue;
            }
363
            if (isset($role->personneRessource->affectations->affectation)) {
Côme Chilliet's avatar
Côme Chilliet committed
364
              $quotiteMax = NULL;
365
              foreach ($role->personneRessource->affectations->affectation as $affectation) {
366
367
368
                if (!$this->checkValidite($affectation, $now)) {
                  continue;
                }
Côme Chilliet's avatar
Côme Chilliet committed
369
370
                $UUID     = (string)$affectation->identifiantStructureInterne;
                $quotite  = (isset($affectation->quotite) ? (int)$affectation->quotite : 0);
371
372
                if (!empty($UUID)) {
                  $entite = $ldapUuidToCodeEntiteCallback($UUID);
373
374
375
                  if (isset($entite['supannTypeEntite'])) {
                    $values['supannAccount']['supannTypeEntiteAffectation'][] = $entite['supannTypeEntite'];
                  }
376
                  $values['supannAccount']['supannEntiteAffectation'][]         = $entite['supannCodeEntite'];
Côme Chilliet's avatar
Côme Chilliet committed
377
378
379
380
                  if (($quotiteMax === NULL) || ($quotite > $quotiteMax)) {
                    $quotiteMax                                                   = $quotite;
                    $values['supannAccount']['supannEntiteAffectationPrincipale'] = $entite['supannCodeEntite'];
                  }
381
382
383
                }
              }
            }
384
            if (isset($role->personneRessource->elementsDeCarriere->elementCarriere)) {
385
386
387
388
389
              foreach ($role->personneRessource->elementsDeCarriere->elementCarriere as $elementCarriere) {
                if (!$this->checkValidite($elementCarriere, $now)) {
                  continue;
                }
                /* Warning: supannEmpCorps and employeeType are mono-value so we replace them */
390
                if (isset($elementCarriere->corps)) {
391
392
                  $values['supannAccount']['supannEmpCorps'] = (string)$elementCarriere->corps;
                }
393
                if (isset($elementCarriere->bapReferens)) {
394
395
396
397
                  $values['supannAccount']['supannActivite'][] = (string)$elementCarriere->bapReferens;
                }
              }
            }
398
399
          }
        }
400
        if (isset($rattachement->fonctionsOccupees->fonctionOccupee)) {
401
402
403
404
405
          foreach ($rattachement->fonctionsOccupees->fonctionOccupee as $fonctionOccupee) {
            if (!$this->checkValidite($fonctionOccupee, $now)) {
              continue;
            }
            $values['supannAccount']['supannRoleGenerique'][] = (string)$fonctionOccupee->fonctionRh;
Côme Chilliet's avatar
Côme Chilliet committed
406
            $UUID                                             = (string)$fonctionOccupee->identifiantStructureInterne;
407
            if (!empty($UUID)) {
408
              $entite = $ldapUuidToCodeEntiteCallback($UUID, TRUE);
409
410
              $values['supannAccount']['supannTypeEntiteAffectation'][] = $entite['supannTypeEntite'];
              $values['supannAccount']['supannEntiteAffectation'][] = $entite['supannCodeEntite'];
411
412
413
414
              $values['supannAccount']['supannRoleEntite'][] =
                '[role='.$fonctionOccupee->fonctionRh.']'.
                '[type='.$entite['supannTypeEntite'].']'.
                '[code='.$entite['supannCodeEntite'].']';
415
416
417
418
419
            }
          }
        }
      }
    }
420

421
422
423
    foreach (array('supannRefId','supannEntiteAffectation','supannRoleGenerique','supannTypeEntiteAffectation','supannRoleEntite','supannActivite') as $arrayattribute) {
      $values['supannAccount'][$arrayattribute] = array_values(array_unique($values['supannAccount'][$arrayattribute]));
    }
424
425
426
427

    return $values;
  }

428
  protected function convertAddress(SimpleXMLElement $address)
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
  {
    $adresse = '';
    if (!empty($address->adresseFR)) {
      if (!empty($address->adresseFR->batiment)) {
        $adresse .= $address->adresseFR->batiment;
        if (!empty($address->adresseFR->etage)) {
          $adresse .= ', '.$address->adresseFR->etage;
        }
        $adresse .= "\n";
      }
      $adresse .= $address->adresseFR->numeroVoie;
      if (!empty($address->adresseFR->codeBTQC)) {
        $adresse .= ' '.$address->adresseFR->codeBTQC;
      }
      $adresse .= ' '.$address->adresseFR->typeVoie;
      $adresse .= ' '.$address->adresseFR->nomVoie;
      $adresse .= "\n";
      if (!empty($address->adresseFR->complement)) {
        $adresse .= $address->adresseFR->complement."\n";
      }
      if (!empty($address->adresseFR->lieuDit)) {
        $adresse .= $address->adresseFR->lieuDit."\n";
      }
      $adresse .= $address->adresseFR->codePostal;
      $adresse .= ' '.$address->adresseFR->BD;
      $adresse .= "\n";
      $adresse .= "FRANCE\n";
456
457
458
459
460
    } elseif (!empty($address->adresseEtr)) {
      if (!empty($address->adresseEtr->batiment)) {
        $adresse .= $address->adresseEtr->batiment;
        if (!empty($address->adresseEtr->etage)) {
          $adresse .= ', '.$address->adresseEtr->etage;
461
462
463
        }
        $adresse .= "\n";
      }
464
465
      $adresse .= $address->adresseEtr->numeroVoie;
      $adresse .= ' '.$address->adresseEtr->nomVoie;
466
      $adresse .= "\n";
467
468
      if (!empty($address->adresseEtr->complement)) {
        $adresse .= $address->adresseEtr->complement."\n";
469
      }
470
471
      $adresse .= $address->adresseEtr->codePostal;
      $adresse .= ' '.$address->adresseEtr->ville;
472
      $adresse .= "\n";
473
474
      $adresse .= $address->adresseEtr->etat."\n";
      $adresse .= $address->adresseEtr->pays."\n";
475
476
477
478
479
480
481
    } else {
      $adresse = FALSE;
    }

    return $adresse;
  }

482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
  protected function checkValidite(SimpleXMLElement $object, DateTime $now)
  {
    if ($object->dateDebutValidite) {
      $dateDebutValidite = new DateTime($object->dateDebutValidite);
      if ($dateDebutValidite >= $now) {
        // Object is not valid yet, skip it
        return FALSE;
      }
    }
    if ($object->dateFinValidite) {
      $dateFinValidite = new DateTime($object->dateFinValidite);
      if ($dateFinValidite < $now) {
        // Object is not valid anymore, skip it
        return FALSE;
      }
    }
    return TRUE;
  }

501
  protected function getUUIDFromReferenceCroisee($identifiantApplication, $referenceCroisee)
502
503
  {
    foreach ($referenceCroisee->identifiantsExternes as $ref) {
504
      if ($ref->identifiantApplication == $identifiantApplication) {
505
506
507
508
509
510
511
        return $ref->identifiantExterne;
      }
    }

    return '';
  }

512
  public static function genUUID()
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
  {
    //UUID v4
    return sprintf(
      '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
      // 32 bits for "time_low"
      mt_rand(0, 0xffff), mt_rand(0, 0xffff),
      // 16 bits for "time_mid"
      mt_rand(0, 0xffff),
      // 16 bits for "time_hi_and_version",
      // four most significant bits holds version number 4
      mt_rand(0, 0x0fff) | 0x4000,
      // 16 bits, 8 bits for "clk_seq_hi_res",
      // 8 bits for "clk_seq_low",
      // two most significant bits holds zero and one for variant DCE1.1
      mt_rand(0, 0x3fff) | 0x8000,
      // 48 bits for "node"
      mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
    );
  }
532
}