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

(-)a/Koha/Illrequest.pm (-6 / +8 lines)
Lines 24-29 use Try::Tiny qw( catch try ); Link Here
24
use DateTime;
24
use DateTime;
25
25
26
use C4::Letters;
26
use C4::Letters;
27
use Mojo::Util qw(deprecated);
27
28
28
use Koha::Cache::Memory::Lite;
29
use Koha::Cache::Memory::Lite;
29
use Koha::Database;
30
use Koha::Database;
Lines 177-182 sub statusalias { Link Here
177
=cut
178
=cut
178
179
179
sub illrequestattributes {
180
sub illrequestattributes {
181
    deprecated 'illrequestattributes is DEPRECATED in favor of extended_attributes';
180
    my ( $self ) = @_;
182
    my ( $self ) = @_;
181
    return Koha::Illrequestattributes->_new_from_dbic(
183
    return Koha::Illrequestattributes->_new_from_dbic(
182
        scalar $self->_result->illrequestattributes
184
        scalar $self->_result->illrequestattributes
Lines 247-266 sub library { Link Here
247
    return Koha::Library->_new_from_dbic( scalar $self->_result->library );
249
    return Koha::Library->_new_from_dbic( scalar $self->_result->library );
248
}
250
}
249
251
250
=head3 ill_extended_attributes
252
=head3 extended_attributes
251
253
252
    my $ill_extended_attributes = $request->ill_extended_attributes;
254
    my $extended_attributes = $request->extended_attributes;
253
255
254
Returns the linked I<Koha::Illrequestattributes> resultset object.
256
Returns the linked I<Koha::Illrequestattributes> resultset object.
255
257
256
=cut
258
=cut
257
259
258
sub ill_extended_attributes {
260
sub extended_attributes {
259
    my ( $self ) = @_;
261
    my ( $self ) = @_;
260
262
261
    return Koha::Illrequestattributes->_new_from_dbic(
263
    my $rs = $self->_result->extended_attributes;
262
        scalar $self->_result->ill_extended_attributes
264
    # We call search to use the filters in Koha::Illrequestattributes->search
263
    );
265
    return Koha::Illrequestattributes->_new_from_dbic($rs)->search;
264
}
266
}
265
267
266
=head3 status_alias
268
=head3 status_alias
(-)a/Koha/Illrequestattributes.pm (+16 lines)
Lines 32-37 Koha::Illrequestattributes - Koha Illrequestattributes Object class Link Here
32
32
33
=head2 Class Methods
33
=head2 Class Methods
34
34
35
=cut
36
37
=head3 search
38
39
my $attributes = Koha::Illrequestattributes->search( $params );
40
41
=cut
42
43
sub search {
44
    my ( $self, $params, $attributes ) = @_;
45
46
    unless ( exists $attributes->{order_by} ) { $attributes->{order_by} = ['me.type', 'value'] }
47
48
    return $self->SUPER::search( $params, $attributes );
49
}
50
35
=head3 type
51
=head3 type
36
52
37
=cut
53
=cut
(-)a/Koha/Schema/Result/Illrequest.pm (-1 / +1 lines)
Lines 342-348 __PACKAGE__->has_many( Link Here
342
);
342
);
343
343
344
__PACKAGE__->has_many(
344
__PACKAGE__->has_many(
345
  "ill_extended_attributes",
345
  "extended_attributes",
346
  "Koha::Schema::Result::Illrequestattribute",
346
  "Koha::Schema::Result::Illrequestattribute",
347
  { "foreign.illrequest_id" => "self.illrequest_id" },
347
  { "foreign.illrequest_id" => "self.illrequest_id" },
348
  { cascade_copy => 0, cascade_delete => 0 },
348
  { cascade_copy => 0, cascade_delete => 0 },
(-)a/admin/columns_settings.yml (-16 / +1 lines)
Lines 824-830 modules: Link Here
824
      ill-requests:
824
      ill-requests:
825
        columns:
825
        columns:
826
            -
826
            -
827
              columnname: illrequest_id
827
              columnname: ill_request_id
828
            -
828
            -
829
              columnname: metadata_author
829
              columnname: metadata_author
830
            -
830
            -
Lines 851-877 modules: Link Here
851
              columnname: library_branchname
851
              columnname: library_branchname
852
            -
852
            -
853
              columnname: status
853
              columnname: status
854
            -
855
              columnname: placed
856
              cannot_be_toggled: 1
857
              cannot_be_modified: 1
858
              is_hidden: 1
859
            -
854
            -
860
              columnname: placed_formatted
855
              columnname: placed_formatted
861
            -
862
              columnname: updated
863
              cannot_be_toggled: 1
864
              cannot_be_modified: 1
865
              is_hidden: 1
866
            -
856
            -
867
              columnname: updated_formatted
857
              columnname: updated_formatted
868
            -
858
            -
869
              columnname: replied
859
              columnname: replied
870
            -
871
              columnname: completed
872
              cannot_be_toggled: 1
873
              cannot_be_modified: 1
874
              is_hidden: 1
875
            -
860
            -
876
              columnname: completed_formatted
861
              columnname: completed_formatted
877
            -
862
            -
(-)a/api/v1/swagger/definitions/ill_request.yaml (-1 / +1 lines)
Lines 108-114 properties: Link Here
108
      - integer
108
      - integer
109
      - "null"
109
      - "null"
110
    description: The linked comment objects count (x-koha-embed)
110
    description: The linked comment objects count (x-koha-embed)
111
  ill_extended_attributes:
111
  extended_attributes:
112
    type:
112
    type:
113
      - array
113
      - array
114
      - "null"
114
      - "null"
(-)a/api/v1/swagger/paths/illrequests.yaml (-1 / +1 lines)
Lines 27-33 Link Here
27
            - biblio
27
            - biblio
28
            - comments
28
            - comments
29
            - comments+count
29
            - comments+count
30
            - ill_extended_attributes
30
            - extended_attributes
31
            - library
31
            - library
32
            - id_prefix
32
            - id_prefix
33
            - patron
33
            - patron
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/ill-list-table-strings.inc (-16 / +2 lines)
Lines 1-21 Link Here
1
<!-- ill-list-table-strings.inc -->
1
<!-- ill-list-table-strings.inc -->
2
<script>
2
<script>
3
    var ill_borrower_details = _("View patron details");
4
    var ill_biblio_details = _("View bibliographic record");
5
    var ill_statuses = {
6
        new: _("New request"),
7
        req: _("Requested"),
8
        genreq: _("Requested from partners"),
9
        rev: _("Reverted"),
10
        que: _("Queued request"),
11
        canc: _("Cancellation requested"),
12
        comp: _("Completed"),
13
        del: _("Delete request")
14
    };
15
    var ill_manage = _("Manage request");
3
    var ill_manage = _("Manage request");
16
    var ill_columns = {
4
    var ill_manage_select_backend_first = _("Select a backend first");
17
        biblio_id: _("Bibliographic record ID"),
5
    var ill_all_statuses = _("All statuses");
18
        updated: _("Updated on")
19
    };
20
</script>
6
</script>
21
<!-- / ill-list-table-strings.inc -->
7
<!-- / ill-list-table-strings.inc -->
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/ill-list-table.inc (-17 / +10 lines)
Lines 1-30 Link Here
1
[% IF prefilters.length > 0 %]
2
<table id="ill-requests" data-prefilters="[% prefilters | html %]">
3
[% ELSE %]
4
<table id="ill-requests">
1
<table id="ill-requests">
5
[% END %]
6
    <thead>
2
    <thead>
7
        <tr id="illview-header">
3
        <tr id="ill_requests_header">
8
            <th scope="col">Request ID</th>
4
            <th scope="col">Request ID</th>
9
            <th scope="col">Author</th>
5
            <th scope="col" data-datatype="related-object" data-related="extended_attributes" data-related-key="type" data-related-value="author"         data-related-search-on="value">Author</th>
10
            <th scope="col">Title</th>
6
            <th scope="col" data-datatype="related-object" data-related="extended_attributes" data-related-key="type" data-related-value="title"         data-related-search-on="value">Title</th>
11
            <th scope="col">Article title</th>
7
            <th scope="col" data-datatype="related-object" data-related="extended_attributes" data-related-key="type" data-related-value="article_title" data-related-search-on="value">Article title</th>
12
            <th scope="col">Issue</th>
8
            <th scope="col" data-datatype="related-object" data-related="extended_attributes" data-related-key="type" data-related-value="issue"         data-related-search-on="value">Issue</th>
13
            <th scope="col">Volume</th>
9
            <th scope="col" data-datatype="related-object" data-related="extended_attributes" data-related-key="type" data-related-value="volume"        data-related-search-on="value">Volume</th>
14
            <th scope="col">Year</th>
10
            <th scope="col" data-datatype="related-object" data-related="extended_attributes" data-related-key="type" data-related-value="year"          data-related-search-on="value">Year</th>
15
            <th scope="col">Pages</th>
11
            <th scope="col" data-datatype="related-object" data-related="extended_attributes" data-related-key="type" data-related-value="pages"         data-related-search-on="value">Pages</th>
16
            <th scope="col">Request type</th>
12
            <th scope="col" data-datatype="related-object" data-related="extended_attributes" data-related-key="type" data-related-value="type"          data-related-search-on="value">Request type</th>
17
            <th scope="col">Order ID</th>
13
            <th scope="col">Order ID</th>
18
            <th scope="col">Patron</th>
14
            <th scope="col">Patron</th>
19
            <th scope="col">Bibliographic record ID</th>
15
            <th scope="col">Bibliographic record ID</th>
20
            <th scope="col">Library</th>
16
            <th scope="col">Library</th>
21
            <th scope="col">Status</th>
17
            <th scope="col">Status</th>
22
            <th scope="col" class="placed">&nbsp;</th>
23
            <th scope="col" class="placed_formatted">Placed on</th>
18
            <th scope="col" class="placed_formatted">Placed on</th>
24
            <th scope="col" class="updated">&nbsp;</th>
25
            <th scope="col" class="updated_formatted">Updated on</th>
19
            <th scope="col" class="updated_formatted">Updated on</th>
26
            <th scope="col">Replied</th>
20
            <th scope="col">Replied</th>
27
            <th scope="col" class="completed">&nbsp;</th>
28
            <th scope="col" class="completed_formatted">Completed on</th>
21
            <th scope="col" class="completed_formatted">Completed on</th>
29
            <th scope="col">Access URL</th>
22
            <th scope="col">Access URL</th>
30
            <th scope="col">Cost</th>
23
            <th scope="col">Cost</th>
Lines 38-41 Link Here
38
    </thead>
31
    </thead>
39
    <tbody id="illview-body">
32
    <tbody id="illview-body">
40
    </tbody>
33
    </tbody>
41
</table>
34
</table>
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/js-biblio-format.inc (-24 / +33 lines)
Lines 13-29 Link Here
13
                return ''; // empty string for no biblio
13
                return ''; // empty string for no biblio
14
            }
14
            }
15
15
16
            var title = '<span class="biblio-title">';
16
            var title = '';
17
            if (biblio.title != null && biblio.title != '') {
17
18
                title += escape_str(biblio.title);
18
            if ( config && config.biblio_id_only ) {
19
            } else {
19
                title = escape_str(biblio.biblio_id);
20
                title += __("No title");
21
            }
20
            }
22
            title += '</span>';
21
            else {
22
                title = '<span class="biblio-title">';
23
                if (biblio.title != null && biblio.title != '') {
24
                    title += escape_str(biblio.title);
25
                } else {
26
                    title += __("No title");
27
                }
28
                title += '</span>';
23
29
24
            // add subtitle
30
                // add subtitle
25
            if (biblio.subtitle != null && biblio.subtitle != '') {
31
                if (biblio.subtitle != null && biblio.subtitle != '') {
26
                title += ' <span class="biblio-subtitle">' + escape_str(biblio.subtitle) + '</span>';
32
                    title += ' <span class="biblio-subtitle">' + escape_str(biblio.subtitle) + '</span>';
33
                }
27
            }
34
            }
28
35
29
            // set title as link
36
            // set title as link
Lines 39-61 Link Here
39
                }
46
                }
40
            }
47
            }
41
48
42
            // add medium
49
            if ( !config || !config.biblio_id_only ) {
43
            if (biblio.medium != null && biblio.medium != '') {
50
                // add medium
44
                title += ' <span class="biblio-medium">' + escape_str(biblio.medium) + '</span>';
51
                if (biblio.medium != null && biblio.medium != '') {
45
            }
52
                    title += ' <span class="biblio-medium">' + escape_str(biblio.medium) + '</span>';
46
47
            // add part numbers/names
48
            let part_numbers = (typeof biblio.part_number === 'string') ? biblio.part_number.split("|") : [];
49
            let part_names = (typeof biblio.part_name === 'string') ? biblio.part_name.split("|") : [];
50
            let i = 0;
51
            while (part_numbers[i] || part_names[i]) {
52
                if (part_numbers[i]) {
53
                    title += ' <span class="part-number">' + escape_str(part_numbers[i]) + '</span>';
54
                }
53
                }
55
                if (part_names[i]) {
54
56
                    title += ' <span class="part-name">' + escape_str(part_names[i]) + '</span>';
55
                // add part numbers/names
56
                let part_numbers = (typeof biblio.part_number === 'string') ? biblio.part_number.split("|") : [];
57
                let part_names = (typeof biblio.part_name === 'string') ? biblio.part_name.split("|") : [];
58
                let i = 0;
59
                while (part_numbers[i] || part_names[i]) {
60
                    if (part_numbers[i]) {
61
                        title += ' <span class="part-number">' + escape_str(part_numbers[i]) + '</span>';
62
                    }
63
                    if (part_names[i]) {
64
                        title += ' <span class="part-name">' + escape_str(part_names[i]) + '</span>';
65
                    }
66
                    i++;
57
                }
67
                }
58
                i++;
59
            }
68
            }
60
69
61
            return title;
70
            return title;
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/ill/ill-requests.tt (-49 / +64 lines)
Lines 68-77 Link Here
68
                                    <label for="illfilter_keyword">Keyword:</label>
68
                                    <label for="illfilter_keyword">Keyword:</label>
69
                                    <input type="text" name="illfilter_keyword" id="illfilter_keyword" />
69
                                    <input type="text" name="illfilter_keyword" id="illfilter_keyword" />
70
                                </li>
70
                                </li>
71
                                <li>
72
                                    <label for="illfilter_backend">Backend:</label>
73
                                    <select name="illfilter_backend" id="illfilter_backend">
74
                                        <option value="">All backends</option>
75
                                    </select>
76
                                </li>
71
                                <li>
77
                                <li>
72
                                    <label for="illfilter_status">Status:</label>
78
                                    <label for="illfilter_status">Status:</label>
73
                                    <select name="illfilter_status" id="illfilter_status">
79
                                    <select name="illfilter_status" id="illfilter_status">
74
                                        <option value=""></option>
75
                                    </select>
80
                                    </select>
76
                                </li>
81
                                </li>
77
                                <li>
82
                                <li>
Lines 93-99 Link Here
93
                                <li>
98
                                <li>
94
                                    <label for="illfilter_branchname">Library:</label>
99
                                    <label for="illfilter_branchname">Library:</label>
95
                                    <select name="illfilter_branchname" id="illfilter_branchname">
100
                                    <select name="illfilter_branchname" id="illfilter_branchname">
96
                                        <option value=""></option>
101
                                        <option value="">All libraries</option>
102
                                        [% PROCESS options_for_libraries libraries => Branches.all( selected => userbranch, only_from_group => 1 ) %]
97
                                    </select>
103
                                    </select>
98
                                </li>
104
                                </li>
99
                                <li>
105
                                <li>
Lines 150-156 Link Here
150
                    [% IF !whole.stage || whole.stage == 'form' %]
156
                    [% IF !whole.stage || whole.stage == 'form' %]
151
                        <h1 id="ill-issue-title">Issue requested item to [% INCLUDE 'patron-title.inc' patron = request.patron %]</h1>
157
                        <h1 id="ill-issue-title">Issue requested item to [% INCLUDE 'patron-title.inc' patron = request.patron %]</h1>
152
                        [% IF !request.biblio_id || request.biblio_id.length == 0 %]
158
                        [% IF !request.biblio_id || request.biblio_id.length == 0 %]
153
                        <div class="alert">This item cannot be checked out out as there is no bibliographic record associated with it</div>
159
                        <div class="alert">This item cannot be issued as it has no biblio record associated with it</div>
154
                        [% END %]
160
                        [% END %]
155
                        [% IF whole.value.errors.itemcount %]
161
                        [% IF whole.value.errors.itemcount %]
156
                        <div class="alert">The bibliographic record for this request has multiple items, it should only have one. Please fix this then try again.</div>
162
                        <div class="alert">The bibliographic record for this request has multiple items, it should only have one. Please fix this then try again.</div>
Lines 599-613 Link Here
599
                            <span class="fa fa-eye"></span>
605
                            <span class="fa fa-eye"></span>
600
                            Display supplier metadata
606
                            Display supplier metadata
601
                        </a>
607
                        </a>
602
                        [% IF Koha.Preference('IllLog') %]
608
                        <a title="ILL request log" id="ill-request-display-log" class="btn btn-default pull-right" href="#">
603
                            <a title="ILL request log" id="ill-request-display-log" class="btn btn-default pull-right" href="#">
609
                            <span class="fa fa-calendar"></span>
604
                                <span class="fa fa-calendar"></span>
610
                            ILL request log
605
                                ILL request log
611
                        </a>
606
                            </a>
607
                        [% END %]
608
                    </div>
612
                    </div>
609
                    <div class="page-section">
613
                    <div class="ill-view-panel panel panel-default">
610
                        <h3>Request details</h3>
614
                        <div class="panel-heading">
615
                            <h3>Request details</h3>
616
                        </div>
617
                        <div class="panel-body">
611
                            <h4>Details from library</h4>
618
                            <h4>Details from library</h4>
612
                            <div class="rows">
619
                            <div class="rows">
613
                                <ol>
620
                                <ol>
Lines 618-624 Link Here
618
                                    <li class="borrowernumber">
625
                                    <li class="borrowernumber">
619
                                        <span class="label borrowernumber">Patron:</span>
626
                                        <span class="label borrowernumber">Patron:</span>
620
                                        [% borrowerlink = "/cgi-bin/koha/members/moremember.pl" _ "?borrowernumber=" _ request.patron.borrowernumber %]
627
                                        [% borrowerlink = "/cgi-bin/koha/members/moremember.pl" _ "?borrowernumber=" _ request.patron.borrowernumber %]
621
                                        <a href="[% borrowerlink | url %]" title="View patron details">
628
                                        <a href="[% borrowerlink | url %]" title="View borrower details">
622
                                        [% request.patron.firstname _ " " _ request.patron.surname _ " [" _ request.patron.cardnumber _ "]" | html %]
629
                                        [% request.patron.firstname _ " " _ request.patron.surname _ " [" _ request.patron.cardnumber _ "]" | html %]
623
                                        </a>
630
                                        </a>
624
                                    </li>
631
                                    </li>
Lines 664-670 Link Here
664
                                        [% IF request.price_paid %][% request.price_paid | $Price %][% ELSE %]<span>N/A</span>[% END %]
671
                                        [% IF request.price_paid %][% request.price_paid | $Price %][% ELSE %]<span>N/A</span>[% END %]
665
                                    </li>
672
                                    </li>
666
                                    <li class="req_id">
673
                                    <li class="req_id">
667
                                        <span class="label req_id">Request ID:</span>
674
                                        <span class="label req_id">Request number:</span>
668
                                        [% request.id_prefix _ request.illrequest_id | html %]
675
                                        [% request.id_prefix _ request.illrequest_id | html %]
669
                                    </li>
676
                                    </li>
670
                                    <li class="notesstaff">
677
                                    <li class="notesstaff">
Lines 672-678 Link Here
672
                                        <p>[% request.notesstaff | html %]</p>
679
                                        <p>[% request.notesstaff | html %]</p>
673
                                    </li>
680
                                    </li>
674
                                    <li class="notesopac">
681
                                    <li class="notesopac">
675
                                        <span class="label notes_opac">OPAC notes:</span>
682
                                        <span class="label notes_opac">Notes:</span>
676
                                        <p>[% request.notesopac | html %]</p>
683
                                        <p>[% request.notesopac | html %]</p>
677
                                    </li>
684
                                    </li>
678
                                </ol>
685
                                </ol>
Lines 688-693 Link Here
688
                                    [% END %]
695
                                    [% END %]
689
                                </ol>
696
                                </ol>
690
                            </div>
697
                            </div>
698
                        </div>
691
                    </div>
699
                    </div>
692
700
693
                    <div id="dataPreview" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="dataPreviewLabel" aria-hidden="true">
701
                    <div id="dataPreview" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="dataPreviewLabel" aria-hidden="true">
Lines 738-777 Link Here
738
                        </div>
746
                        </div>
739
                    </div>
747
                    </div>
740
748
741
                    <div class="page-section">
749
                    <div class="ill-view-panel panel panel-default">
742
                        <h3>[% request.illcomments.count | html %] comments</h3>
750
                        <div class="panel-heading">
743
                        [% IF request.illcomments.count && request.illcomments.count > 0 %]
751
                            <h3>[% request.illcomments.count | html %] comments</h3>
744
                            [% FOREACH comment IN request.illcomments %]
752
                        </div>
745
                                <div class="rows comment_[% comment.patron.categorycode | html %]">
753
                        <div class="panel-body">
746
                                <h5>Comment by:
754
                            [% IF request.illcomments.count && request.illcomments.count > 0 %]
747
                                <a href="[% borrowerlink | url %]" title="View patron details">
755
                                [% FOREACH comment IN request.illcomments %]
748
                                [% comment.patron.firstname _ " " _ comment.patron.surname _ " [" _ comment.patron.cardnumber _ "]" | html %]</a>
756
                                    <div class="rows comment_[% comment.patron.categorycode | html %]">
749
                                [% comment.timestamp | $KohaDates with_hours => 1 %]</h5>
757
                                    <h5>Comment by:
750
                                <p>[% comment.comment | html %]</p>
758
                                    <a href="[% borrowerlink | url %]" title="View borrower details">
751
                                </div>
759
                                    [% comment.patron.firstname _ " " _ comment.patron.surname _ " [" _ comment.patron.cardnumber _ "]" | html %]</a>
760
                                    [% comment.timestamp | $KohaDates with_hours => 1 %]</h5>
761
                                    <p>[% comment.comment | html %]</p>
762
                                    </div>
763
                                [% END %]
752
                            [% END %]
764
                            [% END %]
753
                        [% END %]
765
                                <div class="rows">
754
                        <div class="rows">
766
                                    <h3><a id="toggle_addcomment" href="#">Add comment</a></h3>
755
                            <h3><a id="toggle_addcomment" href="#">Add comment</a></h3>
767
                                    <div id="addcomment" class="content_hidden">
756
                            <div id="addcomment" class="content_hidden">
768
                                        <form class="validated" method="post" action="/cgi-bin/koha/ill/ill-requests.pl">
757
                                <form class="validated" method="post" action="/cgi-bin/koha/ill/ill-requests.pl">
769
                                            <input type="hidden" value="save_comment" name="method">
758
                                    <input type="hidden" value="save_comment" name="method">
770
                                            <input type="hidden" value="[% csrf_token | html %]" name="csrf_token">
759
                                    <input type="hidden" value="[% csrf_token | html %]" name="csrf_token">
771
                                            <input type="hidden" value="[% request.illrequest_id | html %]" name="illrequest_id">
760
                                    <input type="hidden" value="[% request.illrequest_id | html %]" name="illrequest_id">
772
                                            <fieldset class="rows">
761
                                    <fieldset class="rows">
773
                                                <ol>
762
                                        <ol>
774
                                                    <li>
763
                                            <li>
775
                                                        <label class="required" for="comment">Comment: </label>
764
                                                <label class="required" for="comment">Comment: </label>
776
                                                        <textarea class="required" required="required" cols="80" rows="10" id="comment" name="comment"></textarea>
765
                                                <textarea class="required" required="required" cols="80" rows="10" id="comment" name="comment"></textarea>
777
                                                        <span class="required">Required</span>
766
                                                <span class="required">Required</span>
778
                                                    </li>
767
                                            </li>
779
                                                </ol>
768
                                        </ol>
780
                                            </fieldset>
769
                                    </fieldset>
781
                                            <fieldset class="action">
770
                                    <fieldset class="action">
782
                                                <input type="submit" class="btn btn-primary" value="Submit" />
771
                                        <input type="submit" class="btn btn-primary" value="Submit" />
783
                                            </fieldset>
772
                                    </fieldset>
784
                                        </form>
773
                                </form>
785
                                    </div>
774
                            </div>
786
                                </div>
775
                        </div>
787
                        </div>
776
                    </div>
788
                    </div>
777
789
Lines 780-791 Link Here
780
                    <h1>View ILL requests</h1>
792
                    <h1>View ILL requests</h1>
781
                    <div id="results" class="page-section">
793
                    <div id="results" class="page-section">
782
                        <h2>Details for all requests</h2>
794
                        <h2>Details for all requests</h2>
783
                        [% INCLUDE 'ill-list-table.inc' %]
795
                         [% INCLUDE 'ill-list-table.inc' %]
784
                    </div> <!-- /#results -->
796
                    </div> <!-- /#results -->
785
                [% ELSIF query_type == 'availability' %]
797
                [% ELSIF query_type == 'availability' %]
786
                    <!-- availability -->
798
                    <!-- availability -->
787
                    <h1>Availability</h1>
799
                    <h1>Availability</h1>
788
                    <div id="results" class="page-section">
800
                    <div id="results">
789
                        <h3>Displaying availability results</h3>
801
                        <h3>Displaying availability results</h3>
790
                        <form method="POST" action="/cgi-bin/koha/ill/ill-requests.pl">
802
                        <form method="POST" action="/cgi-bin/koha/ill/ill-requests.pl">
791
                            [% FOREACH key IN whole.keys %]
803
                            [% FOREACH key IN whole.keys %]
Lines 830-835 Link Here
830
842
831
[% MACRO jsinclude BLOCK %]
843
[% MACRO jsinclude BLOCK %]
832
    [% INCLUDE 'datatables.inc' %]
844
    [% INCLUDE 'datatables.inc' %]
845
    [% INCLUDE 'js-biblio-format.inc' %]
846
    [% INCLUDE 'js-patron-format.inc' %]
833
    [% INCLUDE 'columns_settings.inc' %]
847
    [% INCLUDE 'columns_settings.inc' %]
834
    [% INCLUDE 'calendar.inc' %]
848
    [% INCLUDE 'calendar.inc' %]
835
    [% INCLUDE 'select2.inc' %]
849
    [% INCLUDE 'select2.inc' %]
Lines 871-876 Link Here
871
    [% IF query_type == 'generic_confirm' && Koha.Preference('ILLCheckAvailability') %]
885
    [% IF query_type == 'generic_confirm' && Koha.Preference('ILLCheckAvailability') %]
872
        [% Asset.js("js/ill-availability-partner.js") | $raw %]
886
        [% Asset.js("js/ill-availability-partner.js") | $raw %]
873
    [% END %]
887
    [% END %]
888
874
[% END %]
889
[% END %]
875
890
876
[% TRY %]
891
[% TRY %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/ill-requests.tt (+2 lines)
Lines 56-61 Link Here
56
        [% Asset.js("js/members-menu.js") | $raw %]
56
        [% Asset.js("js/members-menu.js") | $raw %]
57
        [% INCLUDE 'datatables.inc' %]
57
        [% INCLUDE 'datatables.inc' %]
58
        [% INCLUDE 'columns_settings.inc' %]
58
        [% INCLUDE 'columns_settings.inc' %]
59
        [% INCLUDE 'js-biblio-format.inc' %]
60
        [% INCLUDE 'js-patron-format.inc' %]
59
        [% INCLUDE 'calendar.inc' %]
61
        [% INCLUDE 'calendar.inc' %]
60
        <script>
62
        <script>
61
            var prefilters = '[% prefilters | html %]';
63
            var prefilters = '[% prefilters | html %]';
(-)a/koha-tmpl/intranet-tmpl/prog/js/datatables.js (-3 / +37 lines)
Lines 560-568 function _dt_default_ajax (params){ Link Here
560
                        // escape SQL LIKE special characters %
560
                        // escape SQL LIKE special characters %
561
                        value = value.replace(/(\%|\\)/g, "\\$1");
561
                        value = value.replace(/(\%|\\)/g, "\\$1");
562
                    }
562
                    }
563
                    part[!attr.includes('.')?'me.'+attr:attr] = criteria === 'exact'
563
                    
564
                        ? value
564
                    let built_value;
565
                        : {like: (['contains', 'ends_with'].indexOf(criteria) !== -1?'%':'') + value + (['contains', 'starts_with'].indexOf(criteria) !== -1?'%':'')};
565
                    if ( col.datatype !== undefined ) {
566
                        if ( col.datatype == 'date' ) {
567
                            let rfc3339 = $date_to_rfc3339(value);
568
                            if ( rfc3339 != 'Invalid Date' ) {
569
                                built_value = rfc3339;
570
                            }
571
                        }
572
                        else if (col.datatype == 'related-object') {
573
                            let query_term = value;
574
575
                            if (criteria != 'exact') {
576
                                query_term = { like: (['contains', 'ends_with'].indexOf(criteria) !== -1 ? '%' : '') + value + (['contains', 'starts_with'].indexOf(criteria) !== -1 ? '%' : '') };
577
                            }
578
579
                            part = {
580
                                [col.related + '.' + col.relatedKey]: col.relatedValue,
581
                                [col.related + '.' + col.relatedSearchOn]: query_term
582
                            };
583
                        } else {
584
                            console.log("datatype %s not supported yet".format(col.datatype));
585
                        }
586
                    }
587
588
                    if (col.datatype != 'related-object') {
589
                        let value_part;
590
                        if ( criteria === 'exact' ) {
591
                            value_part = built_value ? [value, built_value] : value
592
                        } else {
593
                            let like = {like: (['contains', 'ends_with'].indexOf(criteria) !== -1?'%':'') + value + (['contains', 'starts_with'].indexOf(criteria) !== -1?'%':'')};
594
                            value_part = built_value ? [like, built_value] : like;
595
                        }
596
597
                        part[!attr.includes('.')?'me.'+attr:attr] = value_part;
598
                    }
599
566
                    parts.push(part);
600
                    parts.push(part);
567
                }
601
                }
568
                return parts;
602
                return parts;
(-)a/koha-tmpl/intranet-tmpl/prog/js/ill-list-table.js (-488 / +418 lines)
Lines 1-322 Link Here
1
$(document).ready(function() {
1
$(document).ready(function() {
2
3
    // Illview Datatable setup
4
5
    var table;
6
7
    // Filters that are active
8
    var activeFilters = {};
9
10
    // Get any prefilters
11
    var prefilters = $('table#ill-requests').data('prefilters');
12
13
    // Fields we need to expand (flatten)
14
    var expand = [
15
        'metadata',
16
        'patron',
17
        'library'
18
    ];
19
20
    // Expanded fields
21
    // This is auto populated
22
    var expanded = {};
23
24
    // Filterable columns
25
    var filterable = {
26
        status: {
27
            prep: function(tableData, oData) {
28
                var uniques = {};
29
                tableData.forEach(function(row) {
30
                    var resolvedName;
31
                    if (row.status_alias) {
32
                        resolvedName = row.status_alias.lib;
33
                    } else {
34
                        resolvedName = getStatusName(
35
                            row.capabilities[row.status].name,
36
                            row
37
                        );
38
                    }
39
                    uniques[resolvedName] = 1
40
                });
41
                Object.keys(uniques).sort().forEach(function(unique) {
42
                    $('#illfilter_status').append(
43
                        '<option value="' + unique  +
44
                        '">' + unique +  '</option>'
45
                    );
46
                });
47
            },
48
            listener: function() {
49
                var me = 'status';
50
                $('#illfilter_status').change(function() {
51
                    var sel = $('#illfilter_status option:selected').val();
52
                    if (sel && sel.length > 0) {
53
                        activeFilters[me] = function() {
54
                            table.api().column(13).search(sel);
55
                        }
56
                    } else {
57
                        if (activeFilters.hasOwnProperty(me)) {
58
                            delete activeFilters[me];
59
                        }
60
                    }
61
                });
62
            },
63
            clear: function() {
64
                $('#illfilter_status').val('');
65
            }
66
        },
67
        pickupBranch: {
68
            prep: function(tableData, oData) {
69
                var uniques = {};
70
                tableData.forEach(function(row) {
71
                    uniques[row.library_branchname] = 1
72
                });
73
                Object.keys(uniques).sort().forEach(function(unique) {
74
                    $('#illfilter_branchname').append(
75
                        '<option value="' + unique  +
76
                        '">' + unique +  '</option>'
77
                    );
78
                });
79
            },
80
            listener: function() {
81
                var me = 'pickupBranch';
82
                $('#illfilter_branchname').change(function() {
83
                    var sel = $('#illfilter_branchname option:selected').val();
84
                    if (sel && sel.length > 0) {
85
                        activeFilters[me] = function() {
86
                            table.api().column(12).search(sel);
87
                        }
88
                    } else {
89
                        if (activeFilters.hasOwnProperty(me)) {
90
                            delete activeFilters[me];
91
                        }
92
                    }
93
                });
94
            },
95
            clear: function() {
96
                $('#illfilter_branchname').val('');
97
            }
98
        },
99
        patron: {
100
            listener: function() {
101
                var me = 'patron';
102
                $('#illfilter_patron').change(function() {
103
                    var val = $('#illfilter_patron').val();
104
                    if (val && val.length > 0) {
105
                        activeFilters[me] = function() {
106
                            table.api().column(10).search(val);
107
                        }
108
                    } else {
109
                        if (activeFilters.hasOwnProperty(me)) {
110
                            delete activeFilters[me];
111
                        }
112
                    }
113
                });
114
            },
115
            clear: function() {
116
                $('#illfilter_patron').val('');
117
            }
118
        },
119
        keyword: {
120
            listener: function () {
121
                var me = 'keyword';
122
                $('#illfilter_keyword').change(function () {
123
                    var val = $('#illfilter_keyword').val();
124
                    if (val && val.length > 0) {
125
                        activeFilters[me] = function () {
126
                            table.api().search(val);
127
                        }
128
                    } else {
129
                        if (activeFilters.hasOwnProperty(me)) {
130
                            delete activeFilters[me];
131
                        }
132
                    }
133
                });
134
            },
135
            clear: function () {
136
                $('#illfilter_keyword').val('');
137
            }
138
        },
139
        dateModified: {
140
            clear: function() {
141
                $('#illfilter_datemodified_start, #illfilter_datemodified_end').val('');
142
            }
143
        },
144
        datePlaced: {
145
            clear: function() {
146
                $('#illfilter_dateplaced_start, #illfilter_dateplaced_end').val('');
147
            }
148
        }
149
    }; //END Filterable columns
150
151
    // Expand any fields we're expanding
152
    var expandExpand = function(row) {
153
        expand.forEach(function(thisExpand) {
154
            if (row.hasOwnProperty(thisExpand)) {
155
                if (!expanded.hasOwnProperty(thisExpand)) {
156
                    expanded[thisExpand] = [];
157
                }
158
                var expandObj = row[thisExpand];
159
                Object.keys(expandObj).forEach(
160
                    function(thisExpandCol) {
161
                        var expColName = thisExpand + '_' + thisExpandCol.replace(/\s/g,'_');
162
                        // Keep a list of fields that have been expanded
163
                        // so we can create toggle links for them
164
                        if (expanded[thisExpand].indexOf(expColName) == -1) {
165
                            expanded[thisExpand].push(expColName);
166
                        }
167
                        expandObj[expColName] =
168
                            expandObj[thisExpandCol];
169
                        delete expandObj[thisExpandCol];
170
                    }
171
                );
172
                $.extend(true, row, expandObj);
173
                delete row[thisExpand];
174
            }
175
        });
176
    };
177
    //END Expand
178
179
    // Strip the expand prefix if it exists, we do this for display
180
    var stripPrefix = function(value) {
181
        expand.forEach(function(thisExpand) {
182
            var regex = new RegExp(thisExpand + '_', 'g');
183
            value = value.replace(regex, '');
184
        });
185
        return value;
186
    };
187
188
    // Our 'render' function for borrowerlink
189
    var createPatronLink = function(data, type, row) {
190
        var patronLink = '<a title="' + ill_borrower_details + '" ' +
191
            'href="/cgi-bin/koha/members/moremember.pl?' +
192
            'borrowernumber='+row.borrowernumber+'">';
193
        if ( row.patron_firstname ) {
194
            patronLink = patronLink + row.patron_firstname + ' ';
195
        }
196
        patronLink = patronLink + row.patron_surname +
197
            ' (' + row.patron_cardnumber + ')' + '</a>';
198
        return patronLink;
199
    };
200
201
    // Our 'render' function for biblio_id
202
    var createBiblioLink = function(data, type, row) {
203
        return (row.biblio_id) ?
204
            '<a title="' + ill_biblio_details + '" ' +
205
            'href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=' +
206
            row.biblio_id + '">' +
207
            row.biblio_id +
208
            '</a>' : '';
209
    };
210
211
    // Our 'render' function for title
212
    var createTitle = function(data, type, row) {
213
        return (
214
            row.hasOwnProperty('metadata_container_title') &&
215
            row.metadata_container_title
216
        ) ? row.metadata_container_title : row.metadata_title;
217
    };
218
219
    // Render function for request ID
220
    var createRequestId = function(data, type, row) {
221
        return row.id_prefix + row.illrequest_id;
222
    };
223
224
    // Render function for type
225
    var createType = function(data, type, row) {
226
        if (!row.hasOwnProperty('metadata_Type') || !row.metadata_Type) {
227
            if (row.hasOwnProperty('medium') && row.medium) {
228
                row.metadata_Type = row.medium;
229
            } else {
230
                row.metadata_Type = null;
231
            }
232
        }
233
        return row.metadata_Type;
234
    };
235
236
    // Render function for request status
237
    var createStatus = function(data, type, row, meta) {
238
        if (row.status_alias) {
239
            return row.status_alias.lib
240
                ? row.status_alias.lib
241
                : row.status_alias.authorised_value;
242
        } else {
243
            var status_name = row.capabilities[row.status].name;
244
            return getStatusName(status_name, row);
245
        }
246
    };
247
248
    var getStatusName = function(origName, row) {
249
        switch( origName ) {
250
            case "New request":
251
                return ill_statuses.new;
252
            case "Requested":
253
                return ill_statuses.req;
254
            case "Requested from partners":
255
                var statStr = ill_statuses.genreq;
256
                if (
257
                    row.hasOwnProperty('requested_partners') &&
258
                    row.requested_partners &&
259
                    row.requested_partners.length > 0
260
                ) {
261
                    statStr += ' (' + row.requested_partners + ')';
262
                }
263
                return statStr;
264
            case "Request reverted":
265
                return ill_statuses.rev;
266
            case "Queued request":
267
                return ill_statuses.que;
268
            case "Cancellation requested":
269
                return ill_statuses.canc;
270
            case "Completed":
271
                return ill_statuses.comp;
272
            case "Delete request":
273
                return ill_statuses.del;
274
            default:
275
                return origName;
276
        }
277
    };
278
279
    // Render function for creating a row's action link
280
    var createActionLink = function(data, type, row) {
281
        return '<a class="btn btn-default btn-sm" ' +
282
            'href="/cgi-bin/koha/ill/ill-requests.pl?' +
283
            'method=illview&amp;illrequest_id=' +
284
            row.illrequest_id +
285
            '">' + ill_manage + '</a>';
286
    };
287
288
    // Columns that require special treatment
289
    var specialCols = {
290
        action: {
291
            func: createActionLink,
292
            skipSanitize: true
293
        },
294
        illrequest_id: {
295
            func: createRequestId
296
        },
297
        status: {
298
            func: createStatus
299
        },
300
        biblio_id: {
301
            name: ill_columns.biblio_id,
302
            func: createBiblioLink,
303
            skipSanitize: true
304
        },
305
        metadata_title: {
306
            func: createTitle
307
        },
308
        metadata_Type: {
309
            func: createType
310
        },
311
        updated: {
312
            name: ill_columns.updated
313
        },
314
        patron: {
315
            skipSanitize: true,
316
            func: createPatronLink
317
        }
318
    };
319
320
    // Display the modal containing request supplier metadata
2
    // Display the modal containing request supplier metadata
321
    $('#ill-request-display-log').on('click', function(e) {
3
    $('#ill-request-display-log').on('click', function(e) {
322
        e.preventDefault();
4
        e.preventDefault();
Lines 360-559 $(document).ready(function() { Link Here
360
        $('#dataPreview').modal({show:true});
42
        $('#dataPreview').modal({show:true});
361
    });
43
    });
362
44
363
    // Allow us to chain Datatable render helpers together, so we
45
    function display_extended_attribute(row, type) {
364
    // can use our custom functions and render.text(), which
46
        var arr = $.grep(row.extended_attributes, ( x => x.type === type ));
365
    // provides us with data sanitization
47
        if (arr.length > 0) {
366
    $.fn.dataTable.render.multi = function(renderArray) {
48
            return escape_str(arr[0].value);
367
        return function(d, type, row, meta) {
368
            for(var r = 0; r < renderArray.length; r++) {
369
                var toCall = renderArray[r].hasOwnProperty('display') ?
370
                    renderArray[r].display :
371
                    renderArray[r];
372
                d = toCall(d, type, row, meta);
373
            }
374
            return d;
375
        }
49
        }
50
51
        return '';
376
    }
52
    }
377
53
378
    // Get our data from the API and process it prior to passing
54
    // At the moment, the only prefilter possible is borrowernumber
379
    // it to datatables
55
    // see ill/ill-requests.pl and members/ill-requests.pl
380
    var filterParam = prefilters ? '&' + prefilters : '';
56
    let additional_prefilters = [];
381
    // Only fire the request if we're on an appropriate page
57
    if(prefilters){
382
    if (
58
            let prefilters_array = prefilters.split("&");
383
        (
59
            prefilters_array.forEach((prefilter) => {
384
            // ILL list requests page
60
                let prefilter_split = prefilter.split("=");
385
            window.location.href.match(/ill\/ill-requests\.pl/) &&
61
                additional_prefilters.push( {
386
            window.location.search.length == 0
62
                     "key": prefilter_split[0],
387
        ) ||
63
                     "value": prefilter_split[1]
388
        // Patron profile page
64
                } );
389
        window.location.href.match(/members\/ill-requests\.pl/)
65
390
    ) {
391
        var ajax = $.ajax(
392
            '/api/v1/illrequests?embed=metadata,patron,capabilities,library,status_alias,comments,requested_partners'
393
            + filterParam
394
        ).done(function() {
395
            var data = JSON.parse(ajax.responseText);
396
            // Make a copy, we'll be removing columns next and need
397
            // to be able to refer to data that has been removed
398
            var dataCopy = $.extend(true, [], data);
399
            // Expand columns that need it and create an array
400
            // of all column names
401
            $.each(dataCopy, function(k, row) {
402
                expandExpand(row);
403
            });
66
            });
67
    }
404
68
405
            // Assemble an array of column definitions for passing
69
    let additional_filters = {
406
            // to datatables
70
        "me.backend": function(){
407
            var colData = [];
71
            let backend = $("#illfilter_backend").val();
408
            var columns = table_settings['columns'];
72
            if (!backend) return "";
409
            columns.forEach(function(thisCol) {
73
            return { "=": backend  }
410
                var colName = thisCol.columnname;
74
        },
411
                // Create the base column object
75
        "me.branchcode": function(){
412
                var colObj = $.extend({}, thisCol);
76
            let branchcode = $("#illfilter_branchname").val();
413
                colObj.name = colName;
77
            if (!branchcode) return "";
414
                colObj.className = colName;
78
            return { "=": branchcode }
415
                colObj.defaultContent = '';
79
        },
416
80
        "me.borrowernumber": function(){
417
                // We may need to process the data going in this
81
            let borrowernumber_pre_filter = additional_prefilters.find(e => e.key === 'borrowernumber');
418
                // column, so do it if necessary
82
            if ( additional_prefilters.length == 0 || typeof borrowernumber_pre_filter === undefined) return "";
419
                if (
83
            return { "=": borrowernumber_pre_filter["value"] }
420
                    specialCols.hasOwnProperty(colName) &&
84
        },
421
                    specialCols[colName].hasOwnProperty('func')
85
        "-or": function(){
422
                ) {
86
            let patron = $("#illfilter_patron").val();
423
                    var renderArray = [
87
            let status = $("#illfilter_status").val();
424
                        specialCols[colName].func
88
            let filters = [];
425
                    ];
89
            let patron_sub_or = [];
426
                    if (!specialCols[colName].skipSanitize) {
90
            let status_sub_or = [];
427
                        renderArray.push(
91
            let subquery_and = [];
428
                            $.fn.dataTable.render.text()
92
429
                        );
93
            if (!patron && !status) return "";
94
95
            if(patron){
96
                const patron_search_fields = "me.borrowernumber,patron.cardnumber,patron.firstname,patron.surname";
97
                patron_search_fields.split(',').forEach(function(attr){
98
                    let operator = "=";
99
                    let patron_data = patron;
100
                    if ( attr != "me.borrowernumber" && attr != "patron.cardnumber") {
101
                        operator = "like";
102
                        patron_data = "%" + patron + "%";
430
                    }
103
                    }
104
                    patron_sub_or.push({
105
                        [attr]:{[operator]: patron_data }
106
                    });
107
                });
108
                subquery_and.push(patron_sub_or);
109
            }
431
110
432
                    colObj.render = $.fn.dataTable.render.multi(
111
            if(status){
433
                        renderArray
112
                const status_search_fields = "me.status,me.status_av";
434
                    );
113
                status_search_fields.split(',').forEach(function(attr){
435
                } else {
114
                    status_sub_or.push({
436
                    colObj.data = colName;
115
                        [attr]:{"=": status }
437
                    colObj.render = $.fn.dataTable.render.text()
116
                    });
438
                }
117
                });
439
                // Make sure properties that aren't present in the API
118
                subquery_and.push(status_sub_or);
440
                // response are populated with null to avoid Datatables
119
            }
441
                // choking on their absence
120
442
                dataCopy.forEach(function(thisData) {
121
            filters.push({"-and": subquery_and});
443
                    if (!thisData.hasOwnProperty(colName)) {
122
444
                        thisData[colName] = null;
123
            return filters;
445
                    }
124
        },
125
        "me.placed": function(){
126
            if ( additional_prefilters.length != 0 && !additional_prefilters.find(e => e.key === 'placed')) return "";
127
            let placed_start = $('#illfilter_dateplaced_start').get(0)._flatpickr.selectedDates[0];
128
            let placed_end = $('#illfilter_dateplaced_end').get(0)._flatpickr.selectedDates[0];
129
            if (!placed_start && !placed_end) return "";
130
            return {
131
                ...(placed_start && {">=": placed_start}),
132
                ...(placed_end && {"<=": placed_end})
133
            }
134
        },
135
        "me.updated": function(){
136
            if ( additional_prefilters.length != 0 && !additional_prefilters.find(e => e.key === 'updated')) return "";
137
            let updated_start = $('#illfilter_datemodified_start').get(0)._flatpickr.selectedDates[0];
138
            let updated_end = $('#illfilter_datemodified_end').get(0)._flatpickr.selectedDates[0];
139
            if (!updated_start && !updated_end) return "";
140
            // set selected datetime hours and minutes to the end of the day
141
            // to grab any request updated during that day
142
            let updated_end_value = new Date(updated_end);
143
            updated_end_value.setHours(updated_end_value.getHours()+23);
144
            updated_end_value.setMinutes(updated_end_value.getMinutes()+59);
145
            return {
146
                ...(updated_start && {">=": updated_start}),
147
                ...(updated_end && {"<=": updated_end_value})
148
            }
149
        },
150
        "-and": function(){
151
            let keyword = $("#illfilter_keyword").val();
152
            if (!keyword) return "";
153
154
            let filters = [];
155
            let subquery_and = [];
156
157
            const search_fields = "me.illrequest_id,me.borrowernumber,me.biblio_id,me.due_date,me.branchcode,library.name,me.status,me.status_alias,me.placed,me.replied,me.updated,me.completed,me.medium,me.accessurl,me.cost,me.price_paid,me.notesopac,me.notesstaff,me.orderid,me.backend,patron.firstname,patron.surname";
158
            let sub_or = [];
159
            search_fields.split(',').forEach(function(attr){
160
                sub_or.push({
161
                        [attr]:{"like":"%" + keyword + "%"}
446
                });
162
                });
447
                colData.push(colObj);
448
            });
163
            });
164
            subquery_and.push(sub_or);
165
            filters.push({"-and": subquery_and});
166
167
            const extended_attributes = "title,type,author,article_title,pages,issue,volume,year";
168
            let extended_sub_or = [];
169
            subquery_and = [];
170
            extended_sub_or.push({
171
                "extended_attributes.type": extended_attributes.split(','),
172
                "extended_attributes.value":{"like":"%" + keyword + "%"}
173
            });
174
            subquery_and.push(extended_sub_or);
449
175
450
            // Initialise the datatable
176
            filters.push({"-and": subquery_and});
451
            table = KohaTable("ill-requests", {
177
            return filters;
452
                'aoColumnDefs': [
178
        }
453
                    { // Last column shouldn't be sortable or searchable
179
    };
454
                        'aTargets': [ 'actions' ],
455
                        'bSortable': false,
456
                        'bSearchable': false
457
                    },
458
                    { // When sorting 'placed', we want to use the
459
                        // unformatted column
460
                        'aTargets': [ 'placed_formatted'],
461
                        'iDataSort': 14
462
                    },
463
                    { // When sorting 'updated', we want to use the
464
                        // unformatted column
465
                        'aTargets': [ 'updated_formatted'],
466
                        'iDataSort': 16
467
                    },
468
                    { // When sorting 'completed', we want to use the
469
                        // unformatted column
470
                        'aTargets': [ 'completed_formatted'],
471
                        'iDataSort': 19
472
                    }
473
                ],
474
                'aaSorting': [[ 16, 'desc' ]], // Default sort, updated descending
475
                'processing': true, // Display a message when manipulating
476
                'sPaginationType': "full_numbers", // Pagination display
477
                'deferRender': true, // Improve performance on big datasets
478
                'data': dataCopy,
479
                "dom": '<"top pager"<"table_entries"ilp><"table_controls"B>>tr<"bottom pager"ip>',
480
                'columns': colData,
481
                'originalData': data, // Enable render functions to access
482
                                        // our original data
483
                'initComplete': function() {
484
485
                    // Prepare any filter elements that need it
486
                    for (var el in filterable) {
487
                        if (filterable.hasOwnProperty(el)) {
488
                            if (filterable[el].hasOwnProperty('prep')) {
489
                                filterable[el].prep(dataCopy, data);
490
                            }
491
                            if (filterable[el].hasOwnProperty('listener')) {
492
                                filterable[el].listener();
493
                            }
494
                        }
495
                    }
496
180
181
    var ill_requests_table = $("#ill-requests").kohaTable({
182
        "ajax": {
183
            "url": '/api/v1/ill_requests'
184
        },
185
        "embed": [
186
            '+strings',
187
            'biblio',
188
            'comments+count',
189
            'extended_attributes',
190
            'library',
191
            'id_prefix',
192
            'patron'
193
        ],
194
        "stateSave": true, // remember state on page reload
195
        "columns": [
196
            {
197
                "data": "ill_request_id",
198
                "searchable": true,
199
                "orderable": true,
200
                "render": function( data, type, row, meta ) {
201
                    return '<a href="/cgi-bin/koha/ill/ill-requests.pl?' +
202
                            'method=illview&amp;illrequest_id=' +
203
                            encodeURIComponent(data) +
204
                            '">' + escape_str(row.id_prefix) + escape_str(data) + '</a>';
205
                }
206
            },
207
            {
208
                "data": "", // author
209
                "orderable": false,
210
                "render": function(data, type, row, meta) {
211
                    return display_extended_attribute(row, 'author');
212
                }
213
            },
214
            {
215
                "data": "", // title
216
                "orderable": false,
217
                "render": function(data, type, row, meta) {
218
                    return display_extended_attribute(row, 'title');
219
                }
220
            },
221
            {
222
                "data": "", // article_title
223
                "orderable": false,
224
                "render": function(data, type, row, meta) {
225
                    return display_extended_attribute(row, 'article_title');
226
                }
227
            },
228
            {
229
                "data": "", // issue
230
                "orderable": false,
231
                "render": function(data, type, row, meta) {
232
                    return display_extended_attribute(row, 'issue');
233
                }
234
            },
235
            {
236
                "data": "", // volume
237
                "orderable": false,
238
                "render": function(data, type, row, meta) {
239
                    return display_extended_attribute(row, 'volume');
240
                }
241
            },
242
            {
243
                "data": "",  // year
244
                "orderable": false,
245
                "render": function(data, type, row, meta) {
246
                    return display_extended_attribute(row, 'year');
247
                }
248
            },
249
            {
250
                "data": "", // pages
251
                "orderable": false,
252
                "render": function(data, type, row, meta) {
253
                    return display_extended_attribute(row, 'pages');
254
                }
255
            },
256
            {
257
                "data": "", // type
258
                "orderable": false,
259
                "render": function(data, type, row, meta) {
260
                    return display_extended_attribute(row, 'type');
261
                }
262
            },
263
            {
264
                "data": "ill_backend_request_id",
265
                "orderable": true,
266
                "render": function(data, type, row, meta) {
267
                    return escape_str(data);
497
                }
268
                }
498
            }, table_settings);
269
            },
499
270
            {
500
            // Custom date range filtering
271
                "data": "patron.firstname:patron.surname:patron.cardnumber",
501
            $.fn.dataTable.ext.search.push(function(settings, data, dataIndex) {
272
                "render": function(data, type, row, meta) {
502
                var placedStart = $('#illfilter_dateplaced_start').get(0)._flatpickr.selectedDates[0];
273
                    return (row.patron) ? $patron_to_html( row.patron, { display_cardnumber: true, url: true } ) : ''; }                    },
503
                var placedEnd = $('#illfilter_dateplaced_end').get(0)._flatpickr.selectedDates[0];
274
            {
504
                var modifiedStart = $('#illfilter_datemodified_start').get(0)._flatpickr.selectedDates[0];
275
                "data": "biblio_id",
505
                var modifiedEnd = $('#illfilter_datemodified_end').get(0)._flatpickr.selectedDates[0];
276
                "orderable": true,
506
                var rowPlaced = data[14] ? new Date(data[14]) : null;
277
                "render": function(data, type, row, meta) {
507
                var rowModified = data[16] ? new Date(data[16]) : null;
278
                    if ( data === null ) {
508
                var placedPassed = true;
279
                        return "";
509
                var modifiedPassed = true;
280
                    }
510
                if (placedStart && rowPlaced && rowPlaced < placedStart) {
281
                    return $biblio_to_html(row.biblio, { biblio_id_only: 1, link: 1 });
511
                    placedPassed = false
512
                };
513
                if (placedEnd && rowPlaced && rowPlaced > placedEnd) {
514
                    placedPassed = false;
515
                }
282
                }
516
                if (modifiedStart && rowModified && rowModified < modifiedStart) {
283
            },
517
                    modifiedPassed = false
284
            {
518
                };
285
                "data": "library.name",
519
                if (modifiedEnd && rowModified && rowModified > modifiedEnd) {
286
                "orderable": true,
520
                    modifiedPassed = false;
287
                "render": function(data, type, row, meta) {
288
                    return escape_str(data);
521
                }
289
                }
290
            },
291
            {
292
                "data": "status",
293
                "orderable": true,
294
                "render": function(data, type, row, meta) {
295
                    let status_label = row._strings.status_av ?
296
                        row._strings.status_av.str ?
297
                            row._strings.status_av.str :
298
                            row._strings.status_av.code :
299
                        row._strings.status.str
300
                    return escape_str(status_label);
301
                }
302
            },
303
            {
304
                "data": "requested_date",
305
                "orderable": true,
306
                "render": function(data, type, row, meta) {
307
                    return $date(data);
308
                }
309
            },
310
            {
311
                "data": "timestamp",
312
                "orderable": true,
313
                "render": function(data, type, row, meta) {
314
                    return $date(data);
315
                }
316
            },
317
            {
318
                "data": "replied_date",
319
                "orderable": true,
320
                "render": function(data, type, row, meta) {
321
                    return $date(data);
322
                }
323
            },
324
            {
325
                "data": "completed_date",
326
                "orderable": true,
327
                "render": function(data, type, row, meta) {
328
                    return $date(data);
329
                }
330
            },
331
            {
332
                "data": "access_url",
333
                "orderable": true,
334
                "render": function(data, type, row, meta) {
335
                    return escape_str(data);
336
                }
337
            },
338
            {
339
                "data": "cost",
340
                "orderable": true,
341
                "render": function(data, type, row, meta) {
342
                    return escape_str(data);
343
                }
344
            },
345
            {
346
                "data": "paid_price",
347
                "orderable": true,
348
                "render": function(data, type, row, meta) {
349
                    return escape_str(data);
350
                }
351
            },
352
            {
353
                "data": "comments_count",
354
                "orderable": true,
355
                "searchable": false,
356
                "render": function(data, type, row, meta) {
357
                    return escape_str(data);
358
                }
359
            },
360
            {
361
                "data": "opac_notes",
362
                "orderable": true,
363
                "render": function(data, type, row, meta) {
364
                    return escape_str(data);
365
                }
366
            },
367
            {
368
                "data": "staff_notes",
369
                "orderable": true,
370
                "render": function(data, type, row, meta) {
371
                    return escape_str(data);
372
                }
373
            },
374
            {
375
                "data": "ill_backend_id",
376
                "orderable": true,
377
                "render": function(data, type, row, meta) {
378
                    return escape_str(data);
379
                }
380
            },
381
            {
382
                "data": "ill_request_id",
383
                "orderable": false,
384
                "searchable": false,
385
                "render": function( data, type, row, meta ) {
386
                    return '<a class="btn btn-default btn-sm" ' +
387
                            'href="/cgi-bin/koha/ill/ill-requests.pl?' +
388
                            'method=illview&amp;illrequest_id=' +
389
                            encodeURIComponent(data) +
390
                            '">' + ill_manage + '</a>';
391
                }
392
            }
393
        ]
394
    }, table_settings, null, additional_filters);
522
395
523
                return placedPassed && modifiedPassed;
396
    $("#illfilter_form").on('submit', filter);
524
397
525
            });
398
    function redrawTable() {
399
        let table_dt = ill_requests_table.DataTable();
400
        table_dt.draw();
401
    }
526
402
403
    function filter() {
404
        redrawTable();
405
        return false;
406
    }
407
408
    function clearSearch() {
409
        let filters = [
410
            "illfilter_backend",
411
            "illfilter_branchname",
412
            "illfilter_patron",
413
            "illfilter_keyword",
414
        ];
415
        filters.forEach((filter) => {
416
            $("#"+filter).val("");
527
        });
417
        });
528
    } //END if window.location.search.length == 0
529
418
530
    var clearSearch = function() {
419
        //Clear flatpickr date filters
531
        table.api().search('').columns().search('');
420
        $('#illfilter_form > fieldset > ol > li:nth-child(4) > span > a').click();
532
        activeFilters = {};
421
        $('#illfilter_form > fieldset > ol > li:nth-child(5) > span > a').click();
533
        for (var filter in filterable) {
422
        $('#illfilter_form > fieldset > ol > li:nth-child(6) > span > a').click();
534
            if (
423
        $('#illfilter_form > fieldset > ol > li:nth-child(7) > span > a').click();
535
                filterable.hasOwnProperty(filter) &&
424
536
                filterable[filter].hasOwnProperty('clear')
425
        disableStatusFilter();
537
            ) {
426
538
                filterable[filter].clear();
427
        redrawTable();
428
    }
429
430
    function populateStatusFilter(backend) {
431
        $.ajax({
432
            type: "GET",
433
            url: "/api/v1/ill_backends/"+backend+"/statuses",
434
            success: function(statuses){
435
                $('#illfilter_status').append(
436
                    '<option value="">'+ill_all_statuses+'</option>'
437
                );
438
                statuses.sort((a, b) => a.str.localeCompare(b.str)).forEach(function(status) {
439
                    $('#illfilter_status').append(
440
                        '<option value="' + status.code  +
441
                        '">' + status.str +  '</option>'
442
                    );
443
                });
539
            }
444
            }
540
        }
445
        });
541
        table.api().draw();
446
    }
542
    };
543
447
544
    // Apply any search filters, or clear any previous
448
    function populateBackendFilter() {
545
    // ones
449
        $.ajax({
546
    $('#illfilter_form').submit(function(event) {
450
            type: "GET",
547
        event.preventDefault();
451
            url: "/api/v1/ill_backends",
548
        table.api().search('').columns().search('');
452
            success: function(backends){
549
        for (var active in activeFilters) {
453
                backends.sort((a, b) => a.ill_backend_id.localeCompare(b.ill_backend_id)).forEach(function(backend) {
550
            if (activeFilters.hasOwnProperty(active)) {
454
                    $('#illfilter_backend').append(
551
                activeFilters[active]();
455
                        '<option value="' + backend.ill_backend_id  +
456
                        '">' + backend.ill_backend_id +  '</option>'
457
                    );
458
                });
552
            }
459
            }
460
        });
461
    }
462
463
    function disableStatusFilter() {
464
        $('#illfilter_status').children().remove();
465
        $("#illfilter_status").attr('title', ill_manage_select_backend_first);
466
        $('#illfilter_status').prop("disabled", true);
467
    }
468
469
    function enableStatusFilter() {
470
        $('#illfilter_status').children().remove();
471
        $("#illfilter_status").attr('title', '');
472
        $('#illfilter_status').prop("disabled", false);
473
    }
474
475
    $('#illfilter_backend').change(function() {
476
        var selected_backend = $('#illfilter_backend option:selected').val();
477
        if (selected_backend && selected_backend.length > 0) {
478
            populateStatusFilter(selected_backend);
479
            enableStatusFilter();
480
        } else {
481
            disableStatusFilter();
553
        }
482
        }
554
        table.api().draw();
555
    });
483
    });
556
484
485
    disableStatusFilter();
486
    populateBackendFilter();
487
557
    // Clear all filters
488
    // Clear all filters
558
    $('#clear_search').click(function() {
489
    $('#clear_search').click(function() {
559
        clearSearch();
490
        clearSearch();
560
- 

Return to bug 22440