Completed
Pull Request — master (#13)
by Vojta
06:35
created

ReservationsFacade::sendMails()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 11
ccs 0
cts 2
cp 0
rs 9.4285
cc 1
eloc 4
nc 1
nop 1
crap 2
1
<?php namespace VojtaSvoboda\Reservations\Facades;
2
3
use Auth;
4
use Carbon\Carbon;
5
use Config;
6
use Event;
7
use Illuminate\Database\Eloquent\Collection;
8
use Illuminate\Support\Facades\DB;
9
use October\Rain\Exception\ApplicationException;
10
use October\Rain\Exception\ValidationException;
11
use VojtaSvoboda\Reservations\Classes\DatesResolver;
12
use VojtaSvoboda\Reservations\Mailers\ReservationAdminMailer;
13
use VojtaSvoboda\Reservations\Mailers\ReservationMailer;
14
use VojtaSvoboda\Reservations\Models\Reservation;
15
use VojtaSvoboda\Reservations\Models\Settings;
16
use VojtaSvoboda\Reservations\Models\Status;
17
18
/**
19
 * Public reservations facade.
20
 *
21
 * Usage: App::make(ReservationsFacade::class);
22
 *
23
 * @package VojtaSvoboda\Reservations\Facades
24
 */
25
class ReservationsFacade
26
{
27
    /** @var Reservation $reservations */
28
    private $reservations;
29
30
    /** @var Status $statuses */
31
    private $statuses;
32
33
    /** @var DatesResolver $datesResolver */
34
    private $datesResolver;
35
36
    /** @var array $returningUsersCache */
37
    private $returningUsersCache;
38
39
    /** @var ReservationMailer $mailer */
40
    private $mailer;
41
42
    /** @var ReservationAdminMailer $adminMailer */
43
    private $adminMailer;
44
45
    /**
46
     * ReservationsFacade constructor.
47
     *
48
     * @param Reservation $reservations
49
     * @param Status $statuses
50
     * @param DatesResolver $resolver
51
     * @param ReservationMailer $mailer
52
     * @param ReservationAdminMailer $adminMailer
53
     */
54 9
    public function __construct(
55
        Reservation $reservations, Status $statuses, DatesResolver $resolver,
56
        ReservationMailer $mailer, ReservationAdminMailer $adminMailer
57
    ) {
58 9
        $this->reservations = $reservations;
59 9
        $this->statuses = $statuses;
60 9
        $this->datesResolver = $resolver;
61 9
        $this->mailer = $mailer;
62 9
        $this->adminMailer = $adminMailer;
63 9
    }
64
65
    /**
66
     * Create and store reservation.
67
     *
68
     * @param array $data
69
     *
70
     * @return Reservation $reservation
71
     *
72
     * @throws ApplicationException
73
     * @throws ValidationException
74
     */
75 8
    public function storeReservation($data)
76
    {
77
        // transform date and time to Carbon
78 8
        $data['date'] = $this->transformDateTime($data);
79
80
        // check date availability
81 6
        $this->checkDate($data);
82
83
        // create reservation
84 6
        $reservation = $this->reservations->create($data);
85
86
        // send mails to client and admin
87 6
        $this->sendMails($reservation);
88
89
        return $reservation;
90 6
    }
91
92
    /**
93 6
     * Send mail to client and admin.
94
     *
95 6
     * @param Reservation $reservation
96
     */
97
    public function sendMails($reservation)
98
    {
99
        // calculate reservations by same email
100
        $sameCount = $this->getReservationsWithSameEmailCount($reservation->email);
101
102
        // send reservation confirmation to customer
103
        $this->mailer->send($reservation, $sameCount);
104
105
        // send reservation confirmation to admin
106
        $this->adminMailer->send($reservation, $sameCount);
107
    }
108
109
    /**
110
     * Get all reservations.
111
     *
112
     * @return Collection
113
     */
114
    public function getReservations()
115
    {
116
        return $this->reservations->all();
117
    }
118
119
    /**
120
     * Get all active (not cancelled) reservations.
121
     *
122
     * @return Collection
123
     */
124
    public function getActiveReservations()
125
    {
126
        return $this->reservations->notCancelled()->get();
127
    }
128
129
    /**
130
     * Get all reserved time slots.
131
     *
132
     * @return array
133
     */
134
    public function getReservedDates()
135
    {
136
        $reservations = $this->getActiveReservations();
137
138
        return $this->datesResolver->getDatesFromReservations($reservations);
139
    }
140
141
    /**
142
     * Get all reservations by given date interval.
143
     *
144
     * @param Carbon $since Date from.
145
     * @param Carbon $till Date to.
146
     *
147
     * @return mixed
148
     */
149
    public function getReservationsByInterval(Carbon $since, Carbon $till)
150 6
    {
151
        return $this->reservations->whereBetween('date', [$since, $till])->get();
152 6
    }
153
154
    /**
155
     * Get reservations count by one email.
156
     *
157
     * @param $email
158
     *
159
     * @return int
160
     */
161
    public function getReservationsWithSameEmailCount($email)
162 1
    {
163
        return $this->reservations->where('email', $email)->notCancelled()->count();
164
    }
165 1
166 1
    /**
167
     * Is user returning or not? You have to set this parameter at Backend Reservations setting.
168
     *
169
     * @param $email
170
     *
171 1
     * @return bool
172
     */
173 1
    public function isUserReturning($email)
174 1
    {
175 1
        // if disabled, return always false
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
176 1
        $threshold = Settings::get('returning_mark', 0);
177
        if ($threshold < 1) {
178 1
            return false;
179 1
        }
180
181
        // load emails count
182
        if ($this->returningUsersCache === null) {
183 1
            $items = $this
184 1
                ->reservations
185
                ->select(DB::raw('email, count(*) as count'))
186 1
                ->groupBy('email')
187
                ->get();
188
            // refactor to mapWithKeys after upgrade to Laravel 5.3.
189
            foreach($items as $item) {
190
                $this->returningUsersCache[$item['email']] = $item['count'];
191
            }
192
        }
193
194
        $returning = $this->returningUsersCache;
195
        $actual = isset($returning[$email]) ? $returning[$email] : 0;
196
197
        return $threshold > 0 && $actual >= $threshold;
198
    }
199
200
    /**
201
     * Bulk reservation state change.
202
     *
203
     * @param array $ids
204
     * @param string $ident
205
     */
206
    public function bulkStateChange($ids, $ident)
207
    {
208
        // get state
209
        $status = $this->statuses->where('ident', $ident)->first();
210
        if (!$status) {
211
            return;
212
        }
213
214
        // go through reservations
215
        foreach ($ids as $id)
216
        {
217
            $reservation = $this->reservations->find($id);
218
            if (!$reservation) {
219
                continue;
220
            }
221
222
            $reservation->status = $status;
223
            $reservation->save();
224
        }
225
    }
226
227
    /**
228
     * Bulk reservations delete.
229
     *
230
     * @param array $ids
231
     */
232
    public function bulkDelete($ids)
233
    {
234
        // go through reservations
235
        foreach ($ids as $id)
236
        {
237
            $reservation = $this->reservations->find($id);
238
            if (!$reservation) {
239
                continue;
240
            }
241
242
            $reservation->delete();
243
        }
244 9
    }
245
246
    /**
247 9
     * Transform date and time to DateTime string.
248 1
     *
249
     * @param $data
250 8
     *
251 1
     * @return Carbon
252
     *
253
     * @throws ApplicationException
254 7
     */
255
    public function transformDateTime($data)
256 7
    {
257
        // validate date and time
258
        if (empty($data['date'])) {
259
            throw new ApplicationException('You have to select pickup date!');
260
261
        } elseif (empty($data['time'])) {
262
            throw new ApplicationException('You have to select pickup hour!');
263
        }
264
265
        $format = Config::get('vojtasvoboda.reservations::config.formats.datetime', 'd/m/Y H:i');
266 6
267
        return Carbon::createFromFormat($format, trim($data['date'] . ' ' . $data['time']));
268
    }
269 6
270
    /**
271
     * Check gived date and time.
272
     *
273
     * @param array $data
274 6
     *
275 1
     * @throws ApplicationException
276
     */
277 6
    public function checkDate($data)
278
    {
279
        // check reservation sent limit
280
        if ($this->isCreatedWhileAgo()) {
281
            throw new ApplicationException('You can sent only one reservation per 30 seconds, please wait a second.');
282
        }
283
284
        // check date availability
285
        if (!$this->isDateAvailable($data['date'])) {
286 6
            throw new ApplicationException($data['date']->format('d.m.Y H:i') . ' is already booked.');
287
        }
288
    }
289 6
290
    /**
291
     * Returns if date is available to book.
292 6
     *
293 6
     * @param Carbon $date
294 6
     *
295
     * @return bool
296
     */
297 6
    public function isDateAvailable(Carbon $date)
298 6
    {
299 6
        // get boundary dates for given reservation date
300
        $boundaries = $this->datesResolver->getBoundaryDates($date);
301
302 6
        // get all reservations in this date
303
        $reservations = $this->reservations->notCancelled()->whereBetween('date', $boundaries)->get();
304 6
305
        return $reservations->count() === 0;
306
    }
307
308
    /**
309
     * Try to find some reservation in less then given limit (default 30 seconds).
310
     *
311
     * @return boolean
312 6
     */
313
    public function isCreatedWhileAgo()
314 6
    {
315
        // protection time
316
        $time = Config::get('vojtasvoboda.reservations::config.protection_time', '-30 seconds');
317
        $timeLimit = Carbon::parse($time)->toDateTimeString();
318
319
        // try to find some message
320
        $item = $this->reservations->machine()->where('created_at', '>', $timeLimit)->first();
321
322
        return $item !== null;
323
    }
324
}
325