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

(-)a/Koha/ArticleRequest.pm (-2 / +16 lines)
Lines 102-110 sub complete { Link Here
102
=cut
102
=cut
103
103
104
sub cancel {
104
sub cancel {
105
    my ( $self, $notes ) = @_;
105
    my ( $self, $cancellation_reason, $notes ) = @_;
106
106
107
    $self->status(Koha::ArticleRequest::Status::Canceled);
107
    $self->status(Koha::ArticleRequest::Status::Canceled);
108
    $self->cancellation_reason($cancellation_reason) if $cancellation_reason;
108
    $self->notes($notes) if $notes;
109
    $self->notes($notes) if $notes;
109
    $self->store();
110
    $self->store();
110
    $self->notify();
111
    $self->notify();
Lines 119-124 sub notify { Link Here
119
    my ($self) = @_;
120
    my ($self) = @_;
120
121
121
    my $status = $self->status;
122
    my $status = $self->status;
123
    my $reason = $self->notes;
124
    if ( !defined $reason && $self->cancellation_reason ) {
125
        my $av = Koha::AuthorisedValues->search(
126
            {
127
                category            => 'AR_CANCELLATION',
128
                authorised_value    => $self->cancellation_reason
129
            }
130
        )->next;
131
        $reason = $av->lib_opac ? $av->lib_opac : $av->lib if $av;
132
    }
122
133
123
    require C4::Letters;
134
    require C4::Letters;
124
    if (
135
    if (
Lines 135-140 sub notify { Link Here
135
                items            => $self->itemnumber,
146
                items            => $self->itemnumber,
136
                branches         => $self->branchcode,
147
                branches         => $self->branchcode,
137
            },
148
            },
149
            substitute => {
150
                reason => $reason,
151
            },
138
        )
152
        )
139
      )
153
      )
140
    {
154
    {
Lines 144-150 sub notify { Link Here
144
                borrowernumber         => $self->borrowernumber,
158
                borrowernumber         => $self->borrowernumber,
145
                message_transport_type => 'email',
159
                message_transport_type => 'email',
146
            }
160
            }
147
        ) or warn "can't enqueue letter ". $letter->{code};
161
        ) or warn "can't enqueue letter " . $letter->{code};
148
    }
162
    }
149
}
163
}
150
164
(-)a/Koha/Exceptions/ArticleRequests.pm (+17 lines)
Line 0 Link Here
1
package Koha::Exceptions::ArticleRequests;
2
3
use Modern::Perl;
4
5
use Exception::Class (
6
7
    'Koha::Exceptions::ArticleRequests' => {
8
        description => 'Something went wrong!',
9
    },
10
    'Koha::Exceptions::ArticleRequests::FailedCancel' => {
11
        isa => 'Koha::Exceptions::ArticleRequests',
12
        description => 'Failed to cancel article request'
13
    }
14
15
);
16
17
1;
(-)a/Koha/REST/V1/ArticleRequests.pm (+76 lines)
Line 0 Link Here
1
package Koha::REST::V1::ArticleRequests;
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use Mojo::Base 'Mojolicious::Controller';
21
22
use Koha::Database;
23
use Koha::ArticleRequests;
24
25
use Scalar::Util qw( blessed );
26
use Try::Tiny qw( catch try );
27
28
=head1 NAME
29
30
Koha::REST::V1::ArticleRequests
31
32
=head1 API
33
34
=head2 Methods
35
36
=head3 cancel
37
38
Controller function that handles cancelling a Koha::ArticleRequest object
39
40
=cut
41
42
sub cancel {
43
    my $c = shift->openapi->valid_input or return;
44
45
    my $ar = Koha::ArticleRequests->find( $c->validation->param('ar_id') );
46
47
    unless ( $ar ) {
48
        return $c->render(
49
            status  => 404,
50
            openapi => { error => "Article request not found" }
51
        );
52
    }
53
54
    my $reason = $c->validation->param('cancellation_reason');
55
    my $notes = $c->validation->param('notes');
56
57
    return try {
58
59
        $ar->cancel($reason, $notes);
60
        return $c->render(
61
            status  => 204,
62
            openapi => q{}
63
        );
64
    } catch {
65
        if ( blessed $_ && $_->isa('Koha::Exceptions::ArticleRequests::FailedCancel') ) {
66
            return $c->render(
67
                status  => 403,
68
                openapi => { error => "Article request cannot be canceled" }
69
            );
70
        }
71
72
        $c->unhandled_exception($_);
73
    };
74
}
75
76
1;
(-)a/Koha/REST/V1/Patrons.pm (+49 lines)
Lines 419-422 sub guarantors_can_see_checkouts { Link Here
419
    };
419
    };
420
}
420
}
421
421
422
=head3 cancel_article_request
423
424
Controller function that handles cancelling a patron's Koha::ArticleRequest object
425
426
=cut
427
428
sub cancel_article_request {
429
    my $c = shift->openapi->valid_input or return;
430
431
    my $patron = Koha::Patrons->find( $c->validation->param('patron_id') );
432
433
    unless ( $patron ) {
434
        return $c->render(
435
            status  => 404,
436
            openapi => { error => "Patron not found" }
437
        );
438
    }
439
440
    my $ar = $patron->article_requests->find( $c->validation->param('ar_id') );
441
442
    unless ( $ar ) {
443
        return $c->render(
444
            status  => 404,
445
            openapi => { error => "Article request not found" }
446
        );
447
    }
448
449
    my $reason = $c->validation->param('cancellation_reason');
450
    my $notes = $c->validation->param('notes');
451
452
    return try {
453
454
        $ar->cancel($reason, $notes);
455
        return $c->render(
456
            status  => 204,
457
            openapi => q{}
458
        );
459
    } catch {
460
        if ( blessed $_ && $_->isa('Koha::Exceptions::ArticleRequests::FailedCancel') ) {
461
            return $c->render(
462
                status  => 403,
463
                openapi => { error => "Article request cannot be canceled" }
464
            );
465
        }
466
467
        $c->unhandled_exception($_);
468
    };
469
}
470
422
1;
471
1;
(-)a/api/v1/swagger/parameters.json (+9 lines)
Lines 56-61 Link Here
56
  "cashup_id_pp": {
56
  "cashup_id_pp": {
57
    "$ref": "parameters/cashup.json#/cashup_id_pp"
57
    "$ref": "parameters/cashup.json#/cashup_id_pp"
58
  },
58
  },
59
  "ar_id_pp": {
60
    "$ref": "parameters/article_request.json#/ar_id_pp"
61
  },
62
  "ar_reason_qp": {
63
    "$ref": "parameters/article_request.json#/ar_reason_qp"
64
  },
65
  "ar_notes_qp": {
66
    "$ref": "parameters/article_request.json#/ar_notes_qp"
67
  },
59
  "match": {
68
  "match": {
60
    "name": "_match",
69
    "name": "_match",
61
    "in": "query",
70
    "in": "query",
(-)a/api/v1/swagger/parameters/article_request.json (+23 lines)
Line 0 Link Here
1
{
2
  "ar_id_pp": {
3
    "name": "ar_id",
4
    "in": "path",
5
    "description": "Article request identifier",
6
    "required": true,
7
    "type": "integer"
8
  },
9
  "ar_reason_qp": {
10
    "name": "cancellation_reason",
11
    "in": "query",
12
    "description": "Article request cancellation reason",
13
    "required": false,
14
    "type": "string"
15
  },
16
  "ar_notes_qp": {
17
    "name": "notes",
18
    "in": "query",
19
    "description": "Article request custom cancellation reason",
20
    "required": false,
21
    "type": "string"
22
  }
23
}
(-)a/api/v1/swagger/paths.json (-1 / +7 lines)
Lines 17-22 Link Here
17
  "/acquisitions/funds": {
17
  "/acquisitions/funds": {
18
    "$ref": "paths/acquisitions_funds.json#/~1acquisitions~1funds"
18
    "$ref": "paths/acquisitions_funds.json#/~1acquisitions~1funds"
19
  },
19
  },
20
  "/article_requests/{ar_id}": {
21
    "$ref": "paths/article_requests.json#/~1article_requests~1{ar_id}"
22
  },
20
  "/biblios/{biblio_id}": {
23
  "/biblios/{biblio_id}": {
21
    "$ref": "paths/biblios.json#/~1biblios~1{biblio_id}"
24
    "$ref": "paths/biblios.json#/~1biblios~1{biblio_id}"
22
  },
25
  },
Lines 134-140 Link Here
134
  "/patrons/{patron_id}/extended_attributes/{extended_attribute_id}": {
137
  "/patrons/{patron_id}/extended_attributes/{extended_attribute_id}": {
135
    "$ref": "paths/patrons_extended_attributes.json#/~1patrons~1{patron_id}~1extended_attributes~1{extended_attribute_id}"
138
    "$ref": "paths/patrons_extended_attributes.json#/~1patrons~1{patron_id}~1extended_attributes~1{extended_attribute_id}"
136
  },
139
  },
137
   "/patrons/{patron_id}/holds": {
140
  "/patrons/{patron_id}/holds": {
138
    "$ref": "paths/patrons_holds.json#/~1patrons~1{patron_id}~1holds"
141
    "$ref": "paths/patrons_holds.json#/~1patrons~1{patron_id}~1holds"
139
  },
142
  },
140
  "/patrons/{patron_id}/password": {
143
  "/patrons/{patron_id}/password": {
Lines 170-175 Link Here
170
  "/public/patrons/{patron_id}/guarantors/can_see_checkouts": {
173
  "/public/patrons/{patron_id}/guarantors/can_see_checkouts": {
171
    "$ref": "paths/public_patrons.json#/~1public~1patrons~1{patron_id}~1guarantors~1can_see_checkouts"
174
    "$ref": "paths/public_patrons.json#/~1public~1patrons~1{patron_id}~1guarantors~1can_see_checkouts"
172
  },
175
  },
176
  "/public/patrons/{patron_id}/article_requests/{ar_id}": {
177
    "$ref": "paths/public_patrons.json#/~1public~1patrons~1{patron_id}~1article_requests~1{ar_id}"
178
  },
173
  "/quotes": {
179
  "/quotes": {
174
    "$ref": "paths/quotes.json#/~1quotes"
180
    "$ref": "paths/quotes.json#/~1quotes"
175
  },
181
  },
(-)a/api/v1/swagger/paths/article_requests.json (+70 lines)
Line 0 Link Here
1
{
2
    "/article_requests/{ar_id}": {
3
        "delete": {
4
            "x-mojo-to": "ArticleRequests#cancel",
5
            "operationId": "cancelArticleRequest",
6
            "tags": [
7
                "article_requests"
8
            ],
9
            "summary": "Cancel article requests",
10
            "parameters": [
11
                {
12
                    "$ref": "../parameters.json#/ar_id_pp"
13
                },
14
                {
15
                    "$ref": "../parameters.json#/ar_reason_qp"
16
                },
17
                {
18
                    "$ref": "../parameters.json#/ar_notes_qp"
19
                }
20
            ],
21
            "produces": ["application/json"],
22
            "responses": {
23
                "204": {
24
                    "description": "Article request canceled"
25
                },
26
                "400": {
27
                    "description": "Bad request",
28
                    "schema": {
29
                        "$ref": "../definitions.json#/error"
30
                    }
31
                },
32
                "401": {
33
                    "description": "Authentication required",
34
                    "schema": {
35
                        "$ref": "../definitions.json#/error"
36
                    }
37
                },
38
                "403": {
39
                    "description": "Access forbidden",
40
                    "schema": {
41
                        "$ref": "../definitions.json#/error"
42
                    }
43
                },
44
                "404": {
45
                    "description": "Patron not found",
46
                    "schema": {
47
                        "$ref": "../definitions.json#/error"
48
                    }
49
                },
50
                "500": {
51
                    "description": "Internal server error",
52
                    "schema": {
53
                        "$ref": "../definitions.json#/error"
54
                    }
55
                },
56
                "503": {
57
                    "description": "Under maintenance",
58
                    "schema": {
59
                        "$ref": "../definitions.json#/error"
60
                    }
61
                }
62
            },
63
            "x-koha-authorization": {
64
                "permissions": {
65
                    "reserveforothers": "1"
66
                  }
67
            }
68
        }
69
    }
70
}
(-)a/api/v1/swagger/paths/public_patrons.json (+70 lines)
Lines 242-246 Link Here
242
                "allow-owner": true
242
                "allow-owner": true
243
            }
243
            }
244
        }
244
        }
245
    },
246
    "/public/patrons/{patron_id}/article_requests/{ar_id}": {
247
        "delete": {
248
            "x-mojo-to": "Patrons#cancel_article_request",
249
            "operationId": "cancelPatronArticleRequest",
250
            "tags": [
251
                "patrons",
252
                "article_requests"
253
            ],
254
            "summary": "Cancel patron's article requests",
255
            "parameters": [
256
                {
257
                    "$ref": "../parameters.json#/patron_id_pp"
258
                },
259
                {
260
                    "$ref": "../parameters.json#/ar_id_pp"
261
                },
262
                {
263
                    "$ref": "../parameters.json#/ar_reason_qp"
264
                },
265
                {
266
                    "$ref": "../parameters.json#/ar_notes_qp"
267
                }
268
            ],
269
            "produces": ["application/json"],
270
            "responses": {
271
                "204": {
272
                    "description": "Patron's article request canceled"
273
                },
274
                "400": {
275
                    "description": "Bad request",
276
                    "schema": {
277
                        "$ref": "../definitions.json#/error"
278
                    }
279
                },
280
                "401": {
281
                    "description": "Authentication required",
282
                    "schema": {
283
                        "$ref": "../definitions.json#/error"
284
                    }
285
                },
286
                "403": {
287
                    "description": "Access forbidden",
288
                    "schema": {
289
                        "$ref": "../definitions.json#/error"
290
                    }
291
                },
292
                "404": {
293
                    "description": "Patron not found",
294
                    "schema": {
295
                        "$ref": "../definitions.json#/error"
296
                    }
297
                },
298
                "500": {
299
                    "description": "Internal server error",
300
                    "schema": {
301
                        "$ref": "../definitions.json#/error"
302
                    }
303
                },
304
                "503": {
305
                    "description": "Under maintenance",
306
                    "schema": {
307
                        "$ref": "../definitions.json#/error"
308
                    }
309
                }
310
            },
311
            "x-koha-authorization": {
312
                "allow-owner": true
313
            }
314
        }
245
    }
315
    }
246
}
316
}
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/authorised_values.tt (+2 lines)
Lines 424-429 Authorized values &rsaquo; Administration &rsaquo; Koha Link Here
424
            <p>General holdings: type of unit designator</p>
424
            <p>General holdings: type of unit designator</p>
425
        [% CASE 'HOLD_CANCELLATION' %]
425
        [% CASE 'HOLD_CANCELLATION' %]
426
            <p>Reasons why a hold might have been cancelled</p>
426
            <p>Reasons why a hold might have been cancelled</p>
427
        [% CASE 'AR_CANCELLATION' %]
428
            <p>Reasons why an article request might have been cancelled</p>
427
        [% CASE 'HSBND_FREQ' %]
429
        [% CASE 'HSBND_FREQ' %]
428
            <p>Frequencies used by the housebound module. They are displayed on the housebound tab in the patron account in staff.</p>
430
            <p>Frequencies used by the housebound module. They are displayed on the housebound tab in the patron account in staff.</p>
429
        [% CASE 'ITEMTYPECAT' %]
431
        [% CASE 'ITEMTYPECAT' %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/article-requests.tt (-23 / +76 lines)
Lines 42-48 Link Here
42
                    Complete request
42
                    Complete request
43
                </a>
43
                </a>
44
44
45
                <a class="ar-cancel-request" href="#" onclick="HandleMulti( Cancel, [% id_arg | html %], $(this) ); return false;">
45
                <a class="ar-cancel-request" href="#" onclick="Cancel( [% id_arg | html %], $(this) ); return false;">
46
                    <i class="fa fa-minus-circle"></i>
46
                    <i class="fa fa-minus-circle"></i>
47
                    Cancel request
47
                    Cancel request
48
                </a>
48
                </a>
Lines 82-87 Link Here
82
      </div>
82
      </div>
83
    </div>
83
    </div>
84
[% END %]
84
[% END %]
85
[% BLOCK cancel_modal %]
86
    <div id="cancelModal" class="modal" tabindex="-1" role="dialog" aria-hidden="true">
87
        <div class="modal-dialog" role="document">
88
            <div class="modal-content">
89
                <div class="modal-header">
90
                    <button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">×</button>
91
                    <h3>Confirm deletion</h3>
92
                </div>
93
94
                <div class="modal-body">
95
                    <p>Are you sure you want to cancel this article request?</p>
96
97
                    <fieldset class="action">
98
                        [% SET ar_cancellation = AuthorisedValues.GetAuthValueDropbox('AR_CANCELLATION') %]
99
                        [% IF ar_cancellation %]
100
                            <label for="cancellation-reason" class="col-sm-4">Cancellation reason: </label>
101
                            <select class="cancellation-reason col-sm-8" name="cancellation-reason" id="modal-cancellation-reason">
102
                                <option value="" selected>Other reasons</option>
103
                                [% FOREACH reason IN ar_cancellation %]
104
                                    <option value="[% reason.authorised_value | html %]">[% reason.lib | html %]</option>
105
                                [% END %]
106
                            </select>
107
                        [% END %]
108
                    </fieldset>
109
                    <fieldset class="action">
110
                        <div class="hint col-sm-offset-4">Enter reason</div>
111
                        <input type="text" class="notes col-sm-offset-4 col-sm-8" name="notes" id="modal-notes"/>
112
                    </fieldset>
113
                </div>
114
115
                <div class="modal-footer">
116
                    <button id="cancelModalConfirmBtn" type="button" class="btn btn-danger" data-dismiss="modal">Confirm cancellation</button>
117
                    <a href="#" data-dismiss="modal">Cancel</a>
118
                </div>
119
            </div>
120
        </div>
121
    </div>
122
[% END %]
85
123
86
<body id="circ_article-requests" class="circ">
124
<body id="circ_article-requests" class="circ">
87
    [% INCLUDE 'header.inc' %]
125
    [% INCLUDE 'header.inc' %]
Lines 465-470 Link Here
465
            </div>
503
            </div>
466
        </div>
504
        </div>
467
    </div>
505
    </div>
506
    [% PROCESS cancel_modal %]
468
507
469
[% MACRO jsinclude BLOCK %]
508
[% MACRO jsinclude BLOCK %]
470
    [% INCLUDE 'datatables.inc' %]
509
    [% INCLUDE 'datatables.inc' %]
Lines 573-602 Link Here
573
            window.open(link, 'popup', 'width=600,height=400,resizable=1,toolbar=0,scrollbars=1,top');
612
            window.open(link, 'popup', 'width=600,height=400,resizable=1,toolbar=0,scrollbars=1,top');
574
        }
613
        }
575
614
615
        $('#modal-cancellation-reason').on('change', function(e) {
616
            let reason = $(this).val();
617
            $('#modal-notes').attr('disabled', !!reason);
618
        })
619
620
        // Confirm cancellation of article requests
621
        let cancel_id;
622
        let cancel_a;
623
        $("#cancelModalConfirmBtn").on("click",function(e) {
624
            let reason = $("#modal-cancellation-reason").val();
625
            let notes = $("#modal-notes").val();
626
            let query = '?'+(reason?'cancellation_reason='+reason:'notes='+notes)
627
628
            HandleMulti(function(id, a) {
629
                var table_row = a.closest('tr');
630
                table_row.find('.ar-process-request').remove();
631
                table_row.find('input[type="checkbox"]').prop('checked', false);
632
633
634
                a.closest('td').prepend('<img src="[% interface | html %]/[% theme | html %]/img/spinner-small.gif"/>').find('div.dropdown').hide();
635
636
                $.ajax({
637
                    type: "DELETE",
638
                    url: '/api/v1/article_requests/'+id+query,
639
                    success: function( data ) {
640
                        active_datatable.row( a.closest('tr') ).remove().draw();
641
                        UpdateTabCounts();
642
                        activateBatchActions( active_tab );
643
                    }
644
                });
645
            }, cancel_id, cancel_a)
646
        });
647
576
        function Cancel( id, a ) {
648
        function Cancel( id, a ) {
577
            // last_cancel_reason: undefined means 'prompt for new reason'
649
            cancel_id = id;
578
            // a null value indicates that prompt was cancelled
650
            cancel_a = a;
579
            if( last_cancel_reason === undefined ) last_cancel_reason = prompt(_("Please specify the reason for cancelling selected item(s):"));
580
            if ( last_cancel_reason === null ) {
581
                return;
582
            }
583
651
584
            a.closest('td').prepend('<img src="[% interface | html %]/[% theme | html %]/img/spinner-small.gif"/>').find('div.dropdown').hide();
652
            $('#cancelModal').modal();
585
            $.ajax({
586
                type: "POST",
587
                url: '/cgi-bin/koha/svc/article_request',
588
                data: {
589
                    action: 'cancel',
590
                    id: id,
591
                    notes: last_cancel_reason
592
                },
593
                success: function( data ) {
594
                    active_datatable.row( a.closest('tr') ).remove().draw();
595
                    UpdateTabCounts();
596
                    activateBatchActions( active_tab );
597
                },
598
                dataType: 'json'
599
            });
600
        }
653
        }
601
654
602
        function SetPending( id, a ) {
655
        function SetPending( id, a ) {
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/request-article.tt (-21 / +67 lines)
Lines 3-8 Link Here
3
[% USE KohaDates %]
3
[% USE KohaDates %]
4
[% USE Branches %]
4
[% USE Branches %]
5
[% USE ItemTypes %]
5
[% USE ItemTypes %]
6
[% USE AuthorisedValues %]
6
[% SET footerjs = 1 %]
7
[% SET footerjs = 1 %]
7
[% SET article_requests_view = 1 %]
8
[% SET article_requests_view = 1 %]
8
[% SET biblionumber = biblio.biblionumber %]
9
[% SET biblionumber = biblio.biblionumber %]
Lines 11-16 Link Here
11
[% INCLUDE 'doc-head-close.inc' %]
12
[% INCLUDE 'doc-head-close.inc' %]
12
</head>
13
</head>
13
14
15
[% BLOCK cancel_modal %]
16
    <div id="cancelModal" class="modal" tabindex="-1" role="dialog" aria-hidden="true">
17
        <div class="modal-dialog" role="document">
18
            <div class="modal-content">
19
                <div class="modal-header">
20
                    <button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">×</button>
21
                    <h3>Confirm deletion</h3>
22
                </div>
23
24
                <div class="modal-body">
25
                    <p>Are you sure you want to cancel this article request?</p>
26
27
                    <fieldset class="action">
28
                        [% SET ar_cancellation = AuthorisedValues.GetAuthValueDropbox('AR_CANCELLATION') %]
29
                        [% IF ar_cancellation %]
30
                            <label for="cancellation-reason" class="col-sm-4">Cancellation reason: </label>
31
                            <select class="cancellation-reason col-sm-8" name="cancellation-reason" id="modal-cancellation-reason">
32
                                <option value="" selected>Other reasons</option>
33
                                [% FOREACH reason IN ar_cancellation %]
34
                                    <option value="[% reason.authorised_value | html %]">[% reason.lib | html %]</option>
35
                                [% END %]
36
                            </select>
37
                        [% END %]
38
                    </fieldset>
39
                    <fieldset class="action">
40
                        <div class="hint col-sm-offset-4">Enter reason</div>
41
                        <input type="text" class="notes col-sm-offset-4 col-sm-8" name="notes" id="modal-notes"/>
42
                    </fieldset>
43
                </div>
44
45
                <div class="modal-footer">
46
                    <button id="cancelModalConfirmBtn" type="button" class="btn btn-danger" data-dismiss="modal">Confirm cancellation</button>
47
                    <a href="#" data-dismiss="modal">Cancel</a>
48
                </div>
49
            </div>
50
        </div>
51
    </div>
52
[% END %]
53
14
<body id="circ_request-article" class="circ">
54
<body id="circ_request-article" class="circ">
15
    [% INCLUDE 'header.inc' %]
55
    [% INCLUDE 'header.inc' %]
16
    [% INCLUDE 'circ-search.inc' %]
56
    [% INCLUDE 'circ-search.inc' %]
Lines 317-322 Link Here
317
                                [% END %]
357
                                [% END %]
318
                            </table>
358
                            </table>
319
                        </fieldset>
359
                        </fieldset>
360
                        [% PROCESS cancel_modal %]
320
                    [% END %]
361
                    [% END %]
321
362
322
            </main>
363
            </main>
Lines 401-429 Link Here
401
                }
442
                }
402
            });
443
            });
403
444
404
            $(".ar-cancel-request").on("click", function(){
445
            $('#modal-cancellation-reason').on('change', function(e) {
405
                var a = $(this);
446
                let reason = $(this).val();
406
                var notes = prompt(_("Reason for cancellation:"));
447
                $('#modal-notes').attr('disabled', !!reason);
448
            })
449
450
            let cancel_a;
451
            $("#cancelModalConfirmBtn").on("click",function(e) {
452
                var id = cancel_a.attr('id').split("cancel-")[1];
453
                $("#cancel-processing-" + id ).hide('slow');
454
                $("#cancel-processing-spinner-" + id ).show('slow');
455
456
                let reason = $("#modal-cancellation-reason").val();
457
                let notes = $("#modal-notes").val();
458
                let query = '?'+(reason?'cancellation_reason='+reason:'notes='+notes)
459
460
                $.ajax({
461
                    type: "DELETE",
462
                    url: '/api/v1/article_requests/'+id+query,
463
                    success: function( data ) {
464
                        cancel_a.parents('tr').hide('slow');
465
                    }
466
                });
467
            });
407
468
408
                if ( notes != null ) {
409
                    var id = this.id.split("cancel-")[1];
410
                    $("#cancel-processing-" + id ).hide('slow');
411
                    $("#cancel-processing-spinner-" + id ).show('slow');
412
469
413
                    $.ajax({
470
            $(".ar-cancel-request").on("click", function(){
414
                        type: "POST",
471
                cancel_a = $(this);
415
                        url: '/cgi-bin/koha/svc/article_request',
472
                $('#cancelModal').modal();
416
                        data: {
417
                            action: 'cancel',
418
                            id: id,
419
                            notes: notes
420
                        },
421
                        success: function( data ) {
422
                            a.parents('tr').hide('slow');
423
                        },
424
                        dataType: 'json'
425
                    });
426
                }
427
            });
473
            });
428
474
429
            // Initialize format(s)
475
            // Initialize format(s)
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt (-12 / +34 lines)
Lines 5-10 Link Here
5
[% USE Branches %]
5
[% USE Branches %]
6
[% USE ItemTypes %]
6
[% USE ItemTypes %]
7
[% USE Price %]
7
[% USE Price %]
8
[% USE AuthorisedValues %]
8
[% SET AdlibrisEnabled = Koha.Preference('AdlibrisCoversEnabled') %]
9
[% SET AdlibrisEnabled = Koha.Preference('AdlibrisCoversEnabled') %]
9
[% SET AdlibrisURL = Koha.Preference('AdlibrisCoversURL') %]
10
[% SET AdlibrisURL = Koha.Preference('AdlibrisCoversURL') %]
10
11
Lines 715-721 Link Here
715
                            <div id="opac-user-article-requests">
716
                            <div id="opac-user-article-requests">
716
                                [% IF logged_in_user.article_requests_current.count %]
717
                                [% IF logged_in_user.article_requests_current.count %]
717
                                    <table id="article-requests-table" class="table table-bordered table-striped">
718
                                    <table id="article-requests-table" class="table table-bordered table-striped">
718
                                        <caption>Article requests <span class="count">([% logged_in_user.article_requests_current.count | html %] total)</span></caption>
719
                                        <caption>Article requests <span class="count"></span></caption>
719
                                        <thead>
720
                                        <thead>
720
                                            <tr>
721
                                            <tr>
721
                                                <th class="anti-the article-request-record-title">Record title</th>
722
                                                <th class="anti-the article-request-record-title">Record title</th>
Lines 803-814 Link Here
803
                                                </td>
804
                                                </td>
804
805
805
                                                <td class="article-request-cancel">
806
                                                <td class="article-request-cancel">
806
                                                    <span class="tdlabel">Cancel:</span>
807
                                                    <button data-title="[% ar.biblio.title | html %] [% ar.item.enumchron | html %]" data-article-request_id="[% ar.id | html %]" class="btn btn-sm btn-danger btn-delete-article-request"><i class="fa fa-remove" aria-hidden="true"></i> Cancel</button>
807
                                                    <form action="/cgi-bin/koha/opac-article-request-cancel.pl" id="delete_article_request_[% ar.id | html %]">
808
                                                        <legend class="sr-only">Cancel article request</legend>
809
                                                        <input type="hidden" name="id" value="[% ar.id | html %]" />
810
                                                        <button data-title="[% ar.biblio.title | html %] [% ar.item.enumchron | html %]" data-article-request_id="[% ar.id | html %]" type="submit" class="btn btn-sm btn-danger btn-delete-article-request"><i class="fa fa-remove" aria-hidden="true"></i> Cancel</button>
811
                                                    </form>
812
                                                </td>
808
                                                </td>
813
                                            </tr>
809
                                            </tr>
814
                                        [% END %]
810
                                        [% END %]
Lines 845-850 Link Here
845
    [% INCLUDE 'calendar.inc' %]
841
    [% INCLUDE 'calendar.inc' %]
846
    [% INCLUDE 'datatables.inc' %]
842
    [% INCLUDE 'datatables.inc' %]
847
    <script>
843
    <script>
844
        var AR_CAPTION_COUNT = _("(%s total)");
845
846
848
        function tableInit( tableId ){
847
        function tableInit( tableId ){
849
            if( tableId == "checkoutst" ){
848
            if( tableId == "checkoutst" ){
850
                $(".dt-buttons").append("<button type=\"button\" class=\"dt-button buttons-ical\" id=\"buttons-ics\">iCal</button> ");
849
                $(".dt-buttons").append("<button type=\"button\" class=\"dt-button buttons-ical\" id=\"buttons-ics\">iCal</button> ");
Lines 854-859 Link Here
854
            }
853
            }
855
        }
854
        }
856
        $(document).ready(function(){
855
        $(document).ready(function(){
856
            $('#opac-user-article-requests caption .count').html(AR_CAPTION_COUNT.format('[% logged_in_user.article_requests_current.count | html %]'));
857
            $('#opac-user-views').tabs();
857
            $('#opac-user-views').tabs();
858
            $(".modal-nojs").addClass("modal").addClass("hide").removeClass("modal-nojs");
858
            $(".modal-nojs").addClass("modal").addClass("hide").removeClass("modal-nojs");
859
            $(".suspend-until").prop("readonly",1);
859
            $(".suspend-until").prop("readonly",1);
Lines 863-868 Link Here
863
                var hold_title = $(this).data("title");
863
                var hold_title = $(this).data("title");
864
                var reserve_id = $(this).data("reserve_id");
864
                var reserve_id = $(this).data("reserve_id");
865
                confirmModal( hold_title, _("Are you sure you want to cancel this hold?"), _("Yes, cancel hold"), _("No, do not cancel hold"), function( result ){
865
                confirmModal( hold_title, _("Are you sure you want to cancel this hold?"), _("Yes, cancel hold"), _("No, do not cancel hold"), function( result ){
866
                        $("#bootstrap-confirm-box-modal").remove()
866
                        if( result ){
867
                        if( result ){
867
                            $("#delete_hold_" + reserve_id ).submit();
868
                            $("#delete_hold_" + reserve_id ).submit();
868
                        }
869
                        }
Lines 874-885 Link Here
874
                e.preventDefault();
875
                e.preventDefault();
875
                var article_request = $(this).data("title");
876
                var article_request = $(this).data("title");
876
                var article_request_id = $(this).data("article-request_id");
877
                var article_request_id = $(this).data("article-request_id");
877
                confirmModal( article_request, _("Are you sure you want to cancel this article request?"), _("Yes, cancel article request"), _("No, do not cancel article request"), function( result ){
878
                (function(row){
879
                    var doCancel = function( result ){
880
                        $("#bootstrap-confirm-box-modal").remove();
878
                        if( result ){
881
                        if( result ){
879
                            $("#delete_article_request_" + article_request_id ).submit();
882
                            $.ajax({
883
                                type: "DELETE",
884
                                url: '/api/v1/public/patrons/'+borrowernumber+'/article_requests/'+article_request_id,
885
                                success: function( data ) {
886
                                    row.parents('tr').hide({
887
                                        duration: 'slow',
888
                                        complete: function() {
889
                                            var ar_tab = $('a[href="#opac-user-article-requests"');
890
                                            var ar_table = $('#article-requests-table');
891
                                            var ar_length = $('tbody tr:visible', ar_table).length;
892
                                            var ar_count = $('caption .count', ar_table);
893
894
                                            ar_tab.html(ar_tab.html().replace(/\(\d+\)/, '('+ar_length+')'));
895
                                            ar_count.html(AR_CAPTION_COUNT.format(ar_length));
896
                                        }
897
                                    });
898
                                }
899
                            });
880
                        }
900
                        }
881
                    }
901
                    };
882
                );
902
                    confirmModal( article_request, _("Are you sure you want to cancel this article request?"), _("Yes, cancel article request"), _("No, do not cancel article request"), doCancel);
903
                })($(this))
883
            });
904
            });
884
905
885
            $("#suspend_all_submit").on("click", function(e){
906
            $("#suspend_all_submit").on("click", function(e){
Lines 887-892 Link Here
887
                var title = _("Are you sure you want to suspend all holds?");
908
                var title = _("Are you sure you want to suspend all holds?");
888
                var body = _("All holds will be suspended.");
909
                var body = _("All holds will be suspended.");
889
                confirmModal( body, title, _("Yes, suspend all holds"), "", function( result ){
910
                confirmModal( body, title, _("Yes, suspend all holds"), "", function( result ){
911
                        $("#bootstrap-confirm-box-modal").remove()
890
                        if( result ){
912
                        if( result ){
891
                            $("#suspend_all_holds").submit();
913
                            $("#suspend_all_holds").submit();
892
                        }
914
                        }
Lines 899-904 Link Here
899
                var title = _("Are you sure you want to resume all suspended holds?");
921
                var title = _("Are you sure you want to resume all suspended holds?");
900
                var body = _("All holds will resume.");
922
                var body = _("All holds will resume.");
901
                confirmModal( body, title, _("Yes, resume all holds"), _("No, do not resume holds"), function( result ){
923
                confirmModal( body, title, _("Yes, resume all holds"), _("No, do not resume holds"), function( result ){
924
                        $("#bootstrap-confirm-box-modal").remove()
902
                        if( result ){
925
                        if( result ){
903
                            $("#resume_all_holds").submit();
926
                            $("#resume_all_holds").submit();
904
                        }
927
                        }
905
- 

Return to bug 27947