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

Return to bug 20600