LoansController   A
last analyzed

Complexity

Total Complexity 37

Size/Duplication

Total Lines 424
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 178
c 3
b 0
f 0
dl 0
loc 424
rs 9.44
wmc 37

14 Methods

Rating   Name   Duplication   Size   Complexity  
A edit() 0 3 1
A update() 0 26 2
A lost() 0 9 1
A checkoutLocalItem() 0 29 2
B checkoutAlmaItem() 0 67 7
A restore() 0 15 2
A checkin() 0 13 3
A checkinAlmaItem() 0 23 2
A json() 0 9 1
A loggedResponse() 0 8 2
A checkout() 0 8 2
B checkinLocalLoan() 0 45 7
A getIndex() 0 15 3
A getShow() 0 6 2
1
<?php
2
3
namespace App\Http\Controllers;
4
5
use App\Events\LoanTableUpdated;
6
use App\Http\Requests\CheckinRequest;
7
use App\Http\Requests\CheckoutRequest;
8
use App\Item;
9
use App\Loan;
10
use App\User;
11
use Carbon\Carbon;
12
use Illuminate\Http\Request;
13
use Illuminate\Http\Response;
14
use Illuminate\Validation\ValidationException;
15
use Scriptotek\Alma\Client as AlmaClient;
16
use Scriptotek\Alma\Bibs\Item as AlmaItem;
17
use Scriptotek\Alma\Exception\RequestFailed;
18
use function Stringy\create as s;
19
20
class LoansController extends Controller
21
{
22
    /**
23
     * Validation error messages.
24
     *
25
     * @static array
26
     */
27
    protected $messages = [
28
        'user.required' => 'Trenger enten navn eller låne-ID.',
29
        'user.id.required_without' => 'Trenger enten navn eller låne-ID.',
30
        'user.name.required_without' => 'Trenger enten navn eller låne-ID.',
31
        'thing.required' => 'Uten ting blir det bare ingenting.',
32
    ];
33
34
    /*
35
     * Factory for Laravel Auth
36
     */
37
    protected $auth;
38
39
    /*
40
     * The currently logged in library
41
     */
42
    protected $library;
43
44
    /**
45
     * Display a listing of the resource.
46
     *
47
     * @param Request $request
48
     * @return Response
49
     */
50
    public function getIndex(Request $request)
51
    {
52
        $user = $request->input('user')
53
            ? ['name' => $request->input('user')]
54
            : $request->session()->get('user');
55
56
        $thing = $request->input('thing')
57
            ? ['name' => $request->input('thing')]
58
            : $request->session()->get('thing');
59
60
        return response()->view('loans.index', [
61
            'library_id' => \Auth::user()->id,
62
            'user' => $user,
63
            'thing' => $thing,
64
        ])->header('Cache-Control', 'private, no-store, no-cache, must-revalidate, max-age=0');
65
    }
66
67
    /**
68
     * Display a listing of the resource.
69
     *
70
     * @param Request $request
71
     * @return Response
72
     */
73
    public function json()
74
    {
75
        $library = \Auth::user();
76
77
        $loans = Loan::with('item.thing', 'user', 'user.identifiers', 'notifications')
78
            ->where('library_id', $library->id)
79
            ->orderBy('created_at', 'desc')->get();
80
81
        return response()->json($loans);
0 ignored issues
show
Bug Best Practice introduced by
The expression return response()->json($loans) returns the type Illuminate\Http\JsonResponse which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
82
    }
83
84
    /**
85
     * Display the specified resource.
86
     *
87
     * @param Loan $loan
88
     * @return Response
89
     */
90
    public function getShow(Loan $loan)
91
    {
92
        if ($loan) {
0 ignored issues
show
introduced by
$loan is of type App\Loan, thus it always evaluated to true.
Loading history...
93
            return response()->view('loans.show', array('loan' => $loan));
94
        } else {
95
            return response()->view('errors.404', array('what' => 'Lånet'), 404);
96
        }
97
    }
98
99
100
    /**
101
     * Logs the response and returns it.
102
     *
103
     * @param Loan $loan
104
     * @return Response
105
     */
106
    protected function loggedResponse($data)
107
    {
108
        if (isset($data['error'])) {
109
            \Log::info($data['error'], ['library' => \Auth::user()->name]);
110
            return response()->json($data, 422);
0 ignored issues
show
Bug Best Practice introduced by
The expression return response()->json($data, 422) returns the type Illuminate\Http\JsonResponse which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
111
        }
112
        \Log::info($data['status'], ['library' => \Auth::user()->name]);
113
        return response()->json($data, 200);
0 ignored issues
show
Bug Best Practice introduced by
The expression return response()->json($data, 200) returns the type Illuminate\Http\JsonResponse which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
114
    }
115
116
    /**
117
     * Store a newly created resource in storage.
118
     *
119
     * @param AlmaClient $alma
120
     * @param CheckoutRequest $request
121
     * @return Response
122
     */
123
    public function checkout(AlmaClient $alma, CheckoutRequest $request)
124
    {
125
        if (is_a($request->item, AlmaItem::class)) {
126
            return $this->checkoutAlmaItem($alma, $request->item, $request->user, $request);
127
        }
128
129
        // Create new loan
130
        return $this->checkoutLocalItem($request->item, $request->user, $request);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->checkoutLo...equest->user, $request) also could return the type Illuminate\Http\JsonResponse which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
131
    }
132
133
    public function checkoutLocalItem(Item $item, User $user, Request $request)
134
    {
135
        $loan = Loan::create([
136
            'user_id' => $user->id,
137
            'item_id' => $item->id,
138
            'due_at' => Carbon::now()
139
                ->addDays($item->thing->properties->loan_time)
140
                ->setTime(0, 0, 0),
141
            'as_guest' => false,
142
        ]);
143
        if (!$loan) {
144
            return response()->json(['errors' => $loan->errors], 409);
145
        }
146
147
        $user->loan_count += 1;
148
        $user->last_loan_at = Carbon::now();
149
        $user->save();
150
151
        event(new LoanTableUpdated('checkout', $request, $loan));
152
153
        $loan->load('user', 'item', 'item.thing');
154
155
        return $this->loggedResponse([
156
            'status' => sprintf(
157
                'Lånte ut %s (<a href="%s">Detaljer</a>).',
158
                $item->thing->properties->get('name_indefinite.nob'),
159
                action('LoansController@getShow', $loan->id)
160
            ),
161
            'loan' => $loan,
162
        ]);
163
    }
164
165
    /**
166
     * Show the form for editing the specified resource.
167
     *
168
     * @param Loan $loan
169
     * @return Response
170
     */
171
    public function edit(Loan $loan)
172
    {
173
        return response()->view('loans.edit', ['loan' => $loan]);
174
    }
175
176
    /**
177
     * Update the specified resource in storage.
178
     *
179
     * @param Loan $loan
180
     * @param Request $request
181
     * @return void
182
     */
183
    public function update(Loan $loan, Request $request)
184
    {
185
        $request->validate([
186
            'due_at' => 'required|date',
187
        ]);
188
189
        $oldDate = $loan->due_at;
190
191
        $loan->due_at = Carbon::parse($request->due_at);
192
        $loan->note = $request->note;
193
        $loan->save();
194
195
        if ($oldDate != $loan->due_at) {
196
            \Log::info(sprintf(
197
                'Endret forfallsdato for <a href="%s">utlånet</a> av %s fra %s til %s.',
198
                action('LoansController@getShow', $loan->id),
199
                $loan->item->thing->properties->get('name_indefinite.nob'),
200
                $oldDate->toDateString(),
201
                $loan->due_at->toDateString()
202
            ), ['library' => \Auth::user()->name]);
203
        }
204
205
        event(new LoanTableUpdated('update', $request, $loan));
206
207
        return redirect()->action('LoansController@getIndex')
0 ignored issues
show
Bug Best Practice introduced by
The expression return redirect()->actio...'Lånet ble oppdatert') returns the type Illuminate\Http\RedirectResponse which is incompatible with the documented return type void.
Loading history...
208
            ->with('status', 'Lånet ble oppdatert');
209
    }
210
211
    /**
212
     * Mark the specified resource as lost.
213
     *
214
     * @param Loan $loan
215
     * @param Request $request
216
     * @return Response
217
     */
218
    public function lost(Loan $loan, Request $request)
219
    {
220
        $loan->lost();
221
222
        event(new LoanTableUpdated('lost', $request, $loan));
223
224
        return $this->loggedResponse([
225
            'status' => sprintf('Registrerte %s som tapt.', $loan->item->formattedLink(false, false)),
226
            'undoLink' => action('LoansController@restore', $loan->id),
227
        ]);
228
    }
229
230
    /**
231
     * Checkin the specified loan.
232
     *
233
     * @param AlmaClient $alma
234
     * @param CheckinRequest $request
235
     * @return Response
236
     */
237
    public function checkin(AlmaClient $alma, CheckinRequest $request)
238
    {
239
        if ($request->loan) {
240
            return $this->checkinLocalLoan($request->loan, $request, $alma);
241
        }
242
243
        if ($request->almaItem) {
244
            return $this->checkinAlmaItem($alma, $request->almaItem);
245
        }
246
247
        return response()->json([
0 ignored issues
show
Bug Best Practice introduced by
The expression return response()->json(...asjon, men hvem vet.')) returns the type Illuminate\Http\JsonResponse which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
248
            'status' => 'Ingenting har blitt returnert. Det kan argumenteres for at dette var en ' .
249
                'unødvendig operasjon, men hvem vet.'
250
        ]);
251
    }
252
253
    /**
254
     * Restores the specified loan.
255
     *
256
     * @param Loan $loan
257
     * @param Request $request
258
     * @return Response
259
     */
260
    public function restore(Loan $loan, Request $request)
261
    {
262
        if ($loan->is_lost) {
263
            $loan->found();
264
        } else {
265
            $loan->restore();
266
        }
267
268
        event(new LoanTableUpdated('restore', $request, $loan));
269
270
        return $this->loggedResponse([
271
            'status' => sprintf(
272
                '%s er fortsatt utlånt (<a href="%s">Detaljer</a>).',
273
                s($loan->item->thing->properties->get('name_definite.nob'))->upperCaseFirst(),
274
                action('LoansController@getShow', $loan->id)
275
            )
276
        ]);
277
    }
278
279
    /**
280
     * Checkout Alma item without creating a local copy.
281
     *
282
     * @param AlmaClient $client
283
     * @param AlmaItem $item
284
     * @param User $localUser
285
     * @param Request $request
286
     * @return Response
287
     */
288
    protected function checkoutAlmaItem(AlmaClient $client, AlmaItem $almaItem, User $localUser, Request $request)
289
    {
290
        $library = \Auth::user();
291
292
        if (empty($library->library_code)) {
0 ignored issues
show
Bug introduced by
The property library_code does not exist on App\User. Did you mean library_id?
Loading history...
293
            return $this->loggedResponse([
294
                'error' => 'Alma-utlån krever at bibliotekskode er registrert'
295
                    . ' i kontoinnstillingene.',
296
            ]);
297
        }
298
299
        if ($localUser->in_alma) {
300
            $almaUser = $client->users->get($localUser->alma_primary_id);
301
        } else {
302
            if (empty($library->temporary_barcode)) {
303
                return $this->loggedResponse([
304
                    'error' => 'Brukeren finnes ikke i Alma. Hvis du vil låne ut på midlertidig lånekort'
305
                        . ' må det registreres i kontoinnstillingene.',
306
                ]);
307
            }
308
309
            $almaUser = $client->users->get($library->temporary_barcode);
0 ignored issues
show
Bug introduced by
The property temporary_barcode does not seem to exist on App\User. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
310
        }
311
312
        $almaLibrary = $client->libraries[$library->library_code];
313
314
        try {
315
            $response = $almaItem->checkOut($almaUser, $almaLibrary);
316
        } catch (RequestFailed $e) {
317
            return $this->loggedResponse([
318
                'error' => $e->getMessage(),
319
            ]);
320
        }
321
322
        if ($response->loan_status != 'ACTIVE') {
323
            return $this->loggedResponse([
324
                'error' => 'Utlån av Alma-dokument i Bibrex feilet, prøv i Alma i stedet.',
325
            ]);
326
        }
327
328
        # The Alma checkout was successful. If the user is not in Alma, we create a
329
        # temporary local item to keep track of the loan.
330
        if (!$localUser->in_alma) {
331
            $localItem = Item::withTrashed()->firstOrNew([
332
                'thing_id' => 1,
333
                'barcode' => $response->item_barcode,
334
            ]);
335
            $localItem->library_id = $library->id;
336
            $localItem->note = $response->title;
337
            $localItem->save();
338
339
            \Log::info(sprintf(
340
                'Opprettet midlertidig Bibrex-eksemplar for Alma-utlån (<a href="%s">Detaljer</a>)',
341
                action('ItemsController@show', $localItem->id)
342
            ), ['library' => \Auth::user()->name]);
343
344
            return $this->checkoutLocalItem($localItem, $localUser, $request);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->checkoutLo..., $localUser, $request) also could return the type Illuminate\Http\JsonResponse which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
345
        }
346
347
        # If the user exists in Alma, we don't create a local item.
348
        return $this->loggedResponse([
349
            'status' => sprintf(
350
                '%s (%s) ble lånt ut til %s i Alma. Forfaller: %s',
351
                $response->item_barcode,
352
                $response->title,
353
                $response->user_id,
354
                $response->due_date
355
            ),
356
        ]);
357
    }
358
359
    /**
360
     * Checkin Alma item.
361
     *
362
     * @param AlmaClient $client
363
     * @param AlmaItem $item
364
     * @return Response
365
     */
366
    protected function checkinAlmaItem(AlmaClient $client, AlmaItem $item)
367
    {
368
        $library = \Auth::user();
369
370
        if (empty($library->library_code)) {
0 ignored issues
show
Bug introduced by
The property library_code does not exist on App\User. Did you mean library_id?
Loading history...
371
            return $this->loggedResponse([
372
                'error' => 'Alma-innleveringer krever at bibliotekskode er registrert'
373
                    . ' i kontoinnstillingene.',
374
            ]);
375
        }
376
377
        $almaLibrary = $client->libraries[$library->library_code];
378
379
        $response = $item->scanIn($almaLibrary, 'DEFAULT_CIRC_DESK', [
380
            'place_on_hold_shelf' => 'true',
381
            'auto_print_slip' => 'true',
382
        ]);
383
384
        return $this->loggedResponse([
385
            'status' => sprintf(
386
                '<small>%s ble skanna inn i Alma, og Alma svarte:</small><br>%s',
387
                $item->item_data->barcode,
388
                $response->getMessage()
389
            ),
390
        ]);
391
    }
392
393
    /**
394
     * @param Loan $loan
395
     * @param Request $request
396
     * @param AlmaClient $alma
397
     * @return Response
398
     */
399
    protected function checkinLocalLoan(Loan $loan, Request $request, AlmaClient $alma)
400
    {
401
        $library = \Auth::user();
402
403
        if ($loan->is_lost) {
404
            $loan->found();
405
            return $this->loggedResponse(['status' => sprintf(
406
                '%s var registrert som tapt, men er nå tilbake!',
407
                $loan->item->formattedLink(true)
408
            )]);
409
        }
410
411
        if ($loan->trashed()) {
412
            if ($loan->item->thing_id == 1 && !empty($library->library_code)) {
0 ignored issues
show
Bug introduced by
The property library_code does not exist on App\User. Did you mean library_id?
Loading history...
413
                // Could still be on loan in Alma
414
                $almaItem = $alma->items->fromBarcode($loan->item->barcode);
415
                return $this->checkinAlmaItem($alma, $almaItem);
0 ignored issues
show
Bug introduced by
It seems like $almaItem can also be of type null; however, parameter $item of App\Http\Controllers\Loa...ller::checkinAlmaItem() does only seem to accept Scriptotek\Alma\Bibs\Item, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

415
                return $this->checkinAlmaItem($alma, /** @scrutinizer ignore-type */ $almaItem);
Loading history...
416
            }
417
418
            return response()->json(['status' => sprintf(
0 ignored issues
show
Bug Best Practice introduced by
The expression return response()->json(...attedLink(true))), 200) returns the type Illuminate\Http\JsonResponse which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
419
                '%s var allerede levert (men det går greit).',
420
                $loan->item->formattedLink(true)
421
            )], 200);
422
        }
423
424
        $loan->checkIn();
425
426
        $user = $loan->user;
427
        $user->last_loan_at = Carbon::now();
428
        $user->save();
429
430
        event(new LoanTableUpdated('checkin', $request, $loan));
431
432
        if ($loan->item->thing_id == 1 && !empty($library->library_code)) {
433
            $almaItem = $alma->items->fromBarcode($loan->item->barcode);
434
            return $this->checkinAlmaItem($alma, $almaItem);
435
        }
436
437
        return $this->loggedResponse([
438
            'status' => sprintf(
439
                'Returnerte %s (<a href="%s">Detaljer</a>).',
440
                $loan->item->thing->properties->get('name_indefinite.nob'),
441
                action('LoansController@getShow', $loan->id)
442
            ),
443
            'undoLink' => action('LoansController@restore', $loan->id),
444
        ]);
445
    }
446
}
447