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

(-)a/Koha/Hold.pm (-4 / +29 lines)
Lines 179-184 sub delete { Link Here
179
    return $deleted;
179
    return $deleted;
180
}
180
}
181
181
182
=head3 cleanup_hold_group
183
184
$self->cleanup_hold_group;
185
186
Check if a hold group is left with a single or zero holds. Delete hold_group if so.
187
Accepts an optional $hold_group_id that, if defined, uses that instead of self->hold_group_id
188
189
=cut
190
191
sub cleanup_hold_group {
192
    my ( $self, $hold_group_id ) = @_;
193
194
    my $hold_group_id_to_check = $hold_group_id // $self->hold_group_id;
195
    my $hold_group             = Koha::HoldGroups->find($hold_group_id_to_check);
196
    return unless $hold_group;
197
198
    if ( $hold_group->holds->count <= 1 ) {
199
        $hold_group->delete();
200
    }
201
}
202
182
=head3 set_transfer
203
=head3 set_transfer
183
204
184
=cut
205
=cut
Lines 673-681 sub cancellation_requested { Link Here
673
694
674
my $cancel_hold = $hold->cancel(
695
my $cancel_hold = $hold->cancel(
675
    {
696
    {
676
        [ charge_cancel_fee   => 1||0, ]
697
        [ charge_cancel_fee       => 1||0, ]
677
        [ cancellation_reason => $cancellation_reason, ]
698
        [ cancellation_reason     => $cancellation_reason, ]
678
        [ skip_holds_queue    => 1||0 ]
699
        [ skip_holds_queue        => 1||0 ]
700
        [ skip_hold_group_cleanup => 1||0 ]
679
    }
701
    }
680
);
702
);
681
703
Lines 799-804 sub cancel { Link Here
799
        }
821
        }
800
    );
822
    );
801
823
824
    $self->cleanup_hold_group() unless $params->{skip_hold_group_cleanup};
825
802
    if ($autofill_next) {
826
    if ($autofill_next) {
803
        my ( undef, $next_hold ) = C4::Reserves::CheckReserves( $self->item );
827
        my ( undef, $next_hold ) = C4::Reserves::CheckReserves( $self->item );
804
        if ($next_hold) {
828
        if ($next_hold) {
Lines 886-894 sub fill { Link Here
886
            if ( $self->hold_group_id ) {
910
            if ( $self->hold_group_id ) {
887
                my @holds = $self->hold_group->holds->as_list;
911
                my @holds = $self->hold_group->holds->as_list;
888
                foreach my $h (@holds) {
912
                foreach my $h (@holds) {
889
                    $h->cancel unless $h->reserve_id == $self->id;
913
                    $h->cancel( { skip_hold_group_cleanup => 1 } ) unless $h->reserve_id == $self->id;
890
                }
914
                }
891
            }
915
            }
916
            $self->cleanup_hold_group();
892
917
893
            Koha::BackgroundJob::BatchUpdateBiblioHoldsQueue->new->enqueue(
918
            Koha::BackgroundJob::BatchUpdateBiblioHoldsQueue->new->enqueue(
894
                { biblio_ids => [ $old_me->biblionumber ] } )
919
                { biblio_ids => [ $old_me->biblionumber ] } )
(-)a/Koha/Patron.pm (-1 / +7 lines)
Lines 1852-1857 Creates and returns a hold group given a list of hold ids Link Here
1852
1852
1853
If force_grouped is supplied, the hold group will be created even if the holds are already grouped
1853
If force_grouped is supplied, the hold group will be created even if the holds are already grouped
1854
1854
1855
Checks if the hold is moving from another group, and if so, removes the old group if empty
1856
1855
=cut
1857
=cut
1856
1858
1857
sub create_hold_group {
1859
sub create_hold_group {
Lines 1908-1916 sub create_hold_group { Link Here
1908
        { visual_hold_group_id => $next_available_visual_hold_group_id }
1910
        { visual_hold_group_id => $next_available_visual_hold_group_id }
1909
    );
1911
    );
1910
    foreach my $hold_id (@$hold_ids) {
1912
    foreach my $hold_id (@$hold_ids) {
1911
        my $hold = Koha::Holds->find($hold_id);
1913
        my $hold                   = Koha::Holds->find($hold_id);
1914
        my $previous_hold_group_id = $hold->hold_group_id;
1912
1915
1913
        $hold->hold_group_id( $hold_group_rs->hold_group_id )->store;
1916
        $hold->hold_group_id( $hold_group_rs->hold_group_id )->store;
1917
        if ( $previous_hold_group_id && $previous_hold_group_id != $hold_group_rs->hold_group_id ) {
1918
            $hold->cleanup_hold_group($previous_hold_group_id);
1919
        }
1914
    }
1920
    }
1915
1921
1916
    return Koha::HoldGroup->_new_from_dbic($hold_group_rs);
1922
    return Koha::HoldGroup->_new_from_dbic($hold_group_rs);
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/modals/holds_table_modals.inc (+21 lines)
Lines 74-76 Link Here
74
        </div>
74
        </div>
75
    </div>
75
    </div>
76
[% END %]
76
[% END %]
77
78
[% BLOCK 'group-hold-modal' %]
79
    <div id="group-modal" class="modal" role="dialog" aria-hidden="true">
80
        <div class="modal-dialog">
81
            <div class="modal-content">
82
                <div class="modal-header">
83
                    <h1 class="modal-title" id="suspend-modal-label"> Group selected holds </h1>
84
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
85
                </div>
86
                <div class="modal-body">
87
                    <p>Are you sure you want to group the selected holds?</p>
88
                </div>
89
                <div class="modal-footer">
90
                    <button id="group-modal-submit" class="btn btn-primary" type="submit" name="submit">Group</button>
91
                    <button type="button" class="btn btn-default" data-bs-dismiss="modal">Cancel </button>
92
                </div>
93
                <div id="inputs"></div>
94
            </div>
95
        </div>
96
    </div>
97
[% END %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/patron-detail-tabs.inc (+9 lines)
Lines 151-156 Link Here
151
                                <tr>
151
                                <tr>
152
                                    <th id="checkbox" data-colname="checkbox"><input type="checkbox" class="select_hold_all" /></th>
152
                                    <th id="checkbox" data-colname="checkbox"><input type="checkbox" class="select_hold_all" /></th>
153
                                    <th>Hold date</th>
153
                                    <th>Hold date</th>
154
                                    [% IF Koha.Preference('DisplayAddHoldGroups') %]
155
                                        <th>Hold group</th>
156
                                    [% END %]
154
                                    <th class="anti-the">Title</th>
157
                                    <th class="anti-the">Title</th>
155
                                    <th>Call number</th>
158
                                    <th>Call number</th>
156
                                    <th>Item type</th>
159
                                    <th>Item type</th>
Lines 173-178 Link Here
173
176
174
                    [% PROCESS 'cancel-hold-modal' form_action = '/cgi-bin/koha/reserve/modrequest.pl' from_param = patronpage %]
177
                    [% PROCESS 'cancel-hold-modal' form_action = '/cgi-bin/koha/reserve/modrequest.pl' from_param = patronpage %]
175
                    [% PROCESS 'suspend-hold-modal' %]
178
                    [% PROCESS 'suspend-hold-modal' %]
179
                    [% PROCESS 'group-hold-modal' %]
180
                    [% IF Koha.Preference('DisplayAddHoldGroups') %]
181
                        <fieldset class="action">
182
                            <button class="btn btn-primary group_selected_holds" data-bulk="true"></button>
183
                        </fieldset>
184
                    [% END # IF DisplayAddHoldGroups %]
176
185
177
                    [% IF Koha.Preference('SuspendHoldsIntranet') %]
186
                    [% IF Koha.Preference('SuspendHoldsIntranet') %]
178
                        <fieldset class="action">
187
                        <fieldset class="action">
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt (+1 lines)
Lines 1105-1110 Link Here
1105
            relatives_borrowernumbers.push("[% b | html %]");
1105
            relatives_borrowernumbers.push("[% b | html %]");
1106
        [% END %]
1106
        [% END %]
1107
        var SuspendHoldsIntranet = [% ( Koha.Preference('SuspendHoldsIntranet') ) ? 1 : 0 | html %];
1107
        var SuspendHoldsIntranet = [% ( Koha.Preference('SuspendHoldsIntranet') ) ? 1 : 0 | html %];
1108
        var DisplayAddHoldGroups = [% ( Koha.Preference('DisplayAddHoldGroups') ) ? 1 : 0 | html %];
1108
    </script>
1109
    </script>
1109
    [% Asset.js("js/pages/circulation.js") | $raw %]
1110
    [% Asset.js("js/pages/circulation.js") | $raw %]
1110
    [% IF Koha.Preference('ClaimReturnedLostValue') || Koha.Preference('BundleLostValue') %]
1111
    [% IF Koha.Preference('ClaimReturnedLostValue') || Koha.Preference('BundleLostValue') %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt (+1 lines)
Lines 780-785 Link Here
780
            relatives_borrowernumbers.push("[% b | html %]");
780
            relatives_borrowernumbers.push("[% b | html %]");
781
        [% END %]
781
        [% END %]
782
        var SuspendHoldsIntranet = [% ( Koha.Preference('SuspendHoldsIntranet') ) ? 1 : 0 | html %];
782
        var SuspendHoldsIntranet = [% ( Koha.Preference('SuspendHoldsIntranet') ) ? 1 : 0 | html %];
783
        var DisplayAddHoldGroups = [% ( Koha.Preference('DisplayAddHoldGroups') ) ? 1 : 0 | html %];
783
    </script>
784
    </script>
784
    [% Asset.js("js/pages/circulation.js") | $raw %]
785
    [% Asset.js("js/pages/circulation.js") | $raw %]
785
    [% IF Koha.Preference('ClaimReturnedLostValue') || Koha.Preference('BundleLostValue') %]
786
    [% IF Koha.Preference('ClaimReturnedLostValue') || Koha.Preference('BundleLostValue') %]
(-)a/koha-tmpl/intranet-tmpl/prog/js/holds.js (-25 / +131 lines)
Lines 164-169 $(document).ready(function () { Link Here
164
                                return (
164
                                return (
165
                                    '<input type="checkbox" class="select_hold" data-id="' +
165
                                    '<input type="checkbox" class="select_hold" data-id="' +
166
                                    oObj.reserve_id +
166
                                    oObj.reserve_id +
167
                                    (oObj.hold_group_id
168
                                        ? '" data-hold-group-id="' +
169
                                          oObj.hold_group_id +
170
                                          '"'
171
                                        : '"') +
167
                                    '" data-borrowernumber="' +
172
                                    '" data-borrowernumber="' +
168
                                    borrowernumber +
173
                                    borrowernumber +
169
                                    '" data-biblionumber="' +
174
                                    '" data-biblionumber="' +
Lines 178-183 $(document).ready(function () { Link Here
178
                                sort: "reservedate",
183
                                sort: "reservedate",
179
                            },
184
                            },
180
                        },
185
                        },
186
                        ...(DisplayAddHoldGroups
187
                            ? [
188
                                  {
189
                                      data: function (oObj) {
190
                                          title = "";
191
                                          if (oObj.visual_hold_group_id) {
192
                                              var link =
193
                                                  '<a class="hold-group" href="/cgi-bin/koha/reserve/hold-group.pl?hold_group_id=' +
194
                                                  oObj.hold_group_id +
195
                                                  '">' +
196
                                                  oObj.visual_hold_group_id +
197
                                                  "</a>";
198
199
                                              title =
200
                                                  "<span>" + link + "</span>";
201
                                          }
202
203
                                          return title;
204
                                      },
205
                                  },
206
                              ]
207
                            : []),
181
                        {
208
                        {
182
                            data: function (oObj) {
209
                            data: function (oObj) {
183
                                title =
210
                                title =
Lines 232-248 $(document).ready(function () { Link Here
232
                                        "</span>";
259
                                        "</span>";
233
                                }
260
                                }
234
261
235
                                if (oObj.hold_group_id) {
236
                                    title += "<br>";
237
                                    var link =
238
                                        '<a class="hold-group" href="/cgi-bin/koha/reserve/hold-group.pl?hold_group_id=' +
239
                                        oObj.hold_group_id +
240
                                        '">' +
241
                                        __("part of a hold group") +
242
                                        "</a>";
243
                                    title += "<span>(" + link + ")</span>";
244
                                }
245
246
                                return title;
262
                                return title;
247
                            },
263
                            },
248
                        },
264
                        },
Lines 603-621 $(document).ready(function () { Link Here
603
        e.preventDefault();
619
        e.preventDefault();
604
        let selected_holds;
620
        let selected_holds;
605
        if (!$(this).data("hold-id")) {
621
        if (!$(this).data("hold-id")) {
606
            selected_holds =
622
            selected_holds = get_selected_holds_data();
607
                "[" +
608
                $(".holds_table .select_hold:checked")
609
                    .toArray()
610
                    .map(el =>
611
                        JSON.stringify({
612
                            hold: $(el).data("id"),
613
                            borrowernumber: $(el).data("borrowernumber"),
614
                            biblionumber: $(el).data("biblionumber"),
615
                        })
616
                    )
617
                    .join(",") +
618
                "]";
619
        } else {
623
        } else {
620
            selected_holds =
624
            selected_holds =
621
                "[" + JSON.stringify({ hold: $(this).data("hold-id") }) + "]";
625
                "[" + JSON.stringify({ hold: $(this).data("hold-id") }) + "]";
Lines 785-790 $(document).ready(function () { Link Here
785
        });
789
        });
786
    }
790
    }
787
791
792
    var MSG_GROUP_SELECTED = _("Group selected (%s)");
793
788
    function updateSelectedHoldsButtonCounters() {
794
    function updateSelectedHoldsButtonCounters() {
789
        $(".cancel_selected_holds").html(
795
        $(".cancel_selected_holds").html(
790
            MSG_CANCEL_SELECTED.format(
796
            MSG_CANCEL_SELECTED.format(
Lines 796-801 $(document).ready(function () { Link Here
796
                $(".holds_table .select_hold:checked").length
802
                $(".holds_table .select_hold:checked").length
797
            )
803
            )
798
        );
804
        );
805
        $(".group_selected_holds").html(
806
            MSG_GROUP_SELECTED.format(
807
                $(".holds_table .select_hold:checked").length
808
            )
809
        );
799
    }
810
    }
800
811
801
    updateSelectedHoldsButtonCounters();
812
    updateSelectedHoldsButtonCounters();
Lines 926-929 $(document).ready(function () { Link Here
926
            '<input type="hidden" name="reserve_id" value="' + hold.hold + '">'
937
            '<input type="hidden" name="reserve_id" value="' + hold.hold + '">'
927
        );
938
        );
928
    }
939
    }
940
941
    $(".group_selected_holds").html(
942
        MSG_GROUP_SELECTED.format($(".holds_table .select_hold:checked").length)
943
    );
944
945
    $(".group_selected_holds").click(function (e) {
946
        if ($(".holds_table .select_hold:checked").length > 1) {
947
            let selected_holds = get_selected_holds_data();
948
            const group_ids = JSON.parse(selected_holds)
949
                .filter(hold => hold.hold_group_id)
950
                .map(hold => hold.hold_group_id);
951
952
            if (group_ids.length > 0) {
953
                $("#group-modal .modal-body").prepend(
954
                    '<div class="alert alert-warning">' +
955
                        __(
956
                            "Already grouped holds will be moved to the new group"
957
                        ) +
958
                        "</div>"
959
                );
960
            }
961
962
            $("#group-modal").modal("show");
963
        }
964
        return false;
965
    });
966
967
    $("#group-modal-submit").click(function (e) {
968
        e.preventDefault();
969
        let selected_holds = get_selected_holds_data();
970
971
        const hold_ids = JSON.parse(selected_holds).map(hold => hold.hold);
972
973
        try {
974
            group_holds(hold_ids)
975
                .success(function () {
976
                    holdsTable.api().ajax.reload();
977
                })
978
                .fail(function (jqXHR) {
979
                    $("#group-modal .modal-body").prepend(
980
                        '<div class="alert alert-danger">' +
981
                            jqXHR.responseJSON.error +
982
                            "</div>"
983
                    );
984
                    $("#group-modal-submit").prop("disabled", true);
985
                })
986
                .done(function () {
987
                    $("#group-modal").modal("hide");
988
                    $(".select_hold_all").click();
989
                });
990
        } catch (error) {
991
            if (error.status === 404) {
992
                alert(__("Unable to group, hold not found."));
993
            } else {
994
                alert(
995
                    __(
996
                        "Your request could not be processed. Check the logs for details."
997
                    )
998
                );
999
            }
1000
        }
1001
        return false;
1002
    });
1003
1004
    function group_holds(hold_ids) {
1005
        return $.ajax({
1006
            method: "POST",
1007
            url: "/api/v1/patrons/" + borrowernumber + "/hold_groups",
1008
            contentType: "application/json",
1009
            data: JSON.stringify({ hold_ids: hold_ids, force_grouped: true }),
1010
        });
1011
    }
1012
1013
    $("#group-modal").on("hidden.bs.modal", function () {
1014
        $("#group-modal .modal-body .alert-warning").remove();
1015
        $("#group-modal .modal-body .alert-danger").remove();
1016
        $("#group-modal-submit").prop("disabled", false);
1017
    });
1018
1019
    function get_selected_holds_data() {
1020
        return (
1021
            "[" +
1022
            $(".holds_table .select_hold:checked")
1023
                .toArray()
1024
                .map(el =>
1025
                    JSON.stringify({
1026
                        hold: $(el).data("id"),
1027
                        borrowernumber: $(el).data("borrowernumber"),
1028
                        biblionumber: $(el).data("biblionumber"),
1029
                        hold_group_id: $(el).data("hold-group-id"),
1030
                    })
1031
                )
1032
                .join(",") +
1033
            "]"
1034
        );
1035
    }
929
});
1036
});
930
- 

Return to bug 40517