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

(-)a/circ/returns.pl (-1 / +100 lines)
Lines 185-191 my $borrower; Link Here
185
my $returned = 0;
185
my $returned = 0;
186
my $messages;
186
my $messages;
187
my $issue;
187
my $issue;
188
my $barcode    = $query->param('barcode');
188
my $barcode_input  = $query->param('barcode');
189
my $batch_barcodes = $query->param('batch_barcodes');
190
191
# Check if barcode input contains multiple lines (batch mode)
192
my $is_batch_mode = $barcode_input && $barcode_input =~ /\n/;
193
if ($is_batch_mode) {
194
    $batch_barcodes = $barcode_input;
195
    $barcode_input  = undef;            # Clear single barcode when in batch mode
196
}
197
my $barcode    = $barcode_input;
189
my $exemptfine = $query->param('exemptfine');
198
my $exemptfine = $query->param('exemptfine');
190
if ( $exemptfine
199
if ( $exemptfine
191
    && !C4::Auth::haspermission( C4::Context->userenv->{'id'}, { 'updatecharges' => 'writeoff' } ) )
200
    && !C4::Auth::haspermission( C4::Context->userenv->{'id'}, { 'updatecharges' => 'writeoff' } ) )
Lines 273-278 if ( $transit && $op eq 'cud-transfer' ) { Link Here
273
282
274
# actually return book and prepare item table.....
283
# actually return book and prepare item table.....
275
my $returnbranch;
284
my $returnbranch;
285
286
# Handle batch returns
287
my @batch_results;
288
if ( $batch_barcodes && $op eq 'cud-checkin' ) {
289
    my @barcodes = split /\s*\n\s*/, $batch_barcodes;
290
    @barcodes = grep { $_ && $_ !~ /^\s*$/ } @barcodes;    # Remove empty lines
291
292
    foreach my $batch_barcode (@barcodes) {
293
        $batch_barcode = barcodedecode($batch_barcode) if $batch_barcode;
294
        next unless $batch_barcode;
295
296
        my $batch_item   = Koha::Items->find( { barcode => $batch_barcode } );
297
        my %batch_result = (
298
            barcode  => $batch_barcode,
299
            success  => 0,
300
            messages => {},
301
            borrower => undef,
302
            item     => $batch_item
303
        );
304
305
        if ($batch_item) {
306
            my $batch_itemnumber = $batch_item->itemnumber;
307
308
            # Check if we should display a checkin message
309
            my $itemtype = Koha::ItemTypes->find( $batch_item->effective_itemtype );
310
            if ( $itemtype && $itemtype->checkinmsg ) {
311
                $batch_result{checkinmsg}     = $itemtype->checkinmsg;
312
                $batch_result{checkinmsgtype} = $itemtype->checkinmsgtype;
313
            }
314
315
            # Process the return date
316
            my $return_date = $dropboxmode ? $dropboxdate : dt_from_string($return_date_override);
317
318
            # Check for multi-part confirmation requirement
319
            my $needs_confirm =
320
                   C4::Context->preference("CircConfirmItemParts")
321
                && $batch_item->materials
322
                && !$query->param('multiple_confirm');
323
324
            # Check for bundle confirmation requirement
325
            my $bundle_confirm = $batch_item->is_bundle
326
                && !$query->param('confirm_items_bundle_return');
327
328
            # Process waiting holds cancellation requests
329
            if ($batch_item) {
330
                my $waiting_holds_to_be_cancelled = $batch_item->holds->waiting->filter_by_has_cancellation_requests;
331
                while ( my $hold = $waiting_holds_to_be_cancelled->next ) {
332
                    $hold->cancel;
333
                }
334
            }
335
336
            # Do the actual return unless confirmation needed
337
            unless ( $needs_confirm || $bundle_confirm ) {
338
                my ( $batch_returned, $batch_messages, $batch_issue, $batch_borrower ) =
339
                    AddReturn( $batch_barcode, $userenv_branch, $exemptfine, $return_date );
340
341
                $batch_result{success}  = $batch_returned;
342
                $batch_result{messages} = $batch_messages;
343
                $batch_result{issue}    = $batch_issue;
344
                $batch_result{borrower} = $batch_borrower;
345
346
                if ($batch_returned) {
347
                    unshift @checkins, {
348
                        barcode        => $batch_barcode,
349
                        duedate        => $batch_issue ? $batch_issue->date_due       : undef,
350
                        borrowernumber => $batch_issue ? $batch_issue->borrowernumber : undef,
351
                        not_returned   => 0,
352
                    };
353
                } elsif ( C4::Context->preference('ShowAllCheckins') && !$batch_messages->{'BadBarcode'} ) {
354
                    unshift @checkins, {
355
                        barcode        => $batch_barcode,
356
                        duedate        => $batch_issue ? $batch_issue->date_due       : undef,
357
                        borrowernumber => $batch_issue ? $batch_issue->borrowernumber : undef,
358
                        not_returned   => 1,
359
                    };
360
                }
361
            } else {
362
                $batch_result{needs_confirm}  = $needs_confirm;
363
                $batch_result{bundle_confirm} = $bundle_confirm;
364
            }
365
        } else {
366
            $batch_result{messages}{'BadBarcode'} = $batch_barcode;
367
        }
368
369
        push @batch_results, \%batch_result;
370
    }
371
372
    $template->param( batch_results => \@batch_results );
373
}
374
276
if ( $barcode && ( $op eq 'cud-checkin' || $op eq 'cud-affect_reserve' ) ) {
375
if ( $barcode && ( $op eq 'cud-checkin' || $op eq 'cud-affect_reserve' ) ) {
277
    $barcode = barcodedecode($barcode) if $barcode;
376
    $barcode = barcodedecode($barcode) if $barcode;
278
    my $item = Koha::Items->find( { barcode => $barcode } );
377
    my $item = Koha::Items->find( { barcode => $barcode } );
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt (-3 / +155 lines)
Lines 1174-1182 Link Here
1174
                <div class="col-sm-6">
1174
                <div class="col-sm-6">
1175
                    <div class="form-control-group">
1175
                    <div class="form-control-group">
1176
                        [% IF ( exemptfine || dropboxmode ) %]
1176
                        [% IF ( exemptfine || dropboxmode ) %]
1177
                            <input name="barcode" id="barcode" size="14" placeholder="Enter item barcode" class="barcode focus input-warning" type="text" />
1177
                            <textarea
1178
                                name="barcode"
1179
                                id="barcode"
1180
                                placeholder="Enter item barcode"
1181
                                class="barcode focus input-warning"
1182
                                rows="1"
1183
                                style="width: 240px; height: 2.2em; resize: none; overflow: hidden; white-space: nowrap;"
1184
                            ></textarea>
1178
                        [% ELSE %]
1185
                        [% ELSE %]
1179
                            <input name="barcode" id="barcode" size="14" placeholder="Enter item barcode" class="barcode focus" type="text" />
1186
                            <textarea name="barcode" id="barcode" placeholder="Enter item barcode" class="barcode focus" rows="1" style="width: 240px; height: 2.2em; resize: none; overflow: hidden; white-space: nowrap;"></textarea>
1180
                        [% END %]
1187
                        [% END %]
1181
                        <input type="hidden" name="op" value="cud-checkin" />
1188
                        <input type="hidden" name="op" value="cud-checkin" />
1182
1189
Lines 1264-1269 Link Here
1264
                    <label for="dropboxcheck">Book drop mode</label>
1271
                    <label for="dropboxcheck">Book drop mode</label>
1265
                </div>
1272
                </div>
1266
1273
1274
                <div id="batch-mode-setting" class="circ-setting">
1275
                    <input type="checkbox" id="batch-mode-toggle" name="batch_mode" value="batch_mode" />
1276
                    <label for="batch-mode-toggle">Enable batch mode for multiple returns</label>
1277
                </div>
1278
1267
                [% IF Koha.Preference('ExpireReservesMaxPickUpDelayCharge') %]
1279
                [% IF Koha.Preference('ExpireReservesMaxPickUpDelayCharge') %]
1268
                    <div class="forgive-manual-hold-fees circ-setting">
1280
                    <div class="forgive-manual-hold-fees circ-setting">
1269
                        [% IF ( forgivemanualholdsexpire ) %]
1281
                        [% IF ( forgivemanualholdsexpire ) %]
Lines 1282-1287 Link Here
1282
    </form>
1294
    </form>
1283
    <!-- /#checkin-form -->
1295
    <!-- /#checkin-form -->
1284
1296
1297
    [% IF ( batch_results.size ) %]
1298
        <div class="page-section">
1299
            <h2>Batch return results</h2>
1300
            <table id="batch-results-table" class="table table-striped">
1301
                <thead>
1302
                    <tr>
1303
                        <th>Barcode</th>
1304
                        <th>Status</th>
1305
                        <th>Title</th>
1306
                        <th>Patron</th>
1307
                        <th>Messages</th>
1308
                    </tr>
1309
                </thead>
1310
                <tbody>
1311
                    [% FOREACH result IN batch_results %]
1312
                        <tr class="[% IF result.success %]success[% ELSE %]danger[% END %]">
1313
                            <td>[% result.barcode | html %]</td>
1314
                            <td>
1315
                                [% IF result.success %]
1316
                                    <span class="label label-success">Returned</span>
1317
                                [% ELSIF result.needs_confirm %]
1318
                                    <span class="label label-warning">Needs confirmation</span>
1319
                                [% ELSIF result.bundle_confirm %]
1320
                                    <span class="label label-warning">Bundle confirmation required</span>
1321
                                [% ELSIF result.messages.BadBarcode %]
1322
                                    <span class="label label-danger">Invalid barcode</span>
1323
                                [% ELSE %]
1324
                                    <span class="label label-danger">Failed</span>
1325
                                [% END %]
1326
                            </td>
1327
                            <td>
1328
                                [% IF result.item %]
1329
                                    <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% result.item.biblio.biblionumber | uri %]"> [% result.item.biblio.title | html %] </a>
1330
                                [% END %]
1331
                            </td>
1332
                            <td>
1333
                                [% IF result.borrower %]
1334
                                    <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% result.borrower.borrowernumber | uri %]"> [% result.borrower.firstname | html %] [% result.borrower.surname | html %] </a>
1335
                                [% END %]
1336
                            </td>
1337
                            <td>
1338
                                [% IF result.checkinmsg %]
1339
                                    <div class="alert alert-[% result.checkinmsgtype || 'info' %]">[% result.checkinmsg | html %]</div>
1340
                                [% END %]
1341
                                [% FOREACH code IN result.messages.keys %]
1342
                                    [% IF code == 'WasTransfered' %]
1343
                                        <div class="alert alert-info">Item transferred to [% result.messages.TransferTo %]</div>
1344
                                    [% ELSIF code == 'NeedsTransfer' %]
1345
                                        <div class="alert alert-warning">Item needs transfer</div>
1346
                                    [% ELSIF code == 'NotIssued' %]
1347
                                        <div class="alert alert-warning">Item was not checked out</div>
1348
                                    [% ELSIF code == 'WasLost' %]
1349
                                        <div class="alert alert-info">Item was lost, now found</div>
1350
                                    [% ELSIF code == 'withdrawn' %]
1351
                                        <div class="alert alert-warning">Item is withdrawn</div>
1352
                                    [% ELSIF code == 'Debarred' %]
1353
                                        <div class="alert alert-danger">Patron is restricted</div>
1354
                                    [% END %]
1355
                                [% END %]
1356
                            </td>
1357
                        </tr>
1358
                    [% END %]
1359
                </tbody>
1360
            </table>
1361
        </div>
1362
    [% END %]
1363
1285
    [% IF ( checkins.size ) %]
1364
    [% IF ( checkins.size ) %]
1286
        <div class="page-section">
1365
        <div class="page-section">
1287
            <h2>Checked-in items</h2>
1366
            <h2>Checked-in items</h2>
Lines 1755-1760 Link Here
1755
                ],
1834
                ],
1756
            });
1835
            });
1757
1836
1837
            // Debounce variables for RFID batch input
1838
            let debounceTimer;
1839
            let isReceivingRFIDInput = false;
1840
1841
            // Batch mode toggle functionality
1842
            $('#batch-mode-toggle').on('change', function() {
1843
                const $barcodeTextarea = $('#barcode');
1844
1845
                if ($(this).is(':checked')) {
1846
                    // Switch to multi-line batch mode
1847
                    $barcodeTextarea.attr({
1848
                        'placeholder': 'Enter barcodes, one per line',
1849
                        'rows': 8
1850
                    }).css({
1851
                        'height': 'auto',
1852
                        'overflow': 'auto',
1853
                        'white-space': 'pre-wrap',
1854
                        'resize': 'vertical'
1855
                    });
1856
                } else {
1857
                    // Switch back to single-line mode
1858
                    $barcodeTextarea.attr({
1859
                        'placeholder': 'Enter item barcode',
1860
                        'rows': 1
1861
                    }).css({
1862
                        'height': '2.2em',
1863
                        'overflow': 'hidden',
1864
                        'white-space': 'nowrap',
1865
                        'resize': 'none'
1866
                    });
1867
                }
1868
                $barcodeTextarea.focus();
1869
            });
1870
1871
            // Handle RFID input with debouncing
1872
            $('#barcode').on('input paste', function(e) {
1873
                const currentValue = $(this).val();
1874
1875
                // Clear any existing timer
1876
                clearTimeout(debounceTimer);
1877
1878
                // Check if this looks like RFID batch input (contains newlines)
1879
                if (currentValue.includes('\n')) {
1880
                    isReceivingRFIDInput = true;
1881
1882
                    // Auto-enable batch mode if not already enabled
1883
                    if (!$('#batch-mode-toggle').is(':checked')) {
1884
                        $('#batch-mode-toggle').prop('checked', true).trigger('change');
1885
                    }
1886
1887
                    // Set a debounce timer to submit after RFID scanning finishes
1888
                    debounceTimer = setTimeout(function() {
1889
                        isReceivingRFIDInput = false;
1890
                        $('#checkin-form').submit();
1891
                    }, 500); // 500ms delay after last input
1892
                }
1893
            });
1894
1895
            // Prevent immediate form submission on Enter if receiving RFID input
1896
            $('#barcode').on('keydown', function(e) {
1897
                if (e.which === 13 && isReceivingRFIDInput) {
1898
                    e.preventDefault();
1899
                    return false;
1900
                }
1901
            });
1902
1903
            // Prevent form submission during RFID input
1904
            $('#checkin-form').on('submit', function(e) {
1905
                if (isReceivingRFIDInput) {
1906
                    e.preventDefault();
1907
                    return false;
1908
                }
1909
            });
1910
1758
            [% IF ( !(Koha.Preference('TransfersBlockCirc')) && Koha.Preference('AutomaticConfirmTransfer') ) %]
1911
            [% IF ( !(Koha.Preference('TransfersBlockCirc')) && Koha.Preference('AutomaticConfirmTransfer') ) %]
1759
                $("#wrong-transfer-modal").on('hidden.bs.modal',function(){
1912
                $("#wrong-transfer-modal").on('hidden.bs.modal',function(){
1760
                    $("#wrongtransferform").submit();
1913
                    $("#wrongtransferform").submit();
1761
- 

Return to bug 19814