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

(-)a/circ/returns.pl (-1 / +100 lines)
Lines 211-217 my $borrower; Link Here
211
my $returned = 0;
211
my $returned = 0;
212
my $messages;
212
my $messages;
213
my $issue;
213
my $issue;
214
my $barcode    = $query->param('barcode');
214
my $barcode_input  = $query->param('barcode');
215
my $batch_barcodes = $query->param('batch_barcodes');
216
217
# Check if barcode input contains multiple lines (batch mode)
218
my $is_batch_mode = $barcode_input && $barcode_input =~ /\n/;
219
if ($is_batch_mode) {
220
    $batch_barcodes = $barcode_input;
221
    $barcode_input  = undef;            # Clear single barcode when in batch mode
222
}
223
my $barcode    = $barcode_input;
215
my $exemptfine = $query->param('exemptfine');
224
my $exemptfine = $query->param('exemptfine');
216
if ( $exemptfine
225
if ( $exemptfine
217
    && !C4::Auth::haspermission( C4::Context->userenv->{'id'}, { 'updatecharges' => 'writeoff' } ) )
226
    && !C4::Auth::haspermission( C4::Context->userenv->{'id'}, { 'updatecharges' => 'writeoff' } ) )
Lines 291-296 if ( $transit && $op eq 'cud-transfer' ) { Link Here
291
300
292
# actually return book and prepare item table.....
301
# actually return book and prepare item table.....
293
my $returnbranch;
302
my $returnbranch;
303
304
# Handle batch returns
305
my @batch_results;
306
if ( $batch_barcodes && $op eq 'cud-checkin' ) {
307
    my @barcodes = split /\s*\n\s*/, $batch_barcodes;
308
    @barcodes = grep { $_ && $_ !~ /^\s*$/ } @barcodes;    # Remove empty lines
309
310
    foreach my $batch_barcode (@barcodes) {
311
        $batch_barcode = barcodedecode($batch_barcode) if $batch_barcode;
312
        next unless $batch_barcode;
313
314
        my $batch_item   = Koha::Items->find( { barcode => $batch_barcode } );
315
        my %batch_result = (
316
            barcode  => $batch_barcode,
317
            success  => 0,
318
            messages => {},
319
            borrower => undef,
320
            item     => $batch_item
321
        );
322
323
        if ($batch_item) {
324
            my $batch_itemnumber = $batch_item->itemnumber;
325
326
            # Check if we should display a checkin message
327
            my $itemtype = Koha::ItemTypes->find( $batch_item->effective_itemtype );
328
            if ( $itemtype && $itemtype->checkinmsg ) {
329
                $batch_result{checkinmsg}     = $itemtype->checkinmsg;
330
                $batch_result{checkinmsgtype} = $itemtype->checkinmsgtype;
331
            }
332
333
            # Process the return date
334
            my $return_date = $dropboxmode ? $dropboxdate : dt_from_string($return_date_override);
335
336
            # Check for multi-part confirmation requirement
337
            my $needs_confirm =
338
                   C4::Context->preference("CircConfirmItemParts")
339
                && $batch_item->materials
340
                && !$query->param('multiple_confirm');
341
342
            # Check for bundle confirmation requirement
343
            my $bundle_confirm = $batch_item->is_bundle
344
                && !$query->param('confirm_items_bundle_return');
345
346
            # Process waiting holds cancellation requests
347
            if ($batch_item) {
348
                my $waiting_holds_to_be_cancelled = $batch_item->holds->waiting->filter_by_has_cancellation_requests;
349
                while ( my $hold = $waiting_holds_to_be_cancelled->next ) {
350
                    $hold->cancel;
351
                }
352
            }
353
354
            # Do the actual return unless confirmation needed
355
            unless ( $needs_confirm || $bundle_confirm ) {
356
                my ( $batch_returned, $batch_messages, $batch_issue, $batch_borrower ) =
357
                    AddReturn( $batch_barcode, $userenv_branch, $exemptfine, $return_date );
358
359
                $batch_result{success}  = $batch_returned;
360
                $batch_result{messages} = $batch_messages;
361
                $batch_result{issue}    = $batch_issue;
362
                $batch_result{borrower} = $batch_borrower;
363
364
                if ($batch_returned) {
365
                    unshift @checkins, {
366
                        barcode        => $batch_barcode,
367
                        duedate        => $batch_issue ? $batch_issue->date_due       : undef,
368
                        borrowernumber => $batch_issue ? $batch_issue->borrowernumber : undef,
369
                        not_returned   => 0,
370
                    };
371
                } elsif ( C4::Context->preference('ShowAllCheckins') && !$batch_messages->{'BadBarcode'} ) {
372
                    unshift @checkins, {
373
                        barcode        => $batch_barcode,
374
                        duedate        => $batch_issue ? $batch_issue->date_due       : undef,
375
                        borrowernumber => $batch_issue ? $batch_issue->borrowernumber : undef,
376
                        not_returned   => 1,
377
                    };
378
                }
379
            } else {
380
                $batch_result{needs_confirm}  = $needs_confirm;
381
                $batch_result{bundle_confirm} = $bundle_confirm;
382
            }
383
        } else {
384
            $batch_result{messages}{'BadBarcode'} = $batch_barcode;
385
        }
386
387
        push @batch_results, \%batch_result;
388
    }
389
390
    $template->param( batch_results => \@batch_results );
391
}
392
294
if ( $barcode && ( $op eq 'cud-checkin' || $op eq 'cud-affect_reserve' ) ) {
393
if ( $barcode && ( $op eq 'cud-checkin' || $op eq 'cud-affect_reserve' ) ) {
295
    $barcode = barcodedecode($barcode) if $barcode;
394
    $barcode = barcodedecode($barcode) if $barcode;
296
    my $item = Koha::Items->find( { barcode => $barcode } );
395
    my $item = Koha::Items->find( { barcode => $barcode } );
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt (-3 / +155 lines)
Lines 1155-1163 Link Here
1155
                <div class="col-sm-6">
1155
                <div class="col-sm-6">
1156
                    <div class="form-control-group">
1156
                    <div class="form-control-group">
1157
                        [% IF ( exemptfine || dropboxmode ) %]
1157
                        [% IF ( exemptfine || dropboxmode ) %]
1158
                            <input name="barcode" id="barcode" size="14" placeholder="Enter item barcode" class="barcode focus input-warning" type="text" />
1158
                            <textarea
1159
                                name="barcode"
1160
                                id="barcode"
1161
                                placeholder="Enter item barcode"
1162
                                class="barcode focus input-warning"
1163
                                rows="1"
1164
                                style="width: 240px; height: 2.2em; resize: none; overflow: hidden; white-space: nowrap;"
1165
                            ></textarea>
1159
                        [% ELSE %]
1166
                        [% ELSE %]
1160
                            <input name="barcode" id="barcode" size="14" placeholder="Enter item barcode" class="barcode focus" type="text" />
1167
                            <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>
1161
                        [% END %]
1168
                        [% END %]
1162
                        <input type="hidden" name="op" value="cud-checkin" />
1169
                        <input type="hidden" name="op" value="cud-checkin" />
1163
1170
Lines 1245-1250 Link Here
1245
                    <label for="dropboxcheck">Book drop mode</label>
1252
                    <label for="dropboxcheck">Book drop mode</label>
1246
                </div>
1253
                </div>
1247
1254
1255
                <div id="batch-mode-setting" class="circ-setting">
1256
                    <input type="checkbox" id="batch-mode-toggle" name="batch_mode" value="batch_mode" />
1257
                    <label for="batch-mode-toggle">Enable batch mode for multiple returns</label>
1258
                </div>
1259
1248
                [% IF Koha.Preference('ExpireReservesMaxPickUpDelayCharge') %]
1260
                [% IF Koha.Preference('ExpireReservesMaxPickUpDelayCharge') %]
1249
                    <div class="forgive-manual-hold-fees circ-setting">
1261
                    <div class="forgive-manual-hold-fees circ-setting">
1250
                        [% IF ( forgivemanualholdsexpire ) %]
1262
                        [% IF ( forgivemanualholdsexpire ) %]
Lines 1263-1268 Link Here
1263
    </form>
1275
    </form>
1264
    <!-- /#checkin-form -->
1276
    <!-- /#checkin-form -->
1265
1277
1278
    [% IF ( batch_results.size ) %]
1279
        <div class="page-section">
1280
            <h2>Batch return results</h2>
1281
            <table id="batch-results-table" class="table table-striped">
1282
                <thead>
1283
                    <tr>
1284
                        <th>Barcode</th>
1285
                        <th>Status</th>
1286
                        <th>Title</th>
1287
                        <th>Patron</th>
1288
                        <th>Messages</th>
1289
                    </tr>
1290
                </thead>
1291
                <tbody>
1292
                    [% FOREACH result IN batch_results %]
1293
                        <tr class="[% IF result.success %]success[% ELSE %]danger[% END %]">
1294
                            <td>[% result.barcode | html %]</td>
1295
                            <td>
1296
                                [% IF result.success %]
1297
                                    <span class="label label-success">Returned</span>
1298
                                [% ELSIF result.needs_confirm %]
1299
                                    <span class="label label-warning">Needs confirmation</span>
1300
                                [% ELSIF result.bundle_confirm %]
1301
                                    <span class="label label-warning">Bundle confirmation required</span>
1302
                                [% ELSIF result.messages.BadBarcode %]
1303
                                    <span class="label label-danger">Invalid barcode</span>
1304
                                [% ELSE %]
1305
                                    <span class="label label-danger">Failed</span>
1306
                                [% END %]
1307
                            </td>
1308
                            <td>
1309
                                [% IF result.item %]
1310
                                    <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% result.item.biblio.biblionumber | uri %]"> [% result.item.biblio.title | html %] </a>
1311
                                [% END %]
1312
                            </td>
1313
                            <td>
1314
                                [% IF result.borrower %]
1315
                                    <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% result.borrower.borrowernumber | uri %]"> [% result.borrower.firstname | html %] [% result.borrower.surname | html %] </a>
1316
                                [% END %]
1317
                            </td>
1318
                            <td>
1319
                                [% IF result.checkinmsg %]
1320
                                    <div class="alert alert-[% result.checkinmsgtype || 'info' %]">[% result.checkinmsg | html %]</div>
1321
                                [% END %]
1322
                                [% FOREACH code IN result.messages.keys %]
1323
                                    [% IF code == 'WasTransfered' %]
1324
                                        <div class="alert alert-info">Item transferred to [% result.messages.TransferTo %]</div>
1325
                                    [% ELSIF code == 'NeedsTransfer' %]
1326
                                        <div class="alert alert-warning">Item needs transfer</div>
1327
                                    [% ELSIF code == 'NotIssued' %]
1328
                                        <div class="alert alert-warning">Item was not checked out</div>
1329
                                    [% ELSIF code == 'WasLost' %]
1330
                                        <div class="alert alert-info">Item was lost, now found</div>
1331
                                    [% ELSIF code == 'withdrawn' %]
1332
                                        <div class="alert alert-warning">Item is withdrawn</div>
1333
                                    [% ELSIF code == 'Debarred' %]
1334
                                        <div class="alert alert-danger">Patron is restricted</div>
1335
                                    [% END %]
1336
                                [% END %]
1337
                            </td>
1338
                        </tr>
1339
                    [% END %]
1340
                </tbody>
1341
            </table>
1342
        </div>
1343
    [% END %]
1344
1266
    [% IF ( checkins.size ) %]
1345
    [% IF ( checkins.size ) %]
1267
        <div class="page-section">
1346
        <div class="page-section">
1268
            <h2>Checked-in items</h2>
1347
            <h2>Checked-in items</h2>
Lines 1736-1741 Link Here
1736
                ],
1815
                ],
1737
            });
1816
            });
1738
1817
1818
            // Debounce variables for RFID batch input
1819
            let debounceTimer;
1820
            let isReceivingRFIDInput = false;
1821
1822
            // Batch mode toggle functionality
1823
            $('#batch-mode-toggle').on('change', function() {
1824
                const $barcodeTextarea = $('#barcode');
1825
1826
                if ($(this).is(':checked')) {
1827
                    // Switch to multi-line batch mode
1828
                    $barcodeTextarea.attr({
1829
                        'placeholder': 'Enter barcodes, one per line',
1830
                        'rows': 8
1831
                    }).css({
1832
                        'height': 'auto',
1833
                        'overflow': 'auto',
1834
                        'white-space': 'pre-wrap',
1835
                        'resize': 'vertical'
1836
                    });
1837
                } else {
1838
                    // Switch back to single-line mode
1839
                    $barcodeTextarea.attr({
1840
                        'placeholder': 'Enter item barcode',
1841
                        'rows': 1
1842
                    }).css({
1843
                        'height': '2.2em',
1844
                        'overflow': 'hidden',
1845
                        'white-space': 'nowrap',
1846
                        'resize': 'none'
1847
                    });
1848
                }
1849
                $barcodeTextarea.focus();
1850
            });
1851
1852
            // Handle RFID input with debouncing
1853
            $('#barcode').on('input paste', function(e) {
1854
                const currentValue = $(this).val();
1855
1856
                // Clear any existing timer
1857
                clearTimeout(debounceTimer);
1858
1859
                // Check if this looks like RFID batch input (contains newlines)
1860
                if (currentValue.includes('\n')) {
1861
                    isReceivingRFIDInput = true;
1862
1863
                    // Auto-enable batch mode if not already enabled
1864
                    if (!$('#batch-mode-toggle').is(':checked')) {
1865
                        $('#batch-mode-toggle').prop('checked', true).trigger('change');
1866
                    }
1867
1868
                    // Set a debounce timer to submit after RFID scanning finishes
1869
                    debounceTimer = setTimeout(function() {
1870
                        isReceivingRFIDInput = false;
1871
                        $('#checkin-form').submit();
1872
                    }, 500); // 500ms delay after last input
1873
                }
1874
            });
1875
1876
            // Prevent immediate form submission on Enter if receiving RFID input
1877
            $('#barcode').on('keydown', function(e) {
1878
                if (e.which === 13 && isReceivingRFIDInput) {
1879
                    e.preventDefault();
1880
                    return false;
1881
                }
1882
            });
1883
1884
            // Prevent form submission during RFID input
1885
            $('#checkin-form').on('submit', function(e) {
1886
                if (isReceivingRFIDInput) {
1887
                    e.preventDefault();
1888
                    return false;
1889
                }
1890
            });
1891
1739
            [% IF ( !(Koha.Preference('TransfersBlockCirc')) && Koha.Preference('AutomaticConfirmTransfer') ) %]
1892
            [% IF ( !(Koha.Preference('TransfersBlockCirc')) && Koha.Preference('AutomaticConfirmTransfer') ) %]
1740
                $("#wrong-transfer-modal").on('hidden.bs.modal',function(){
1893
                $("#wrong-transfer-modal").on('hidden.bs.modal',function(){
1741
                    $("#wrongtransferform").submit();
1894
                    $("#wrongtransferform").submit();
1742
- 

Return to bug 19814