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

Return to bug 20600