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

(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/ill/ill-requests.tt (-9 / +497 lines)
Lines 3-11 Link Here
3
[% USE Branches %]
3
[% USE Branches %]
4
[% USE Koha %]
4
[% USE Koha %]
5
[% USE KohaDates %]
5
[% USE KohaDates %]
6
6
[% SET footerjs = 1 %]
7
[% INCLUDE 'doc-head-open.inc' %]
7
[% INCLUDE 'doc-head-open.inc' %]
8
<title>Koha &rsaquo; ILL requests  &rsaquo;</title>
8
<title>Koha &rsaquo; ILL requests</title>
9
[% INCLUDE 'doc-head-close.inc' %]
9
[% INCLUDE 'doc-head-close.inc' %]
10
[% Asset.js("lib/jquery/plugins/jquery.checkboxes.min.js") | $raw %]
10
[% Asset.js("lib/jquery/plugins/jquery.checkboxes.min.js") | $raw %]
11
[% Asset.css("css/datatables.css") | $raw %]
11
[% Asset.css("css/datatables.css") | $raw %]
Lines 551-569 Link Here
551
                        </li>
551
                        </li>
552
                        <li>
552
                        <li>
553
                            <label for="illfilter_dateplaced_start">Date placed between:</label>
553
                            <label for="illfilter_dateplaced_start">Date placed between:</label>
554
                            <input type="text" name="illfilter_dateplaced_start" id="illfilter_dateplaced_start" class="datepicker">
554
                            <input type="text" name="illfilter_dateplaced_start" id="illfilter_dateplaced_start" class="datepicker" />
555
                        </li>
555
                        </li>
556
                        <li>
556
                        <li>
557
                            <label for="illfilter_dateplaced_end">and:</label>
557
                            <label for="illfilter_dateplaced_end">and:</label>
558
                            <input type="text" name="illfilter_dateplaced_end" id="illfilter_dateplaced_end" class="datepicker">
558
                            <input type="text" name="illfilter_dateplaced_end" id="illfilter_dateplaced_end" class="datepicker" />
559
                        </li>
559
                        </li>
560
                        <li>
560
                        <li>
561
                            <label for="illfilter_datemodified_start">Updated between:</label>
561
                            <label for="illfilter_datemodified_start">Updated between:</label>
562
                            <input type="text" name="illfilter_datemodified_start" id="illfilter_datemodified_start" class="datepicker">
562
                            <input type="text" name="illfilter_datemodified_start" id="illfilter_datemodified_start" class="datepicker" />
563
                        </li>
563
                        </li>
564
                        <li>
564
                        <li>
565
                            <label for="illfilter_datemodified_end">and:</label>
565
                            <label for="illfilter_datemodified_end">and:</label>
566
                            <input type="text" name="illfilter_datemodified_end" id="illfilter_datemodified_end" class="datepicker">
566
                            <input type="text" name="illfilter_datemodified_end" id="illfilter_datemodified_end" class="datepicker" />
567
                        </li>
567
                        </li>
568
                        <li>
568
                        <li>
569
                            <label for="illfilter_branchname">Library:</label>
569
                            <label for="illfilter_branchname">Library:</label>
Lines 573-579 Link Here
573
                        </li>
573
                        </li>
574
                        <li>
574
                        <li>
575
                            <label for="illfilter_barcode">Patron barcode:</label>
575
                            <label for="illfilter_barcode">Patron barcode:</label>
576
                            <input type="text" name="illfilter_barcode" id="illfilter_barcode">
576
                            <input type="text" name="illfilter_barcode" id="illfilter_barcode" />
577
                        </li>
577
                        </li>
578
                    </ol>
578
                    </ol>
579
                    <fieldset class="action">
579
                    <fieldset class="action">
Lines 639-645 Link Here
639
                                <ol>
639
                                <ol>
640
                                    <li>
640
                                    <li>
641
                                        <label for="partner_filter">Filter partner libraries:</label>
641
                                        <label for="partner_filter">Filter partner libraries:</label>
642
                                        <input type="text" id="partner_filter">
642
                                        <input type="text" id="partner_filter" />
643
                                    </li>
643
                                    </li>
644
                                    <li>
644
                                    <li>
645
                                        <label for="partners" class="required">Select partner libraries:</label>
645
                                        <label for="partners" class="required">Select partner libraries:</label>
Lines 1001-1004 Link Here
1001
[% CATCH %]
1001
[% CATCH %]
1002
[% END %]
1002
[% END %]
1003
1003
1004
[% MACRO jsinclude BLOCK %]
1005
    [% INCLUDE 'datatables.inc' %]
1006
    [% INCLUDE 'calendar.inc' %]
1007
    <script>
1008
        $(document).ready(function() {
1009
1010
            // Illview Datatable setup
1011
1012
            var table;
1013
1014
            // Filters that are active
1015
            var activeFilters = {};
1016
1017
            // Fields we don't want to display
1018
            var ignore = [
1019
                'accessurl',
1020
                'backend',
1021
                'branchcode',
1022
                'completed',
1023
                'capabilities',
1024
                'cost',
1025
                'medium',
1026
                'notesopac',
1027
                'notesstaff',
1028
                'replied'
1029
            ];
1030
1031
            // Fields we need to expand (flatten)
1032
            var expand = [
1033
                'metadata',
1034
                'patron'
1035
            ];
1036
1037
            // Expanded fields
1038
            // This is auto populated
1039
            var expanded = {};
1040
1041
            // The core fields that should be displayed first
1042
            var core = [
1043
                'metadata_Author',
1044
                'metadata_Title',
1045
                'borrowername',
1046
                'patron_cardnumber',
1047
                'biblio_id',
1048
                'library',
1049
                'status',
1050
                'placed',
1051
                'placed_formatted',
1052
                'updated',
1053
                'updated_formatted',
1054
                'illrequest_id',
1055
                'action'
1056
            ];
1057
1058
            // Filterable columns
1059
            var filterable = {
1060
                status: {
1061
                    prep: function(tableData, oData) {
1062
                        var uniques = {};
1063
                        tableData.forEach(function(row) {
1064
                            var resolvedName = getStatusName(
1065
                                oData[0].capabilities[row.status].name
1066
                            );
1067
                            uniques[resolvedName] = 1
1068
                        });
1069
                        Object.keys(uniques).sort().forEach(function(unique) {
1070
                            $('#illfilter_status').append(
1071
                                '<option value="' + unique  +
1072
                                '">' + unique +  '</option>'
1073
                            );
1074
                        });
1075
                    },
1076
                    listener: function() {
1077
                        var me = 'status';
1078
                        $('#illfilter_status').change(function() {
1079
                            var sel = $('#illfilter_status option:selected').val();
1080
                            if (sel && sel.length > 0) {
1081
                                activeFilters[me] = function() {
1082
                                    table.column(6).search(sel);
1083
                                }
1084
                            } else {
1085
                                if (activeFilters.hasOwnProperty(me)) {
1086
                                    delete activeFilters[me];
1087
                                }
1088
                            }
1089
                        });
1090
                    },
1091
                    clear: function() {
1092
                        $('#illfilter_status').val('');
1093
                    }
1094
                },
1095
                pickupBranch: {
1096
                    prep: function(tableData, oData) {
1097
                        var uniques = {};
1098
                        tableData.forEach(function(row) {
1099
                            uniques[row.library.branchname] = 1
1100
                        });
1101
                        Object.keys(uniques).sort().forEach(function(unique) {
1102
                            $('#illfilter_branchname').append(
1103
                                '<option value="' + unique  +
1104
                                '">' + unique +  '</option>'
1105
                            );
1106
                        });
1107
                    },
1108
                    listener: function() {
1109
                        var me = 'pickupBranch';
1110
                        $('#illfilter_branchname').change(function() {
1111
                            var sel = $('#illfilter_branchname option:selected').val();
1112
                            if (sel && sel.length > 0) {
1113
                                activeFilters[me] = function() {
1114
                                    table.column(5).search(sel);
1115
                                }
1116
                            } else {
1117
                                if (activeFilters.hasOwnProperty(me)) {
1118
                                    delete activeFilters[me];
1119
                                }
1120
                            }
1121
                        });
1122
                    },
1123
                    clear: function() {
1124
                        $('#illfilter_branchname').val('');
1125
                    }
1126
                },
1127
                barcode: {
1128
                    listener: function() {
1129
                        var me = 'barcode';
1130
                        $('#illfilter_barcode').change(function() {
1131
                            var val = $('#illfilter_barcode').val();
1132
                            if (val && val.length > 0) {
1133
                                activeFilters[me] = function() {
1134
                                    table.column(3).search(val);
1135
                                }
1136
                            } else {
1137
                                if (activeFilters.hasOwnProperty(me)) {
1138
                                    delete activeFilters[me];
1139
                                }
1140
                            }
1141
                        });
1142
                    },
1143
                    clear: function() {
1144
                        $('#illfilter_barcode').val('');
1145
                    }
1146
                },
1147
                dateModified: {
1148
                    clear: function() {
1149
                        $('#illfilter_datemodified_start, #illfilter_datemodified_end').val('');
1150
                    }
1151
                },
1152
                datePlaced: {
1153
                    clear: function() {
1154
                        $('#illfilter_dateplaced_start, #illfilter_dateplaced_end').val('');
1155
                    }
1156
                }
1157
            };
1158
1159
            // Remove any fields we're ignoring
1160
            var removeIgnore = function(dataObj) {
1161
                dataObj.forEach(function(thisRow) {
1162
                    ignore.forEach(function(thisIgnore) {
1163
                        if (thisRow.hasOwnProperty(thisIgnore)) {
1164
                            delete thisRow[thisIgnore];
1165
                        }
1166
                    });
1167
                });
1168
            };
1169
1170
            // Expand any fields we're expanding
1171
            var expandExpand = function(row) {
1172
                expand.forEach(function(thisExpand) {
1173
                    if (row.hasOwnProperty(thisExpand)) {
1174
                        if (!expanded.hasOwnProperty(thisExpand)) {
1175
                            expanded[thisExpand] = [];
1176
                        }
1177
                        var expandObj = row[thisExpand];
1178
                        Object.keys(expandObj).forEach(
1179
                            function(thisExpandCol) {
1180
                                var expColName = thisExpand + '_' + thisExpandCol;
1181
                                // Keep a list of fields that have been expanded
1182
                                // so we can create toggle links for them
1183
                                if (expanded[thisExpand].indexOf(expColName) == -1) {
1184
                                    expanded[thisExpand].push(expColName);
1185
                                }
1186
                                expandObj[expColName] =
1187
                                    expandObj[thisExpandCol];
1188
                                delete expandObj[thisExpandCol];
1189
                            }
1190
                        );
1191
                        $.extend(true, row, expandObj);
1192
                        delete row[thisExpand];
1193
                    }
1194
                });
1195
            };
1196
1197
            // Build a de-duped list of all column names
1198
            var allCols = {};
1199
            core.map(function(thisCore) {
1200
                allCols[thisCore] = 1;
1201
            });
1202
1203
            // Strip the expand prefix if it exists, we do this for display
1204
            var stripPrefix = function(value) {
1205
                expand.forEach(function(thisExpand) {
1206
                    var regex = new RegExp(thisExpand + '_', 'g');
1207
                    value = value.replace(regex, '');
1208
                });
1209
                return value;
1210
            };
1211
1212
            // Our 'render' function for borrowerlink
1213
            var createPatronLink = function(data, type, row) {
1214
                return '<a title="' + _("View borrower details") + '" ' +
1215
                    'href="/cgi-bin/koha/members/moremember.pl?' +
1216
                    'borrowernumber='+row.borrowernumber+'">' +
1217
                    row.patron_firstname + ' ' + row.patron_surname +
1218
                    '</a>';
1219
            };
1220
1221
            // Our 'render' function for the library name
1222
            var createLibrary = function(data, type, row) {
1223
                return row.library.branchname;
1224
            };
1225
1226
            // Render function for request ID
1227
            var createRequestId = function(data, type, row) {
1228
                return row.id_prefix + row.illrequest_id;
1229
            };
1230
1231
            // Render function for request status
1232
            var createStatus = function(data, type, row, meta) {
1233
                var origData = meta.settings.oInit.originalData;
1234
                if (origData.length > 0) {
1235
                    var status_name = meta.settings.oInit.originalData[0].capabilities[
1236
                        row.status
1237
                    ].name;
1238
                    return getStatusName(status_name);
1239
                } else {
1240
                    return '';
1241
                }
1242
            };
1243
1244
            var getStatusName = function(origName) {
1245
                switch( origName ) {
1246
                    case "New request":
1247
                        return _("New request");
1248
                    case "Requested":
1249
                        return _("Requested");
1250
                    case "Requested from partners":
1251
                        return _("Requested from partners");
1252
                    case "Request reverted":
1253
                        return _("Request reverted");
1254
                    case "Queued request":
1255
                        return _("Queued request");
1256
                    case "Cancellation requested":
1257
                        return _("Cancellation requested");
1258
                    case "Completed":
1259
                        return _("Completed");
1260
                    case "Delete request":
1261
                        return _("Delete request");
1262
                    default:
1263
                        return origName;
1264
                }
1265
            };
1266
1267
            // Render function for creating a row's action link
1268
            var createActionLink = function(data, type, row) {
1269
                return '<a class="btn btn-default btn-sm" ' +
1270
                    'href="/cgi-bin/koha/ill/ill-requests.pl?' +
1271
                    'method=illview&amp;illrequest_id=' +
1272
                    row.illrequest_id +
1273
                    '">' + _("Manage request") + '</a>';
1274
            };
1275
1276
            // Columns that require special treatment
1277
            var specialCols = {
1278
                action: {
1279
                    name: '',
1280
                    func: createActionLink
1281
                },
1282
                borrowername: {
1283
                    name: _("Patron"),
1284
                    func: createPatronLink
1285
                },
1286
                illrequest_id: {
1287
                    name: _("Request number"),
1288
                    func: createRequestId
1289
                },
1290
                status: {
1291
                    name: _("Status"),
1292
                    func: createStatus
1293
                },
1294
                biblio_id: {
1295
                    name: _("Biblio ID")
1296
                },
1297
                library: {
1298
                    name: _("Library"),
1299
                    func: createLibrary
1300
                },
1301
                updated: {
1302
                    name: _("Updated on"),
1303
                },
1304
                patron_cardnumber: {
1305
                    name: _("Patron barcode")
1306
                }
1307
            };
1308
1309
            // Toggle request attributes in Illview
1310
            $('#toggle_requestattributes').on('click', function(e) {
1311
                e.preventDefault();
1312
                $('#requestattributes').toggleClass('content_hidden');
1313
            });
1314
1315
            // Filter partner list
1316
            $('#partner_filter').keyup(function() {
1317
                var needle = $('#partner_filter').val();
1318
                $('#partners > option').each(function() {
1319
                    var regex = new RegExp(needle, 'i');
1320
                    if (
1321
                        needle.length == 0 ||
1322
                        $(this).is(':selected') ||
1323
                        $(this).text().match(regex)
1324
                    ) {
1325
                        $(this).show();
1326
                    } else {
1327
                        $(this).hide();
1328
                    }
1329
                });
1330
            });
1331
1332
        // Display the modal containing request supplier metadata
1333
        $('#ill-request-display-metadata').on('click', function(e) {
1334
            e.preventDefault();
1335
            $('#dataPreview').modal({show:true});
1336
        });
1337
1338
            // Get our data from the API and process it prior to passing
1339
            // it to datatables
1340
            var ajax = $.ajax(
1341
                '/api/v1/illrequests?embed=metadata,patron,capabilities,library'
1342
                ).done(function() {
1343
                    var data = JSON.parse(ajax.responseText);
1344
                    // Make a copy, we'll be removing columns next and need
1345
                    // to be able to refer to data that has been removed
1346
                    var dataCopy = $.extend(true, [], data);
1347
                    // Remove all columns we're not interested in
1348
                    removeIgnore(dataCopy);
1349
                    // Expand columns that need it and create an array
1350
                    // of all column names
1351
                    $.each(dataCopy, function(k, row) {
1352
                        expandExpand(row);
1353
                    });
1354
1355
                    // Assemble an array of column definitions for passing
1356
                    // to datatables
1357
                    var colData = [];
1358
                    Object.keys(allCols).forEach(function(thisCol) {
1359
                        // Create the base column object
1360
                        var colObj = {
1361
                            name: thisCol,
1362
                            className: thisCol,
1363
                            defaultContent: ''
1364
                        };
1365
                        // We may need to process the data going in this
1366
                        // column, so do it if necessary
1367
                        if (
1368
                            specialCols.hasOwnProperty(thisCol) &&
1369
                            specialCols[thisCol].hasOwnProperty('func')
1370
                        ) {
1371
                            colObj.render = specialCols[thisCol].func;
1372
                        } else {
1373
                            colObj.data = thisCol;
1374
                        }
1375
                        colData.push(colObj);
1376
                    });
1377
1378
                    // Initialise the datatable
1379
                    table = $('#ill-requests').DataTable($.extend(true, {}, dataTablesDefaults, {
1380
                        'aoColumnDefs': [
1381
                            { // Last column shouldn't be sortable or searchable
1382
                                'aTargets': [ 'actions' ],
1383
                                'bSortable': false,
1384
                                'bSearchable': false
1385
                            },
1386
                            { // Hide the two date columns we use just for sorting
1387
                                'aTargets': [ 'placed', 'updated' ],
1388
                                'bVisible': false,
1389
                                'bSearchable': true
1390
                            },
1391
                            { // When sorting 'placed', we want to use the
1392
                              // unformatted column
1393
                              'aTargets': [ 'placed_formatted'],
1394
                              'iDataSort': 7
1395
                            },
1396
                            { // When sorting 'updated', we want to use the
1397
                              // unformatted column
1398
                              'aTargets': [ 'updated_formatted'],
1399
                              'iDataSort': 9
1400
                            }
1401
                        ],
1402
                        'aaSorting': [[ 9, 'desc' ]], // Default sort, updated descending
1403
                        'processing': true, // Display a message when manipulating
1404
                        'sPaginationType': "full_numbers", // Pagination display
1405
                        'deferRender': true, // Improve performance on big datasets
1406
                        'data': dataCopy,
1407
                        'columns': colData,
1408
                        'originalData': data, // Enable render functions to access
1409
                                              // our original data
1410
                        'initComplete': function() {
1411
1412
                            // Prepare any filter elements that need it
1413
                            for (var el in filterable) {
1414
                                if (filterable.hasOwnProperty(el)) {
1415
                                    if (filterable[el].hasOwnProperty('prep')) {
1416
                                        filterable[el].prep(dataCopy, data);
1417
                                    }
1418
                                    if (filterable[el].hasOwnProperty('listener')) {
1419
                                        filterable[el].listener();
1420
                                    }
1421
                                }
1422
                            }
1423
1424
                        }
1425
                    }));
1426
1427
                    // Custom date range filtering
1428
                    $.fn.dataTable.ext.search.push(function(settings, data, dataIndex) {
1429
                        var placedStart = $('#illfilter_dateplaced_start').datepicker('getDate');
1430
                        var placedEnd = $('#illfilter_dateplaced_end').datepicker('getDate');
1431
                        var modifiedStart = $('#illfilter_datemodified_start').datepicker('getDate');
1432
                        var modifiedEnd = $('#illfilter_datemodified_end').datepicker('getDate');
1433
                        var rowPlaced = data[7] ? new Date(data[7]) : null;
1434
                        var rowModified = data[9] ? new Date(data[9]) : null;
1435
                        var placedPassed = true;
1436
                        var modifiedPassed = true;
1437
                        if (placedStart && rowPlaced && rowPlaced < placedStart) {
1438
                            placedPassed = false
1439
                        };
1440
                        if (placedEnd && rowPlaced && rowPlaced > placedEnd) {
1441
                            placedPassed = false;
1442
                        }
1443
                        if (modifiedStart && rowModified && rowModified < modifiedStart) {
1444
                            modifiedPassed = false
1445
                        };
1446
                        if (modifiedEnd && rowModified && rowModified > modifiedEnd) {
1447
                            modifiedPassed = false;
1448
                        }
1449
1450
                        return placedPassed && modifiedPassed;
1451
1452
                    });
1453
1454
                }
1455
            );
1456
1457
            var clearSearch = function() {
1458
                table.search('').columns().search('');
1459
                activeFilters = {};
1460
                for (var filter in filterable) {
1461
                    if (
1462
                        filterable.hasOwnProperty(filter) &&
1463
                        filterable[filter].hasOwnProperty('clear')
1464
                    ) {
1465
                        filterable[filter].clear();
1466
                    }
1467
                }
1468
                table.draw();
1469
            };
1470
1471
            // Apply any search filters, or clear any previous
1472
            // ones
1473
            $('#illfilter_form').submit(function(event) {
1474
                event.preventDefault();
1475
                table.search('').columns().search('');
1476
                for (var active in activeFilters) {
1477
                    if (activeFilters.hasOwnProperty(active)) {
1478
                        activeFilters[active]();
1479
                    }
1480
                }
1481
                table.draw();
1482
            });
1483
1484
            // Clear all filters
1485
            $('#clear_search').click(function() {
1486
                clearSearch();
1487
            });
1488
1489
        });
1490
    </script>
1491
[% END %]
1492
1004
[% INCLUDE 'intranet-bottom.inc' %]
1493
[% INCLUDE 'intranet-bottom.inc' %]
1005
- 

Return to bug 20600