Failed Conditions
Push — master ( 15235a...0b7e32 )
by Sylvain
07:51
created

Importer::insertBookables()   B

Complexity

Conditions 6
Paths 24

Size

Total Lines 99
Code Lines 76

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
cc 6
eloc 76
nc 24
nop 0
dl 0
loc 99
ccs 0
cts 81
cp 0
crap 42
rs 7.9014
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Application\Service;
6
7
use Application\Api\Exception;
8
use Doctrine\DBAL\Driver\PDOConnection;
9
use Doctrine\ORM\EntityManager;
10
use Interop\Container\ContainerInterface;
11
12
class Importer
13
{
14
    /**
15
     * @var ContainerInterface
16
     */
17
    private $container;
18
19
    /**
20
     * @var EntityManager
21
     */
22
    private $entityManager;
23
24
    /**
25
     * @var PDOConnection
26
     */
27
    private $filemaker;
28
29
    /**
30
     * @var PDOConnection
31
     */
32
    private $typo3;
33
34
    /**
35
     * @var array
36
     */
37
    private $members = [];
38
39
    /**
40
     * @var array
41
     */
42
    private $users = [];
43
44
    /**
45
     * Storage requests
46
     *
47
     * @var array
48
     */
49
    private $storage = [];
50
51
    /**
52
     * Allocated storage
53
     * [idBookable] => number of bookings
54
     *
55
     * @var array
56
     */
57
    private $storageAllocated = [];
58
59
    /**
60
     * Import constructor
61
     */
62
    public function __construct(ContainerInterface $container, EntityManager $entityManager)
63
    {
64
        $this->container = $container;
65
        $this->entityManager = $entityManager;
66
    }
67
68
    /**
69
     * Import the members from FileMaker and TYPO3
70
     */
71
    public function import(): void
72
    {
73
        $this->loadMembers();
74
        $this->loadPeople();
75
        $this->deleteTestData();
76
        $this->loadStorageRequests();
77
        $this->insertBookables();
78
        $this->insertUsers();
79
        $this->insertBookings();
80
    }
81
82
    /**
83
     * @return PDOConnection
84
     */
85
    private function connectFileMaker(): PDOConnection
86
    {
87
        if ($this->filemaker) {
88
            return $this->filemaker;
89
        }
90
        $config = $this->container->get('config');
91
92
        $dsn = sprintf('odbc:Driver={%s};Server=%s;Database=%s;charset=UTF-8', $config['filemaker']['driver'], $config['filemaker']['host'], $config['filemaker']['dbname']);
93
        $this->filemaker = new PDOConnection($dsn, $config['filemaker']['user'], $config['filemaker']['password']);
94
95
        return $this->filemaker;
96
    }
97
98
    /**
99
     * @return PDOConnection
100
     */
101
    private function connectTypo3(): PDOConnection
102
    {
103
        if ($this->typo3) {
104
            return $this->typo3;
105
        }
106
        $config = $this->container->get('config');
107
108
        $this->typo3 = new PDOConnection(sprintf('mysql:host=%s;port=%u;dbname=%s', $config['typo3']['host'], $config['typo3']['port'], $config['typo3']['dbname']), $config['typo3']['user'], $config['typo3']['password']);
109
110
        $this->typo3->exec('SET wait_timeout=1200');
111
112
        return $this->typo3;
113
    }
114
115
    /**
116
     * Load members from FileMaker "ichtus" table into memory
117
     */
118
    private function loadMembers(): void
119
    {
120
        $this->connectFileMaker();
121
        $query = <<<EOT
122
          SELECT ID_membre,
123
               "nom_prénom",
124
               "date_entrée ichtus",
125
               remarques,
126
               "liens de famille",
127
               "date_séance d'accueil",
128
               "date_formulaire_adhésion",
129
               membre_new,
130
               membre_actif,
131
               membre_suspension,
132
               "membre_archivé",
133
               assurances,
134
               envoi_papier
135
          FROM ichtus
136
          WHERE ((membre_new>0 AND "date_formulaire_adhésion">=DATE '2018-10-01') OR membre_actif>0 OR membre_suspension>0) AND "membre_archivé"=0 AND remarques NOT LIKE '%Ignorer%'
137
EOT;
138
        $statement = $this->filemaker->prepare(trim($query));
139
        if ($statement->execute()) {
140
            echo sprintf('%u membres à importer...', $statement->rowCount()) . PHP_EOL;
141
            foreach ($statement->fetchAll(\PDO::FETCH_ASSOC) as $member) {
142
                foreach ($member as $fieldName => $fieldValue) {
143
                    $member[$fieldName] = $this->fromMacRoman($fieldValue);
144
                }
145
                $this->members[$member['ID_membre']] = $member;
146
                echo sprintf('Membre %u importé', $member['ID_membre']) . PHP_EOL;
147
            }
148
        }
149
    }
150
151
    /**
152
     * Load people from TYPO3 fe_users into memory
153
     */
154
    private function loadPeople(): void
155
    {
156
        $this->connectTypo3();
157
        $query = <<<EOT
158
          SELECT *
159
          FROM fe_users
160
          WHERE FIND_IN_SET(CAST(family_uid as char), :members) AND status_archived=0;
161
EOT;
162
        $statement = $this->typo3->prepare($query);
163
        $statement->bindValue(':members', implode(',', array_keys($this->members)));
164
165
        if ($statement->execute()) {
166
            echo sprintf('%u individus à importer...', $statement->rowCount()) . PHP_EOL;
167
            $withoutLoginCount = 0;
168
            foreach ($statement->fetchAll(\PDO::FETCH_ASSOC) as $user) {
169
                if (($user['family_status'] === 'chef de famille' || $user['family_status'] === 'chef(fe) de famille') && $user['uid'] !== $user['family_uid']) {
170
                    echo sprintf('WARN: utilisateur %u ne devrait pas être de chef de la famille %u', $user['uid'], $user['family_uid']) . PHP_EOL;
171
                }
172
                if (empty($user['new_username'])) {
173
                    echo sprintf("WARN: utilisateur %u (%s %s) n'a pas de login MyIchtus", $user['uid'], $user['first_name'], $user['last_name']) . PHP_EOL;
174
                    ++$withoutLoginCount;
175
                }
176
                $this->users[$user['uid']] = $user;
177
                echo sprintf('Individu %u importé', $user['uid']) . PHP_EOL;
178
            }
179
            if ($withoutLoginCount > 0) {
180
                echo sprintf('%u individus sans login MyIchtus', $withoutLoginCount) . PHP_EOL;
181
            }
182
        }
183
    }
184
185
    /**
186
     * Create users
187
     */
188
    private function insertUsers(): void
189
    {
190
        $conn = $this->entityManager->getConnection();
191
192
        $typo3 = $this->connectTypo3();
193
194
        $insert = <<<EOT
195
                INSERT INTO user(
196
                  id,
197
                  login,
198
                  password,
199
                  first_name,
200
                  last_name,
201
                  birthday,
202
                  sex,
203
                  email,
204
                  street,
205
                  postcode,
206
                  locality,
207
                  country_id,
208
                  mobile_phone,
209
                  phone,
210
                  internal_remarks,
211
                  iban,
212
                  has_insurance,
213
                  swiss_sailing,
214
                  swiss_sailing_type,
215
                  swiss_windsurf_type,
216
                  receives_newsletter,
217
                  role,
218
                  family_relationship,
219
                  billing_type,
220
                  welcome_session_date,
221
                  status,
222
                  creation_date,
223
                  door4
224
                ) VALUES (
225
                  :id,
226
                  :login,
227
                  :password,
228
                  :first_name,
229
                  :last_name,
230
                  :birthday,
231
                  :sex,
232
                  :email,
233
                  :street,
234
                  :postcode,
235
                  :locality,
236
                  :country_id,
237
                  :mobile_phone,
238
                  :phone,
239
                  :remarks,
240
                  :iban,
241
                  :has_insurance,
242
                  :swiss_sailing,
243
                  :swiss_sailing_type,
244
                  :swiss_windsurf_type,
245
                  :receives_newsletter,
246
                  :role,
247
                  :family_relationship,
248
                  :billing_type,
249
                  :welcome_session_date,
250
                  :status,
251
                  :creation_date,
252
                  :door4
253
                )
254
EOT;
255
        $insert = $conn->prepare($insert);
256
257
        $createAccount = <<<EOT
258
                INSERT INTO account(
259
                  owner_id,
260
                  creation_date,
261
                  balance,
262
                  name,
263
                  parent_id,
264
                  type,
265
                  code
266
                ) VALUES (
267
                  :owner,
268
                  NOW(),
269
                  :balance,
270
                  :name,
271
                  10011, -- Passifs -> 2030 Acomptes de clients
272
                  'liability',
273
                  :code
274
                )
275
EOT;
276
        $createAccount = $conn->prepare($createAccount);
277
278
        $linkToTag = $conn->prepare('INSERT INTO user_tag_user(user_tag_id, user_id) VALUES (:user_tag_id, :user_id)');
279
280
        $linkToLicense = $conn->prepare('INSERT INTO license_user(license_id, user_id) VALUES (:license_id, :user_id)');
281
282
        $exportPassword = $typo3->prepare('UPDATE fe_users SET new_password=:password WHERE uid=:user_id');
283
284
        foreach ($this->users as $user) {
285
            echo sprintf('Insert user %u (%s %s)', $user['uid'], $user['first_name'], $user['last_name']) . PHP_EOL;
286
            $insert->bindValue(':id', $user['uid']);
287
            $insert->bindValue(':login', $user['new_username']);
288
            $insert->bindValue(':first_name', $user['first_name']);
289
            $insert->bindValue(':last_name', $user['last_name']);
290
            $insert->bindValue(':birthday', $user['date_birth'] !== null && $user['date_birth'] !== '0000-00-00' ? $user['date_birth'] : null);
291
            $insert->bindValue(':sex', $user['sexe'] === 'F' ? 2 : 1);
292
            $insert->bindValue(':email', !empty($user['email']) ? $user['email'] : null);
293
            $insert->bindValue(':street', $user['address']);
294
            $insert->bindValue(':postcode', $user['zip']);
295
            $insert->bindValue(':locality', $user['city']);
296
297
            switch ($user['country']) {
298
                case 'CH':
299
                    $country_id = 1;
300
301
                    break;
302
                case 'FR':
303
                case 'France':
304
                    $country_id = 2;
305
306
                    break;
307
                case 'DE':
308
                    $country_id = 10;
309
310
                    break;
311
                case 'CA':
312
                    $country_id = 6;
313
314
                    break;
315
                case 'NL':
316
                    $country_id = 19;
317
318
                    break;
319
                default:
320
                    $country_id = null;
321
                    echo sprintf("WARN: pas de correspondance pour le code pays %s de l\\'individu %u (%s %s)", $user['country'], $user['uid'], $user['first_name'], $user['last_name']) . PHP_EOL;
322
            }
323
            $insert->bindValue(':country_id', $country_id);
324
325
            $insert->bindValue(':mobile_phone', !empty($user['natel']) ? $user['natel'] : '');
326
            $insert->bindValue(':phone', $user['telephone']);
327
328
            if ($user['uid'] === $user['family_uid']) {
329
                // Si responsable de l'adhésion, fusionne les notes au niveau du membre et de l'individu
330
                $remarks = implode(PHP_EOL, [$this->members[$user['family_uid']]['remarques'], $user['notes']]);
331
            } else {
332
                $remarks = !empty($user['notes']) ? $user['notes'] : '';
333
            }
334
335
            $insert->bindValue(':remarks', $remarks);
336
            $insert->bindValue(':iban', !empty($user['IBAN']) ? $user['IBAN'] : '');
337
338
            $insurances = $this->members[$user['family_uid']]['assurances'];
339
            $insert->bindValue(':has_insurance', !empty($insurances) && mb_strpos($insurances, 'RC privée') !== false);
340
341
            $insert->bindValue(':swiss_sailing', !empty($user['ichtus_swiss_sailing']) ? $user['ichtus_swiss_sailing'] : '');
342
            switch ($user['ichtus_swiss_sailing_type']) {
343
                case 'A':
344
                    $swissSailingType = 'active';
345
346
                    break;
347
                case 'P':
348
                    $swissSailingType = 'passive';
349
350
                    break;
351
                case 'J':
352
                    $swissSailingType = 'junior';
353
354
                    break;
355
                default:
356
                    $swissSailingType = null;
357
            }
358
            $insert->bindValue(':swiss_sailing_type', $swissSailingType);
359
360
            switch ($user['ichtus_swiss_windsurf_type']) {
361
                case 'A':
362
                    $swissWindsurfType = 'active';
363
364
                    break;
365
                case 'P':
366
                    $swissWindsurfType = 'passive';
367
368
                    break;
369
                default:
370
                    $swissWindsurfType = null;
371
            }
372
            $insert->bindValue(':swiss_windsurf_type', $swissWindsurfType);
373
374
            $insert->bindValue(':receives_newsletter', !empty($user['email']) ? 1 : 0);
375
376
            switch ($user['family_status']) {
377
                case 'chef de famille':
378
                    $relationship = 'householder';
379
                    $role = 'member';
380
381
                    break;
382
                case 'chef(fe) de famille':
383
                    $relationship = 'householder';
384
                    $role = 'member';
385
386
                    break;
387
                case 'conjoint':
388
                    $relationship = 'partner';
389
                    $role = 'individual';
390
391
                    break;
392
                case 'enfant':
393
                    $relationship = 'child';
394
                    $role = 'individual';
395
396
                    break;
397
                case 'parent':
398
                    $relationship = 'parent';
399
                    $role = 'individual';
400
401
                    break;
402
                case 'soeur':
403
                    $relationship = 'sister';
404
                    $role = 'individual';
405
406
                    break;
407
                case 'frère':
408
                    $relationship = 'brother';
409
                    $role = 'individual';
410
411
                    break;
412
                case 'beau-frère':
413
                    $relationship = 'brother';
414
                    $role = 'individual';
415
416
                    break;
417
                default:
418
                    $relationship = 'householder';
419
                    $role = 'individual';
420
                    echo sprintf("WARN: individu %u (%s %s) n'a pas de statut familial", $user['uid'], $user['first_name'], $user['last_name']) . PHP_EOL;
421
            }
422
            if (in_array((int) $user['uid'], [1057, 2738], true)) {
423
                $role = 'administrator';
424
            } elseif (!empty($user['ichtus_comite_fonction'])) {
425
                $role = 'responsible';
426
            }
427
            $insert->bindValue(':role', $role);
428
            $insert->bindValue(':door4', (int) in_array($role, ['responsible', 'administrator'], true));
429
            $insert->bindValue(':family_relationship', $relationship);
430
431
            if ($this->members[$user['family_uid']]['envoi_papier'] && empty($user['email'])) {
432
                $insert->bindValue(':billing_type', 'paper');
433
            } else {
434
                $insert->bindValue(':billing_type', 'electronic');
435
            }
436
            $insert->bindValue(':welcome_session_date', $this->members[$user['family_uid']]["date_séance d'accueil"]);
437
438
            $userStatus = 'new';
439
            if ($user['status_new'] + $user['status_actif'] + $user['status_archived'] > 1) {
440
                echo sprintf('WARN individu %u (%s %s) a plus d\' un statut actif à la fois', $user['uid'], $user['first_name'], $user['last_name']) . PHP_EOL;
441
            }
442
443
            if ($this->members[$user['family_uid']]['membre_suspension'] + $this->members[$user['family_uid']]['membre_actif'] + $this->members[$user['family_uid']]['membre_archivé'] > 1) {
444
                echo sprintf('WARN membre/famille %u a plus d\' un statut actif à la fois', $user['family_uid']) . PHP_EOL;
445
            }
446
447
            if ($this->members[$user['family_uid']]['membre_suspension']) {
448
                $userStatus = 'inactive';
449
            } elseif ($this->members[$user['family_uid']]['membre_actif']) {
450
                if ($user['status_actif']) {
451
                    $userStatus = 'active';
452
                } else {
453
                    echo sprintf('WARN individu %u (%s %s) de la famille %u ignoré car désactivé', $user['uid'], $user['first_name'], $user['last_name'], $user['family_uid']) . PHP_EOL;
454
455
                    continue;
456
                }
457
            } elseif ($this->members[$user['family_uid']]['membre_archivé']) {
458
                $userStatus = 'archived';
459
            }
460
            $insert->bindValue(':status', $userStatus);
461
462
            if ($userStatus === 'new') {
463
                $insert->bindValue(':creation_date', $this->members[$user['family_uid']]['date_formulaire_adhésion']);
464
            } else {
465
                $insert->bindValue(':creation_date', $this->members[$user['family_uid']]['date_entrée ichtus']);
466
            }
467
468
            $password = $user['new_password'];
469
            if (empty($password)) {
470
                // Generate a new random password and store it in TYPO3 fe_users to send a newsletter to users
471
                $password = $this->generatePassword();
472
                echo sprintf('Generating new pass %s for user %s', $password, $user['uid']) . PHP_EOL;
473
                $exportPassword->bindValue(':password', $password);
474
                $exportPassword->bindValue(':user_id', $user['uid']);
475
                $exportPassword->execute();
476
            } else {
477
                echo sprintf('Using existing pass %s for user %s', $password, $user['uid']) . PHP_EOL;
478
            }
479
            $insert->bindValue(':password', password_hash($password, PASSWORD_DEFAULT));
480
481
            if ($insert->execute() === false) {
482
                echo sprintf('ERROR: création de l\'individu %u (%s %s)', $user['uid'], $user['first_name'], $user['last_name']) . PHP_EOL;
483
484
                continue;
485
            }
486
487
            // Crée un compte débiteur pour le membre
488
            $createAccount->bindValue(':owner', $user['uid']);
489
            $createAccount->bindValue(':name', implode(' ', [$user['first_name'], $user['last_name']]));
490
            $accountNumber = sprintf('2030%04u', $user['uid']); // 2030 (Acomptes de client) & ID User = numéro de compte unique
491
            $createAccount->bindValue(':code', $accountNumber);
492
            $createAccount->bindValue(':balance', 0.00); // Importer le solde des comptes 2018 ?
493
            if ($createAccount->execute() === false) {
494
                echo sprintf('ERROR: échec de création de compte débiteur n°%u pour l\'utilisateur %u (%s %s)', $accountNumber, $user['uid'], $user['first_name'], $user['last_name']) . PHP_EOL;
495
            }
496
497
            // Assigne les tags au membre
498
            $linkToTag->bindValue(':user_id', $user['uid']);
499
            if (!empty($user['ichtus_comite_fonction'])) {
500
                $userTagId = $this->insertUserTag($user['ichtus_comite_fonction']);
501
                $linkToTag->bindValue(':user_tag_id', $userTagId);
502
                $linkToTag->execute();
503
            }
504
            if (!empty($this->users[$user['uid']]['ichtus_NFT'])) {
505
                $userTagId = $this->insertUserTag('Membre NFT');
506
                $linkToTag->bindValue(':user_tag_id', $userTagId);
507
                $linkToTag->execute();
508
            }
509
510
            // Assigne les brevets au membre
511
            $linkToLicense->bindValue(':user_id', $user['uid']);
512
            $licenses = [];
513
            switch ($user['ichtus_autvoile']) {
514
                case 3: $licenses[] = 2002; // Voile niveau 3 (+ inférieurs)
515
                // no break
516
                case 2: $licenses[] = 2001; // Voile niveau 2 (+ inférieurs)
517
                // no break
518
                case 1: $licenses[] = 2000;
519
520
break;
521
                default:
522
            }
523
            if ($user['ichtus_permisvoile']) {
524
                $licenses[] = 2006;
525
            }
526
            if ($user['ichtus_permismoteur']) {
527
                $licenses[] = 2007;
528
            }
529
            foreach ($licenses as $license) {
530
                $linkToLicense->bindValue(':license_id', $license);
531
                $linkToLicense->execute();
532
            }
533
        }
534
535
        $updateOwner = $conn->prepare('UPDATE user SET owner_id=:owner WHERE id=:id');
536
        foreach ($this->users as $user) {
537
            if ($user['family_uid'] && $user['family_uid'] !== $user['uid']) {
538
                // Update family ownership
539
                $updateOwner->bindValue(':owner', $user['family_uid']);
540
                $updateOwner->bindValue(':id', $user['uid']);
541
                $updateOwner->execute();
542
            }
543
        }
544
    }
545
546
    public function loadStorageRequests(): void
547
    {
548
        $this->connectTypo3();
549
        $query = 'SELECT * FROM tx_speciality_storage_places';
550
        $statement = $this->typo3->prepare($query);
551
552
        if ($statement->execute()) {
553
            echo sprintf('%u demandes d\'emplacement de stockage à importer...', $statement->rowCount()) . PHP_EOL;
554
            foreach ($statement->fetchAll(\PDO::FETCH_ASSOC) as $request) {
555
                if (!array_key_exists($request['uid_link'], $this->members)) {
556
                    echo sprintf('WARN: demande de stockage %u pour membre %u (%s %s) introuvable', $request['uid'], $request['uid_link'], $request['first_name'], $request['last_name']) . PHP_EOL;
557
                }
558
                $this->storage[$request['uid_link']] = $request;
559
            }
560
        }
561
    }
562
563
    /**
564
     * Create bookables (storage lockers, cabinets, space for boats)
565
     */
566
    private function insertBookables(): void
567
    {
568
        $conn = $this->entityManager->getConnection();
569
570
        $insert = <<<EOT
571
                INSERT INTO bookable(
572
                  code,
573
                  name,
574
                  description,
575
                  initial_price,
576
                  periodic_price,
577
                  simultaneous_booking_maximum,
578
                  booking_type,
579
                  creation_date,
580
                  credit_account_id
581
                ) VALUES (
582
                  :code,
583
                  :name,
584
                  :description,
585
                  :initial_price,
586
                  :periodic_price,
587
                  :simultaneous_booking_maximum,
588
                  :booking_type,
589
                  NOW(),
590
                  10036 -- Vente de prestations -> Location casiers
591
                )
592
EOT;
593
594
        $insert = $conn->prepare($insert);
595
596
        $linkToTag = $conn->prepare('INSERT INTO bookable_tag_bookable(bookable_tag_id, bookable_id) VALUES (:bookable_tag_id, :bookable_id)');
597
598
        // Armoires
599
        $insert->bindValue(':initial_price', 0);
600
        $insert->bindValue(':periodic_price', 50);
601
        // Une armoire peut être partagée entre 2 ou 3 membres
602
        $insert->bindValue(':simultaneous_booking_maximum', 3);
603
604
        /*
605
         * admin_only, because l'attribution d'un casier particulier est faite par l'admin,
606
         * bien que le membre demande un "Casier" il ne doit pas pouvoir réserver "Casier 26"
607
         */
608
        $insert->bindValue(':booking_type', 'admin_only');
609
610
        $insert->bindValue(':description', 'Armoire (50 x 200 x 70 cm)');
611
        for ($i = 1; $i <= 120; ++$i) {
612
            $insert->bindValue(':name', sprintf('Armoire %u', $i));
613
            $insert->bindValue(':code', sprintf('STA%u', $i));
614
            $insert->execute();
615
            $linkToTag->bindValue(':bookable_id', $conn->lastInsertId());
616
            $linkToTag->bindValue(':bookable_tag_id', $this->insertBookableTag('Armoire'));
617
            $linkToTag->execute();
618
            $linkToTag->bindValue(':bookable_tag_id', $this->insertBookableTag('Stockage'));
619
            $linkToTag->execute();
620
        }
621
622
        // Casiers
623
        $insert->bindValue(':periodic_price', 30);
624
        $insert->bindValue(':simultaneous_booking_maximum', 1);
625
        $insert->bindValue(':description', 'Casier (50 x 50 x 70 cm)');
626
        for ($i = 1; $i <= 36; ++$i) {
627
            $insert->bindValue(':name', sprintf('Casier %u', $i));
628
            $insert->bindValue(':code', sprintf('STC%u', $i));
629
            $insert->execute();
630
            $linkToTag->bindValue(':bookable_id', $conn->lastInsertId());
631
            $linkToTag->bindValue(':bookable_tag_id', $this->insertBookableTag('Casier'));
632
            $linkToTag->execute();
633
            $linkToTag->bindValue(':bookable_tag_id', $this->insertBookableTag('Stockage'));
634
            $linkToTag->execute();
635
        }
636
637
        // Stockage flotteurs
638
        $insert->bindValue(':periodic_price', 50);
639
        $insert->bindValue(':description', 'Emplacement de stockage sous le local pour un ou deux flotteurs (80 x 45 x 300 cm)');
640
        for ($i = 1; $i <= 80; ++$i) {
641
            $insert->bindValue(':name', sprintf('Stockage flotteur %u', $i));
642
            $insert->bindValue(':code', sprintf('STF%u', $i));
643
            $insert->execute();
644
            $linkToTag->bindValue(':bookable_id', $conn->lastInsertId());
645
            $linkToTag->bindValue(':bookable_tag_id', $this->insertBookableTag('Flotteurs'));
646
            $linkToTag->execute();
647
            $linkToTag->bindValue(':bookable_tag_id', $this->insertBookableTag('Stockage'));
648
            $linkToTag->execute();
649
        }
650
651
        // Râtelier du Wishbone Club
652
        $insert->bindValue(':periodic_price', 100);
653
        $insert->bindValue(':description', 'Casier râtelier WBC (100 x 60 x 300 cm)');
654
        for ($i = 65; $i <= 81; ++$i) {
655
            $door = chr($i); // doors A to Q
656
            for ($position = 1; $position <= 5; ++$position) {
657
                $insert->bindValue(':name', sprintf('Casier râtelier %s%u', $door, $position));
658
                $insert->bindValue(':code', sprintf('STCR%s%u', $door, $position));
659
                $insert->execute();
660
                $linkToTag->bindValue(':bookable_id', $conn->lastInsertId());
661
                $linkToTag->bindValue(':bookable_tag_id', $this->insertBookableTag('Casier du râtelier WBC'));
662
                $linkToTag->execute();
663
                $linkToTag->bindValue(':bookable_tag_id', $this->insertBookableTag('Stockage'));
664
                $linkToTag->execute();
665
            }
666
        }
667
    }
668
669
    /**
670
     * Create periodic bookings for all members
671
     */
672
    private function insertBookings(): void
673
    {
674
        $conn = $this->entityManager->getConnection();
675
676
        $insert = <<<EOT
677
                INSERT INTO booking(
678
                  owner_id,
679
                  creation_date,
680
                  status,
681
                  participant_count,
682
                  start_date,
683
                  bookable_id,
684
                  remarks
685
                ) VALUES (
686
                  :owner,
687
                  NOW(),
688
                  :status,
689
                  :participant_count,
690
                  NOW(),
691
                  :bookable,
692
                  :remarks
693
                )
694
EOT;
695
696
        $insert = $conn->prepare($insert);
697
        $insert->bindValue(':status', 'booked');
698
        $insert->bindValue(':participant_count', 1);
699
        $insert->bindValue(':remarks', '');
700
701
        // Réservations liées au chef de famille
702
        foreach ($this->members as $idMember => $member) {
703
            // Cotisation annuelle
704
            $insert->bindValue(':owner', $idMember);
705
            $insert->bindValue(':bookable', 3006); // Cotisation annuelle
706
            $insert->execute();
707
708
            // Fond de réparation
709
            $insert->bindValue(':bookable', 3026); // Fonds de réparation interne
710
            $insert->execute();
711
        }
712
713
        // Réservations concernant des membres du ménage, mais cependant liées et facturées au chef de famille
714
        foreach ($this->users as $idUser => $user) {
715
            $insert->bindValue(':owner', $user['family_uid']);
716
            $insert->bindValue(':remarks', implode(' ', [$user['first_name'], $user['last_name']]));
717
718
            // Adhésion NFT (optionnel)
719
            if (!empty($user['ichtus_NFT'])) {
720
                $insert->bindValue(':bookable', 3004); // Cotisation NFT
721
                $insert->execute();
722
            }
723
724
            // Licence Swiss Sailing
725
            if (!empty($user['ichtus_swiss_sailing'])) {
726
                switch ($user['ichtus_swiss_sailing_type']) {
727
                    case 'A':
728
                        $idBookable = 3027; // Licence Swiss Sailing (voile)
729
                        break;
730
                    case 'J':
731
                        $idBookable = 3030; // Cotisation Swiss Sailing (NFT, junior)
732
                        break;
733
                    default:
734
                        $idBookable = null;
735
                }
736
                if ($idBookable) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $idBookable of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
737
                    $insert->bindValue(':bookable', $idBookable);
738
                    $insert->execute();
739
                }
740
            }
741
742
            // Licence Swiss Windsurfing
743
            if (!empty($user['ichtus_swiss_windsurf_type']) && $user['ichtus_swiss_windsurf_type'] === 'A') {
744
                $insert->bindValue(':bookable', 3028); // Cotisation Swiss Windsurfing (NFT)
745
                $insert->execute();
746
            }
747
        }
748
        $insert->bindValue(':remarks', '');
749
750
        // Attribution des emplacements de stockage
751
        $selectBookableByName = $conn->prepare('SELECT id, name, simultaneous_booking_maximum FROM bookable WHERE name=:name');
752
        foreach ($this->storage as $request) {
753
            if (empty($request['uid_link']) || !array_key_exists($request['uid_link'], $this->members)) {
754
                echo sprintf('ERROR: UID membre de %s %s inconnu dans fichier de demande de stockage', $request['first_name'], $request['last_name']) . PHP_EOL;
755
756
                continue;
757
            }
758
            $insert->bindValue(':owner', $request['uid_link']);
759
            foreach ([1 => 'Armoire %u', 2 => 'Armoire %u', 3 => 'Casier %u'] as $index => $bookableName) {
760
                if ($request["materiel{$index}"] > 0 && !empty($request["materiel{$index}attrib"])) {
761
                    $selectBookableByName->bindValue(':name', sprintf($bookableName, $request["materiel{$index}attrib"]));
762
                    $bookable = null;
763
                    if ($selectBookableByName->execute() && $selectBookableByName->rowCount() === 1) {
764
                        $bookable = $selectBookableByName->fetch(\PDO::FETCH_ASSOC);
765
                    }
766
                    if ($bookable) {
767
                        $insert->bindValue(':bookable', $bookable['id']);
768
                        $insert->execute();
769
                        if (!array_key_exists($bookable['id'], $this->storageAllocated)) {
770
                            $this->storageAllocated[$bookable['id']] = 1;
771
                        } else {
772
                            $this->storageAllocated[$bookable['id']] += 1;
773
                        }
774
                        echo sprintf('%s attribué à %s %s', $bookable['name'], $this->users[$request['uid_link']]['first_name'], $this->users[$request['uid_link']]['last_name']) . PHP_EOL;
775
                        if ($this->storageAllocated[$bookable['id']] > $bookable['simultaneous_booking_maximum']) {
776
                            echo sprintf('WARN: %s attribué %u fois dépassant la limite de %u', $bookable['name'], $this->storageAllocated[$bookable], $bookable['simultaneous_booking_maximum']) . PHP_EOL;
777
                        }
778
                    } else {
779
                        echo sprintf("ERROR: cannot find $bookableName in bookables", $request["materiel{$index}attrib"]) . PHP_EOL;
780
                    }
781
                }
782
            }
783
        }
784
    }
785
786
    /**
787
     * Insert or find an user tag by name
788
     *
789
     * @param string $name
790
     *
791
     * @return int ID of the existing or newly tag
792
     */
793
    private function insertUserTag(string $name): int
794
    {
795
        $conn = $this->entityManager->getConnection();
796
797
        $existing = $conn->prepare('SELECT id FROM user_tag WHERE name = :name');
798
        $existing->bindValue(':name', $name);
799
        $existing->execute();
800
        if ($existing->rowCount()) {
801
            return (int) $existing->fetchColumn();
802
        }
803
804
        $insert = $conn->prepare('INSERT INTO user_tag(creation_date, name) VALUES (NOW(), :name)');
805
        $insert->bindValue(':name', $name);
806
        if ($insert->execute()) {
807
            return (int) $conn->lastInsertId();
808
        }
809
810
        throw new Exception(sprintf('Cannot find or insert UserTag "%s"', $name));
811
    }
812
813
    /**
814
     * Insert or find a bookable tag by name
815
     *
816
     * @param string $name
817
     *
818
     * @return int ID of the existing or newly tag
819
     */
820
    private function insertBookableTag(string $name): int
821
    {
822
        $conn = $this->entityManager->getConnection();
823
824
        $existing = $conn->prepare('SELECT id FROM bookable_tag WHERE name = :name');
825
        $existing->bindValue(':name', $name);
826
        $existing->execute();
827
        if ($existing->rowCount()) {
828
            return (int) $existing->fetchColumn();
829
        }
830
831
        $insert = $conn->prepare('INSERT INTO bookable_tag(creation_date, name) VALUES (NOW(), :name)');
832
        $insert->bindValue(':name', $name);
833
        if ($insert->execute()) {
834
            return (int) $conn->lastInsertId();
835
        }
836
837
        throw new Exception(sprintf('Cannot find or insert BookableTag "%s"', $name));
838
    }
839
840
    /**
841
     * Convert MacRoman string to UTF-8
842
     *
843
     * @param mixed $string
844
     *
845
     * @return string
846
     */
847
    private function fromMacRoman($string): ?string
848
    {
849
        return !empty($string) ? iconv('MacRoman', 'UTF-8', $string) : $string;
850
    }
851
852
    /**
853
     * Delete existing test data prior importing
854
     */
855
    private function deleteTestData(): void
856
    {
857
        $conn = $this->entityManager->getConnection();
858
        $result = $conn->executeQuery('SELECT id FROM account a where a.owner_id < 0');
859
        $accounts = $result->fetchAll(\PDO::FETCH_COLUMN);
860
        $stmt = $conn->prepare('DELETE tl, t FROM transaction_line tl JOIN transaction t ON tl.transaction_id = t.id WHERE FIND_IN_SET(CAST(tl.debit_id as char), :accounts) OR FIND_IN_SET(CAST(tl.credit_id as char), :accounts)');
861
        $stmt->bindValue('accounts', implode(',', $accounts));
862
        $stmt->execute();
863
        $stmt = $conn->prepare('DELETE FROM account WHERE FIND_IN_SET(CAST(id as char), :accounts)');
864
        $stmt->bindValue('accounts', implode(',', $accounts));
865
        $stmt->execute();
866
        $stmt = $conn->prepare('DELETE FROM message WHERE creator_id < 0 OR owner_id < 0');
867
        $stmt->execute();
868
        $stmt = $conn->prepare('DELETE FROM user_tag WHERE creator_id < 0 OR owner_id < 0');
869
        $stmt->execute();
870
        $stmt = $conn->prepare('DELETE FROM user_tag WHERE creator_id < 0 OR owner_id < 0');
871
        $stmt->execute();
872
        $stmt = $conn->prepare('DELETE FROM expense_claim WHERE creator_id < 0 OR owner_id < 0');
873
        $stmt->execute();
874
        $stmt = $conn->prepare('DELETE FROM booking WHERE creator_id < 0 OR owner_id < 0');
875
        $stmt->execute();
876
        $stmt = $conn->prepare('UPDATE user set owner_id = NULL WHERE id < 0');
877
        $stmt->execute();
878
        $stmt = $conn->prepare('DELETE FROM user WHERE id < 0');
879
        $stmt->execute();
880
    }
881
882
    /**
883
     * Generate password string which evaluate to "medium" security level by digitalspagethi mix
884
     *
885
     * @param int $length length of password
886
     *
887
     * @return string
888
     */
889
    private function generatePassword(int $length = 10): string
890
    {
891
        $numberLength = 2;
892
        $vowels = 'aeuyAEUY';
893
        $consonants = 'bdghjmnpqrstvzBDGHJLMNPQRSTVWXZ';
894
        $numbers = '23456789';
895
896
        $password = '';
897
        $alt = time() % 2;
898
        for ($i = 0; $i < $length - $numberLength; ++$i) {
899
            if ($alt === 1) {
900
                $password .= $consonants[(mt_rand() % mb_strlen($consonants))];
901
                $alt = 0;
902
            } else {
903
                $password .= $vowels[(mt_rand() % mb_strlen($vowels))];
904
                $alt = 1;
905
            }
906
        }
907
908
        for ($i = 0; $i < $numberLength; ++$i) {
909
            $password .= $numbers[(mt_rand() % mb_strlen($numbers))];
910
        }
911
912
        return $password;
913
    }
914
}
915