FF : initial SQL mods file; needs testing
authorBill Erickson <berick@esilibrary.com>
Fri, 25 Oct 2013 15:47:25 +0000 (11:47 -0400)
committerBill Erickson <berick@esilibrary.com>
Fri, 25 Oct 2013 15:47:25 +0000 (11:47 -0400)
Signed-off-by: Bill Erickson <berick@esilibrary.com>
Open-ILS/src/sql/Pg/fulfillment-mods.sql [new file with mode: 0644]

diff --git a/Open-ILS/src/sql/Pg/fulfillment-mods.sql b/Open-ILS/src/sql/Pg/fulfillment-mods.sql
new file mode 100644 (file)
index 0000000..8b85228
--- /dev/null
@@ -0,0 +1,864 @@
+-- FulfILLment Database Changes / Applied to the default Evergreen schema
+BEGIN;
+
+-- Altered Tables ------------------------------------------------------------
+
+ALTER TABLE actor.card
+    ADD COLUMN org INT NOT NULL 
+        REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED;
+
+CREATE UNIQUE INDEX actor_card_barcode_org_idx ON actor.card (barcode, org);
+
+ALTER TABLE asset.copy
+    ADD COLUMN source_lib INT NOT NULL 
+        REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED;
+
+DROP INDEX IF EXISTS copy_barcode_key;
+CREATE UNIQUE INDEX copy_barcode_key ON asset.copy (barcode, source_lib) 
+    WHERE deleted = FALSE OR deleted IS FALSE;
+
+ALTER TABLE biblio.record_entry
+    ADD COLUMN remote_id TEXT;
+
+CREATE INDEX biblio_record_entry_remote_id_owner_idx 
+    ON biblio.record_entry ( remote_id, owner );
+
+
+-- New Tables ----------------------------------------------------------------
+
+CREATE TABLE actor.web_action_print_template (
+    id          SERIAL      PRIMARY KEY,
+    owner       INT         NOT NULL REFERENCES actor.usr (id) 
+                            ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+    focus       TEXT        NOT NULL CHECK (focus IN ('circ','hold','transit','copy')),
+    action      TEXT        CHECK (action IN ('Check In','Recall','Receive',
+                            'Check Out','Capture','Reject','Freeze','Thaw','Cancel')),
+    direction   TEXT        CHECK (direction IN ('Incoming','Outgoing')),
+    template    TEXT        NOT NULL
+);
+
+-- Functions -----------------------------------------------------------------
+
+CREATE OR REPLACE FUNCTION biblio.fast_import (p_owner INT, p_marc TEXT) RETURNS BOOL AS $func$
+DECLARE
+    is_del          BOOL;
+    rid_value       TEXT;
+    existing_bib    biblio.record_entry%ROWTYPE;
+BEGIN
+
+    SELECT oils_xpath_string( REPLACE(BTRIM(value,'"'),E'\\"','"'), p_marc ) INTO rid_value 
+        FROM actor.org_unit_ancestor_setting( 'ff.remote.bib_refresh.lai_id_field', p_owner ) LIMIT 1;
+
+    IF rid_value IS NULL THEN
+        RETURN FALSE;
+    END IF;
+
+    SELECT SUBSTR( oils_xpath_string( '//*[local-name()="leader"]', p_marc ), 6, 1) = 'd' INTO is_del;
+
+    SELECT * INTO existing_bib FROM biblio.record_entry WHERE remote_id = rid_value AND owner = p_owner;
+
+    IF existing_bib.id IS NULL AND NOT is_del THEN
+        -- RAISE NOTICE 'INSERTing for %', rid_value;
+        INSERT INTO biblio.record_entry (marc, owner, remote_id, last_xact_id)
+            VALUES (p_marc, p_owner, rid_value, EXTRACT(EPOCH FROM now()));
+    ELSE
+        IF !is_del THEN
+            -- RAISE NOTICE 'UPDATEing for %', existing_bib.id;
+            UPDATE  biblio.record_entry
+              SET   marc = p_marc,
+                    last_xact_id = EXTRACT(EPOCH FROM now())
+              WHERE id = existing_bib.id;
+        ELSE
+            DELETE FROM biblio.record_entry WHERE id = existing_bib.id;
+        END IF;
+    END IF;
+
+    IF FOUND THEN
+        RETURN TRUE;
+    ELSE
+        RETURN FALSE;
+    END IF;
+
+END;
+$func$ LANGUAGE PLPGSQL;
+
+-- Triggers ------------------------------------------------------------------
+
+
+CREATE OR REPLACE FUNCTION biblio.item_load_trigger () RETURNS TRIGGER AS $$
+BEGIN
+    INSERT INTO action_trigger.event (target, event_def, run_time) 
+        VALUES (NEW.id, 92, NOW()); -- item load trigger, below
+    RETURN NEW;
+END;
+$$ LANGUAGE PLPGSQL;
+
+CREATE TRIGGER bre_load_item_tgr AFTER INSERT ON biblio.record_entry 
+    FOR EACH ROW EXECUTE PROCEDURE biblio.item_load_trigger ();
+
+
+
+-- SEED DATA -----------------------------------------------------------------
+
+INSERT INTO action_trigger.hook (key,core_type,description,passive) 
+    VALUES ('refresh_timeout.bre','bre','Bib record needs to be refreshed',TRUE);
+INSERT INTO action_trigger.hook (key,core_type,description,passive) 
+    VALUES ('refresh_timeout.acp','acp','Item record needs to be refreshed',TRUE);
+INSERT INTO action_trigger.hook (key,core_type,description) 
+    VALUES ('bre.created','bre','Bib record is created');
+
+
+INSERT INTO action_trigger.reactor (module,description) VALUES
+(   'FulfILLment::AT::Reactor::ItemRefresh::ByItem',
+    oils_i18n_gettext(
+        'FulfILLment::AT::Reactor::ItemRefresh::ByItem',
+        'Refreshes item data via FulfILLment APIs',
+        'atreact',
+        'description'
+    )
+);
+
+INSERT INTO action_trigger.reactor (module,description) VALUES
+(   'FulfILLment::AT::Reactor::ItemLoad::ByBib',
+    oils_i18n_gettext(
+        'FulfILLment::AT::Reactor::ItemLoad::ByBib',
+        'Load initial item data via FulfILLment APIs',
+        'atreact',
+        'description'
+    )
+);
+
+INSERT INTO action_trigger.reactor (module,description) VALUES
+(   'FulfILLment::AT::Reactor::BibRefresh',
+    oils_i18n_gettext(
+        'FulfILLment::AT::Reactor::BibRefresh',
+        'Refreshes bibliographic data via FulfILLment APIs',
+        'atreact',
+        'description'
+    )
+);
+
+INSERT INTO action_trigger.event_definition 
+    (id, active, owner, name, hook, validator, reactor, delay, delay_field, group_field) 
+    VALUES (90, 'f', 1, 'Weekly item refresh', 'refresh_timeout.acp', 'NOOP_True', 
+        'FulfILLment::AT::Reactor::ItemRefresh::ByItem', '1 week', 'cache_time', 'source_lib');
+
+INSERT INTO action_trigger.event_definition 
+    (id, active, owner, name, hook, validator, reactor, delay, delay_field, group_field) 
+    VALUES (91, 'f', 1, 'Monthly bib refresh', 'refresh_timeout.bre', 'NOOP_True', 
+        'FulfILLment::AT::Reactor::BibRefresh', '1 month', 'edit_date', 'owner');
+
+INSERT INTO action_trigger.event_definition 
+    (id, active, owner, name, hook, validator, reactor) 
+    VALUES (92, 'f', 1, 'Initial item load', 
+        'bre.created', 'NOOP_True', 'FulfILLment::AT::Reactor::ItemLoad::ByBib');
+
+
+INSERT INTO config.org_unit_setting_type ( name, label, description, datatype ) VALUES (
+    'ff.remote.bib_refresh.interval',
+    oils_i18n_gettext( 'ff.remote.bib_refresh.interval', 'LAI: Remote Bibliograph Record refresh interval', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.bib_refresh.interval', 'How often should FufILLment attempt to refresh bibliographic records for this remote ILS', 'coust', 'description'),
+    'interval'
+), (
+    'ff.remote.bib_refresh.lai_id_field',
+    oils_i18n_gettext( 'ff.remote.bib_refresh.lai_id_field', 'LAI: Remote ILS record ID field and subfield', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.bib_refresh.lai_id_field', 'Where, within bibliographic records, the remote ILS stores the local unique identifier', 'coust', 'description'),
+    'string'
+), (
+    'ff.remote.bib_refresh.previous',
+    oils_i18n_gettext( 'ff.remote.bib_refresh.previous', 'LAI: Previous Remote Bibliograph Record refresh', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.bib_refresh.previous', 'Timestamp of the previous attempt to refresh bibliographic records for this remote ILS', 'coust', 'description'),
+    'string'
+), (
+    'ff.remote.bib_refresh.chunk_size',
+    oils_i18n_gettext( 'ff.remote.bib_refresh.chunk_size', 'LAI: Remote Bibliograph Record refresh chunk size', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.bib_refresh.chunk_size', 'How many bibliographic records should be requested at a time', 'coust', 'description'),
+    'integer'
+), (
+    'ff.remote.connector.extra.agency',
+    oils_i18n_gettext( 'ff.remote.connector.extra.agency', 'LAI: NCIP Agency', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.extra.agency', 'NCIP Agency to be used for this remote ILS', 'coust', 'description'),
+    'string'
+), (
+    'ff.remote.connector.location',
+    oils_i18n_gettext( 'ff.remote.connector.location', 'LAI: ILS-defined Location', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.location', 'ILS-defined Location to be used for this remote ILS', 'coust', 'description'),
+    'string'
+), (
+    'ff.remote.connector.type',
+    oils_i18n_gettext( 'ff.remote.connector.type', 'LAI: Connector Type', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.type', 'Connector to be used for this remote ILS', 'coust', 'description'),
+    'string'
+), (
+    'ff.remote.connector.host',
+    oils_i18n_gettext( 'ff.remote.connector.host', 'LAI: Default Connector Host', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.host', 'Default host to be used with the owning site''s Connector', 'coust', 'description'),
+    'string'
+), (
+    'ff.remote.connector.port',
+    oils_i18n_gettext( 'ff.remote.connector.port', 'LAI: Default Connector Port', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.port', 'Default port to be used with the the owning site''sConnector', 'coust', 'description'),
+    'integer'
+), (
+    'ff.remote.connector.user',
+    oils_i18n_gettext( 'ff.remote.connector.user', 'LAI: Default Connector User', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.user', 'Default user to be used with the owing site''s Connector', 'coust', 'description'),
+    'string'
+), (
+    'ff.remote.connector.passwd',
+    oils_i18n_gettext( 'ff.remote.connector.passwd', 'LAI: Default Connector Password', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.passwd', 'Default password to be used with the owning site''s Connector', 'coust', 'description'),
+    'string'
+), (
+    'ff.remote.connector.user.actor',
+    oils_i18n_gettext( 'ff.remote.connector.user.actor', 'LAI: Connector Actor Data User', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.user.actor', 'Actor data override user', 'coust', 'description'),
+    'string'
+), (
+    'ff.remote.connector.passwd.actor',
+    oils_i18n_gettext( 'ff.remote.connector.passwd.actor', 'LAI: Connector Actor Data Password', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.passwd.actor', 'Actor data override password', 'coust', 'description'),
+    'string'
+), (
+    'ff.remote.connector.user.resource',
+    oils_i18n_gettext( 'ff.remote.connector.user.resource', 'LAI: Connector Resource Data User', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.user.resource', 'Resource data override user', 'coust', 'description'),
+    'string'
+), (
+    'ff.remote.connector.passwd.resource',
+    oils_i18n_gettext( 'ff.remote.connector.passwd.resource', 'LAI: Connector Resource Data Password', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.passwd.resource', 'Resource data override password', 'coust', 'description'),
+    'string'
+),(
+    'ff.remote.connector.user.hold',
+    oils_i18n_gettext( 'ff.remote.connector.user.hold', 'LAI: Connector Hold Data User', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.user.hold', 'Hold data override user', 'coust', 'description'),
+    'string'
+), (
+    'ff.remote.connector.host.resource',
+    oils_i18n_gettext( 'ff.remote.connector.host.resource', 'LAI: Connector Resource Data Host', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.host.resource', 'Resource data override host', 'coust', 'description'),
+    'string'
+), (
+    'ff.remote.connector.passwd.hold',
+    oils_i18n_gettext( 'ff.remote.connector.passwd.hold', 'LAI: Connector Hold Data Password', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.passwd.hold', 'Hold data override password', 'coust', 'description'),
+    'string'),
+(   'ff.remote.connector.extra.pickup_location',
+    oils_i18n_gettext( 'ff.remote.connector.extra.pickup_location', 'LAI: Central Shipping Location for outgoing ILL Requests', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.extra.pickup_location', 'If outgoing ILLs are handled centrally, the code of the lender intra-system hold pickup location', 'coust', 'description'),
+    'string'), 
+(   'ff.remote.connector.extra.location',
+    oils_i18n_gettext( 'ff.remote.connector.extra.location', 'LAI: Location code/prefix for bibs', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.extra.location', 'Needed by Aleph, Symphony and Polaris for bib requests', 'coust', 'description'),
+    'string'), 
+(   'ff.remote.connector.extra.z3950.port',
+    oils_i18n_gettext( 'ff.remote.connector.extra.z3950.port', 'LAI: Z39.50 port for bibs', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.extra.z3950.port', 'Z39.50 port for bibs', 'coust', 'description'),
+    'string'), 
+(   'ff.remote.connector.extra.z3950.database',
+    oils_i18n_gettext( 'ff.remote.connector.extra.z3950.database', 'LAI: Z39.50 database name for bibs', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.extra.z3950.database', 'Z39.50 database name for bibs', 'coust', 'description'),
+    'string'), 
+(   'ff.remote.connector.extra.z3950.search_attr',
+    oils_i18n_gettext( 'ff.remote.connector.extra.z3950.search_attr', 'LAI: Z39.50 search attribute for bibs', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.extra.z3950.search_attr', 'Z39.50 search attribute for bibs', 'coust', 'description'),
+    'string'), 
+(   'ff.remote.connector.port.hold',
+    oils_i18n_gettext( 'ff.remote.connector.port.hold', 'LAI: Connector Hold Data Port', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.port.hold', 'Host to be used with the owning site''s Connector', 'coust', 'description'),
+    'string'), 
+(   'ff.remote.connector.port.resource',
+    oils_i18n_gettext( 'ff.remote.connector.port.resource', 'LAI: Connector Resource Data Port', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.port.resource', 'Host to be used with the owning site''s Connector', 'coust', 'description'),
+    'string'), 
+(   'ff.remote.connector.port.actor',
+    oils_i18n_gettext( 'ff.remote.connector.port.actor', 'LAI: Connector Actor Data Port', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.port.actor', 'Host to be used with the owning site''s Connector', 'coust', 'description'),
+    'string'), 
+(   'ff.remote.connector.port.item',
+    oils_i18n_gettext( 'ff.remote.connector.port.item', 'LAI: Connector Item Data Port', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.port.item', 'Host to be used with the owning site''s Connector', 'coust', 'description'),
+    'string'), 
+(   'ff.remote.connector.host.actor',
+    oils_i18n_gettext( 'ff.remote.connector.host.actor', 'LAI: Connector Actor Data Host', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.host.actor', 'Host to be used with the owing site''s Connector', 'coust', 'description'),
+    'string'), 
+(   'ff.remote.connector.host.hold',
+    oils_i18n_gettext( 'ff.remote.connector.host.hold', 'LAI: Connector Hold Data Host', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.host.hold', 'Host to be used with the owing site''s Connector', 'coust', 'description'),
+    'string'), 
+(   'ff.remote.connector.host.item',
+    oils_i18n_gettext( 'ff.remote.connector.host.item', 'LAI: Connector Item Data Host', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.host.item', 'Host to be used with the owing site''s Connector', 'coust', 'description'),
+    'string'), 
+(   'ff.remote.connector.user.item',
+    oils_i18n_gettext( 'ff.remote.connector.user.item', 'LAI: Connector Item Data User', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.user.item', 'User to be used with the owing site''s Connector', 'coust', 'description'),
+    'string'), 
+(   'ff.remote.connector.passwd.item',
+    oils_i18n_gettext( 'ff.remote.connector.passwd.item', 'LAI: Connector Item Data Password', 'coust', 'label'),
+    oils_i18n_gettext( 'ff.remote.connector.passwd.item', 'Password to be used with the owing site''s Connector', 'coust', 'description'),
+    'string');
+
+
+
+-- item auto-ingest related settings 
+INSERT INTO config.org_unit_setting_type ( name, label, description, datatype ) VALUES (
+    'ff.remote.item_cache.purge.interval',
+    oils_i18n_gettext(
+        'ff.remote.item_cache.purge.interval', 
+        'LAI: Item Cache Purge interval', 
+        'coust', 
+        'label'),
+    oils_i18n_gettext(
+        'ff.remote.item_cache.purge.interval', 
+        'How often should FufILLment purge unused item record cache entries for this remote ILS', 
+        'coust', 
+        'description'),
+    'interval'
+), (
+    'ff.remote.item_cache.purge.previous',
+    oils_i18n_gettext(
+        'ff.remote.item_cache.purge.previous', 
+        'LAI: Previous Remote Item Cache purge', 
+        'coust', 
+        'label'),
+    oils_i18n_gettext(
+        'ff.remote.item_cache.purge.previous', 
+        'Timestamp of the previous item cache purge for this remote ILS', 
+        'coust', 
+        'description'),
+    'string'
+);
+
+-- default user group for participating institutions
+INSERT INTO config.org_unit_setting_type ( name, label, description, datatype, fm_class ) 
+    VALUES ( 
+        'ff.remote.user_cache.default_group',
+        oils_i18n_gettext('ff.remote.user_cache.default_group', 'LAI: Default user group for autocollected patrons', 'coust', 'label'),
+        oils_i18n_gettext('ff.remote.user_cache.default_group', 'When fetching a user from the remote ILS, what user group should users be dropped into?', 'coust', 'description'),
+        'link',
+        'pgt'
+    );
+
+
+INSERT INTO config.org_unit_setting_type (name, label, description, datatype)
+VALUES (
+    'ff.remote.connector.version',
+    oils_i18n_gettext(
+        'ff.remote.connector.version', 
+        'LAI: Connector Version',
+        'coust', 'label'
+    ),
+    oils_i18n_gettext(
+        'ff.remote.connector.version', 
+        'Optional connector version string; used for loading version-specific behavior',
+        'coust', 'description'
+    ),
+    'string'
+);
+
+INSERT INTO config.org_unit_setting_type (name, label, description, datatype)
+VALUES (
+    'ff.remote.connector.extra.sip2.host',
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.sip2.host', 
+        'LAI: SIP2 Hostname',
+        'coust', 'label'
+    ),
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.sip2.host', 
+        'SIP2 hostname, if different from the default connector host',
+        'coust', 'description'
+    ),
+    'string'
+), (
+    'ff.remote.connector.extra.sip2.port',
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.sip2.port', 
+        'LAI: SIP2 Port',
+        'coust', 'label'
+    ),
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.sip2.port', 
+        'SIP2 port number',
+        'coust', 'description'
+    ),
+    'string'
+), (
+    'ff.remote.connector.extra.sip2.institution',
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.sip2.institution', 
+        'LAI: SIP2 Institution (agency)',
+        'coust', 'label'
+    ),
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.sip2.institution', 
+        'SIP2 Institution (agency)',
+        'coust', 'description'
+    ),
+    'string'
+), (
+    'ff.remote.connector.extra.sip2.username',
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.sip2.username', 
+        'LAI: SIP2 login username',
+        'coust', 'label'
+    ),
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.sip2.username', 
+        'LAI: SIP2 login username',
+        'coust', 'description'
+    ),
+    'string'
+), (
+    'ff.remote.connector.extra.sip2.password',
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.sip2.password', 
+        'LAI: SIP2 login password',
+        'coust', 'label'
+    ),
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.sip2.password', 
+        'LAI: SIP2 login password',
+        'coust', 'description'
+    ),
+    'string'
+);
+
+
+INSERT INTO config.org_unit_setting_type (name, label, description, datatype)
+VALUES (
+    'ff.remote.connector.extra.z3950.host',
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.z3950.host', 
+        'LAI: Z39.50 Server Hostname',
+        'coust', 'label'
+    ),
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.z3950.host', 
+        'Z39.50 Server Hostname, if different from the default connector host',
+        'coust', 'description'
+    ),
+    'string'
+), (
+    'ff.remote.connector.extra.z3950.username',
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.z3950.username', 
+        'LAI: Z39.50 Server Username',
+        'coust', 'label'
+    ),
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.z3950.username', 
+        'Z39.50 Server Username',
+        'coust', 'description'
+    ),
+    'string'
+), (
+    'ff.remote.connector.extra.z3950.password',
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.z3950.password', 
+        'LAI: Z39.50 Server Password',
+        'coust', 'label'
+    ),
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.z3950.password', 
+        'Z39.50 Server Password',
+        'coust', 'description'
+    ),
+    'string'
+);
+
+
+INSERT INTO actor.web_action_print_template 
+    (owner, focus, direction, template) 
+    VALUES (1, 'hold', 'Outgoing', $$
+<html>
+ <head>
+  <style>
+   th { font-weight: bold; }
+  </style>
+ </head>
+ <body>
+ <h1>Outgoing ILL Request</h1>
+ <p>
+    This item has been captured for an ILL request at the 
+    lending library and is en route to the borrowing library.
+ </p>
+ <table>
+  <tr>
+   <th>Action</th>
+   <td>${action}</td>
+  </tr>
+  <tr>
+   <th>Copy Barcode</th>
+   <td>${copy.barcode}</td>
+  </tr>
+  <tr>
+   <th>Borrower Patron Barcode</th>
+   <td>${card.barcode}</td>
+  </tr>
+  <tr>
+   <th>Borrowing Library (Destination)</th>
+   <td>${transit.dest.name}</td>
+  </tr>
+  <tr>
+   <th>Transit Date</th>
+   <td>${transit.source_send_time:truncate_date}</td>
+  </tr>
+ </table>
+</body>
+$$);
+    
+-- TODO borrower copy barcode
+INSERT INTO actor.web_action_print_template 
+    (owner, focus, direction, action, template) 
+    VALUES (1, 'hold', 'Incoming', 'Check In', $$
+<html>
+ <head>
+  <style>
+   th { font-weight: bold; }
+  </style>
+ </head>
+ <body>
+ <h1>ILL Item Received</h1>
+ <p>ILL request item has arrived at the borrowing library.</p>
+ <table>
+  <tr>
+   <th>Action</th>
+   <td>Check In</td>
+  </tr>
+  <tr>
+   <th>ILL Copy Barcode</th>
+   <td>${copy.barcode}</td>
+  </tr>
+  <tr>
+   <th>Borrower Patron Barcode</th>
+   <td>${card.barcode}</td>
+  </tr>
+ </table>
+</body>
+$$);
+
+-- TODO borrower copy barcode
+INSERT INTO actor.web_action_print_template 
+    (owner, focus, direction, action, template) 
+    VALUES (1, 'circ', 'Incoming', 'Check Out', $$
+<html>
+ <head>
+  <style>
+   th { font-weight: bold; }
+  </style>
+ </head>
+ <body>
+ <h1>ILL Item Checked Out</h1>
+ <p>ILL request item has been checked out to the borrowing user.</p>
+ <table>
+  <tr>
+   <th>Action</th>
+   <td>Check Out</td>
+  </tr>
+  <tr>
+   <th>ILL Copy Barcode</th>
+   <td>${copy.barcode}</td>
+  </tr>
+  <tr>
+   <th>Borrower Patron Barcode</th>
+   <td>${card.barcode}</td>
+  </tr>
+  <tr>
+   <th>Due Date</th>
+   <td>${circ.due_date:truncate_date}</td>
+  </tr>
+  <tr>
+   <th>Transit Date</th>
+   <td>${transit.source_send_time:truncate_date}</td>
+  </tr>
+ </table>
+</body>
+$$);
+
+
+INSERT INTO actor.web_action_print_template 
+    (owner, focus, direction, action, template) 
+    VALUES (1, 'circ', 'Outgoing', 'Check In', $$
+<html>
+ <head>
+  <style>
+   th { font-weight: bold; }
+  </style>
+ </head>
+ <body>
+ <h1>ILL Item Checked In</h1>
+ <p>
+    ILL request circulation is complete.  
+    The item is now in transit back to the lending library.
+ </p>
+ <table>
+  <tr>
+   <th>Action</th>
+   <td>Check In</td>
+  </tr>
+  <tr>
+   <th>ILL Copy Barcode</th>
+   <td>${copy.barcode}</td>
+  </tr>
+  <tr>
+   <th>Borrower Patron Barcode</th>
+   <td>${card.barcode}</td>
+  </tr>
+  <tr>
+   <th>Due Date</th>
+   <td>${circ.due_date:truncate_date}</td>
+  </tr>
+  <tr>
+   <th>Lending Library (Destination)</th>
+   <td>${transit.dest.name}</td>
+  </tr>
+  <tr>
+   <th>Transit Date</th>
+   <td>${transit.source_send_time:truncate_date}</td>
+  </tr>
+ </table>
+</body>
+$$);
+
+INSERT INTO actor.web_action_print_template 
+    (owner, focus, direction, action, template) 
+    VALUES (1, 'transit', 'Incoming', 'Check In', $$
+<html>
+ <head>
+  <style>
+   th { font-weight: bold; }
+  </style>
+ </head>
+ <body>
+ <h1>ILL Item Returned Home</h1>
+ <p>
+    ILL item has transited back to the home/lending library.
+ </p>
+ <table>
+  <tr>
+   <th>Action</th>
+   <td>Check In</td>
+  </tr>
+  <tr>
+   <th>ILL Copy Barcode</th>
+   <td>${copy.barcode}</td>
+  </tr>
+  <tr>
+   <th>Transit Source</th>
+   <td>${transit.source.name}</td>
+  </tr>
+  <tr>
+   <th>Transit Date</th>
+   <td>${transit.source_send_time:truncate_date}</td>
+  </tr>
+ </table>
+</body>
+$$);
+
+
+INSERT INTO config.org_unit_setting_type (name, label, description, datatype)
+VALUES (
+    'ff.remote.connector.disabled',
+    oils_i18n_gettext(
+        'ff.remote.connector.disabled',
+        'LAI: Disable Connector',
+        'coust', 'label'
+    ),
+    oils_i18n_gettext(
+        'ff.remote.connector.disabled',
+        'If true, do not use this connector for any remote communication',
+        'coust', 'description'
+    ),
+    'bool'
+);
+
+INSERT INTO config.org_unit_setting_type (name, label, description, datatype)
+VALUES (
+    'ff.remote.connector.extra.ncip.host',
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.ncip.host',
+        'LAI: NCIP Server',
+        'coust', 'label'
+    ),
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.ncip.host',
+        'NCIP Server hostname or IP address',
+        'coust', 'description'
+    ),
+    'string'
+), (
+    'ff.remote.connector.extra.ncip.port',
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.ncip.port',
+        'LAI: NCIP Port',
+        'coust', 'label'
+    ),
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.ncip.port',
+        'NCIP Server port number',
+        'coust', 'description'
+    ),
+    'integer'
+), (
+    'ff.remote.connector.extra.ncip.protocol',
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.ncip.protocol',
+        'LAI: NCIP Connection Protocol',
+        'coust', 'label'
+    ),
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.ncip.protocol',
+        'NCIP Connection Protocol. https, http, or tcp',
+        'coust', 'description'
+    ),
+    'integer'
+), (
+    'ff.remote.connector.extra.ncip.path',
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.ncip.path',
+        'LAI: NCIP URL path.  HTTP(S) only',
+        'coust', 'label'
+    ),
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.ncip.path',
+        'NCIP URL path.  HTTP(S) only.  E.g. "/ncip/message"',
+        'coust', 'description'
+    ),
+    'string'
+), (
+    'ff.remote.connector.extra.ncip.ils_agency.name',
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.ncip.ils_agency.name',
+        'LAI: NCIP ILS Agency Name',
+        'coust', 'label'
+    ),
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.ncip.ils_agency.name',
+        'LAI: NCIP ILS Agency Name',
+        'coust', 'description'
+    ),
+    'string'
+), (
+    'ff.remote.connector.extra.ncip.ils_agency.uri',
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.ncip.ils_agency.uri',
+        'LAI: NCIP ILS Agency URI',
+        'coust', 'label'
+    ),
+    oils_i18n_gettext(
+        'ff.remote.connector.extra.ncip.ils_agency.uri',
+        'LAI: NCIP ILS Agency URI',
+        'coust', 'description'
+    ),
+    'string'
+);
+
+
+INSERT INTO actor.web_action_print_template 
+    (owner, focus, template) VALUES (1, 'copy', $$
+<html>
+ <head>
+  <style>
+   th {font-weight:bold; text-align:left}
+   td {text-align:left}
+  </style>
+ </head>
+ <body>
+ <table>
+  <tr><th>Copy Barcode</th><td>${barcode}</td></tr>
+  <tr><th>Status:</th><td>${status}</td></tr>        
+  <tr><th>Owning Lib:</th><td>${item_circ_lib}</td></tr>
+  <tr><th>Title:</th><td>${title}</td></tr>          
+  <tr><th>Author:</th><td>${author}</td></tr>        
+  <tr><th>Call Number:</th><td>${call_number}</td></tr>
+ </table>
+</body>
+$$);
+
+INSERT INTO actor.web_action_print_template 
+    (owner, focus, template) VALUES (1, 'hold', $$
+<html>
+ <head>
+  <style>
+   th {font-weight:bold; text-align:left}
+   td {text-align:left}
+  </style>
+ </head>
+ <body>
+ <table>
+  <tr><th>Copy Barcode</th><td>${barcode}</td></tr>
+  <tr><th>Status:</th><td>${status}</td></tr>        
+  <tr><th>Owning Lib:</th><td>${item_circ_lib}</td></tr>
+  <tr><th>Title:</th><td>${title}</td></tr>          
+  <tr><th>Author:</th><td>${author}</td></tr>        
+  <tr><th>Call Number:</th><td>${call_number}</td></tr>
+  <tr><th>Hold Requesting Patron:</th><td>${hold_request_usr}</td></tr>
+  <tr><th>Hold Requesting Library:</th><td>${hold_request_lib}</td></tr>
+  <tr><th>Hold Pickup Library:</th><td>${hold_pickup_lib}</td></tr>
+  <tr><th>Hold Request Date:</th><td>${hold_request_time}</td></tr>
+  <tr><th>Hold Capture Date:</th><td>${hold_capture_time}</td></tr>
+  <tr><th>Hold Cancel Date:</th><td>${hold_cancel_time}</td></tr>                                              
+  <tr><th>Hold Cancel Date:</th><td>${hold_cancel_cause}</td></tr>                                              
+  <tr><th>Transit Source:</th><td>${transit_source}</td></tr>
+  <tr><th>Transit Destination:</th><td>${transit_dest}</td></tr>
+  <tr><th>Transit Send Date:</th><td>${transit_time}</td></tr>
+  <tr><th>Transit Receive Date:</th><td>${transit_recv_time}</td></tr>
+ </table>
+</body>
+$$);
+
+INSERT INTO actor.web_action_print_template 
+    (owner, focus, template) VALUES (1, 'circ', $$
+<html>
+ <head>
+  <style>
+   th {font-weight:bold; text-align:left}
+   td {text-align:left}
+  </style>
+ </head>
+ <body>
+ <table>
+  <tr><th>Copy Barcode</th><td>${barcode}</td></tr>
+  <tr><th>Status:</th><td>${status}</td></tr>        
+  <tr><th>Owning Lib:</th><td>${item_circ_lib}</td></tr>
+  <tr><th>Title:</th><td>${title}</td></tr>          
+  <tr><th>Author:</th><td>${author}</td></tr>        
+  <tr><th>Call Number:</th><td>${call_number}</td></tr>
+  <tr><th>Circulating Library:</th><td>${circ_circ_lib}</td></tr>
+  <tr><th>Circulating Patron:</th><td>${circ_usr}</td></tr>
+  <tr><th>Checkout date:</th><td>${xact_start}</td></tr>
+  <tr><th>Due Date:</th><td>${due_date}</td></tr>
+ </table>
+</body>
+$$);
+
+INSERT INTO actor.web_action_print_template 
+    (owner, focus, template) VALUES (1, 'transit', $$
+<html>
+ <head>
+  <style>
+   th {font-weight:bold; text-align:left}
+   td {text-align:left}
+  </style>
+ </head>
+ <body>
+ <table>
+  <tr><th>Copy Barcode</th><td>${barcode}</td></tr>
+  <tr><th>Status:</th><td>${status}</td></tr>        
+  <tr><th>Owning Lib:</th><td>${item_circ_lib}</td></tr>
+  <tr><th>Title:</th><td>${title}</td></tr>          
+  <tr><th>Author:</th><td>${author}</td></tr>        
+  <tr><th>Call Number:</th><td>${call_number}</td></tr>
+  <tr><th>Transit Source:</th><td>${transit_source}</td></tr>
+  <tr><th>Transit Destination:</th><td>${transit_dest}</td></tr>
+  <tr><th>Transit Send Date:</th><td>${transit_time}</td></tr>
+  <tr><th>Transit Receive Date:</th><td>${transit_recv_time}</td></tr>
+ </table>
+</body>
+$$);
+
+COMMIT;