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

(-)a/C4/Circulation.pm (-75 / +1 lines)
Lines 825-839 sub CanBookBeIssued { Link Here
825
    my $circ_library = Koha::Libraries->find( _GetCircControlBranch( $item_object, $patron ) );
825
    my $circ_library = Koha::Libraries->find( _GetCircControlBranch( $item_object, $patron ) );
826
826
827
    my $now = dt_from_string();
827
    my $now = dt_from_string();
828
    my @message_log;
829
828
830
    $duedate ||= CalcDateDue( $now, $effective_itemtype, $circ_library->branchcode, $patron );
829
    $duedate ||= CalcDateDue( $now, $effective_itemtype, $circ_library->branchcode, $patron );
831
830
832
    if ( DateTime->compare( $duedate, $now ) == -1 ) {    # duedate cannot be before now
831
    if ( DateTime->compare( $duedate, $now ) == -1 ) {    # duedate cannot be before now
833
        $needsconfirmation{INVALID_DATE} = $duedate;
832
        $needsconfirmation{INVALID_DATE} = $duedate;
834
        if ($issueconfirmed) {
835
            push( @message_log, "sticky due date is invalid or due date in the past" );
836
        }
837
    }
833
    }
838
834
839
    my $fees = Koha::Charges::Fees->new(
835
    my $fees = Koha::Charges::Fees->new(
Lines 879-887 sub CanBookBeIssued { Link Here
879
    }
875
    }
880
    if ( $patron->is_debarred ) {
876
    if ( $patron->is_debarred ) {
881
        $issuingimpossible{DEBARRED} = 1;
877
        $issuingimpossible{DEBARRED} = 1;
882
        if ($issueconfirmed) {
883
            push( @message_log, "borrower is restricted" );
884
        }
885
    }
878
    }
886
879
887
    if ( $patron->is_expired ) {
880
    if ( $patron->is_expired ) {
Lines 954-969 sub CanBookBeIssued { Link Here
954
    } else {
947
    } else {
955
        if ( $patron_borrowing_status->{noissuescharge}->{overlimit} && $allowfineoverride ) {
948
        if ( $patron_borrowing_status->{noissuescharge}->{overlimit} && $allowfineoverride ) {
956
            $needsconfirmation{DEBT} = $patron_borrowing_status->{noissuescharge}->{charge};
949
            $needsconfirmation{DEBT} = $patron_borrowing_status->{noissuescharge}->{charge};
957
            if ($issueconfirmed) {
958
                push( @message_log, "borrower had amend" );
959
            }
960
        } elsif ( $patron_borrowing_status->{noissuescharge}->{overlimit} && !$allowfineoverride ) {
950
        } elsif ( $patron_borrowing_status->{noissuescharge}->{overlimit} && !$allowfineoverride ) {
961
            $issuingimpossible{DEBT} = $patron_borrowing_status->{noissuescharge}->{charge};
951
            $issuingimpossible{DEBT} = $patron_borrowing_status->{noissuescharge}->{charge};
962
        } elsif ( $patron_borrowing_status->{noissuescharge}->{charge} > 0 && $allfinesneedoverride ) {
952
        } elsif ( $patron_borrowing_status->{noissuescharge}->{charge} > 0 && $allfinesneedoverride ) {
963
            $needsconfirmation{DEBT} = $patron_borrowing_status->{noissuescharge}->{charge};
953
            $needsconfirmation{DEBT} = $patron_borrowing_status->{noissuescharge}->{charge};
964
            if ($issueconfirmed) {
965
                push( @message_log, "borrower had amend" );
966
            }
967
        }
954
        }
968
    }
955
    }
969
956
Lines 1044-1052 sub CanBookBeIssued { Link Here
1044
                $needsconfirmation{issued_surname}        = $patron->surname;
1031
                $needsconfirmation{issued_surname}        = $patron->surname;
1045
                $needsconfirmation{issued_cardnumber}     = $patron->cardnumber;
1032
                $needsconfirmation{issued_cardnumber}     = $patron->cardnumber;
1046
                $needsconfirmation{issued_borrowernumber} = $patron->borrowernumber;
1033
                $needsconfirmation{issued_borrowernumber} = $patron->borrowernumber;
1047
                if ($issueconfirmed) {
1048
                    push( @message_log, "item is checked out for someone else" );
1049
                }
1050
            }
1034
            }
1051
        }
1035
        }
1052
    }
1036
    }
Lines 1074-1082 sub CanBookBeIssued { Link Here
1074
            $needsconfirmation{current_loan_count}        = $toomany->{count};
1058
            $needsconfirmation{current_loan_count}        = $toomany->{count};
1075
            $needsconfirmation{max_loans_allowed}         = $toomany->{max_allowed};
1059
            $needsconfirmation{max_loans_allowed}         = $toomany->{max_allowed};
1076
            $needsconfirmation{circulation_rule_TOO_MANY} = $toomany->{circulation_rule};
1060
            $needsconfirmation{circulation_rule_TOO_MANY} = $toomany->{circulation_rule};
1077
            if ($issueconfirmed) {
1078
                push( @message_log, "too many checkout" );
1079
            }
1080
        } else {
1061
        } else {
1081
            $issuingimpossible{TOO_MANY}                  = $toomany->{reason};
1062
            $issuingimpossible{TOO_MANY}                  = $toomany->{reason};
1082
            $issuingimpossible{current_loan_count}        = $toomany->{count};
1063
            $issuingimpossible{current_loan_count}        = $toomany->{count};
Lines 1109-1117 sub CanBookBeIssued { Link Here
1109
        } else {
1090
        } else {
1110
            $needsconfirmation{NOT_FOR_LOAN_FORCING} = 1;
1091
            $needsconfirmation{NOT_FOR_LOAN_FORCING} = 1;
1111
            $needsconfirmation{item_notforloan}      = $item_object->notforloan;
1092
            $needsconfirmation{item_notforloan}      = $item_object->notforloan;
1112
            if ($issueconfirmed) {
1113
                push( @message_log, "item not for loan" );
1114
            }
1115
        }
1093
        }
1116
    } else {
1094
    } else {
1117
1095
Lines 1157-1165 sub CanBookBeIssued { Link Here
1157
        my $code = $av->count ? $av->next->lib : '';
1135
        my $code = $av->count ? $av->next->lib : '';
1158
        $needsconfirmation{ITEM_LOST} = $code if ( C4::Context->preference("IssueLostItem") eq 'confirm' );
1136
        $needsconfirmation{ITEM_LOST} = $code if ( C4::Context->preference("IssueLostItem") eq 'confirm' );
1159
        $alerts{ITEM_LOST}            = $code if ( C4::Context->preference("IssueLostItem") eq 'alert' );
1137
        $alerts{ITEM_LOST}            = $code if ( C4::Context->preference("IssueLostItem") eq 'alert' );
1160
        if ($issueconfirmed) {
1161
            push( @message_log, "item lost" );
1162
        }
1163
    }
1138
    }
1164
    if ( C4::Context->preference("IndependentBranches") ) {
1139
    if ( C4::Context->preference("IndependentBranches") ) {
1165
        my $userenv = C4::Context->userenv;
1140
        my $userenv = C4::Context->userenv;
Lines 1260-1272 sub CanBookBeIssued { Link Here
1260
                    $needsconfirmation{'resbranchcode'}     = $res->{branchcode};
1235
                    $needsconfirmation{'resbranchcode'}     = $res->{branchcode};
1261
                    $needsconfirmation{'reswaitingdate'}    = $res->{'waitingdate'};
1236
                    $needsconfirmation{'reswaitingdate'}    = $res->{'waitingdate'};
1262
                    $needsconfirmation{'reserve_id'}        = $res->{reserve_id};
1237
                    $needsconfirmation{'reserve_id'}        = $res->{reserve_id};
1263
1264
                    if ($issueconfirmed) {
1265
                        push(
1266
                            @message_log,
1267
                            "item is on reserve and waiting, but has been reserved by some other patron"
1268
                        );
1269
                    }
1270
                } elsif ( $restype eq "Reserved" ) {
1238
                } elsif ( $restype eq "Reserved" ) {
1271
1239
1272
                    # The item is on reserve for someone else.
1240
                    # The item is on reserve for someone else.
Lines 1278-1287 sub CanBookBeIssued { Link Here
1278
                    $needsconfirmation{'resbranchcode'}     = $res->{branchcode};
1246
                    $needsconfirmation{'resbranchcode'}     = $res->{branchcode};
1279
                    $needsconfirmation{'resreservedate'}    = $res->{reservedate};
1247
                    $needsconfirmation{'resreservedate'}    = $res->{reservedate};
1280
                    $needsconfirmation{'reserve_id'}        = $res->{reserve_id};
1248
                    $needsconfirmation{'reserve_id'}        = $res->{reserve_id};
1281
1282
                    if ($issueconfirmed) {
1283
                        push( @message_log, "item is on reserve for someone else" );
1284
                    }
1285
                } elsif ( $restype eq "Transferred" ) {
1249
                } elsif ( $restype eq "Transferred" ) {
1286
1250
1287
                    # The item is determined hold being transferred for someone else.
1251
                    # The item is determined hold being transferred for someone else.
Lines 1293-1302 sub CanBookBeIssued { Link Here
1293
                    $needsconfirmation{'resbranchcode'}     = $res->{branchcode};
1257
                    $needsconfirmation{'resbranchcode'}     = $res->{branchcode};
1294
                    $needsconfirmation{'resreservedate'}    = $res->{reservedate};
1258
                    $needsconfirmation{'resreservedate'}    = $res->{reservedate};
1295
                    $needsconfirmation{'reserve_id'}        = $res->{reserve_id};
1259
                    $needsconfirmation{'reserve_id'}        = $res->{reserve_id};
1296
1297
                    if ($issueconfirmed) {
1298
                        push( @message_log, "item is determined hold being transferred for someone else" );
1299
                    }
1300
                } elsif ( $restype eq "Processing" ) {
1260
                } elsif ( $restype eq "Processing" ) {
1301
1261
1302
                    # The item is determined hold being processed for someone else.
1262
                    # The item is determined hold being processed for someone else.
Lines 1308-1317 sub CanBookBeIssued { Link Here
1308
                    $needsconfirmation{'resbranchcode'}     = $res->{branchcode};
1268
                    $needsconfirmation{'resbranchcode'}     = $res->{branchcode};
1309
                    $needsconfirmation{'resreservedate'}    = $res->{reservedate};
1269
                    $needsconfirmation{'resreservedate'}    = $res->{reservedate};
1310
                    $needsconfirmation{'reserve_id'}        = $res->{reserve_id};
1270
                    $needsconfirmation{'reserve_id'}        = $res->{reserve_id};
1311
1312
                    if ($issueconfirmed) {
1313
                        push( @message_log, "item is determined hold being processed for someone else" );
1314
                    }
1315
                }
1271
                }
1316
            }
1272
            }
1317
        }
1273
        }
Lines 1355-1363 sub CanBookBeIssued { Link Here
1355
    if ( $restriction_age && $patron->dateofbirth && $restriction_age > $patron->get_age() ) {
1311
    if ( $restriction_age && $patron->dateofbirth && $restriction_age > $patron->get_age() ) {
1356
        if ( C4::Context->preference('AgeRestrictionOverride') ) {
1312
        if ( C4::Context->preference('AgeRestrictionOverride') ) {
1357
            $needsconfirmation{AGE_RESTRICTION} = "$agerestriction";
1313
            $needsconfirmation{AGE_RESTRICTION} = "$agerestriction";
1358
            if ($issueconfirmed) {
1359
                push( @message_log, "age restriction" );
1360
            }
1361
        } else {
1314
        } else {
1362
            $issuingimpossible{AGE_RESTRICTION} = "$agerestriction";
1315
            $issuingimpossible{AGE_RESTRICTION} = "$agerestriction";
1363
        }
1316
        }
Lines 1416-1449 sub CanBookBeIssued { Link Here
1416
        }
1369
        }
1417
    }
1370
    }
1418
1371
1419
    my $borrower   = $patron;
1372
    return ( \%issuingimpossible, \%needsconfirmation, \%alerts, \%messages );
1420
    my $user       = C4::Context->userenv->{number};
1421
    my $branchcode = C4::Context->userenv->{branch};
1422
1423
    # action, cardnumber, barcode, date, heure, user, branche
1424
    if ($issueconfirmed) {
1425
1426
        my $infos = (
1427
            {
1428
                message        => \@message_log,
1429
                borrowernumber => $borrower->borrowernumber,
1430
                barcode        => $barcode,
1431
                manager_id     => $user,
1432
                branchcode     => $branchcode,
1433
            }
1434
        );
1435
1436
        my $json_infos = JSON->new->utf8->pretty->encode($infos);
1437
        $json_infos =~ s/"/'/g;
1438
1439
        logaction(
1440
            "CIRCULATION", "ISSUE",
1441
            $borrower->{'borrowernumber'},
1442
            $json_infos,
1443
        ) if C4::Context->preference("IssueLog");
1444
    }
1445
1446
    return ( \%issuingimpossible, \%needsconfirmation, \%alerts, \%messages, \@message_log );
1447
}
1373
}
1448
1374
1449
=head2 CanBookBeReturned
1375
=head2 CanBookBeReturned
(-)a/C4/Reserves.pm (-2 / +22 lines)
Lines 22-27 package C4::Reserves; Link Here
22
22
23
use Modern::Perl;
23
use Modern::Perl;
24
24
25
use JSON qw( to_json );
26
25
use C4::Accounts;
27
use C4::Accounts;
26
use C4::Biblio      qw( GetMarcFromKohaField );
28
use C4::Biblio      qw( GetMarcFromKohaField );
27
use C4::Circulation qw( CheckIfIssuedToPatron GetAgeRestriction GetBranchItemRule );
29
use C4::Circulation qw( CheckIfIssuedToPatron GetAgeRestriction GetBranchItemRule );
Lines 192-197 sub AddReserve { Link Here
192
    my $itemtype               = $params->{itemtype};
194
    my $itemtype               = $params->{itemtype};
193
    my $non_priority           = $params->{non_priority};
195
    my $non_priority           = $params->{non_priority};
194
    my $item_group_id          = $params->{item_group_id};
196
    my $item_group_id          = $params->{item_group_id};
197
    my $confirmations          = $params->{confirmations};
198
    my $forced                 = $params->{forced};
195
199
196
    $resdate ||= dt_from_string;
200
    $resdate ||= dt_from_string;
197
201
Lines 261-268 sub AddReserve { Link Here
261
    # record patron activity
265
    # record patron activity
262
    $hold->patron->update_lastseen('hold');
266
    $hold->patron->update_lastseen('hold');
263
267
264
    logaction( 'HOLDS', 'CREATE', $hold->id, $hold )
268
    # Log the hold creation
265
        if C4::Context->preference('HoldsLog');
269
    if ( C4::Context->preference('HoldsLog') ) {
270
        my $info = $hold->id;
271
        if ( defined($confirmations) || defined($forced) ) {
272
            $info = to_json(
273
                {
274
                    hold          => $hold->id,
275
                    branchcode    => $hold->branchcode,
276
                    biblionumber  => $hold->biblionumber,
277
                    itemnumber    => $hold->itemnumber,
278
                    confirmations => $confirmations,
279
                    forced        => $forced
280
                },
281
                { pretty => 1, canonical => 1 }
282
            );
283
        }
284
        logaction( 'HOLDS', 'CREATE', $hold->id, $info );
285
    }
266
286
267
    my $reserve_id = $hold->id();
287
    my $reserve_id = $hold->id();
268
288
(-)a/Koha/REST/V1/Holds.pm (+7 lines)
Lines 191-196 sub add { Link Here
191
191
192
        my $priority = C4::Reserves::CalculatePriority($biblio_id);
192
        my $priority = C4::Reserves::CalculatePriority($biblio_id);
193
193
194
        # Build confirmations array for logging overrides
195
        my $confirmations = [];
196
        if ($override_all) {
197
            push @{$confirmations}, 'HOLD_POLICY_OVERRIDE';
198
        }
199
194
        my $hold_id = C4::Reserves::AddReserve(
200
        my $hold_id = C4::Reserves::AddReserve(
195
            {
201
            {
196
                branchcode       => $pickup_library_id,
202
                branchcode       => $pickup_library_id,
Lines 206-211 sub add { Link Here
206
                itemtype         => $item_type,
212
                itemtype         => $item_type,
207
                non_priority     => $non_priority,
213
                non_priority     => $non_priority,
208
                item_group_id    => $item_group_id,
214
                item_group_id    => $item_group_id,
215
                confirmations    => $confirmations,
209
            }
216
            }
210
        );
217
        );
211
218
(-)a/circ/circulation.pl (-33 lines)
Lines 39-45 use C4::Members; Link Here
39
use C4::Biblio   qw( TransformMarcToKoha );
39
use C4::Biblio   qw( TransformMarcToKoha );
40
use C4::Search   qw( new_record_from_zebra );
40
use C4::Search   qw( new_record_from_zebra );
41
use C4::Reserves qw( ModReserveAffect );
41
use C4::Reserves qw( ModReserveAffect );
42
use C4::Log      qw( logaction );
43
use Koha::Holds;
42
use Koha::Holds;
44
use C4::Context;
43
use C4::Context;
45
use CGI::Session;
44
use CGI::Session;
Lines 326-334 if ($patron) { Link Here
326
# STEP 3 : ISSUING
325
# STEP 3 : ISSUING
327
#
326
#
328
#
327
#
329
my $message;
330
my @message;
331
332
if ( @$barcodes && $op eq 'cud-checkout' ) {
328
if ( @$barcodes && $op eq 'cud-checkout' ) {
333
    my $checkout_infos;
329
    my $checkout_infos;
334
    for my $barcode (@$barcodes) {
330
    for my $barcode (@$barcodes) {
Lines 564-597 if ( @$barcodes && $op eq 'cud-checkout' ) { Link Here
564
                    }
560
                    }
565
                );
561
                );
566
                $template_params->{issue} = $issue;
562
                $template_params->{issue} = $issue;
567
568
                my $borrower       = $patron;
569
                my $borrowernumber = $patron->borrowernumber;
570
                my $user           = C4::Context->userenv->{number};
571
                my $branchcode     = C4::Context->userenv->{branch};
572
                $message = "Restriction overridden temporarily";
573
                @message = ("Restriction overridden temporarily");
574
575
                if ($issueconfirmed) {
576
                    my $infos = (
577
                        {
578
                            message        => \@message,
579
                            borrowernumber => $borrowernumber,
580
                            barcode        => $barcode,
581
                            manager_id     => $user,
582
                            branchcode     => $branchcode,
583
                        }
584
                    );
585
586
                    my $json_infos = JSON->new->utf8->pretty->encode($infos);
587
                    $json_infos =~ s/"/'/g;
588
589
                    logaction(
590
                        "CIRCULATION", "ISSUE",
591
                        $borrower->{'borrowernumber'},
592
                        $json_infos,
593
                    ) if C4::Context->preference("IssueLog");
594
                }
595
                $session->clear('auto_renew');
563
                $session->clear('auto_renew');
596
                $inprocess = 1;
564
                $inprocess = 1;
597
            }
565
            }
Lines 810-816 $template->param( Link Here
810
    stickyduedate             => $stickyduedate,
778
    stickyduedate             => $stickyduedate,
811
    duedatespec               => $duedatespec,
779
    duedatespec               => $duedatespec,
812
    restoreduedatespec        => $restoreduedatespec,
780
    restoreduedatespec        => $restoreduedatespec,
813
    message                   => $message,
814
    totaldue                  => sprintf( '%.2f', $balance ),                         # FIXME not used in template?
781
    totaldue                  => sprintf( '%.2f', $balance ),                         # FIXME not used in template?
815
    inprocess                 => $inprocess,
782
    inprocess                 => $inprocess,
816
    $view                     => 1,
783
    $view                     => 1,
(-)a/circ/renew.pl (-47 / +2 lines)
Lines 24-30 use C4::Context; Link Here
24
use C4::Auth        qw( get_template_and_user );
24
use C4::Auth        qw( get_template_and_user );
25
use C4::Output      qw( output_html_with_http_headers );
25
use C4::Output      qw( output_html_with_http_headers );
26
use C4::Circulation qw( barcodedecode CanBookBeRenewed GetLatestAutoRenewDate AddRenewal );
26
use C4::Circulation qw( barcodedecode CanBookBeRenewed GetLatestAutoRenewDate AddRenewal );
27
use C4::Log         qw( logaction );
28
use Koha::DateUtils qw( dt_from_string );
27
use Koha::DateUtils qw( dt_from_string );
29
use Koha::Database;
28
use Koha::Database;
30
use Koha::BiblioFrameworks;
29
use Koha::BiblioFrameworks;
Lines 66-107 if ( $op eq 'cud-renew' && $barcode ) { Link Here
66
65
67
            $patron = $checkout->patron;
66
            $patron = $checkout->patron;
68
            my $borrowernumber = $patron->borrowernumber;
67
            my $borrowernumber = $patron->borrowernumber;
69
            my $user           = C4::Context->userenv->{number};
70
            my $branchcode     = C4::Context->userenv->{branch};
71
            my @message;
72
68
73
            if ( ( $patron->is_debarred || q{} ) lt dt_from_string()->ymd() ) {
69
            if ( ( $patron->is_debarred || q{} ) lt dt_from_string()->ymd() ) {
74
                my $confirmations;
70
                my $confirmations;
75
                my $can_renew;
71
                my $can_renew;
76
                my $info;
72
                my $info;
77
                ( $can_renew, $error, $info ) = CanBookBeRenewed( $patron, $checkout, $override_limit );
73
                ( $can_renew, $error, $info ) = CanBookBeRenewed( $patron, $checkout, $override_limit );
78
                push @{$confirmations}, $override_limit if $override_limit;
74
                push @{$confirmations}, 'RENEWAL_LIMIT' if $override_limit;
79
75
80
                if ( $error && ( $error eq 'on_reserve' ) ) {
76
                if ( $error && ( $error eq 'on_reserve' ) ) {
81
                    if ($override_holds) {
77
                    if ($override_holds) {
82
                        $can_renew = 1;
78
                        $can_renew = 1;
83
                        $error     = undef;
79
                        $error     = undef;
84
80
                        push @{$confirmations}, 'ON_RESERVE';
85
                        @message = ("Override Renew hold for another");
86
87
                        my $infos = (
88
                            {
89
                                message        => \@message,
90
                                borrowernumber => $borrowernumber,
91
                                barcode        => $barcode,
92
                                manager_id     => $user,
93
                                branchcode     => $branchcode,
94
                            }
95
                        );
96
97
                        my $json_infos = JSON->new->utf8->pretty->encode($infos);
98
                        $json_infos =~ s/"/'/g;
99
100
                        logaction(
101
                            "CIRCULATION", "RENEWAL",
102
                            $patron->borrowernumber,
103
                            $json_infos,
104
                        ) if C4::Context->preference("RenewalLog");
105
                    } else {
81
                    } else {
106
                        $can_renew = 0;
82
                        $can_renew = 0;
107
                    }
83
                    }
Lines 133-159 if ( $op eq 'cud-renew' && $barcode ) { Link Here
133
                        }
109
                        }
134
                    );
110
                    );
135
                    $template->param( date_due => $date_due );
111
                    $template->param( date_due => $date_due );
136
137
                    @message = ("Override limit Renew");
138
139
                    my $infos = (
140
                        {
141
                            message        => \@message,
142
                            borrowernumber => $borrowernumber,
143
                            barcode        => $barcode,
144
                            manager_id     => $user,
145
                            branchcode     => $branchcode,
146
                        }
147
                    );
148
149
                    my $json_infos = JSON->new->utf8->pretty->encode($infos);
150
                    $json_infos =~ s/"/'/g;
151
152
                    logaction(
153
                        "CIRCULATION", "RENEWAL",
154
                        $patron->borrowernumber,
155
                        $json_infos,
156
                    ) if C4::Context->preference("RenewalLog");
157
                }
112
                }
158
            } else {
113
            } else {
159
                $error = "patron_restricted";
114
                $error = "patron_restricted";
(-)a/circ/returns.pl (-27 lines)
Lines 42-48 use C4::Members; Link Here
42
use C4::Output   qw( output_html_with_http_headers );
42
use C4::Output   qw( output_html_with_http_headers );
43
use C4::Reserves qw( ModReserve ModReserveAffect CheckReserves );
43
use C4::Reserves qw( ModReserve ModReserveAffect CheckReserves );
44
use C4::RotatingCollections;
44
use C4::RotatingCollections;
45
use C4::Log qw( logaction );
46
use Koha::AuthorisedValues;
45
use Koha::AuthorisedValues;
47
use Koha::BiblioFrameworks;
46
use Koha::BiblioFrameworks;
48
use Koha::Calendar;
47
use Koha::Calendar;
Lines 159-190 if ( $query->param('reserve_id') && $op eq 'cud-affect_reserve' ) { Link Here
159
            $transfer->transit;
158
            $transfer->transit;
160
        }
159
        }
161
    }
160
    }
162
} else {
163
    my $message    = "return an element that is reserved";
164
    my @message    = ("return an element that is reserved");
165
    my $user       = C4::Context->userenv->{number};
166
    my $branchcode = C4::Context->userenv->{branch};
167
    my $barcode    = $query->param('barcode');
168
169
    my $infos = (
170
        {
171
            message => \@message,
172
173
            #'card number' => $cardnumber,
174
            barcode    => $barcode,
175
            manager_id => $user,
176
            branchcode => $branchcode,
177
        }
178
    );
179
180
    my $json_infos = JSON->new->utf8->pretty->encode($infos);
181
    $json_infos =~ s/"/'/g;
182
183
    logaction(
184
        "CIRCULATION", "RETURN",
185
        $session,
186
        $json_infos,
187
    ) if C4::Context->preference("ReturnLog");
188
}
161
}
189
162
190
if ( $query->param('recall_id') && $op eq 'cud-affect_recall' ) {
163
if ( $query->param('recall_id') && $op eq 'cud-affect_recall' ) {
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/action-logs.inc (+10 lines)
Lines 179-184 Link Here
179
179
180
[% BLOCK translate_log_override %]
180
[% BLOCK translate_log_override %]
181
    [% SWITCH override %]
181
    [% SWITCH override %]
182
    [% CASE 'HOLD_POLICY_OVERRIDE' %]
183
        <span>Hold policy override</span>
182
    [% CASE 'INVALID_DATE' %]
184
    [% CASE 'INVALID_DATE' %]
183
        <span>Invalid date confirmed</span>
185
        <span>Invalid date confirmed</span>
184
    [% CASE 'DEBT_GUARANTEES' %]
186
    [% CASE 'DEBT_GUARANTEES' %]
Lines 189-194 Link Here
189
        <span>Patron had debt</span>
191
        <span>Patron had debt</span>
190
    [% CASE 'USERBLOCKEDOVERDUE' %]
192
    [% CASE 'USERBLOCKEDOVERDUE' %]
191
        <span>Patron had overdues</span>
193
        <span>Patron had overdues</span>
194
    [% CASE 'USERBLOCKEDNOENDDATE' %]
195
        <span>Patron had an indefinite restriction</span>
192
    [% CASE 'ADDITIONAL_MATERIALS' %]
196
    [% CASE 'ADDITIONAL_MATERIALS' %]
193
        <span>Additional materials were confirmed</span>
197
        <span>Additional materials were confirmed</span>
194
    [% CASE 'RENEW_ISSUE' %]
198
    [% CASE 'RENEW_ISSUE' %]
Lines 247-252 Link Here
247
        <span>Override Renew hold for another</span>
251
        <span>Override Renew hold for another</span>
248
    [% CASE 'TOO_MUCH' %]
252
    [% CASE 'TOO_MUCH' %]
249
        <span>Override auto-renew too much owing restriction</span>
253
        <span>Override auto-renew too much owing restriction</span>
254
    [% CASE 'CURRENTISSUE' %]
255
        <span>Item is currently checked out to this patron</span>
256
    [% CASE 'UNSEEN' %]
257
        <span>Unseen renewal</span>
258
    [% CASE 'SEEN' %]
259
        <span>Seen renewal</span>
250
    [% CASE %]
260
    [% CASE %]
251
        <span>[% override | html %]</span>
261
        <span>[% override | html %]</span>
252
    [% END %]
262
    [% END %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt (-5 lines)
Lines 788-798 Link Here
788
        <p>Item checked out</p>
788
        <p>Item checked out</p>
789
    [% END %]
789
    [% END %]
790
790
791
    [% IF ( message ) %]
792
        [% INCLUDE 'patron-toolbar.inc' %]
793
        <h4>No patron matched <span class="ex">[% message | html %]</span></h4>
794
    [% END %]
795
796
    <!-- BARCODE ENTRY -->
791
    <!-- BARCODE ENTRY -->
797
792
798
    [% IF patron %]
793
    [% IF patron %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/viewlog.tt (+22 lines)
Lines 349-354 Link Here
349
                                                <div class="confirmed"> [% PROCESS translate_log_override override=confirmation %] </div>
349
                                                <div class="confirmed"> [% PROCESS translate_log_override override=confirmation %] </div>
350
                                            [% END %]
350
                                            [% END %]
351
                                        </div>
351
                                        </div>
352
                                    [% ELSIF ( loopro.module == 'HOLDS' && loopro.json_found ) %]
353
                                        <div class="loginfo" id="loginfo[% loopro.action_id | html %]">
354
                                            <div>
355
                                                <a href="/cgi-bin/koha/reserve/request.pl?biblionumber=[% loopro.json.biblionumber | uri %]" title="Display holds for this record"
356
                                                    >Hold [% loopro.json.hold | html %] on biblio [% loopro.json.biblionumber | html %]</a
357
                                                >
358
                                                [% IF loopro.json.itemnumber %]
359
                                                    -
360
                                                    <a
361
                                                        href="/cgi-bin/koha/catalogue/moredetail.pl?itemnumber=[% loopro.json.itemnumber | uri %]&amp;biblionumber=[% loopro.json.biblionumber | uri %]#item[% loopro.json.itemnumber | uri %]"
362
                                                        title="Display detail for this item"
363
                                                        >Item [% loopro.json.itemnumber | html %]</a
364
                                                    >
365
                                                [% END %]
366
                                            </div>
367
                                            [% FOREACH force IN loopro.json.forced %]
368
                                                <div class="forced"> [% PROCESS translate_log_override override=force %] </div>
369
                                            [% END %]
370
                                            [% FOREACH confirmation IN loopro.json.confirmations %]
371
                                                <div class="confirmed"> [% PROCESS translate_log_override override=confirmation %] </div>
372
                                            [% END %]
373
                                        </div>
352
                                    [% ELSIF loopro.module == "SYSTEMPREFERENCE" || loopro.module == "REPORTS" || loopro.module == "NEWS" %]
374
                                    [% ELSIF loopro.module == "SYSTEMPREFERENCE" || loopro.module == "REPORTS" || loopro.module == "NEWS" %]
353
                                        <div class="loginfo" id="loginfo[% loopro.action_id | html %]">[% loopro.info | trim | html %]</div>
375
                                        <div class="loginfo" id="loginfo[% loopro.action_id | html %]">[% loopro.info | trim | html %]</div>
354
                                        <div class="compare_info" id="compare_info[% loopro.action_id | html %]">
376
                                        <div class="compare_info" id="compare_info[% loopro.action_id | html %]">
(-)a/reserve/request.pl (-28 lines)
Lines 40-46 use C4::Serials qw( CountSubscriptionFromBiblionumber ); Link Here
40
use C4::Circulation qw( _GetCircControlBranch GetBranchItemRule );
40
use C4::Circulation qw( _GetCircControlBranch GetBranchItemRule );
41
use Koha::DateUtils qw( dt_from_string );
41
use Koha::DateUtils qw( dt_from_string );
42
use C4::Search      qw( enabled_staff_search_views );
42
use C4::Search      qw( enabled_staff_search_views );
43
use C4::Log         qw( logaction );
44
43
45
use Koha::Biblios;
44
use Koha::Biblios;
46
use Koha::Checkouts;
45
use Koha::Checkouts;
Lines 570-602 if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold ) Link Here
570
                            $num_alreadyheld++;
569
                            $num_alreadyheld++;
571
                        }
570
                        }
572
571
573
                        my $borrower       = $patron;
574
                        my $borrowernumber = $patron->borrowernumber;
575
                        my $user           = C4::Context->userenv->{number};
576
                        my $branchcode     = C4::Context->userenv->{branch};
577
                        my $message        = "Override limitation of hold";
578
                        my @message        = ("Override limitation of hold");
579
                        my $barcode        = $item->{barcode};
580
581
                        my $infos = (
582
                            {
583
                                message        => \@message,
584
                                borrowernumber => $borrowernumber,
585
                                barcode        => $barcode,
586
                                manager_id     => $user,
587
                                branchcode     => $branchcode,
588
                            }
589
                        );
590
591
                        my $json_infos = JSON->new->utf8->pretty->encode($infos);
592
                        $json_infos =~ s/"/'/g;
593
594
                        logaction(
595
                            "HOLD", "ISSUE",
596
                            $borrower->{'borrowernumber'},
597
                            $json_infos,
598
                        ) if C4::Context->preference("IssueLog");
599
600
                        push( @available_itemtypes, $item->{itype} );
572
                        push( @available_itemtypes, $item->{itype} );
601
                    } else {
573
                    } else {
602
574
(-)a/svc/renew (-50 / +2 lines)
Lines 26-32 use Try::Tiny; Link Here
26
use C4::Circulation qw( AddRenewal CanBookBeRenewed );
26
use C4::Circulation qw( AddRenewal CanBookBeRenewed );
27
use C4::Context;
27
use C4::Context;
28
use C4::Auth qw(check_cookie_auth);
28
use C4::Auth qw(check_cookie_auth);
29
use C4::Log  qw( logaction );
30
29
31
use Koha::DateUtils qw(output_pref dt_from_string);
30
use Koha::DateUtils qw(output_pref dt_from_string);
32
31
Lines 54-63 my $date_due; Link Here
54
if ( $input->param('date_due') ) {
53
if ( $input->param('date_due') ) {
55
    $date_due = dt_from_string( scalar $input->param('date_due') );
54
    $date_due = dt_from_string( scalar $input->param('date_due') );
56
}
55
}
57
my $borrower = Koha::Patrons->find($borrowernumber);
58
my $user     = C4::Context->userenv->{'number'};
59
my $message;
60
my @message;
61
56
62
my $data;
57
my $data;
63
$data->{itemnumber}     = $itemnumber;
58
$data->{itemnumber}     = $itemnumber;
Lines 75-130 my $confirmations; Link Here
75
if ( $data->{error} && $data->{error} eq 'on_reserve' && C4::Context->preference('AllowRenewalOnHoldOverride') ) {
70
if ( $data->{error} && $data->{error} eq 'on_reserve' && C4::Context->preference('AllowRenewalOnHoldOverride') ) {
76
    $data->{renew_okay} = 1;
71
    $data->{renew_okay} = 1;
77
    $data->{error}      = undef;
72
    $data->{error}      = undef;
78
73
    push @{$confirmations}, 'ON_RESERVE';
79
    push @{$confirmations}, 'ON_RESERVE' if $override_limit;
80
    $message = "Override Renew hold for another";
81
    @message = ("Override Renew hold for another");
82
83
    my $infos = (
84
        {
85
            message        => \@message,
86
            borrowernumber => $borrowernumber,
87
            barcode        => $item->barcode,
88
            manager_id     => $user,
89
            branchcode     => $branchcode,
90
        }
91
    );
92
93
    my $json_infos = JSON->new->utf8->pretty->encode($infos);
94
    $json_infos =~ s/"/'/g;
95
96
    logaction(
97
        "CIRCULATION", "RENEWAL",
98
        $borrower->{'borrowernumber'},
99
        $json_infos,
100
    ) if C4::Context->preference("IssueLog");
101
}
74
}
102
75
103
if ( $data->{error} && $data->{error} eq 'too_many' && C4::Context->preference('AllowRenewalLimitOverride') ) {
76
if ( $data->{error} && $data->{error} eq 'too_many' && C4::Context->preference('AllowRenewalLimitOverride') ) {
104
    $data->{renew_okay} = 1;
77
    $data->{renew_okay} = 1;
105
    $data->{error}      = undef;
78
    $data->{error}      = undef;
106
79
    push @{$confirmations}, 'RENEWAL_LIMIT' if $override_limit;
107
    $message = "Override limit Renew";
108
    @message = ("Override limit Renew");
109
110
    my $infos = (
111
        {
112
            message        => \@message,
113
            borrowernumber => $borrowernumber,
114
            barcode        => $item->barcode,
115
            manager_id     => $user,
116
            branchcode     => $branchcode,
117
        }
118
    );
119
120
    my $json_infos = JSON->new->utf8->pretty->encode($infos);
121
    $json_infos =~ s/"/'/g;
122
123
    logaction(
124
        "CIRCULATION", "RENEWAL",
125
        $borrower->{'borrowernumber'},
126
        $json_infos,
127
    ) if C4::Context->preference("IssueLog");
128
}
80
}
129
81
130
if ( $data->{renew_okay} || ( $seen && $data->{error} eq 'too_unseen' ) ) {
82
if ( $data->{renew_okay} || ( $seen && $data->{error} eq 'too_unseen' ) ) {
(-)a/t/db_dependent/Circulation.t (-1 / +20 lines)
Lines 19-25 use Modern::Perl; Link Here
19
use utf8;
19
use utf8;
20
20
21
use Test::NoWarnings;
21
use Test::NoWarnings;
22
use Test::More tests => 80;
22
use Test::More tests => 81;
23
use Test::Exception;
23
use Test::Exception;
24
use Test::MockModule;
24
use Test::MockModule;
25
use Test::Deep qw( cmp_deeply );
25
use Test::Deep qw( cmp_deeply );
Lines 7907-7912 subtest 'Bug 9762: AddRenewal override JSON logging' => sub { Link Here
7907
    is_deeply( $log_data->{forced},        ['TOO_MUCH'],                      'Forced overrides logged correctly' );
7907
    is_deeply( $log_data->{forced},        ['TOO_MUCH'],                      'Forced overrides logged correctly' );
7908
};
7908
};
7909
7909
7910
subtest 'Bug 40866: CanBookBeIssued returns correct number of values' => sub {
7911
    plan tests => 2;
7912
7913
    my $library = $builder->build_object( { class => 'Koha::Libraries' } );
7914
    my $patron =
7915
        $builder->build_object( { class => 'Koha::Patrons', value => { branchcode => $library->branchcode } } );
7916
    my $item = $builder->build_sample_item( { library => $library->branchcode } );
7917
7918
    t::lib::Mocks::mock_userenv( { patron => $patron, branchcode => $library->branchcode } );
7919
7920
    # CanBookBeIssued should return exactly 4 values after Bug 40866 cleanup
7921
    # (issuingimpossible, needsconfirmation, alerts, messages)
7922
    # The 5th return value (@message_log) from the original Bug 9762 implementation was removed
7923
    my @result = C4::Circulation::CanBookBeIssued( $patron, $item->barcode );
7924
7925
    is( scalar @result, 4, 'CanBookBeIssued returns exactly 4 values' );
7926
    ok( ref( $result[0] ) eq 'HASH', 'First return value is issuingimpossible hashref' );
7927
};
7928
7910
$schema->storage->txn_rollback;
7929
$schema->storage->txn_rollback;
7911
C4::Context->clear_syspref_cache();
7930
C4::Context->clear_syspref_cache();
7912
$branches = Koha::Libraries->search();
7931
$branches = Koha::Libraries->search();
(-)a/t/db_dependent/Reserves.t (-1 / +91 lines)
Lines 17-23 Link Here
17
17
18
use Modern::Perl;
18
use Modern::Perl;
19
19
20
use Test::More tests => 70;
20
use Test::More tests => 71;
21
use Test::NoWarnings;
21
use Test::NoWarnings;
22
use Test::MockModule;
22
use Test::MockModule;
23
use Test::Warn;
23
use Test::Warn;
Lines 25-30 use Test::Warn; Link Here
25
use t::lib::Mocks;
25
use t::lib::Mocks;
26
use t::lib::TestBuilder;
26
use t::lib::TestBuilder;
27
27
28
use JSON qw( from_json );
28
use MARC::Record;
29
use MARC::Record;
29
use DateTime::Duration;
30
use DateTime::Duration;
30
31
Lines 2004-2006 subtest 'CheckReserves() item type tests' => sub { Link Here
2004
2005
2005
    $schema->storage->txn_rollback;
2006
    $schema->storage->txn_rollback;
2006
};
2007
};
2008
2009
subtest 'Bug 40866: AddReserve override JSON logging' => sub {
2010
    plan tests => 8;
2011
2012
    $schema->storage->txn_begin;
2013
2014
    my $library = $builder->build_object( { class => 'Koha::Libraries' } );
2015
    my $patron  = $builder->build_object(
2016
        {
2017
            class => 'Koha::Patrons',
2018
            value => { branchcode => $library->branchcode }
2019
        }
2020
    );
2021
    my $biblio = $builder->build_sample_biblio();
2022
    my $item   = $builder->build_sample_item(
2023
        {
2024
            library      => $library->branchcode,
2025
            biblionumber => $biblio->biblionumber
2026
        }
2027
    );
2028
2029
    t::lib::Mocks::mock_userenv( { patron => $patron, branchcode => $library->branchcode } );
2030
    t::lib::Mocks::mock_preference( 'HoldsLog', 1 );
2031
2032
    # Clear any existing logs
2033
    Koha::ActionLogs->search( { module => 'HOLDS', action => 'CREATE' } )->delete;
2034
2035
    # Test 1: Normal hold without overrides - should log hold ID only
2036
    my $hold_id = C4::Reserves::AddReserve(
2037
        {
2038
            branchcode     => $library->branchcode,
2039
            borrowernumber => $patron->borrowernumber,
2040
            biblionumber   => $biblio->biblionumber,
2041
            priority       => 1,
2042
        }
2043
    );
2044
    ok( $hold_id, 'Hold created successfully' );
2045
2046
    my $logs = Koha::ActionLogs->search(
2047
        {
2048
            module => 'HOLDS',
2049
            action => 'CREATE',
2050
            object => $hold_id
2051
        },
2052
        { order_by => { -desc => 'timestamp' } }
2053
    );
2054
    is( $logs->count, 1, 'One log entry created for normal hold' );
2055
    my $log = $logs->next;
2056
    is( $log->info, $hold_id, 'Normal hold logs hold ID only' );
2057
2058
    # Cancel the hold for next test
2059
    my $hold = Koha::Holds->find($hold_id);
2060
    $hold->cancel;
2061
2062
    # Test 2: Hold with override confirmation - should log JSON with confirmations
2063
    my $hold_id2 = C4::Reserves::AddReserve(
2064
        {
2065
            branchcode     => $library->branchcode,
2066
            borrowernumber => $patron->borrowernumber,
2067
            biblionumber   => $biblio->biblionumber,
2068
            priority       => 1,
2069
            confirmations  => ['HOLD_POLICY_OVERRIDE'],
2070
            forced         => []
2071
        }
2072
    );
2073
    ok( $hold_id2, 'Hold with override created successfully' );
2074
2075
    $logs = Koha::ActionLogs->search(
2076
        {
2077
            module => 'HOLDS',
2078
            action => 'CREATE',
2079
            object => $hold_id2
2080
        },
2081
        { order_by => { -desc => 'timestamp' } }
2082
    );
2083
    is( $logs->count, 1, 'One log entry created for override hold' );
2084
    $log = $logs->next;
2085
2086
    my $log_data = eval { from_json( $log->info ) };
2087
    ok( !$@,                               'Log info is valid JSON' );
2088
    ok( exists $log_data->{confirmations}, 'JSON contains confirmations array' );
2089
    is_deeply(
2090
        $log_data->{confirmations},
2091
        ['HOLD_POLICY_OVERRIDE'],
2092
        'Confirmations logged correctly'
2093
    );
2094
2095
    $schema->storage->txn_rollback;
2096
};
(-)a/t/db_dependent/api/v1/holds.t (-2 / +71 lines)
Lines 17-23 Link Here
17
17
18
use Modern::Perl;
18
use Modern::Perl;
19
19
20
use Test::More tests => 18;
20
use Test::More tests => 19;
21
use Test::NoWarnings;
21
use Test::NoWarnings;
22
use Test::MockModule;
22
use Test::MockModule;
23
use Test::Mojo;
23
use Test::Mojo;
Lines 25-30 use t::lib::TestBuilder; Link Here
25
use t::lib::Mocks;
25
use t::lib::Mocks;
26
26
27
use DateTime;
27
use DateTime;
28
use JSON       qw( from_json );
28
use Mojo::JSON qw(encode_json);
29
use Mojo::JSON qw(encode_json);
29
30
30
use C4::Context;
31
use C4::Context;
Lines 32-37 use Koha::Patrons; Link Here
32
use C4::Reserves qw( AddReserve CanItemBeReserved CanBookBeReserved );
33
use C4::Reserves qw( AddReserve CanItemBeReserved CanBookBeReserved );
33
use C4::Items;
34
use C4::Items;
34
35
36
use Koha::ActionLogs;
35
use Koha::Database;
37
use Koha::Database;
36
use Koha::DateUtils qw( dt_from_string output_pref );
38
use Koha::DateUtils qw( dt_from_string output_pref );
37
use Koha::Biblios;
39
use Koha::Biblios;
Lines 1885-1887 subtest 'PUT /holds/{hold_id}/lowest_priority tests' => sub { Link Here
1885
1887
1886
    $schema->storage->txn_rollback;
1888
    $schema->storage->txn_rollback;
1887
};
1889
};
1888
- 
1890
1891
subtest 'Bug 40866: API hold creation with override logs confirmations' => sub {
1892
    plan tests => 6;
1893
1894
    $schema->storage->txn_begin;
1895
1896
    my $librarian = $builder->build_object(
1897
        {
1898
            class => 'Koha::Patrons',
1899
            value => { flags => 1 }
1900
        }
1901
    );
1902
    my $password = 'thePassword123';
1903
    $librarian->set_password( { password => $password, skip_validation => 1 } );
1904
    my $userid = $librarian->userid;
1905
1906
    my $patron = $builder->build_object(
1907
        {
1908
            class => 'Koha::Patrons',
1909
            value => { flags => 0 }
1910
        }
1911
    );
1912
1913
    my $library = $builder->build_object( { class => 'Koha::Libraries' } );
1914
    my $biblio  = $builder->build_sample_biblio;
1915
1916
    t::lib::Mocks::mock_preference( 'AllowHoldPolicyOverride', 1 );
1917
    t::lib::Mocks::mock_preference( 'HoldsLog',                1 );
1918
1919
    # Clear any existing logs
1920
    Koha::ActionLogs->search( { module => 'HOLDS', action => 'CREATE' } )->delete;
1921
1922
    my $post_data = {
1923
        patron_id         => $patron->id,
1924
        biblio_id         => $biblio->id,
1925
        pickup_library_id => $library->branchcode,
1926
    };
1927
1928
    # Create hold with override
1929
    my $hold_id =
1930
        $t->post_ok( "//$userid:$password@/api/v1/holds" => { 'x-koha-override' => 'any' } => json => $post_data )
1931
        ->status_is(201)->tx->res->json->{hold_id};
1932
1933
    ok( $hold_id, 'Hold created via API with override' );
1934
1935
    # Verify the hold was logged with override information
1936
    my $logs = Koha::ActionLogs->search(
1937
        {
1938
            module => 'HOLDS',
1939
            action => 'CREATE',
1940
            object => $hold_id
1941
        },
1942
        { order_by => { -desc => 'timestamp' } }
1943
    );
1944
1945
    is( $logs->count, 1, 'One log entry created for API hold with override' );
1946
1947
    my $log      = $logs->next;
1948
    my $log_data = eval { from_json( $log->info ) };
1949
    ok( !$@, 'Log info is valid JSON' );
1950
    is_deeply(
1951
        $log_data->{confirmations},
1952
        ['HOLD_POLICY_OVERRIDE'],
1953
        'HOLD_POLICY_OVERRIDE logged in confirmations array'
1954
    );
1955
1956
    $schema->storage->txn_rollback;
1957
};

Return to bug 40866