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

(-)a/Koha/Hold.pm (-1 / +11 lines)
Lines 579-586 Returns the related Koha::Library object for this Hold Link Here
579
=cut
579
=cut
580
580
581
sub branch {
581
sub branch {
582
    return shift->pickup_library(@_);
583
}
584
585
=head3 pickup_library
586
587
Returns the related Koha::Biblio object for this hold
588
589
=cut
590
591
sub pickup_library {
582
    my ($self) = @_;
592
    my ($self) = @_;
583
    my $rs = $self->_result->branchcode;
593
    my $rs = $self->_result->pickup_library;
584
    return Koha::Library->_new_from_dbic($rs);
594
    return Koha::Library->_new_from_dbic($rs);
585
}
595
}
586
596
(-)a/Koha/Old/Hold.pm (+26 lines)
Lines 47-52 sub biblio { Link Here
47
    return Koha::Biblio->_new_from_dbic($rs);
47
    return Koha::Biblio->_new_from_dbic($rs);
48
}
48
}
49
49
50
=head3 item
51
52
Returns the related Koha::Item object for this old Hold
53
54
=cut
55
56
sub item {
57
    my ($self) = @_;
58
    my $rs = $self->_result->itemnumber;
59
    return unless $rs;
60
    return Koha::Item->_new_from_dbic($rs);
61
}
62
63
=head3 pickup_library
64
65
Returns the related Koha::Biblio object for this old hold
66
67
=cut
68
69
sub pickup_library {
70
    my ($self) = @_;
71
    my $rs = $self->_result->pickup_library;
72
    return unless $rs;
73
    return Koha::Library->_new_from_dbic($rs);
74
}
75
50
=head3 anonymize
76
=head3 anonymize
51
77
52
    $old_hold->anonymize();
78
    $old_hold->anonymize();
(-)a/Koha/REST/V1/Holds.pm (-1 / +10 lines)
Lines 26-31 use C4::Reserves; Link Here
26
use Koha::Items;
26
use Koha::Items;
27
use Koha::Patrons;
27
use Koha::Patrons;
28
use Koha::Holds;
28
use Koha::Holds;
29
use Koha::Old::Holds;
29
use Koha::DateUtils qw( dt_from_string );
30
use Koha::DateUtils qw( dt_from_string );
30
31
31
use List::MoreUtils qw( any );
32
use List::MoreUtils qw( any );
Lines 44-51 Method that handles listing Koha::Hold objects Link Here
44
sub list {
45
sub list {
45
    my $c = shift->openapi->valid_input or return;
46
    my $c = shift->openapi->valid_input or return;
46
47
48
    my $old = $c->param('old');
49
    $c->req->params->remove('old');
50
47
    return try {
51
    return try {
48
        my $holds = $c->objects->search( Koha::Holds->new );
52
        my $holds_set =
53
            $old
54
            ? Koha::Old::Holds->new
55
            : Koha::Holds->new;
56
57
        my $holds = $c->objects->search( $holds_set );
49
        return $c->render( status => 200, openapi => $holds );
58
        return $c->render( status => 200, openapi => $holds );
50
    }
59
    }
51
    catch {
60
    catch {
(-)a/Koha/REST/V1/Patrons.pm (+3 lines)
Lines 44-49 Controller function that handles listing Koha::Patron objects Link Here
44
44
45
sub list {
45
sub list {
46
    my $c = shift->openapi->valid_input or return;
46
    my $c = shift->openapi->valid_input or return;
47
    use Data::Printer colored => 1; warn p $c->req->headers;
48
    use Data::Printer colored => 1; warn p $c->stash('koha.embed');
49
47
50
48
    return try {
51
    return try {
49
52
(-)a/Koha/REST/V1/Patrons/Holds.pm (-8 / +10 lines)
Lines 49-64 sub list { Link Here
49
        );
49
        );
50
    }
50
    }
51
51
52
    return try {
52
    my $old = $c->param('old');
53
    $c->req->params->remove('old');
53
54
54
        my $holds = $c->objects->search( $patron->holds );
55
    return try {
56
        my $holds_set =
57
            $old
58
            ? Koha::Old::Holds->new
59
            : Koha::Holds->new;
55
60
56
        return $c->render(
61
        my $holds = $c->objects->search( $holds_set );
57
            status  => 200,
62
        return $c->render( status => 200, openapi => $holds );
58
            openapi => $holds
63
    } catch {
59
        );
60
    }
61
    catch {
62
        $c->unhandled_exception($_);
64
        $c->unhandled_exception($_);
63
    };
65
    };
64
}
66
}
(-)a/api/v1/swagger/definitions/hold.yaml (+15 lines)
Lines 108-112 properties: Link Here
108
      - boolean
108
      - boolean
109
      - "null"
109
      - "null"
110
    description: Cancellation requests count for the hold (x-koha-embed)
110
    description: Cancellation requests count for the hold (x-koha-embed)
111
  biblio:
112
    type:
113
      - object
114
      - "null"
115
    description: Bibliographic record
116
  item:
117
    type:
118
      - object
119
      - "null"
120
    description: The item
121
  pickup_library:
122
    type:
123
      - object
124
      - "null"
125
    description: Pickup library
111
126
112
additionalProperties: false
127
additionalProperties: false
(-)a/api/v1/swagger/paths/holds.yaml (+7 lines)
Lines 88-93 Link Here
88
      - $ref: "../swagger.yaml#/parameters/q_param"
88
      - $ref: "../swagger.yaml#/parameters/q_param"
89
      - $ref: "../swagger.yaml#/parameters/q_body"
89
      - $ref: "../swagger.yaml#/parameters/q_body"
90
      - $ref: "../swagger.yaml#/parameters/request_id_header"
90
      - $ref: "../swagger.yaml#/parameters/request_id_header"
91
      - name: old
92
        in: query
93
        description: By default, current holds are returned, when this is true then
94
          old holds are returned as result.
95
        type: boolean
91
      - name: x-koha-embed
96
      - name: x-koha-embed
92
        in: header
97
        in: header
93
        required: false
98
        required: false
Lines 97-102 Link Here
97
          type: string
102
          type: string
98
          enum:
103
          enum:
99
            - cancellation_requested
104
            - cancellation_requested
105
            - biblio
106
            - pickup_library
100
          collectionFormat: csv
107
          collectionFormat: csv
101
    produces:
108
    produces:
102
      - application/json
109
      - application/json
(-)a/api/v1/swagger/paths/patrons_holds.yaml (-1 / +10 lines)
Lines 15-20 Link Here
15
      - $ref: "../swagger.yaml#/parameters/q_param"
15
      - $ref: "../swagger.yaml#/parameters/q_param"
16
      - $ref: "../swagger.yaml#/parameters/q_body"
16
      - $ref: "../swagger.yaml#/parameters/q_body"
17
      - $ref: "../swagger.yaml#/parameters/request_id_header"
17
      - $ref: "../swagger.yaml#/parameters/request_id_header"
18
      - name: old
19
        in: query
20
        description: By default, current holds are returned, when this is true then
21
          old holds are returned as result.
22
        type: boolean
18
      - name: x-koha-embed
23
      - name: x-koha-embed
19
        in: header
24
        in: header
20
        required: false
25
        required: false
Lines 24-30 Link Here
24
          type: string
29
          type: string
25
          enum:
30
          enum:
26
            - cancellation_requested
31
            - cancellation_requested
27
          collectionFormat: csv
32
            - biblio
33
            - item
34
            - pickup_library
35
            - pickup_library.branchname
36
        collectionFormat: csv
28
    produces:
37
    produces:
29
      - application/json
38
      - application/json
30
    responses:
39
    responses:
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/holdshistory.tt (-51 / +145 lines)
Lines 48-57 Link Here
48
    <div class="dialog alert">Staff members are not allowed to access patron's holds history</div>
48
    <div class="dialog alert">Staff members are not allowed to access patron's holds history</div>
49
[% ELSIF is_anonymous %]
49
[% ELSIF is_anonymous %]
50
    <div class="dialog alert">This is the anonymous patron, so no holds history is displayed.</div>
50
    <div class="dialog alert">This is the anonymous patron, so no holds history is displayed.</div>
51
[% ELSIF ( !holds ) %]
52
    <div class="dialog message">This patron has no holds history.</div>
53
[% ELSE %]
51
[% ELSE %]
54
52
53
<!-- FIXME    <div class="dialog message">This patron has no holds history.</div> -->
55
[% SET show_itemtype_column = Koha.Preference('AllowHoldItemTypeSelection') %]
54
[% SET show_itemtype_column = Koha.Preference('AllowHoldItemTypeSelection') %]
56
55
57
<div id="holdshistory" class="page-section">
56
<div id="holdshistory" class="page-section">
Lines 72-125 Link Here
72
        <th>Status</th>
71
        <th>Status</th>
73
        </tr>
72
        </tr>
74
      </thead>
73
      </thead>
75
      <tbody>
74
  </table>
76
      [% FOREACH hold IN holds %]
75
  <table id="table_oldholdshistory">
76
      <thead>
77
        <tr>
77
        <tr>
78
          <td>[% INCLUDE 'biblio-title.inc' biblio=hold.biblio link = 1 %]</td>
78
        <th class="anti-the">Title</th>
79
          <td>[% hold.biblio.author | html %]</td>
79
        <th>Author</th>
80
          <td>[% hold.item.barcode | html %]</td>
80
        <th>Barcode</th>
81
          <td>[% Branches.GetName( hold.branchcode ) | html %]</td>
81
        <th>Library</th>
82
          <td data-order="[% hold.reservedate | html %]">[% hold.reservedate | $KohaDates %]</td>
82
        <th>Hold date</th>
83
          <td data-order="[% hold.expirationdate | html %]">
83
        <th>Expiration date</th>
84
                [% hold.expirationdate | $KohaDates %]
84
        <th>Waiting date</th>
85
          </td>
85
        <th>Cancellation date</th>
86
          <td data-order="[% hold.waitingdate | html %]">
86
        [% IF show_itemtype_column %]
87
                [% hold.waitingdate | $KohaDates %]
87
          <th>Requested item type</th>
88
          </td>
88
        [% END %]
89
          <td data-order="[% hold.cancellationdate | html %]">
89
        <th>Status</th>
90
                [% hold.cancellationdate | $KohaDates %]
91
          </td>
92
          [% IF show_itemtype_column %]
93
            <td>
94
              [% IF hold.itemtype %]
95
                  [% ItemTypes.GetDescription( hold.itemtype ) | html %]
96
              [% ELSE %]
97
                  <span>Any item type</span>
98
              [% END %]
99
            </td>
100
          [% END %]
101
          <td>
102
          [% IF hold.found == 'F' %]
103
              <span>Fulfilled</span>
104
          [% ELSIF hold.cancellationdate %]
105
              <span>Cancelled</span>
106
                [% IF hold.cancellation_reason %]
107
                    ([% AuthorisedValues.GetByCode('HOLD_CANCELLATION', hold.cancellation_reason) | html %])
108
                [% END %]
109
          [% ELSIF hold.found == 'W' %]
110
              <span>Waiting</span>
111
          [% ELSIF hold.found == 'P' %]
112
              <span>Processing</span>
113
          [% ELSIF hold.found == 'T' %]
114
              <span>In transit</span>
115
          [% ELSE %]
116
              <span>Pending</span>
117
          [% END %]
118
          </td>
119
        </tr>
90
        </tr>
120
      [% END %]
91
      </thead>
121
      </tbody>
122
  </table>
92
  </table>
93
123
</div>
94
</div>
124
95
125
[% END %]
96
[% END %]
Lines 139-144 Link Here
139
    [% INCLUDE 'columns_settings.inc' %]
110
    [% INCLUDE 'columns_settings.inc' %]
140
    [% INCLUDE 'str/members-menu.inc' %]
111
    [% INCLUDE 'str/members-menu.inc' %]
141
    [% Asset.js("js/members-menu.js") | $raw %]
112
    [% Asset.js("js/members-menu.js") | $raw %]
113
    [% INCLUDE 'js-biblio-format.inc' %]
142
    <script>
114
    <script>
143
        $(document).ready(function() {
115
        $(document).ready(function() {
144
            var table_settings = [% TablesSettings.GetTableSettings('members', 'holdshistory', 'holdshistory-table', 'json') | $raw %];
116
            var table_settings = [% TablesSettings.GetTableSettings('members', 'holdshistory', 'holdshistory-table', 'json') | $raw %];
Lines 146-155 Link Here
146
              //Remove item type column settings
118
              //Remove item type column settings
147
              table_settings['columns'] = table_settings['columns'].filter(function(c){return c['columnname'] != 'itemtype';});
119
              table_settings['columns'] = table_settings['columns'].filter(function(c){return c['columnname'] != 'itemtype';});
148
            [% END %]
120
            [% END %]
149
            var table = KohaTable("table_holdshistory", {
121
            build_holds_table("#table_holdshistory");
150
                "sPaginationType": "full",
122
            build_holds_table("#table_oldholdshistory", 1);
151
                "aaSorting": [[4, 'desc']]
123
            function build_holds_table(table_id, old){
152
            }, table_settings);
124
                let table_url = '/api/v1/patrons/[% patron.borrowernumber | uri %]/holds';
125
                if (old){table_url += '?old=1'}
126
                $(table_id).kohaTable({
127
                    ajax: {
128
                        url: table_url,
129
                        //dataSrc: function ( json ) {
130
                        //    json.data.forEach((el, i) => el.item ??= { external_id: '' });
131
                        //    console.log(json.data);
132
                        //    return json.data;
133
                        //},
134
                    },
135
                    order: [],
136
                    embed: ['biblio', 'item', 'pickup_library', 'pickup_library.branchname'],
137
                    columns: [
138
                        {
139
                            data: "biblio.title:biblio.subtitle:biblio.medium",
140
                            searchable: true,
141
                            orderable: true,
142
                            render: function (data, type, row, meta) {
143
                                return $biblio_to_html(row.biblio, { link: 1 });
144
                            }
145
                        },
146
                        {
147
                            data: "biblio.author",
148
                            searchable: true,
149
                            orderable: true,
150
                            render: function (data, type, row, meta) {
151
                                return row.biblio.author;
152
                            }
153
                        },
154
                        {
155
                            data: "item.external_id",
156
                            searchable: true,
157
                            orderable: true,
158
                            render: function (data, type, row, meta) {
159
                                return row.item ? row.item.external_id : "";
160
                            }
161
                        },
162
                        {
163
                            data: "pickup_library_id:pickup_library.branchname",
164
                            searchable: true,
165
                            orderable: true,
166
                            render: function (data, type, row, meta) {
167
                                return row.pickup_library.name;
168
                            }
169
                        },
170
                        {
171
                            data: "hold_date",
172
                            type: "date",
173
                            searchable: true,
174
                            orderable: true,
175
                            render: function (data, type, row, meta) {
176
                                return $date(row.hold_date);
177
                            }
178
                        },
179
                        {
180
                            data: "expiration_date",
181
                            type: "date",
182
                            searchable: true,
183
                            orderable: true,
184
                            render: function (data, type, row, meta) {
185
                                return $date(row.expiration_date)
186
                            }
187
                        },
188
                        {
189
                            data: "waiting_date",
190
                            type: "date",
191
                            searchable: true,
192
                            orderable: true,
193
                            render: function (data, type, row, meta) {
194
                                return $date(row.waiting_date)
195
                            }
196
                        },
197
                        {
198
                            data: "cancellation_date",
199
                            type: "date",
200
                            searchable: true,
201
                            orderable: true,
202
                            render: function (data, type, row, meta) {
203
                                return $date(row.cancellation_date)
204
                            }
205
                        },
206
                        [% IF show_itemtype_column %]
207
                        {
208
                            data: "item_type.item_type",
209
                            searchable: true,
210
                            orderable: true,
211
                            render: function (data, type, row, meta) {
212
                                if ( row.item_type ) {
213
                                    return row.item_type.item_type;
214
                                } else {
215
                                    return _("Any item type");
216
                                }
217
                            }
218
                        },
219
                        [% END %]
220
                        {
221
                            data: "found", // FIXME filter with dropdown list
222
                            searchable: true,
223
                            orderable: true,
224
                            render: function (data, type, row, meta) {
225
                                if ( row.status == 'F' ) {
226
                                    return _("Fulfilled");
227
                                } else if (row.cancellation_date) {
228
                                    let r = _("Cancelled");
229
                                    if (row.cancellation_reason){
230
                                        r += "(%s)".format("FIXME"); //FIXME Add HOLD_CANCELLATION description
231
                                    }
232
                                    return r;
233
                                } else if (row.status == 'W') {
234
                                    return _("Waiting");
235
                                } else if (row.status == 'P') {
236
                                    return _("Processing");
237
                                } else if (row.status == 'T') {
238
                                    return _("In transit");
239
                                }
240
241
                                return _("Pending");
242
                            }
243
                        },
244
                    ],
245
                }, table_settings);
246
            }
153
        });
247
        });
154
    </script>
248
    </script>
155
[% END %]
249
[% END %]
(-)a/members/holdshistory.pl (-35 / +11 lines)
Lines 26-81 use Koha::Patrons; Link Here
26
26
27
my $input = CGI->new;
27
my $input = CGI->new;
28
28
29
my $borrowernumber;
29
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
30
my $cardnumber;
30
    {
31
my @all_holds;
31
        template_name => "members/holdshistory.tt",
32
32
        query         => $input,
33
my ($template, $loggedinuser, $cookie)= get_template_and_user({template_name => "members/holdshistory.tt",
33
        type          => "intranet",
34
                query => $input,
34
        flagsrequired => { borrowers => 'edit_borrowers' },
35
                type => "intranet",
35
    }
36
                flagsrequired => {borrowers => 'edit_borrowers'},
36
);
37
                });
38
39
my $patron;
40
37
41
if ($input->param('cardnumber')) {
38
my $cardnumber     = $input->param('cardnumber');
42
    $cardnumber = $input->param('cardnumber');
39
my $borrowernumber = $input->param('borrowernumber');
43
    $patron = Koha::Patrons->find( { cardnumber => $cardnumber } );
40
my $patron         = Koha::Patrons->find( $cardnumber ? { cardnumber => $cardnumber } : $borrowernumber );
44
}
45
if ($input->param('borrowernumber')) {
46
    $borrowernumber = $input->param('borrowernumber');
47
    $patron = Koha::Patrons->find( $borrowernumber );
48
}
49
41
50
unless ( $patron ) {
42
unless ( $patron ) {
51
    print $input->redirect("/cgi-bin/koha/circ/circulation.pl?borrowernumber=$borrowernumber");
43
    print $input->redirect("/cgi-bin/koha/circ/circulation.pl?borrowernumber=$borrowernumber");
52
    exit;
44
    exit;
53
}
45
}
54
46
55
my $holds;
56
my $old_holds;
57
58
if ( $borrowernumber eq C4::Context->preference('AnonymousPatron') ){
47
if ( $borrowernumber eq C4::Context->preference('AnonymousPatron') ){
59
    # use of 'eq' in the above comparison is intentional -- the
48
    # use of 'eq' in the above comparison is intentional -- the
60
    # system preference value could be blank
49
    # system preference value could be blank
61
    $template->param( is_anonymous => 1 );
50
    $template->param( is_anonymous => 1 );
62
} else {
63
    $holds = $patron->holds;
64
    $old_holds = $patron->old_holds;
65
66
    while (my $hold = $holds->next) {
67
        push @all_holds, $hold;
68
    }
69
70
    while (my $hold = $old_holds->next) {
71
        push @all_holds, $hold;
72
    }
73
}
51
}
74
52
75
$template->param(
53
$template->param(
76
    holdshistoryview => 1,
54
    holdshistoryview => 1,
77
    patron           => $patron,
55
    patron           => $patron,
78
    holds            => \@all_holds,
79
);
56
);
80
57
81
output_html_with_http_headers $input, $cookie, $template->output;
58
output_html_with_http_headers $input, $cookie, $template->output;
82
- 

Return to bug 35560