ReserveWeekTask::processAllDatesForBestMembers()   A
last analyzed

Complexity

Conditions 5
Paths 5

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 0
loc 23
ccs 0
cts 14
cp 0
rs 9.2408
c 0
b 0
f 0
cc 5
nc 5
nop 0
crap 30
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the zibios/sharep.
7
 *
8
 * (c) Zbigniew Ślązak
9
 */
10
11
namespace App\Task;
12
13
use App\Entity\Accounting\Journal;
14
use App\Entity\Accounting\JournalMove;
15
use App\Entity\Accounting\Task;
16
use App\Entity\EntityInterface;
17
use App\Entity\Parking\Member;
18
use App\Entity\Parking\Reservation;
19
use App\Enum\Entity\JournalTypeEnum;
20
use App\Enum\Entity\ReservationTypeEnum;
21
use App\Enum\Entity\TaskTypeEnum;
22
use App\Enum\Functional\ApplicationEnum;
23
use App\Repository\Functional\ParkingReservationRepository;
24
25
class ReserveWeekTask extends AbstractTask
26
{
27
    /** @var ReserveDaysProperties */
28
    private $properties;
29
    /** @var array|EntityInterface[] */
30
    private $entitiesToSave = [];
31
    /** @var int */
32
    private $availablePlacesSummary = 0;
33
    /** @var array */
34
    private $availablePlacesByDate = [];
35
36
    // -----------------------------------------------------------------------------------------------------------------
37
38
    public function __construct(
39
        ParkingReservationRepository $parkingReservationRepository,
40
        ReserveDaysProperties $properties
41
    ) {
42
        parent::__construct($parkingReservationRepository);
43
        $this->properties = $properties;
44
    }
45
46
    // -----------------------------------------------------------------------------------------------------------------
47
48
    public function run(\DateTimeImmutable $weekAnyWorkdayDate): void
49
    {
50
        $weekWorkdaysDates = $this->getWeekWorkdaysDates($weekAnyWorkdayDate);
51
        $this->properties->calculate(...$weekWorkdaysDates);
52
53
        $this->processAllDatesForBestMembers();
54
55
        $this->parkingReservationRepository->saveAllInTransaction(...$this->entitiesToSave);
56
    }
57
58
    // -----------------------------------------------------------------------------------------------------------------
59
60
    private function processAllDatesForBestMembers(): void
61
    {
62
        $this->availablePlacesSummary = $this->properties->getPlacesCountSummary();
63
        $this->availablePlacesByDate = $this->properties->getPlacesCountByDate();
64
65
        $task = new Task(TaskTypeEnum::FILL());
66
        $this->parkingReservationRepository->saveAll($task);
67
68
        /** @var member $member */
69
        foreach ($this->properties->getMembersSortedByPoints() as $member) {
70
            if (0 === $this->availablePlacesSummary) {
71
                break;
72
            }
73
            if ($this->availablePlacesSummary < 0) {
74
                throw new \DomainException('Calculation error: availablePlacesSummary < 0');
75
            }
76
            if (array_sum($this->availablePlacesByDate) !== $this->availablePlacesSummary) {
77
                throw new \DomainException('Calculation error: availablePlacesSummary != count(availablePlacesByDate)');
78
            }
79
80
            $this->processAllDatesForMember($member, $task);
81
        }
82
    }
83
84
    private function processAllDatesForMember(Member $member, Task $task): void
85
    {
86
        $journal = new Journal($task, JournalTypeEnum::RESERVE());
87
        $this->entitiesToSave[] = $journal;
88
89
        $reservedPlaces = 0;
90
        $reservedDate = null;
91
        /** @var \DateTimeImmutable $date */
92
        foreach ($this->properties->getDates() as $date) {
93
            $reservedDate = $date;
94
            $dateString = $date->format(ApplicationEnum::DATE_FORMAT);
95
96
            if (0 === $this->availablePlacesSummary) {
97
                break;
98
            }
99
            if (0 === $this->availablePlacesByDate[$dateString]) {
100
                continue;
101
            }
102
103
            $reservedPlaces += $this->processOneDayForMemberReturnReservedPlaces($date, $member, $journal);
104
105
            $this->availablePlacesSummary -= $reservedPlaces;
106
            $this->availablePlacesByDate[$dateString] -= $reservedPlaces;
107
            if ($this->availablePlacesSummary < 0) {
108
                throw new \DomainException('Calculation error: availablePlacesSummary < 0');
109
            }
110
            if ($this->availablePlacesByDate[$dateString] < 0) {
111
                throw new \DomainException('Calculation error: availablePlacesByDate[date] < 0');
112
            }
113
        }
114
115
        $systemMember = $this->parkingReservationRepository->getSystemMember();
116
        $journalMove = new JournalMove(
117
            $journal,
118
            $systemMember,
119
            $reservedDate,
120
            0,
121
            $reservedPlaces * ApplicationEnum::PLACE_POINTS
122
        );
123
        $this->entitiesToSave[] = $journalMove;
124
    }
125
126
    private function processOneDayForMemberReturnReservedPlaces(
127
        \DateTimeImmutable $date,
128
        Member $member,
129
        Journal $journal
130
    ): int {
131
        $dateString = $date->format(ApplicationEnum::DATE_FORMAT);
132
133
        if (false === $this->properties->isMembershipForMemberAndDate($member, $date)) {
134
            return 0;
135
        }
136
137
        if ($this->properties->getReservationForMemberAndDate($member, $date)) {
138
            return 0;
139
        }
140
141
        $places = 1;
142
        $memberNeed = $this->properties->getMemberNeedForMemberAndDate($member, $date);
143
        if ($memberNeed) {
144
            $places = $memberNeed->getPlaces();
145
        }
146
        if (0 === $places) {
147
            return 0;
148
        }
149
        if ($places > $this->availablePlacesByDate[$dateString]) {
150
            $places = $this->availablePlacesByDate[$dateString];
151
        }
152
153
        $reservation = new Reservation(
154
            $member,
155
            $date,
156
            $places,
157
            ReservationTypeEnum::ASSIGNED()
158
        );
159
        $this->entitiesToSave[] = $reservation;
160
161
        $journalMove = new JournalMove(
162
            $journal,
163
            $member,
164
            $date,
165
            $places * ApplicationEnum::PLACE_POINTS,
166
            0
167
        );
168
        $this->entitiesToSave[] = $journalMove;
169
170
        return $places;
171
    }
172
}
173