Some notes from me walking through EG circ code, figuring out how it works and where the entry points for the backend javascript are. Of course, most or all of this going to change soon with the in-db circ code. :) For circulation behavior, there are two pertinent services, open-ils.penalty and open-ils.circ, which pull in the following backend javascript files: open-ils.penalty -> penalty/patron_penalty.js open-ils.circ -> circ/circ_permit_patron.js circ/circ_permit_copy.js circ/circ_duration.js circ/circ_recurring_fines.js circ/circ_max_fines.js circ/circ_permit_renew.js circ/circ_permit_hold.js The scripts used by the services are determined by configuration in opensrf.xml and are intended to be modified by admins for their installation. Certain other javascript files get pulled in by these scripts: circ/circ_lib.js circ/circ_groups.js catalog/record_type.js phys_char.js fixed_fields.js JSON_V1.js JSON_v1.js circ/circ_item_config.js circ/circ_lib.js The main source file for open-ils.circ is Circ.pm, but it pulls in Circ/Circulate.pm, which loads in the javascript specified in opensrf.xml. For checkouts, there are two pertinent circ methods: open-ils.circ.checkout.permit open-ils.circ.checkout The first determines whether the checkout is allowed, and a permit_key from that is passed to open-ils.circ.checkout to create the actual circulation. For permit, in Circulate.pm, the program flow goes something like this, assuming no shortcutting "bail outs": run_method $circulator = new Circulator, so initialize (setup references for backend javascript) mk_script_runner, to build the javascript environment and fetch most of the objects needed do_permit If the requestor is not the patron, check the VIEW_PERMIT_CHECKOUT permission ("Allows a user to determine of another user can checkout an item") check_captured_holds if copy status is On Holds Shelf and hold is for a different patron, push ITEM_ON_HOLDS_SHELF into the event list do_copy_checks if copy status is In Transit, then return/bail with COPY_IN_TRANSIT event handle_claims_returned if there is an open circulation on the item with a CLAIMSRETURNED stop fines value, then we'll either bail with a CIRC_CLAIMS_RETURNED event, or if .permit.override, we'll check in the item unless renewal check for open circulation and if found, return/bail with OPEN_CIRCULATION_EXISTS event run_patron_permit_scripts ! circ_permit_patron script ^---- ENTRY POINT FOR CUSTOM BEHAVIOR, via circ_permit_patron.js ! gather_penalty_request ^---- ENTRY POINT FOR CUSTOM BEHAVIOR, indirectly via patron_penalty.js push any events from these into the event list run_copy_permit_scripts unless pre-cat or non-cat ! circ_permit_copy script ^---- ENTRY POINT FOR CUSTOM BEHAVIOR, via circ_permit_copy.js check_copy_alert (COPY_ALERT_MESSAGE event if found) push any events from these into the event list override_events unless renewal If events are found here and this is not a .permit.override call, then we'll bail otherwise we'll test each event in the list and see if the requestor has the appropriate .override permission we'll bail on the first event where this is not the case, and remove the event from the event list if it is push SUCCESS into event list if multiple events, remove SUCCESS return $circulator->events For checkout, in Circulate.pm, the program flow goes something like this, assuming no shortcutting "bail outs": run_method $circulator = new Circulator, so initialize (setup references for backend javascript) mk_script_runner, to build the javascript environment and fetch most of the objects needed do_checkout If not a renewal, check the COPY_CHECKOUT_PERMISSION Check the permit key, and if this is a permit override, check the CIRC_PERMIT_OVERRIDE permission Consider type of circ: Non-cataloged, pre-cataloged, and normal if A) NON-CATALOGED checkout_noncat (this is defined in Circ/NonCat.pm) return if B) PRE-CAT insert 'environment.isPrecat' into script make_precat_copy (and shove it into the javascript environment for the copy checks) else if has a pre-cat call number then return ITEM_NOT_CATALOGED event (this is unclear to me) do_copy_checks if copy status is In Transit, then return/bail with COPY_IN_TRANSIT event handle_claims_returned if there is an open circulation on the item with a CLAIMSRETURNED stop fines value, then we'll either bail with a CIRC_CLAIMS_RETURNED event, or if .permit.override, we'll check in the item unless renewal check for open circulation and if found, return/bail with OPEN_CIRCULATION_EXISTS event run_checkout_scripts ! circ_duration script ^---- ENTRY POINT FOR CUSTOM BEHAVIOR, via circ_duration.js (and circ_item_config.js) # This actually figures which in-db settings to use for durationRule, recurringFinesRule, and maxFine build_checkout_circ_object apply_modified_due_date create_action_circulation update the copy status to Checked Out handle_checkout_holds update_patron_penalties if permit override or renewal return SUCCESS event and payload