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

Return to bug 20600