</actions>
</permacrud>
</class>
+ <class id="aacs" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="action::all_circulation_slim" oils_persist:tablename="action.all_circulation_slim" reporter:core="true" reporter:label="Combined Aged and Active circulations" oils_persist:readonly="true">
+ <fields oils_persist:primary="id" oils_persist:sequence="money.billable_xact_id_seq">
+ <field reporter:label="Check In Library" name="checkin_lib" reporter:datatype="org_unit"/>
+ <field reporter:label="Check In Staff" name="checkin_staff" reporter:datatype="link"/>
+ <field reporter:label="Check In Date/Time" name="checkin_time" reporter:datatype="timestamp"/>
+ <field reporter:label="Circulating Library" name="circ_lib" reporter:datatype="org_unit"/>
+ <field reporter:label="Circulating Staff" name="circ_staff" reporter:datatype="link"/>
+ <field reporter:label="Desk Renewal" name="desk_renewal" reporter:datatype="bool"/>
+ <field reporter:label="Due Date/Time" name="due_date" reporter:datatype="timestamp"/>
+ <field reporter:label="Circulation Duration" name="duration" reporter:datatype="interval"/>
+ <field reporter:label="Circ Duration Rule" name="duration_rule" reporter:datatype="link"/>
+ <field reporter:label="Fine Interval" name="fine_interval" reporter:datatype="interval"/>
+ <field reporter:label="Circ ID" name="id" reporter:datatype="id" />
+ <field reporter:label="Max Fine Amount" name="max_fine" reporter:datatype="money" />
+ <field reporter:label="Max Fine Rule" name="max_fine_rule" reporter:datatype="link"/>
+ <field reporter:label="OPAC Renewal" name="opac_renewal" reporter:datatype="bool"/>
+ <field reporter:label="Phone Renewal" name="phone_renewal" reporter:datatype="bool"/>
+ <field reporter:label="Recurring Fine Amount" name="recurring_fine" reporter:datatype="money" />
+ <field reporter:label="Recurring Fine Rule" name="recurring_fine_rule" reporter:datatype="link"/>
+ <field reporter:label="Remaining Renewals" name="renewal_remaining" reporter:datatype="int" />
+ <field reporter:label="Grace Period" name="grace_period" reporter:datatype="interval" />
+ <field reporter:label="Fine Stop Reason" name="stop_fines" reporter:datatype="text"/>
+ <field reporter:label="Fine Stop Date/Time" name="stop_fines_time" reporter:datatype="timestamp"/>
+ <field reporter:label="Circulating Item" name="target_copy" reporter:datatype="link"/>
+ <field reporter:label="Transaction Finish Date/Time" name="xact_finish" reporter:datatype="timestamp" />
+ <field reporter:label="Checkout Date/Time" name="xact_start" reporter:datatype="timestamp" />
+ <field reporter:label="Record Creation Date/Time" name="create_time" reporter:datatype="timestamp" />
+ <field reporter:label="Parent Circulation" name="parent_circ" reporter:datatype="link"/>
+ <field reporter:label="Checkin Scan Time" name="checkin_scan_time" reporter:datatype="timestamp"/>
+ <field reporter:label="Checkin Workstation" name="checkin_workstation" reporter:datatype="link"/>
+ <field reporter:label="Patron" name="usr" reporter:datatype="link"/>
+ <field reporter:label="Transaction Billings" name="billings" oils_persist:virtual="true" reporter:datatype="link"/>
+ <field reporter:label="Transaction Payments" name="payments" oils_persist:virtual="true" reporter:datatype="link"/>
+ <field reporter:label="Base Transaction" name="billable_transaction" oils_persist:virtual="true" reporter:datatype="link"/>
+ <field reporter:label="Workstation" name="workstation" reporter:datatype="link"/>
+ <field reporter:label="Circulation Type" name="circ_type" oils_persist:virtual="true" reporter:datatype="text"/>
+ <field reporter:label="Billing Totals" name="billing_total" oils_persist:virtual="true" reporter:datatype="money"/>
+ <field reporter:label="Payment Totals" name="payment_total" oils_persist:virtual="true" reporter:datatype="money"/>
+ <field reporter:label="Archived Patron Stat-Cat Entries" name="aaactsc_entries" oils_persist:virtual="true" reporter:datatype="link"/>
+ <field reporter:label="Archived Copy Stat-Cat Entries" name="aaasc_entries" oils_persist:virtual="true" reporter:datatype="link"/>
+ <field reporter:label="Linked Active Circulation" name="active_circ" oils_persist:virtual="true" reporter:datatype="link"/>
+ <field reporter:label="Linked Aged Circulation" name="aged_circ" oils_persist:virtual="true" reporter:datatype="link"/>
+ </fields>
+ <links>
+ <link field="billable_transaction" reltype="might_have" key="id" map="" class="mbt"/>
+ <link field="circ_staff" reltype="has_a" key="id" map="" class="au"/>
+ <link field="checkin_lib" reltype="has_a" key="id" map="" class="aou"/>
+ <link field="target_copy" reltype="has_a" key="id" map="" class="acp"/>
+ <link field="checkin_staff" reltype="has_a" key="id" map="" class="au"/>
+ <link field="circ_lib" reltype="has_a" key="id" map="" class="aou"/>
+ <link field="payments" reltype="has_many" key="xact" map="" class="mp"/>
+ <link field="billings" reltype="has_many" key="xact" map="" class="mb"/>
+ <link field="duration_rule" reltype="has_a" key="name" map="" class="crcd"/>
+ <link field="max_fine_rule" reltype="has_a" key="name" map="" class="crmf"/>
+ <link field="recurring_fine_rule" reltype="has_a" key="name" map="" class="crrf"/>
+ <link field="circ_type" reltype="might_have" key="id" map="" class="rcirct"/>
+ <link field="billing_total" reltype="might_have" key="xact" map="" class="rxbt"/>
+ <link field="payment_total" reltype="might_have" key="xact" map="" class="rxpt"/>
+ <link field="workstation" reltype="has_a" key="id" map="" class="aws"/>
+ <link field="checkin_workstation" reltype="has_a" key="id" map="" class="aws"/>
+ <link field="aaactsc_entries" reltype="has_many" key="xact" map="" class="aaactsc"/>
+ <link field="aaasc_entries" reltype="has_many" key="xact" map="" class="aaasc"/>
+ <link field="active_circ" reltype="might_have" key="id" map="" class="circ"/>
+ <link field="aged_circ" reltype="might_have" key="id" map="" class="acirc"/>
+ <link field="parent_circ" reltype="might_have" key="id" map="" class="acirc"/>
+ <link field="usr" reltype="has_a" key="id" map="" class="au"/>
+ </links>
+ <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+ <actions>
+ <retrieve permission="VIEW_CIRCULATIONS" context_field="circ_lib" />
+ </actions>
+ </permacrud>
+ </class>
+
<class id="combcirc" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="action::all_circulation" oils_persist:tablename="action.all_circulation" reporter:core="true" reporter:label="Combined Aged and Active Circulations" oils_persist:readonly="true">
<fields oils_persist:primary="id" oils_persist:sequence="money.billable_xact_id_seq">
<field reporter:label="Check In Library" name="checkin_lib" reporter:datatype="org_unit"/>
Retrieve a circ object by id
@param authtoken Login session key
@pararm circid The id of the circ object
- @param all_circ Returns an action.all_circulation object instead
+ @param all_circ Returns an action.all_circulation_slim object instead
of an action.circulation object to pick up aged circs.
/
);
my $e = new_editor(authtoken => $a);
return $e->event unless $e->checkauth;
my $method = $all_circ ?
- 'retrieve_action_all_circulation' :
+ 'retrieve_action_all_circulation_slim' :
'retrieve_action_circulation';
my $circ = $e->$method($i) or return $e->event;
if( $e->requestor->id ne ($circ->usr || '') ) {
$count = 4 unless defined $count;
}
- return $e->search_action_all_circulation([
+ return $e->search_action_all_circulation_slim([
{target_copy => $copyid},
- {limit => $count, order_by => { combcirc => "xact_start DESC" }}
+ {limit => $count, order_by => { aacs => "xact_start DESC" }}
]);
}
# find the most recent circulation for the requested copy,
# be it active, completed, or aged.
- my $circ = $e->search_action_all_circulation([
+ my $circ = $e->search_action_all_circulation_slim([
{ target_copy => $copy_id },
{
flesh => 1,
flesh_fields => {
- combcirc => [
+ aacs => [
'workstation',
'checkin_workstation',
'duration_rule',
'recurring_fine_rule'
],
},
- order_by => { combcirc => 'xact_start desc' },
+ order_by => { aacs => 'xact_start desc' },
limit => 1
}
])->[0];
my $chain = $e->json_query({from => ['action.all_circ_chain', $circ_id]});
for my $circ_info (@$chain) {
- my $circ = Fieldmapper::action::all_circulation->new;
+ my $circ = Fieldmapper::action::all_circulation_slim->new;
$circ->$_($circ_info->{$_}) for keys %$circ_info;
$conn->respond($circ);
}
my $first_circ =
$e->json_query({from => ['action.all_circ_chain', $circ_id]})->[0];
- my $prev_circ = $e->search_action_all_circulation([
+ my $prev_circ = $e->search_action_all_circulation_slim([
{ target_copy => $first_circ->{target_copy},
xact_start => {'<' => $first_circ->{xact_start}}
}, {
flesh => 1,
flesh_fields => {
- combcirc => [
+ aacs => [
'active_circ',
'aged_circ'
]
},
- order_by => { combcirc => 'xact_start desc' },
+ order_by => { aacs => 'xact_start desc' },
limit => 1
}
])->[0];
{from => ['action.all_circ_chain', $prev_circ->id]});
for my $circ_info (@$chain) {
- my $circ = Fieldmapper::action::all_circulation->new;
+ my $circ = Fieldmapper::action::all_circulation_slim->new;
$circ->$_($circ_info->{$_}) for keys %$circ_info;
$conn->respond($circ);
}
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 VIEW action.all_circulation_slim AS
+ SELECT * FROM action.circulation
+UNION ALL
+ SELECT
+ id,
+ NULL AS usr,
+ xact_start,
+ xact_finish,
+ unrecovered,
+ target_copy,
+ circ_lib,
+ circ_staff,
+ checkin_staff,
+ checkin_lib,
+ renewal_remaining,
+ grace_period,
+ due_date,
+ stop_fines_time,
+ checkin_time,
+ create_time,
+ duration,
+ fine_interval,
+ recurring_fine,
+ max_fine,
+ phone_renewal,
+ desk_renewal,
+ opac_renewal,
+ duration_rule,
+ recurring_fine_rule,
+ max_fine_rule,
+ stop_fines,
+ workstation,
+ checkin_workstation,
+ copy_location,
+ checkin_scan_time,
+ parent_circ
+ FROM action.aged_circulation
+;
+
+
+
CREATE OR REPLACE FUNCTION action.age_circ_on_delete () RETURNS TRIGGER AS $$
DECLARE
found char := 'N';
-- same as action.circ_chain, but returns action.all_circulation
-- rows which may include aged circulations.
CREATE OR REPLACE FUNCTION action.all_circ_chain (ctx_circ_id INTEGER)
- RETURNS SETOF action.all_circulation AS $$
+ RETURNS SETOF action.all_circulation_slim AS $$
DECLARE
- tmp_circ action.all_circulation%ROWTYPE;
- circ_0 action.all_circulation%ROWTYPE;
+ tmp_circ action.all_circulation_slim%ROWTYPE;
+ circ_0 action.all_circulation_slim%ROWTYPE;
BEGIN
- SELECT INTO tmp_circ * FROM action.all_circulation WHERE id = ctx_circ_id;
+ SELECT INTO tmp_circ * FROM action.all_circulation_slim WHERE id = ctx_circ_id;
IF tmp_circ IS NULL THEN
RETURN NEXT tmp_circ;
-- find the front of the chain
WHILE TRUE LOOP
- SELECT INTO tmp_circ * FROM action.all_circulation
+ SELECT INTO tmp_circ * FROM action.all_circulation_slim
WHERE id = tmp_circ.parent_circ;
IF tmp_circ IS NULL THEN
EXIT;
EXIT;
END IF;
RETURN NEXT tmp_circ;
- SELECT INTO tmp_circ * FROM action.all_circulation
+ SELECT INTO tmp_circ * FROM action.all_circulation_slim
WHERE parent_circ = tmp_circ.id;
END LOOP;
DECLARE
-- first circ in the chain
- circ_0 action.all_circulation%ROWTYPE;
+ circ_0 action.all_circulation_slim%ROWTYPE;
-- last circ in the chain
- circ_n action.all_circulation%ROWTYPE;
+ circ_n action.all_circulation_slim%ROWTYPE;
-- circ chain under construction
chain action.circ_chain_summary;
- tmp_circ action.all_circulation%ROWTYPE;
+ tmp_circ action.all_circulation_slim%ROWTYPE;
BEGIN
END;
$$ LANGUAGE 'plpgsql';
-
CREATE OR REPLACE FUNCTION action.usr_visible_holds (usr_id INT) RETURNS SETOF action.hold_request AS $func$
DECLARE
h action.hold_request%ROWTYPE;
FROM asset.copy cp
JOIN precalc_copy_filter_bib_list c ON (cp.id = c.copy)
JOIN asset.call_number cn ON (cn.id = cp.call_number)
- LEFT JOIN action.all_circulation circ ON (
+ LEFT JOIN action.all_circulation_slim circ ON (
circ.target_copy = cp.id
AND stop_fines NOT IN (
'LOST',
--- /dev/null
+BEGIN;
+
+-- SELECT evergreen.upgrade_deps_block_check('1XXX', :eg_version);
+
+CREATE OR REPLACE VIEW action.all_circulation_slim AS
+ SELECT * FROM action.circulation
+UNION ALL
+ SELECT
+ id,
+ NULL AS usr,
+ xact_start,
+ xact_finish,
+ unrecovered,
+ target_copy,
+ circ_lib,
+ circ_staff,
+ checkin_staff,
+ checkin_lib,
+ renewal_remaining,
+ grace_period,
+ due_date,
+ stop_fines_time,
+ checkin_time,
+ create_time,
+ duration,
+ fine_interval,
+ recurring_fine,
+ max_fine,
+ phone_renewal,
+ desk_renewal,
+ opac_renewal,
+ duration_rule,
+ recurring_fine_rule,
+ max_fine_rule,
+ stop_fines,
+ workstation,
+ checkin_workstation,
+ copy_location,
+ checkin_scan_time,
+ parent_circ
+ FROM action.aged_circulation
+;
+
+DROP FUNCTION action.summarize_all_circ_chain(INTEGER);
+DROP FUNCTION action.all_circ_chain(INTEGER);
+
+CREATE OR REPLACE FUNCTION action.all_circ_chain (ctx_circ_id INTEGER)
+ RETURNS SETOF action.all_circulation_slim AS $$
+DECLARE
+ tmp_circ action.all_circulation_slim%ROWTYPE;
+ circ_0 action.all_circulation_slim%ROWTYPE;
+BEGIN
+
+ SELECT INTO tmp_circ * FROM action.all_circulation_slim 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_slim
+ 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_slim
+ 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_slim%ROWTYPE;
+
+ -- last circ in the chain
+ circ_n action.all_circulation_slim%ROWTYPE;
+
+ -- circ chain under construction
+ chain action.circ_chain_summary;
+ tmp_circ action.all_circulation_slim%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';
+
+CREATE OR REPLACE FUNCTION rating.percent_time_circulating(badge_id INT)
+ RETURNS TABLE (record BIGINT, value NUMERIC) AS $f$
+DECLARE
+ badge rating.badge_with_orgs%ROWTYPE;
+BEGIN
+
+ SELECT * INTO badge FROM rating.badge_with_orgs WHERE id = badge_id;
+
+ PERFORM rating.precalc_bibs_by_copy(badge_id);
+
+ DELETE FROM precalc_copy_filter_bib_list WHERE id NOT IN (
+ SELECT id FROM precalc_filter_bib_list
+ INTERSECT
+ SELECT id FROM precalc_bibs_by_copy_list
+ );
+
+ ANALYZE precalc_copy_filter_bib_list;
+
+ RETURN QUERY
+ SELECT bib,
+ SUM(COALESCE(circ_time,0))::NUMERIC / SUM(age)::NUMERIC
+ FROM (SELECT cn.record AS bib,
+ cp.id,
+ EXTRACT( EPOCH FROM AGE(cp.active_date) ) + 1 AS age,
+ SUM( -- time copy spent circulating
+ EXTRACT(
+ EPOCH FROM
+ AGE(
+ COALESCE(circ.checkin_time, circ.stop_fines_time, NOW()),
+ circ.xact_start
+ )
+ )
+ )::NUMERIC AS circ_time
+ FROM asset.copy cp
+ JOIN precalc_copy_filter_bib_list c ON (cp.id = c.copy)
+ JOIN asset.call_number cn ON (cn.id = cp.call_number)
+ LEFT JOIN action.all_circulation_slim circ ON (
+ circ.target_copy = cp.id
+ AND stop_fines NOT IN (
+ 'LOST',
+ 'LONGOVERDUE',
+ 'CLAIMSRETURNED',
+ 'LONGOVERDUE'
+ )
+ AND NOT (
+ checkin_time IS NULL AND
+ stop_fines = 'MAXFINES'
+ )
+ )
+ WHERE cn.owning_lib = ANY (badge.orgs)
+ AND cp.active_date IS NOT NULL
+ -- Next line requires that copies with no circs (circ.id IS NULL) also not be deleted
+ AND ((circ.id IS NULL AND NOT cp.deleted) OR circ.id IS NOT NULL)
+ GROUP BY 1,2,3
+ ) x
+ GROUP BY 1;
+END;
+$f$ LANGUAGE PLPGSQL STRICT;
+
+
+-- ROLLBACK;
+COMMIT;
+
limit : 1
}
- //Retrieve separate copy, combcirc, and accs information
+ //Retrieve separate copy, aacs, and accs information
service.getCopy = function(barcode, id) {
if (barcode) return egCore.pcrud.search(
'acp', {barcode : barcode, deleted : 'f'},
.then(function(copy) {return copy});
}
service.getCirc = function(id) {
- return egCore.pcrud.search('combcirc', { target_copy : id },
+ return egCore.pcrud.search('aacs', { target_copy : id },
service.circFlesh).then(function(circ) {return circ});
}
service.getSummary = function(id) {
}).then(function(count) {
- egCore.pcrud.search('combcirc',
+ egCore.pcrud.search('aacs',
{target_copy : copyId},
{ flesh : 2,
flesh_fields : {
- combcirc : [
+ aacs : [
'usr',
'workstation',
'checkin_workstation',
],
au : ['card']
},
- order_by : {combcirc : 'xact_start desc'},
+ order_by : {aacs : 'xact_start desc'},
limit : count
}