Passed
Push — master ( c12e55...c256f6 )
by Adrien
05:36
created

User::userTagRemoved()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Application\Model;
6
7
use Application\DBAL\Types\BillingTypeType;
8
use Application\DBAL\Types\BookingStatusType;
9
use Application\DBAL\Types\RelationshipType;
10
use Application\Repository\LogRepository;
11
use Application\Repository\UserRepository;
12
use Application\Service\Role;
13
use Application\Traits\HasAddress;
14
use Application\Traits\HasDoorAccess;
15
use Application\Traits\HasIban;
16
use Application\Traits\HasRemarks;
17
use Cake\Chronos\Chronos;
18
use Cake\Chronos\Date;
19
use Doctrine\Common\Collections\ArrayCollection;
20
use Doctrine\Common\Collections\Collection;
21
use Doctrine\ORM\Mapping as ORM;
22
use Ecodev\Felix\Api\Exception;
23
use Ecodev\Felix\Model\CurrentUser;
24
use Ecodev\Felix\Model\Traits\HasInternalRemarks;
25
use Ecodev\Felix\Model\Traits\HasPassword;
26
use GraphQL\Doctrine\Annotation as API;
27
28
/**
29
 * User.
30
 *
31
 * @ORM\Entity(repositoryClass="Application\Repository\UserRepository")
32
 * @ORM\HasLifecycleCallbacks
33
 * @ORM\AssociationOverrides({
34
 *     @ORM\AssociationOverride(name="owner", inversedBy="users")
35
 * })
36
 * @API\Sorting({
37
 *     "Application\Api\Input\Sorting\Age",
38
 *     "Application\Api\Input\Sorting\Balance",
39
 * })
40
 * @API\Filters({
41
 *     @API\Filter(field="custom", operator="Application\Api\Input\Operator\HasBookingWithTaggedBookableOperatorType", type="id"),
42
 *     @API\Filter(field="custom", operator="Application\Api\Input\Operator\HasBookingWithBookableOperatorType", type="id"),
43
 *     @API\Filter(field="custom", operator="Application\Api\Input\Operator\HasBookingStatusOperatorType", type="id"),
44
 *     @API\Filter(field="custom", operator="Application\Api\Input\Operator\HasBookingCompletedOperatorType", type="boolean"),
45
 *     @API\Filter(field="bookingCount", operator="Application\Api\Input\Operator\BookingCount\BookingCountEqualOperatorType", type="int"),
46
 *     @API\Filter(field="bookingCount", operator="Application\Api\Input\Operator\BookingCount\BookingCountGreaterOperatorType", type="int"),
47
 *     @API\Filter(field="bookingCount", operator="Application\Api\Input\Operator\BookingCount\BookingCountGreaterOrEqualOperatorType", type="int"),
48
 *     @API\Filter(field="bookingCount", operator="Application\Api\Input\Operator\BookingCount\BookingCountLessOperatorType", type="int"),
49
 *     @API\Filter(field="bookingCount", operator="Application\Api\Input\Operator\BookingCount\BookingCountLessOrEqualOperatorType", type="int"),
50
 *     @API\Filter(field="balance", operator="Application\Api\Input\Operator\AccountBalance\EqualOperatorType", type="Money"),
51
 *     @API\Filter(field="balance", operator="Application\Api\Input\Operator\AccountBalance\GreaterOperatorType", type="Money"),
52
 *     @API\Filter(field="balance", operator="Application\Api\Input\Operator\AccountBalance\GreaterOrEqualOperatorType", type="Money"),
53
 *     @API\Filter(field="balance", operator="Application\Api\Input\Operator\AccountBalance\LessOperatorType", type="Money"),
54
 *     @API\Filter(field="balance", operator="Application\Api\Input\Operator\AccountBalance\LessOrEqualOperatorType", type="Money"),
55
 *     @API\Filter(field="bookingDate", operator="Application\Api\Input\Operator\BookingDate\BookingDateEqualOperatorType", type="Date"),
56
 *     @API\Filter(field="bookingDate", operator="Application\Api\Input\Operator\BookingDate\BookingDateGreaterOperatorType", type="Date"),
57
 *     @API\Filter(field="bookingDate", operator="Application\Api\Input\Operator\BookingDate\BookingDateGreaterOrEqualOperatorType", type="Date"),
58
 *     @API\Filter(field="bookingDate", operator="Application\Api\Input\Operator\BookingDate\BookingDateLessOperatorType", type="Date"),
59
 *     @API\Filter(field="bookingDate", operator="Application\Api\Input\Operator\BookingDate\BookingDateLessOrEqualOperatorType", type="Date"),
60
 * })
61
 */
62
class User extends AbstractModel implements \Ecodev\Felix\Model\User
63
{
64
    final public const ROLE_ANONYMOUS = 'anonymous';
65
    final public const ROLE_BOOKING_ONLY = 'booking_only';
66
    final public const ROLE_INDIVIDUAL = 'individual';
67
    final public const ROLE_ACCOUNTING_VERIFICATOR = 'accounting_verificator';
68
    final public const ROLE_MEMBER = 'member';
69
    final public const ROLE_TRAINER = 'trainer';
70
    final public const ROLE_FORMATION_RESPONSIBLE = 'formation_responsible';
71
    final public const ROLE_RESPONSIBLE = 'responsible';
72
    final public const ROLE_ADMINISTRATOR = 'administrator';
73
74
    final public const STATUS_INACTIVE = 'inactive';
75
    final public const STATUS_NEW = 'new';
76
    final public const STATUS_ACTIVE = 'active';
77
    final public const STATUS_ARCHIVED = 'archived';
78
79
    use HasAddress;
80
    use HasDoorAccess;
81
    use HasIban;
82
    use HasInternalRemarks;
83
    use HasPassword;
84
    use HasRemarks;
85
86
    private static ?User $currentUser = null;
87
88
    /**
89
     * Set currently logged in user
90
     * WARNING: this method should only be called from \Application\Authentication\AuthenticationListener.
91
     *
92
     * @param User $user
93
     */
94 281
    public static function setCurrent(?self $user): void
95
    {
96 281
        self::$currentUser = $user;
97
98
        // Initialize ACL filter with current user if a logged in one exists
99
        /** @var UserRepository $userRepository */
100 281
        $userRepository = _em()->getRepository(self::class);
101 281
        $aclFilter = $userRepository->getAclFilter();
102 281
        $aclFilter->setUser($user);
103
104 281
        CurrentUser::set($user);
105
    }
106
107
    /**
108
     * Returns currently logged user or null.
109
     */
110 103
    public static function getCurrent(): ?self
111
    {
112 103
        return self::$currentUser;
113
    }
114
115
    /**
116
     * @ORM\Column(type="string", length=50, nullable=true, unique=true)
117
     */
118
    private ?string $login = null;
119
120
    /**
121
     * @ORM\Column(type="string", length=191)
122
     */
123
    private string $firstName = '';
124
125
    /**
126
     * @ORM\Column(type="string", length=191)
127
     */
128
    private string $lastName = '';
129
130
    /**
131
     * @ORM\Column(type="string", length=191, nullable=true, unique=true)
132
     */
133
    private ?string $email = null;
134
135
    /**
136
     * @ORM\Column(type="UserRole", options={"default" = User::ROLE_INDIVIDUAL})
137
     */
138
    private string $role = self::ROLE_INDIVIDUAL;
139
140
    /**
141
     * @ORM\Column(type="UserStatus", options={"default" = User::STATUS_NEW})
142
     */
143
    private string $status = self::STATUS_NEW;
144
145
    /**
146
     * @ORM\Column(type="datetime", nullable=true)
147
     */
148
    private ?Chronos $welcomeSessionDate = null;
149
150
    /**
151
     * @ORM\Column(type="datetime", nullable=true)
152
     */
153
    private ?Chronos $resignDate = null;
154
155
    /**
156
     * @var int sex
157
     *
158
     * @ORM\Column(type="smallint", options={"default" = 0}))
159
     */
160
    private int $sex = 0;
161
162
    /**
163
     * @ORM\Column(type="string", length=25, options={"default" = ""})
164
     */
165
    private string $phone = '';
166
167
    /**
168
     * @ORM\Column(type="string", length=25, options={"default" = ""})
169
     */
170
    private string $mobilePhone = '';
171
172
    /**
173
     * @ORM\Column(type="string", length=25, options={"default" = ""})
174
     */
175
    private string $swissSailing = '';
176
177
    /**
178
     * @ORM\Column(type="SwissSailingType", nullable=true)
179
     */
180
    private ?string $swissSailingType = null;
181
182
    /**
183
     * @ORM\Column(type="SwissWindsurfType", nullable=true)
184
     */
185
    private ?string $swissWindsurfType = null;
186
187
    /**
188
     * @ORM\Column(type="date", nullable=true)
189
     */
190
    private ?Date $birthday = null;
191
192
    /**
193
     * @ORM\Column(type="boolean", options={"default" = 0})
194
     */
195
    private bool $termsAgreement = false;
196
197
    /**
198
     * @ORM\Column(type="boolean", options={"default" = 0})
199
     */
200
    private bool $hasInsurance = false;
201
202
    /**
203
     * @ORM\Column(type="boolean", options={"default" = 0})
204
     */
205
    private bool $receivesNewsletter = false;
206
207
    /**
208
     * @ORM\Column(type="Relationship", options={"default" = RelationshipType::HOUSEHOLDER})
209
     */
210
    private string $familyRelationship = RelationshipType::HOUSEHOLDER;
211
212
    /**
213
     * @ORM\Column(type="BillingType", options={"default" = BillingTypeType::ELECTRONIC})
214
     */
215
    private string $billingType = BillingTypeType::ELECTRONIC;
216
217
    /**
218
     * @ORM\Column(type="datetime", nullable=true)
219
     */
220
    private ?Chronos $firstLogin = null;
221
222
    /**
223
     * @ORM\Column(type="datetime", nullable=true)
224
     */
225
    private ?Chronos $lastLogin = null;
226
227
    /**
228
     * @var Collection<Booking>
229
     *
230
     * @ORM\OneToMany(targetEntity="Booking", mappedBy="owner")
231
     */
232
    private Collection $bookings;
233
234
    /**
235
     * @var Collection<License>
236
     *
237
     * @ORM\ManyToMany(targetEntity="License", mappedBy="users")
238
     */
239
    private Collection $licenses;
240
241
    /**
242
     * @var Collection<UserTag>
243
     *
244
     * @ORM\ManyToMany(targetEntity="UserTag", mappedBy="users")
245
     */
246
    private Collection $userTags;
247
248
    /**
249
     * @var Collection<Message>
250
     *
251
     * @ORM\OneToMany(targetEntity="Message", mappedBy="recipient")
252
     */
253
    private Collection $messages;
254
255
    /**
256
     * There is actually 0 to 1 account, never more. And this is
257
     * enforced by DB unique constraints.
258
     *
259
     * @var Collection<Account>
260
     *
261
     * @ORM\OneToMany(targetEntity="Account", mappedBy="owner")
262
     */
263
    private Collection $accounts;
264
265
    /**
266
     * @var Collection<User>
267
     *
268
     * @ORM\OneToMany(targetEntity="User", mappedBy="owner")
269
     */
270
    private Collection $users;
271
272
    /**
273
     * Constructor.
274
     *
275
     * @param string $role role for new user
276
     */
277 111
    public function __construct(string $role = self::ROLE_INDIVIDUAL)
278
    {
279 111
        $this->role = $role;
280 111
        $this->bookings = new ArrayCollection();
281 111
        $this->accounts = new ArrayCollection();
282 111
        $this->licenses = new ArrayCollection();
283 111
        $this->userTags = new ArrayCollection();
284 111
        $this->messages = new ArrayCollection();
285 111
        $this->users = new ArrayCollection();
286
    }
287
288
    /**
289
     * Set login (eg: johndoe).
290
     *
291
     * @API\Input(type="Login")
292
     */
293 16
    public function setLogin(string $login): void
294
    {
295 16
        $this->login = $login;
296
    }
297
298
    /**
299
     * Get login (eg: johndoe).
300
     *
301
     * @API\Field(type="?Login")
302
     */
303 34
    public function getLogin(): ?string
304
    {
305 34
        return $this->login;
306
    }
307
308
    /**
309
     * Set first name.
310
     */
311 11
    public function setFirstName(string $firstName): void
312
    {
313 11
        $this->firstName = $firstName;
314
    }
315
316
    /**
317
     * Get first name.
318
     */
319 35
    public function getFirstName(): string
320
    {
321 35
        return $this->firstName;
322
    }
323
324
    /**
325
     * Set last name.
326
     */
327 11
    public function setLastName(string $lastName): void
328
    {
329 11
        $this->lastName = $lastName;
330
    }
331
332
    /**
333
     * Get last name.
334
     */
335 28
    public function getLastName(): string
336
    {
337 28
        return $this->lastName;
338
    }
339
340
    /**
341
     * Get full name.
342
     */
343 28
    public function getName(): string
344
    {
345 28
        return implode(' ', [$this->getFirstName(), $this->getLastName()]);
346
    }
347
348
    /**
349
     * Set email.
350
     *
351
     * @API\Input(type="?Email")
352
     */
353 6
    public function setEmail(?string $email): void
354
    {
355 6
        $this->email = $email;
356
    }
357
358
    /**
359
     * Get email.
360
     *
361
     * @API\Field(type="?Email")
362
     */
363 17
    public function getEmail(): ?string
364
    {
365 17
        return $this->email;
366
    }
367
368
    /**
369
     * Get the user role.
370
     *
371
     * @API\Field(type="UserRole")
372
     */
373 100
    public function getRole(): string
374
    {
375 100
        return $this->role;
376
    }
377
378
    /**
379
     * Sets the user role.
380
     *
381
     * @API\Input(type="UserRole")
382
     */
383 8
    public function setRole(string $role): void
384
    {
385 8
        if (!Role::canUpdate(self::getCurrent(), $this->role, $role)) {
386 3
            $currentRole = self::getCurrent() ? self::getCurrent()->getRole() : self::ROLE_ANONYMOUS;
387
388 3
            throw new Exception($currentRole . ' is not allowed to change role from ' . $this->role . ' to ' . $role);
389
        }
390
391 5
        $this->role = $role;
392
    }
393
394 11
    public function setOwner(?self $owner = null): void
395
    {
396 11
        if ($owner === $this) {
397 1
            throw new Exception('This user cannot be owned by himself');
398
        }
399
400 10
        if ($owner && $owner->getOwner()) {
401 1
            throw new Exception('This user cannot be owned by a user who is himself owned by somebody else');
402
        }
403
404 10
        if ($owner && $this->users->count()) {
405 1
            throw new Exception('This user owns other users, so he cannot himself be owned by somebody else');
406
        }
407
408 10
        if ($this->getOwner()) {
409 3
            $this->getOwner()->getEmail(); // Trigger lazy loading
410 3
            $this->getOwner()->users->removeElement($this);
411
        }
412
413 10
        parent::setOwner($owner);
414
415 10
        if ($this->getOwner()) {
416 5
            $this->getOwner()->getEmail(); // Trigger lazy loading
417 5
            $this->getOwner()->users->add($this);
418 5
            $this->setStatus($this->getOwner()->getStatus());
419
        }
420
    }
421
422
    /**
423
     * @API\Field(type="Application\Api\Enum\UserStatusType")
424
     */
425 11
    public function getStatus(): string
426
    {
427 11
        return $this->status;
428
    }
429
430
    /**
431
     * Whether the user is allowed to log in or stay logged in.
432
     */
433 4
    public function canLogin(): bool
434
    {
435 4
        return in_array($this->getStatus(), [self::STATUS_ACTIVE, self::STATUS_INACTIVE, self::STATUS_NEW], true);
436
    }
437
438
    /**
439
     * @API\Input(type="Application\Api\Enum\UserStatusType")
440
     */
441 16
    public function setStatus(string $newStatus): void
442
    {
443 16
        if ($newStatus === self::STATUS_ARCHIVED && $this->status !== self::STATUS_ARCHIVED) {
444 2
            $this->setResignDate(Chronos::NOW());
445 15
        } elseif ($this->status === self::STATUS_ARCHIVED && $newStatus !== self::STATUS_ARCHIVED) {
446
            $this->setResignDate(null);
447
        }
448
449 16
        $this->status = $newStatus;
450 16
        $this->revokeToken();
451
452 16
        foreach ($this->users as $user) {
453 1
            if ($user !== $this) {
454 1
                $user->setStatus($newStatus);
455
            }
456
        }
457
    }
458
459
    /**
460
     * Whether this user is a family owner or not.
461
     *
462
     * This is used for our internal logic and should
463
     * NEVER be related to `familyRelationship`. That field
464
     * is purely informative for humans.
465
     */
466 1
    public function isFamilyOwner(): bool
467
    {
468 1
        return !$this->getOwner();
469
    }
470
471 1
    public function initialize(): void
472
    {
473 1
        $this->role = self::ROLE_MEMBER; // Bypass security
474 1
        $this->setStatus(self::STATUS_NEW);
475
    }
476
477
    public function getPhone(): string
478
    {
479
        return $this->phone;
480
    }
481
482 1
    public function setPhone(string $phone): void
483
    {
484 1
        $this->phone = $phone;
485
    }
486
487
    public function getMobilePhone(): string
488
    {
489
        return $this->mobilePhone;
490
    }
491
492 2
    public function setMobilePhone(string $mobilePhone): void
493
    {
494 2
        $this->mobilePhone = $mobilePhone;
495
    }
496
497
    public function getBirthday(): ?Date
498
    {
499
        return $this->birthday;
500
    }
501
502 1
    public function setBirthday(?Date $birthday): void
503
    {
504 1
        $this->birthday = $birthday;
505
    }
506
507
    /**
508
     * return null|int.
509
     */
510
    public function getAge(): ?int
511
    {
512
        if ($this->birthday) {
513
            return (new Date())->diffInYears($this->birthday);
514
        }
515
516
        return null;
517
    }
518
519
    /**
520
     * Get bookings.
521
     */
522 3
    public function getBookings(): Collection
523
    {
524 3
        return $this->bookings;
525
    }
526
527
    /**
528
     * Get active bookings (confirmed and non-terminated).
529
     *
530
     * @API\Exclude
531
     */
532 2
    public function getRunningBookings(): Collection
533
    {
534 2
        return $this->bookings->filter(fn (Booking $booking) => $booking->getStatus() === BookingStatusType::BOOKED && $booking->getEndDate() === null);
535
    }
536
537
    /**
538
     * Notify the user that it has a new booking.
539
     * This should only be called by Booking::setResponsible().
540
     */
541 16
    public function bookingAdded(Booking $booking): void
542
    {
543 16
        $this->bookings->add($booking);
544
    }
545
546
    /**
547
     * Notify the user that it has a booking was removed.
548
     * This should only be called by Booking::setResponsible().
549
     */
550 4
    public function bookingRemoved(Booking $booking): void
551
    {
552 4
        $this->bookings->removeElement($booking);
553
    }
554
555 2
    public function getLicenses(): Collection
556
    {
557 2
        return $this->licenses;
558
    }
559
560 1
    public function getUserTags(): Collection
561
    {
562 1
        return $this->userTags;
563
    }
564
565
    /**
566
     * Notify the user that it has a new license.
567
     * This should only be called by License::addUser().
568
     */
569 1
    public function licenseAdded(License $license): void
570
    {
571 1
        $this->licenses->add($license);
572
    }
573
574
    /**
575
     * Notify the user that it a license was removed.
576
     * This should only be called by License::removeUser().
577
     */
578 1
    public function licenseRemoved(License $license): void
579
    {
580 1
        $this->licenses->removeElement($license);
581
    }
582
583
    /**
584
     * Notify the user that it has a new userTag.
585
     * This should only be called by UserTag::addUser().
586
     */
587 1
    public function userTagAdded(UserTag $userTag): void
588
    {
589 1
        $this->userTags->add($userTag);
590
    }
591
592
    /**
593
     * Notify the user that a userTag was removed.
594
     * This should only be called by UserTag::removeUser().
595
     */
596 1
    public function userTagRemoved(UserTag $userTag): void
597
    {
598 1
        $this->userTags->removeElement($userTag);
599
    }
600
601
    public function isTermsAgreement(): bool
602
    {
603
        return $this->termsAgreement;
604
    }
605
606 2
    public function setTermsAgreement(bool $termsAgreement): void
607
    {
608 2
        $this->termsAgreement = $termsAgreement;
609
    }
610
611
    public function hasInsurance(): bool
612
    {
613
        return $this->hasInsurance;
614
    }
615
616 2
    public function setHasInsurance(bool $hasInsurance): void
617
    {
618 2
        $this->hasInsurance = $hasInsurance;
619
    }
620
621
    public function getWelcomeSessionDate(): ?Chronos
622
    {
623
        return $this->welcomeSessionDate;
624
    }
625
626
    public function setWelcomeSessionDate(?Chronos $welcomeSessionDate): void
627
    {
628
        $this->welcomeSessionDate = $welcomeSessionDate;
629
    }
630
631 1
    public function getResignDate(): ?Chronos
632
    {
633 1
        return $this->resignDate;
634
    }
635
636 2
    public function setResignDate(?Chronos $resignDate): void
637
    {
638 2
        $this->resignDate = $resignDate;
639
    }
640
641
    public function getReceivesNewsletter(): bool
642
    {
643
        return $this->receivesNewsletter;
644
    }
645
646 1
    public function setReceivesNewsletter(bool $receivesNewsletter): void
647
    {
648 1
        $this->receivesNewsletter = $receivesNewsletter;
649
    }
650
651
    /**
652
     * Get the sex.
653
     *
654
     * @API\Field(type="Sex")
655
     */
656
    public function getSex(): int
657
    {
658
        return $this->sex;
659
    }
660
661
    /**
662
     * Set the sex.
663
     *
664
     * @API\Input(type="Sex")
665
     */
666 1
    public function setSex(int $sex): void
667
    {
668 1
        $this->sex = $sex;
669
    }
670
671
    /**
672
     * Get the Swiss Sailing licence number.
673
     */
674
    public function getSwissSailing(): string
675
    {
676
        return $this->swissSailing;
677
    }
678
679 1
    public function setSwissSailing(string $swissSailing): void
680
    {
681 1
        $this->swissSailing = $swissSailing;
682
    }
683
684
    /**
685
     * Get the Swiss Sailing licence type.
686
     *
687
     * @API\Field(type="?SwissSailingType")
688
     */
689
    public function getSwissSailingType(): ?string
690
    {
691
        return $this->swissSailingType;
692
    }
693
694
    /**
695
     * Set the Swiss Sailing licence type.
696
     *
697
     * @API\Input(type="?SwissSailingType")
698
     */
699
    public function setSwissSailingType(?string $swissSailingType): void
700
    {
701
        $this->swissSailingType = $swissSailingType;
702
    }
703
704
    /**
705
     * Get the Swiss Windsurf licence type.
706
     *
707
     * @API\Field(type="?SwissWindsurfType")
708
     */
709
    public function getSwissWindsurfType(): ?string
710
    {
711
        return $this->swissWindsurfType;
712
    }
713
714
    /**
715
     * Set the Swiss Windsurf licence type.
716
     *
717
     * @API\Input(type="?SwissWindsurfType")
718
     */
719
    public function setSwissWindsurfType(?string $swissWindsurfType): void
720
    {
721
        $this->swissWindsurfType = $swissWindsurfType;
722
    }
723
724
    /**
725
     * Get the first login date.
726
     */
727 1
    public function getFirstLogin(): ?Chronos
728
    {
729 1
        return $this->firstLogin;
730
    }
731
732
    /**
733
     * Get the last login date.
734
     */
735 1
    public function getLastLogin(): ?Chronos
736
    {
737 1
        return $this->lastLogin;
738
    }
739
740 3
    public function recordLogin(): void
741
    {
742 3
        _log()->info(LogRepository::LOGIN);
743
744 3
        $now = new Chronos();
745 3
        if (!$this->firstLogin) {
746 3
            $this->firstLogin = $now;
747
        }
748
749 3
        $this->lastLogin = $now;
750
    }
751
752
    /**
753
     * @API\Field(type="Relationship")
754
     */
755
    public function getFamilyRelationship(): string
756
    {
757
        return $this->familyRelationship;
758
    }
759
760
    /**
761
     * @API\Input(type="Relationship")
762
     */
763 3
    public function setFamilyRelationship(string $familyRelationship): void
764
    {
765 3
        $this->familyRelationship = $familyRelationship;
766
    }
767
768
    /**
769
     * @API\Field(type="BillingType")
770
     */
771
    public function getBillingType(): string
772
    {
773
        return $this->billingType;
774
    }
775
776
    /**
777
     * @API\Input(type="BillingType")
778
     */
779 1
    public function setBillingType(string $billingType): void
780
    {
781 1
        $this->billingType = $billingType;
782
    }
783
784
    /**
785
     * Get the user transaction account.
786
     */
787 41
    public function getAccount(): ?Account
788
    {
789 41
        if ($this->getOwner() && $this->getOwner() !== $this) {
790 8
            return $this->getOwner()->getAccount();
791
        }
792
793 41
        return $this->accounts->count() ? $this->accounts->first() : null;
794
    }
795
796
    /**
797
     * Notify the user that it has a new account
798
     * This should only be called by Account::setOwner().
799
     */
800 21
    public function accountAdded(Account $account): void
801
    {
802 21
        $this->accounts->clear();
803 21
        $this->accounts->add($account);
804
    }
805
806
    /**
807
     * Notify the user that a account was removed
808
     * This should only be called by Account::setOwner().
809
     */
810 1
    public function accountRemoved(): void
811
    {
812 1
        $this->accounts->clear();
813
    }
814
815
    /**
816
     * Get messages sent to the user.
817
     */
818 1
    public function getMessages(): Collection
819
    {
820 1
        return $this->messages;
821
    }
822
823
    /**
824
     * Notify the user that it has a new message
825
     * This should only be called by Message::setRecipient().
826
     */
827 11
    public function messageAdded(Message $message): void
828
    {
829 11
        $this->messages->add($message);
830
    }
831
832
    /**
833
     * Notify the user that a message was removed
834
     * This should only be called by Message::setRecipient().
835
     */
836 1
    public function messageRemoved(Message $message): void
837
    {
838 1
        $this->messages->removeElement($message);
839
    }
840
841
    /**
842
     * Check if the user can *really* open a door
843
     * This also takes into account the user status and role.
844
     *
845
     * @API\Field(args={@API\Argument(name="door", type="?Application\Api\Enum\DoorType")})
846
     *
847
     * @param null|string $door a particular door, or null for any
848
     */
849 6
    public function getCanOpenDoor(?string $door = null): bool
850
    {
851 6
        $allowedStatus = [self::STATUS_ACTIVE];
852 6
        $allowedRoles = [
853
            self::ROLE_ACCOUNTING_VERIFICATOR,
854
            self::ROLE_INDIVIDUAL,
855
            self::ROLE_MEMBER,
856
            self::ROLE_TRAINER,
857
            self::ROLE_FORMATION_RESPONSIBLE,
858
            self::ROLE_RESPONSIBLE,
859
            self::ROLE_ADMINISTRATOR,
860
        ];
861
862 6
        if ($door && !$this->$door) {
863 3
            return false;
864
        }
865
866 6
        if (!in_array($this->status, $allowedStatus, true) || !in_array($this->role, $allowedRoles, true)) {
867 2
            return false;
868
        }
869
870 4
        return true;
871
    }
872
873
    /**
874
     * Override parent to prevents users created from administration to be family of the administrator.
875
     *
876
     * The owner must be explicitly set for all users.
877
     */
878 3
    protected function getOwnerForCreation(): ?self
879
    {
880 3
        return null;
881
    }
882
}
883