View | Details | Raw Unified | Return to bug 7317
Collapse All | Expand All

(-)a/Koha/Illrequest.pm (+1162 lines)
Line 0 Link Here
1
package Koha::Illrequest;
2
3
# Copyright PTFS Europe 2016
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
15
# details.
16
#
17
# You should have received a copy of the GNU General Public License along with
18
# Koha; if not, write to the Free Software Foundation, Inc., 51 Franklin
19
# Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21
# use Modern::Perl;
22
23
use Clone 'clone';
24
use File::Basename qw/basename/;
25
use Koha::Database;
26
use Koha::Illrequestattributes;
27
use Koha::Patron;
28
29
use base qw(Koha::Object);
30
31
=head1 NAME
32
33
Koha::Illrequest - Koha Illrequest Object class
34
35
=head1 (Re)Design
36
37
An ILLRequest consists of two parts; the Illrequest Koha::Object, and a series
38
of related Illrequestattributes.
39
40
The former encapsulates the basic necessary information that any ILL requires
41
to be usable in Koha.  The latter is a set of additional properties used by
42
one of the backends.
43
44
The former subsumes the legacy "Status" object.  The latter remains
45
encapsulated in the "Record" object.
46
47
TODO:
48
49
- Anything invoking the ->status method; annotated with:
50
  + # Old use of ->status !
51
52
=head1 API
53
54
=head2 Backend API Response Principles
55
56
All methods should return a hashref in the following format:
57
58
=item * error
59
60
This should be set to 1 if an error was encountered.
61
62
=item * status
63
64
The status should be a string from the list of statuses detailed below.
65
66
=item * message
67
68
The message is a free text field that can be passed on to the end user.
69
70
=item * value
71
72
The value returned by the method.
73
74
=over
75
76
=head2 Interface Status Messages
77
78
=over
79
80
=item * branch_address_incomplete
81
82
An interface request has determined branch address details are incomplete.
83
84
=item * cancel_success
85
86
The interface's cancel_request method was successful in cancelling the
87
Illrequest using the API.
88
89
=item * cancel_fail
90
91
The interface's cancel_request method failed to cancel the Illrequest using
92
the API.
93
94
=item * unavailable
95
96
The interface's request method returned saying that the desired item is not
97
available for request.
98
99
=head2 Class Methods
100
101
=cut
102
103
=head3 type
104
105
=cut
106
107
sub _type {
108
    return 'Illrequest';
109
}
110
111
# XXX: Method to expose DBIx accessor for illrequestattributes relationship
112
sub illrequestattributes {
113
    my ( $self ) = @_;
114
    return Koha::Illrequestattributes->_new_from_dbic(
115
        scalar $self->_result->illrequestattributes
116
    );
117
}
118
119
# XXX: Method to expose DBIx accessor for borrower relationship
120
sub patron {
121
    my ( $self ) = @_;
122
    return Koha::Patron->_new_from_dbic(
123
        scalar $self->_result->borrowernumber
124
    );
125
}
126
127
sub status {
128
    my ( $self, $new ) = @_;
129
    # Fetch old status...
130
    my $old = $self->SUPER::status;
131
    # If new...
132
    if ( $new ) {
133
        # Invoke hook, then update to $new
134
        $rs = $self->backend_update_status({
135
            request    => $self,
136
            other      => {
137
                old_status => $old,
138
                new_status => $new,
139
            }
140
        });
141
        die($rs->{message}) if $rs->{error};
142
        return $self->SUPER::status($new);
143
    }
144
    return $old;
145
}
146
147
sub load_backend {
148
    my ( $self, $backend_id ) = @_;
149
150
    my @raw = qw/Koha Illbackends/; # Base Path
151
152
    my $backend_name = $backend_id || $self->backend;
153
    $location = join "/", @raw, $backend_name, "Base.pm"; # File to load
154
    $backend_class = join "::", @raw, $backend_name, "Base"; # Package name
155
    require $location;
156
    $self->{_my_backend} = $backend_class->new({ config => $self->_config });
157
    return $self;
158
}
159
160
=head3 _backend
161
162
    my $backend = $abstract->_backend($new_backend);
163
    my $backend = $abstract->_backend;
164
165
Getter/Setter for our API object.
166
167
=cut
168
169
sub _backend {
170
    my ( $self, $backend ) = @_;
171
    $self->{_my_backend} = $backend if ( $backend );
172
    # Dynamically load our backend object, as late as possible.
173
    $self->load_backend unless ( $self->{_my_backend} );
174
    return $self->{_my_backend};
175
}
176
177
=head3 _config
178
179
    my $config = $abstract->_config($config);
180
    my $config = $abstract->_config;
181
182
Getter/Setter for our config object.
183
184
=cut
185
186
sub _config {
187
    my ( $self, $config ) = @_;
188
    $self->{_my_config} = $config if ( $config );
189
    # Load our config object, as late as possible.
190
    unless ( $self->{_my_config} ) {
191
        $self->{_my_config} = Koha::Illrequest::Config->new;
192
    }
193
    return $self->{_my_config};
194
}
195
196
=head3 metadata
197
198
=cut
199
200
sub metadata {
201
    my ( $self ) = @_;
202
    return {};
203
}
204
205
=head3 _core_status_graph
206
207
=cut
208
209
sub _core_status_graph {
210
    my ( $self ) = @_;
211
    return {
212
        NEW => {
213
            prev_actions => [ ],                 # Actions containing buttons
214
                                                 # leading to this status
215
            id             => 'NEW',             # ID of this status
216
            name           => 'New request',     # UI name of this status
217
            ui_method_name => 'New request',     # UI name of method leading
218
                                                 # to this status
219
            method         => 'create',          # method to this status
220
            next_actions   => [ 'REQ', 'KILL' ], # buttons to add to all
221
                                                 # requests with this status
222
            ui_method_icon => 'fa-plus',         # UI Style class
223
        },
224
        REQ => {
225
            prev_actions   => [ 'NEW', 'REQREV', 'QUEUED' ],
226
            id             => 'REQ',
227
            name           => 'Requested',
228
            ui_method_name => 'Confirm request',
229
            method         => 'confirm',
230
            next_actions   => [ 'REQREV', 'CANCREQ' ],
231
            ui_method_icon => 'fa-check',
232
        },
233
        REQREV => {
234
            prev_actions   => [ 'CANCREQ', 'REQ' ],
235
            id             => 'REQREV',
236
            name           => 'Request reverted',
237
            ui_method_name => 'Revert Request',
238
            method         => 'cancel',
239
            next_actions   => [ 'REQ', 'KILL' ],
240
            ui_method_icon => 'fa-times',
241
        },
242
        QUEUED => {
243
            prev_actions   => [ ],
244
            id             => 'QUEUED',
245
            name           => 'Queued request',
246
            ui_method_name => 0,
247
            method         => 0,
248
            next_actions   => [ 'REQ', 'KILL' ],
249
            ui_method_icon => 0,
250
        },
251
        CANCREQ => {
252
            prev_actions   => [ 'REQ' ],
253
            id             => 'CANCREQ',
254
            name           => 'Cancellation requested',
255
            ui_method_name => 0,
256
            method         => 0,
257
            next_actions   => [ 'REQREV' ],
258
            ui_method_icon => 0,
259
        },
260
        COMP => {
261
            prev_actions   => [ 'REQ' ],
262
            id             => 'COMP',
263
            name           => 'Completed',
264
            ui_method_name => 0,
265
            method         => 0,
266
            next_actions   => [ ],
267
            ui_method_icon => 0,
268
        },
269
        KILL => {
270
            prev_actions   => [ 'QUEUED', 'REQREV', 'NEW' ],
271
            id             => 'KILL',
272
            name           => 0,
273
            ui_method_name => 'Delete request',
274
            method         => 'delete',
275
            next_actions   => [ ],
276
            ui_method_icon => 'fa-trash',
277
        },
278
    };
279
}
280
281
sub _status_graph_union {
282
    my ( $self, $core_status_graph, $backend_status_graph ) = @_;
283
    # Create new status graph with:
284
    # - all core_status_graph
285
    # - for-each each backend_status_graph
286
    #   + add to new status graph
287
    #   + for each core prev_action:
288
    #     * locate core_status
289
    #     * update next_actions with additional next action.
290
    #   + for each core next_action:
291
    #     * locate core_status
292
    #     * update prev_actions with additional prev action
293
294
    my @core_status_ids = keys %{$core_status_graph};
295
    my $status_graph = clone($core_status_graph);
296
297
    foreach my $backend_status_key ( keys %{$backend_status_graph} ) {
298
        $backend_status = $backend_status_graph->{$backend_status_key};
299
        # Add to new status graph
300
        $status_graph->{$backend_status_key} = $backend_status;
301
        # Update all core methods' next_actions.
302
        foreach my $prev_action ( @{$backend_status->{prev_actions}} ) {
303
            if ( grep $prev_action, @core_status_ids ) {
304
                my @next_actions =
305
                     @{$status_graph->{$prev_action}->{next_actions}};
306
                push @next_actions, $backend_status_key;
307
                $status_graph->{$prev_action}->{next_actions}
308
                    = \@next_actions;
309
            }
310
        }
311
        # Update all core methods' prev_actions
312
        foreach my $next_action ( @{$backend_status->{next_actions}} ) {
313
            if ( grep $next_action, @core_status_ids ) {
314
                my @prev_actions =
315
                     @{$status_graph->{$next_action}->{prev_actions}};
316
                push @prev_actions, $backend_status_key;
317
                $status_graph->{$next_action}->{prev_actions}
318
                    = \@prev_actions;
319
            }
320
        }
321
    }
322
323
    return $status_graph;
324
}
325
326
### Core API methods
327
328
=head3 capabilities
329
330
    my $capabilities = $illrequest->capabilities;
331
332
Return a hashref mapping methods to operation names supported by the queried
333
backend.
334
335
Example return value:
336
337
    { create => "Create Request", confirm => "Progress Request" }
338
339
=cut
340
341
sub capabilities {
342
    my ( $self, $status ) = @_;
343
    # Generate up to date status_graph
344
    my $status_graph = $self->_status_graph_union(
345
        $self->_core_status_graph,
346
        $self->_backend->status_graph({
347
            request => $self,
348
            other   => {}
349
        })
350
    );
351
    # Extract available actions from graph.
352
    return $status_graph->{$status} if $status;
353
    # Or return entire graph.
354
    return $status_graph;
355
}
356
357
sub available_backends {
358
    my ( $self ) = @_;
359
    my $backend_dir = $self->_config->backend_dir;
360
    my @backends = ();
361
    my @backends = <$backend_dir/*> if ( $backend_dir );
362
    my @backends = map { basename($_) } @backends;
363
    return \@backends;
364
}
365
366
sub available_actions {
367
    my ( $self ) = @_;
368
    my $current_action = $self->capabilities($self->status);
369
    my @available_actions = map { $self->capabilities($_) }
370
        @{$current_action->{next_actions}};
371
    return \@available_actions;
372
}
373
374
sub backend_confirm {
375
    my ( $self, $params ) = @_;
376
377
    # The backend handles setting of mandatory fields in the commit stage:
378
    # - orderid
379
    # - accessurl, cost (if available).
380
    my $response = $self->_backend->confirm({
381
            request    => $self,
382
            other      => $params,
383
        });
384
    return $self->expandTemplate($response);
385
}
386
387
sub backend_update_status {
388
    my ( $self, $params ) = @_;
389
    return $self->expandTemplate($self->_backend->update_status($params));
390
}
391
392
=head3 backend_cancel
393
394
    my $ILLResponse = $illRequest->backend_cancel;
395
396
The standard interface method allowing for request cancellation.
397
398
=cut
399
400
sub backend_cancel {
401
    my ( $self ) = @_;
402
403
    my $result = $self->_backend->cancel({ request => $self });
404
405
    # FIXME: API breakage: Untypical old return value (preserved below) may
406
    # cause issues!
407
    # return ( $self->expandTemplate($result), $self );
408
409
    return $self->expandTemplate($result);
410
}
411
412
=head3 backend_renew
413
414
    my $renew_response = $illRequest->backend_renew;
415
416
The standard interface method allowing for request renewal queries.
417
418
=cut
419
420
sub backend_renew {
421
    my ( $self ) = @_;
422
    return $self->expandTemplate(
423
        $self->_backend->renew({
424
            request    => $self,
425
        })
426
    );
427
}
428
429
=head3 backend_status
430
431
    my $status_response = $illRequest->backend_status;
432
433
The standard interface method allowing for request status queries.
434
435
=cut
436
437
sub backend_status {
438
    my ( $self, $params ) = @_;
439
    return $self->expandTemplate(
440
        $self->_backend->status({
441
            request    => $self,
442
            other      => $params,
443
        })
444
    );
445
}
446
447
=head3 backend_create
448
449
    my $create_response = $abstractILL->backend_create($params);
450
451
Return an array of Record objects created by querying our backend with
452
a Search query.
453
454
In the context of the other ILL methods, this is a special method: we only
455
pass it $params, as it does not yet have any other data associated with it.
456
457
=cut
458
459
sub backend_create {
460
    my ( $self, $params ) = @_;
461
462
    # First perform API action, then...
463
    my $args = {
464
        request => $self,
465
        other   => $params,
466
    };
467
    my $result = $self->_backend->create($args);
468
469
    # ... simple case: we're not at 'commit' stage.
470
    my $stage = $result->{stage};
471
    return $self->expandTemplate($result)
472
        unless ( 'commit' eq $stage || 'commit_manual' eq $stage );
473
474
    # ... complex case: commit!
475
476
    # Do we still have space for an ILL or should we queue?
477
    my $permitted = $self->check_limits(
478
        { patron => $self->patron }, { librarycode => $self->branchcode }
479
    );
480
481
    # Now augment our committed request.
482
483
    # FIXME: WTF? may have to deal with manual creation here!
484
    # if ( $params->{uin} ) {
485
    #     # API guarantees it will return UIN of backend if available.
486
    #     $result->{uin} = $params->{uin};
487
    # } else {
488
    #     # Else, considered manual creation
489
    #     $result->{primary_manual} = 1;
490
    # }
491
492
    # FIXME: These two are for legacy purposes.  Up to date branch and
493
    # borrower can be found via
494
    # $result->{request}->{borrower,branch}_id
495
    $result->{branch} = "FIXME: Incorrect branch reference!";
496
    $result->{borrower} = "FIXME: Incorrect borrower reference!";
497
498
    $result->{permitted} = $permitted;             # Queue request?
499
500
    # FIXME: Here we should simply populate ourselves with our available data.
501
    #
502
    # This involves...
503
504
    # ...Updating status!
505
    $self->status('QUEUED')->store unless ( $permitted );
506
507
    # FIXME: Fix Unmediated ILLs!
508
    # Handle Unmediated ILLs
509
    # if ( C4::Context->preference("UnmediatedILL") && $permitted
510
    #       # XXX: Why && result manual?
511
    #       && $result->{manual} ) {
512
    #     # FIXME: Also carry out privilege checks
513
    #     my ( $response, $new_rq ) = $self->place_request; # WTF?
514
    #     if ( $response ) {
515
    #         $result->{value}->{request} = $new_rq;
516
    #         return $result;
517
    #     } else {
518
    #         die "Placing the request failed.";
519
    #     }
520
    # } else {
521
    #     $result->{value}->{request} = $request;
522
    #     return $result;
523
    # }
524
525
    return $self->expandTemplate($result);
526
}
527
528
=head3 expandTemplate
529
530
    my $params = $abstract->expandTemplate($params);
531
532
Return a version of $PARAMS augmented with our required template path.
533
534
=cut
535
536
sub expandTemplate {
537
    my ( $self, $params ) = @_;
538
    my $backend = $self->_backend->name;
539
    # Generate path to file to load
540
    my $backend_dir = $self->_config->backend_dir;
541
    my $backend_tmpl = join "/", $backend_dir, $backend;
542
    my $intra_tmpl =  join "/", $backend_tmpl, "intra-includes",
543
        $params->{method} . ".inc";
544
    # Set file to load
545
    $params->{template} = $intra_tmpl;
546
    return $params;
547
}
548
549
#### Abstract Imports
550
551
=head3 getCensorNotesStaff
552
553
    my $bool = $abstract->getCensorNotesStaff;
554
555
Return a boolean indicating whether we should be censoring staff notes or not,
556
as determined by our configuration file.
557
558
=cut
559
560
sub getCensorNotesStaff {
561
    my ( $self ) = @_;
562
    my $censorship = $self->_config->censorship;
563
    return $censorship->{censor_notes_staff};
564
}
565
566
=head3 getDisplayReplyDate
567
568
    my 0 = $abstract->getDisplayReplyDate;
569
570
Return a 0 if we want to hide it or 1 if not.
571
572
=cut
573
574
sub getDisplayReplyDate {
575
    my ( $self ) = @_;
576
    my $censorship = $self->_config->censorship;
577
    # If censor is yes, don't display and vice versa.
578
    return ( $censorship->{censor_reply_date} ) ? 0 : 1;
579
}
580
581
=head3 getLimits
582
583
    my $limit_rules = $abstract->getLimits( {
584
        type  => 'brw_cat' | 'branch',
585
        value => $value
586
    } );
587
588
Return the ILL limit rules for the supplied combination of type / value.
589
590
As the config may have no rules for this particular type / value combination,
591
or for the default, we must define fall-back values here.
592
593
=cut
594
595
# FIXME: Needs unit tests!
596
sub getLimits {
597
    my ( $self, $params ) = @_;
598
    my $limits = $self->_config->getLimitRules($params->{type});
599
600
    return $limits->{$params->{value}}
601
        || $limits->{default}
602
        || { count => -1, method => 'active' };
603
}
604
605
=head3 getPrefix
606
607
    my $prefix = $abstract->getPrefix( {
608
        brw_cat => $brw_cat,
609
        branch  => $branch_code,
610
    } );
611
612
Return the ILL prefix as defined by our $params: either per borrower category,
613
per branch or the default.
614
615
=cut
616
617
sub getPrefix {
618
    my ( $self, $params ) = @_;
619
    my $brn_prefixes = $self->_config->getPrefixes('branch');
620
    my $brw_prefixes = $self->_config->getPrefixes('brw_cat');
621
622
    return $brw_prefixes->{$params->{brw_cat}}
623
        || $brn_prefixes->{$params->{branch}}
624
        || $brw_prefixes->{default}
625
        || "";                  # "the empty prefix"
626
}
627
628
#### Illrequests Imports
629
630
=head3 check_limits
631
632
    my $ok = $illRequests->check_limits( {
633
        borrower   => $borrower,
634
        branchcode => 'branchcode' | undef,
635
    } );
636
637
Given $PARAMS, a hashref containing a $borrower object and a $branchcode,
638
see whether we are still able to place ILLs.
639
640
LimitRules are derived from koha-conf.xml:
641
 + default limit counts, and counting method
642
 + branch specific limit counts & counting method
643
 + borrower category specific limit counts & counting method
644
 + err on the side of caution: a counting fail will cause fail, even if
645
   the other counts passes.
646
647
=cut
648
649
# FIXME: Needs unit tests!
650
sub check_limits {
651
    my ( $self, $params ) = @_;
652
    my $patron     = $params->{patron};
653
    my $branchcode = $params->{librarycode} || $patron->branchcode;
654
655
    # Establish rules
656
    my ( $branch_rules, $brw_rules ) = (
657
        $self->getLimits( {
658
            type => 'branch',
659
            value => $branchcode
660
        } ),
661
        $self->getLimits( {
662
            type => 'brw_cat',
663
            value => $patron->categorycode,
664
        } ),
665
    );
666
    # Almost there, but category code didn't quite work.
667
    my ( $branch_limit, $brw_limit )
668
        = ( $branch_rules->{count}, $brw_rules->{count} );
669
    my ( $branch_count, $brw_count ) = (
670
        $self->_limit_counter(
671
            $branch_rules->{method}, { branch_id => $branchcode }
672
        ),
673
        $self->_limit_counter(
674
            $brw_rules->{method}, { borrower_id => $patron->borrowernumber }
675
        ),
676
    );
677
678
    # Compare and return
679
    # A limit of -1 means no limit exists.
680
    # We return blocked if either branch limit or brw limit is reached.
681
    if ( ( $branch_limit != -1 && $branch_limit <= $branch_count )
682
             || ( $brw_limit != -1 && $brw_limit <= $brw_count ) ) {
683
        return 0;
684
    } else {
685
        return 1;
686
    }
687
}
688
689
# FIXME: Needs unit tests!
690
sub _limit_counter {
691
    my ( $self, $method, $target ) = @_;
692
693
    # Establish parameters of counts
694
    my $where;
695
    if ($method && $method eq 'annual') {
696
        $where = \"YEAR(placement_date) = YEAR(NOW())";
697
    } else {                    # assume 'active'
698
        # FIXME: This status list is ugly. There should be a method in config
699
        # to return these.
700
        $where = { status => { -not_in => [ 'QUEUED', 'COMP' ] } };
701
    }
702
703
    # Create resultset
704
    my $resultset = Koha::Illrequests->search({ %{$target}, %{$where} });
705
706
    # Fetch counts
707
    return $resultset->count;
708
}
709
710
=head3 summary
711
712
    my $summary = $illRequest->summary();
713
714
Return a data-structure ready for JSON or other format based processing and
715
display to the end-user.  It returns a composit of $self's Record and Status
716
`summary' methods.
717
718
=cut
719
720
# FIXME: To be handled in templates
721
# FIXME: Needs Record handling sorting out
722
# sub getSummary {
723
#     my ( $self, $params ) = @_;
724
#     $params->{id_prefix} = $self->id_prefix;
725
#     my $record = $self->record->getSummary($params);
726
#     my $status = $self->getStatusSummary($params);
727
#     my %summary = (%{$record}, %{$status});
728
#     return \%summary;
729
# }
730
731
# FIXME: To be handled in templates
732
# sub getStatusSummary {
733
#     my ( $self, $params ) = @_;
734
#     my $return = {
735
#         id             => [ "Request Number", $self->illrequest_id ],
736
#         biblionumber   => [ "Biblio Number", $self->biblio_id ],
737
#         status         => [ "Status", $self->status ],
738
#         reqtype        => [ "Request Type", $self->medium ],
739
#     };
740
#     # Add borrower or borrowernumber.
741
#     if ( $params->{brw} ) {
742
#         $return->{borrower} = [ "Borrower", $self->patron ]
743
#     } else {
744
#         $return->{borrowernumber}
745
#             = [ "Borrower Number", $self->borrower_id ];
746
#     }
747
#     # Add ID with prefix
748
#     $return->{prefix_id} = [
749
#         "Request Number", $params->{id_prefix} . $self->illrequest_id
750
#     ];
751
#     return $return;
752
# }
753
754
# FIXME: To be handled in templates
755
# # FIXME: Missing new canonical fields!
756
# sub getFullStatus {
757
#     my ( $self, $params ) = @_;
758
759
#     my $return = {
760
#         id              => [ "Request Number", $self->illrequest_id ],
761
#         biblionumber    => [ "Biblio Number", $self->biblio_id ],
762
#         status          => [ "Status", $self->status ],
763
#         placement_date  => [ "Placement Date", $self->placed ],
764
#         ts              => [ "Timestamp", $self->updated ],
765
#         completion_date => [ "Completion Date", $self->completed ],
766
#         reqtype         => [ "Request Type", $self->medium ],
767
#         branch          => [ "Branch", $self->branch_id ],
768
#     };
769
#     # Add borrower or borrowernumber.
770
#     if ( $params->{brw} ) {
771
#         $return->{borrower} = [ "Borrower", $self->patron ]
772
#     } else {
773
#         $return->{borrowernumber}
774
#             = [ "Borrower Number", $self->borrower_id ];
775
#     }
776
#     # Add ID with prefix
777
#     $return->{prefix_id} = [
778
#         "Request Number", $params->{id_prefix} . $self->illrequest_id
779
#     ];
780
#     # Add Reply Date if it's used
781
#     $return->{reply_date} = [
782
#         $params->{display_reply_date}, $self->replied
783
#     ] if ( $params->{display_reply_date} );
784
#     return $return;
785
# }
786
787
# =head3 getFullDetails
788
789
#     my $details = $illRequest->getFullDetails;
790
#     my $details = $illRequest->getFullDetails( { brw => 1 } );
791
792
# Return a data-structure ready for JSON or other format based processing and
793
# display to the end-user.  It returns a composit of $self's Record and Status
794
# `fullDetails' methods.
795
796
# =cut
797
798
# FIXME: To be handled in templates
799
# # FIXME: Needs Record handling sorting out
800
# sub getFullDetails {
801
#     my ( $self, $params ) = @_;
802
#     $params->{id_prefix} = $self->id_prefix;
803
#     $params = $self->_censor($params);
804
#     my $record = $self->record->getFullDetails($params);
805
#     my $status = $self->getFullStatus($params);
806
#     my %summary = (%{$record}, %{$status});
807
808
#     return \%summary;
809
# }
810
811
# =head3 getForEditing
812
813
#     my $partialRequest = $illRequest->getForEditing();
814
815
# Return a data-structure ready-for-JSON-or-other-format conversion and
816
# display. The data-structure will be a hashref of 2, with the first entry
817
# consisting of a summary of the Record, and the second entry consisting of the
818
# full Status details.
819
820
# The former is for display and should not be edited by hand.  The latter can be edited.
821
822
# =cut
823
824
# FIXME: To be handled in templates
825
# # FIXME: Needs Record handling sorting out
826
# sub getForEditing {
827
#     my ( $self, $params ) = @_;
828
#     $params->{id_prefix} = $self->id_prefix;
829
#     $params = $self->_censor($params);
830
#     my $record = $self->record->getFullDetails($params);
831
#     my $status = $self->getFullStatus($params);
832
833
#     return [ $record, $status ];
834
# }
835
836
# =head3 _seed_from_manual_entry
837
838
#     my $request = $illRequest->_seed_from_manual_entry($params);
839
840
# When an API does not have any valid items for a customer, they may want to
841
# manually enter item details.  This procedure provides a way for us to create
842
# an Illrequest in Koha using fields populated via Abstract's
843
# `manual_entry_fields` method.
844
845
# =cut
846
847
# sub _seed_from_manual_entry {
848
#     my ( $self, $opts ) = @_;
849
#     $self->record($opts->{value});
850
851
#     # Our fields
852
#     $self->reqtype($opts->{"m./type"});
853
#     $self->borrowernumber($opts->{borrower});
854
#     $self->branch($opts->{branch});
855
#     $self->ts(DateTime->now);
856
#     $self->placement_date(DateTime->now);
857
#     if ( $opts->{permitted} ) {
858
#         $self->status('NEW');
859
#     } else {
860
#         $self->status('QUEUED');
861
#     }
862
863
#     # FIXME: No longer exists
864
#     # $self->save;                # save to DB.
865
866
#     return $self;
867
# }
868
869
# =head3 _seed_from_api
870
871
#     my $request = $illRequest->_seed_from_api($params);
872
873
# This seeding procedure is designed to populate an Illrequest using a search
874
# result from the API in use by Abstract.
875
876
# =cut
877
878
# sub _seed_from_api {
879
#     my ( $self, $opts ) = @_;
880
881
#     # FIXME: illcomm: We are currently creating the Record using
882
#     # spec.yaml, at the Record level.  I think it might be better to
883
#     # let the API define what values to store in Record.  Perhaps we
884
#     # still use a Spec.yaml, but make that backend defined: BLDSS
885
#     # might do, but NNCIPP might not.
886
#     #
887
#     # All that Record should care about is that we have key-value
888
#     # pairs that can dessicate and reconstitute data stored in the db.
889
#     $self->record($opts->{value});
890
891
#     # Our fields
892
#     $self->reqtype($self->record->getProperty('type'));
893
#     $self->borrowernumber($opts->{borrower});
894
#     $self->branch($opts->{branch});
895
#     $self->ts(DateTime->now);
896
#     $self->reply_date(DateTime->now);
897
#     $self->placement_date(DateTime->now);
898
#     if ( $opts->{permitted} ) {
899
#         $self->status('NEW');
900
#     } else {
901
#         $self->status('QUEUED');
902
#     }
903
904
#     # FIXME: No longer exists
905
#     # $self->save;                # save to DB.
906
907
#     return $self;
908
# }
909
910
# =head3 _seed_from_store
911
912
#     my $request = $illRequest->_seed_from_store($params);
913
914
# Read a Record from the Koha Database. Here, we simply do a db attribute /
915
# Illrequest dump and feed that dump into Record structure: column_names =>
916
# column values.
917
918
# =cut
919
920
# # FIXME: Unclear what we do here now: We already load our own values, using
921
# # ->search or ->find.  Maybe here we just need to create record?
922
923
# sub _seed_from_store {
924
#     my ( $self, $opts ) = @_;
925
926
#     my $result_set = Koha::Database->new->schema->resultset('Illrequest');
927
#     my $result = $result_set->find( $opts->{id} );
928
929
#     if ( $result ) {
930
#         my $linked = $result_set->search_related(
931
#             'ill_request_attributes', { req_id => $opts->{id} }
932
#         );
933
#         my $attributes = { $result->get_columns };
934
#         while ( my $attribute = $linked->next ) {
935
#             $attributes->{ $attribute->get_column('type') }
936
#                 = $attribute->get_column('value');
937
#         }
938
#         $attributes->{borrower} = _borrower_from_number({
939
#             number => $attributes->{borrowernumber}, strategy => 'brw'
940
#         });
941
#         # XXX: A bit Kludgy.
942
#         my $tmp = $self->_abstract->build($attributes);
943
#         $self->record($tmp->{record});
944
#         $self->status($tmp->{status});
945
#         return $self;
946
#     }
947
948
#     return 0;
949
# }
950
951
=head3 requires_moderation
952
953
    my $status = $illRequest->requires_moderation;
954
955
Return the name of the status if moderation by staff is required; or 0
956
otherwise.
957
958
=cut
959
960
sub requires_moderation {
961
    my ( $self ) = @_;
962
    my $require_moderation = {
963
        'CANCREQ' => 'CANCREQ',
964
    };
965
    return $require_moderation->{$self->status};
966
}
967
968
=head3 is_manual_request
969
970
    my $bool = $illRequest->is_manual_request;
971
972
Return 1 if this request is a manually created request, 0 if it was created
973
using the API search method.
974
975
=cut
976
977
# FIXME: Needs Record handling sorting out.  Update 18/01/17 I believe manual
978
# should be a separate backend, and thus it can be handled just like any other
979
# backend.  This should be removed once confirmed working.
980
sub is_manual_request {
981
    my ( $self ) = @_;
982
    return 1 if ( $self->record->property('manual') );
983
    return 0
984
}
985
986
=head3 place_generic_request
987
988
    my ( $result, $email ) = $illRequest->place_generic_request($params);
989
990
Create an email from $PARAMS and submit it.  If we are successful, return 1
991
and the email summary.  If not, then return 0 and the email summary.
992
993
=cut
994
995
sub place_generic_request {
996
    my ( $self, $params ) = @_;
997
998
    my $message = Koha::Email->new;
999
    $params->{to} = join("; ", @{$params->{to}});
1000
    if ( !$params->{from} || $params->{from} eq '' ) {
1001
        die "No originator for email: ", $params->{from};
1002
    }
1003
    if ( !$params->{replyto} || $params->{replyto} eq '') {
1004
        $params->{replyto} = $params->{from};
1005
    }
1006
    if ( !$params->{sender} || $params->{sender} eq '' ) {
1007
        $params->{sender} = $params->{from};
1008
    }
1009
    my %mail = $message->create_message_headers(
1010
        {
1011
            to          => $params->{to},
1012
            from        => $params->{from},
1013
            replyto     => $params->{replyto},
1014
            sender      => $params->{sender},
1015
            subject     => Encode::encode( "utf8", $params->{subject} ),
1016
            message     => Encode::encode( "utf8", $params->{message} ),
1017
            contenttype => 'text/plain; charset="utf8"',
1018
        }
1019
    );
1020
1021
    my $result = sendmail(%mail);
1022
    if ( $result ) {
1023
        # XXX: Needs store?
1024
        $self->status("GENREQ");
1025
        return (1, $params);
1026
    } else {
1027
        carp($Mail::Sendmail::error);
1028
        return (0, $params);
1029
    }
1030
1031
}
1032
1033
=head3 prepare_generic_request
1034
1035
    my $emailTemplate = $illRequest->prepare_generic_request;
1036
1037
Return a hashref containing 'subject'and 'body' for an email.
1038
1039
=cut
1040
1041
# FIXME: Needs Record handling sorting out
1042
sub prepare_generic_request {
1043
    my ( $self ) = @_;
1044
1045
1046
    my $draft->{subject} = "ILL Request";
1047
    $draft->{body} = <<EOF;
1048
Dear Sir/Madam,
1049
1050
    We would like to request an interlibrary loan for title matching the
1051
following description:
1052
1053
EOF
1054
1055
    my $details = $self->record->getFullDetails;
1056
    while (my ($key, $values) = each %{$details}) {
1057
        if (${$values}[1]) {
1058
            $draft->{body} .= "  - " . ${$values}[0]
1059
                . ": " . ${$values}[1]. "\n";
1060
        }
1061
    }
1062
1063
    $draft->{body} .= <<EOF;
1064
1065
Please let us know if you are able to supply this to us.
1066
1067
Kind Regards
1068
EOF
1069
1070
    return $draft;
1071
}
1072
1073
=head3 _borrower_from_number
1074
1075
    my $_borrower_from_number = $illRequest->_borrower_from_number();
1076
1077
Return a borrower from the given card or borrower $NUMBER.  The strategy for
1078
resolution depends on $strategy:
1079
  - 'crd' means try only cardnumber, error otherwise.
1080
  - 'brw' means try only borrowernumber, error otherwise.
1081
  - else: try both and return the first match.
1082
1083
=cut
1084
1085
sub _borrower_from_number {
1086
    my ( $params ) = @_;
1087
    my $number = $params->{number};
1088
    my $strategy = $params->{strategy};
1089
1090
    my $patrons = Koha::Patrons->new;
1091
    my $brws;
1092
    if ( $strategy && 'crd' eq $strategy ) {
1093
        $brws = $patrons->search( { cardnumber => $number } );
1094
    } elsif ( $strategy && 'brw' eq $strategy ) {
1095
        $brws = $patrons->search( { borrowernumber => $number } );
1096
    } else {
1097
        $brws = $patrons->search( { borrowernumber => $number } );
1098
        $brws = $patrons->search( { cardnumber => $number } )
1099
            unless ( $brws->count == 1 );
1100
    }
1101
1102
    # we should have a unique brw.
1103
    die "Invalid borrower" if ( $brws->count > 1 );
1104
1105
    # Check if borrower still exists / has not been deleted.
1106
    if ( $brws->count == 0 ) {
1107
        die "Invalid borrower" if ( $params->{required} );
1108
        # We allow "deleted" borrowers.
1109
        return { type => "borrower", deleted => 1 };
1110
    }
1111
    return $brws->next;
1112
}
1113
1114
=head3 id_prefix
1115
1116
    my $prefix = $record->id_prefix;
1117
1118
Return the prefix appropriate for the current Illrequest as derived from the
1119
borrower and branch associated with this request's Status, and the config
1120
file.
1121
1122
=cut
1123
1124
sub id_prefix {
1125
    my ( $self ) = @_;
1126
    # FIXME: can we automatically use borrowernumber as borrower?
1127
    my $brw = $self->patron;
1128
    my $brw_cat = "dummy";
1129
    $brw_cat = $brw->categorycode
1130
        unless ( 'HASH' eq ref($brw) && $brw->{deleted} );
1131
    my $prefix = $self->getPrefix( {
1132
        brw_cat => $brw_cat,
1133
        branch  => $self->branchcode,
1134
    } );
1135
    $prefix .= "-" if ( $prefix );
1136
    return $prefix;
1137
}
1138
1139
=head3 _censor
1140
1141
    my $params = $illRequest->_censor($params);
1142
1143
Return $params, modified to reflect our censorship requirements.
1144
1145
=cut
1146
1147
sub _censor {
1148
    my ( $self, $params ) = @_;
1149
    $params->{censor_notes_staff} = $self->getCensorNotesStaff
1150
        if ( $params->{opac} );
1151
    $params->{display_reply_date} = $self->getDisplayReplyDate;
1152
1153
    return $params;
1154
}
1155
1156
=head1 AUTHOR
1157
1158
Alex Sassmannshausen <alex.sassmannshausen@ptfs-europe.com>
1159
1160
=cut
1161
1162
1;
(-)a/Koha/Illrequest/Backend/Dummy/Base.pm (+576 lines)
Line 0 Link Here
1
package Koha::Illrequest::Backend::Dummy::Base;
2
3
# Copyright PTFS Europe 2014
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
use DateTime;
22
use Koha::Illrequestattribute;
23
24
=head1 NAME
25
26
Koha::Illrequest::Backend::Dummy - Koha ILL Backend: Dummy
27
28
=head1 SYNOPSIS
29
30
Koha ILL implementation for the "Dummy" backend.
31
32
=head1 DESCRIPTION
33
34
=head2 Overview
35
36
We will be providing the Abstract interface which requires we implement the
37
following methods:
38
- create        -> initial placement of the request for an ILL order
39
- confirm       -> confirm placement of the ILL order
40
- list          -> list all ILL Requests currently placed with the backend
41
- renew         -> request a currently borrowed ILL be renewed in the backend
42
- update_status -> ILL module update hook: custom actions on status update
43
- cancel        -> request an already 'confirm'ed ILL order be cancelled
44
- status        -> request the current status of a confirmed ILL order
45
46
Each of the above methods will receive the following parameter from
47
Illrequest.pm:
48
49
  {
50
      request    => $request,
51
      other      => $other,
52
  }
53
54
where:
55
56
- $REQUEST is the Illrequest object in Koha.  It's associated
57
  Illrequestattributes can be accessed through the `illrequestattributes`
58
  method.
59
- $OTHER is any further data, generally provided through templates .INCs
60
61
Each of the above methods should return a hashref of the following format:
62
63
    return {
64
        error   => 0,
65
        # ^------- 0|1 to indicate an error
66
        status  => 'result_code',
67
        # ^------- Summary of the result of the operation
68
        message => 'Human readable message.',
69
        # ^------- Message, possibly to be displayed
70
        #          Normally messages are derived from status in INCLUDE.
71
        #          But can be used to pass API messages to the INCLUDE.
72
        method  => 'list',
73
        # ^------- Name of the current method invoked.
74
        #          Used to load the appropriate INCLUDE.
75
        stage   => 'commit',
76
        # ^------- The current stage of this method
77
        #          Used by INCLUDE to determine HTML to generate.
78
        #          'commit' will result in final processing by Illrequest.pm.
79
        next    => 'illview'|'illlist',
80
        # ^------- When stage is 'commit', should we move on to ILLVIEW the
81
        #          current request or ILLLIST all requests.
82
        value   => {},
83
        # ^------- A hashref containing an arbitrary return value that this
84
        #          backend wants to supply to its INCLUDE.
85
    };
86
87
=head2 On the Dummy backend
88
89
The Dummy backend is rather simple, but provides correctly formatted response
90
values, that other backends can model themselves after.
91
92
The code is not DRY -- primarily so that each method can be looked at in
93
isolation rather than having to familiarise oneself with helper procedures.
94
95
=head1 API
96
97
=head2 Class Methods
98
99
=cut
100
101
=head3 new
102
103
  my $backend = Koha::Illrequest::Backend::Dummy->new;
104
105
=cut
106
107
sub new {
108
    # -> instantiate the backend
109
    my ( $class ) = @_;
110
    my $self = {};
111
    bless( $self, $class );
112
    return $self;
113
}
114
115
=head3 _data_store
116
117
  my $request = $self->_data_store($id);
118
  my $requests = $self->_data_store;
119
120
A mock of a data store.  When passed no parameters it returns all entries.
121
When passed one it will return the entry matched by its id.
122
123
=cut
124
125
sub _data_store {
126
    my $data = {
127
        1234 => {
128
            id     => 1234,
129
            title  => "Ordering ILLs using Koha",
130
            author => "A.N. Other",
131
        },
132
        5678 => {
133
            id     => 5678,
134
            title  => "Interlibrary loans in Koha",
135
            author => "A.N. Other",
136
        },
137
    };
138
    # ID search
139
    my ( $self, $id ) = @_;
140
    return $data->{$id} if $id;
141
142
    # Full search
143
    my @entries;
144
    while ( my ( $k, $v ) = each %{$data} ) {
145
        push @entries, $v;
146
    }
147
    return \@entries;
148
}
149
150
=head3 create
151
152
  my $response = $backend->create({
153
      request    => $requestdetails,
154
      other      => $other,
155
  });
156
157
This is the initial creation of the request.  Generally this stage will be
158
some form of search with the backend.
159
160
By and large we will not have useful $requestdetails (borrowernumber,
161
branchcode, status, etc.).
162
163
$params is simply an additional slot for any further arbitrary values to pass
164
to the backend.
165
166
This is an example of a multi-stage method.
167
168
=cut
169
170
sub create {
171
    # -> initial placement of the request for an ILL order
172
    my ( $self, $params ) = @_;
173
    my $stage = $params->{other}->{stage};
174
    if ( !$stage || $stage eq 'init' ) {
175
        # We simply need our template .INC to produce a search form.
176
        return {
177
            error   => 0,
178
            status  => '',
179
            message => '',
180
            method  => 'create',
181
            stage   => 'search_form',
182
            value   => {},
183
        };
184
    } elsif ( $stage eq 'search_form' ) {
185
	# Received search query in 'other'; perform search...
186
187
        # No-op on Dummy
188
189
        # and return results.
190
        return {
191
            error   => 0,
192
            status  => '',
193
            message => '',
194
            method  => 'create',
195
            stage   => 'search_results',
196
            value   => {
197
                borrowernumber => $params->{other}->{borrowernumber},
198
                branchcode     => $params->{other}->{branchcode},
199
                medium         => $params->{other}->{medium},
200
                candidates     => $self->_data_store,
201
            }
202
        };
203
    } elsif ( $stage eq 'search_results' ) {
204
        # We have a selection
205
        my $id = $params->{other}->{id};
206
207
        # -> select from backend...
208
        my $request_details = $self->_data_store($id);
209
210
        # ...Populate Illrequest
211
        my $request = $params->{request};
212
        $request->borrower_id($params->{other}->{borrowernumber});
213
        $request->branch_id($params->{other}->{branchcode});
214
        $request->medium($params->{other}->{medium});
215
        $request->status('NEW');
216
        $request->placed(DateTime->now);
217
        $request->updated(DateTime->now);
218
        $request->store;
219
        # ...Populate Illrequestattributes
220
        while ( my ( $type, $value ) = each %{$request_details} ) {
221
            Koha::Illrequestattribute->new({
222
                illrequest_id => $request->illrequest_id,
223
                type          => $type,
224
                value         => $value,
225
            })->store;
226
        }
227
228
        # -> create response.
229
        return {
230
            error   => 0,
231
            status  => '',
232
            message => '',
233
            method  => 'create',
234
            stage   => 'commit',
235
            next    => 'illview',
236
            value   => $request_details,
237
        };
238
    } else {
239
	# Invalid stage, return error.
240
        return {
241
            error   => 1,
242
            status  => 'unknown_stage',
243
            message => '',
244
            method  => 'create',
245
            stage   => $params->{stage},
246
            value   => {},
247
        };
248
    }
249
}
250
251
=head3 confirm
252
253
  my $response = $backend->confirm({
254
      request    => $requestdetails,
255
      other      => $other,
256
  });
257
258
Confirm the placement of the previously "selected" request (by using the
259
'create' method).
260
261
In this case we will generally use $request.
262
This will be supplied at all times through Illrequest.  $other may be supplied
263
using templates.
264
265
=cut
266
267
sub confirm {
268
    # -> confirm placement of the ILL order
269
    my ( $self, $params ) = @_;
270
    # Turn Illrequestattributes into a plain hashref
271
    my $value = {};
272
    my $attributes = $params->{request}->illrequestattributes;
273
    foreach my $attr (@{$attributes->as_list}) {
274
        $value->{$attr->type} = $attr->value;
275
    };
276
    # Submit request to backend...
277
278
    # No-op for Dummy
279
280
    # ...parse response...
281
    $attributes->find_or_create({ type => "status", value => "On order" });
282
    my $request = $params->{request};
283
    $request->cost("30 GBP");
284
    $request->orderid($value->{id});
285
    $request->status("REQ");
286
    $request->accessurl("URL") if $value->{url};
287
    $request->store;
288
    $value->{status} = "On order";
289
    $value->{cost} = "30 GBP";
290
    # ...then return our result:
291
    return {
292
        error    => 0,
293
        status   => '',
294
        message  => '',
295
        method   => 'confirm',
296
        stage    => 'commit',
297
        next     => 'illview',
298
        value    => $value,
299
    };
300
}
301
302
=head3 list
303
304
  my $response = $backend->list({
305
      request    => $requestdetails,
306
      other      => $other,
307
  };
308
309
Attempt to get a list of the currently registered requests with the backend.
310
311
Parameters are optional for this request.  A backend may be supplied with
312
details of a specific request (or a group of requests in $other), but equally
313
no parameters might be provided at all.
314
315
Normally no parameters will be provided in the 'create' stage.  After this,
316
parameters may be provided using templates.
317
318
=cut
319
320
sub list {
321
    # -> list all ILL Requests currently placed with the backend
322
    #    (we ignore all params provided)
323
    my ( $self, $params ) = @_;
324
    my $stage = $params->{other}->{stage};
325
    if ( !$stage || $stage eq 'init' ) {
326
        return {
327
            error   => 0,
328
            status  => '',
329
            message => '',
330
            method  => 'list',
331
            stage   => 'list',
332
            value   => {
333
                1 => {
334
                    id     => 1234,
335
                    title  => "Ordering ILLs using Koha",
336
                    author => "A.N. Other",
337
                    status => "On order",
338
                    cost   => "30 GBP",
339
                },
340
            },
341
        };
342
    } elsif ( $stage eq 'list' ) {
343
        return {
344
            error   => 0,
345
            status  => '',
346
            message => '',
347
            method  => 'list',
348
            stage   => 'commit',
349
            value   => {},
350
        };
351
    } else {
352
        # Invalid stage, return error.
353
        return {
354
            error   => 1,
355
            status  => 'unknown_stage',
356
            message => '',
357
            method  => 'create',
358
            stage   => $params->{stage},
359
            value   => {},
360
        };
361
    }
362
}
363
364
=head3 renew
365
366
  my $response = $backend->renew({
367
      request    => $requestdetails,
368
      other      => $other,
369
  });
370
371
Attempt to renew a request that was supplied through backend and is currently
372
in use by us.
373
374
We will generally use $request.  This will be supplied at all times through
375
Illrequest.  $other may be supplied using templates.
376
377
=cut
378
379
sub renew {
380
    # -> request a currently borrowed ILL be renewed in the backend
381
    my ( $self, $params ) = @_;
382
    # Turn Illrequestattributes into a plain hashref
383
    my $value = {};
384
    my $attributes = $params->{request}->illrequestattributes;
385
    foreach my $attr (@{$attributes->as_list}) {
386
        $value->{$attr->type} = $attr->value;
387
    };
388
    # Submit request to backend, parse response...
389
    my ( $error, $status, $message ) = ( 0, '', '' );
390
    if ( !$value->{status} || $value->{status} eq 'On order' ) {
391
        $error = 1;
392
        $status = 'not_renewed';
393
        $message = 'Order not yet delivered.';
394
    } else {
395
        $value->{status} = "Renewed";
396
    }
397
    # ...then return our result:
398
    return {
399
        error   => $error,
400
        status  => $status,
401
        message => $message,
402
        method  => 'renew',
403
        stage   => 'commit',
404
        value   => $value,
405
    };
406
}
407
408
=head3 update_status
409
410
  my $response = $backend->update_status({
411
      request    => $requestdetails,
412
      other      => $other,
413
  });
414
415
Our Illmodule is handling a request to update the status of an Illrequest.  As
416
part of this we give the backend an opportunity to perform arbitrary actions
417
on update to a new status.
418
419
We will provide $request.  This will be supplied at all times through
420
Illrequest.  $other will contain entries for the old status and the new
421
status, as well as other information provided from templates.
422
423
$old_status, $new_status.
424
425
=cut
426
427
sub update_status {
428
    # -> ILL module update hook: custom actions on status update
429
    my ( $self, $params ) = @_;
430
    # Turn Illrequestattributes into a plain hashref
431
    my $value = {};
432
    my $attributes = $params->{request}->illrequestattributes;
433
    foreach my $attr (@{$attributes->as_list}) {
434
        $value->{$attr->type} = $attr->value;
435
    };
436
    # Submit request to backend, parse response...
437
    my ( $error, $status, $message ) = (0, '', '');
438
    my $old = $params->{other}->{old_status};
439
    my $new = $params->{other}->{new_status};
440
    if ( !$new || $new eq 'ERR' ) {
441
        ( $error, $status, $message ) = (
442
            1, 'failed_update_hook',
443
            'Fake reason for failing to perform update operation.'
444
        );
445
    }
446
    return {
447
        error   => $error,
448
        status  => $status,
449
        message => $message,
450
        method  => 'update_status',
451
        stage   => 'commit',
452
        value   => $value,
453
    };
454
}
455
456
=head3 cancel
457
458
  my $response = $backend->cancel({
459
      request    => $requestdetails,
460
      other      => $other,
461
  });
462
463
We will attempt to cancel a request that was confirmed.
464
465
We will generally use $request.  This will be supplied at all times through
466
Illrequest.  $other may be supplied using templates.
467
468
=cut
469
470
sub cancel {
471
    # -> request an already 'confirm'ed ILL order be cancelled
472
    my ( $self, $params ) = @_;
473
    # Turn Illrequestattributes into a plain hashref
474
    my $value = {};
475
    my $attributes = $params->{request}->illrequestattributes;
476
    foreach my $attr (@{$attributes->as_list}) {
477
        $value->{$attr->type} = $attr->value;
478
    };
479
    # Submit request to backend, parse response...
480
    my ( $error, $status, $message ) = (0, '', '');
481
    if ( !$value->{status} ) {
482
        ( $error, $status, $message ) = (
483
            1, 'unknown_request', 'Cannot cancel an unknown request.'
484
        );
485
    } else {
486
        $attributes->find({ type => "status" })->delete;
487
        $params->{request}->status("REQREV");
488
        $params->{request}->cost(undef);
489
        $params->{request}->orderid(undef);
490
        $params->{request}->store;
491
    }
492
    return {
493
        error   => $error,
494
        status  => $status,
495
        message => $message,
496
        method  => 'cancel',
497
        stage   => 'commit',
498
        value   => $value,
499
    };
500
}
501
502
=head3 status
503
504
  my $response = $backend->create({
505
      request    => $requestdetails,
506
      other      => $other,
507
  });
508
509
We will try to retrieve the status of a specific request.
510
511
We will generally use $request.  This will be supplied at all times through
512
Illrequest.  $other may be supplied using templates.
513
514
=cut
515
516
sub status {
517
    # -> request the current status of a confirmed ILL order
518
    my ( $self, $params ) = @_;
519
    my $value = {};
520
    my $stage = $params->{other}->{stage};
521
    my ( $error, $status, $message ) = (0, '', '');
522
    if ( !$stage || $stage eq 'init' ) {
523
        # Generate status result
524
        # Turn Illrequestattributes into a plain hashref
525
        my $attributes = $params->{request}->illrequestattributes;
526
        foreach my $attr (@{$attributes->as_list}) {
527
            $value->{$attr->type} = $attr->value;
528
        }
529
        ;
530
        # Submit request to backend, parse response...
531
        if ( !$value->{status} ) {
532
            ( $error, $status, $message ) = (
533
                1, 'unknown_request', 'Cannot query status of an unknown request.'
534
            );
535
        }
536
        return {
537
            error   => $error,
538
            status  => $status,
539
            message => $message,
540
            method  => 'status',
541
            stage   => 'status',
542
            value   => $value,
543
        };
544
545
    } elsif ( $stage eq 'status') {
546
        # No more to do for method.  Return to illlist.
547
        return {
548
            error   => $error,
549
            status  => $status,
550
            message => $message,
551
            method  => 'status',
552
            stage   => 'commit',
553
            next    => 'illlist',
554
            value   => {},
555
        };
556
557
    } else {
558
        # Invalid stage, return error.
559
        return {
560
            error   => 1,
561
            status  => 'unknown_stage',
562
            message => '',
563
            method  => 'create',
564
            stage   => $params->{stage},
565
            value   => {},
566
        };
567
    }
568
}
569
570
=head1 AUTHOR
571
572
Alex Sassmannshausen <alex.sassmannshausen@ptfs-europe.com>
573
574
=cut
575
576
1;
(-)a/Koha/Illrequest/Config.pm (+516 lines)
Line 0 Link Here
1
package Koha::Illrequest::Config;
2
3
# Copyright 2013,2014 PTFS Europe Ltd
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
use C4::Context;
22
23
=head1 NAME
24
25
Koha::Illrequest::Config - Koha ILL Configuration Object
26
27
=head1 SYNOPSIS
28
29
Object-oriented class that giving access to the illconfig data derived
30
from ill/config.yaml.
31
32
=head1 DESCRIPTION
33
34
Config object providing abstract representation of the expected XML
35
returned by ILL API.
36
37
In particular the config object uses a YAML file, whose path is
38
defined by <illconfig> in koha-conf.xml. That YAML file provides the
39
data structure exposed in this object.
40
41
By default the configured data structure complies with fields used by
42
the British Library Interlibrary Loan DSS API.
43
44
The config file also provides mappings for Record Object accessors.
45
46
FIXME: illcomm: In general Config should be split into two parts:
47
those that are high-level and those that are backend specific.  The
48
latter should not get specific accessors, but rather a generic
49
accessor, that takes a setting name as string parameter.
50
51
=head1 API
52
53
=head2 Class Methods
54
55
=head3 new
56
57
    my $config = Koha::Illrequest::Config->new();
58
59
Create a new Koha::Illrequest::Config object, with mapping data loaded from the
60
ILL configuration file.
61
62
=cut
63
64
sub new {
65
    my ( $class, $test ) = @_;
66
    my $self  = {};
67
68
    $self->{configuration} = _load_configuration(
69
        C4::Context->config("interlibrary_loans"),
70
        C4::Context->preference("UnmediatedILL")
71
      ) unless ( $test );
72
73
    bless $self, $class;
74
75
    return $self;
76
}
77
78
=head3 backend
79
80
    $backend = $config->backend($name);
81
    $backend = $config->backend;
82
83
Standard setter/accessor for our backend.
84
85
=cut
86
87
sub backend {
88
    my ( $self, $new ) = @_;
89
    $self->{configuration}->{backend} = $new if $new;
90
    return $self->{configuration}->{backend};
91
}
92
93
=head3 backend_dir
94
95
    $backend_dir = $config->backend_dir($new_path);
96
    $backend_dir = $config->backend_dir;
97
98
Standard setter/accessor for our backend_directory.
99
100
=cut
101
102
sub backend_dir {
103
    my ( $self, $new ) = @_;
104
    $self->{configuration}->{backend_directory} = $new if $new;
105
    return $self->{configuration}->{backend_directory};
106
}
107
108
=head3 limits
109
110
    $limits = $config->limits($limitshash);
111
    $limits = $config->limits;
112
113
Standard setter/accessor for our limits.  No parsing is performed on
114
$LIMITSHASH, so caution should be exercised when using this setter.
115
116
=cut
117
118
sub limits {
119
    my ( $self, $new ) = @_;
120
    $self->{configuration}->{limits} = $new if $new;
121
    return $self->{configuration}->{limits};
122
}
123
124
=head3 getPrefixes
125
126
    my $prefixes = $config->getPrefixes('brw_cat' | 'branch');
127
128
Return the prefix for ILLs defined by our config.
129
130
=cut
131
132
sub getPrefixes {
133
    my ( $self, $type ) = @_;
134
    die "Unexpected type." unless ( $type eq 'brw_cat' || $type eq 'branch' );
135
    my $values = $self->{configuration}->{prefixes}->{$type};
136
    $values->{default} = $self->{configuration}->{prefixes}->{default};
137
    return $values;
138
}
139
140
=head3 getLibraryPrivileges
141
142
    my $privileges= $config->getLibraryPrivileges;
143
144
Return the LibraryPrivilege definitions defined by our config.
145
146
=cut
147
148
sub getLibraryPrivileges {
149
    my ( $self ) = @_;
150
    my $values= $self->{configuration}->{library_privileges}->{branch} || {};
151
    $values->{default} =
152
        $self->{configuration}->{library_privileges}->{default};
153
    return $values;
154
}
155
156
=head3 getLimitRules
157
158
    my $rules = $config->getLimitRules('brw_cat' | 'branch')
159
160
Return the hash of ILL limit rules defined by our config.
161
162
=cut
163
164
sub getLimitRules {
165
    my ( $self, $type ) = @_;
166
    die "Unexpected type." unless ( $type eq 'brw_cat' || $type eq 'branch' );
167
    my $values = $self->{configuration}->{limits}->{$type};
168
    $values->{default} = $self->{configuration}->{limits}->{default};
169
    return $values;
170
}
171
172
=head3 getDigitalRecipients
173
174
    my $recipient_rules= $config->getDigitalRecipients('brw_cat' | 'branch');
175
176
Return the hash of digital_recipient settings defined by our config.
177
178
=cut
179
180
sub getDigitalRecipients {
181
    my ( $self, $type ) = @_;
182
    die "Unexpected type." unless ( $type eq 'brw_cat' || $type eq 'branch' );
183
    my $values = $self->{configuration}->{digital_recipients}->{$type};
184
    $values->{default} =
185
        $self->{configuration}->{digital_recipients}->{default};
186
    return $values;
187
}
188
189
=head3 getDefaultFormats
190
191
    my $defaultFormat = $config->getLimitRules('brw_cat' | 'branch')
192
193
Return the hash of ILL default formats defined by our config.
194
195
=cut
196
197
sub getDefaultFormats {
198
    my ( $self, $type ) = @_;
199
    die "Unexpected type." unless ( $type eq 'brw_cat' || $type eq 'branch' );
200
    my $values = $self->{configuration}->{default_formats}->{$type};
201
    $values->{default} = $self->{configuration}->{default_formats}->{default};
202
    return $values;
203
}
204
205
=head3 getCredentials
206
207
    my $credentials = $config->getCredentials($branchCode);
208
209
Fetch the best-fit credentials: if we have credentials for $branchCode, use
210
those; otherwise fall back on default credentials.  If neither can be found,
211
simply populate application details, and populate key details with 0.
212
213
=cut
214
215
sub getCredentials {
216
    my ( $self, $branchCode ) = @_;
217
    my $creds = $self->{configuration}->{credentials}
218
        || die "We have no credentials defined.  Please check koha-conf.xml.";
219
220
    my $exact = { api_key => 0, api_auth => 0 };
221
    if ( $branchCode && $creds->{api_keys}->{$branchCode} ) {
222
        $exact = $creds->{api_keys}->{$branchCode}
223
    } elsif ( $creds->{api_keys}->{default} ) {
224
        $exact = $creds->{api_keys}->{default};
225
    }
226
227
    return {
228
        api_key              => $exact->{api_key},
229
        api_key_auth         => $exact->{api_auth},
230
        api_application      => $creds->{api_application}->{key},
231
        api_application_auth => $creds->{api_application}->{auth},
232
    };
233
}
234
235
=head3 censorship
236
237
    my $censoredValues = $config->censorship($hash);
238
    my $censoredValues = $config->censorship;
239
240
Standard setter/accessor for our limits.  No parsing is performed on $HASH, so
241
caution should be exercised when using this setter.
242
243
Return our censorship values for the OPAC as loaded from the koha-conf.xml, or
244
the fallback value (no censorship).
245
246
=cut
247
248
sub censorship {
249
    my ( $self, $new ) = @_;
250
    $self->{configuration}->{censorship} = $new if $new;
251
    return $self->{configuration}->{censorship};
252
}
253
254
=head3 getApiUrl
255
256
    my $api_url = $config->getApiUrl;
257
258
Return the url for the api configured by koha-conf.xml, or the fall-back url.
259
260
=cut
261
262
sub getApiUrl {
263
    my ( $self ) = @_;
264
    return $self->{configuration}->{api_url};
265
}
266
267
=head3 getApiSpecFile
268
269
    my $api_spec_file = $config->getApiSpecFile;
270
271
Return the path pointing to the API specfile, if it indeed exists, from by
272
koha-conf.xml, or 0.
273
274
=cut
275
276
sub getApiSpecFile {
277
    my ( $self ) = @_;
278
    return $self->{configuration}->{spec_file} || 0;
279
}
280
281
=head3 _load_configuration
282
283
    my $configuration = $config->_load_configuration($config_from_xml);
284
285
Read the configuration values passed as the parameter, and populate a hashref
286
suitable for use with these.
287
288
A key task performed here is the parsing of the input in the configuration
289
file to ensure we have only valid input there.
290
291
=cut
292
293
sub _load_configuration {
294
    my ( $from_xml, $unmediated ) = @_;
295
    my $xml_config  = $from_xml->{configuration};
296
    my $xml_api_url = $from_xml->{api_url};
297
    my $xml_backend_dir = $from_xml->{backend_directory};
298
299
    # Input validation
300
    die "CONFIGURATION has not been defined in koha-conf.xml."
301
        unless ( ref($xml_config) eq "HASH" );
302
    die "APPLICATION has not been defined in koha-conf.xml."
303
        unless ( ref($from_xml->{application}) eq "HASH" );
304
305
    # Default data structure to be returned
306
    my $configuration = {
307
        backend_directory  => $xml_backend_dir,
308
        api_url            => $xml_api_url || 'http://apitest.bldss.bl.uk',
309
        spec_file          => $from_xml->{api_specification},
310
        censorship         => {
311
            censor_notes_staff => 0,
312
            censor_reply_date => 0,
313
        },
314
        credentials        => {
315
            api_application => {},
316
            api_keys        => {},
317
        },
318
        library_privileges => {},
319
        limits             => {},
320
        default_formats    => {},
321
        digital_recipients => {},
322
        prefixes           => {},
323
    };
324
325
    # Per Branch Configuration
326
    my $branches = $xml_config->{branch};
327
    if ( ref($branches) eq "ARRAY" ) {
328
        # Multiple branch overrides defined
329
        map {
330
            _load_unit_config({
331
                unit   => $_,
332
                id     => $_->{code},
333
                config => $configuration,
334
                type   => 'branch'
335
            })
336
        } @{$branches};
337
    } elsif ( ref($branches) eq "HASH" ) {
338
        # Single branch override defined
339
        _load_unit_config({
340
            unit   => $branches,
341
            id     => $branches->{code},
342
            config => $configuration,
343
            type   => 'branch'
344
        });
345
    }
346
347
    # Per Borrower Category Configuration
348
    my $brw_cats = $xml_config->{borrower_category};
349
    if ( ref($brw_cats) eq "ARRAY" ) {
350
        # Multiple borrower category overrides defined
351
        map {
352
            _load_unit_config({
353
                unit   => $_,
354
                id     => $_->{code},
355
                config => $configuration,
356
                type   => 'brw_cat'
357
            })
358
        } @{$brw_cats};
359
    } elsif ( ref($brw_cats) eq "HASH" ) {
360
        # Single branch override defined
361
        _load_unit_config({
362
            unit   => $brw_cats,
363
            id     => $brw_cats->{code},
364
            config => $configuration,
365
            type   => 'brw_cat'
366
        });
367
    }
368
369
    # Default Configuration
370
    _load_unit_config({
371
        unit   => $xml_config,
372
        id     => 'default',
373
        config => $configuration
374
    });
375
376
    # Application key & auth
377
    $configuration->{credentials}->{api_application}  = {
378
        key  => $from_xml->{application}->{key},
379
        auth => $from_xml->{application}->{auth},
380
    };
381
382
    # Censorship
383
    my $staff_comments = $from_xml->{staff_request_comments};
384
    $configuration->{censorship}->{censor_notes_staff} = 1
385
        if ( $staff_comments && 'hide' eq $staff_comments );
386
    my $reply_date = $from_xml->{reply_date};
387
    if ( 'hide' eq $reply_date ) {
388
        $configuration->{censorship}->{censor_reply_date} = 1;
389
    } else {
390
        $configuration->{censorship}->{censor_reply_date} = $reply_date;
391
    }
392
393
    die "No DEFAULT_FORMATS has been defined in koha-conf.xml, but UNMEDIATEDILL is active."
394
        if ( $unmediated && !$configuration->{default_formats}->{default} );
395
396
    return $configuration;
397
}
398
399
=head3 _load_unit_config
400
401
    my $configuration->{part} = _load_unit_config($params);
402
403
$PARAMS is a hashref with the following elements:
404
- unit: the part of the configuration we are parsing.
405
- id: the name within which we will store the parsed unit in config.
406
- config: the configuration we are augmenting.
407
- type: the type config unit we are parsing.  Assumed to be 'default'.
408
409
Read `unit', and augment `config' with these under `id'.
410
411
This is a helper for _load_configuration.
412
413
A key task performed here is the parsing of the input in the configuration
414
file to ensure we have only valid input there.
415
416
=cut
417
418
sub _load_unit_config {
419
    my ( $params ) = @_;
420
    my $unit = $params->{unit};
421
    my $id = $params->{id};
422
    my $config = $params->{config};
423
    my $type = $params->{type};
424
    return $config unless $id;
425
426
    if ( $unit->{api_key} && $unit->{api_auth} ) {
427
        $config->{credentials}->{api_keys}->{$id} = {
428
            api_key  => $unit->{api_key},
429
            api_auth => $unit->{api_auth},
430
        };
431
    }
432
    # Add request_limit rules.
433
    # METHOD := 'annual' || 'active'
434
    # COUNT  := x >= -1
435
    if ( ref $unit->{request_limit} eq 'HASH' ) {
436
        my $method  = $unit->{request_limit}->{method};
437
        my $count = $unit->{request_limit}->{count};
438
        if ( 'default' eq $id ) {
439
            $config->{limits}->{$id}->{method}  = $method
440
                if ( $method && ( 'annual' eq $method || 'active' eq $method ) );
441
            $config->{limits}->{$id}->{count} = $count
442
                if ( $count && ( -1 <= $count ) );
443
        } else {
444
            $config->{limits}->{$type}->{$id}->{method}  = $method
445
                if ( $method && ( 'annual' eq $method || 'active' eq $method ) );
446
            $config->{limits}->{$type}->{$id}->{count} = $count
447
                if ( $count && ( -1 <= $count ) );
448
        }
449
    }
450
451
    # Add library_privilege rules (only per branch).
452
    # LIBRARY_PRIVILEGE := 1 || 0
453
    unless ( $type && 'brw_cat' eq $type ) {
454
        if ( $unit->{library_privilege} ) {
455
            if ( 'default' eq $id ) {
456
                $config->{library_privileges}->{$id} =
457
                    $unit->{library_privilege};
458
            } else {
459
                $config->{library_privileges}->{branch}->{$id} =
460
                    $unit->{library_privilege};
461
            }
462
        }
463
    }
464
465
    # Add prefix rules.
466
    # PREFIX := string
467
    if ( $unit->{prefix} ) {
468
        if ( 'default' eq $id ) {
469
            $config->{prefixes}->{$id} = $unit->{prefix};
470
        } else {
471
            $config->{prefixes}->{$type}->{$id} = $unit->{prefix};
472
        }
473
    }
474
475
    # Add digital_recipient rules.
476
    # DIGITAL_RECIPIENT := borrower || branch (defaults to borrower)
477
    if ( $unit->{digital_recipient} ) {
478
        if ( 'default' eq $id ) {
479
            $config->{digital_recipients}->{$id} = $unit->{digital_recipient};
480
        } else {
481
            $config->{digital_recipients}->{$type}->{$id} =
482
                $unit->{digital_recipient};
483
        }
484
    }
485
486
    # Add default_formats types.
487
    # FORMAT && QUALITY && QUANTITY && SERVICE && SPEED := x >= 0
488
    if ( ref $unit->{default_formats} eq 'HASH' ) {
489
        my @fields = qw(format quality quantity service speed);
490
        if ( 'default' eq $id ) {
491
            for ( @fields ) {
492
                my $val = $unit->{default_formats}->{$_};
493
                die "Invalid default_formats: '$_' missing"
494
                    unless $val;
495
                $config->{default_formats}->{$id}->{$_} = $val;
496
            }
497
        } else {
498
            for ( @fields ) {
499
                my $val = $unit->{default_formats}->{$_};
500
                die "Invalid default_formats: '$_' missing"
501
                    unless $val;
502
                $config->{default_formats}->{$type}->{$id}->{$_} = $val;
503
            }
504
        }
505
    }
506
507
    return $config;
508
}
509
510
=head1 AUTHOR
511
512
Alex Sassmannshausen <alex.sassmannshausen@ptfs-europe.com>
513
514
=cut
515
516
1;
(-)a/Koha/Illrequestattribute.pm (+51 lines)
Line 0 Link Here
1
package Koha::Illrequestattribute;
2
3
# Copyright PTFS Europe 2016
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
15
# details.
16
#
17
# You should have received a copy of the GNU General Public License along with
18
# Koha; if not, write to the Free Software Foundation, Inc., 51 Franklin
19
# Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21
use Modern::Perl;
22
23
use Koha::Database;
24
25
use base qw(Koha::Object);
26
27
=head1 NAME
28
29
Koha::Illrequestattribute - Koha Illrequestattribute Object class
30
31
=head1 API
32
33
=head2 Class Methods
34
35
=cut
36
37
=head3 type
38
39
=cut
40
41
sub _type {
42
    return 'Illrequestattribute';
43
}
44
45
=head1 AUTHOR
46
47
Alex Sassmannshausen <alex.sassmannshausen@ptfs-europe.com>
48
49
=cut
50
51
1;
(-)a/Koha/Illrequestattributes.pm (+55 lines)
Line 0 Link Here
1
package Koha::Illrequestattributes;
2
3
# Copyright PTFS Europe 2016
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
22
use Koha::Database;
23
use Koha::Illrequestattribute;
24
25
use base qw(Koha::Objects);
26
27
=head1 NAME
28
29
Koha::Illrequestattributes - Koha Illrequestattributes Object class
30
31
=head1 API
32
33
=head2 Class Methods
34
35
=cut
36
37
=head3 type
38
39
=cut
40
41
sub _type {
42
    return 'Illrequestattribute';
43
}
44
45
sub object_class {
46
    return 'Koha::Illrequestattribute';
47
}
48
49
=head1 AUTHOR
50
51
Alex Sassmannshausen <alex.sassmannshausen@ptfs-europe.com>
52
53
=cut
54
55
1;
(-)a/Koha/Illrequests.pm (+99 lines)
Line 0 Link Here
1
package Koha::Illrequests;
2
3
# Copyright PTFS Europe 2016
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
22
use Koha::Database;
23
use Koha::Illrequest;
24
use Koha::Illrequest::Config;
25
26
use base qw(Koha::Objects);
27
28
=head1 NAME
29
30
Koha::Illrequests - Koha Illrequests Object class
31
32
=head1 API
33
34
=head2 Class Methods
35
36
=cut
37
38
=head3 type
39
40
=cut
41
42
sub _type {
43
    return 'Illrequest';
44
}
45
46
sub object_class {
47
    return 'Koha::Illrequest';
48
}
49
50
##### To be implemented Facade
51
52
=head3 new
53
54
    my $illRequests = Koha::Illrequests->new();
55
56
Create an ILLREQUESTS object, a singleton through which we can interact with
57
ILLREQUEST objects stored in the database or search for ILL candidates at API
58
backends.
59
60
=cut
61
62
sub new {
63
    my ( $class, $attributes ) = @_;
64
65
    my $self = $class->SUPER::new($class, $attributes);
66
67
    # FIXME: Unless we can inject config into Illrequest objects, strip this
68
    # out.
69
    my $config = Koha::Illrequest::Config->new; # <- Necessary
70
    $self->{_config} = $config;                 # <- Necessary
71
72
    return $self;
73
}
74
75
=head3 search_incomplete
76
77
    my $requests = $illRequests->search_incomplete;
78
79
A specialised version of `search`, returning all requests currently
80
not considered completed.
81
82
=cut
83
84
sub search_incomplete {
85
    my ( $self ) = @_;
86
    $self->search( {
87
        status => [
88
            -and => { '!=', 'COMP' }, { '!=', 'GENCOMP' }
89
        ]
90
    } );
91
}
92
93
=head1 AUTHOR
94
95
Alex Sassmannshausen <alex.sassmannshausen@ptfs-europe.com>
96
97
=cut
98
99
1;
(-)a/Koha/REST/V1/Illrequests.pm (+80 lines)
Line 0 Link Here
1
package Koha::REST::V1::Illrequests;
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it under the
6
# terms of the GNU General Public License as published by the Free Software
7
# Foundation; either version 3 of the License, or (at your option) any later
8
# version.
9
#
10
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License along
15
# with Koha; if not, write to the Free Software Foundation, Inc.,
16
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18
use Modern::Perl;
19
20
use Mojo::Base 'Mojolicious::Controller';
21
22
use Koha::Illrequests;
23
use Koha::Library;
24
25
sub list {
26
    my ($c, $args, $cb) = @_;
27
28
    my $filter;
29
    $args //= {};
30
    my $output = [];
31
32
    # Create a hash where all keys are embedded values
33
    # Enables easy checking
34
    my %embed;
35
    if (defined $args->{embed}) {
36
        %embed = map { $_ => 1 }  @{$args->{embed}};
37
        delete $args->{embed};
38
    }
39
40
    for my $filter_param ( keys %$args ) {
41
        my @values = split(/,/, $args->{$filter_param});
42
        $filter->{$filter_param} = \@values;
43
    }
44
45
    my $requests = Koha::Illrequests->search($filter);
46
47
    while (my $request = $requests->next) {
48
        my $unblessed = $request->unblessed;
49
        # Add the request's id_prefix
50
        $unblessed->{id_prefix} = $request->id_prefix;
51
        # Augment the request response with patron details
52
        # if appropriate
53
        if (defined $embed{patron}) {
54
            my $patron = $request->patron;
55
            $unblessed->{patron} = {
56
                firstname  => $patron->firstname,
57
                surname    => $patron->surname,
58
                cardnumber => $patron->cardnumber
59
            };
60
        }
61
        # Augment the request response with status details
62
        # if appropriate
63
        if (defined $embed{capabilities}) {
64
            $unblessed->{capabilities} = $request->capabilities;
65
        }
66
        # Augment the request response with branch details
67
        # if appropriate
68
        if (defined $embed{branch}) {
69
            $unblessed->{branch} = Koha::Libraries->find(
70
                $request->branchcode
71
            )->unblessed;
72
        }
73
        push @{$output}, $unblessed
74
    }
75
76
    return $c->$cb( $output, 200 );
77
78
}
79
80
1;
(-)a/api/v1/swagger/paths.json (+3 lines)
Lines 16-20 Link Here
16
  },
16
  },
17
  "/patrons/{borrowernumber}": {
17
  "/patrons/{borrowernumber}": {
18
    "$ref": "paths/patrons.json#/~1patrons~1{borrowernumber}"
18
    "$ref": "paths/patrons.json#/~1patrons~1{borrowernumber}"
19
  },
20
  "/illrequests": {
21
    "$ref": "paths/illrequests.json#/~1illrequests"
19
  }
22
  }
20
}
23
}
(-)a/api/v1/swagger/paths/illrequests.json (+98 lines)
Line 0 Link Here
1
{
2
    "/illrequests": {
3
        "get": {
4
            "x-mojo-controller": "Koha::REST::V1::Illrequests",
5
            "operationId": "list",
6
            "tags": ["illrequests"],
7
            "parameters": [{
8
                "name": "embed",
9
                "in": "query",
10
                "description": "Additional objects that should be embedded in the response",
11
                "required": false,
12
                "type": "array",
13
                "collectionFormat": "csv",
14
                "items": {
15
                    "type": "string",
16
                    "enum": [
17
                        "patron",
18
                        "branch",
19
                        "capabilities"
20
                    ]
21
                }
22
            }, {
23
                "name": "backend",
24
                "in": "query",
25
                "description": "The name of a ILL backend",
26
                "required": false,
27
                "type": "string"
28
            }, {
29
                "name": "orderid",
30
                "in": "query",
31
                "description": "The order ID of a request",
32
                "required": false,
33
                "type": "string"
34
            }, {
35
                "name": "biblio_id",
36
                "in": "query",
37
                "description": "The biblio ID associated with a request",
38
                "required": false,
39
                "type": "integer"
40
            }, {
41
                "name": "borrower_id",
42
                "in": "query",
43
                "description": "The borrower ID associated with a request",
44
                "required": false,
45
                "type": "integer"
46
            }, {
47
                "name": "completed",
48
                "in": "query",
49
                "description": "The date the request was considered completed",
50
                "required": false,
51
                "type": "string"
52
            }, {
53
                "name": "status",
54
                "in": "query",
55
                "description": "A full status string e.g. REQREV",
56
                "required": false,
57
                "type": "string"
58
            }, {
59
                "name": "medium",
60
                "in": "query",
61
                "description": "The medium of the requested item",
62
                "required": false,
63
                "type": "string"
64
            }, {
65
                "name": "updated",
66
                "in": "query",
67
                "description": "The last updated date of the request",
68
                "required": false,
69
                "type": "string"
70
            }, {
71
                "name": "placed",
72
                "in": "query",
73
                "description": "The date the request was placed",
74
                "required": false,
75
                "type": "string"
76
            }, {
77
                "name": "branch_id",
78
                "in": "query",
79
                "description": "The ID of the pickup branch",
80
                "required": false,
81
                "type": "string"
82
            }],
83
            "produces": [
84
                "application/json"
85
            ],
86
            "responses": {
87
                "200": {
88
                    "description": "OK"
89
                }
90
            },
91
            "x-koha-authorization": {
92
                "permissions": {
93
                    "borrowers": "1"
94
                }
95
            }
96
        }
97
    }
98
}
(-)a/etc/koha-conf.xml (+14 lines)
Lines 149-153 __PAZPAR2_TOGGLE_XML_POST__ Link Here
149
 <plack_max_requests>50</plack_max_requests>
149
 <plack_max_requests>50</plack_max_requests>
150
 <plack_workers>2</plack_workers>
150
 <plack_workers>2</plack_workers>
151
151
152
 <interlibrary_loans>
153
     <!-- Path to where Illbackends are located on the system
154
          - This setting should normally not be touched -->
155
     <backend_directory>__PERL_MODULE_DIR__/Koha/Illbackends</backend_directory>
156
     <!-- How should we treat staff comments?
157
          - hide: don't show in OPAC
158
          - show: show in OPAC -->
159
     <staff_request_comments>hide</staff_request_comments>
160
     <!-- How should we treat the reply_date field?
161
          - hide: don't show this field in the UI
162
          - any other string: show, with this label -->
163
     <reply_date>hide</reply_date>
164
 </interlibrary_loans>
165
152
</config>
166
</config>
153
</yazgfs>
167
</yazgfs>
(-)a/ill/ill-requests.pl (+223 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2013 PTFS-Europe Ltd and Mark Gavillet
4
# Copyright 2014 PTFS-Europe Ltd
5
#
6
# This file is part of Koha.
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
22
use CGI;
23
24
use C4::Auth;
25
use C4::Output;
26
use Koha::AuthorisedValues;
27
use Koha::Illrequests;
28
use Koha::Libraries;
29
30
my $cgi = CGI->new;
31
my $illRequests = Koha::Illrequests->new;
32
33
# Grab all passed data
34
# 'our' since Plack changes the scoping
35
# of 'my'
36
our $params = $cgi->Vars();
37
38
my $op = $params->{method};
39
40
my ( $template, $patronnumber, $cookie ) = get_template_and_user( {
41
    template_name => 'ill/ill-requests.tt',
42
    query         => $cgi,
43
    type          => 'intranet',
44
    flagsrequired => { ill => '*' },
45
} );
46
47
if ( $op eq 'illview' ) {
48
    # View the details of an ILL
49
    my $request = Koha::Illrequests->find($params->{illrequest_id});
50
51
    $template->param(
52
        request => $request
53
    );
54
55
} elsif ( $op eq 'create' ) {
56
    # We're in the process of creating a request
57
    my $request = Koha::Illrequest->new
58
        ->load_backend($params->{backend});
59
    my $backend_result = $request->backend_create($params);
60
    $template->param(
61
        whole   => $backend_result,
62
        request => $request
63
    );
64
    handle_commit_maybe($backend_result, $request);
65
66
} elsif ( $op eq 'confirm' ) {
67
    # Backend 'confirm' method
68
    # confirm requires a specific request, so first, find it.
69
    my $request = Koha::Illrequests->find($params->{illrequest_id});
70
    my $backend_result = $request->backend_confirm($params);
71
    $template->param( whole => $backend_result );
72
73
    # handle special commit rules & update type
74
    handle_commit_maybe($backend_result, $request);
75
76
} elsif ( $op eq 'status' ) {
77
    # Backend 'status' method
78
    # status requires a specific request, so first, find it.
79
    my $request = Koha::Illrequests->find($params->{illrequest_id});
80
    my $backend_result = $request->backend_status($params);
81
    $template->param(
82
        whole   => $backend_result,
83
        request => $request,
84
    );
85
86
    # handle special commit rules & update type
87
    handle_commit_maybe($backend_result, $request);
88
89
} elsif ( $op eq 'cancel' ) {
90
    # Backend 'cancel' method
91
    # cancel requires a specific request, so first, find it.
92
    my $request = Koha::Illrequests->find($params->{illrequest_id});
93
    my $backend_result = $request->backend_cancel($params);
94
    $template->param(
95
        whole   => $backend_result,
96
        request => $request,
97
    );
98
99
    # handle special commit rules & update type
100
    handle_commit_maybe($backend_result, $request);
101
102
} elsif ( $op eq 'edit_action' ) {
103
    # Handle edits to the Illrequest object.
104
    # (not the Illrequestattributes)
105
    # We simulate the API for backend requests for uniformity.
106
    # So, init:
107
    my $request = Koha::Illrequests->find($params->{illrequest_id});
108
    if ( !$params->{stage} ) {
109
        my $backend_result = {
110
            error   => 0,
111
            status  => '',
112
            message => '',
113
            method  => 'edit_action',
114
            stage   => 'init',
115
            next    => '',
116
            value   => {}
117
        };
118
        $template->param(
119
            whole   => $backend_result,
120
            request => $request
121
        );
122
    } else {
123
        # Commit:
124
        # Save the changes
125
        $request->borrowernumber($params->{borrowernumber});
126
        $request->biblio_id($params->{biblio_id});
127
        $request->branchcode($params->{branchcode});
128
        $request->notesopac($params->{notesopac});
129
        $request->notesstaff($params->{notesstaff});
130
        $request->store;
131
        my $backend_result = {
132
            error   => 0,
133
            status  => '',
134
            message => '',
135
            method  => 'edit_action',
136
            stage   => 'commit',
137
            next    => 'illlist',
138
            value   => {}
139
        };
140
        handle_commit_maybe($backend_result, $request);
141
    }
142
143
} elsif ( $op eq 'moderate_action' ) {
144
    # Moderate action is required for an ILL submodule / syspref.
145
    # Currently still needs to be implemented.
146
    redirect_to_list();
147
148
} elsif ( $op eq 'delete_action' ) {
149
    # We simply delete the request...
150
    my $request = Koha::Illrequests->find($params->{illrequest_id})->delete;
151
    # ... then return to list view.
152
    redirect_to_list();
153
154
} elsif ( $op eq 'manual_action' ) {
155
    my %flds = $cgi->Vars;
156
    my $flds = {};
157
    while ( my ( $k, $v ) = each %flds ) {
158
        $flds->{$k} = $v if ( 'query_type' ne $k or 'query_value' );
159
    }
160
    # Rename borrower key
161
    $flds->{borrower} = $flds->{brw};
162
    my $request = $illRequests->request($flds);
163
    # push @{$requests}, $request if $request; # Obsolete
164
    $op = 'request';
165
166
} else {
167
    # type eq 'illlist' || default action
168
    # Display all current ILLs
169
    my $requests = $illRequests->search();
170
171
    $template->param(
172
        requests => $requests
173
    );
174
175
    # If we receive a pre-filter, make it available to the template
176
    my $possible_filters = ['borrowernumber'];
177
    my $active_filters = [];
178
    foreach my $filter(@{$possible_filters}) {
179
        if ($params->{$filter}) {
180
            push @{$active_filters},
181
                { name => $filter, value => $params->{$filter}};
182
        }
183
    }
184
    if (scalar @{$active_filters} > 0) {
185
        $template->param(
186
            prefilters => $active_filters
187
        );
188
    }
189
}
190
191
# Get a list of backends
192
my $ir = Koha::Illrequest->new;
193
194
$template->param(
195
    backends    => $ir->available_backends,
196
    media       => [ "Book", "Article", "Journal" ],
197
    query_type  => $op,
198
    branches    => Koha::Libraries->search->unblessed,
199
    here_link   => "/cgi-bin/koha/ill/ill-requests.pl"
200
);
201
202
output_html_with_http_headers( $cgi, $cookie, $template->output );
203
204
sub handle_commit_maybe {
205
    my ( $backend_result, $request ) = @_;
206
    # We need to special case 'commit'
207
    if ( $backend_result->{stage} eq 'commit' ) {
208
        if ( $backend_result->{next} eq 'illview' ) {
209
            # Redirect to a view of the newly created request
210
            print $cgi->redirect(
211
                '/cgi-bin/koha/ill/ill-requests.pl?method=illview&illrequest_id='.
212
                $request->id
213
            );
214
        } else {
215
            # Redirect to a requests list view
216
            redirect_to_list();
217
        }
218
    }
219
}
220
221
sub redirect_to_list {
222
    print $cgi->redirect('/cgi-bin/koha/ill/ill-requests.pl');
223
}
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc (+3 lines)
Lines 108-112 Link Here
108
    [% IF Koha.Preference('HouseboundModule') %]
108
    [% IF Koha.Preference('HouseboundModule') %]
109
        [% IF houseboundview %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/housebound.pl?borrowernumber=[% borrowernumber %]">Housebound</a></li>
109
        [% IF houseboundview %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/housebound.pl?borrowernumber=[% borrowernumber %]">Housebound</a></li>
110
    [% END %]
110
    [% END %]
111
    [% IF Koha.Preference('ILLModule') %]
112
        <li><a href="/cgi-bin/koha/ill/ill-requests.pl?borrowernumber=[% borrowernumber %]">Interlibrary loans</a></li>
113
    [% END %]
111
</ul></div>
114
</ul></div>
112
[% END %]
115
[% END %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/ill-toolbar.inc (+31 lines)
Line 0 Link Here
1
[% USE Koha %]
2
<script type="text/javascript">
3
//<![CDATA[
4
$(document).ready(function(){
5
});
6
//]]>
7
</script>
8
9
[% IF Koha.Preference('ILLModule ') %]
10
<div id="toolbar" class="btn-toolbar">
11
    [% IF backends.size > 1 %]
12
    <div class="dropdown btn-group">
13
        <button class="btn btn-small dropdown-toggle" type="button" id="ill-backend-dropdown" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
14
            <i class="fa fa-plus"></i> New ILL request <span class="caret"></span>
15
        </button>
16
        <ul class="dropdown-menu" aria-labelledby="ill-backend-dropdown">
17
            [% FOREACH backend IN backends %]
18
            <li><a href="/cgi-bin/koha/ill/ill-requests.pl?method=create&backend=[% backend %]">[% backend %]</a></li>
19
            [% END %]
20
        </ul>
21
    </div>
22
    [% ELSE %]
23
    <a id="ill-new" class="btn btn-small" href="/cgi-bin/koha/ill/ill-requests.pl?method=create&backend=[% backends.0 %]">
24
        <i class="fa fa-plus"></i> New ILL request
25
    </a>
26
    [% END %]
27
    <a id="ill-list" class="btn btn-small btn-group" href="/cgi-bin/koha/ill/ill-requests.pl">
28
        <i class="fa fa-list"></i> List requests
29
    </a>
30
</div>
31
[% END %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/ill/ill-requests.tt (+343 lines)
Line 0 Link Here
1
[% USE AuthorisedValues %]
2
[% USE Branches %]
3
4
[% INCLUDE 'doc-head-open.inc' %]
5
<title>Koha &rsaquo; ILL requests  &rsaquo;</title>
6
[% INCLUDE 'doc-head-close.inc' %]
7
<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.tablesorter.min.js"></script>
8
<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.checkboxes.min.js"></script>
9
<link rel="stylesheet" type="text/css" href="[% interface %]/[% theme %]/css/datatables.css" />
10
[% INCLUDE 'datatables.inc' %]
11
[% INCLUDE 'calendar.inc' %]
12
<script type="text/javascript">
13
//<![CDATA[
14
    $(document).ready(function() {
15
        var myTable = $("#ill-requests").DataTable($.extend(true, {}, dataTablesDefaults, {
16
            "aoColumnDefs": [  // Last column shouldn't be sortable or searchable
17
                { "aTargets": [ -1 ], "bSortable": false, "bSearchable": false },
18
            ],
19
            "aaSorting": [[ 4, "desc" ]], // Default sort, updated descending
20
            "iDisplayLength": 10, // 10 results per page
21
            "sPaginationType": "full_numbers", // Pagination display
22
            "sAjaxDataProp": "", // Data is in the root object of the response
23
            "deferRender": true, // Improve performance on big datasets
24
            "ajax": {
25
                url: "/api/v1/illrequests?embed=patron,capabilities,branch",
26
                cache: true
27
            },
28
            "columns": [
29
                {  
30
                    render: function(data, type, row) {
31
                        return '<a title="View borrower details" ' +
32
                            'href="/cgi-bin/koha/members/moremember.pl?borrowernumber='+row.borrowernumber+'">' +
33
                            row.patron.firstname + ' ' + row.patron.surname +
34
                            '</a>';
35
                    },
36
                    className: 'borrower_name'
37
                },
38
                {
39
                    data: 'borrowernumber',
40
                    className: 'borrowernumber'
41
                },
42
                {
43
                    data: 'biblio_id',
44
                    className: 'biblio_id'
45
                },
46
                {
47
                    data: 'branch.branchname',
48
                    className: 'branch_name'
49
                },
50
                {
51
                    render: function(data, type, row) {
52
                        return row.capabilities[row.status].name;
53
                    },
54
                    className: 'status'
55
                },
56
                {
57
                    data: 'updated',
58
                    className: 'updated'
59
                },
60
                {
61
                    data: 'medium',
62
                    className: 'medium'
63
                },
64
                {
65
                    data: 'cost',
66
                    className: 'cost'
67
                },
68
                {
69
                    render: function(data, type, row) {
70
                        return row.id_prefix + row.illrequest_id;
71
                    },
72
                    className: 'request_id'
73
                },
74
                {
75
                    data: null,
76
                    render: function(data, type, row) {
77
                        return '<a class="btn btn-mini" ' +
78
                            'href="/cgi-bin/koha/ill/ill-requests.pl?method=illview&illrequest_id=' +
79
                            row.illrequest_id +
80
                            '">Manage request</a>' +
81
                            '</div>'
82
                    }
83
                }
84
            ]
85
        }));
86
        var filters = $('#ill-requests').data();
87
        if (typeof filters !== 'undefined') {
88
            var filterNames = Object.keys(filters).filter(
89
                function(thisData) {
90
                    return thisData.match(/^filter/);
91
                }
92
            );
93
            filterNames.forEach(function(thisFilter) {
94
                var filterClass = "." + toColumnName(thisFilter);
95
                var regex = '^'+filters[thisFilter]+'$';
96
                myTable.columns(filterClass).search(regex, true, false).draw();
97
            });
98
            myTable.draw();
99
        }
100
101
        function toColumnName(myVal) {
102
            return myVal
103
                .replace(/^filter/, '')
104
                .replace(/([A-Z])/g, "_$1")
105
                .replace(/^_/,'').toLowerCase();
106
        };
107
        
108
    });
109
//]]>
110
</script>
111
</head>
112
113
<body id="acq_suggestion" class="acq">
114
[% INCLUDE 'header.inc' %]
115
[% INCLUDE 'cat-search.inc' %]
116
117
<div id="breadcrumbs">
118
  <a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo;
119
  [% IF query_type == 'create' %]
120
  <a href=[% parent %]>ILL requests</a> &rsaquo; New request
121
  [% ELSIF query_type == 'status' %]
122
  <a href=[% parent %]>ILL requests</a> &rsaquo; Status
123
  [% ELSE %]
124
  ILL requests
125
  [% END %]
126
</div>
127
128
<div id="doc3" class="yui-t2">
129
<div id="bd">
130
  <div id="yui-main">
131
    <div class="yui-b">
132
      [% INCLUDE 'ill-toolbar.inc' %]
133
134
      [% IF whole.error %]
135
      <h1>Error performing operation</h1>
136
      <!-- Dispatch on Status -->
137
      <p>We encountered an error:</p>
138
      <ol>
139
        <li>[% whole.status %]</li>
140
        <li>[% whole.message %]</li>
141
      </ol>
142
      [% END %]
143
144
      [% IF query_type == 'create' %]
145
      <h1>New ILL request</h1>
146
      [% INCLUDE $whole.template %]
147
148
      [% ELSIF query_type == 'confirm' %]
149
      <h1>Confirm ILL request</h1>
150
      [% INCLUDE $whole.template %]
151
152
      [% ELSIF query_type == 'status' %]
153
      <h1>View current status of an ILL request</h1>
154
      [% INCLUDE $whole.template %]
155
156
      [% ELSIF query_type == 'edit_action' %]
157
      <form method="POST" action=[% here_link %]>
158
        <fieldset class="rows">
159
          <legend>Request details</legend>
160
          <ol>
161
            <li class="borrowernumber">
162
              <label for="borrowernumber">Borrower number:</label>
163
              <input name="borrowernumber" id="borrowernumber" type="text" value="[% request.borrowernumber %]">
164
            </li>
165
            <li class="biblio_id">
166
              <label for="biblio_id" class="biblio_id">Biblio number:</label>
167
              <input name="biblio_id" id="biblio_id" type="text" value="[% request.biblio_id %]" />
168
            </li>
169
            <li class="branchcode">
170
              <label class="branchcode">Branch:</label>
171
              <select name="branchcode" id="branch">
172
                <option value=""></option>
173
                [% FOREACH branch IN branches %]
174
                [% IF ( branch.branchcode == request.branchcode ) %]
175
                <option value="[% branch.branchcode %]" selected="selected">
176
                  [% branch.branchname %]
177
                </option>
178
                [% ELSE %]
179
                <option value="[% branch.branchcode %]">
180
                  [% branch.branchname %]
181
                </option>
182
                [% END %]
183
                [% END %]
184
              </select>
185
            </li>
186
            <li class="status">
187
              <label class="status">Status:</label>
188
              [% stat = request.status %]
189
              [% request.capabilities.$stat.name %]
190
            </li>
191
            <li class="updated">
192
              <label class="updated">Last updated:</label>
193
              [% request.updated %]
194
            </li>
195
            <li class="medium">
196
              <label class="medium">Request type:</label>
197
              [% request.medium %]
198
            </li>
199
            <li class="cost">
200
              <label class="cost">Cost:</label>
201
              [% request.cost %]
202
            </li>
203
            <li class="req_id">
204
              <label class="req_id">Request number:</label>
205
              [% request.id_prefix _ request.illrequest_id %]
206
            </li>
207
            <li class="notesstaff">
208
              <label class="notesstaff">Staff notes:</label>
209
              <textarea name="notesstaff" id="notesstaff" rows="5">[% request.notesstaff %]</textarea>
210
            </li>
211
            <li class="notesopac">
212
              <label class="notesopac">Opac notes:</label>
213
              <textarea name="notesopac" id="notesopac" rows="5">[% request.notesopac %]</textarea>
214
            </li>
215
            <ol>
216
              [% FOREACH attr IN request.illrequestattributes %]
217
              <li class="[% attr.type %]">
218
                <label class="[% attr.type %]">[% attr.type %]</label>
219
                [% attr.value %]
220
              </li>
221
              [% END %]
222
            </ol>
223
          </ol>
224
        </fieldset>
225
        <input type="hidden" value="edit_action" name="method"/>
226
        <input type="hidden" value="form" name="stage"/>
227
        <input type="hidden" value="[% request.illrequest_id %]" name="illrequest_id"/>
228
        <input type="submit" value="submit"/>
229
      </form>
230
231
      [% ELSIF query_type == 'illview' %]
232
      [% actions = request.available_actions %]
233
      [% capabilities = request.capabilities %]
234
      [% req_status = request.status %]
235
      <h1>Manage ILL request</h1>
236
      <div id="toolbar" class="btn-toolbar">
237
        <a title="Edit request" id="ill-toolbar-btn-edit-action" class="btn btn-small" href="/cgi-bin/koha/ill/ill-requests.pl?method=edit_action&illrequest_id=[% request.illrequest_id %]">
238
          Edit request
239
        </a>
240
        [% FOREACH action IN actions %]
241
        [% IF action.method != 0 %]
242
            <a title="[% action.ui_method_name %]" id="ill-toolbar-btn-[% action.id | lower %]" class="btn btn-small" href="/cgi-bin/koha/ill/ill-requests.pl?method=[% action.method %]&illrequest_id=[% request.illrequest_id %]">
243
            <span class="fa [% action.ui_method_icon %]"></span>
244
            [% action.ui_method_name %]
245
            </a>
246
        [% END %]
247
        [% END %]
248
      </div>
249
      <fieldset class="rows" style="float: none;">
250
         <ol>
251
           <li class="borrowernumber">
252
             <label class="borrowernumber">Borrower:</label>
253
             [% borrowerlink = "/cgi-bin/koha/members/moremember.pl"
254
                               _ "?borrowernumber=" _ brw.borrowernumber %]
255
             <a href="[% borrowerlink %]" title="View borrower details">
256
               [% request.patron.firstname _ " "
257
                  _ request.patron.surname _ " ["
258
                  _ request.patron.cardnumber
259
                  _ "]" %]
260
             </a>
261
           </li>
262
           <li class="biblio_id">
263
             <label class="biblio_id">Biblio number:</label>
264
             [% request.biblio_id %]
265
           </li>
266
           <li class="branchcode">
267
             <label class="branchcode">Branch:</label>
268
             [% Branches.GetName(request.branchcode) %]
269
           </li>
270
           <li class="status">
271
             <label class="status">Status:</label>
272
             [% capabilities.$req_status.name %]
273
           </li>
274
           <li class="updated">
275
             <label class="updated">Last updated:</label>
276
             [% request.updated %]
277
           </li>
278
           <li class="medium">
279
             <label class="medium">Request type:</label>
280
             [% request.medium %]
281
           </li>
282
           <li class="cost">
283
             <label class="cost">Cost:</label>
284
             [% request.cost %]
285
           </li>
286
           <li class="req_id">
287
             <label class="req_id">Request number:</label>
288
             [% request.id_prefix _ request.illrequest_id %]
289
           </li>
290
           <li class="notesstaff">
291
             <label class="notes_staff">Staff notes:</label>
292
             <pre>[% request.notesstaff %]</pre>
293
           </li>
294
           <li class="notesopac">
295
             <label class="notes_opac">Notes:</label>
296
             <pre>[% request.notesopac %]</pre>
297
           </li>
298
           <ol>
299
             [% FOREACH attr IN request.illrequestattributes %]
300
             <li class="[% attr.type %]">
301
               <label class="[% attr.type %]">[% attr.type %]</label>
302
               [% attr.value %]
303
             </li>
304
             [% END %]
305
           </ol>
306
         </ol>
307
       </fieldset>
308
      </div>
309
310
      [% ELSE %]
311
      <!-- illlist -->
312
      <h1>View ILL requests</h1>
313
      <div id="results">
314
        <h2>Details for all requests</h2>
315
        <table 
316
            [% FOREACH filter IN prefilters %]
317
            data-filter-[% filter.name %]="[% filter.value %]"
318
            [% END %]
319
            id="ill-requests">
320
          <thead>
321
            <tr>
322
              <th id="borrower_name">Borrower:</th>
323
              <th id="borrowernumber">Borrower number:</th>
324
              <th id="biblio_id">Biblio number:</th>
325
              <th id="branchcode">Branch:</th>
326
              <th id="status">Status:</th>
327
              <th id="updated">Last updated:</th>
328
              <th id="medium">Request type:</th>
329
              <th id="cost">Cost:</th>
330
              <th id="req_id">Request number:</th>
331
              <th id="link">Manage request:</th>
332
            </tr>
333
          </thead>
334
          <tbody>
335
          </tbody>
336
        </table>
337
      </div>
338
      [% END %]
339
340
  </div>
341
</div>
342
343
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/intranet-main.tt (+5 lines)
Lines 63-68 Link Here
63
                    <li>
63
                    <li>
64
                        <a class="icon_general icon_authorities" href="/cgi-bin/koha/authorities/authorities-home.pl">Authorities</a>
64
                        <a class="icon_general icon_authorities" href="/cgi-bin/koha/authorities/authorities-home.pl">Authorities</a>
65
                    </li>
65
                    </li>
66
                    [% IF Koha.Preference('ILLModule') %]
67
                    <li>
68
                        <a class="icon_general icon_ill" href="/cgi-bin/koha/ill/ill-requests.pl">ILL requests</a>
69
                    </li>
70
                    [% END %]
66
                </ul>
71
                </ul>
67
            </div><!-- /area-list-left -->
72
            </div><!-- /area-list-left -->
68
        </div><!-- /yui-u first -->
73
        </div><!-- /yui-u first -->
(-)a/t/db_dependent/Illrequest.t (+544 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
#
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it under the
6
# terms of the GNU General Public License as published by the Free Software
7
# Foundation; either version 2 of the License, or (at your option) any later
8
# version.
9
#
10
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License along
15
# with Koha; if not, write to the Free Software Foundation, Inc.,
16
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
#
18
19
use Modern::Perl;
20
21
use File::Basename qw/basename/;
22
use Koha::Database;
23
use Koha::Illrequestattributes;
24
use Koha::Patrons;
25
use t::lib::TestBuilder;
26
27
use Test::More tests => 44;
28
29
# We want to test the Koha IllRequest object.  At its core it's a simple
30
# Koha::Object, mapping to the ill_request table.
31
#
32
# This object will supersede the Status object in ILLModule.
33
#
34
# We must ensure perfect backward compatibility between the current model and
35
# the Status less model.
36
37
use_ok('Koha::Illrequest');
38
use_ok('Koha::Illrequests');
39
40
my $schema = Koha::Database->new->schema;
41
$schema->storage->txn_begin;
42
43
my $builder = t::lib::TestBuilder->new;
44
45
my $patron = $builder->build({ source => 'Borrower' });
46
my $branch = $builder->build({ source => 'Branch' });
47
48
my $illRequest = $builder->build({
49
    source => 'Illrequest',
50
    value => {
51
        borrowernumber  => $patron->{borrowernumber},
52
        branch          => $branch->{branchcode},
53
        biblionumber    => 0,
54
        status          => 'NEW',
55
        completion_date => 0,
56
        reqtype         => 'book',
57
    }
58
});
59
60
my $illObject = Koha::Illrequests->find($illRequest->{illrequest_id});
61
62
isa_ok($illObject, "Koha::Illrequest");
63
64
# Test delete works correctly.
65
my $illRequestDelete = $builder->build({
66
    source => 'Illrequest',
67
    value => {
68
        borrowernumber  => $patron->{borrowernumber},
69
        branch          => $branch->{branchcode},
70
        biblionumber    => 0,
71
        status          => 'NEW',
72
        completion_date => 0,
73
        reqtype         => 'book',
74
    }
75
});
76
sub ill_req_search {
77
    return Koha::Illrequestattributes->search({
78
        illrequest_id => $illRequestDelete->{illrequest_id}
79
    })->count;
80
}
81
82
is(ill_req_search, 0, "Correctly not found matching Illrequestattributes.");
83
# XXX: For some reason test builder can't build Illrequestattributes.
84
my $illReqAttr = Koha::Illrequestattribute->new({
85
    illrequest_id => $illRequestDelete->{illrequest_id},
86
    type => "test",
87
    value => "Hello World"
88
})->store;
89
is(ill_req_search, 1, "We have found a matching Illrequestattribute.");
90
91
Koha::Illrequests->find($illRequestDelete->{illrequest_id})->delete;
92
is(
93
    Koha::Illrequests->find($illRequestDelete->{illrequest_id}),
94
    undef,
95
    "Correctly deleted Illrequest."
96
);
97
is(ill_req_search, 0, "Correctly deleted Illrequestattributes.");
98
99
# Test Accessing of related records.
100
101
# # TODO the conclusion from being able to use one_to_many? we no longer need
102
# # the Record object: simply pass the `ill_request_attributes` resultset
103
# # whenever one would pass a Record.
104
105
my $illRequest2 = $builder->build({
106
    source => 'Illrequest',
107
    value  => {
108
        borrower_id => $patron->{borrowernumber},
109
        branch_id   => $branch->{branchcode},
110
        biblio_id   => 0,
111
        status      => 'NEW',
112
        completed   => 0,
113
        medium      => 'book',
114
    }
115
});
116
my $illReqAttr2 = Koha::Illrequestattribute->new({
117
    illrequest_id => $illRequest2->{illrequest_id},
118
    type          => "test2",
119
    value         => "Hello World"
120
})->store;
121
my $illReqAttr3 = Koha::Illrequestattribute->new({
122
    illrequest_id => $illRequest2->{illrequest_id},
123
    type          => "test3",
124
    value         => "Hello Space"
125
})->store;
126
127
my $illRequestAttributes = Koha::Illrequests
128
    ->find($illRequest2->{illrequest_id})->illrequestattributes;
129
130
isa_ok($illRequestAttributes, "Koha::Illrequestattributes");
131
132
is($illRequestAttributes->count, 2, "Able to search related.");
133
134
# Test loading of 'Config'.
135
136
my $rqConfigTest = Koha::Illrequest->new({
137
    borrower_id => $patron->{borrowernumber},
138
    branch_id   => $branch->{branchcode},
139
});
140
141
isa_ok($rqConfigTest->_config, "Koha::Illrequest::Config");
142
143
# Test loading of 'Dummy' backend.
144
145
my $rqBackendTest = Koha::Illrequest->new({
146
    borrower_id => $patron->{borrowernumber},
147
    branch_id   => $branch->{branchcode},
148
})->store;
149
150
$rqBackendTest->_config->backend("Dummy");
151
$rqBackendTest->_config->limits({ default => { count => -1 } });
152
isa_ok($rqBackendTest->_backend, "Koha::Illbackends::Dummy::Base");
153
154
# Test use of 'Dummy' Backend.
155
156
## Test backend_update_status
157
158
# FIXME: This breaks transparancy of ->status method!
159
eval { $rqBackendTest->status("ERR") };
160
ok($@, "status: Test for status error on hook fail.");
161
162
# FIXME: Will need to test this on new illRequest to not pollute rest of
163
# tests.
164
165
# is($rqBackendTest->status("NEW")->status, "NEW", "status: Setter works
166
# OK.");
167
# is($rqBackendTest->status(null), null, "status: Unsetter works OK.");
168
169
## Test backend_create
170
171
is(
172
    $rqBackendTest->status,
173
    undef,
174
    "backend_create: Test our status initiates correctly."
175
);
176
177
# Request a search form
178
my $created_rq = $rqBackendTest->backend_create({
179
    stage  => "search_form",
180
    method => "create",
181
});
182
183
is( $created_rq->{stage}, 'search_results',
184
    "backend_create: search_results stage." );
185
186
# Request search results
187
# FIXME: fails because of missing patron / branch info.
188
# $created_rq = $rqBackendTest->backend_create({
189
#     stage  => "search_results",
190
#     method => "create",
191
#     other  => { search => "interlibrary loans" },
192
# });
193
194
# is_deeply(
195
#     $created_rq,
196
#     {
197
#         error    => 0,
198
#         status   => '',
199
#         message  => '',
200
#         method   => 'create',
201
#         stage    => 'search_results',
202
#         template => 'ill/Dummy/create.inc',
203
#         value    => [
204
#             {
205
#                 id     => 1234,
206
#                 title  => "Ordering ILLs using Koha",
207
#                 author => "A.N. Other",
208
#             },
209
#             {
210
#                 id     => 5678,
211
#                 title  => "Interlibrary loans in Koha",
212
#                 author => "A.N. Other",
213
#             },
214
#         ],
215
#     }
216
#     ,
217
#     "backend_create: search_results stage."
218
# );
219
220
# # Create the request
221
# $created_rq = $rqBackendTest->backend_create({
222
#     stage  => "commit",
223
#     method => "create",
224
#     other  => {
225
#         id     => 1234,
226
#         title  => "Ordering ILLs using Koha",
227
#         author => "A.N. Other",
228
#     },
229
# });
230
231
# while ( my ( $field, $value ) = each %{$created_rq} ) {
232
#     isnt($value, undef, "backend_create: key '$field' exists");
233
# };
234
235
# is(
236
#     $rqBackendTest->status,
237
#     "NEW",
238
#     "backend_create: Test our status was updated."
239
# );
240
241
# cmp_ok(
242
#     $rqBackendTest->illrequestattributes->count,
243
#     "==",
244
#     3,
245
#     "backend_create: Ensure we have correctly stored our new attributes."
246
# );
247
248
# ## Test backend_list
249
250
# is_deeply(
251
#     $rqBackendTest->backend_list->{value},
252
#     {
253
#         1 => {
254
#             id     => 1234,
255
#             title  => "Ordering ILLs using Koha",
256
#             author => "A.N. Other",
257
#             status => "On order",
258
#             cost   => "30 GBP",
259
#         }
260
#     },
261
#     "backend_list: Retrieve our list of requested requests."
262
# );
263
264
# ## Test backend_renew
265
266
# ok(
267
#     $rqBackendTest->backend_renew->{error},
268
#     "backend_renew: Error for invalid request."
269
# );
270
# is_deeply(
271
#     $rqBackendTest->backend_renew->{value},
272
#     {
273
#         id     => 1234,
274
#         title  => "Ordering ILLs using Koha",
275
#         author => "A.N. Other",
276
#     },
277
#     "backend_renew: Renew request."
278
# );
279
280
# ## Test backend_confirm
281
282
# my $rqBackendTestConfirmed = $rqBackendTest->backend_confirm;
283
# is(
284
#     $rqBackendTest->status,
285
#     "REQ",
286
#     "backend_commit: Confirm status update correct."
287
# );
288
# is(
289
#     $rqBackendTest->orderid,
290
#     1234,
291
#     "backend_commit: Confirm orderid populated correctly."
292
# );
293
294
# ## Test backend_status
295
296
# is(
297
#     $rqBackendTest->backend_status->{error},
298
#     0,
299
#     "backend_status: error for invalid request."
300
# );
301
# is_deeply(
302
#     $rqBackendTest->backend_status->{value},
303
#     {
304
#         id     => 1234,
305
#         status => "On order",
306
#         title  => "Ordering ILLs using Koha",
307
#         author => "A.N. Other",
308
#     },
309
#     "backend_status: Retrieve the status of request."
310
# );
311
312
# # Now test trying to get status on non-confirmed request.
313
my $rqBackendTestUnconfirmed = Koha::Illrequest->new({
314
    borrower_id => $patron->{borrowernumber},
315
    branch_id   => $branch->{branchcode},
316
})->store;
317
$rqBackendTestUnconfirmed->_config->backend("Dummy");
318
$rqBackendTestUnconfirmed->_config->limits({ default => { count => -1 } });
319
320
$rqBackendTestUnconfirmed->backend_create({
321
    stage  => "commit",
322
    method => "create",
323
    other  => {
324
        id     => 1234,
325
        title  => "Ordering ILLs using Koha",
326
        author => "A.N. Other",
327
    },
328
});
329
is(
330
    $rqBackendTestUnconfirmed->backend_status->{error},
331
    1,
332
    "backend_status: error for invalid request."
333
);
334
335
## Test backend_cancel
336
337
# is(
338
#     $rqBackendTest->backend_cancel->{error},
339
#     0,
340
#     "backend_cancel: Successfully cancelling request."
341
# );
342
# is_deeply(
343
#     $rqBackendTest->backend_cancel->{value},
344
#     {
345
#         id     => 1234,
346
#         title  => "Ordering ILLs using Koha",
347
#         author => "A.N. Other",
348
#     },
349
#     "backend_cancel: Cancel request."
350
# );
351
352
# Now test trying to cancel non-confirmed request.
353
is(
354
    $rqBackendTestUnconfirmed->backend_cancel->{error},
355
    1,
356
    "backend_cancel: error for invalid request."
357
);
358
is_deeply(
359
    $rqBackendTestUnconfirmed->backend_cancel->{value},
360
    {},
361
    "backend_cancel: Cancel request."
362
);
363
364
# Test Helpers
365
366
## Test getCensorNotesStaff
367
368
is($rqBackendTest->getCensorNotesStaff, 1, "getCensorNotesStaff: Public.");
369
$rqBackendTest->_config->censorship({
370
    censor_notes_staff => 0,
371
    censor_reply_date  => 0,
372
});
373
is($rqBackendTest->getCensorNotesStaff, 0, "getCensorNotesStaff: Censored.");
374
375
## Test getCensorNotesStaff
376
377
is($rqBackendTest->getDisplayReplyDate, 1, "getDisplayReplyDate: Yes.");
378
$rqBackendTest->_config->censorship({
379
    censor_notes_staff => 0,
380
    censor_reply_date  => 1,
381
});
382
is($rqBackendTest->getDisplayReplyDate, 0, "getDisplayReplyDate: No.");
383
384
# FIXME: These should be handled by the templates.
385
# # Test Output Helpers
386
387
# ## Test getStatusSummary
388
389
# $rqBackendTest->medium("Book")->store;
390
# is_deeply(
391
#     $rqBackendTest->getStatusSummary({brw => 0}),
392
#     {
393
#         biblionumber => ["Biblio Number", undef],
394
#         borrowernumber => ["Borrower Number", $patron->{borrowernumber}],
395
#         id => ["Request Number", $rqBackendTest->illrequest_id],
396
#         prefix_id => ["Request Number", $rqBackendTest->illrequest_id],
397
#         reqtype => ["Request Type", "Book"],
398
#         status => ["Status", "REQREV"],
399
#     },
400
#     "getStatusSummary: Without Borrower."
401
# );
402
403
# is_deeply(
404
#     $rqBackendTest->getStatusSummary({brw => 1}),
405
#     {
406
#         biblionumber => ["Biblio Number", undef],
407
#         borrower => ["Borrower", Koha::Patrons->find($patron->{borrowernumber})],
408
#         id => ["Request Number", $rqBackendTest->illrequest_id],
409
#         prefix_id => ["Request Number", $rqBackendTest->illrequest_id],
410
#         reqtype => ["Request Type", "Book"],
411
#         status => ["Status", "REQREV"],
412
#     },
413
#     "getStatusSummary: With Borrower."
414
# );
415
416
# ## Test getFullStatus
417
418
# is_deeply(
419
#     $rqBackendTest->getFullStatus({brw => 0}),
420
#     {
421
#         biblionumber => ["Biblio Number", undef],
422
#         borrowernumber => ["Borrower Number", $patron->{borrowernumber}],
423
#         id => ["Request Number", $rqBackendTest->illrequest_id],
424
#         prefix_id => ["Request Number", $rqBackendTest->illrequest_id],
425
#         reqtype => ["Request Type", "Book"],
426
#         status => ["Status", "REQREV"],
427
#         placement_date => ["Placement Date", $rqBackendTest->placed],
428
#         completion_date => ["Completion Date", $rqBackendTest->completed],
429
#         ts => ["Timestamp", $rqBackendTest->updated],
430
#         branch => ["Branch", $rqBackendTest->branch_id],
431
#     },
432
#     "getFullStatus: Without Borrower."
433
# );
434
435
# is_deeply(
436
#     $rqBackendTest->getFullStatus({brw => 1}),
437
#     {
438
#         biblionumber => ["Biblio Number", undef],
439
#         borrower => ["Borrower", Koha::Patrons->find($patron->{borrowernumber})],
440
#         id => ["Request Number", $rqBackendTest->illrequest_id],
441
#         prefix_id => ["Request Number", $rqBackendTest->illrequest_id],
442
#         reqtype => ["Request Type", "Book"],
443
#         status => ["Status", "REQREV"],
444
#         placement_date => ["Placement Date", $rqBackendTest->placed],
445
#         completion_date => ["Completion Date", $rqBackendTest->completed],
446
#         ts => ["Timestamp", $rqBackendTest->updated],
447
#         branch => ["Branch", $rqBackendTest->branch_id],
448
#     },
449
#     "getFullStatus: With Borrower."
450
# );
451
452
## Test available_backends
453
subtest 'available_backends' => sub {
454
    plan tests => 1;
455
456
    my $rq = Koha::Illrequest->new({
457
        borrower_id => $patron->{borrowernumber},
458
        branch_id   => $branch->{branchcode},
459
    })->store;
460
461
    my @backends = ();
462
    my $backenddir = $rq->_config->backend_dir;
463
    @backends = <$backenddir/*> if ( $backenddir );
464
    @backends = map { basename($_) } @backends;
465
    is_deeply(\@backends, $rq->available_backends,
466
              "Correctly identify available backends.");
467
468
};
469
470
## Test capabilities
471
472
my $rqCapTest = Koha::Illrequest->new({
473
    borrower_id => $patron->{borrowernumber},
474
    branch_id   => $branch->{branchcode},
475
})->store;
476
477
is( keys %{$rqCapTest->_core_status_graph},
478
    @{[ 'NEW', 'REQ', 'REVREQ', 'QUEUED', 'CANCREQ', 'COMP', 'KILL' ]},
479
    "Complete list of core statuses." );
480
481
my $union = $rqCapTest->_status_graph_union(
482
    $rqCapTest->_core_status_graph,
483
    {
484
        TEST => {
485
            prev_actions => [ 'COMP' ],
486
            id           => 'TEST',
487
            name         => "Test",
488
            ui_method_name => "Perform test",
489
            method         => 'test',
490
            next_actions   => [ 'NEW' ]
491
        },
492
        BLAH => {
493
            prev_actions => [ 'COMP' ],
494
            id           => 'BLAH',
495
            name         => "BLAH",
496
            ui_method_name => "Perform test",
497
            method         => 'test',
498
            next_actions   => [ 'NEW' ]
499
        },
500
    }
501
);
502
ok( ( grep 'BLAH', @{$union->{COMP}->{next_actions}} and
503
          grep 'TEST', @{$union->{COMP}->{next_actions}} ),
504
    "next_actions: updated." );
505
ok( ( grep 'BLAH', @{$union->{NEW}->{prev_actions}} and
506
          grep 'TEST', @{$union->{NEW}->{prev_actions}} ),
507
    "next_actions: updated." );
508
509
## Test available_backends
510
subtest 'available_actions' => sub {
511
    plan tests => 1;
512
513
    my $rq = Koha::Illrequest->new({
514
        borrower_id => $patron->{borrowernumber},
515
        branch_id   => $branch->{branchcode},
516
        status      => 'NEW',
517
    })->store;
518
519
    is_deeply(
520
        $rq->available_actions,
521
        [
522
            {
523
                prev_actions   => [ 'NEW', 'REQREV', 'QUEUED' ],
524
                id             => 'REQ',
525
                name           => 'Requested',
526
                ui_method_name => 'Create request',
527
                method         => 'confirm',
528
                next_actions   => [ 'REQREV' ],
529
            },
530
            {
531
                prev_actions   => [ 'CANCREQ', 'QUEUED', 'REQREV', 'NEW' ],
532
                id             => 'KILL',
533
                name           => 0,
534
                ui_method_name => 'Delete request',
535
                method         => 'delete',
536
                next_actions   => [ ],
537
            }
538
        ]
539
    );
540
};
541
542
$schema->storage->txn_rollback;
543
544
1;
(-)a/t/db_dependent/Illrequest/Config.t (+344 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use Test::Exception;
21
use Test::More;
22
use Test::Warn;
23
24
# Some data structures that will be repeatedly referenced
25
my $defaults  = {
26
    api_key  => "564euie",
27
    api_auth => "unidaenudvnled",
28
};
29
my $application = {
30
    key  => "6546uedrun",
31
    auth => "edutrineadue",
32
};
33
# Simulate $from_xml
34
my $params = {
35
    application            => $application,
36
    backend                => "Dummy",
37
    configuration          => $defaults,
38
    reply_date             => "hide",
39
    staff_request_comments => "hide",
40
};
41
my $first_branch = {
42
    code => "test", api_key => "dphügnpgüffq", api_auth => "udrend"
43
};
44
my $second_branch = {
45
    code          => "second",
46
    api_key       => "eduirn",
47
    api_auth      => "eudtireand",
48
    request_limit => { count => "5" },
49
};
50
51
BEGIN {
52
    use_ok('Koha::Illrequest::Config');
53
}
54
55
my $config = Koha::Illrequest::Config->new(1); # with test_mode enabled.
56
isa_ok($config, 'Koha::Illrequest::Config');
57
58
# _load_configuration
59
is_deeply(
60
    Koha::Illrequest::Config::_load_configuration($params),
61
    {
62
        api_url         => 'http://apitest.bldss.bl.uk',
63
        backend         => 'Dummy',
64
        censorship      => {
65
            censor_notes_staff => 1,
66
            censor_reply_date => 1,
67
        },
68
        credentials     => {
69
            api_application => $application,
70
            api_keys        => { default => $defaults },
71
        },
72
        default_formats => {},
73
        digital_recipients => {},
74
        library_privileges => {},
75
        limits          => {},
76
        prefixes           => {},
77
        spec_file       => undef,
78
    },
79
    "Basic _load_configuration"
80
);
81
82
$params->{configuration}->{request_limit}->{count} = 10;
83
is_deeply(
84
    Koha::Illrequest::Config::_load_configuration($params),
85
    {
86
        api_url            => 'http://apitest.bldss.bl.uk',
87
        backend            => 'Dummy',
88
        censorship         => {
89
            censor_notes_staff => 1,
90
            censor_reply_date => 1,
91
        },
92
        credentials        => {
93
            api_application => $application,
94
            api_keys        => {
95
                default => {
96
                    api_auth => $defaults->{api_auth},
97
                    api_key  => $defaults->{api_key},
98
                }
99
            },
100
        },
101
        default_formats    => {},
102
        digital_recipients => {},
103
        library_privileges => {},
104
        limits             => { default => { count => 10 } },
105
        prefixes           => {},
106
        spec_file          => undef,
107
    },
108
    "Basic _load_configuration, with limit"
109
);
110
111
$params->{configuration}->{branch} = $first_branch;
112
is_deeply(
113
    Koha::Illrequest::Config::_load_configuration($params),
114
    {
115
        api_url         => 'http://apitest.bldss.bl.uk',
116
        backend         => 'Dummy',
117
        censorship      => {
118
            censor_notes_staff => 1,
119
            censor_reply_date => 1,
120
        },
121
        credentials     => {
122
            api_keys        => {
123
                default => {
124
                    api_key  => $defaults->{api_key},
125
                    api_auth => $defaults->{api_auth},
126
                },
127
                $first_branch->{code} => {
128
                    api_key  => $first_branch->{api_key},
129
                    api_auth => $first_branch->{api_auth},
130
                },
131
            },
132
            api_application => $application,
133
        },
134
        default_formats => {},
135
        digital_recipients => {},
136
        library_privileges => {},
137
        limits          => { default => { count => 10 } },
138
        prefixes           => {},
139
        spec_file       => undef,
140
    },
141
    "Single Branch _load_configuration"
142
);
143
144
$params->{configuration}->{branch} = [ $first_branch, $second_branch ];
145
is_deeply(
146
    Koha::Illrequest::Config::_load_configuration($params),
147
    {
148
        api_url         => 'http://apitest.bldss.bl.uk',
149
        credentials     => {
150
            api_keys        => {
151
                default => {
152
                    api_key  => $defaults->{api_key},
153
                    api_auth => $defaults->{api_auth},
154
                },
155
                $first_branch->{code} => {
156
                    api_key  => $first_branch->{api_key},
157
                    api_auth => $first_branch->{api_auth},
158
                },
159
                $second_branch->{code} => {
160
                    api_key  => $second_branch->{api_key},
161
                    api_auth => $second_branch->{api_auth},
162
                },
163
            },
164
            api_application => $application,
165
        },
166
        backend         => 'Dummy',
167
        censorship      => {
168
            censor_notes_staff => 1,
169
            censor_reply_date => 1,
170
        },
171
        default_formats => {},
172
        digital_recipients => {},
173
        library_privileges => {},
174
        limits          => {
175
            default => {count => 10 },
176
            branch  => {
177
                $second_branch->{code} => {count => 5 },
178
            },
179
        },
180
        prefixes           => {},
181
        spec_file       => undef,
182
    },
183
    "Multi Branch _load_configuration"
184
);
185
186
dies_ok { Koha::Illrequest::Config::_load_configuration($params, 1) }
187
    "Unmediated, missing config _load_configuration";
188
189
$params->{configuration}->{default_formats} = {
190
    format => 1, quality => 1, quantity => 1, service => 1, speed => 1
191
};
192
is_deeply(
193
    Koha::Illrequest::Config::_load_configuration($params, 1),
194
    {
195
        api_url         => 'http://apitest.bldss.bl.uk',
196
        backend         => 'Dummy',
197
        censorship      => {
198
            censor_notes_staff => 1,
199
            censor_reply_date => 1,
200
        },
201
        credentials     => {
202
            api_keys        => {
203
                default => {
204
                    api_key  => $defaults->{api_key},
205
                    api_auth => $defaults->{api_auth},
206
                },
207
                $first_branch->{code} => {
208
                    api_key  => $first_branch->{api_key},
209
                    api_auth => $first_branch->{api_auth},
210
                },
211
                $second_branch->{code} => {
212
                    api_key  => $second_branch->{api_key},
213
                    api_auth => $second_branch->{api_auth},
214
                },
215
            },
216
            api_application => $application,
217
        },
218
        default_formats => {
219
            default => {
220
                format => 1,
221
                quality => 1,
222
                quantity => 1,
223
                service => 1,
224
                speed => 1
225
            }
226
        },
227
        digital_recipients => {},
228
        library_privileges => {},
229
        limits          => {
230
            default => {count => 10 },
231
            branch  => {
232
                $second_branch->{code} => {count => 5 },
233
            },
234
        },
235
        prefixes           => {},
236
        spec_file       => undef,
237
    },
238
    "default_formats, default only _load_configuration"
239
);
240
241
# getDefaultFormats
242
dies_ok { $config->getLimitRules('wrongType') }
243
    "Faulty getDefaultFormats";
244
245
$config->{configuration} =
246
    Koha::Illrequest::Config::_load_configuration($params);
247
is_deeply(
248
    $config->getDefaultFormats('brw_cat'),
249
    {
250
        default => {
251
            format => 1,
252
            quality => 1,
253
            quantity => 1,
254
            service => 1,
255
            speed => 1
256
        }
257
    },
258
    "Default getDefaultFormats"
259
);
260
261
# getLimitRules
262
dies_ok { $config->getLimitRules('wrongType') }
263
    "Faulty getLimitRules";
264
265
$config->{configuration} =
266
    Koha::Illrequest::Config::_load_configuration($params);
267
is_deeply(
268
    $config->getLimitRules('branch'),
269
    {
270
        default => { count => 10 },
271
        second  => { count => 5 },
272
    },
273
    "second branch getLimitRules"
274
);
275
276
is_deeply(
277
    $config->getLimitRules('brw_cat'),
278
    {
279
        default => { count => 10 },
280
    },
281
    "empty brw_cat getLimitRules"
282
);
283
284
# getCredentials
285
$params = {
286
    application            => $application,
287
    backend                => 'Dummy',
288
    configuration          => {},
289
    reply_date             => "hide",
290
    staff_request_comments => "hide",
291
};
292
$config->{configuration} =
293
    Koha::Illrequest::Config::_load_configuration($params);
294
is_deeply(
295
    $config->getCredentials,
296
    {
297
        api_key              => 0,
298
        api_key_auth         => 0,
299
        api_application      => $application->{key},
300
        api_application_auth => $application->{auth},
301
    },
302
    "getCredentials, no creds, just App."
303
);
304
305
$params->{configuration} = $defaults;
306
$config->{configuration} =
307
    Koha::Illrequest::Config::_load_configuration($params),
308
is_deeply(
309
    $config->getCredentials,
310
    {
311
        api_key              => $defaults->{api_key},
312
        api_key_auth         => $defaults->{api_auth},
313
        api_application      => $application->{key},
314
        api_application_auth => $application->{auth},
315
    },
316
    "getCredentials, default creds & App."
317
);
318
319
$params->{configuration}->{branch} = $first_branch;
320
$config->{configuration} =
321
    Koha::Illrequest::Config::_load_configuration($params),
322
is_deeply(
323
    $config->getCredentials($first_branch->{code}),
324
    {
325
        api_key              => $first_branch->{api_key},
326
        api_key_auth         => $first_branch->{api_auth},
327
        api_application      => $application->{key},
328
        api_application_auth => $application->{auth},
329
    },
330
    "getCredentials, $first_branch->{code} creds & App."
331
);
332
333
is_deeply(
334
    $config->getCredentials("random"),
335
    {
336
        api_key              => $defaults->{api_key},
337
        api_key_auth         => $defaults->{api_auth},
338
        api_application      => $application->{key},
339
        api_application_auth => $application->{auth},
340
    },
341
    "getCredentials, fallback creds & app."
342
);
343
344
done_testing;
(-)a/t/db_dependent/Illrequest/Dummy.t (+378 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
#
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it under the
6
# terms of the GNU General Public License as published by the Free Software
7
# Foundation; either version 2 of the License, or (at your option) any later
8
# version.
9
#
10
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License along
15
# with Koha; if not, write to the Free Software Foundation, Inc.,
16
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
#
18
19
use Modern::Perl;
20
21
use Koha::Database;
22
use Koha::Illrequests;
23
use t::lib::TestBuilder;
24
25
use Test::More tests => 15;
26
27
# This is a set of basic tests for the Dummy backend, largely to provide
28
# sanity checks for testing at the higher level Illrequest.pm level.
29
#
30
# The Dummy backend is rather simple, but provides correctly formatted
31
# response values, that other backends can model themselves after.
32
33
use_ok('Koha::Illrequest::Backend::Dummy');
34
35
my $backend = Koha::Illrequest::Backend::Dummy->new;
36
37
isa_ok($backend, 'Koha::Illrequest::Backend::Dummy');
38
39
40
my $schema = Koha::Database->new->schema;
41
$schema->storage->txn_begin;
42
43
my $builder = t::lib::TestBuilder->new;
44
45
my $patron = $builder->build({ source => 'Borrower' });
46
my $branch = $builder->build({ source => 'Branch' });
47
48
my $illRequest = $builder->build({
49
    source => 'Illrequest',
50
    value => {
51
        borrowernumber  => $patron->{borrowernumber},
52
        branch          => $branch->{branchcode},
53
    }
54
});
55
my $mock_request = Koha::Illrequests->find($illRequest->{illrequest_id});
56
$mock_request->_config->backend("Dummy");
57
$mock_request->_config->limits({ default => { count => -1 } });
58
59
# Test Create
60
my $rq = $backend->create({
61
    request    => $mock_request,
62
    method     => 'create',
63
    stage      => 'search_form',
64
    other      => undef,
65
});
66
67
is_deeply(
68
    $rq,
69
    {
70
        error   => 0,
71
        status  => '',
72
        message => '',
73
        method  => 'create',
74
        stage   => 'search_form',
75
        value   => {},
76
    },
77
    "Search_Form stage of create method."
78
);
79
80
$rq = $backend->create({
81
    request    => $mock_request,
82
    method     => 'create',
83
    stage      => 'search_results',
84
    other      => { search => "interlibrary loans" },
85
});
86
87
is_deeply(
88
    $rq,
89
    {
90
        error   => 0,
91
        status  => '',
92
        message => '',
93
        method  => 'create',
94
        stage   => 'search_results',
95
        value   => [
96
            {
97
                id     => 1234,
98
                title  => "Ordering ILLs using Koha",
99
                author => "A.N. Other",
100
            },
101
            {
102
                id     => 5678,
103
                title  => "Interlibrary loans in Koha",
104
                author => "A.N. Other",
105
            },
106
        ],
107
    },
108
    "Search_Results stage of create method."
109
);
110
111
$rq = $backend->create({
112
    request    => $mock_request,
113
    method     => 'create',
114
    stage      => 'commit',
115
    other      => {
116
        id     => 1234,
117
        title  => "Ordering ILLs using Koha",
118
        author => "A.N. Other",
119
    },
120
});
121
122
is_deeply(
123
    $rq,
124
    {
125
        error   => 0,
126
        status  => '',
127
        message => '',
128
        method  => 'create',
129
        stage   => 'commit',
130
        value   => {
131
            id     => 1234,
132
            title  => "Ordering ILLs using Koha",
133
            author => "A.N. Other"
134
        },
135
    },
136
    "Commit stage of create method."
137
);
138
139
$rq = $backend->create({
140
    request    => $mock_request,
141
    method     => 'create',
142
    stage      => 'unknown_stage',
143
    other      => {
144
        id     => 1234,
145
        title  => "Ordering ILLs using Koha",
146
        author => "A.N. Other",
147
    },
148
});
149
150
is_deeply(
151
    $rq,
152
    {
153
        error   => 1,
154
        status  => 'unknown_stage',
155
        message => '',
156
        method  => 'create',
157
        stage   => 'unknown_stage',
158
        value   => {},
159
    },
160
    "Commit stage of create method."
161
);
162
163
# Test Confirm
164
165
$rq = $backend->confirm({
166
    request    => $mock_request,
167
    other      => undef,
168
});
169
170
is_deeply(
171
    $rq,
172
    {
173
        error   => 0,
174
        status  => '',
175
        message => '',
176
        method  => 'confirm',
177
        stage   => 'commit',
178
        value   => {
179
            id     => 1234,
180
            title  => "Ordering ILLs using Koha",
181
            author => "A.N. Other",
182
            status => "On order",
183
            cost   => "30 GBP",
184
        },
185
    },
186
    "Basic confirm method."
187
);
188
189
# Test List
190
191
is_deeply(
192
    $backend->list,
193
    {
194
        error   => 0,
195
        status  => '',
196
        message => '',
197
        method  => 'list',
198
        stage   => 'commit',
199
        value   => {
200
            1 => {
201
                id     => 1234,
202
                title  => "Ordering ILLs using Koha",
203
                author => "A.N. Other",
204
                status => "On order",
205
                cost   => "30 GBP",
206
            },
207
        },
208
    },
209
    "Basic list method."
210
);
211
212
# Test Renew
213
214
is_deeply(
215
    $backend->renew({
216
        request    => $mock_request,
217
        other      => undef,
218
    }),
219
    {
220
        error   => 1,
221
        status  => 'not_renewed',
222
        message => 'Order not yet delivered.',
223
        method  => 'renew',
224
        stage   => 'commit',
225
        value   => {
226
            id     => 1234,
227
            title  => "Ordering ILLs using Koha",
228
            author => "A.N. Other",
229
            status => "On order",
230
        },
231
    },
232
    "Basic renew method."
233
);
234
235
Koha::Illrequestattributes->find({
236
    illrequest_id => $mock_request->illrequest_id,
237
    type          => "status"
238
})->set({ value => "Delivered" })->store;
239
240
is_deeply(
241
    $backend->renew({
242
        request    => $mock_request,
243
        other      => undef,
244
    }),
245
    {
246
        error   => 0,
247
        status  => '',
248
        message => '',
249
        method  => 'renew',
250
        stage   => 'commit',
251
        value   => {
252
            id     => 1234,
253
            title  => "Ordering ILLs using Koha",
254
            author => "A.N. Other",
255
            status => "Renewed",
256
        },
257
    },
258
    "Modified renew method."
259
);
260
261
# Test Update_Status
262
263
is_deeply(
264
    $backend->update_status({
265
        request    => $mock_request,
266
        other      => undef,
267
    }),
268
    {
269
        error   => 1,
270
        status  => 'failed_update_hook',
271
        message => 'Fake reason for failing to perform update operation.',
272
        method  => 'update_status',
273
        stage   => 'commit',
274
        value   => {
275
            id     => 1234,
276
            title  => "Ordering ILLs using Koha",
277
            author => "A.N. Other",
278
            status => "Delivered",
279
        },
280
    },
281
    "Basic update_status method."
282
);
283
284
# FIXME: Perhaps we should add a test checking for specific status code
285
# transitions.
286
287
# Test Cancel
288
289
is_deeply(
290
    $backend->cancel({
291
        request    => $mock_request,
292
        other      => undef,
293
    }),
294
    {
295
        error   => 0,
296
        status  => '',
297
        message => '',
298
        method  => 'cancel',
299
        stage   => 'commit',
300
        value   => {
301
            id     => 1234,
302
            title  => "Ordering ILLs using Koha",
303
            author => "A.N. Other",
304
            status => "Delivered",
305
        },
306
    },
307
    "Basic cancel method."
308
);
309
310
is_deeply(
311
    $backend->cancel({
312
        request    => $mock_request,
313
        other      => undef,
314
    }),
315
    {
316
        error   => 1,
317
        status  => 'unknown_request',
318
        message => 'Cannot cancel an unknown request.',
319
        method  => 'cancel',
320
        stage   => 'commit',
321
        value   => {
322
            id     => 1234,
323
            title  => "Ordering ILLs using Koha",
324
            author => "A.N. Other",
325
        },
326
    },
327
    "Attempt to cancel an unconfirmed request."
328
);
329
330
# Test Status
331
332
is_deeply(
333
    $backend->status({
334
        request    => $mock_request,
335
        other      => undef,
336
    }),
337
    {
338
        error   => 1,
339
        status  => 'unknown_request',
340
        message => 'Cannot query status of an unknown request.',
341
        method  => 'status',
342
        stage   => 'commit',
343
        value   => {
344
            id     => 1234,
345
            title  => "Ordering ILLs using Koha",
346
            author => "A.N. Other",
347
        },
348
    },
349
    "Attempt to get status of an unconfirmed request."
350
);
351
352
$rq = $backend->confirm({
353
    request    => $mock_request,
354
    other      => undef,
355
});
356
357
is_deeply(
358
    $backend->status({
359
        request    => $mock_request,
360
        other      => undef,
361
    }),
362
    {
363
        error   => 0,
364
        status  => '',
365
        message => '',
366
        method  => 'status',
367
        stage   => 'commit',
368
        value   => {
369
            id     => 1234,
370
            title  => "Ordering ILLs using Koha",
371
            author => "A.N. Other",
372
            status => "On order",
373
        },
374
    },
375
    "Basic status method."
376
);
377
378
1;
(-)a/t/db_dependent/api/v1/illrequests.t (-1 / +136 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/env perl
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it under the
6
# terms of the GNU General Public License as published by the Free Software
7
# Foundation; either version 3 of the License, or (at your option) any later
8
# version.
9
#
10
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License along
15
# with Koha; if not, write to the Free Software Foundation, Inc.,
16
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18
use Modern::Perl;
19
20
use Test::More tests => 1;
21
use Test::Mojo;
22
use Test::Warn;
23
24
use t::lib::TestBuilder;
25
use t::lib::Mocks;
26
27
use C4::Auth;
28
use Koha::Illrequests;
29
30
my $schema  = Koha::Database->new->schema;
31
my $builder = t::lib::TestBuilder->new;
32
33
# FIXME: sessionStorage defaults to mysql, but it seems to break transaction handling
34
# this affects the other REST api tests
35
t::lib::Mocks::mock_preference( 'SessionStorage', 'tmp' );
36
37
my $remote_address = '127.0.0.1';
38
my $t              = Test::Mojo->new('Koha::REST::V1');
39
40
subtest 'list() tests' => sub {
41
42
    plan tests => 6;
43
44
    $schema->storage->txn_begin;
45
46
    Koha::Illrequests->search->delete;
47
    my ( $borrowernumber, $session_id ) =
48
      create_user_and_session( { authorized => 1 } );
49
50
    ## Authorized user tests
51
    # No requests, so empty array should be returned
52
    my $tx = $t->ua->build_tx( GET => '/api/v1/illrequests' );
53
    $tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
54
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
55
    $t->request_ok($tx)->status_is(200)->json_is( [] );
56
57
#    my $city_country = 'France';
58
#    my $city         = $builder->build(
59
#        { source => 'City', value => { city_country => $city_country } } );
60
#
61
#    # One city created, should get returned
62
#    $tx = $t->ua->build_tx( GET => '/api/v1/cities' );
63
#    $tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
64
#    $tx->req->env( { REMOTE_ADDR => $remote_address } );
65
#    $t->request_ok($tx)->status_is(200)->json_is( [$city] );
66
#
67
#    my $another_city = $builder->build(
68
#        { source => 'City', value => { city_country => $city_country } } );
69
#    my $city_with_another_country = $builder->build( { source => 'City' } );
70
#
71
#    # Two cities created, they should both be returned
72
#    $tx = $t->ua->build_tx( GET => '/api/v1/cities' );
73
#    $tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
74
#    $tx->req->env( { REMOTE_ADDR => $remote_address } );
75
#    $t->request_ok($tx)->status_is(200)
76
#      ->json_is( [ $city, $another_city, $city_with_another_country ] );
77
#
78
#    # Filtering works, two cities sharing city_country
79
#    $tx =
80
#      $t->ua->build_tx( GET => "/api/v1/cities?city_country=" . $city_country );
81
#    $tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
82
#    $tx->req->env( { REMOTE_ADDR => $remote_address } );
83
#    my $result =
84
#      $t->request_ok($tx)->status_is(200)->json_is( [ $city, $another_city ] );
85
#
86
#    $tx = $t->ua->build_tx(
87
#        GET => "/api/v1/cities?city_name=" . $city->{city_name} );
88
#    $tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
89
#    $tx->req->env( { REMOTE_ADDR => $remote_address } );
90
#    $t->request_ok($tx)->status_is(200)->json_is( [$city] );
91
92
    # Warn on unsupported query parameter
93
    $tx = $t->ua->build_tx( GET => '/api/v1/illrequests?request_blah=blah' );
94
    $tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
95
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
96
    $t->request_ok($tx)->status_is(400)->json_is(
97
        [{ path => '/query/request_blah', message => 'Malformed query string'}]
98
    );
99
100
    $schema->storage->txn_rollback;
101
};
102
103
sub create_user_and_session {
104
105
    my $args  = shift;
106
    my $flags = ( $args->{authorized} ) ? $args->{authorized} : 0;
107
    my $dbh   = C4::Context->dbh;
108
109
    my $user = $builder->build(
110
        {
111
            source => 'Borrower',
112
            value  => {
113
                flags => $flags
114
            }
115
        }
116
    );
117
118
    # Create a session for the authorized user
119
    my $session = C4::Auth::get_session('');
120
    $session->param( 'number',   $user->{borrowernumber} );
121
    $session->param( 'id',       $user->{userid} );
122
    $session->param( 'ip',       '127.0.0.1' );
123
    $session->param( 'lasttime', time() );
124
    $session->flush;
125
126
    if ( $args->{authorized} ) {
127
        $dbh->do( "
128
            INSERT INTO user_permissions (borrowernumber,module_bit,code)
129
            VALUES (?,3,'parameters_remaining_permissions')", undef,
130
            $user->{borrowernumber} );
131
    }
132
133
    return ( $user->{borrowernumber}, $session->id );
134
}
135
136
1;

Return to bug 7317