Table of Contents

What are circulations? How do you encode them?

Circulations are how we keep track of a certain type of item (material) usage in Evergreen. When an item "circulates", it is checked out to (loaned to, or placed in custody of) a patron (in the common case, "user" is more general). The item generally leaves the building, but doesn't have to, and after a set amount of time may become "due" for return. Patrons may "renew" the loan period for their items, and usually get fined for any that are overdue. Evergreen doesn't allow "nested" circulations. An item may be actively circulating only once at any given time.

In Evergreen, circulations are a type of billable transaction (in an object oriented sense, circulations inherit from billable transactions). A transaction is either opened or closed, and may or may not contain (or be linked to from) billings and payments. If the total monetary amount of the billings is greater than that of the payments, then the patron owes money for that billable transaction. For circulations, each overdue/late fine per fine interval is recorded as a line item billing that is attached to the circulation/billable transaction.

IDL for circulation

        <class id="circ" controller="open-ils.cstore" oils_obj:fieldmapper="action::circulation" oils_persist:tablename="action.circulation" reporter:core="true" reporter:label="Circulation">
                <fields oils_persist:primary="id" oils_persist:sequence="money.billable_xact_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
                        <field name="isdeleted" oils_obj:array_position="2" oils_persist:virtual="true" />
                        <field reporter:label="Check In Library" name="checkin_lib" oils_obj:array_position="3" oils_persist:virtual="false" reporter:datatype="org_unit"/>
                        <field reporter:label="Check In Staff" name="checkin_staff" oils_obj:array_position="4" oils_persist:virtual="false" reporter:datatype="link"/>
                        <field reporter:label="Check In Date/Time" name="checkin_time" oils_obj:array_position="5" oils_persist:virtual="false" reporter:datatype="timestamp"/>
                        <field reporter:label="Circulating Library" name="circ_lib" oils_obj:array_position="6" oils_persist:virtual="false"  reporter:datatype="org_unit"/>
                        <field reporter:label="Circulating Staff" name="circ_staff" oils_obj:array_position="7" oils_persist:virtual="false" reporter:datatype="link"/>
                        <field reporter:label="Desk Renewal" name="desk_renewal" oils_obj:array_position="8" oils_persist:virtual="false" reporter:datatype="bool"/>
                        <field reporter:label="Due Date/Time" name="due_date" oils_obj:array_position="9" oils_persist:virtual="false" reporter:datatype="timestamp"/>
                        <field reporter:label="Circulation Duration" name="duration" oils_obj:array_position="10" oils_persist:virtual="false" reporter:datatype="interval"/>
                        <field reporter:label="Circ Duration Rule" name="duration_rule" oils_obj:array_position="11" oils_persist:virtual="false" reporter:datatype="link"/>
                        <field reporter:label="Fine Interval" name="fine_interval" oils_obj:array_position="12" oils_persist:virtual="false" reporter:datatype="interval"/>
                        <field reporter:label="Circ ID" name="id" oils_obj:array_position="13" oils_persist:virtual="false" reporter:datatype="id" />
                        <field reporter:label="Max Fine Amount" name="max_fine" oils_obj:array_position="14" oils_persist:virtual="false" reporter:datatype="money" />
                        <field reporter:label="Max Fine Rule" name="max_fine_rule" oils_obj:array_position="15" oils_persist:virtual="false" reporter:datatype="link"/>
                        <field reporter:label="OPAC Renewal" name="opac_renewal" oils_obj:array_position="16" oils_persist:virtual="false" reporter:datatype="bool"/>
                        <field reporter:label="Phone Renewal" name="phone_renewal" oils_obj:array_position="17" oils_persist:virtual="false" reporter:datatype="bool"/>
                        <field reporter:label="Recurring Fine Amount" name="recuring_fine" oils_obj:array_position="18" oils_persist:virtual="false" reporter:datatype="money" />
                        <field reporter:label="Recurring Fine Rule" name="recuring_fine_rule" oils_obj:array_position="19" oils_persist:virtual="false" reporter:datatype="link"/>
                        <field reporter:label="Remaining Renewals" name="renewal_remaining" oils_obj:array_position="20" oils_persist:virtual="false" reporter:datatype="int" />
                        <field reporter:label="Fine Stop Reason" name="stop_fines" oils_obj:array_position="21" oils_persist:virtual="false" reporter:datatype="text"/>
                        <field reporter:label="Fine Stop Date/Time" name="stop_fines_time" oils_obj:array_position="22" oils_persist:virtual="false" reporter:datatype="timestamp"/>
                        <field reporter:label="Circulating Item" name="target_copy" oils_obj:array_position="23" oils_persist:virtual="false" reporter:datatype="link"/>
                        <field reporter:label="Patron" name="usr" oils_obj:array_position="24" oils_persist:virtual="false" reporter:datatype="link"/>
                        <field reporter:label="Transaction Finish Date/Time" name="xact_finish" oils_obj:array_position="25" oils_persist:virtual="false" reporter:datatype="timestamp" />
                        <field reporter:label="Check Out Date/Time" name="xact_start" oils_obj:array_position="26" oils_persist:virtual="false" reporter:datatype="timestamp" />
                        <field reporter:label="Record Creation Date/Time" name="create_time" oils_obj:array_position="27" oils_persist:virtual="false" reporter:datatype="timestamp" />
                        <field reporter:label="Transaction Billings" name="billings" oils_obj:array_position="28" oils_persist:virtual="true" reporter:datatype="link"/>
                        <field reporter:label="Transaction Payments" name="payments" oils_obj:array_position="29" oils_persist:virtual="true" reporter:datatype="link"/>
                        <field reporter:label="Base Transaction" name="billable_transaction" oils_obj:array_position="30" oils_persist:virtual="true" reporter:datatype="link"/>
                        <field reporter:label="Circulation Type" name="circ_type" oils_obj:array_position="31" oils_persist:virtual="true" reporter:datatype="text"/>
                        <field reporter:label="Billing Totals" name="billing_total" oils_obj:array_position="32" oils_persist:virtual="true" reporter:datatype="money"/>
                        <field reporter:label="Payment Totals" name="payment_total" oils_obj:array_position="33" oils_persist:virtual="true" reporter:datatype="money"/>
                </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="usr" 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="recuring_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"/>
                </links>
        </class>

database table definition for circulation

evergreen=# \d "action".circulation
                                            Table "action.circulation"
       Column       |           Type           |                            Modifiers
--------------------+--------------------------+------------------------------------------------------------------
 id                 | bigint                   | not null default nextval('money.billable_xact_id_seq'::regclass)
 usr                | integer                  | not null
 xact_start         | timestamp with time zone | not null default now()
 xact_finish        | timestamp with time zone |
 target_copy        | bigint                   | not null
 circ_lib           | integer                  | not null
 circ_staff         | integer                  | not null
 checkin_staff      | integer                  |
 checkin_lib        | integer                  |
 renewal_remaining  | integer                  | not null
 due_date           | timestamp with time zone |
 stop_fines_time    | timestamp with time zone |
 checkin_time       | timestamp with time zone |
 create_time        | timestamp with time zone | not null default now()
 duration           | interval                 |
 fine_interval      | interval                 | not null default '1 day'::interval
 recuring_fine      | numeric(6,2)             |
 max_fine           | numeric(6,2)             |
 phone_renewal      | boolean                  | not null default false
 desk_renewal       | boolean                  | not null default false
 opac_renewal       | boolean                  | not null default false
 duration_rule      | text                     | not null
 recuring_fine_rule | text                     | not null
 max_fine_rule      | text                     | not null
 stop_fines         | text                     |
Indexes:
    "circulation_pkey" PRIMARY KEY, btree (id)
    "circ_checkin_time" btree (checkin_time) WHERE checkin_time IS NOT NULL
    "circ_circ_lib_idx" btree (circ_lib)
    "circ_open_date_idx" btree (xact_start) WHERE xact_finish IS NULL
    "circ_open_xacts_idx" btree (usr) WHERE xact_finish IS NULL
    "circ_outstanding_idx" btree (usr) WHERE checkin_time IS NULL
Check constraints:
    "circulation_stop_fines_check" CHECK (stop_fines = ANY (ARRAY['CHECKIN'::text, 'CLAIMSRETURNED'::text, 'LOST'::text, 'MAXFINES'::text, 'RENEW'::text, 'LONGOVERDUE'::text]))
Foreign-key constraints:
    "action_circulation_circ_lib_fkey" FOREIGN KEY (circ_lib) REFERENCES actor.org_unit(id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED
    "action_circulation_target_copy_fkey" FOREIGN KEY (target_copy) REFERENCES asset."copy"(id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED
    "action_circulation_usr_fkey" FOREIGN KEY (usr) REFERENCES actor.usr(id) DEFERRABLE INITIALLY DEFERRED
Triggers:
    action_circulation_stop_fines_tgr BEFORE UPDATE ON "action".circulation FOR EACH ROW EXECUTE PROCEDURE "action".circulation_claims_returned()
Inherits: billable_xact

ILD for billable transaction

        <class id="mbt" controller="open-ils.cstore" oils_obj:fieldmapper="money::billable_transaction" oils_persist:tablename="money.billable_xact" reporter:label="Billable Transaction">
                <fields oils_persist:primary="id" oils_persist:sequence="money.billable_xact_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
                        <field name="isdeleted" oils_obj:array_position="2" oils_persist:virtual="true" />
                        <field reporter:label="Transaction ID" name="id" oils_obj:array_position="3" oils_persist:virtual="false" reporter:datatype="id" />
                        <field reporter:label="User" name="usr" oils_obj:array_position="4" oils_persist:virtual="false" reporter:datatype="link"/>
                        <field reporter:label="Transaction Finish Date/Time" name="xact_finish" oils_obj:array_position="5" oils_persist:virtual="false" reporter:datatype="timestamp"/>
                        <field reporter:label="Transaction Start Date/Time" name="xact_start" oils_obj:array_position="6" oils_persist:virtual="false" reporter:datatype="timestamp"/>
                        <field reporter:label="Grocery Billing link" name="grocery" oils_obj:array_position="7" oils_persist:virtual="true" reporter:datatype="link"/>
                        <field reporter:label="Circulation Billing link" name="circulation" oils_obj:array_position="8" oils_persist:virtual="true" reporter:datatype="link"/>
                        <field reporter:label="Billing Line Items" name="billings" oils_obj:array_position="9" oils_persist:virtual="true" reporter:datatype="link"/>
                        <field reporter:label="Payment Line Items" name="payments" oils_obj:array_position="10" oils_persist:virtual="true" reporter:datatype="link"/>
                        <field reporter:label="Billing Totals" name="billing_total" oils_obj:array_position="11" oils_persist:virtual="true" reporter:datatype="money"/>
                        <field reporter:label="Payment Totals" name="payment_total" oils_obj:array_position="12" oils_persist:virtual="true" reporter:datatype="money"/>
                </fields>
                <links>
                        <link field="grocery" reltype="might_have" key="id" map="" class="mg"/>
                        <link field="circulation" reltype="might_have" key="id" map="" class="circ"/>
                        <link field="usr" reltype="has_a" key="id" map="" class="au"/>
                        <link field="payments" reltype="has_many" key="xact" map="" class="mp"/>
                        <link field="billings" reltype="has_many" key="xact" map="" class="mb"/>
                        <link field="billing_total" reltype="might_have" key="xact" map="" class="rxbt"/>
                        <link field="payment_total" reltype="might_have" key="xact" map="" class="rxpt"/>
                </links>
        </class>

database table definition for billable transaction

evergreen=# \d money.billable_xact
                                        Table "money.billable_xact"
   Column    |           Type           |                            Modifiers
-------------+--------------------------+------------------------------------------------------------------
 id          | bigint                   | not null default nextval('money.billable_xact_id_seq'::regclass)
 usr         | integer                  | not null
 xact_start  | timestamp with time zone | not null default now()
 xact_finish | timestamp with time zone |
Indexes:
    "billable_xact_pkey" PRIMARY KEY, btree (id)
    "m_b_x_open_xacts_idx" btree (usr)
Foreign-key constraints:
    "money_billable_xact_usr_fkey" FOREIGN KEY (usr) REFERENCES actor.usr(id) DEFERRABLE INITIALLY DEFERRED