From: Bill Erickson Date: Wed, 23 Mar 2016 15:44:30 +0000 (-0400) Subject: LP#1497335 Aged circs display / API / WIP X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=b5dd4b0859484e52b2ad5dde695b9434d75bed8f;p=working%2FEvergreen.git LP#1497335 Aged circs display / API / WIP Signed-off-by: Bill Erickson --- diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml index 66e7d871da..d036b3d335 100644 --- a/Open-ILS/examples/fm_IDL.xml +++ b/Open-ILS/examples/fm_IDL.xml @@ -4144,6 +4144,10 @@ SELECT usr, + + + + @@ -4184,6 +4188,7 @@ SELECT usr, + @@ -4191,6 +4196,8 @@ SELECT usr, + + diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ.pm index 7b22f0ec03..946f712542 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ.pm @@ -1073,49 +1073,33 @@ sub copy_details { my $transit = $e->search_action_transit_copy( { target_copy => $copy_id, dest_recv_time => undef } )->[0]; - # find the latest circ, open or closed - my $circ = $e->search_action_all_circulation( - [ - { target_copy => $copy_id }, - { - flesh => 2, - flesh_fields => { - combcirc => [ - 'active_circ', - 'aged_circ' - ], - circ => [ - 'workstation', - 'checkin_workstation', - 'duration_rule', - 'max_fine_rule', - 'recurring_fine_rule' - ], - acirc => [ - 'workstation', - 'checkin_workstation', - 'duration_rule', - 'max_fine_rule', - 'recurring_fine_rule' - ] - }, - order_by => { circ => 'xact_start desc' }, - limit => 1 - } - ] - )->[0]; - - if ($circ) { - $circ = $circ->active_circ ? $circ->active_circ : $circ->aged_circ; - } + # find the most recent circulation for the requested copy, + # be it active, completed, or aged. + my $circ = $e->search_action_all_circulation([ + { target_copy => $copy_id }, + { + flesh => 1, + flesh_fields => { + combcirc => [ + 'workstation', + 'checkin_workstation', + 'duration_rule', + 'max_fine_rule', + 'recurring_fine_rule' + ], + }, + order_by => { circ => 'xact_start desc' }, + limit => 1 + } + ])->[0]; return { - copy => $copy, - hold => $hold, + copy => $copy, + hold => $hold, transit => $transit, - circ => $circ, + circ => $circ, volume => $vol, - mvr => $mvr, + mvr => $mvr }; } @@ -1857,51 +1841,51 @@ sub retrieve_prev_circ_chain { return $e->event unless $e->checkauth; return $e->event unless $e->allowed('VIEW_CIRCULATIONS'); - if($self->api_name =~ /summary/) { - my $first_circ = $e->json_query({from => ['action.circ_chain', $circ_id]})->[0]; - my $target_copy = $$first_circ{'target_copy'}; - my $usr = $$first_circ{'usr'}; - my $last_circ_from_prev_chain = $e->json_query({ - 'select' => { 'circ' => ['id','usr'] }, - 'from' => 'circ', - 'where' => { - target_copy => $target_copy, - xact_start => { '<' => $$first_circ{'xact_start'} } + my $first_circ = + $e->json_query({from => ['action.all_circ_chain', $circ_id]})->[0]; + + my $prev_circ = $e->search_action_all_circulation([ + { target_copy => $first_circ->{target_copy}, + xact_start => {'<' => $first_circ->{xact_start}} + }, { + flesh => 1, + flesh_fields => { + combcirc => [ + 'active_circ', + 'aged_circ' + ] }, - 'order_by' => [{ 'class'=>'circ', 'field'=>'xact_start', 'direction'=>'desc' }], - 'limit' => 1 - })->[0]; - return undef unless $last_circ_from_prev_chain; - return undef unless $$last_circ_from_prev_chain{'id'}; - my $sum = $e->json_query({from => ['action.summarize_circ_chain', $$last_circ_from_prev_chain{'id'}]})->[0]; - return undef unless $sum; - my $obj = Fieldmapper::action::circ_chain_summary->new; - $obj->$_($sum->{$_}) for keys %$sum; - return { 'summary' => $obj, 'usr' => $$last_circ_from_prev_chain{'usr'} }; + order_by => { circ => 'xact_start desc' }, + limit => 1 + } + ])->[0]; - } else { + return undef unless $prev_circ; - my $first_circ = $e->json_query({from => ['action.circ_chain', $circ_id]})->[0]; - my $target_copy = $$first_circ{'target_copy'}; - my $last_circ_from_prev_chain = $e->json_query({ - 'select' => { 'circ' => ['id'] }, - 'from' => 'circ', - 'where' => { - target_copy => $target_copy, - xact_start => { '<' => $$first_circ{'xact_start'} } - }, - 'order_by' => [{ 'class'=>'circ', 'field'=>'xact_start', 'direction'=>'desc' }], - 'limit' => 1 + my $chain_usr = $prev_circ->usr; # note: may be undef + + if ($self->api_name =~ /summary/) { + my $sum = $e->json_query({ + from => [ + 'action.summarize_all_circ_chain', + $prev_circ->id + ] })->[0]; - return undef unless $last_circ_from_prev_chain; - return undef unless $$last_circ_from_prev_chain{'id'}; - my $chain = $e->json_query({from => ['action.circ_chain', $$last_circ_from_prev_chain{'id'}]}); - for my $circ_info (@$chain) { - my $circ = Fieldmapper::action::circulation->new; - $circ->$_($circ_info->{$_}) for keys %$circ_info; - $conn->respond($circ); - } + my $summary = Fieldmapper::action::circ_chain_summary->new; + $summary->$_($sum->{$_}) for keys %$sum; + + return {summary => $summary, usr => $chain_usr}; + } + + + my $chain = $e->json_query( + {from => ['action.all_circ_chain', $prev_circ->id]}); + + for my $circ_info (@$chain) { + my $circ = Fieldmapper::action::all_circulation->new; + $circ->$_($circ_info->{$_}) for keys %$circ_info; + $conn->respond($circ); } return undef; diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.aged-circ-chains.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.aged-circ-chains.sql new file mode 100644 index 0000000000..c0e0981b81 --- /dev/null +++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.aged-circ-chains.sql @@ -0,0 +1,195 @@ + +BEGIN; + +-- SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version); + +DROP VIEW IF EXISTS action.all_circulation; +CREATE VIEW action.all_circulation AS + SELECT aged_circulation.id, aged_circulation.usr_post_code, + aged_circulation.usr_home_ou, aged_circulation.usr_profile, + aged_circulation.usr_birth_year, aged_circulation.copy_call_number, + aged_circulation.copy_location, aged_circulation.copy_owning_lib, + aged_circulation.copy_circ_lib, aged_circulation.copy_bib_record, + aged_circulation.xact_start, aged_circulation.xact_finish, + aged_circulation.target_copy, aged_circulation.circ_lib, + aged_circulation.circ_staff, aged_circulation.checkin_staff, + aged_circulation.checkin_lib, aged_circulation.renewal_remaining, + aged_circulation.grace_period, aged_circulation.due_date, + aged_circulation.stop_fines_time, aged_circulation.checkin_time, + aged_circulation.create_time, aged_circulation.duration, + aged_circulation.fine_interval, aged_circulation.recurring_fine, + aged_circulation.max_fine, aged_circulation.phone_renewal, + aged_circulation.desk_renewal, aged_circulation.opac_renewal, + aged_circulation.duration_rule, + aged_circulation.recurring_fine_rule, + aged_circulation.max_fine_rule, aged_circulation.stop_fines, + aged_circulation.workstation, aged_circulation.checkin_workstation, + aged_circulation.checkin_scan_time, aged_circulation.parent_circ, + NULL AS usr + FROM action.aged_circulation +UNION ALL + SELECT DISTINCT circ.id, + COALESCE(a.post_code, b.post_code) AS usr_post_code, + p.home_ou AS usr_home_ou, p.profile AS usr_profile, + date_part('year'::text, p.dob)::integer AS usr_birth_year, + cp.call_number AS copy_call_number, circ.copy_location, + cn.owning_lib AS copy_owning_lib, cp.circ_lib AS copy_circ_lib, + cn.record AS copy_bib_record, circ.xact_start, circ.xact_finish, + circ.target_copy, circ.circ_lib, circ.circ_staff, + circ.checkin_staff, circ.checkin_lib, circ.renewal_remaining, + circ.grace_period, circ.due_date, circ.stop_fines_time, + circ.checkin_time, circ.create_time, circ.duration, + circ.fine_interval, circ.recurring_fine, circ.max_fine, + circ.phone_renewal, circ.desk_renewal, circ.opac_renewal, + circ.duration_rule, circ.recurring_fine_rule, circ.max_fine_rule, + circ.stop_fines, circ.workstation, circ.checkin_workstation, + circ.checkin_scan_time, circ.parent_circ, circ.usr + FROM action.circulation circ + JOIN asset.copy cp ON circ.target_copy = cp.id +JOIN asset.call_number cn ON cp.call_number = cn.id +JOIN actor.usr p ON circ.usr = p.id +LEFT JOIN actor.usr_address a ON p.mailing_address = a.id +LEFT JOIN actor.usr_address b ON p.billing_address = b.id; + + +CREATE OR REPLACE FUNCTION action.all_circ_chain (ctx_circ_id INTEGER) + RETURNS SETOF action.all_circulation AS $$ +DECLARE + tmp_circ action.all_circulation%ROWTYPE; + circ_0 action.all_circulation%ROWTYPE; +BEGIN + + SELECT INTO tmp_circ * FROM action.all_circulation WHERE id = ctx_circ_id; + + IF tmp_circ IS NULL THEN + RETURN NEXT tmp_circ; + END IF; + circ_0 := tmp_circ; + + -- find the front of the chain + WHILE TRUE LOOP + SELECT INTO tmp_circ * FROM action.all_circulation + WHERE id = tmp_circ.parent_circ; + IF tmp_circ IS NULL THEN + EXIT; + END IF; + circ_0 := tmp_circ; + END LOOP; + + -- now send the circs to the caller, oldest to newest + tmp_circ := circ_0; + WHILE TRUE LOOP + IF tmp_circ IS NULL THEN + EXIT; + END IF; + RETURN NEXT tmp_circ; + SELECT INTO tmp_circ * FROM action.all_circulation + WHERE parent_circ = tmp_circ.id; + END LOOP; + +END; +$$ LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION action.summarize_all_circ_chain + (ctx_circ_id INTEGER) RETURNS action.circ_chain_summary AS $$ + +DECLARE + + -- first circ in the chain + circ_0 action.all_circulation%ROWTYPE; + + -- last circ in the chain + circ_n action.all_circulation%ROWTYPE; + + -- circ chain under construction + chain action.circ_chain_summary; + tmp_circ action.all_circulation%ROWTYPE; + +BEGIN + + chain.num_circs := 0; + FOR tmp_circ IN SELECT * FROM action.all_circ_chain(ctx_circ_id) LOOP + + IF chain.num_circs = 0 THEN + circ_0 := tmp_circ; + END IF; + + chain.num_circs := chain.num_circs + 1; + circ_n := tmp_circ; + END LOOP; + + chain.start_time := circ_0.xact_start; + chain.last_stop_fines := circ_n.stop_fines; + chain.last_stop_fines_time := circ_n.stop_fines_time; + chain.last_checkin_time := circ_n.checkin_time; + chain.last_checkin_scan_time := circ_n.checkin_scan_time; + SELECT INTO chain.checkout_workstation name FROM actor.workstation WHERE id = circ_0.workstation; + SELECT INTO chain.last_checkin_workstation name FROM actor.workstation WHERE id = circ_n.checkin_workstation; + + IF chain.num_circs > 1 THEN + chain.last_renewal_time := circ_n.xact_start; + SELECT INTO chain.last_renewal_workstation name FROM actor.workstation WHERE id = circ_n.workstation; + END IF; + + RETURN chain; + +END; +$$ LANGUAGE 'plpgsql'; + + +COMMIT; + + +/* REVERT + +DROP FUNCTION IF EXISTS action.summarize_all_circ_chain (INTEGER); +DROP FUNCTION IF EXISTS action.all_circ_chain (INTEGER); +DROP VIEW IF EXISTS action.all_circulation; +CREATE VIEW action.all_circulation AS + SELECT aged_circulation.id, aged_circulation.usr_post_code, + aged_circulation.usr_home_ou, aged_circulation.usr_profile, + aged_circulation.usr_birth_year, aged_circulation.copy_call_number, + aged_circulation.copy_location, aged_circulation.copy_owning_lib, + aged_circulation.copy_circ_lib, aged_circulation.copy_bib_record, + aged_circulation.xact_start, aged_circulation.xact_finish, + aged_circulation.target_copy, aged_circulation.circ_lib, + aged_circulation.circ_staff, aged_circulation.checkin_staff, + aged_circulation.checkin_lib, aged_circulation.renewal_remaining, + aged_circulation.grace_period, aged_circulation.due_date, + aged_circulation.stop_fines_time, aged_circulation.checkin_time, + aged_circulation.create_time, aged_circulation.duration, + aged_circulation.fine_interval, aged_circulation.recurring_fine, + aged_circulation.max_fine, aged_circulation.phone_renewal, + aged_circulation.desk_renewal, aged_circulation.opac_renewal, + aged_circulation.duration_rule, + aged_circulation.recurring_fine_rule, + aged_circulation.max_fine_rule, aged_circulation.stop_fines, + aged_circulation.workstation, aged_circulation.checkin_workstation, + aged_circulation.checkin_scan_time, aged_circulation.parent_circ + FROM action.aged_circulation +UNION ALL + SELECT DISTINCT circ.id, + COALESCE(a.post_code, b.post_code) AS usr_post_code, + p.home_ou AS usr_home_ou, p.profile AS usr_profile, + date_part('year'::text, p.dob)::integer AS usr_birth_year, + cp.call_number AS copy_call_number, circ.copy_location, + cn.owning_lib AS copy_owning_lib, cp.circ_lib AS copy_circ_lib, + cn.record AS copy_bib_record, circ.xact_start, circ.xact_finish, + circ.target_copy, circ.circ_lib, circ.circ_staff, + circ.checkin_staff, circ.checkin_lib, circ.renewal_remaining, + circ.grace_period, circ.due_date, circ.stop_fines_time, + circ.checkin_time, circ.create_time, circ.duration, + circ.fine_interval, circ.recurring_fine, circ.max_fine, + circ.phone_renewal, circ.desk_renewal, circ.opac_renewal, + circ.duration_rule, circ.recurring_fine_rule, circ.max_fine_rule, + circ.stop_fines, circ.workstation, circ.checkin_workstation, + circ.checkin_scan_time, circ.parent_circ + FROM action.circulation circ + JOIN asset.copy cp ON circ.target_copy = cp.id +JOIN asset.call_number cn ON cp.call_number = cn.id +JOIN actor.usr p ON circ.usr = p.id +LEFT JOIN actor.usr_address a ON p.mailing_address = a.id +LEFT JOIN actor.usr_address b ON p.billing_address = b.id; + +*/ + diff --git a/Open-ILS/xul/staff_client/server/circ/alternate_copy_summary.js b/Open-ILS/xul/staff_client/server/circ/alternate_copy_summary.js index 2e82c0a7d5..6966275efc 100644 --- a/Open-ILS/xul/staff_client/server/circ/alternate_copy_summary.js +++ b/Open-ILS/xul/staff_client/server/circ/alternate_copy_summary.js @@ -437,17 +437,22 @@ function load_item() { set("stop_fines", details.circ.stop_fines()); set("stop_fines_time", util.date.formatted_date( details.circ.stop_fines_time(), '%{localized}' )); set("target_copy", details.circ.target_copy()); - set("circ_usr", details.circ.usr()); - network.simple_request('FM_AU_FLESHED_RETRIEVE_VIA_ID',[ ses(), details.circ.usr() ], function(preq) { - var r_au = preq.getResultObject(); - JSAN.use('patron.util'); - set( - 'patron_name', - patron.util.format_name( r_au ) + ' : ' + r_au.card().barcode(), - details.circ.usr() - ); - set_tooltip('patron_name','circ id ' + details.circ.id()); - }); + + if (details.circ.usr()) { + set("circ_usr", details.circ.usr()); + network.simple_request('FM_AU_FLESHED_RETRIEVE_VIA_ID',[ ses(), details.circ.usr() ], function(preq) { + var r_au = preq.getResultObject(); + JSAN.use('patron.util'); + set( + 'patron_name', + patron.util.format_name( r_au ) + ' : ' + r_au.card().barcode(), + details.circ.usr() + ); + set_tooltip('patron_name','circ id ' + details.circ.id()); + }); + } else { + set("circ_usr", ""); + } set("xact_finish", util.date.formatted_date( details.circ.xact_finish(), '%{localized}' )); set("xact_start", util.date.formatted_date( details.circ.xact_start(), '%{localized}' )); set("create_time", util.date.formatted_date( details.circ.create_time(), '%{localized}' ));