Bug 33961: Remove built-in offline circ tool
The tool has not been updated and is no longer working with modern browser. It should either be rewritten/adjusted or removed. Given that we didn't get complains its non-functional status, bugs related to this tool didn't get attention, and the community is lacking resources, I am suggesting to remove it and redirect users to the koct FF plugin that is known to be working. Test plan: See bug 10240 and use `git grep` to confirm that we are removing all tracks of this feature. Signed-off-by: Owen Leonard <oleonard@myacpl.org> Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de> Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
This commit is contained in:
parent
5308697ab8
commit
3248afdc12
|
|
@ -225,7 +225,6 @@ sub _shared_preferences {
|
|||
SuspendHoldsOpac
|
||||
TransferWhenCancelAllWaitingHolds
|
||||
AllowAllMessageDeletion
|
||||
AllowOfflineCirculation
|
||||
PatronAutoComplete
|
||||
CircAutoPrintQuickSlip
|
||||
DisplayClearScreenButton
|
||||
|
|
|
|||
|
|
@ -37,6 +37,4 @@ my ($template, $loggedinuser, $cookie, $flags) = get_template_and_user(
|
|||
# Checking if there is a Fast Cataloging Framework
|
||||
$template->param( fast_cataloging => 1 ) if Koha::BiblioFrameworks->find( 'FA' );
|
||||
|
||||
$template->{'VARS'}->{'AllowOfflineCirculation'} = C4::Context->preference('AllowOfflineCirculation');
|
||||
|
||||
output_html_with_http_headers $query, $cookie, $template->output;
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# Copyright 2013 C & P Bibliography Services
|
||||
# This file is part of Koha.
|
||||
#
|
||||
# Koha is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Koha is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Koha; if not, see <http://www.gnu.org/licenses>.
|
||||
|
||||
use Modern::Perl;
|
||||
use CGI qw ( -utf8 );
|
||||
use C4::Auth qw( get_template_and_user );
|
||||
|
||||
my $query = CGI->new;
|
||||
my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user(
|
||||
{
|
||||
template_name => "circ/offline-mf.tt",
|
||||
query => $query,
|
||||
type => "intranet",
|
||||
flagsrequired => { circulate => "circulate_remaining_permissions" },
|
||||
}
|
||||
);
|
||||
|
||||
$template->{'VARS'}->{'cookie'} = $cookie;
|
||||
print $query->header( -type => 'text/cache-manifest', cookie => $cookie );
|
||||
print $template->output;
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# Copyright 2013 C & P Bibliography Services
|
||||
# This file is part of Koha.
|
||||
#
|
||||
# Koha is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Koha is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Koha; if not, see <http://www.gnu.org/licenses>.
|
||||
|
||||
use Modern::Perl;
|
||||
use CGI qw ( -utf8 );
|
||||
use C4::Auth qw( get_template_and_user );
|
||||
use C4::Output qw( output_html_with_http_headers );
|
||||
use C4::Context;
|
||||
|
||||
my $query = CGI->new;
|
||||
my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user(
|
||||
{
|
||||
template_name => "circ/offline.tt",
|
||||
query => $query,
|
||||
type => "intranet",
|
||||
flagsrequired => { circulate => "circulate_remaining_permissions" },
|
||||
}
|
||||
);
|
||||
|
||||
$template->{'VARS'}->{'AllowOfflineCirculation'} =
|
||||
C4::Context->preference('AllowOfflineCirculation');
|
||||
$template->{'VARS'}->{'maxoutstanding'} =
|
||||
C4::Context->preference('maxoutstanding') || 0;
|
||||
output_html_with_http_headers $query, $cookie, $template->output;
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
use Modern::Perl;
|
||||
|
||||
return {
|
||||
bug_number => "33961",
|
||||
description => "Remove Offline circulation tool",
|
||||
up => sub {
|
||||
my ($args) = @_;
|
||||
my ($dbh, $out) = @$args{qw(dbh out)};
|
||||
$dbh->do(q{
|
||||
DELETE FROM systempreferences
|
||||
WHERE variable="AllowOfflineCirculation"
|
||||
});
|
||||
say $out "Removed system preference 'AllowOfflineCirculation'";
|
||||
},
|
||||
};
|
||||
|
|
@ -35,7 +35,6 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `
|
|||
('AllowMultipleCovers','0','1','Allow multiple cover images to be attached to each bibliographic record.','YesNo'),
|
||||
('AllowMultipleIssuesOnABiblio',1,'Allow/Don\'t allow patrons to check out multiple items from one biblio','','YesNo'),
|
||||
('AllowNotForLoanOverride','0','','If ON, Koha will allow the librarian to loan a not for loan item.','YesNo'),
|
||||
('AllowOfflineCirculation','0','','If on, enables HTML5 offline circulation functionality.','YesNo'),
|
||||
('AllowPatronToControlAutorenewal','0',NULL,'If enabled, patrons will have a field in their account to choose whether their checkouts are auto renewed or not','YesNo'),
|
||||
('AllowPatronToSetCheckoutsVisibilityForGuarantor', '0', NULL, 'If enabled, the patron can set checkouts to be visible to their guarantor', 'YesNo'),
|
||||
('AllowPatronToSetFinesVisibilityForGuarantor', '0', NULL, 'If enabled, the patron can set fines to be visible to their guarantor', 'YesNo'),
|
||||
|
|
|
|||
|
|
@ -1,517 +0,0 @@
|
|||
(function($, undefined) {
|
||||
var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
|
||||
var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange;
|
||||
var IDBCursor = window.IDBCursor || window.webkitIDBCursor;
|
||||
IDBCursor.PREV = IDBCursor.PREV || "prev";
|
||||
IDBCursor.NEXT = IDBCursor.NEXT || "next";
|
||||
|
||||
/**
|
||||
* Best to use the constant IDBTransaction since older version support numeric types while the latest spec
|
||||
* supports strings
|
||||
*/
|
||||
var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction;
|
||||
|
||||
function getDefaultTransaction(mode) {
|
||||
var result = null;
|
||||
switch (mode) {
|
||||
case 0:
|
||||
case 1:
|
||||
case "readwrite":
|
||||
case "readonly":
|
||||
result = mode;
|
||||
break;
|
||||
default:
|
||||
result = IDBTransaction.READ_WRITE || "readwrite";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
$.extend({
|
||||
/**
|
||||
* The IndexedDB object used to open databases
|
||||
* @param {Object} dbName - name of the database
|
||||
* @param {Object} config - version, onupgradeneeded, onversionchange, schema
|
||||
*/
|
||||
"indexedDB": function(dbName, config) {
|
||||
if (config) {
|
||||
// Parse the config argument
|
||||
if (typeof config === "number") config = {
|
||||
"version": config
|
||||
};
|
||||
|
||||
var version = config.version;
|
||||
if (config.schema && !version) {
|
||||
var max = -1;
|
||||
for (key in config.schema) {
|
||||
max = max > key ? max : key;
|
||||
}
|
||||
version = config.version || max;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var wrap = {
|
||||
"request": function(req, args) {
|
||||
return $.Deferred(function(dfd) {
|
||||
try {
|
||||
var idbRequest = typeof req === "function" ? req(args) : req;
|
||||
idbRequest.onsuccess = function(e) {
|
||||
|
||||
dfd.resolveWith(idbRequest, [idbRequest.result, e]);
|
||||
};
|
||||
idbRequest.onerror = function(e) {
|
||||
|
||||
dfd.rejectWith(idbRequest, [idbRequest.error, e]);
|
||||
};
|
||||
if (typeof idbRequest.onblocked !== "undefined" && idbRequest.onblocked === null) {
|
||||
idbRequest.onblocked = function(e) {
|
||||
|
||||
var res;
|
||||
try {
|
||||
res = idbRequest.result;
|
||||
} catch (e) {
|
||||
res = null; // Required for Older Chrome versions, accessing result causes error
|
||||
}
|
||||
dfd.notifyWith(idbRequest, [res, e]);
|
||||
};
|
||||
}
|
||||
if (typeof idbRequest.onupgradeneeded !== "undefined" && idbRequest.onupgradeneeded === null) {
|
||||
idbRequest.onupgradeneeded = function(e) {
|
||||
|
||||
dfd.notifyWith(idbRequest, [idbRequest.result, e]);
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
e.name = "exception";
|
||||
dfd.rejectWith(idbRequest, ["exception", e]);
|
||||
}
|
||||
});
|
||||
},
|
||||
// Wraps the IDBTransaction to return promises, and other dependent methods
|
||||
"transaction": function(idbTransaction) {
|
||||
return {
|
||||
"objectStore": function(storeName) {
|
||||
try {
|
||||
return wrap.objectStore(idbTransaction.objectStore(storeName));
|
||||
} catch (e) {
|
||||
idbTransaction.readyState !== idbTransaction.DONE && idbTransaction.abort();
|
||||
return wrap.objectStore(null);
|
||||
}
|
||||
},
|
||||
"createObjectStore": function(storeName, storeParams) {
|
||||
try {
|
||||
return wrap.objectStore(idbTransaction.db.createObjectStore(storeName, storeParams));
|
||||
} catch (e) {
|
||||
idbTransaction.readyState !== idbTransaction.DONE && idbTransaction.abort();
|
||||
}
|
||||
},
|
||||
"deleteObjectStore": function(storeName) {
|
||||
try {
|
||||
idbTransaction.db.deleteObjectStore(storeName);
|
||||
} catch (e) {
|
||||
idbTransaction.readyState !== idbTransaction.DONE && idbTransaction.abort();
|
||||
}
|
||||
},
|
||||
"abort": function() {
|
||||
idbTransaction.abort();
|
||||
}
|
||||
};
|
||||
},
|
||||
"objectStore": function(idbObjectStore) {
|
||||
var result = {};
|
||||
// Define CRUD operations
|
||||
var crudOps = ["add", "put", "get", "delete", "clear", "count"];
|
||||
for (var i = 0; i < crudOps.length; i++) {
|
||||
result[crudOps[i]] = (function(op) {
|
||||
return function() {
|
||||
return wrap.request(function(args) {
|
||||
return idbObjectStore[op].apply(idbObjectStore, args);
|
||||
}, arguments);
|
||||
};
|
||||
})(crudOps[i]);
|
||||
}
|
||||
|
||||
result.each = function(callback, range, direction) {
|
||||
return wrap.cursor(function() {
|
||||
if (direction) {
|
||||
return idbObjectStore.openCursor(wrap.range(range), direction);
|
||||
} else {
|
||||
return idbObjectStore.openCursor(wrap.range(range));
|
||||
}
|
||||
}, callback);
|
||||
};
|
||||
|
||||
result.index = function(name) {
|
||||
return wrap.index(function() {
|
||||
return idbObjectStore.index(name);
|
||||
});
|
||||
};
|
||||
|
||||
result.createIndex = function(prop, options, indexName) {
|
||||
if (arguments.length === 2 && typeof options === "string") {
|
||||
indexName = arguments[1];
|
||||
options = null;
|
||||
}
|
||||
if (!indexName) {
|
||||
indexName = prop;
|
||||
}
|
||||
return wrap.index(function() {
|
||||
return idbObjectStore.createIndex(indexName, prop, options);
|
||||
});
|
||||
};
|
||||
|
||||
result.deleteIndex = function(indexName) {
|
||||
return idbObjectStore.deleteIndex(indexName);
|
||||
};
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
"range": function(r) {
|
||||
if ($.isArray(r)) {
|
||||
if (r.length === 1) {
|
||||
return IDBKeyRange.only(r[0]);
|
||||
} else {
|
||||
return IDBKeyRange.bound(r[0], r[1], (typeof r[2] === 'undefined') ? true : r[2], (typeof r[3] === 'undefined') ? true : r[3]);
|
||||
}
|
||||
} else if (typeof r === "undefined") {
|
||||
return null;
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
},
|
||||
|
||||
"cursor": function(idbCursor, callback) {
|
||||
return $.Deferred(function(dfd) {
|
||||
try {
|
||||
|
||||
var cursorReq = typeof idbCursor === "function" ? idbCursor() : idbCursor;
|
||||
cursorReq.onsuccess = function(e) {
|
||||
|
||||
if (!cursorReq.result) {
|
||||
dfd.resolveWith(cursorReq, [null, e]);
|
||||
return;
|
||||
}
|
||||
var elem = {
|
||||
// Delete, update do not move
|
||||
"delete": function() {
|
||||
return wrap.request(function() {
|
||||
return cursorReq.result["delete"]();
|
||||
});
|
||||
},
|
||||
"update": function(data) {
|
||||
return wrap.request(function() {
|
||||
return cursorReq.result["update"](data);
|
||||
});
|
||||
},
|
||||
"next": function(key) {
|
||||
this.data = key;
|
||||
},
|
||||
"key": cursorReq.result.key,
|
||||
"value": cursorReq.result.value
|
||||
};
|
||||
|
||||
dfd.notifyWith(cursorReq, [elem, e]);
|
||||
var result = callback.apply(cursorReq, [elem]);
|
||||
|
||||
try {
|
||||
if (result === false) {
|
||||
dfd.resolveWith(cursorReq, [null, e]);
|
||||
} else if (typeof result === "number") {
|
||||
cursorReq.result["advance"].apply(cursorReq.result, [result]);
|
||||
} else {
|
||||
if (elem.data) cursorReq.result["continue"].apply(cursorReq.result, [elem.data]);
|
||||
else cursorReq.result["continue"]();
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
dfd.rejectWith(cursorReq, [cursorReq.result, e]);
|
||||
}
|
||||
};
|
||||
cursorReq.onerror = function(e) {
|
||||
|
||||
dfd.rejectWith(cursorReq, [cursorReq.result, e]);
|
||||
};
|
||||
} catch (e) {
|
||||
|
||||
e.type = "exception";
|
||||
dfd.rejectWith(cursorReq, [null, e]);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
"index": function(index) {
|
||||
try {
|
||||
var idbIndex = (typeof index === "function" ? index() : index);
|
||||
} catch (e) {
|
||||
idbIndex = null;
|
||||
}
|
||||
|
||||
return {
|
||||
"each": function(callback, range, direction) {
|
||||
return wrap.cursor(function() {
|
||||
if (direction) {
|
||||
return idbIndex.openCursor(wrap.range(range), direction);
|
||||
} else {
|
||||
return idbIndex.openCursor(wrap.range(range));
|
||||
}
|
||||
|
||||
}, callback);
|
||||
},
|
||||
"eachKey": function(callback, range, direction) {
|
||||
return wrap.cursor(function() {
|
||||
if (direction) {
|
||||
return idbIndex.openKeyCursor(wrap.range(range), direction);
|
||||
} else {
|
||||
return idbIndex.openKeyCursor(wrap.range(range));
|
||||
}
|
||||
}, callback);
|
||||
},
|
||||
"get": function(key) {
|
||||
if (typeof idbIndex.get === "function") {
|
||||
return wrap.request(idbIndex.get(key));
|
||||
} else {
|
||||
return idbIndex.openCursor(wrap.range(key));
|
||||
}
|
||||
},
|
||||
"count": function() {
|
||||
if (typeof idbIndex.count === "function") {
|
||||
return wrap.request(idbIndex.count());
|
||||
} else {
|
||||
throw "Count not implemented for cursors";
|
||||
}
|
||||
},
|
||||
"getKey": function(key) {
|
||||
if (typeof idbIndex.getKey === "function") {
|
||||
return wrap.request(idbIndex.getKey(key));
|
||||
} else {
|
||||
return idbIndex.openKeyCursor(wrap.range(key));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Start with opening the database
|
||||
var dbPromise = wrap.request(function() {
|
||||
|
||||
return version ? indexedDB.open(dbName, parseInt(version)) : indexedDB.open(dbName);
|
||||
});
|
||||
dbPromise.then(function(db, e) {
|
||||
|
||||
db.onversionchange = function() {
|
||||
// Try to automatically close the database if there is a version change request
|
||||
if (!(config && config.onversionchange && config.onversionchange() !== false)) {
|
||||
db.close();
|
||||
}
|
||||
};
|
||||
}, function(error, e) {
|
||||
|
||||
// Nothing much to do if an error occurs
|
||||
}, function(db, e) {
|
||||
if (e && e.type === "upgradeneeded") {
|
||||
if (config && config.schema) {
|
||||
// Assuming that version is always an integer
|
||||
|
||||
for (var i = e.oldVersion + 1; i <= e.newVersion; i++) {
|
||||
typeof config.schema[i] === "function" && config.schema[i].call(this, wrap.transaction(this.transaction));
|
||||
}
|
||||
}
|
||||
if (config && typeof config.upgrade === "function") {
|
||||
config.upgrade.call(this, wrap.transaction(this.transaction));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return $.extend(dbPromise, {
|
||||
"cmp": function(key1, key2) {
|
||||
return indexedDB.cmp(key1, key2);
|
||||
},
|
||||
"deleteDatabase": function() {
|
||||
// Kinda looks ugly coz DB is opened before it needs to be deleted.
|
||||
// Blame it on the API
|
||||
return $.Deferred(function(dfd) {
|
||||
dbPromise.then(function(db, e) {
|
||||
db.close();
|
||||
wrap.request(function() {
|
||||
return indexedDB.deleteDatabase(dbName);
|
||||
}).then(function(result, e) {
|
||||
dfd.resolveWith(this, [result, e]);
|
||||
}, function(error, e) {
|
||||
dfd.rejectWith(this, [error, e]);
|
||||
}, function(db, e) {
|
||||
dfd.notifyWith(this, [db, e]);
|
||||
});
|
||||
}, function(error, e) {
|
||||
dfd.rejectWith(this, [error, e]);
|
||||
}, function(db, e) {
|
||||
dfd.notifyWith(this, [db, e]);
|
||||
});
|
||||
});
|
||||
},
|
||||
"transaction": function(storeNames, mode) {
|
||||
!$.isArray(storeNames) && (storeNames = [storeNames]);
|
||||
mode = getDefaultTransaction(mode);
|
||||
return $.Deferred(function(dfd) {
|
||||
dbPromise.then(function(db, e) {
|
||||
var idbTransaction;
|
||||
try {
|
||||
|
||||
idbTransaction = db.transaction(storeNames, mode);
|
||||
|
||||
idbTransaction.onabort = idbTransaction.onerror = function(e) {
|
||||
dfd.rejectWith(idbTransaction, [e]);
|
||||
};
|
||||
idbTransaction.oncomplete = function(e) {
|
||||
dfd.resolveWith(idbTransaction, [e]);
|
||||
};
|
||||
} catch (e) {
|
||||
|
||||
e.type = "exception";
|
||||
dfd.rejectWith(this, [e]);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
dfd.notifyWith(idbTransaction, [wrap.transaction(idbTransaction)]);
|
||||
} catch (e) {
|
||||
e.type = "exception";
|
||||
dfd.rejectWith(this, [e]);
|
||||
}
|
||||
}, function(err, e) {
|
||||
dfd.rejectWith(this, [e, err]);
|
||||
}, function(res, e) {
|
||||
|
||||
//dfd.notifyWith(this, ["", e]);
|
||||
});
|
||||
|
||||
});
|
||||
},
|
||||
"objectStore": function(storeName, mode) {
|
||||
var me = this,
|
||||
result = {};
|
||||
|
||||
function op(callback) {
|
||||
return $.Deferred(function(dfd) {
|
||||
function onTransactionProgress(trans, callback) {
|
||||
try {
|
||||
|
||||
callback(trans.objectStore(storeName)).then(function(result, e) {
|
||||
dfd.resolveWith(this, [result, e]);
|
||||
}, function(err, e) {
|
||||
dfd.rejectWith(this, [err, e]);
|
||||
});
|
||||
} catch (e) {
|
||||
|
||||
e.name = "exception";
|
||||
dfd.rejectWith(trans, [e, e]);
|
||||
}
|
||||
}
|
||||
me.transaction(storeName, getDefaultTransaction(mode)).then(function() {
|
||||
|
||||
// Nothing to do when transaction is complete
|
||||
}, function(err, e) {
|
||||
// If transaction fails, CrudOp fails
|
||||
if (err.code === err.NOT_FOUND_ERR && (mode === true || typeof mode === "object")) {
|
||||
|
||||
var db = this.result;
|
||||
db.close();
|
||||
dbPromise = wrap.request(function() {
|
||||
|
||||
return indexedDB.open(dbName, (parseInt(db.version, 10) || 1) + 1);
|
||||
});
|
||||
dbPromise.then(function(db, e) {
|
||||
|
||||
db.onversionchange = function() {
|
||||
// Try to automatically close the database if there is a version change request
|
||||
if (!(config && config.onversionchange && config.onversionchange() !== false)) {
|
||||
db.close();
|
||||
}
|
||||
};
|
||||
me.transaction(storeName, getDefaultTransaction(mode)).then(function() {
|
||||
|
||||
// Nothing much to do
|
||||
}, function(err, e) {
|
||||
dfd.rejectWith(this, [err, e]);
|
||||
}, function(trans, e) {
|
||||
|
||||
onTransactionProgress(trans, callback);
|
||||
});
|
||||
}, function(err, e) {
|
||||
dfd.rejectWith(this, [err, e]);
|
||||
}, function(db, e) {
|
||||
if (e.type === "upgradeneeded") {
|
||||
try {
|
||||
|
||||
db.createObjectStore(storeName, mode === true ? {
|
||||
"autoIncrement": true
|
||||
} : mode);
|
||||
|
||||
} catch (ex) {
|
||||
|
||||
dfd.rejectWith(this, [ex, e]);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
dfd.rejectWith(this, [err, e]);
|
||||
}
|
||||
}, function(trans) {
|
||||
|
||||
onTransactionProgress(trans, callback);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function crudOp(opName, args) {
|
||||
return op(function(wrappedObjectStore) {
|
||||
return wrappedObjectStore[opName].apply(wrappedObjectStore, args);
|
||||
});
|
||||
}
|
||||
|
||||
function indexOp(opName, indexName, args) {
|
||||
return op(function(wrappedObjectStore) {
|
||||
var index = wrappedObjectStore.index(indexName);
|
||||
return index[opName].apply(index[opName], args);
|
||||
});
|
||||
}
|
||||
|
||||
var crud = ["add", "delete", "get", "put", "clear", "count", "each"];
|
||||
for (var i = 0; i < crud.length; i++) {
|
||||
result[crud[i]] = (function(op) {
|
||||
return function() {
|
||||
return crudOp(op, arguments);
|
||||
};
|
||||
})(crud[i]);
|
||||
}
|
||||
|
||||
result.index = function(indexName) {
|
||||
return {
|
||||
"each": function(callback, range, direction) {
|
||||
return indexOp("each", indexName, [callback, range, direction]);
|
||||
},
|
||||
"eachKey": function(callback, range, direction) {
|
||||
return indexOp("eachKey", indexName, [callback, range, direction]);
|
||||
},
|
||||
"get": function(key) {
|
||||
return indexOp("get", indexName, [key]);
|
||||
},
|
||||
"count": function() {
|
||||
return indexOp("count", indexName, []);
|
||||
},
|
||||
"getKey": function(key) {
|
||||
return indexOp("getKey", indexName, [key]);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$.indexedDB.IDBCursor = IDBCursor;
|
||||
$.indexedDB.IDBTransaction = IDBTransaction;
|
||||
$.idb = $.indexedDB;
|
||||
})(jQuery);
|
||||
|
|
@ -3549,31 +3549,6 @@ span {
|
|||
border-bottom-left-radius: 5px;
|
||||
}
|
||||
|
||||
.loading-overlay {
|
||||
background-color: #FFFFFF;
|
||||
cursor: wait;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
opacity: .7;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
|
||||
div {
|
||||
background: transparent url("../img/loading.gif") top left no-repeat;
|
||||
font-size: 175%;
|
||||
font-weight: bold;
|
||||
height: 2em;
|
||||
left: 50%;
|
||||
margin: -1em 0 0 -2.5em;
|
||||
padding-left: 50px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 15em;
|
||||
}
|
||||
}
|
||||
|
||||
#merge_invoices {
|
||||
display: none;
|
||||
margin: 1em auto;
|
||||
|
|
|
|||
|
|
@ -145,12 +145,6 @@ Circulation:
|
|||
- "The following fields should be excluded from the patron checkout history CSV or MARC (ISO 2709) export:"
|
||||
- pref: ExportRemoveFields
|
||||
- (separate fields with space, e.g. 100a 200b 300c).
|
||||
-
|
||||
- pref: AllowOfflineCirculation
|
||||
choices:
|
||||
1: Enable
|
||||
0: "Don't enable"
|
||||
- "offline circulation on regular circulation computers. (<strong>NOTE:</strong> This system preference does not affect the Firefox add-on or the desktop application)."
|
||||
-
|
||||
- pref: ShowAllCheckins
|
||||
choices:
|
||||
|
|
|
|||
|
|
@ -164,9 +164,6 @@
|
|||
<div class="col-md-12">
|
||||
<h4>Offline circulation</h4>
|
||||
<div class="col-sm-5 col-md-3">
|
||||
[% IF (AllowOfflineCirculation) %]
|
||||
<a href="/cgi-bin/koha/circ/offline.pl">Built-in offline circulation interface</a>
|
||||
[% END %]
|
||||
<p><a href="/cgi-bin/koha/offline_circ/process_koc.pl">Upload offline circulation file (.koc)</a></p>
|
||||
<p><a href="/cgi-bin/koha/offline_circ/list.pl">Pending offline circulation actions</a></p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,33 +0,0 @@
|
|||
CACHE MANIFEST
|
||||
# [% cookie | html %]
|
||||
|
||||
# Explicitly cached 'master entries'.
|
||||
CACHE:
|
||||
/cgi-bin/koha/circ/offline.pl
|
||||
[% interface | html %]/lib/bootstrap/bootstrap.min.css
|
||||
[% interface | html %]/lib/bootstrap/bootstrap-theme.min.css
|
||||
[% interface | html %]/lib/bootstrap/bootstrap.min.js
|
||||
[% interface | html %]/lib/jquery/jquery-ui-1.13.1.min.css
|
||||
[% interface | html %]/lib/jquery/jquery-ui-1.13.1.min.js
|
||||
[% interface | html %]/lib/jquery/jquery-3.6.0.min.js
|
||||
[% interface | html %]/lib/jquery/jquery-migrate-3.3.2.min.js
|
||||
[% interface | html %]/lib/jquery/plugins/jquery.highlight-3.js
|
||||
[% interface | html %]/lib/shortcut/shortcut.js
|
||||
[% interface | html %]/lib/jquery/plugins/jquery.indexeddb.js
|
||||
[% interface | html %]/lib/jquery/plugins/jquery.validate.min.js
|
||||
[% interface | html %]/[% theme | html %]/css/print.css
|
||||
[% interface | html %]/[% theme | html %]/css/staff-global.css
|
||||
[% interface | html %]/[% theme | html %]/js/basket.js
|
||||
[% interface | html %]/[% theme | html %]/js/offlinecirc.js
|
||||
[% interface | html %]/[% theme | html %]/js/staff-global.js
|
||||
[% interface | html %]/prog/img/koha-logo-medium.png
|
||||
[% interface | html %]/prog/img/loading.gif
|
||||
[% interface | html %]/prog/sound/beep.ogg
|
||||
[% interface | html %]/prog/sound/critical.ogg
|
||||
|
||||
# Resources that require the user to be online.
|
||||
NETWORK:
|
||||
*
|
||||
|
||||
# Resources that can be substituted if the user is offline
|
||||
FALLBACK:
|
||||
|
|
@ -1,788 +0,0 @@
|
|||
[% USE raw %]
|
||||
[% USE Asset %]
|
||||
[% USE Branches %]
|
||||
[% SET footerjs = 1 %]
|
||||
<!DOCTYPE html>
|
||||
[% IF (AllowOfflineCirculation) %]
|
||||
[% SET manifestattr = 'manifest="/cgi-bin/koha/circ/offline-mf.pl"' %]
|
||||
[% END %]
|
||||
[% IF ( bidi && AllowOfflineCirculation ) %]<html lang="[% lang | html %]" dir="[% bidi | html %]" manifest="/cgi-bin/koha/circ/offline-mf.pl">
|
||||
[% ELSIF ( bidi ) %]<html lang="[% lang | html %]" dir="[% bidi | html %]">
|
||||
[% ELSIF ( AllowOfflineCirculation ) %]<html lang="[% lang | html %]" manifest="/cgi-bin/koha/circ/offline-mf.pl">
|
||||
[% ELSE %]<html lang="[% lang | html %]">[% END %]
|
||||
<head>
|
||||
<title>Circulation › Koha</title>
|
||||
[% INCLUDE 'doc-head-close.inc' %]
|
||||
</head>
|
||||
|
||||
<body id="circ_offline" class="circ">
|
||||
[% WRAPPER 'header.inc' %]
|
||||
[% INCLUDE 'circ-search.inc' %]
|
||||
[% END %]
|
||||
<div class="loading-overlay" style="display: none;">
|
||||
<div>Downloading records, please wait...</div>
|
||||
</div>
|
||||
|
||||
[% WRAPPER 'sub-header.inc' %]
|
||||
[% WRAPPER breadcrumbs %]
|
||||
[% WRAPPER breadcrumb_item %]
|
||||
<a id="go-to-home" href="#offline-home" aria-current="page">Offline circulation</a>
|
||||
[% END %]
|
||||
[% END #/ WRAPPER breadcrumbs %]
|
||||
[% END #/ WRAPPER sub-header.inc %]
|
||||
|
||||
<div class="main container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-10 col-sm-push-2">
|
||||
<main>
|
||||
<h1>Offline circulation</h1>
|
||||
|
||||
<audio id="alert_sound" src="[% interface | html %]/prog/sound/critical.ogg" preload="auto"></audio>
|
||||
<audio id="success_sound" src="[% interface | html %]/prog/sound/beep.ogg" preload="auto"></audio>
|
||||
|
||||
<div id="alerts"></div>
|
||||
|
||||
[% UNLESS (AllowOfflineCirculation) %]
|
||||
<div id="noofflinecircwarning" class="dialog alert">
|
||||
<p><strong>Warning:</strong> Offline circulation has been disabled. You may continue and record transactions, but patron and item information will not be available.</p>
|
||||
</div>
|
||||
[% END %]
|
||||
|
||||
<div id="offline-home" class="offline-home">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<ul>
|
||||
<li><a id="go-to-circ" href="#offline-circulation">Check out</a></li>
|
||||
<li><a id="go-to-returns" href="#offline-returns">Check in</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6">
|
||||
<p><strong>Note:</strong> You must be online to use these options.</p>
|
||||
<ul>
|
||||
<li><a id="go-to-sync" href="#offline-sync">Synchronize</a></li>
|
||||
<li><a id="go-to-pending" href="/cgi-bin/koha/offline_circ/list.pl">Pending offline circulation actions</a>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="offline-sync" style="display: none;" class="offline-sync">
|
||||
<div id="toolbar" class="btn-toolbar">
|
||||
[% IF (AllowOfflineCirculation) %]
|
||||
<a href="#" id="download-records" class="btn btn-default"><i class="fa fa-arrow-down"></i> Download records</a>
|
||||
[% END %]
|
||||
<a href="#" id="upload-transactions" class="btn btn-default"><i class="fa fa-arrow-up"></i> Upload transactions</a>
|
||||
</div>
|
||||
<h1>Offline circulation</h1>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<div id="download-message">
|
||||
In order for offline circulation to work on this computer,
|
||||
your library's records must be up-to-date on this computer:
|
||||
<ul>
|
||||
<li>Patron records were last synced on: <span id="patron-timestamp">(checking)</span></li>
|
||||
<li>Item records were last synced on: <span id="item-timestamp">(checking)</span></li>
|
||||
<li>Circulation records were last synced on: <span id="issue-timestamp">(checking)</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6">
|
||||
<div id="upload-message">
|
||||
</div>
|
||||
<div>View <a href="/cgi-bin/koha/offline_circ/list.pl">pending offline circulation actions</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="offline-returns" style="display: none;" class="offline-returns">
|
||||
<div class="row">
|
||||
<form id="checkin-form" method="post" action="/cgi-bin/koha/circ/returns.pl" autocomplete="off" >
|
||||
<div class="col-sm-6">
|
||||
<fieldset>
|
||||
<legend>Check in</legend>
|
||||
<label for="checkin-barcode">Enter item barcode: </label>
|
||||
<input name="barcode" id="checkin-barcode" size="14" class="focus" type="text" />
|
||||
<input type="submit" class="btn btn-primary" value="Submit" />
|
||||
</fieldset>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="session-returned" style="display: none;">
|
||||
<h2>Checked-in items</h2>
|
||||
<table id="already-checked-in">
|
||||
<thead>
|
||||
<tr><th>Title</th><th>Author</th><th>Barcode</th><th>Home library</th><th>Holding library</th><th>Shelving location</th><th>Call number</th><th>Type</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: none;" class="offline-circulation-instructions">
|
||||
Scan a patron barcode to start.
|
||||
</div>
|
||||
|
||||
<div id="offline-circulation" style="display: none;" class="offline-circulation">
|
||||
<form method="post" action="/cgi-bin/koha/circ/offline.pl" id="mainform" name="mainform" autocomplete="off">
|
||||
<fieldset id="circ_circulation_issue">
|
||||
<span id="clearscreen"><a href="/cgi-bin/koha/circ/offline.pl" title="Clear screen">x</a></span>
|
||||
<label for="checkout-barcode">Checking out to <span class="patron-title"></span></label>
|
||||
<div class="hint">Enter item barcode:</div>
|
||||
<input type="text" name="barcode" id="checkout-barcode" class="barcode focus" size="14" />
|
||||
<input type="submit" class="btn btn-primary" value="Check out" />
|
||||
|
||||
<div class="date-select">
|
||||
<div class="hint">Specify due date [% INCLUDE 'date-format.inc' %]: </div>
|
||||
<input type="text" size="13" id="duedatespec" name="duedatespec" value="[% duedatespec | html %]" class="flatpickr" data-flatpickr-enable-time="true" data-flatpickr-on-close-focus="#checkout-barcode" />
|
||||
<label for="stickyduedate"> Remember for session:</label>
|
||||
<input type="checkbox" id="stickyduedate" onclick="this.form.barcode.focus();" name="stickyduedate" checked="checked" />
|
||||
<input type="button" class="action" id="cleardate" value="Clear" name="cleardate" onclick="this.checked = false; this.form.duedatespec.value = ''; this.form.stickyduedate.checked = false; this.form.barcode.focus(); return false;" />
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<div id="patronlists" class="toptabs">
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li role="presentation" class="active"><a href="#checkouts" aria-controls="checkouts" role="tab" data-toggle="tab"><span class="checkout-count">0</span> Checkouts</a></li>
|
||||
<li role="presentation"><a href="#fines" aria-controls="fines" role="tab" data-toggle="tab"><span class="fine-amount">0</span> in fines</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<!-- SUMMARY : TODAY & PREVIOUS ISSUES -->
|
||||
<div role="tabpanel" class="tab-pane active" id="checkouts">
|
||||
<div id="session-issues">
|
||||
<table id="issuest">
|
||||
<thead><tr>
|
||||
<th scope="col">Due date</th>
|
||||
<th scope="col">Title</th>
|
||||
<th scope="col">Barcode</th>
|
||||
<th scope="col">Item type</th>
|
||||
<th scope="col">Checked out on</th>
|
||||
<th scope="col">Checked out from</th>
|
||||
<th scope="col">Call number</th>
|
||||
<th scope="col">Charge</th>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="oldissues">
|
||||
<h5>Previous checkouts</h5>
|
||||
<table id="oldissuest">
|
||||
<thead><tr>
|
||||
<th scope="col">Due date</th>
|
||||
<th scope="col">Title</th>
|
||||
<th scope="col">Barcode</th>
|
||||
<th scope="col">Item type</th>
|
||||
<th scope="col">Checked out on</th>
|
||||
<th scope="col">Checked out from</th>
|
||||
<th scope="col">Call number</th>
|
||||
<th scope="col">Charge</th>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div role="tabpanel" class="tab-pane" id="fines">
|
||||
<span class="patron-title"></span> has <span class="fine-amount">0</span> in fines. If you would like you can record payments.
|
||||
<fieldset><legend>Pay fines</legend>
|
||||
<label for="pay-fine-amount">Fine amount: </label><input type="text" name="pay-fine-amount" id="pay-fine-amount"/>
|
||||
<button id="pay-fine" class="submit">Pay fine</button>
|
||||
|
||||
<table id="session-payments" style="display: none;">
|
||||
<thead><tr><th>Amount</th><th>Date</th></tr></thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</fieldset>
|
||||
</div> <!-- /# -->fines
|
||||
</div> <!-- /.tab-content -->
|
||||
</div> <!-- /#patronlists -->
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</main>
|
||||
</div> <!-- /.col-sm-10.col-sm-push-2 -->
|
||||
|
||||
<div class="offline-circulation" style="display: none;">
|
||||
<div class="col-sm-2 col-sm-pull-10">
|
||||
<aside>
|
||||
<div class="patroninfo"><h5 class="patron-title"> </h5>
|
||||
<ul>
|
||||
<li id="patron-address-1"></li>
|
||||
<li id="patron-address-2"></li>
|
||||
<li id="patron-address-parts"><!-- city, state, zipcode, country --></li>
|
||||
<li id="patron-phone"></li>
|
||||
<li id="patron-email"></li>
|
||||
<li id="patron-category"></li>
|
||||
<li id="patron-library"></li>
|
||||
</ul>
|
||||
</div>
|
||||
</aside>
|
||||
</div> <!-- /.col-sm-2.col-sm-pull-10 -->
|
||||
</div> <!-- /.row -->
|
||||
</div>
|
||||
|
||||
[% MACRO jsinclude BLOCK %]
|
||||
[% INCLUDE 'calendar.inc' %]
|
||||
[% Asset.js("lib/jquery/plugins/jquery.indexeddb.js") | $raw %]
|
||||
[% Asset.js("js/offlinecirc.js") | $raw %]
|
||||
<script>
|
||||
var ALERT_SUCCESSFUL_CHECKIN = _("Checked in item.");
|
||||
var ALERT_MATERIALS = _("Note about the accompanying materials: %s");
|
||||
var ALERT_RESTRICTED = _("Patron is RESTRICTED");
|
||||
var ALERT_NO_MATCHING_ITEM = _("No item with barcode in offline database (transaction recorded anyway): %s");
|
||||
var ALERT_NOT_CHECKED_OUT = _("Item not listed as checked out in offline database (transaction recorded anyway)");
|
||||
var ALERT_ITEM_WITHDRAWN = _("Item has been withdrawn (transaction recorded anyway)");
|
||||
var ALERT_ITEM_RESTRICTED = _("Item is restricted (transaction recorded anyway)");
|
||||
var ALERT_ITEM_LOST = _("Item has been lost (transaction recorded anyway)");
|
||||
var ALERT_NO_MATCHING_PATRON = _("No patron card number in offline database (proceeding anyway): %s");
|
||||
var ALERT_PATRON_GONE_NO_ADDRESS = _("Patron's address is in doubt (proceeding anyway)");
|
||||
var ALERT_PATRON_CARD_LOST = _("Patron's card is lost");
|
||||
var ALERT_PATRON_EXPIRED = _("Patron's card is expired (%s)");
|
||||
var ALERT_PATRON_BLOCKED_TEMPORARY = _("Patron has had overdue items and is restricted until: %s");
|
||||
var ALERT_PATRON_RESTRICTED = _("Patron is restricted");
|
||||
var ALERT_PATRON_FINE = _("Patron has outstanding fines: %s");
|
||||
var ALERT_PATRON_FINE_OVER_LIMIT = _("Patron fines are over limit: %s");
|
||||
var UPLOAD_PENDING_MESSAGE = _("You have transactions in the offline circulation database on this computer that have not been uploaded.");
|
||||
var NO_UPLOAD_PENDING_MESSAGE = _("You do not have any pending transactions in the offline circulation database on this computer.");
|
||||
|
||||
var start;
|
||||
|
||||
var dateformat = '[% IF ( dateformat_us ) %]mm/dd/yy[% ELSIF ( dateformat_metric ) %]dd/mm/yy[% ELSE %]yy-mm-dd[% END %]';
|
||||
var flatpickr_dateformat_string = [% IF ( dateformat == "us" ) %]"m/d/Y"[% ELSIF ( dateformat == "metric" ) %]"d/m/Y"[% ELSIF ( dateformat == "dmydot" ) %]"d.m.Y"[% ELSE %]"Y-m-d"[% END %];
|
||||
var flatpickr_timeformat_string = [% IF Koha.Preference('TimeFormat') == '12hr' %]"G:i K"[% ELSE %]"H:i"[% END %];
|
||||
var flatpickr_timestamp_string = "Y-m-d H:i";
|
||||
var flatpickr_datetime_string = flatpickr_dateformat_string + " " + flatpickr_timeformat_string;
|
||||
|
||||
function checkin(barcode, item, error) {
|
||||
var alerts = checkAlerts(barcode, item);
|
||||
if (typeof item === 'undefined') {
|
||||
item = { };
|
||||
}
|
||||
item.title = item.title || _("(Unknown)");
|
||||
item.author = item.author || _("(Unknown)");
|
||||
item.homebranch = item.homebranch || "";
|
||||
item.holdingbranch = item.holdingbranch || "";
|
||||
item.callnumber = item.callnumber || "";
|
||||
item.itemtype = item.itemtype || "";
|
||||
item.barcode = item.barcode || barcode;
|
||||
var trans = { "timestamp" : new Date().toMySQLString(),
|
||||
"barcode" : barcode,
|
||||
"action" : "return"
|
||||
};
|
||||
$('#alerts').empty();
|
||||
$('.offline-home').hide();
|
||||
$('.offline-sync').hide();
|
||||
$('.offline-circulation').hide();
|
||||
$('.offline-circulation-instructions').hide();
|
||||
$('.offline-returns').show();
|
||||
kohadb.recordTransaction(trans, function () {
|
||||
$('#session-returned').show();
|
||||
$('#already-checked-in tbody').prepend('<tr><td>' + item.title + '</td><td>' + item.author + '</td><td>' + barcode + '</td><td>' + item.homebranch + '</td><td>' + item.holdingbranch + '</td><td></td><td>' + item.callnumber + '</td><td>' + item.itemtype + '</td></tr>');
|
||||
if (alerts.length > 0) {
|
||||
$('#alerts').append('<div class="dialog alert"><h3>' + _("Check in message") + '</h3></div>');
|
||||
for (var msg in alerts) {
|
||||
$('#alerts .dialog').append('<p>' + alerts[msg] + '</p');
|
||||
}
|
||||
} else {
|
||||
$('#alerts').append('<div class="dialog"><h3>' + ALERT_SUCCESSFUL_CHECKIN + '</h3></div>');
|
||||
}
|
||||
});
|
||||
setTimeout(function() { $('#checkin-barcode').trigger('focus'), 1 });
|
||||
}
|
||||
|
||||
function checkAlerts(barcode, item) {
|
||||
var alerts = [];
|
||||
if (typeof item === 'undefined') {
|
||||
alerts.push(ALERT_NO_MATCHING_ITEM.format(barcode));
|
||||
} else {
|
||||
if (typeof item.materials !== 'undefined' && item.materials != null) {
|
||||
alerts.push(ALERT_MATERIALS.format(item.materials));
|
||||
}
|
||||
}
|
||||
return alerts;
|
||||
}
|
||||
|
||||
function showSyncInfo() {
|
||||
kohadb.loadSetting("item-timestamp", showTimestamp);
|
||||
kohadb.loadSetting("patron-timestamp", showTimestamp);
|
||||
kohadb.loadSetting("issue-timestamp", showTimestamp);
|
||||
kohadb.loadSetting("dirty", function (key, val) {
|
||||
if (val) {
|
||||
$('#upload-message').text(UPLOAD_PENDING_MESSAGE);
|
||||
} else {
|
||||
$('#upload-message').text(NO_UPLOAD_PENDING_MESSAGE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function synchronize() {
|
||||
kohadb.saveSetting("userid", "[% logged_in_user.userid | html %]");
|
||||
kohadb.saveSetting("branchcode", "[% Branches.GetLoggedInBranchcode | html %]");
|
||||
showSyncInfo();
|
||||
[% UNLESS (AllowOfflineCirculation) %]
|
||||
reloadRecords();
|
||||
[% END %]
|
||||
showSyncInfo();
|
||||
$('#download-records').click(reloadRecords);
|
||||
$('#upload-transactions').click(function () {
|
||||
$('.loading-overlay div').text(_("Uploading transactions, please wait..."));
|
||||
$('.loading-overlay').show();
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: "/cgi-bin/koha/offline_circ/service.pl",
|
||||
}).done(function (data) {
|
||||
if (data) {
|
||||
$('.loading-overlay').hide();
|
||||
alert(_("Please log in to Koha and try again. (Error: '%s')").format(data));
|
||||
} else {
|
||||
var uploadIter = $.indexedDB("koha").objectStore("transactions").each(uploadTransaction);
|
||||
uploadIter.done(function() {
|
||||
$.indexedDB("koha").transaction(["transactions"]).then(function(){
|
||||
}, function(err, e){
|
||||
}, function(transaction){
|
||||
transaction.objectStore("transactions").clear();
|
||||
});
|
||||
$('.loading-overlay').hide();
|
||||
kohadb.saveSetting("dirty", false);
|
||||
$('#upload-message').text(NO_UPLOAD_PENDING_MESSAGE);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function fPformatTimeStamp( timestamp ){
|
||||
var datetimeObj = flatpickr.parseDate( timestamp, flatpickr_timestamp_string );
|
||||
return flatpickr.formatDate( datetimeObj, flatpickr_datetime_string );
|
||||
}
|
||||
|
||||
function showTimestamp(key, value) {
|
||||
if (typeof value !== 'undefined') {
|
||||
var ts = new Date(value);
|
||||
$('#' + key).text( fPformatTimeStamp( ts ) + ' ' + ts.toTimeString());
|
||||
} else {
|
||||
$('#' + key).text(_("(never)"));
|
||||
}
|
||||
}
|
||||
|
||||
function reloadRecords(ev) {
|
||||
$(".loading-overlay div").text(_("Loading records, please wait..."));
|
||||
$(".loading-overlay").show();
|
||||
start = new Date();
|
||||
$.indexedDB("koha").transaction(["patrons", "items", "issues"]).then(function(){
|
||||
loadRecords(0);
|
||||
}, function(err, e){
|
||||
}, function(transaction){
|
||||
transaction.objectStore("patrons").clear();
|
||||
transaction.objectStore("items").clear();
|
||||
transaction.objectStore("issues").clear();
|
||||
});
|
||||
if (typeof ev !== 'undefined') {
|
||||
ev.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
function uploadTransaction(transaction) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/cgi-bin/koha/offline_circ/service.pl",
|
||||
data: { "userid" : kohadb.settings.userid,
|
||||
"branchcode" : kohadb.settings.branchcode,
|
||||
"timestamp" : transaction.value.timestamp,
|
||||
"action" : transaction.value.action,
|
||||
"barcode" : transaction.value.barcode,
|
||||
"cardnumber" : transaction.value.cardnumber,
|
||||
"amount" : transaction.value.amount,
|
||||
"pending" : true,
|
||||
},
|
||||
});
|
||||
return undefined, true;
|
||||
}
|
||||
|
||||
function finishedLoading() {
|
||||
kohadb.saveSetting('item-timestamp', start.toISOString())
|
||||
kohadb.saveSetting('patron-timestamp', start.toISOString())
|
||||
kohadb.saveSetting('issue-timestamp', start.toISOString())
|
||||
showTimestamp('item-timestamp', start.toISOString());
|
||||
showTimestamp('patron-timestamp', start.toISOString());
|
||||
showTimestamp('issue-timestamp', start.toISOString());
|
||||
$(".loading-overlay").hide();
|
||||
}
|
||||
|
||||
function loadRecords(page) {
|
||||
[% IF (AllowOfflineCirculation) %]
|
||||
$(".loading-overlay div").text(_("Loading page %s, please wait...").format(page));
|
||||
$(".loading-overlay").show();
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: "/cgi-bin/koha/offline_circ/download.pl",
|
||||
data: { "data": "all",
|
||||
"page": page
|
||||
},
|
||||
dataType: "json",
|
||||
}).done(function (data) {
|
||||
$.indexedDB("koha").transaction(["patrons", "items", "issues"]).then(function(){
|
||||
if (data.finished) {
|
||||
finishedLoading();
|
||||
} else {
|
||||
setTimeout(function () { loadRecords(page + 1); }, 200);
|
||||
}
|
||||
}, function(err, e){
|
||||
}, function(transaction){
|
||||
if (data.patrons) {
|
||||
var patrons = transaction.objectStore("patrons");
|
||||
$.each(data.patrons, function () {
|
||||
patrons.put(this);
|
||||
});
|
||||
}
|
||||
if (data.items) {
|
||||
var items = transaction.objectStore("items");
|
||||
$.each(data.items, function () {
|
||||
items.put(this);
|
||||
});
|
||||
}
|
||||
if (data.issues) {
|
||||
var issues = transaction.objectStore("issues");
|
||||
$.each(data.issues, function () {
|
||||
issues.put(this);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
[% END %]
|
||||
}
|
||||
|
||||
function loadPatron(barcode) {
|
||||
$('#oldissues').hide();
|
||||
$('#session-issues').hide();
|
||||
$('#issuest tbody').empty();
|
||||
$('#session-payments').hide();
|
||||
$('.checkout-count').text(0);
|
||||
$.indexedDB("koha").transaction(["patrons", "issues"]).then(function() {
|
||||
}, function(err, e){
|
||||
}, function(transaction){
|
||||
var patrons = transaction.objectStore("patrons");
|
||||
patrons.get(barcode).done(function (patron, error) {
|
||||
showPatron(barcode, patron, error);
|
||||
});
|
||||
var issuesidx = transaction.objectStore("issues").index("cardnumber");
|
||||
$('#oldissuest tbody').empty();
|
||||
issuesidx.each(function (item) {
|
||||
$('#oldissues').show();
|
||||
$('#oldissuest tbody').append("<tr><td>" + fPformatTimeStamp( item.value.date_due ) + "</td><td>" + item.value.title + "</td><td>" + item.value.barcode + "</td><td>" + item.value.itype + "</td><td>" + fPformatTimeStamp( item.value.issuedate ) + "</td><td>" + item.value.issuebranch + "</td><td>" + item.value.callnumber + "</td><td>" + "" + "</td></tr>");
|
||||
$('.checkout-count').text(parseInt($('.checkout-count').text()) + 1);
|
||||
}, barcode);
|
||||
});
|
||||
}
|
||||
|
||||
function checkout(barcode, item, error) {
|
||||
var alerts = checkAlerts(barcode, item);
|
||||
if (typeof item === 'undefined') {
|
||||
item = { };
|
||||
}
|
||||
item.title = item.title || "";
|
||||
item.author = item.author || "";
|
||||
item.homebranch = item.homebranch || "";
|
||||
item.holdingbranch = item.holdingbranch || "";
|
||||
item.callnumber = item.callnumber || "";
|
||||
item.itemtype = item.itemtype || "";
|
||||
if ($('#duedatespec').val().length === 0) {
|
||||
alert(_("You must set a due date in order to use offline circulation!"));
|
||||
setTimeout(function() { $('#duedatespec').trigger('focus'), 1 });
|
||||
return;
|
||||
}
|
||||
var date_due = flatpickr.parseDate( $('#duedatespec').val(), flatpickr_datetime_string );
|
||||
var trans = { "timestamp" : new Date().toMySQLString(),
|
||||
"barcode" : barcode,
|
||||
"cardnumber" : curpatron.cardnumber,
|
||||
"date_due" : date_due.toMySQLString(),
|
||||
"action" : "issue"
|
||||
};
|
||||
$('#alerts').empty();
|
||||
kohadb.recordTransaction(trans, function () {
|
||||
$('#session-issues').show();
|
||||
$('#issuest tbody').prepend('<tr><td>' + flatpickr.formatDate( date_due, flatpickr_datetime_string ) + '</td><td>' + item.title + '</td><td>' + barcode + '</td><td>' + item.itemtype + '</td><td>' + flatpickr.formatDate( new Date(), flatpickr_datetime_string ) + '</td><td>' + kohadb.settings.branchcode + '</td><td>' + item.callnumber + '</td><td></td></tr>');
|
||||
$('.checkout-count').text(parseInt($('.checkout-count').text()) + 1);
|
||||
if (alerts.length > 0) {
|
||||
$('#alerts').append('<div class="dialog alert"><h3>' + _("Check out message") + '</h3></div>');
|
||||
for (var msg in alerts) {
|
||||
$('#alerts .dialog').append('<p>' + alerts[msg] + '</p');
|
||||
}
|
||||
}
|
||||
$('#checkout-barcode').val('');
|
||||
});
|
||||
}
|
||||
|
||||
function recordFine(amount) {
|
||||
var timestamp = new Date()
|
||||
var trans = { "timestamp" : timestamp.toMySQLString(),
|
||||
"cardnumber" : curpatron.cardnumber,
|
||||
"amount" : amount,
|
||||
"action" : "payment",
|
||||
};
|
||||
kohadb.recordTransaction(trans, function () {
|
||||
$('#session-payments').show();
|
||||
$('#session-payments tbody').prepend('<tr><td>' + amount + '</td><td>' + fPformatTimeStamp( timestamp ) + '</td></tr>');
|
||||
$('.fine-amount').text(parseInt($('.fine-amount').text()) - amount);
|
||||
});
|
||||
}
|
||||
|
||||
function checkPatronAlerts(cardnumber, patron) {
|
||||
var alerts = [];
|
||||
if (typeof patron === 'undefined') {
|
||||
alerts.push(ALERT_NO_MATCHING_PATRON.format(cardnumber));
|
||||
} else {
|
||||
if (patron.gonenoaddress !== '0') {
|
||||
alerts.push(ALERT_PATRON_GONE_NO_ADDRESS);
|
||||
}
|
||||
if (patron.lost !== '0') {
|
||||
alerts.push(ALERT_PATRON_CARD_LOST);
|
||||
}
|
||||
if (patron.debarred !== null) {
|
||||
if (patron.debarred != '9999-12-31') {
|
||||
alerts.push( ALERT_PATRON_BLOCKED_TEMPORARY.format( flatpickr.formatDate( new Date(patron.debarred), flatpickr_datetime_string ) ) );
|
||||
} else {
|
||||
alerts.push(ALERT_PATRON_RESTRICTED);
|
||||
}
|
||||
}
|
||||
if (new Date(patron.dateexpiry) < new Date()) {
|
||||
alerts.push( ALERT_PATRON_EXPIRED.format( flatpickr.formatDate( new Date(patron.dateexpiry), flatpickr_datetime_string ) ) );
|
||||
}
|
||||
if (parseInt(patron.fine) > [% maxoutstanding | html %]) {
|
||||
alerts.push(ALERT_PATRON_FINE_OVER_LIMIT.format(patron.fine));
|
||||
} else if (parseInt(patron.fine) > 0) {
|
||||
alerts.push(ALERT_PATRON_FINE.format(patron.fine));
|
||||
}
|
||||
}
|
||||
return alerts;
|
||||
}
|
||||
|
||||
var curpatron;
|
||||
|
||||
function showPatron(barcode, patron, error) {
|
||||
var alerts = checkPatronAlerts(barcode, patron);
|
||||
if (typeof patron === 'undefined') {
|
||||
patron = { };
|
||||
}
|
||||
patron.surname = patron.surname || "";
|
||||
patron.firstname = patron.firstname || "";
|
||||
patron.othernames = patron.othernames || "";
|
||||
patron.address = patron.address || "";
|
||||
patron.address2 = patron.address2 || "";
|
||||
patron.city = patron.city || "";
|
||||
patron.state = patron.state || "";
|
||||
patron.country = patron.country || "";
|
||||
patron.zipcode = patron.zipcode || "";
|
||||
patron.phone = patron.phone || "";
|
||||
patron.mobile = patron.mobile || "";
|
||||
patron.phonepro = patron.phonepro || "";
|
||||
patron.email = patron.email || "";
|
||||
patron.emailpro = patron.emailpro || "";
|
||||
patron.categorycode = patron.categorycode || "";
|
||||
patron.branchcode = patron.branchcode || "";
|
||||
patron.cardnumber = barcode;
|
||||
patron.fine = patron.fine || "0";
|
||||
|
||||
patron.name = patron.firstname + (patron.othernames.length > 0 ? " (" + patron.othernames + ") " : " ") + patron.surname + " (" + barcode + ")";
|
||||
if (patron.name.length > 0) {
|
||||
$('.patron-title').text(patron.name);
|
||||
} else {
|
||||
$('.patron-title').text(_("Unrecognized patron (%s)").format(barcode));
|
||||
}
|
||||
if (patron.address.length > 0 || patron.address2.length > 0) {
|
||||
$('#patron-address-1').text(patron.address);
|
||||
$('#patron-address-2').text(patron.address2);
|
||||
} else {
|
||||
$('#patron-address-1').html('<span class="empty" id="noaddressstored">' + _("No address stored.") + '</span></li>');
|
||||
$('#patron-address-2').text('');
|
||||
}
|
||||
if (patron.city.length > 0) {
|
||||
$('#patron-address-parts').text(patron.city + (patron.state.length > 0 ? ", " + patron.state : "") + " " + patron.zipcode + (patron.country.length > 0 ? ", " + patron.country : ""));
|
||||
} else {
|
||||
$('#patron-address-parts').html('<span class="empty" id="nocitystored">' + _("No city stored.") + '</span></li>');
|
||||
}
|
||||
if (patron.phone.length > 0 || patron.mobile.length > 0 || patron.phonepro.length > 0) {
|
||||
$('#patron-phone').text((patron.phone.length > 0 ? patron.phone : (patron.mobile.length > 0 ? patron.mobile : (patron.phonepro.length > 0 ? patron.phonepro : ''))));
|
||||
} else {
|
||||
$('#patron-phone').html('<span class="empty" id="nophonestored">' + _("No phone stored.") + '</span></li>');
|
||||
}
|
||||
if (patron.email.length > 0 || patron.emailpro.length > 0) {
|
||||
$('#patron-email').text((patron.email.length > 0 ? patron.email : (patron.emailpro.length > 0 ? patron.emailpro : "")));
|
||||
} else {
|
||||
$('#patron-email').html('<span class="empty" id="noemailstored">' + _("No email stored.") + '</span></li>');
|
||||
}
|
||||
if (patron.categorycode.length > 0) {
|
||||
$('#patron-category').text(_("Category: %s").format(patron.categorycode));
|
||||
} else {
|
||||
$('#patron-category').html('<span class="empty" id="unknowncategory">' + _("Category code unknown.") + '</span></li>');
|
||||
}
|
||||
if (patron.branchcode.length > 0) {
|
||||
$('#patron-library').text(_("Home library: %s").format(patron.branchcode));
|
||||
} else {
|
||||
$('#patron-library').html('<span class="empty" id="unknowncategory">' + _("Home library unknown.") + '</span></li>');
|
||||
}
|
||||
$('.fine-amount').text(patron.fine);
|
||||
$('#alerts').empty();
|
||||
if (alerts.length > 0) {
|
||||
$('#alerts').append('<div class="dialog alert"><h3>' + _("Check out message") + '</h3></div>');
|
||||
for (var msg in alerts) {
|
||||
$('#alerts .dialog').append('<p>' + alerts[msg] + '</p>');
|
||||
}
|
||||
}
|
||||
curpatron = patron;
|
||||
$('main').show();
|
||||
setTimeout(function() { $('#checkout-barcode').trigger('focus'), 1 });
|
||||
}
|
||||
|
||||
// This next bit of code is to deal with the updated session issue
|
||||
if( typeof window.applicationCache !== "undefined" ){
|
||||
window.addEventListener('load', function(e) {
|
||||
window.applicationCache.addEventListener('updateready', function(e) {
|
||||
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
|
||||
// Browser downloaded a new app cache.
|
||||
// Swap it in and reload the page to get the new hotness.
|
||||
window.applicationCache.swapCache();
|
||||
if (confirm(_("A new version of this site is available. Load it?"))) {
|
||||
window.location.reload();
|
||||
}
|
||||
} else {
|
||||
// Manifest didn't changed. Nothing new to server.
|
||||
}
|
||||
}, false);
|
||||
}, false);
|
||||
}
|
||||
|
||||
|
||||
$(document).ready(function () {
|
||||
if( typeof window.applicationCache === "undefined" ){
|
||||
$("#offline-home div").html('<div class="dialog alert"><h3>' + _("Offline circulation disabled") + '</h3><p>' + _("Your browser is not compatible with the built-in offline circulation tool.") + '</div>');
|
||||
} else {
|
||||
kohadb.initialize();
|
||||
}
|
||||
$('#header_search #circ_search .tip').text(_("Enter patron card number:"));
|
||||
|
||||
$('ul[aria-labelledby="logged-in-menu"]').html('<li><a class="toplinks">' + _("You cannot change your branch or logout while using offline circulation") + '</a></li>');
|
||||
|
||||
// Returns code
|
||||
$('#checkin-form, #checkin_search form').submit(function (event) {
|
||||
event.preventDefault();
|
||||
var barcode = $('input[name="barcode"]', this).val();
|
||||
$('input[name="barcode"]', this).val('');
|
||||
$.indexedDB("koha").transaction(["items"]).then(function() {
|
||||
}, function(err, e){
|
||||
}, function(transaction){
|
||||
var items = transaction.objectStore("items");
|
||||
items.get(barcode).done(function (item, error) {
|
||||
checkin(barcode, item, error);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$('#go-to-home').click(function () {
|
||||
$('#alerts').empty();
|
||||
$('.offline-sync').hide();
|
||||
$('.offline-circulation').hide();
|
||||
$('.offline-returns').hide();
|
||||
$('.offline-circulation-instructions').hide();
|
||||
$('.offline-home').show();
|
||||
});
|
||||
|
||||
$('#go-to-returns').click(function () {
|
||||
$('#alerts').empty();
|
||||
$('.offline-home').hide();
|
||||
$('.offline-sync').hide();
|
||||
$('.offline-circulation').hide();
|
||||
$('.offline-circulation-instructions').hide();
|
||||
$('.offline-returns').show();
|
||||
setTimeout(function() { $('#checkin-form input[name="barcode"]').trigger('focus'), 1 });
|
||||
});
|
||||
|
||||
$('#go-to-circ').click(function () {
|
||||
$('#alerts').empty();
|
||||
$('.offline-home').hide();
|
||||
$('.offline-sync').hide();
|
||||
$('.offline-returns').hide();
|
||||
$('.offline-circulation').hide();
|
||||
$('.offline-circulation-instructions').show();
|
||||
$('#header_search').selectTabByID("#circ_search");
|
||||
setTimeout(function() { $('#circ_search input[name="findborrower"]').trigger('focus'), 1 });
|
||||
});
|
||||
|
||||
$('#go-to-sync').click(function () {
|
||||
$('#alerts').empty();
|
||||
showSyncInfo();
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: "/cgi-bin/koha/offline_circ/list.pl",
|
||||
success: function () {
|
||||
$('.offline-home').hide();
|
||||
$('.offline-returns').hide();
|
||||
$('.offline-circulation').hide();
|
||||
$('.offline-circulation-instructions').hide();
|
||||
$('.offline-sync').show();
|
||||
synchronize();
|
||||
},
|
||||
error: function () {
|
||||
alert(_("You are offline and therefore cannot sync your database"));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#go-to-pending').click(function (ev) {
|
||||
$('#alerts').empty();
|
||||
ev.preventDefault();
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: "/cgi-bin/koha/offline_circ/list.pl",
|
||||
success: function () {
|
||||
window.location = '/cgi-bin/koha/offline_circ/list.pl';
|
||||
},
|
||||
error: function () {
|
||||
alert(_("You are offline and therefore cannot process pending operations"));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#patronsearch').submit(function (event) {
|
||||
event.preventDefault();
|
||||
loadPatron($('#findborrower').val());
|
||||
$('.offline-home').hide();
|
||||
$('.offline-returns').hide();
|
||||
$('.offline-sync').hide();
|
||||
$('.offline-circulation-instructions').hide();
|
||||
$('.offline-circulation').show();
|
||||
$('#findborrower').val('');
|
||||
setTimeout(function() { $('#checkout-barcode').trigger('focus'), 1 });
|
||||
});
|
||||
|
||||
$('#pay-fine').click(function (event) {
|
||||
event.preventDefault();
|
||||
recordFine($('#pay-fine-amount').val());
|
||||
});
|
||||
|
||||
$('#mainform').submit(function (event) {
|
||||
event.preventDefault();
|
||||
var barcode = $('#checkout-barcode').val();
|
||||
$.indexedDB("koha").transaction(["items"]).then(function() {
|
||||
}, function(err, e){
|
||||
}, function(transaction){
|
||||
var items = transaction.objectStore("items");
|
||||
items.get(barcode).done(function (item, error) {
|
||||
checkout(barcode, item, error);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
[% END %]
|
||||
|
||||
[% INCLUDE 'intranet-bottom.inc' %]
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
/* Copyright 2013 C & P Bibliography Services
|
||||
*
|
||||
* This file is part of Koha.
|
||||
*
|
||||
* Koha is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Koha is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Koha; if not, see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
(function( kohadb, $, undefined ) {
|
||||
kohadb.settings = kohadb.settings || {};
|
||||
kohadb.initialize = function (callback) {
|
||||
$.indexedDB("koha", {
|
||||
"version": 1,
|
||||
"schema": {
|
||||
"1": function(versionTransaction){
|
||||
var patrons = versionTransaction.createObjectStore("patrons", {
|
||||
"keyPath": "cardnumber"
|
||||
});
|
||||
var items = versionTransaction.createObjectStore("items", {
|
||||
"keyPath": "barcode"
|
||||
});
|
||||
var issues = versionTransaction.createObjectStore("issues", {
|
||||
"keyPath": "barcode"
|
||||
});
|
||||
issues.createIndex("cardnumber", { "multiEntry": true });
|
||||
var transactions = versionTransaction.createObjectStore("transactions", {
|
||||
"keyPath": "timestamp"
|
||||
});
|
||||
var settings = versionTransaction.createObjectStore("offline_settings", {
|
||||
"keyPath": "key"
|
||||
});
|
||||
},
|
||||
}
|
||||
}).done(function(){
|
||||
if (typeof callback === 'function') {
|
||||
callback();
|
||||
kohadb.loadSetting('userid');
|
||||
kohadb.loadSetting('branchcode');
|
||||
}
|
||||
});
|
||||
};
|
||||
kohadb.loadSetting = function (key, callback) {
|
||||
$.indexedDB("koha").transaction(["offline_settings"]).then(function(){
|
||||
}, function(err, e){
|
||||
if (typeof callback === 'function') {
|
||||
callback(key, undefined);
|
||||
}
|
||||
}, function(transaction){
|
||||
var settings = transaction.objectStore("offline_settings");
|
||||
settings.get(key).done(function (item, error) {
|
||||
if (typeof item !== 'undefined') {
|
||||
kohadb.settings[key] = item.value;
|
||||
}
|
||||
if (typeof callback === 'function') {
|
||||
callback(key, kohadb.settings[key]);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
kohadb.saveSetting = function (key, value) {
|
||||
$.indexedDB("koha").transaction(["offline_settings"]).then(function(){
|
||||
}, function(err, e){
|
||||
}, function(transaction){
|
||||
var settings = transaction.objectStore("offline_settings");
|
||||
settings.put({ "key" : key, "value" : value });
|
||||
kohadb.settings[key] = value;
|
||||
});
|
||||
};
|
||||
kohadb.recordTransaction = function (newtrans, callback) {
|
||||
$.indexedDB("koha").transaction(["transactions"]).then(function(){
|
||||
callback(newtrans);
|
||||
}, function(err, e){
|
||||
}, function(dbtransaction) {
|
||||
var transactions = dbtransaction.objectStore("transactions");
|
||||
transactions.put(newtrans);
|
||||
kohadb.saveSetting('dirty', true);
|
||||
});
|
||||
};
|
||||
}( window.kohadb = window.kohadb || {}, jQuery ));
|
||||
|
||||
if ( !Date.prototype.toMySQLString ) {
|
||||
( function() {
|
||||
|
||||
function pad(number) {
|
||||
var r = String(number);
|
||||
if ( r.length === 1 ) {
|
||||
r = '0' + r;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
Date.prototype.toMySQLString = function() {
|
||||
return this.getFullYear()
|
||||
+ '-' + pad( this.getMonth() + 1 )
|
||||
+ '-' + pad( this.getDate() )
|
||||
+ ' ' + pad( this.getHours() )
|
||||
+ ':' + pad( this.getMinutes() )
|
||||
+ ':' + pad( this.getSeconds() )
|
||||
+ '.' + String( (this.getMilliseconds()/1000).toFixed(3) ).slice( 2, 5 );
|
||||
};
|
||||
|
||||
}() );
|
||||
}
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# Copyright 2013 C & P Bibliography Services
|
||||
#
|
||||
# This file is part of Koha.
|
||||
#
|
||||
# Koha is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Koha is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Koha; if not, see <http://www.gnu.org/licenses>.
|
||||
|
||||
use Modern::Perl;
|
||||
use CGI qw ( -utf8 );
|
||||
use JSON qw( to_json );
|
||||
use C4::Auth qw( checkauth );
|
||||
use C4::Output;
|
||||
use C4::Context;
|
||||
use C4::Koha;
|
||||
|
||||
my $query = CGI->new;
|
||||
checkauth( $query, undef, { circulate => "circulate_remaining_permissions" },
|
||||
"intranet" );
|
||||
|
||||
my $page = $query->param('page') || 0;
|
||||
my $startrec = int($page) * 5000;
|
||||
my $req_data = $query->param('data') || '';
|
||||
|
||||
my $patrons_query = q{SELECT
|
||||
borrowers.borrowernumber, cardnumber, surname, firstname, title,
|
||||
othernames, initials, streetnumber, streettype, address, address2, city,
|
||||
state, zipcode, country, email, phone, mobile, fax, dateofbirth, borrowers.branchcode,
|
||||
categorycode, dateenrolled, dateexpiry, COALESCE(gonenoaddress, 0) AS gonenoaddress,
|
||||
COALESCE(lost, 0) AS lost, debarred,
|
||||
debarredcomment, SUM(accountlines.amountoutstanding) AS fine
|
||||
FROM borrowers
|
||||
LEFT JOIN accountlines ON borrowers.borrowernumber=accountlines.borrowernumber
|
||||
WHERE cardnumber IS NOT NULL
|
||||
GROUP BY borrowers.borrowernumber
|
||||
LIMIT ?, 5000;
|
||||
};
|
||||
|
||||
# NOTE: we can't fit very long titles on the interface so there isn't really any point in transferring them
|
||||
my $items_query = q{SELECT
|
||||
items.barcode AS barcode, items.itemnumber AS itemnumber,
|
||||
items.itemcallnumber AS callnumber, items.homebranch AS homebranch,
|
||||
items.holdingbranch AS holdingbranch, items.itype AS itemtype,
|
||||
items.materials AS materials, LEFT(biblio.title, 60) AS title,
|
||||
biblio.author AS author, biblio.biblionumber AS biblionumber
|
||||
FROM items
|
||||
JOIN biblio ON biblio.biblionumber = items.biblionumber
|
||||
WHERE barcode IS NOT NULL
|
||||
LIMIT ?, 5000;
|
||||
};
|
||||
|
||||
my $issues_query = q{SELECT
|
||||
biblio.title AS title,
|
||||
items.barcode AS barcode,
|
||||
items.itemcallnumber AS callnumber,
|
||||
issues.date_due AS date_due,
|
||||
issues.issuedate AS issuedate,
|
||||
issues.renewals_count AS renewals,
|
||||
issues.unseen_renewals AS unseen_renewals,
|
||||
borrowers.cardnumber AS cardnumber,
|
||||
CONCAT(borrowers.surname, ', ', borrowers.firstname) AS borrower_name
|
||||
FROM issues
|
||||
JOIN items ON items.itemnumber = issues.itemnumber
|
||||
JOIN biblio ON biblio.biblionumber = items.biblionumber
|
||||
JOIN borrowers ON borrowers.borrowernumber = issues.borrowernumber
|
||||
WHERE barcode IS NOT NULL
|
||||
LIMIT ?, 5000;
|
||||
};
|
||||
|
||||
my %results;
|
||||
my $finished = 1;
|
||||
if ( $req_data eq 'patrons' || $req_data eq 'all' ) {
|
||||
$results{'patrons'} = get_data( $patrons_query, 'cardnumber', $startrec );
|
||||
}
|
||||
if ( $req_data eq 'items' || $req_data eq 'all' ) {
|
||||
$results{'items'} = get_data( $items_query, 'barcode', $startrec );
|
||||
}
|
||||
if ( $req_data eq 'issues' || $req_data eq 'all' ) {
|
||||
$results{'issues'} = get_data( $issues_query, 'barcode', $startrec );
|
||||
}
|
||||
|
||||
foreach my $key ( keys %results ) {
|
||||
$finished = 0 if keys %{ $results{$key} } == 5000;
|
||||
}
|
||||
$results{'finished'} = $finished;
|
||||
|
||||
print $query->header( -type => 'application/json', -charset => 'utf-8' );
|
||||
print to_json( \%results );
|
||||
|
||||
sub get_data {
|
||||
my ( $sql, $key, $start ) = @_;
|
||||
$start ||= 0;
|
||||
my $dbh = C4::Context->dbh;
|
||||
my $sth = $dbh->prepare($sql);
|
||||
$sth->execute($start);
|
||||
return $sth->fetchall_hashref($key);
|
||||
}
|
||||
Loading…
Reference in New Issue