return $data;
}
+__PACKAGE__->register_method(
+ method => "circ_history_count",
+ api_name => "open-ils.circ.circ_history.count",
+ notes => q/
+ Returns the number of archived circulations for a user
+ @param auth the auth token of the requestor
+ @param user_id the user to check
+ /);
+
+sub circ_history_count {
+ my( $self, $client, $auth, $user_id ) = @_;
+
+ my $e = new_editor( authtoken => $auth );
+ return $e->event unless $e->checkauth;
+
+ my $user_id = (defined $user_id) ? $user_id : $e->requestor->id;
+
+ if( $e->requestor->id ne $user_id ) {
+ return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
+ }
+
+ my $count = $e->json_query({
+ select => {
+ auch => [{
+ column => 'id',
+ transform => 'count',
+ aggregate => 1
+ }]
+ },
+ from => 'auch',
+ where => {'+auch' => {usr => $user_id}}
+ })->[0]->{id};
+
+ return $count;
+}
+
+__PACKAGE__->register_method(
+ method => "circ_history_by_user",
+ api_name => "open-ils.circ.actor.user.circ_history",
+ stream => 1,
+ NOTES => <<" NOTES");
+ Streams a list of circ history objects with the same
+ default flesh as MyOPAC's circ history page.
+ NOTES
+
+sub circ_history_by_user {
+ my ($self, $client, $auth, $user_id, $flesh, $limit, $offset) = @_;
+
+ my $e = new_editor( authtoken => $auth );
+ return $e->event unless $e->checkauth;
+
+ my $user_id = (defined $user_id) ? $user_id : $e->requestor->id;
+
+ if( $e->requestor->id ne $user_id ) {
+ return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
+ }
+
+ my %limits = ();
+ $limits{offset} = $offset if defined $offset;
+ $limits{limit} = $limit if defined $limit;
+
+ my %flesh_ops = (
+ flesh => 3,
+ flesh_fields => {
+ auch => ['target_copy','source_circ'],
+ acp => ['call_number','parts'],
+ acn => ['record','prefix','suffix']
+ },
+ );
+
+ $e->xact_begin;
+ my $circs = $e->search_action_user_circ_history(
+ [
+ {usr => $user_id},
+ { # order newest to oldest by default
+ order_by => {auch => 'xact_start DESC'},
+ $flesh ? %flesh_ops : (),
+ %limits
+ }
+ ],
+ {substream => 1}
+ );
+ $e->rollback;
+
+ unless($flesh){
+ for my $circ (@$circs) {
+ $client->respond(
+ {
+ circ => $circ
+ }
+ );
+ }
+ return undef;
+ }
+
+ $e->xact_begin;
+ my %unapi_cache = ();
+ for my $circ (@$circs) {
+ if ($circ->target_copy->call_number->id == -1) {
+ $client->respond(
+ {
+ circ => $circ,
+ marc_xml => undef # pre-cat copy, use the dummy title/author instead
+ }
+ );
+ next;
+ }
+ my $bre_id = $circ->target_copy->call_number->record->id;
+ my $unapi;
+ if (exists $unapi_cache{$bre_id}) {
+ $unapi = $unapi_cache{$bre_id};
+ } else {
+ my $result = $e->json_query({
+ from => [
+ 'unapi.bre', $bre_id, 'marcxml','record','{mra}', undef, undef, undef
+ ]
+ });
+ if ($result) {
+ $unapi_cache{$bre_id} = $unapi = $result->[0]->{'unapi.bre'};
+ }
+ }
+ if ($unapi) {
+ $client->respond(
+ {
+ circ => $circ,
+ marc_xml => $unapi
+ }
+ );
+ } else {
+ $client->respond(
+ {
+ circ => $circ,
+ marc_xml => undef # failed, but try to go on
+ }
+ );
+ }
+ }
+ $e->rollback;
+
+ return undef;
+}
__PACKAGE__->register_method(
method => "title_from_transaction",
--- /dev/null
+<script language='javascript' src='/opac/common/js/utils.js'> </script>
+<script language='javascript' src='/opac/common/js/config.js'> </script>
+
+<script language='javascript' src='/opac/common/js/JSON_v1.js'> </script>
+<script language='javascript'>
+var fmclasses = {
+ "auch": ["id","usr","target_copy","checkin_time","due_date","xact_start","source_circ"],
+ "acp": ["age_protect","alert_message","barcode","call_number"],
+ "acn": ["copies","create_date","creator","deleted","edit_date","editor","id","label","owning_lib","record","notes","uri_maps","uris","label_sortkey","label_class","prefix","suffix","dewey"],
+ "acnp": ["id","label","label_sortkey","owning_lib"],
+ "acns": ["id","label","label_sortkey","owning_lib"],
+};
+</script>
+<script language='javascript' src='/opac/common/js/fmgen.js'> </script>
+<script language='javascript' src='/opac/common/js/opac_utils.js'> </script>
+
+<script>
+ const auth = "[% CGI.cookie('ses') %]";
+ const progressBarWrapper = "#csv-download-bar-wrapper";
+ const progressBar = "#csv-download-bar";
+ const header = '"Title","Author","Checkout Date","Due Date","Date Returned","Barcode","Call Number","Format"';
+ //number of records to retrieve from the server at once
+ const maxRecords = 50;
+ //number of records processed locally
+ var processedRecords = 0;
+ //total number of AUCH records
+ var totalRecords = 0;
+ content = [];
+
+ function startCircHistoryDownload(){
+
+ new OpenSRF.ClientSession('open-ils.circ').request({
+ method: 'open-ils.circ.circ_history.count',
+ params: [auth],
+ oncomplete: circHistoryDownload,
+ onerror: function(e){console.log(e);}
+ }).send();
+ }
+
+ function circHistoryDownload(r){
+ resp = r.recv();
+ if(!resp)return;
+ totalRecords = resp.content();
+ console.log("Total records to process: " + totalRecords);
+ processedRecords = 0;
+ showProgressBar();
+ for(var i = 0; i < totalRecords; i += maxRecords){
+ new OpenSRF.ClientSession('open-ils.circ').request({
+ method: 'open-ils.circ.actor.user.circ_history',
+ params: [auth,null,true,maxRecords,i],
+ async: true,
+ onresponse: addRecord,
+ oncomplete: exportRecords,
+ onerror: function(e){console.log(e);}
+ }).send();
+ }
+ }
+
+ function addRecord(r){
+ var c = r.response_queue[r.response_queue.length-1].content();
+ var circ = c.circ;
+ var xml = c.marc_xml;
+ var title = titleFromXml(xml);
+ var author = authorFromXml(xml);
+ var format = formatFromXml(xml);
+ var callNumber = cnFromCirc(circ);
+ content.push(
+ [title,author,circ.xact_start(),circ.due_date(),circ.checkin_time(),circ.target_copy().barcode(),callNumber,format]
+ )
+ processedRecords += 1;
+ }
+
+ function showProgressBar(){
+ $(progressBarWrapper).removeClass("hidden");
+ }
+
+ function hideProgressBar(){
+ $(progressBarWrapper).addClass("hidden");
+ }
+
+ function updateProgressBar(){
+ var progress = Math.floor((processedRecords/totalRecords)*100.);
+ $(progressBar).attr('aria-valuenow', progress).css('width', progress+'%');
+ }
+
+ function exportRecords(){
+ updateProgressBar();
+ if(processedRecords < totalRecords){
+ return;
+ }
+ content.sort(function(a,b){return (new Date(a[2])) > (new Date(b[2]));})
+ var csv_content = "";
+ var csv_data = [];
+ csv_data.push(header);
+ content.forEach(function(c){
+ csv_data.push(
+ c.map(function(p){return '"'+p+'"';})
+ .join(",")
+ );
+ }
+ );
+ csv_content = csv_data.join("\r\n");
+ var blob = new Blob([csv_content], { type: 'text/csv;charset=utf-8;' });
+ if (navigator.msSaveBlob) { // IE 10+
+ navigator.msSaveBlob(blob, 'circ_history.csv');
+ } else {
+ var link = document.createElement("a");
+ if (link.download !== undefined) { // feature detection
+ // Browsers that support HTML5 download attribute
+ var url = URL.createObjectURL(blob);
+ link.setAttribute("href", url);
+ link.setAttribute("download", 'circ_history.csv');
+ link.style.visibility = 'hidden';
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ }
+ }
+ hideProgressBar();
+ }
+
+ function titleFromXml(marc_xml){
+ var titleParts = $.map($(marc_xml).find('[tag="245"]').find('[code="a"], [code="b"], [code="n"], [code="p"]'),function(p){return p.innerText;})
+ var titlePartsContent = titleParts.join(" ");
+ return (titlePartsContent || '').replace(/[:;\/]/ig, '').trim();
+ }
+
+ function authorFromXml(marc_xml){
+ var authorParts = $.map($(marc_xml).find('[tag="100"], [tag="110"], [tag="111"] ').find('[code="a"]'),function(p){return p.innerText;})
+ return (authorParts.join(" ") || '').trim();
+ }
+
+ function formatFromXml(marc_xml){
+ var formatParts = $.map($(marc_xml).find('field[name="search_format"],field[name="icon_format"],field[name="mr_hold_format"]'),function(p){return p.innerText;})
+ //only take first valid format we find
+ for(var i = 0; i < formatParts.length; i++){
+ if(formatParts[i] != "")return formatParts[i];
+ }
+ return "";
+ }
+
+ function cnFromCirc(circ){
+ return [circ.target_copy().call_number().prefix().label_sortkey(),circ.target_copy().call_number().label_sortkey(),circ.target_copy().call_number().suffix().label_sortkey()].join("");
+ }
+
+
+</script>
\ No newline at end of file