]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/sql/Pg/1.4.0.5-1.6.0.0-upgrade-db.sql
add 1.6 upgrade sql (and remove 2.0 stub)
[working/Evergreen.git] / Open-ILS / src / sql / Pg / 1.4.0.5-1.6.0.0-upgrade-db.sql
1 /*
2  * Copyright (C) 2009  Equinox Software, Inc.
3  * Mike Rylander <miker@esilibrary.com>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16
17
18
19 DROP SCHEMA acq CASCADE;
20 DROP SCHEMA serial CASCADE;
21
22 BEGIN;
23
24 INSERT INTO config.upgrade_log (version) VALUES ('1.6.0.0');
25  
26 CREATE TABLE config.standing_penalty (
27         id              SERIAL  PRIMARY KEY,
28         name            TEXT    NOT NULL UNIQUE,
29         label           TEXT    NOT NULL,
30         block_list      TEXT
31 );
32 INSERT INTO config.standing_penalty (id,name,label,block_list) VALUES (1,'PATRON_EXCEEDS_FINES','Patron exceeds fine threshold','CIRC|HOLD|RENEW');
33 INSERT INTO config.standing_penalty (id,name,label,block_list) VALUES (2,'PATRON_EXCEEDS_OVERDUE_COUNT','Patron exceeds max overdue item threshold','CIRC|HOLD|RENEW');
34 INSERT INTO config.standing_penalty (id,name,label,block_list) VALUES (3,'PATRON_EXCEEDS_CHECKOUT_COUNT','Patron exceeds max checked out item threshold','CIRC');
35 INSERT INTO config.standing_penalty (id,name,label,block_list) VALUES (4,'PATRON_EXCEEDS_COLLECTIONS_WARNING','Patron exceeds pre-collections warning fine threshold','CIRC|HOLD|RENEW');
36
37 INSERT INTO config.standing_penalty (id,name,label) VALUES (20,'ALERT_NOTE','Alerting Note, no blocks');
38 INSERT INTO config.standing_penalty (id,name,label) VALUES (21,'SILENT_NOTE','Note, no blocks');
39 INSERT INTO config.standing_penalty (id,name,label,block_list) VALUES (22,'STAFF_C','Alerting block on Circ','CIRC');
40 INSERT INTO config.standing_penalty (id,name,label,block_list) VALUES (23,'STAFF_CH','Alerting block on Circ and Hold','CIRC|HOLD');
41 INSERT INTO config.standing_penalty (id,name,label,block_list) VALUES (24,'STAFF_CR','Alerting block on Circ and Renew','CIRC|RENEW');
42 INSERT INTO config.standing_penalty (id,name,label,block_list) VALUES (25,'STAFF_CHR','Alerting block on Circ, Hold and Renew','CIRC|HOLD|RENEW');
43 INSERT INTO config.standing_penalty (id,name,label,block_list) VALUES (26,'STAFF_HR','Alerting block on Hold and Renew','HOLD|RENEW');
44 INSERT INTO config.standing_penalty (id,name,label,block_list) VALUES (27,'STAFF_H','Alerting block on Hold','HOLD');
45 INSERT INTO config.standing_penalty (id,name,label,block_list) VALUES (28,'STAFF_R','Alerting block on Renew','RENEW');
46
47 SELECT SETVAL('config.standing_penalty_id_seq', 100);
48
49 CREATE TABLE config.billing_type (
50     id              SERIAL  PRIMARY KEY,
51     name            TEXT    NOT NULL,
52     owner           INT     NOT NULL REFERENCES actor.org_unit (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
53     default_price   NUMERIC(6,2),
54     CONSTRAINT billing_type_once_per_lib UNIQUE (name, owner)
55 );
56
57 INSERT INTO config.billing_type (id, name, owner) VALUES ( 1, 'Overdue Materials', 1);
58 INSERT INTO config.billing_type (id, name, owner) VALUES ( 2, 'Long Overdue Collection Fee', 1);
59 INSERT INTO config.billing_type (id, name, owner) VALUES ( 3, 'Lost Materials', 1);
60 INSERT INTO config.billing_type (id, name, owner) VALUES ( 4, 'Lost Materials Processing Fee', 1);
61 INSERT INTO config.billing_type (id, name, owner) VALUES ( 5, 'System: Deposit', 1);
62 INSERT INTO config.billing_type (id, name, owner) VALUES ( 6, 'System: Rental', 1);
63 INSERT INTO config.billing_type (id, name, owner) VALUES ( 7, 'Damaged Item', 1);
64 INSERT INTO config.billing_type (id, name, owner) VALUES ( 8, 'Damaged Item Processing Fee', 1);
65 INSERT INTO config.billing_type (id, name, owner) VALUES ( 9, 'Notification Fee', 1);
66
67 SELECT SETVAL('config.billing_type_id_seq'::TEXT, 100);
68  
69 ALTER TABLE actor.usr ADD COLUMN alias TEXT;
70 ALTER TABLE actor.usr ADD COLUMN juvenile BOOL;
71 ALTER TABLE auditor.actor_usr_history ADD COLUMN alias TEXT;
72 ALTER TABLE auditor.actor_usr_history ADD COLUMN juvenile BOOL;
73
74 ALTER TABLE actor.usr ALTER COLUMN juvenile SET DEFAULT FALSE;
75 UPDATE actor.usr SET juvenile=FALSE;
76
77
78 DROP TABLE actor.usr_standing_penalty;
79 CREATE TABLE actor.usr_standing_penalty (
80         id                      SERIAL  PRIMARY KEY,
81         org_unit                INT     NOT NULL REFERENCES actor.org_unit (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
82         usr                     INT     NOT NULL REFERENCES actor.usr (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
83         standing_penalty        INT     NOT NULL REFERENCES config.standing_penalty (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
84         staff                   INT     REFERENCES actor.usr (id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
85         set_date                TIMESTAMP WITH TIME ZONE        DEFAULT NOW(),
86         stop_date               TIMESTAMP WITH TIME ZONE,
87         note                    TEXT
88 );
89 CREATE INDEX actor_usr_standing_penalty_usr_idx ON actor.usr_standing_penalty (usr);
90
91
92 ALTER TABLE actor.usr_address ADD COLUMN pending BOOL;
93 ALTER TABLE actor.usr_address ADD COLUMN replaces INT;
94 ALTER TABLE auditor.actor_usr_address_history ADD COLUMN pending BOOL;
95 ALTER TABLE auditor.actor_usr_address_history ADD COLUMN replaces INT;
96
97 ALTER TABLE actor.usr_address ALTER COLUMN pending SET DEFAULT FALSE;
98 UPDATE actor.usr_address SET pending = FALSE;
99
100
101 CREATE TABLE permission.grp_penalty_threshold (
102     id          SERIAL          PRIMARY KEY,
103     grp         INT             NOT NULL REFERENCES permission.grp_tree (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
104     org_unit    INT             NOT NULL REFERENCES actor.org_unit (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
105     penalty     INT             NOT NULL REFERENCES config.standing_penalty (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
106     threshold   NUMERIC(8,2)    NOT NULL,
107     CONSTRAINT penalty_grp_once UNIQUE (grp,penalty)
108 );
109
110 INSERT INTO permission.grp_penalty_threshold (grp,org_unit,penalty,threshold) VALUES (1,1,1,10.0);
111 INSERT INTO permission.grp_penalty_threshold (grp,org_unit,penalty,threshold) VALUES (1,1,2,10.0);
112 INSERT INTO permission.grp_penalty_threshold (grp,org_unit,penalty,threshold) VALUES (1,1,3,10.0);
113 SELECT SETVAL('permission.grp_penalty_threshold_id_seq'::TEXT, (SELECT MAX(id) FROM permission.grp_penalty_threshold));
114
115
116
117 CREATE OR REPLACE FUNCTION permission.usr_has_perm_at_nd(
118         user_id    IN INTEGER,
119         perm_code  IN TEXT
120 )
121 RETURNS SETOF INTEGER AS $$
122 --
123 -- Return a set of all the org units for which a given user has a given
124 -- permission, granted directly (not through inheritance from a parent
125 -- org unit).
126 --
127 -- The permissions apply to a minimum depth of the org unit hierarchy,
128 -- for the org unit(s) to which the user is assigned.  (They also apply
129 -- to the subordinates of those org units, but we don't report the
130 -- subordinates here.)
131 --
132 -- For purposes of this function, the permission.usr_work_ou_map table
133 -- defines which users belong to which org units.  I.e. we ignore the
134 -- home_ou column of actor.usr.
135 --
136 -- The result set may contain duplicates, which should be eliminated
137 -- by a DISTINCT clause.
138 --
139 DECLARE
140         b_super       BOOLEAN;
141         n_perm        INTEGER;
142         n_min_depth   INTEGER; 
143         n_work_ou     INTEGER;
144         n_curr_ou     INTEGER;
145         n_depth       INTEGER;
146         n_curr_depth  INTEGER;
147 BEGIN
148         --
149         -- Check for superuser
150         --
151         SELECT INTO b_super
152                 super_user
153         FROM
154                 actor.usr
155         WHERE
156                 id = user_id;
157         --
158         IF NOT FOUND THEN
159                 return;                         -- No user?  No permissions.
160         ELSIF b_super THEN
161                 --
162                 -- Super user has all permissions everywhere
163                 --
164                 FOR n_work_ou IN
165                         SELECT
166                                 id
167                         FROM
168                                 actor.org_unit
169                         WHERE
170                                 parent_ou IS NULL
171                 LOOP
172                         RETURN NEXT n_work_ou; 
173                 END LOOP;
174                 RETURN;
175         END IF;
176         --
177         -- Translate the permission name
178         -- to a numeric permission id
179         --
180         SELECT INTO n_perm
181                 id
182         FROM
183                 permission.perm_list
184         WHERE
185                 code = perm_code;
186         --
187         IF NOT FOUND THEN
188                 RETURN;               -- No such permission
189         END IF;
190         --
191         -- Find the highest-level org unit (i.e. the minimum depth)
192         -- to which the permission is applied for this user
193         --
194         -- This query is modified from the one in permission.usr_perms().
195         --
196         SELECT INTO n_min_depth
197                 min( depth )
198         FROM    (
199                 SELECT depth 
200                   FROM permission.usr_perm_map upm
201                  WHERE upm.usr = user_id 
202                    AND upm.perm = n_perm
203                                 UNION
204                 SELECT  gpm.depth
205                   FROM  permission.grp_perm_map gpm
206                   WHERE gpm.perm = n_perm 
207                 AND gpm.grp IN (
208                            SELECT       (permission.grp_ancestors(
209                                         (SELECT profile FROM actor.usr WHERE id = user_id)
210                                 )).id
211                         )
212                                 UNION
213                 SELECT  p.depth
214                   FROM  permission.grp_perm_map p 
215                   WHERE p.perm = n_perm
216                     AND p.grp IN (
217                                 SELECT (permission.grp_ancestors(m.grp)).id 
218                                 FROM   permission.usr_grp_map m
219                                 WHERE  m.usr = user_id
220                         )
221         ) AS x;
222         --
223         IF NOT FOUND THEN
224                 RETURN;                -- No such permission for this user
225         END IF;
226         --
227         -- Identify the org units to which the user is assigned.  Note that
228         -- we pay no attention to the home_ou column in actor.usr.
229         --
230         FOR n_work_ou IN
231                 SELECT
232                         work_ou
233                 FROM
234                         permission.usr_work_ou_map
235                 WHERE
236                         usr = user_id
237         LOOP            -- For each org unit to which the user is assigned
238                 --
239                 -- Determine the level of the org unit by a lookup in actor.org_unit_type.
240                 -- We take it on faith that this depth agrees with the actual hierarchy
241                 -- defined in actor.org_unit.
242                 --
243                 SELECT INTO n_depth
244                     type.depth
245                 FROM
246                     actor.org_unit_type type
247                         INNER JOIN actor.org_unit ou
248                             ON ( ou.ou_type = type.id )
249                 WHERE
250                     ou.id = n_work_ou;
251                 --
252                 IF NOT FOUND THEN
253                         CONTINUE;        -- Maybe raise exception?
254                 END IF;
255                 --
256                 -- Compare the depth of the work org unit to the
257                 -- minimum depth, and branch accordingly
258                 --
259                 IF n_depth = n_min_depth THEN
260                         --
261                         -- The org unit is at the right depth, so return it.
262                         --
263                         RETURN NEXT n_work_ou;
264                 ELSIF n_depth > n_min_depth THEN
265                         --
266                         -- Traverse the org unit tree toward the root,
267                         -- until you reach the minimum depth determined above
268                         --
269                         n_curr_depth := n_depth;
270                         n_curr_ou := n_work_ou;
271                         WHILE n_curr_depth > n_min_depth LOOP
272                                 SELECT INTO n_curr_ou
273                                         parent_ou
274                                 FROM
275                                         actor.org_unit
276                                 WHERE
277                                         id = n_curr_ou;
278                                 --
279                                 IF FOUND THEN
280                                         n_curr_depth := n_curr_depth - 1;
281                                 ELSE
282                                         --
283                                         -- This can happen only if the hierarchy defined in
284                                         -- actor.org_unit is corrupted, or out of sync with
285                                         -- the depths defined in actor.org_unit_type.
286                                         -- Maybe we should raise an exception here, instead
287                                         -- of silently ignoring the problem.
288                                         --
289                                         n_curr_ou = NULL;
290                                         EXIT;
291                                 END IF;
292                         END LOOP;
293                         --
294                         IF n_curr_ou IS NOT NULL THEN
295                                 RETURN NEXT n_curr_ou;
296                         END IF;
297                 ELSE
298                         --
299                         -- The permission applies only at a depth greater than the work org unit.
300                         -- Use connectby() to find all dependent org units at the specified depth.
301                         --
302                         FOR n_curr_ou IN
303                                 SELECT ou::INTEGER
304                                 FROM connectby( 
305                                                 'actor.org_unit',         -- table name
306                                                 'id',                     -- key column
307                                                 'parent_ou',              -- recursive foreign key
308                                                 n_work_ou::TEXT,          -- id of starting point
309                                                 (n_min_depth - n_depth)   -- max depth to search, relative
310                                         )                             --   to starting point
311                                         AS t(
312                                                 ou text,            -- dependent org unit
313                                                 parent_ou text,     -- (ignore)
314                                                 level int           -- depth relative to starting point
315                                         )
316                                 WHERE
317                                         level = n_min_depth - n_depth
318                         LOOP
319                                 RETURN NEXT n_curr_ou;
320                         END LOOP;
321                 END IF;
322                 --
323         END LOOP;
324         --
325         RETURN;
326         --
327 END;
328 $$ LANGUAGE 'plpgsql';
329
330
331 CREATE OR REPLACE FUNCTION permission.usr_has_perm_at_all_nd(
332         user_id    IN INTEGER,
333         perm_code  IN TEXT
334 )
335 RETURNS SETOF INTEGER AS $$
336 --
337 -- Return a set of all the org units for which a given user has a given
338 -- permission, granted either directly or through inheritance from a parent
339 -- org unit.
340 --
341 -- The permissions apply to a minimum depth of the org unit hierarchy, and
342 -- to the subordinates of those org units, for the org unit(s) to which the
343 -- user is assigned.
344 --
345 -- For purposes of this function, the permission.usr_work_ou_map table
346 -- assigns users to org units.  I.e. we ignore the home_ou column of actor.usr.
347 --
348 -- The result set may contain duplicates, which should be eliminated
349 -- by a DISTINCT clause.
350 --
351 DECLARE
352         n_head_ou     INTEGER;
353         n_child_ou    INTEGER;
354 BEGIN
355         FOR n_head_ou IN
356                 SELECT DISTINCT * FROM permission.usr_has_perm_at_nd( user_id, perm_code )
357         LOOP
358                 --
359                 -- The permission applies only at a depth greater than the work org unit.
360                 -- Use connectby() to find all dependent org units at the specified depth.
361                 --
362                 FOR n_child_ou IN
363                         SELECT ou::INTEGER
364                         FROM connectby( 
365                                         'actor.org_unit',   -- table name
366                                         'id',               -- key column
367                                         'parent_ou',        -- recursive foreign key
368                                         n_head_ou::TEXT,    -- id of starting point
369                                         0                   -- no limit on search depth
370                                 )
371                                 AS t(
372                                         ou text,            -- dependent org unit
373                                         parent_ou text,     -- (ignore)
374                                         level int           -- (ignore)
375                                 )
376                 LOOP
377                         RETURN NEXT n_child_ou;
378                 END LOOP;
379         END LOOP;
380         --
381         RETURN;
382         --
383 END;
384 $$ LANGUAGE 'plpgsql';
385
386
387 CREATE OR REPLACE FUNCTION permission.usr_has_perm_at(
388         user_id    IN INTEGER,
389         perm_code  IN TEXT
390 )
391 RETURNS SETOF INTEGER AS $$
392 SELECT DISTINCT * FROM permission.usr_has_perm_at_nd( $1, $2 );
393 $$ LANGUAGE 'sql';
394
395
396 CREATE OR REPLACE FUNCTION permission.usr_has_perm_at_all(
397         user_id    IN INTEGER,
398         perm_code  IN TEXT
399 )
400 RETURNS SETOF INTEGER AS $$
401 SELECT DISTINCT * FROM permission.usr_has_perm_at_all_nd( $1, $2 );
402 $$ LANGUAGE 'sql';
403
404
405
406 CREATE OR REPLACE FUNCTION vandelay.ingest_items ( import_id BIGINT, attr_def_id BIGINT ) RETURNS SETOF vandelay.import_item AS $$
407 DECLARE
408
409     owning_lib      TEXT;
410     circ_lib        TEXT;
411     call_number     TEXT;
412     copy_number     TEXT;
413     status          TEXT;
414     location        TEXT;
415     circulate       TEXT;
416     deposit         TEXT;
417     deposit_amount  TEXT;
418     ref             TEXT;
419     holdable        TEXT;
420     price           TEXT;
421     barcode         TEXT;
422     circ_modifier   TEXT;
423     circ_as_type    TEXT;
424     alert_message   TEXT;
425     opac_visible    TEXT;
426     pub_note        TEXT;
427     priv_note       TEXT;
428
429     attr_def        RECORD;
430     tmp_attr_set    RECORD;
431     attr_set        vandelay.import_item%ROWTYPE;
432
433     xpath           TEXT;
434
435 BEGIN
436
437     SELECT * INTO attr_def FROM vandelay.import_item_attr_definition WHERE id = attr_def_id;
438
439     IF FOUND THEN
440
441         attr_set.definition := attr_def.id;
442
443         -- Build the combined XPath
444
445         owning_lib :=
446             CASE
447                 WHEN attr_def.owning_lib IS NULL THEN 'null()'
448                 WHEN LENGTH( attr_def.owning_lib ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.owning_lib || '"]'
449                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.owning_lib
450             END;
451
452         circ_lib :=
453             CASE
454                 WHEN attr_def.circ_lib IS NULL THEN 'null()'
455                 WHEN LENGTH( attr_def.circ_lib ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circ_lib || '"]'
456                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circ_lib
457             END;
458
459         call_number :=
460             CASE
461                 WHEN attr_def.call_number IS NULL THEN 'null()'
462                 WHEN LENGTH( attr_def.call_number ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.call_number || '"]'
463                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.call_number
464             END;
465
466         copy_number :=
467             CASE
468                 WHEN attr_def.copy_number IS NULL THEN 'null()'
469                 WHEN LENGTH( attr_def.copy_number ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.copy_number || '"]'
470                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.copy_number
471             END;
472
473         status :=
474             CASE
475                 WHEN attr_def.status IS NULL THEN 'null()'
476                 WHEN LENGTH( attr_def.status ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.status || '"]'
477                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.status
478             END;
479
480         location :=
481             CASE
482                 WHEN attr_def.location IS NULL THEN 'null()'
483                 WHEN LENGTH( attr_def.location ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.location || '"]'
484                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.location
485             END;
486
487         circulate :=
488             CASE
489                 WHEN attr_def.circulate IS NULL THEN 'null()'
490                 WHEN LENGTH( attr_def.circulate ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circulate || '"]'
491                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circulate
492             END;
493
494         deposit :=
495             CASE
496                 WHEN attr_def.deposit IS NULL THEN 'null()'
497                 WHEN LENGTH( attr_def.deposit ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.deposit || '"]'
498                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.deposit
499             END;
500
501         deposit_amount :=
502             CASE
503                 WHEN attr_def.deposit_amount IS NULL THEN 'null()'
504                 WHEN LENGTH( attr_def.deposit_amount ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.deposit_amount || '"]'
505                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.deposit_amount
506             END;
507
508         ref :=
509             CASE
510                 WHEN attr_def.ref IS NULL THEN 'null()'
511                 WHEN LENGTH( attr_def.ref ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.ref || '"]'
512                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.ref
513             END;
514
515         holdable :=
516             CASE
517                 WHEN attr_def.holdable IS NULL THEN 'null()'
518                 WHEN LENGTH( attr_def.holdable ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.holdable || '"]'
519                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.holdable
520             END;
521
522         price :=
523             CASE
524                 WHEN attr_def.price IS NULL THEN 'null()'
525                 WHEN LENGTH( attr_def.price ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.price || '"]'
526                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.price
527             END;
528
529         barcode :=
530             CASE
531                 WHEN attr_def.barcode IS NULL THEN 'null()'
532                 WHEN LENGTH( attr_def.barcode ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.barcode || '"]'
533                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.barcode
534             END;
535
536         circ_modifier :=
537             CASE
538                 WHEN attr_def.circ_modifier IS NULL THEN 'null()'
539                 WHEN LENGTH( attr_def.circ_modifier ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circ_modifier || '"]'
540                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circ_modifier
541             END;
542
543         circ_as_type :=
544             CASE
545                 WHEN attr_def.circ_as_type IS NULL THEN 'null()'
546                 WHEN LENGTH( attr_def.circ_as_type ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circ_as_type || '"]'
547                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circ_as_type
548             END;
549
550         alert_message :=
551             CASE
552                 WHEN attr_def.alert_message IS NULL THEN 'null()'
553                 WHEN LENGTH( attr_def.alert_message ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.alert_message || '"]'
554                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.alert_message
555             END;
556
557         opac_visible :=
558             CASE
559                 WHEN attr_def.opac_visible IS NULL THEN 'null()'
560                 WHEN LENGTH( attr_def.opac_visible ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.opac_visible || '"]'
561                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.opac_visible
562             END;
563
564         pub_note :=
565             CASE
566                 WHEN attr_def.pub_note IS NULL THEN 'null()'
567                 WHEN LENGTH( attr_def.pub_note ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.pub_note || '"]'
568                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.pub_note
569             END;
570         priv_note :=
571             CASE
572                 WHEN attr_def.priv_note IS NULL THEN 'null()'
573                 WHEN LENGTH( attr_def.priv_note ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.priv_note || '"]'
574                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.priv_note
575             END;
576
577
578         xpath :=
579             owning_lib      || '|' ||
580             circ_lib        || '|' ||
581             call_number     || '|' ||
582             copy_number     || '|' ||
583             status          || '|' ||
584             location        || '|' ||
585             circulate       || '|' ||
586             deposit         || '|' ||
587             deposit_amount  || '|' ||
588             ref             || '|' ||
589             holdable        || '|' ||
590             price           || '|' ||
591             barcode         || '|' ||
592             circ_modifier   || '|' ||
593             circ_as_type    || '|' ||
594             alert_message   || '|' ||
595             pub_note        || '|' ||
596             priv_note       || '|' ||
597             opac_visible;
598
599         -- RAISE NOTICE 'XPath: %', xpath;
600
601         FOR tmp_attr_set IN
602                 SELECT  *
603                   FROM  xpath_table( 'id', 'marc', 'vandelay.queued_bib_record', xpath, 'id = ' || import_id )
604                             AS t( id BIGINT, ol TEXT, clib TEXT, cn TEXT, cnum TEXT, cs TEXT, cl TEXT, circ TEXT,
605                                   dep TEXT, dep_amount TEXT, r TEXT, hold TEXT, pr TEXT, bc TEXT, circ_mod TEXT,
606                                   circ_as TEXT, amessage TEXT, note TEXT, pnote TEXT, opac_vis TEXT )
607         LOOP
608
609             tmp_attr_set.pr = REGEXP_REPLACE(tmp_attr_set.pr, E'[^0-9\\.]', '', 'g');
610             tmp_attr_set.dep_amount = REGEXP_REPLACE(tmp_attr_set.dep_amount, E'[^0-9\\.]', '', 'g');
611
612             tmp_attr_set.pr := NULLIF( tmp_attr_set.pr, '' );
613             tmp_attr_set.dep_amount := NULLIF( tmp_attr_set.dep_amount, '' );
614
615             SELECT id INTO attr_set.owning_lib FROM actor.org_unit WHERE shortname = UPPER(tmp_attr_set.ol); -- INT
616             SELECT id INTO attr_set.circ_lib FROM actor.org_unit WHERE shortname = UPPER(tmp_attr_set.clib); -- INT
617             SELECT id INTO attr_set.status FROM config.copy_status WHERE LOWER(name) = LOWER(tmp_attr_set.cs); -- INT
618
619             SELECT  id INTO attr_set.location
620               FROM  asset.copy_location
621               WHERE LOWER(name) = LOWER(tmp_attr_set.cl)
622                     AND asset.copy_location.owning_lib = COALESCE(attr_set.owning_lib, attr_set.circ_lib); -- INT
623
624             attr_set.circulate      :=
625                 LOWER( SUBSTRING( tmp_attr_set.circ, 1, 1)) IN ('t','y','1')
626                 OR LOWER(tmp_attr_set.circ) = 'circulating'; -- BOOL
627
628             attr_set.deposit        :=
629                 LOWER( SUBSTRING( tmp_attr_set.dep, 1, 1 ) ) IN ('t','y','1')
630                 OR LOWER(tmp_attr_set.dep) = 'deposit'; -- BOOL
631
632             attr_set.holdable       :=
633                 LOWER( SUBSTRING( tmp_attr_set.hold, 1, 1 ) ) IN ('t','y','1')
634                 OR LOWER(tmp_attr_set.hold) = 'holdable'; -- BOOL
635
636             attr_set.opac_visible   :=
637                 LOWER( SUBSTRING( tmp_attr_set.opac_vis, 1, 1 ) ) IN ('t','y','1')
638                 OR LOWER(tmp_attr_set.opac_vis) = 'visible'; -- BOOL
639
640             attr_set.ref            :=
641                 LOWER( SUBSTRING( tmp_attr_set.r, 1, 1 ) ) IN ('t','y','1')
642                 OR LOWER(tmp_attr_set.r) = 'reference'; -- BOOL
643
644             attr_set.copy_number    := tmp_attr_set.cnum::INT; -- INT,
645             attr_set.deposit_amount := tmp_attr_set.dep_amount::NUMERIC(6,2); -- NUMERIC(6,2),
646             attr_set.price          := tmp_attr_set.pr::NUMERIC(8,2); -- NUMERIC(8,2),
647
648             attr_set.call_number    := tmp_attr_set.cn; -- TEXT
649             attr_set.barcode        := tmp_attr_set.bc; -- TEXT,
650             attr_set.circ_modifier  := tmp_attr_set.circ_mod; -- TEXT,
651             attr_set.circ_as_type   := tmp_attr_set.circ_as; -- TEXT,
652             attr_set.alert_message  := tmp_attr_set.amessage; -- TEXT,
653             attr_set.pub_note       := tmp_attr_set.note; -- TEXT,
654             attr_set.priv_note      := tmp_attr_set.pnote; -- TEXT,
655             attr_set.alert_message  := tmp_attr_set.amessage; -- TEXT,
656
657             RETURN NEXT attr_set;
658
659         END LOOP;
660
661     END IF;
662
663 END;
664 $$ LANGUAGE PLPGSQL;
665
666 CREATE OR REPLACE FUNCTION actor.org_unit_ancestors ( INT ) RETURNS SETOF actor.org_unit AS $$
667         SELECT  a.*
668           FROM  connectby('actor.org_unit'::text,'parent_ou'::text,'id'::text,'name'::text,$1::text,100,'.'::text)
669                         AS t(keyid text, parent_keyid text, level int, branch text,pos int)
670                 JOIN actor.org_unit a ON a.id::text = t.keyid::text
671         JOIN actor.org_unit_type tp ON tp.id = a.ou_type
672         ORDER BY tp.depth, a.name;
673 $$ LANGUAGE SQL STABLE;
674
675 CREATE OR REPLACE FUNCTION actor.org_unit_ancestor_setting( setting_name TEXT, org_id INT ) RETURNS SETOF actor.org_unit_setting AS $$
676 DECLARE
677     setting RECORD;
678     cur_org INT;
679 BEGIN
680     cur_org := org_id;
681     LOOP
682         SELECT INTO setting * FROM actor.org_unit_setting WHERE org_unit = cur_org AND name = setting_name;
683         IF FOUND THEN
684             RETURN NEXT setting;
685         END IF;
686         SELECT INTO cur_org parent_ou FROM actor.org_unit WHERE id = cur_org;
687         EXIT WHEN cur_org IS NULL;
688     END LOOP;
689     RETURN;
690 END;
691 $$ LANGUAGE plpgsql;
692
693 COMMENT ON FUNCTION actor.org_unit_ancestor_setting( TEXT, INT) IS $$
694 /**
695 * Search "up" the org_unit tree until we find the first occurrence of an 
696 * org_unit_setting with the given name.
697 */
698 $$;
699  
700
701 ALTER TABLE asset.copy_tranparency_map RENAME TO copy_transparency_map;
702 ALTER TABLE asset.copy_tranparency_map RENAME COLUMN tansparency TO transparency;
703
704 CREATE TABLE asset.uri (
705     id  SERIAL  PRIMARY KEY,
706     href    TEXT    NOT NULL,
707     label   TEXT,
708     use_restriction TEXT,
709     active  BOOL    NOT NULL DEFAULT TRUE
710 );
711
712 CREATE TABLE asset.uri_call_number_map (
713     id          BIGSERIAL   PRIMARY KEY,
714     uri         INT         NOT NULL REFERENCES asset.uri (id),
715     call_number INT         NOT NULL REFERENCES asset.call_number (id),
716     CONSTRAINT uri_cn_once UNIQUE (uri,call_number)
717 );
718 CREATE INDEX asset_uri_call_number_map_cn_idx ON asset.uri_call_number_map (call_number);
719
720 -----------------------------
721
722 CREATE TABLE container.copy_bucket_type (
723         code    TEXT    PRIMARY KEY,
724         label   TEXT    NOT NULL UNIQUE
725 );
726
727
728 CREATE TABLE container.copy_bucket_note (
729     id      SERIAL      PRIMARY KEY,
730     bucket  INT         NOT NULL REFERENCES container.copy_bucket (id) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED,
731     note    TEXT        NOT NULL
732 );
733
734 ALTER TABLE container.copy_bucket_item ADD COLUMN pos INT;
735 CREATE INDEX copy_bucket_item_bucket_idx ON container.copy_bucket_item (bucket);
736
737 CREATE TABLE container.copy_bucket_item_note (
738     id      SERIAL      PRIMARY KEY,
739     item    INT         NOT NULL REFERENCES container.copy_bucket_item (id) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED,
740     note    TEXT        NOT NULL
741 );
742  
743 ----------------------------- 
744  
745 CREATE TABLE container.call_number_bucket_type (
746         code    TEXT    PRIMARY KEY,
747         label   TEXT    NOT NULL UNIQUE
748 );
749  
750 ALTER TABLE container.call_number_bucket_item ADD COLUMN pos INT;
751 CREATE INDEX call_number_bucket_item_bucket_idx ON container.call_number_bucket_item (bucket);
752
753 CREATE TABLE container.call_number_bucket_note (
754     id      SERIAL      PRIMARY KEY,
755     bucket  INT         NOT NULL REFERENCES container.call_number_bucket (id) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED,
756     note    TEXT        NOT NULL
757 );
758
759
760 CREATE TABLE container.call_number_bucket_item_note (
761     id      SERIAL      PRIMARY KEY,
762     item    INT         NOT NULL REFERENCES container.call_number_bucket_item (id) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED,
763     note    TEXT        NOT NULL
764 );
765
766 ---------------------------
767  
768 CREATE TABLE container.biblio_record_entry_bucket_type (
769         code    TEXT    PRIMARY KEY,
770         label   TEXT    NOT NULL UNIQUE
771 );
772
773
774 CREATE TABLE container.biblio_record_entry_bucket_note (
775     id      SERIAL      PRIMARY KEY,
776     bucket  INT         NOT NULL REFERENCES container.biblio_record_entry_bucket (id) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED,
777     note    TEXT        NOT NULL
778 );
779
780 ALTER TABLE container.biblio_record_entry_bucket_item ADD COLUMN pos INT;
781 CREATE INDEX biblio_record_entry_bucket_item_bucket_idx ON container.biblio_record_entry_bucket_item (bucket);
782
783 CREATE TABLE container.biblio_record_entry_bucket_item_note (
784     id      SERIAL      PRIMARY KEY,
785     item    INT         NOT NULL REFERENCES container.biblio_record_entry_bucket_item (id) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED,
786     note    TEXT        NOT NULL
787 );
788
789 ---------------------------
790  
791 CREATE TABLE container.user_bucket_type (
792         code    TEXT    PRIMARY KEY,
793         label   TEXT    NOT NULL UNIQUE
794 );
795  
796 CREATE TABLE container.user_bucket_note (
797     id      SERIAL      PRIMARY KEY,
798     bucket  INT         NOT NULL REFERENCES container.user_bucket (id) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED,
799     note    TEXT        NOT NULL
800 );
801
802 ALTER TABLE container.user_bucket_item ADD COLUMN pos INT;
803 CREATE INDEX user_bucket_item_bucket_idx ON container.user_bucket_item (bucket);
804
805 CREATE TABLE container.user_bucket_item_note (
806     id      SERIAL      PRIMARY KEY,
807     item    INT         NOT NULL REFERENCES container.user_bucket_item (id) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED,
808     note    TEXT        NOT NULL
809 );
810
811 -----------------------------
812
813 INSERT INTO config.billing_type (name,owner) SELECT DISTINCT billing_type, 1 FROM money.billing WHERE billing_type NOT IN (SELECT name FROM config.billing_type);
814 ALTER TABLE money.billing ADD COLUMN btype INT;
815
816 UPDATE money.billing SET btype = config.billing_type.id FROM config.billing_type WHERE config.billing_type.name = money.billing.billing_type;
817 ALTER TABLE money.billing ALTER COLUMN btype SET NOT NULL;
818 ALTER TABLE money.billing ADD CONSTRAINT btype_fkey FOREIGN KEY (btype) REFERENCES config.billing_type (id) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED;
819
820
821 CREATE TABLE money.materialized_billable_xact_summary AS
822         SELECT * FROM money.billable_xact_summary WHERE 1=0;
823
824 CREATE INDEX money_mat_summary_id_idx ON money.materialized_billable_xact_summary (id);
825 CREATE INDEX money_mat_summary_usr_idx ON money.materialized_billable_xact_summary (usr);
826 CREATE INDEX money_mat_summary_xact_start_idx ON money.materialized_billable_xact_summary (xact_start);
827
828 /* AFTER trigger only! */
829 CREATE OR REPLACE FUNCTION money.mat_summary_create () RETURNS TRIGGER AS $$
830 BEGIN
831         INSERT INTO money.materialized_billable_xact_summary (id, usr, xact_start, xact_finish, total_paid, total_owed, balance_owed)
832                 VALUES ( NEW.id, NEW.usr, NEW.xact_start, NEW.xact_finish, 0.0, 0.0, 0.0);
833         RETURN NEW;
834 END;
835 $$ LANGUAGE PLPGSQL;
836
837 /* BEFORE or AFTER trigger only! */
838 CREATE OR REPLACE FUNCTION money.mat_summary_update () RETURNS TRIGGER AS $$
839 BEGIN
840         UPDATE  money.materialized_billable_xact_summary
841           SET   usr = NEW.usr,
842                 xact_start = NEW.xact_start,
843                 xact_finish = NEW.xact_finish
844           WHERE id = NEW.id;
845         RETURN NEW;
846 END;
847 $$ LANGUAGE PLPGSQL;
848
849 /* AFTER trigger only! */
850 CREATE OR REPLACE FUNCTION money.mat_summary_delete () RETURNS TRIGGER AS $$
851 BEGIN
852         DELETE FROM money.materialized_billable_xact_summary WHERE id = OLD.id;
853         RETURN OLD;
854 END;
855 $$ LANGUAGE PLPGSQL;
856
857 CREATE TRIGGER mat_summary_create_tgr AFTER INSERT ON money.grocery FOR EACH ROW EXECUTE PROCEDURE money.mat_summary_create ();
858 CREATE TRIGGER mat_summary_change_tgr AFTER UPDATE ON money.grocery FOR EACH ROW EXECUTE PROCEDURE money.mat_summary_update ();
859 CREATE TRIGGER mat_summary_remove_tgr AFTER DELETE ON money.grocery FOR EACH ROW EXECUTE PROCEDURE money.mat_summary_delete ();
860
861
862
863 /* BEFORE or AFTER trigger */
864 CREATE OR REPLACE FUNCTION money.materialized_summary_billing_add () RETURNS TRIGGER AS $$
865 BEGIN
866         IF NOT NEW.voided THEN
867                 UPDATE  money.materialized_billable_xact_summary
868                   SET   total_owed = total_owed + NEW.amount,
869                         last_billing_ts = NEW.billing_ts,
870                         last_billing_note = NEW.note,
871                         last_billing_type = NEW.billing_type,
872                         balance_owed = balance_owed + NEW.amount
873                   WHERE id = NEW.xact;
874         END IF;
875
876         RETURN NEW;
877 END;
878 $$ LANGUAGE PLPGSQL;
879
880 /* AFTER trigger only! */
881 CREATE OR REPLACE FUNCTION money.materialized_summary_billing_update () RETURNS TRIGGER AS $$
882 DECLARE
883         old_billing     money.billing%ROWTYPE;
884         old_voided      money.billing%ROWTYPE;
885 BEGIN
886
887         SELECT * INTO old_billing FROM money.billing WHERE xact = NEW.xact AND NOT voided ORDER BY billing_ts DESC LIMIT 1;
888         SELECT * INTO old_voided FROM money.billing WHERE xact = NEW.xact ORDER BY billing_ts DESC LIMIT 1;
889
890         IF NEW.voided AND NOT OLD.voided THEN
891                 IF OLD.id = old_voided.id THEN
892                         UPDATE  money.materialized_billable_xact_summary
893                           SET   last_billing_ts = old_billing.billing_ts,
894                                 last_billing_note = old_billing.note,
895                                 last_billing_type = old_billing.billing_type
896                           WHERE id = OLD.xact;
897                 END IF;
898
899                 UPDATE  money.materialized_billable_xact_summary
900                   SET   total_owed = total_owed - NEW.amount,
901                         balance_owed = balance_owed - NEW.amount
902                   WHERE id = NEW.xact;
903
904         ELSIF NOT NEW.voided AND OLD.voided THEN
905
906                 IF OLD.id = old_billing.id THEN
907                         UPDATE  money.materialized_billable_xact_summary
908                           SET   last_billing_ts = old_billing.billing_ts,
909                                 last_billing_note = old_billing.note,
910                                 last_billing_type = old_billing.billing_type
911                           WHERE id = OLD.xact;
912                 END IF;
913
914                 UPDATE  money.materialized_billable_xact_summary
915                   SET   total_owed = total_owed + NEW.amount,
916                         balance_owed = balance_owed + NEW.amount
917                   WHERE id = NEW.xact;
918
919         ELSE
920                 UPDATE  money.materialized_billable_xact_summary
921                   SET   total_owed = total_owed - (OLD.amount - NEW.amount),
922                         balance_owed = balance_owed - (OLD.amount - NEW.amount)
923                   WHERE id = NEW.xact;
924         END IF;
925
926         RETURN NEW;
927 END;
928 $$ LANGUAGE PLPGSQL;
929
930 /* BEFORE trigger only! */
931 CREATE OR REPLACE FUNCTION money.materialized_summary_billing_del () RETURNS TRIGGER AS $$
932 DECLARE
933         prev_billing    money.billing%ROWTYPE;
934         old_billing     money.billing%ROWTYPE;
935 BEGIN
936         SELECT * INTO prev_billing FROM money.billing WHERE xact = OLD.xact AND NOT voided ORDER BY billing_ts DESC LIMIT 1 OFFSET 1;
937         SELECT * INTO old_billing FROM money.billing WHERE xact = OLD.xact AND NOT voided ORDER BY billing_ts DESC LIMIT 1;
938
939         IF OLD.id = old_billing.id THEN
940                 UPDATE  money.materialized_billable_xact_summary
941                   SET   last_billing_ts = prev_billing.billing_ts,
942                         last_billing_note = prev_billing.note,
943                         last_billing_type = prev_billing.billing_type
944                   WHERE id = NEW.xact;
945         END IF;
946
947         IF NOT OLD.voided THEN
948                 UPDATE  money.materialized_billable_xact_summary
949                   SET   total_owed = total_owed - OLD.amount,
950                         balance_owed = balance_owed + OLD.amount
951                   WHERE id = OLD.xact;
952         END IF;
953
954         RETURN OLD;
955 END;
956 $$ LANGUAGE PLPGSQL;
957
958 CREATE TRIGGER mat_summary_add_tgr AFTER INSERT ON money.billing FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_billing_add ();
959 CREATE TRIGGER mat_summary_upd_tgr AFTER UPDATE ON money.billing FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_billing_update ();
960 CREATE TRIGGER mat_summary_del_tgr BEFORE DELETE ON money.billing FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_billing_del ();
961
962
963 /* BEFORE or AFTER trigger */
964 CREATE OR REPLACE FUNCTION money.materialized_summary_payment_add () RETURNS TRIGGER AS $$
965 BEGIN
966         IF NOT NEW.voided THEN
967                 UPDATE  money.materialized_billable_xact_summary
968                   SET   total_paid = total_paid + NEW.amount,
969                         last_payment_ts = NEW.payment_ts,
970                         last_payment_note = NEW.note,
971                         last_payment_type = TG_ARGV[0],
972                         balance_owed = balance_owed - NEW.amount
973                   WHERE id = NEW.xact;
974         END IF;
975
976         RETURN NEW;
977 END;
978 $$ LANGUAGE PLPGSQL;
979
980 /* AFTER trigger only! */
981 CREATE OR REPLACE FUNCTION money.materialized_summary_payment_update () RETURNS TRIGGER AS $$
982 DECLARE
983         old_payment     money.payment_view%ROWTYPE;
984         old_voided      money.payment_view%ROWTYPE;
985 BEGIN
986
987         SELECT * INTO old_payment FROM money.payment_view WHERE xact = NEW.xact AND NOT voided ORDER BY payment_ts DESC LIMIT 1;
988         SELECT * INTO old_voided FROM money.payment_view WHERE xact = NEW.xact ORDER BY payment_ts DESC LIMIT 1;
989
990         IF NEW.voided AND NOT OLD.voided THEN
991                 IF OLD.id = old_voided.id THEN
992                         UPDATE  money.materialized_billable_xact_summary
993                           SET   last_payment_ts = old_payment.payment_ts,
994                                 last_payment_note = old_payment.note,
995                                 last_payment_type = old_payment.payment_type
996                           WHERE id = OLD.xact;
997                 END IF;
998
999                 UPDATE  money.materialized_billable_xact_summary
1000                   SET   total_paid = total_paid - NEW.amount,
1001                         balance_owed = balance_owed + NEW.amount
1002                   WHERE id = NEW.xact;
1003
1004         ELSIF NOT NEW.voided AND OLD.voided THEN
1005
1006                 IF OLD.id = old_payment.id THEN
1007                         UPDATE  money.materialized_billable_xact_summary
1008                           SET   last_payment_ts = old_payment.payment_ts,
1009                                 last_payment_note = old_payment.note,
1010                                 last_payment_type = old_payment.payment_type
1011                           WHERE id = OLD.xact;
1012                 END IF;
1013
1014                 UPDATE  money.materialized_billable_xact_summary
1015                   SET   total_paid = total_paid + NEW.amount,
1016                         balance_owed = balance_owed - NEW.amount
1017                   WHERE id = NEW.xact;
1018
1019         ELSE
1020                 UPDATE  money.materialized_billable_xact_summary
1021                   SET   total_paid = total_paid - (OLD.amount - NEW.amount),
1022                         balance_owed = balance_owed + (OLD.amount - NEW.amount)
1023                   WHERE id = NEW.xact;
1024         END IF;
1025
1026         RETURN NEW;
1027 END;
1028 $$ LANGUAGE PLPGSQL;
1029
1030 /* BEFORE trigger only! */
1031 CREATE OR REPLACE FUNCTION money.materialized_summary_payment_del () RETURNS TRIGGER AS $$
1032 DECLARE
1033         prev_payment    money.payment_view%ROWTYPE;
1034         old_payment     money.payment_view%ROWTYPE;
1035 BEGIN
1036         SELECT * INTO prev_payment FROM money.payment_view WHERE xact = OLD.xact AND NOT voided ORDER BY payment_ts DESC LIMIT 1 OFFSET 1;
1037         SELECT * INTO old_payment FROM money.payment_view WHERE xact = OLD.xact AND NOT voided ORDER BY payment_ts DESC LIMIT 1;
1038
1039         IF OLD.id = old_payment.id THEN
1040                 UPDATE  money.materialized_billable_xact_summary
1041                   SET   last_payment_ts = prev_payment.payment_ts,
1042                         last_payment_note = prev_payment.note,
1043                         last_payment_type = prev_payment.payment_type
1044                   WHERE id = OLD.xact;
1045         END IF;
1046
1047         IF NOT OLD.voided THEN
1048                 UPDATE  money.materialized_billable_xact_summary
1049                   SET   total_paid = total_paid - OLD.amount,
1050                         balance_owed = balance_owed + OLD.amount
1051                   WHERE id = OLD.xact;
1052         END IF;
1053
1054         RETURN OLD;
1055 END;
1056 $$ LANGUAGE PLPGSQL;
1057
1058 CREATE TRIGGER mat_summary_add_tgr AFTER INSERT ON money.payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_add ('payment');
1059 CREATE TRIGGER mat_summary_upd_tgr AFTER UPDATE ON money.payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_update ('payment');
1060 CREATE TRIGGER mat_summary_del_tgr BEFORE DELETE ON money.payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_del ('payment');
1061
1062 CREATE TRIGGER mat_summary_add_tgr AFTER INSERT ON money.bnm_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_add ('bnm_payment');
1063 CREATE TRIGGER mat_summary_upd_tgr AFTER UPDATE ON money.bnm_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_update ('bnm_payment');
1064 CREATE TRIGGER mat_summary_del_tgr BEFORE DELETE ON money.bnm_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_del ('bnm_payment');
1065
1066 CREATE TRIGGER mat_summary_add_tgr AFTER INSERT ON money.forgive_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_add ('forgive_payment');
1067 CREATE TRIGGER mat_summary_upd_tgr AFTER UPDATE ON money.forgive_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_update ('forgive_payment');
1068 CREATE TRIGGER mat_summary_del_tgr BEFORE DELETE ON money.forgive_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_del ('forgive_payment');
1069
1070 CREATE TRIGGER mat_summary_add_tgr AFTER INSERT ON money.work_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_add ('work_payment');
1071 CREATE TRIGGER mat_summary_upd_tgr AFTER UPDATE ON money.work_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_update ('work_payment');
1072 CREATE TRIGGER mat_summary_del_tgr BEFORE DELETE ON money.work_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_del ('work_payment');
1073
1074 CREATE TRIGGER mat_summary_add_tgr AFTER INSERT ON money.credit_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_add ('credit_payment');
1075 CREATE TRIGGER mat_summary_upd_tgr AFTER UPDATE ON money.credit_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_update ('credit_payment');
1076 CREATE TRIGGER mat_summary_del_tgr BEFORE DELETE ON money.credit_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_del ('credit_payment');
1077
1078 CREATE TRIGGER mat_summary_add_tgr AFTER INSERT ON money.goods_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_add ('goods_payment');
1079 CREATE TRIGGER mat_summary_upd_tgr AFTER UPDATE ON money.goods_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_update ('goods_payment');
1080 CREATE TRIGGER mat_summary_del_tgr BEFORE DELETE ON money.goods_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_del ('goods_payment');
1081
1082 CREATE TRIGGER mat_summary_add_tgr AFTER INSERT ON money.bnm_desk_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_add ('bnm_desk_payment');
1083 CREATE TRIGGER mat_summary_upd_tgr AFTER UPDATE ON money.bnm_desk_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_update ('bnm_desk_payment');
1084 CREATE TRIGGER mat_summary_del_tgr BEFORE DELETE ON money.bnm_desk_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_del ('bnm_desk_payment');
1085
1086 CREATE TRIGGER mat_summary_add_tgr AFTER INSERT ON money.cash_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_add ('bnm_payment');
1087 CREATE TRIGGER mat_summary_upd_tgr AFTER UPDATE ON money.cash_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_update ('bnm_payment');
1088 CREATE TRIGGER mat_summary_del_tgr BEFORE DELETE ON money.cash_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_del ('bnm_payment');
1089
1090 CREATE TRIGGER mat_summary_add_tgr AFTER INSERT ON money.check_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_add ('bnm_payment');
1091 CREATE TRIGGER mat_summary_upd_tgr AFTER UPDATE ON money.check_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_update ('bnm_payment');
1092 CREATE TRIGGER mat_summary_del_tgr BEFORE DELETE ON money.check_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_del ('bnm_payment');
1093
1094 CREATE TRIGGER mat_summary_add_tgr AFTER INSERT ON money.credit_card_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_add ('credit_card_payment');
1095 CREATE TRIGGER mat_summary_upd_tgr AFTER UPDATE ON money.credit_card_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_update ('credit_card_payment');
1096 CREATE TRIGGER mat_summary_del_tgr BEFORE DELETE ON money.credit_card_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_del ('credit_card_payment');
1097
1098
1099 CREATE TRIGGER mat_summary_create_tgr AFTER INSERT ON action.circulation FOR EACH ROW EXECUTE PROCEDURE money.mat_summary_create ();
1100 CREATE TRIGGER mat_summary_change_tgr AFTER UPDATE ON action.circulation FOR EACH ROW EXECUTE PROCEDURE money.mat_summary_update ();
1101 CREATE TRIGGER mat_summary_remove_tgr AFTER DELETE ON action.circulation FOR EACH ROW EXECUTE PROCEDURE money.mat_summary_delete ();
1102
1103 CREATE OR REPLACE VIEW action.billable_circulations AS
1104         SELECT  *
1105           FROM  action.circulation
1106           WHERE xact_finish IS NULL;
1107
1108 CREATE TABLE action.hold_request_cancel_cause (
1109     id      SERIAL  PRIMARY KEY,
1110     label   TEXT    UNIQUE
1111 );
1112 INSERT INTO action.hold_request_cancel_cause (id,label) VALUES (1,'Untargeted expiration');
1113 INSERT INTO action.hold_request_cancel_cause (id,label) VALUES (2,'Hold Shelf expiration');
1114 INSERT INTO action.hold_request_cancel_cause (id,label) VALUES (3,'Patron via phone');
1115 INSERT INTO action.hold_request_cancel_cause (id,label) VALUES (4,'Patron in person');
1116 INSERT INTO action.hold_request_cancel_cause (id,label) VALUES (5,'Staff forced');
1117 INSERT INTO action.hold_request_cancel_cause (id,label) VALUES (6,'Patron via OPAC');
1118 SELECT SETVAL('action.hold_request_cancel_cause_id_seq', 100);
1119  
1120 ALTER TABLE action.hold_request ADD COLUMN cancel_cause INT;
1121 ALTER TABLE action.hold_request ADD COLUMN cancel_note TEXT;
1122
1123
1124 ALTER TABLE config.circ_matrix_matchpoint ADD COLUMN juvenile_flag BOOL;
1125 ALTER TABLE config.circ_matrix_matchpoint ADD COLUMN circulate BOOL NOT NULL DEFAULT TRUE;
1126 ALTER TABLE config.circ_matrix_matchpoint ADD COLUMN duration_rule INT REFERENCES config.rule_circ_duration (id) DEFERRABLE INITIALLY DEFERRED;
1127 ALTER TABLE config.circ_matrix_matchpoint ADD COLUMN recurring_fine_rule INT REFERENCES config.rule_recuring_fine (id) DEFERRABLE INITIALLY DEFERRED;
1128 ALTER TABLE config.circ_matrix_matchpoint ADD COLUMN max_fine_rule INT REFERENCES config.rule_max_fine (id) DEFERRABLE INITIALLY DEFERRED;
1129 ALTER TABLE config.circ_matrix_matchpoint ADD COLUMN script_test TEXT;
1130
1131 ALTER TABLE config.circ_matrix_matchpoint DROP CONSTRAINT ep_once_per_grp_loc_mod_marc;
1132 ALTER TABLE config.circ_matrix_matchpoint
1133         ADD CONSTRAINT ep_once_per_grp_loc_mod_marc
1134                 UNIQUE (grp, org_unit, circ_modifier, marc_type, marc_form, marc_vr_format, ref_flag, juvenile_flag, usr_age_lower_bound, usr_age_upper_bound, is_renewal);
1135
1136 UPDATE  config.circ_matrix_matchpoint
1137   SET   duration_rule = config.circ_matrix_ruleset.duration_rule,
1138         recurring_fine_rule = config.circ_matrix_ruleset.recurring_fine_rule,
1139         max_fine_rule = config.circ_matrix_ruleset.max_fine_rule
1140   FROM  config.circ_matrix_ruleset
1141   WHERE config.circ_matrix_ruleset.matchpoint = config.circ_matrix_matchpoint.id;
1142
1143 DROP TABLE config.circ_matrix_ruleset;
1144
1145 ALTER TABLE config.circ_matrix_circ_mod_test DROP COLUMN circ_mod;
1146 CREATE TABLE config.circ_matrix_circ_mod_test_map (
1147     id      SERIAL  PRIMARY KEY,
1148     circ_mod_test   INT NOT NULL REFERENCES config.circ_matrix_circ_mod_test (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
1149     circ_mod        TEXT    NOT NULL REFERENCES config.circ_modifier (code) ON DELETE CASCADE ON UPDATE CASCADE  DEFERRABLE INITIALLY DEFERRED,
1150     CONSTRAINT cm_once_per_test UNIQUE (circ_mod_test, circ_mod)
1151 );
1152  
1153 DROP FUNCTION action.find_circ_matrix_matchpoint( context_ou INT, match_item BIGINT, match_user INT, renewal BOOL );
1154 CREATE OR REPLACE FUNCTION action.find_circ_matrix_matchpoint( context_ou INT, match_item BIGINT, match_user INT, renewal BOOL ) RETURNS config.circ_matrix_matchpoint AS $func$
1155 DECLARE
1156     current_group    permission.grp_tree%ROWTYPE;
1157     user_object    actor.usr%ROWTYPE;
1158     item_object    asset.copy%ROWTYPE;
1159     rec_descriptor    metabib.rec_descriptor%ROWTYPE;
1160     current_mp    config.circ_matrix_matchpoint%ROWTYPE;
1161     matchpoint    config.circ_matrix_matchpoint%ROWTYPE;
1162 BEGIN
1163     SELECT INTO user_object * FROM actor.usr WHERE id = match_user;
1164     SELECT INTO item_object * FROM asset.copy WHERE id = match_item;
1165     SELECT INTO rec_descriptor r.* FROM metabib.rec_descriptor r JOIN asset.call_number c USING (record) WHERE c.id = item_object.call_number;
1166     SELECT INTO current_group * FROM permission.grp_tree WHERE id = user_object.profile;
1167
1168     LOOP
1169         -- for each potential matchpoint for this ou and group ...
1170         FOR current_mp IN
1171             SELECT    m.*
1172               FROM    config.circ_matrix_matchpoint m
1173                 JOIN actor.org_unit_ancestors( context_ou ) d ON (m.org_unit = d.id)
1174                 LEFT JOIN actor.org_unit_proximity p ON (p.from_org = context_ou AND p.to_org = d.id)
1175               WHERE    m.grp = current_group.id AND m.active
1176               ORDER BY    CASE WHEN p.prox        IS NULL THEN 999 ELSE p.prox END,
1177                     CASE WHEN m.is_renewal = renewal        THEN 128 ELSE 0 END +
1178                     CASE WHEN m.juvenile_flag    IS NOT NULL THEN 64 ELSE 0 END +
1179                     CASE WHEN m.circ_modifier    IS NOT NULL THEN 32 ELSE 0 END +
1180                     CASE WHEN m.marc_type        IS NOT NULL THEN 16 ELSE 0 END +
1181                     CASE WHEN m.marc_form        IS NOT NULL THEN 8 ELSE 0 END +
1182                     CASE WHEN m.marc_vr_format    IS NOT NULL THEN 4 ELSE 0 END +
1183                     CASE WHEN m.ref_flag        IS NOT NULL THEN 2 ELSE 0 END +
1184                     CASE WHEN m.usr_age_lower_bound    IS NOT NULL THEN 0.5 ELSE 0 END +
1185                     CASE WHEN m.usr_age_upper_bound    IS NOT NULL THEN 0.5 ELSE 0 END DESC LOOP
1186
1187             IF current_mp.circ_modifier IS NOT NULL THEN
1188                 CONTINUE WHEN current_mp.circ_modifier <> item_object.circ_modifier;
1189             END IF;
1190
1191             IF current_mp.marc_type IS NOT NULL THEN
1192                 IF item_object.circ_as_type IS NOT NULL THEN
1193                     CONTINUE WHEN current_mp.marc_type <> item_object.circ_as_type;
1194                 ELSE
1195                     CONTINUE WHEN current_mp.marc_type <> rec_descriptor.item_type;
1196                 END IF;
1197             END IF;
1198
1199             IF current_mp.marc_form IS NOT NULL THEN
1200                 CONTINUE WHEN current_mp.marc_form <> rec_descriptor.item_form;
1201             END IF;
1202
1203             IF current_mp.marc_vr_format IS NOT NULL THEN
1204                 CONTINUE WHEN current_mp.marc_vr_format <> rec_descriptor.vr_format;
1205             END IF;
1206
1207             IF current_mp.ref_flag IS NOT NULL THEN
1208                 CONTINUE WHEN current_mp.ref_flag <> item_object.ref;
1209             END IF;
1210
1211             IF current_mp.juvenile_flag IS NOT NULL THEN
1212                 CONTINUE WHEN current_mp.juvenile_flag <> user_object.juvenile;
1213             END IF;
1214
1215             IF current_mp.usr_age_lower_bound IS NOT NULL THEN
1216                 CONTINUE WHEN user_object.dob IS NULL OR current_mp.usr_age_lower_bound < age(user_object.dob);
1217             END IF;
1218
1219             IF current_mp.usr_age_upper_bound IS NOT NULL THEN
1220                 CONTINUE WHEN user_object.dob IS NULL OR current_mp.usr_age_upper_bound > age(user_object.dob);
1221             END IF;
1222
1223
1224             -- everything was undefined or matched
1225             matchpoint = current_mp;
1226
1227             EXIT WHEN matchpoint.id IS NOT NULL;
1228         END LOOP;
1229
1230         EXIT WHEN current_group.parent IS NULL OR matchpoint.id IS NOT NULL;
1231
1232         SELECT INTO current_group * FROM permission.grp_tree WHERE id = current_group.parent;
1233     END LOOP;
1234
1235     RETURN matchpoint;
1236 END;
1237 $func$ LANGUAGE plpgsql;
1238
1239 CREATE OR REPLACE FUNCTION action.item_user_circ_test( circ_ou INT, match_item BIGINT, match_user INT, renewal BOOL ) RETURNS SETOF action.matrix_test_result AS $func$
1240 DECLARE
1241     user_object        actor.usr%ROWTYPE;
1242     standing_penalty    config.standing_penalty%ROWTYPE;
1243     item_object        asset.copy%ROWTYPE;
1244     item_status_object    config.copy_status%ROWTYPE;
1245     item_location_object    asset.copy_location%ROWTYPE;
1246     result            action.matrix_test_result;
1247     circ_test        config.circ_matrix_matchpoint%ROWTYPE;
1248     out_by_circ_mod        config.circ_matrix_circ_mod_test%ROWTYPE;
1249     circ_mod_map        config.circ_matrix_circ_mod_test_map%ROWTYPE;
1250     penalty_type         TEXT;
1251     tmp_grp         INT;
1252     items_out        INT;
1253     context_org_list        INT[];
1254     done            BOOL := FALSE;
1255 BEGIN
1256     result.success := TRUE;
1257
1258     -- Fail if the user is BARRED
1259     SELECT INTO user_object * FROM actor.usr WHERE id = match_user;
1260
1261     -- Fail if we couldn't find a set of tests
1262     IF user_object.id IS NULL THEN
1263         result.fail_part := 'no_user';
1264         result.success := FALSE;
1265         done := TRUE;
1266         RETURN NEXT result;
1267         RETURN;
1268     END IF;
1269
1270     IF user_object.barred IS TRUE THEN
1271         result.fail_part := 'actor.usr.barred';
1272         result.success := FALSE;
1273         done := TRUE;
1274         RETURN NEXT result;
1275     END IF;
1276
1277     -- Fail if the item can't circulate
1278     SELECT INTO item_object * FROM asset.copy WHERE id = match_item;
1279     IF item_object.circulate IS FALSE THEN
1280         result.fail_part := 'asset.copy.circulate';
1281         result.success := FALSE;
1282         done := TRUE;
1283         RETURN NEXT result;
1284     END IF;
1285
1286     -- Fail if the item isn't in a circulateable status on a non-renewal
1287     IF NOT renewal AND item_object.status NOT IN ( 0, 7, 8 ) THEN
1288         result.fail_part := 'asset.copy.status';
1289         result.success := FALSE;
1290         done := TRUE;
1291         RETURN NEXT result;
1292     ELSIF renewal AND item_object.status <> 1 THEN
1293         result.fail_part := 'asset.copy.status';
1294         result.success := FALSE;
1295         done := TRUE;
1296         RETURN NEXT result;
1297     END IF;
1298
1299     -- Fail if the item can't circulate because of the shelving location
1300     SELECT INTO item_location_object * FROM asset.copy_location WHERE id = item_object.location;
1301     IF item_location_object.circulate IS FALSE THEN
1302         result.fail_part := 'asset.copy_location.circulate';
1303         result.success := FALSE;
1304         done := TRUE;
1305         RETURN NEXT result;
1306     END IF;
1307
1308     SELECT INTO circ_test * FROM action.find_circ_matrix_matchpoint(circ_ou, match_item, match_user, renewal);
1309     result.matchpoint := circ_test.id;
1310
1311     SELECT INTO context_org_list ARRAY_ACCUM(id) FROM actor.org_unit_full_path( circ_test.org_unit );
1312
1313     -- Fail if we couldn't find a set of tests
1314     IF result.matchpoint IS NULL THEN
1315         result.fail_part := 'no_matchpoint';
1316         result.success := FALSE;
1317         done := TRUE;
1318         RETURN NEXT result;
1319     END IF;
1320
1321     -- Fail if the test is set to hard non-circulating
1322     IF circ_test.circulate IS FALSE THEN
1323         result.fail_part := 'config.circ_matrix_test.circulate';
1324         result.success := FALSE;
1325         done := TRUE;
1326         RETURN NEXT result;
1327     END IF;
1328
1329     IF renewal THEN
1330         penalty_type = '%RENEW%';
1331     ELSE
1332         penalty_type = '%CIRC%';
1333     END IF;
1334
1335     FOR standing_penalty IN
1336         SELECT  DISTINCT csp.*
1337           FROM  actor.usr_standing_penalty usp
1338                 JOIN config.standing_penalty csp ON (csp.id = usp.standing_penalty)
1339           WHERE usr = match_user
1340                 AND usp.org_unit IN ( SELECT * FROM explode_array(context_org_list) )
1341                 AND (usp.stop_date IS NULL or usp.stop_date > NOW())
1342                 AND csp.block_list LIKE penalty_type LOOP
1343
1344         result.fail_part := standing_penalty.name;
1345         result.success := FALSE;
1346         done := TRUE;
1347         RETURN NEXT result;
1348     END LOOP;
1349
1350     -- Fail if the user has too many items with specific circ_modifiers checked out
1351     FOR out_by_circ_mod IN SELECT * FROM config.circ_matrix_circ_mod_test WHERE matchpoint = circ_test.id LOOP
1352         SELECT  INTO items_out COUNT(*)
1353           FROM  action.circulation circ
1354             JOIN asset.copy cp ON (cp.id = circ.target_copy)
1355           WHERE circ.usr = match_user
1356                AND circ_lib IN ( SELECT * FROM explode_array(context_org_list) )
1357             AND circ.checkin_time IS NULL
1358             AND (circ.stop_fines IN ('MAXFINES','LONGOVERDUE') OR circ.stop_fines IS NULL)
1359             AND cp.circ_modifier IN (SELECT circ_mod FROM config.circ_matrix_circ_mod_test_map WHERE circ_mod_test = out_by_circ_mod.id);
1360         IF items_out >= out_by_circ_mod.items_out THEN
1361             result.fail_part := 'config.circ_matrix_circ_mod_test';
1362             result.success := FALSE;
1363             done := TRUE;
1364             RETURN NEXT result;
1365         END IF;
1366     END LOOP;
1367
1368     -- If we passed everything, return the successful matchpoint id
1369     IF NOT done THEN
1370         RETURN NEXT result;
1371     END IF;
1372
1373     RETURN;
1374 END;
1375 $func$ LANGUAGE plpgsql;
1376
1377 CREATE OR REPLACE FUNCTION actor.calculate_system_penalties( match_user INT, context_org INT ) RETURNS SETOF actor.usr_standing_penalty AS $func$
1378 DECLARE
1379     user_object         actor.usr%ROWTYPE;
1380     new_sp_row          actor.usr_standing_penalty%ROWTYPE;
1381     existing_sp_row     actor.usr_standing_penalty%ROWTYPE;
1382     collections_fines   permission.grp_penalty_threshold%ROWTYPE;
1383     max_fines           permission.grp_penalty_threshold%ROWTYPE;
1384     max_overdue         permission.grp_penalty_threshold%ROWTYPE;
1385     max_items_out       permission.grp_penalty_threshold%ROWTYPE;
1386     tmp_grp             INT;
1387     items_overdue       INT;
1388     items_out           INT;
1389     context_org_list    INT[];
1390     current_fines        NUMERIC(8,2) := 0.0;
1391     tmp_fines            NUMERIC(8,2);
1392     tmp_groc            RECORD;
1393     tmp_circ            RECORD;
1394     tmp_org             actor.org_unit%ROWTYPE;
1395 BEGIN
1396     SELECT INTO user_object * FROM actor.usr WHERE id = match_user;
1397
1398     -- Max fines
1399     SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
1400
1401     -- Fail if the user has a high fine balance
1402     LOOP
1403         tmp_grp := user_object.profile;
1404         LOOP
1405             SELECT * INTO max_fines FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 1 AND org_unit = tmp_org.id;
1406
1407             IF max_fines.threshold IS NULL THEN
1408                 SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
1409             ELSE
1410                 EXIT;
1411             END IF;
1412
1413             IF tmp_grp IS NULL THEN
1414                 EXIT;
1415             END IF;
1416         END LOOP;
1417
1418         IF max_fines.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
1419             EXIT;
1420         END IF;
1421
1422         SELECT * INTO tmp_org FROM actor.org_unit WHERE id = tmp_org.parent_ou;
1423
1424     END LOOP;
1425
1426     IF max_fines.threshold IS NOT NULL THEN
1427
1428         FOR existing_sp_row IN
1429                 SELECT  *
1430                   FROM  actor.usr_standing_penalty
1431                   WHERE usr = match_user
1432                         AND org_unit = max_fines.org_unit
1433                         AND (stop_date IS NULL or stop_date > NOW())
1434                         AND standing_penalty = 1
1435                 LOOP
1436             RETURN NEXT existing_sp_row;
1437         END LOOP;
1438
1439         SELECT  SUM(f.balance_owed) INTO current_fines
1440           FROM  money.materialized_billable_xact_summary f
1441                 JOIN (
1442                     SELECT  g.id
1443                       FROM  money.grocery g
1444                             JOIN  actor.org_unit_full_path( max_fines.org_unit ) fp ON (g.billing_location = fp.id)
1445                       WHERE usr = match_user
1446                             AND xact_finish IS NULL
1447                                 UNION ALL
1448                     SELECT  circ.id
1449                       FROM  action.circulation circ
1450                             JOIN  actor.org_unit_full_path( max_fines.org_unit ) fp ON (circ.circ_lib = fp.id)
1451                       WHERE usr = match_user
1452                             AND xact_finish IS NULL ) l USING (id);
1453
1454         IF current_fines >= max_fines.threshold THEN
1455             new_sp_row.usr := match_user;
1456             new_sp_row.org_unit := max_fines.org_unit;
1457             new_sp_row.standing_penalty := 1;
1458             RETURN NEXT new_sp_row;
1459         END IF;
1460     END IF;
1461
1462     -- Start over for max overdue
1463     SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
1464
1465     -- Fail if the user has too many overdue items
1466     LOOP
1467         tmp_grp := user_object.profile;
1468         LOOP
1469
1470             SELECT * INTO max_overdue FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 2 AND org_unit = tmp_org.id;
1471
1472             IF max_overdue.threshold IS NULL THEN
1473                 SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
1474             ELSE
1475                 EXIT;
1476             END IF;
1477
1478             IF tmp_grp IS NULL THEN
1479                 EXIT;
1480             END IF;
1481         END LOOP;
1482
1483         IF max_overdue.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
1484             EXIT;
1485         END IF;
1486
1487         SELECT INTO tmp_org * FROM actor.org_unit WHERE id = tmp_org.parent_ou;
1488
1489     END LOOP;
1490
1491     IF max_overdue.threshold IS NOT NULL THEN
1492
1493         FOR existing_sp_row IN
1494                 SELECT  *
1495                   FROM  actor.usr_standing_penalty
1496                   WHERE usr = match_user
1497                         AND org_unit = max_overdue.org_unit
1498                         AND (stop_date IS NULL or stop_date > NOW())
1499                         AND standing_penalty = 2
1500                 LOOP
1501             RETURN NEXT existing_sp_row;
1502         END LOOP;
1503
1504         SELECT  INTO items_overdue COUNT(*)
1505           FROM  action.circulation circ
1506                 JOIN  actor.org_unit_full_path( max_overdue.org_unit ) fp ON (circ.circ_lib = fp.id)
1507           WHERE circ.usr = match_user
1508             AND circ.checkin_time IS NULL
1509             AND circ.due_date < NOW()
1510             AND (circ.stop_fines = 'MAXFINES' OR circ.stop_fines IS NULL);
1511
1512         IF items_overdue >= max_overdue.threshold::INT THEN
1513             new_sp_row.usr := match_user;
1514             new_sp_row.org_unit := max_overdue.org_unit;
1515             new_sp_row.standing_penalty := 2;
1516             RETURN NEXT new_sp_row;
1517         END IF;
1518     END IF;
1519
1520     -- Start over for max out
1521     SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
1522
1523     -- Fail if the user has too many checked out items
1524     LOOP
1525         tmp_grp := user_object.profile;
1526         LOOP
1527             SELECT * INTO max_items_out FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 3 AND org_unit = tmp_org.id;
1528
1529             IF max_items_out.threshold IS NULL THEN
1530                 SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
1531             ELSE
1532                 EXIT;
1533             END IF;
1534
1535             IF tmp_grp IS NULL THEN
1536                 EXIT;
1537             END IF;
1538         END LOOP;
1539
1540         IF max_items_out.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
1541             EXIT;
1542         END IF;
1543
1544         SELECT INTO tmp_org * FROM actor.org_unit WHERE id = tmp_org.parent_ou;
1545
1546     END LOOP;
1547
1548
1549     -- Fail if the user has too many items checked out
1550     IF max_items_out.threshold IS NOT NULL THEN
1551
1552         FOR existing_sp_row IN
1553                 SELECT  *
1554                   FROM  actor.usr_standing_penalty
1555                   WHERE usr = match_user
1556                         AND org_unit = max_items_out.org_unit
1557                         AND (stop_date IS NULL or stop_date > NOW())
1558                         AND standing_penalty = 3
1559                 LOOP
1560             RETURN NEXT existing_sp_row;
1561         END LOOP;
1562
1563         SELECT  INTO items_out COUNT(*)
1564           FROM  action.circulation circ
1565                 JOIN  actor.org_unit_full_path( max_items_out.org_unit ) fp ON (circ.circ_lib = fp.id)
1566           WHERE circ.usr = match_user
1567                 AND circ.checkin_time IS NULL
1568                 AND (circ.stop_fines IN ('MAXFINES','LONGOVERDUE') OR circ.stop_fines IS NULL);
1569
1570            IF items_out >= max_items_out.threshold::INT THEN
1571             new_sp_row.usr := match_user;
1572             new_sp_row.org_unit := max_items_out.org_unit;
1573             new_sp_row.standing_penalty := 3;
1574             RETURN NEXT new_sp_row;
1575            END IF;
1576     END IF;
1577
1578     -- Start over for collections warning
1579     SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
1580
1581     -- Fail if the user has a collections-level fine balance
1582     LOOP
1583         tmp_grp := user_object.profile;
1584         LOOP
1585             SELECT * INTO max_fines FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 4 AND org_unit = tmp_org.id;
1586
1587             IF max_fines.threshold IS NULL THEN
1588                 SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
1589             ELSE
1590                 EXIT;
1591             END IF;
1592
1593             IF tmp_grp IS NULL THEN
1594                 EXIT;
1595             END IF;
1596         END LOOP;
1597
1598         IF max_fines.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
1599             EXIT;
1600         END IF;
1601
1602         SELECT * INTO tmp_org FROM actor.org_unit WHERE id = tmp_org.parent_ou;
1603
1604     END LOOP;
1605
1606     IF max_fines.threshold IS NOT NULL THEN
1607
1608         FOR existing_sp_row IN
1609                 SELECT  *
1610                   FROM  actor.usr_standing_penalty
1611                   WHERE usr = match_user
1612                         AND org_unit = max_fines.org_unit
1613                         AND (stop_date IS NULL or stop_date > NOW())
1614                         AND standing_penalty = 4
1615                 LOOP
1616             RETURN NEXT existing_sp_row;
1617         END LOOP;
1618
1619         SELECT  SUM(f.balance_owed) INTO current_fines
1620           FROM  money.materialized_billable_xact_summary f
1621                 JOIN (
1622                     SELECT  g.id
1623                       FROM  money.grocery g
1624                             JOIN  actor.org_unit_full_path( max_fines.org_unit ) fp ON (g.billing_location = fp.id)
1625                       WHERE usr = match_user
1626                             AND xact_finish IS NULL
1627                                 UNION ALL
1628                     SELECT  circ.id
1629                       FROM  action.circulation circ
1630                             JOIN  actor.org_unit_full_path( max_fines.org_unit ) fp ON (circ.circ_lib = fp.id)
1631                       WHERE usr = match_user
1632                             AND xact_finish IS NULL ) l USING (id);
1633
1634         IF current_fines >= max_fines.threshold THEN
1635             new_sp_row.usr := match_user;
1636             new_sp_row.org_unit := max_fines.org_unit;
1637             new_sp_row.standing_penalty := 4;
1638             RETURN NEXT new_sp_row;
1639         END IF;
1640     END IF;
1641
1642
1643     RETURN;
1644 END;
1645 $func$ LANGUAGE plpgsql;
1646
1647
1648 ALTER TABLE config.hold_matrix_matchpoint ADD COLUMN juvenile_flag BOOL;
1649 ALTER TABLE config.hold_matrix_matchpoint ADD COLUMN age_hold_protect_rule INT REFERENCES config.rule_age_hold_protect (id) DEFERRABLE INITIALLY DEFERRED;
1650 ALTER TABLE config.hold_matrix_matchpoint ADD COLUMN holdable BOOL NOT NULL DEFAULT TRUE;
1651 ALTER TABLE config.hold_matrix_matchpoint ADD COLUMN distance_is_from_owner BOOL NOT NULL DEFAULT FALSE;
1652 ALTER TABLE config.hold_matrix_matchpoint ADD COLUMN transit_range INT REFERENCES actor.org_unit_type (id) DEFERRABLE INITIALLY DEFERRED;
1653 ALTER TABLE config.hold_matrix_matchpoint ADD COLUMN max_holds INT;
1654 ALTER TABLE config.hold_matrix_matchpoint ADD COLUMN include_frozen_holds BOOL NOT NULL DEFAULT TRUE;
1655 ALTER TABLE config.hold_matrix_matchpoint ADD COLUMN stop_blocked_user BOOL NOT NULL DEFAULT FALSE;
1656
1657 CREATE OR REPLACE FUNCTION action.find_hold_matrix_matchpoint( pickup_ou INT, request_ou INT, match_item BIGINT, match_user INT, match_requestor INT ) RETURNS INT AS $func$
1658 DECLARE
1659     current_requestor_group    permission.grp_tree%ROWTYPE;
1660     root_ou            actor.org_unit%ROWTYPE;
1661     requestor_object    actor.usr%ROWTYPE;
1662     user_object        actor.usr%ROWTYPE;
1663     item_object        asset.copy%ROWTYPE;
1664     item_cn_object        asset.call_number%ROWTYPE;
1665     rec_descriptor        metabib.rec_descriptor%ROWTYPE;
1666     current_mp_weight    FLOAT;
1667     matchpoint_weight    FLOAT;
1668     tmp_weight        FLOAT;
1669     current_mp        config.hold_matrix_matchpoint%ROWTYPE;
1670     matchpoint        config.hold_matrix_matchpoint%ROWTYPE;
1671 BEGIN
1672     SELECT INTO root_ou * FROM actor.org_unit WHERE parent_ou IS NULL;
1673     SELECT INTO user_object * FROM actor.usr WHERE id = match_user;
1674     SELECT INTO requestor_object * FROM actor.usr WHERE id = match_requestor;
1675     SELECT INTO item_object * FROM asset.copy WHERE id = match_item;
1676     SELECT INTO item_cn_object * FROM asset.call_number WHERE id = item_object.call_number;
1677     SELECT INTO rec_descriptor r.* FROM metabib.rec_descriptor r WHERE r.record = item_cn_object.record;
1678     SELECT INTO current_requestor_group * FROM permission.grp_tree WHERE id = requestor_object.profile;
1679
1680     LOOP
1681         -- for each potential matchpoint for this ou and group ...
1682         FOR current_mp IN
1683             SELECT    m.*
1684               FROM    config.hold_matrix_matchpoint m
1685               WHERE    m.requestor_grp = current_requestor_group.id AND m.active
1686               ORDER BY    CASE WHEN m.circ_modifier    IS NOT NULL THEN 16 ELSE 0 END +
1687                     CASE WHEN m.juvenile_flag    IS NOT NULL THEN 16 ELSE 0 END +
1688                     CASE WHEN m.marc_type        IS NOT NULL THEN 8 ELSE 0 END +
1689                     CASE WHEN m.marc_form        IS NOT NULL THEN 4 ELSE 0 END +
1690                     CASE WHEN m.marc_vr_format    IS NOT NULL THEN 2 ELSE 0 END +
1691                     CASE WHEN m.ref_flag        IS NOT NULL THEN 1 ELSE 0 END DESC LOOP
1692
1693             current_mp_weight := 5.0;
1694
1695             IF current_mp.circ_modifier IS NOT NULL THEN
1696                 CONTINUE WHEN current_mp.circ_modifier <> item_object.circ_modifier;
1697             END IF;
1698
1699             IF current_mp.marc_type IS NOT NULL THEN
1700                 IF item_object.circ_as_type IS NOT NULL THEN
1701                     CONTINUE WHEN current_mp.marc_type <> item_object.circ_as_type;
1702                 ELSE
1703                     CONTINUE WHEN current_mp.marc_type <> rec_descriptor.item_type;
1704                 END IF;
1705             END IF;
1706
1707             IF current_mp.marc_form IS NOT NULL THEN
1708                 CONTINUE WHEN current_mp.marc_form <> rec_descriptor.item_form;
1709             END IF;
1710
1711             IF current_mp.marc_vr_format IS NOT NULL THEN
1712                 CONTINUE WHEN current_mp.marc_vr_format <> rec_descriptor.vr_format;
1713             END IF;
1714
1715             IF current_mp.juvenile_flag IS NOT NULL THEN
1716                 CONTINUE WHEN current_mp.juvenile_flag <> user_object.juvenile;
1717             END IF;
1718
1719             IF current_mp.ref_flag IS NOT NULL THEN
1720                 CONTINUE WHEN current_mp.ref_flag <> item_object.ref;
1721             END IF;
1722
1723
1724             -- caclulate the rule match weight
1725             IF current_mp.item_owning_ou IS NOT NULL AND current_mp.item_owning_ou <> root_ou.id THEN
1726                 SELECT INTO tmp_weight 1.0 / (actor.org_unit_proximity(current_mp.item_owning_ou, item_cn_object.owning_lib)::FLOAT + 1.0)::FLOAT;
1727                 current_mp_weight := current_mp_weight - tmp_weight;
1728             END IF;
1729
1730             IF current_mp.item_circ_ou IS NOT NULL AND current_mp.item_circ_ou <> root_ou.id THEN
1731                 SELECT INTO tmp_weight 1.0 / (actor.org_unit_proximity(current_mp.item_circ_ou, item_object.circ_lib)::FLOAT + 1.0)::FLOAT;
1732                 current_mp_weight := current_mp_weight - tmp_weight;
1733             END IF;
1734
1735             IF current_mp.pickup_ou IS NOT NULL AND current_mp.pickup_ou <> root_ou.id THEN
1736                 SELECT INTO tmp_weight 1.0 / (actor.org_unit_proximity(current_mp.pickup_ou, pickup_ou)::FLOAT + 1.0)::FLOAT;
1737                 current_mp_weight := current_mp_weight - tmp_weight;
1738             END IF;
1739
1740             IF current_mp.request_ou IS NOT NULL AND current_mp.request_ou <> root_ou.id THEN
1741                 SELECT INTO tmp_weight 1.0 / (actor.org_unit_proximity(current_mp.request_ou, request_ou)::FLOAT + 1.0)::FLOAT;
1742                 current_mp_weight := current_mp_weight - tmp_weight;
1743             END IF;
1744
1745             IF current_mp.user_home_ou IS NOT NULL AND current_mp.user_home_ou <> root_ou.id THEN
1746                 SELECT INTO tmp_weight 1.0 / (actor.org_unit_proximity(current_mp.user_home_ou, user_object.home_ou)::FLOAT + 1.0)::FLOAT;
1747                 current_mp_weight := current_mp_weight - tmp_weight;
1748             END IF;
1749
1750             -- set the matchpoint if we found the best one
1751             IF matchpoint_weight IS NULL OR matchpoint_weight > current_mp_weight THEN
1752                 matchpoint = current_mp;
1753                 matchpoint_weight = current_mp_weight;
1754             END IF;
1755
1756         END LOOP;
1757
1758         EXIT WHEN current_requestor_group.parent IS NULL OR matchpoint.id IS NOT NULL;
1759
1760         SELECT INTO current_requestor_group * FROM permission.grp_tree WHERE id = current_requestor_group.parent;
1761     END LOOP;
1762
1763     RETURN matchpoint.id;
1764 END;
1765 $func$ LANGUAGE plpgsql;
1766
1767
1768 CREATE OR REPLACE FUNCTION action.hold_request_permit_test( pickup_ou INT, request_ou INT, match_item BIGINT, match_user INT, match_requestor INT ) RETURNS SETOF action.matrix_test_result AS
1769 $func$
1770 DECLARE
1771     matchpoint_id        INT;
1772     user_object        actor.usr%ROWTYPE;
1773     age_protect_object    config.rule_age_hold_protect%ROWTYPE;
1774     standing_penalty    config.standing_penalty%ROWTYPE;
1775     transit_range_ou_type    actor.org_unit_type%ROWTYPE;
1776     transit_source        actor.org_unit%ROWTYPE;
1777     item_object        asset.copy%ROWTYPE;
1778     result            action.matrix_test_result;
1779     hold_test        config.hold_matrix_matchpoint%ROWTYPE;
1780     hold_count        INT;
1781     hold_transit_prox    INT;
1782     frozen_hold_count    INT;
1783     context_org_list    INT[];
1784     done            BOOL := FALSE;
1785 BEGIN
1786     SELECT INTO user_object * FROM actor.usr WHERE id = match_user;
1787     SELECT INTO context_org_list ARRAY_ACCUM(id) FROM actor.org_unit_full_path( pickup_ou );
1788
1789     -- Fail if we couldn't find a user
1790     IF user_object.id IS NULL THEN
1791         result.fail_part := 'no_user';
1792         result.success := FALSE;
1793         done := TRUE;
1794         RETURN NEXT result;
1795         RETURN;
1796     END IF;
1797
1798     -- Fail if user is barred
1799     IF user_object.barred IS TRUE THEN
1800         result.fail_part := 'actor.usr.barred';
1801         result.success := FALSE;
1802         done := TRUE;
1803         RETURN NEXT result;
1804         RETURN;
1805     END IF;
1806
1807     SELECT INTO item_object * FROM asset.copy WHERE id = match_item;
1808
1809     -- Fail if we couldn't find a copy
1810     IF item_object.id IS NULL THEN
1811         result.fail_part := 'no_item';
1812         result.success := FALSE;
1813         done := TRUE;
1814         RETURN NEXT result;
1815         RETURN;
1816     END IF;
1817
1818     SELECT INTO matchpoint_id action.find_hold_matrix_matchpoint(pickup_ou, request_ou, match_item, match_user, match_requestor);
1819
1820     -- Fail if we couldn't find any matchpoint (requires a default)
1821     IF matchpoint_id IS NULL THEN
1822         result.fail_part := 'no_matchpoint';
1823         result.success := FALSE;
1824         done := TRUE;
1825         RETURN NEXT result;
1826         RETURN;
1827     END IF;
1828
1829     SELECT INTO hold_test * FROM config.hold_matrix_matchpoint WHERE id = matchpoint_id;
1830
1831     result.matchpoint := hold_test.id;
1832     result.success := TRUE;
1833
1834     IF hold_test.holdable IS FALSE THEN
1835         result.fail_part := 'config.hold_matrix_test.holdable';
1836         result.success := FALSE;
1837         done := TRUE;
1838         RETURN NEXT result;
1839     END IF;
1840
1841     IF hold_test.transit_range IS NOT NULL THEN
1842         SELECT INTO transit_range_ou_type * FROM actor.org_unit_type WHERE id = hold_test.transit_range;
1843         IF hold_test.distance_is_from_owner THEN
1844             SELECT INTO transit_source ou.* FROM actor.org_unit ou JOIN asset.call_number cn ON (cn.owning_lib = ou.id) WHERE cn.id = item_object.call_number;
1845         ELSE
1846             SELECT INTO transit_source * FROM actor.org_unit WHERE id = item_object.circ_lib;
1847         END IF;
1848
1849         PERFORM * FROM actor.org_unit_descendants( transit_source.id, transit_range_ou_type.depth ) WHERE id = pickup_ou;
1850
1851         IF NOT FOUND THEN
1852             result.fail_part := 'transit_range';
1853             result.success := FALSE;
1854             done := TRUE;
1855             RETURN NEXT result;
1856         END IF;
1857     END IF;
1858
1859     FOR standing_penalty IN
1860         SELECT  DISTINCT csp.*
1861           FROM  actor.usr_standing_penalty usp
1862                 JOIN config.standing_penalty csp ON (csp.id = usp.standing_penalty)
1863           WHERE usr = match_user
1864                 AND usp.org_unit IN ( SELECT * FROM explode_array(context_org_list) )
1865                 AND (usp.stop_date IS NULL or usp.stop_date > NOW())
1866                 AND csp.block_list LIKE '%HOLD%' LOOP
1867
1868         result.fail_part := standing_penalty.name;
1869         result.success := FALSE;
1870         done := TRUE;
1871         RETURN NEXT result;
1872     END LOOP;
1873
1874     IF hold_test.stop_blocked_user IS TRUE THEN
1875         FOR standing_penalty IN
1876             SELECT  DISTINCT csp.*
1877               FROM  actor.usr_standing_penalty usp
1878                     JOIN config.standing_penalty csp ON (csp.id = usp.standing_penalty)
1879               WHERE usr = match_user
1880                     AND usp.org_unit IN ( SELECT * FROM explode_array(context_org_list) )
1881                     AND (usp.stop_date IS NULL or usp.stop_date > NOW())
1882                     AND csp.block_list LIKE '%CIRC%' LOOP
1883
1884             result.fail_part := standing_penalty.name;
1885             result.success := FALSE;
1886             done := TRUE;
1887             RETURN NEXT result;
1888         END LOOP;
1889     END IF;
1890
1891     IF hold_test.max_holds IS NOT NULL THEN
1892         SELECT    INTO hold_count COUNT(*)
1893           FROM    action.hold_request
1894           WHERE    usr = match_user
1895             AND fulfillment_time IS NULL
1896             AND cancel_time IS NULL
1897             AND CASE WHEN hold_test.include_frozen_holds THEN TRUE ELSE frozen IS FALSE END;
1898
1899         IF hold_count >= hold_test.max_holds THEN
1900             result.fail_part := 'config.hold_matrix_test.max_holds';
1901             result.success := FALSE;
1902             done := TRUE;
1903             RETURN NEXT result;
1904         END IF;
1905     END IF;
1906
1907     IF item_object.age_protect IS NOT NULL THEN
1908         SELECT INTO age_protect_object * FROM config.rule_age_hold_protect WHERE id = item_object.age_protect;
1909
1910         IF item_object.create_date + age_protect_object.age > NOW() THEN
1911             IF hold_test.distance_is_from_owner THEN
1912                 SELECT INTO hold_transit_prox prox FROM actor.org_unit_prox WHERE from_org = item_cn_object.owning_lib AND to_org = pickup_ou;
1913             ELSE
1914                 SELECT INTO hold_transit_prox prox FROM actor.org_unit_prox WHERE from_org = item_object.circ_lib AND to_org = pickup_ou;
1915             END IF;
1916
1917             IF hold_transit_prox > age_protect_object.prox THEN
1918                 result.fail_part := 'config.rule_age_hold_protect.prox';
1919                 result.success := FALSE;
1920                 done := TRUE;
1921                 RETURN NEXT result;
1922             END IF;
1923         END IF;
1924     END IF;
1925
1926     IF NOT done THEN
1927         RETURN NEXT result;
1928     END IF;
1929
1930     RETURN;
1931 END;
1932 $func$ LANGUAGE plpgsql;
1933
1934 CREATE SCHEMA acq;
1935
1936
1937 -- Tables
1938
1939
1940 CREATE TABLE acq.currency_type (
1941     code    TEXT PRIMARY KEY,
1942     label   TEXT
1943 );
1944
1945 -- Use the ISO 4217 abbreviations for currency codes
1946 INSERT INTO acq.currency_type (code, label) VALUES ('USD','US Dollars');
1947 INSERT INTO acq.currency_type (code, label) VALUES ('CAN','Canadian Dollars');
1948 INSERT INTO acq.currency_type (code, label) VALUES ('EUR','Euros');
1949
1950 CREATE TABLE acq.exchange_rate (
1951     id              SERIAL  PRIMARY KEY,
1952     from_currency   TEXT    NOT NULL REFERENCES acq.currency_type (code) DEFERRABLE INITIALLY DEFERRED,
1953     to_currency     TEXT    NOT NULL REFERENCES acq.currency_type (code) DEFERRABLE INITIALLY DEFERRED,
1954     ratio           NUMERIC NOT NULL,
1955     CONSTRAINT exchange_rate_from_to_once UNIQUE (from_currency,to_currency)
1956 );
1957
1958 INSERT INTO acq.exchange_rate (from_currency,to_currency,ratio) VALUES ('USD','CAN',1.2);
1959 INSERT INTO acq.exchange_rate (from_currency,to_currency,ratio) VALUES ('USD','EUR',0.5);
1960
1961 CREATE TABLE acq.provider (
1962     id                  SERIAL  PRIMARY KEY,
1963     name                TEXT    NOT NULL,
1964     owner               INT     NOT NULL REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED,
1965     currency_type       TEXT    NOT NULL REFERENCES acq.currency_type (code) DEFERRABLE INITIALLY DEFERRED,
1966     code                TEXT    UNIQUE,
1967     holding_tag         TEXT,
1968     CONSTRAINT provider_name_once_per_owner UNIQUE (name,owner)
1969 );
1970
1971 CREATE TABLE acq.provider_holding_subfield_map (
1972     id          SERIAL  PRIMARY KEY,
1973     provider    INT     NOT NULL REFERENCES acq.provider (id) DEFERRABLE INITIALLY DEFERRED,
1974     name        TEXT    NOT NULL, -- barcode, price, etc
1975     subfield    TEXT    NOT NULL,
1976     CONSTRAINT name_once_per_provider UNIQUE (provider,name)
1977 );
1978
1979 CREATE TABLE acq.provider_address (
1980     id      SERIAL  PRIMARY KEY,
1981     valid       BOOL    NOT NULL DEFAULT TRUE,
1982     address_type    TEXT,
1983     provider    INT     NOT NULL REFERENCES acq.provider (id) DEFERRABLE INITIALLY DEFERRED,
1984     street1     TEXT    NOT NULL,
1985     street2     TEXT,
1986     city        TEXT    NOT NULL,
1987     county      TEXT,
1988     state       TEXT    NOT NULL,
1989     country     TEXT    NOT NULL,
1990     post_code   TEXT    NOT NULL
1991 );
1992
1993 CREATE TABLE acq.provider_contact (
1994     id      SERIAL  PRIMARY KEY,
1995     provider    INT NOT NULL REFERENCES acq.provider (id) DEFERRABLE INITIALLY DEFERRED,
1996     name    TEXT NULL NULL,
1997     role    TEXT, -- free-form.. e.g. "our sales guy"
1998     email   TEXT,
1999     phone   TEXT
2000 );
2001
2002 CREATE TABLE acq.provider_contact_address (
2003     id          SERIAL  PRIMARY KEY,
2004     valid           BOOL    NOT NULL DEFAULT TRUE,
2005     address_type    TEXT,
2006     contact         INT     NOT NULL REFERENCES acq.provider_contact (id) DEFERRABLE INITIALLY DEFERRED,
2007     street1         TEXT    NOT NULL,
2008     street2         TEXT,
2009     city            TEXT    NOT NULL,
2010     county          TEXT,
2011     state           TEXT    NOT NULL,
2012     country         TEXT    NOT NULL,
2013     post_code       TEXT    NOT NULL
2014 );
2015
2016
2017 CREATE TABLE acq.funding_source (
2018     id      SERIAL  PRIMARY KEY,
2019     name        TEXT    NOT NULL,
2020     owner       INT NOT NULL REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED,
2021     currency_type   TEXT    NOT NULL REFERENCES acq.currency_type (code) DEFERRABLE INITIALLY DEFERRED,
2022     code        TEXT    UNIQUE,
2023     CONSTRAINT funding_source_name_once_per_owner UNIQUE (name,owner)
2024 );
2025
2026 CREATE TABLE acq.funding_source_credit (
2027     id  SERIAL  PRIMARY KEY,
2028     funding_source    INT     NOT NULL REFERENCES acq.funding_source (id) DEFERRABLE INITIALLY DEFERRED,
2029     amount  NUMERIC NOT NULL,
2030     note    TEXT
2031 );
2032
2033 CREATE TABLE acq.fund (
2034     id              SERIAL  PRIMARY KEY,
2035     org             INT     NOT NULL REFERENCES actor.org_unit (id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
2036     name            TEXT    NOT NULL,
2037     year            INT     NOT NULL DEFAULT EXTRACT( YEAR FROM NOW() ),
2038     currency_type   TEXT    NOT NULL REFERENCES acq.currency_type (code) DEFERRABLE INITIALLY DEFERRED,
2039     code            TEXT    UNIQUE,
2040     CONSTRAINT name_once_per_org_year UNIQUE (org,name,year)
2041 );
2042
2043 CREATE TABLE acq.fund_debit (
2044     id          SERIAL  PRIMARY KEY,
2045     fund            INT     NOT NULL REFERENCES acq.fund (id) DEFERRABLE INITIALLY DEFERRED,
2046     origin_amount       NUMERIC NOT NULL,  -- pre-exchange-rate amount
2047     origin_currency_type    TEXT    NOT NULL REFERENCES acq.currency_type (code) DEFERRABLE INITIALLY DEFERRED,
2048     amount          NUMERIC NOT NULL,
2049     encumbrance     BOOL    NOT NULL DEFAULT TRUE,
2050     debit_type      TEXT    NOT NULL,
2051     xfer_destination    INT REFERENCES acq.fund (id) DEFERRABLE INITIALLY DEFERRED,
2052     create_time     TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
2053 );
2054
2055 CREATE TABLE acq.fund_allocation (
2056     id          SERIAL  PRIMARY KEY,
2057     funding_source        INT     NOT NULL REFERENCES acq.funding_source (id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
2058     fund        INT     NOT NULL REFERENCES acq.fund (id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
2059     amount      NUMERIC,
2060     percent     NUMERIC CHECK (percent IS NULL OR percent BETWEEN 0.0 AND 100.0),
2061     allocator   INT NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
2062     note        TEXT,
2063     create_time TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
2064     CONSTRAINT allocation_amount_or_percent CHECK ((percent IS NULL AND amount IS NOT NULL) OR (percent IS NOT NULL AND amount IS NULL))
2065 );
2066
2067
2068 CREATE TABLE acq.picklist (
2069     id      SERIAL              PRIMARY KEY,
2070     owner       INT             NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
2071     creator         INT                             NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
2072     editor          INT                             NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
2073     org_unit    INT             NOT NULL REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED,
2074     name        TEXT                NOT NULL,
2075     create_time TIMESTAMP WITH TIME ZONE    NOT NULL DEFAULT NOW(),
2076     edit_time   TIMESTAMP WITH TIME ZONE    NOT NULL DEFAULT NOW(),
2077     CONSTRAINT name_once_per_owner UNIQUE (name,owner)
2078 );
2079
2080 CREATE TABLE acq.purchase_order (
2081     id      SERIAL              PRIMARY KEY,
2082     owner       INT             NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
2083     creator         INT                             NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
2084     editor          INT                             NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
2085     ordering_agency INT             NOT NULL REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED,
2086     create_time TIMESTAMP WITH TIME ZONE    NOT NULL DEFAULT NOW(),
2087     edit_time   TIMESTAMP WITH TIME ZONE    NOT NULL DEFAULT NOW(),
2088     provider    INT             NOT NULL REFERENCES acq.provider (id) DEFERRABLE INITIALLY DEFERRED,
2089     state       TEXT                NOT NULL DEFAULT 'new'
2090 );
2091 CREATE INDEX po_owner_idx ON acq.purchase_order (owner);
2092 CREATE INDEX po_provider_idx ON acq.purchase_order (provider);
2093 CREATE INDEX po_state_idx ON acq.purchase_order (state);
2094
2095 CREATE TABLE acq.po_note (
2096     id      SERIAL              PRIMARY KEY,
2097     purchase_order  INT             NOT NULL REFERENCES acq.purchase_order (id) DEFERRABLE INITIALLY DEFERRED,
2098     creator     INT             NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
2099     editor      INT             NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
2100     create_time TIMESTAMP WITH TIME ZONE    NOT NULL DEFAULT NOW(),
2101     edit_time   TIMESTAMP WITH TIME ZONE    NOT NULL DEFAULT NOW(),
2102     value       TEXT                NOT NULL
2103 );
2104 CREATE INDEX po_note_po_idx ON acq.po_note (purchase_order);
2105
2106 CREATE TABLE acq.lineitem (
2107     id                  BIGSERIAL                   PRIMARY KEY,
2108     creator             INT                         NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
2109     editor              INT                         NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
2110     selector            INT                         NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
2111     provider            INT                         REFERENCES acq.provider (id) DEFERRABLE INITIALLY DEFERRED,
2112     purchase_order      INT                         REFERENCES acq.purchase_order (id) DEFERRABLE INITIALLY DEFERRED,
2113     picklist            INT                         REFERENCES acq.picklist (id) DEFERRABLE INITIALLY DEFERRED,
2114     expected_recv_time  TIMESTAMP WITH TIME ZONE,
2115     create_time         TIMESTAMP WITH TIME ZONE    NOT NULL DEFAULT NOW(),
2116     edit_time           TIMESTAMP WITH TIME ZONE    NOT NULL DEFAULT NOW(),
2117     marc                TEXT                        NOT NULL,
2118     eg_bib_id           INT                         REFERENCES biblio.record_entry (id) DEFERRABLE INITIALLY DEFERRED,
2119     source_label        TEXT,
2120     item_count          INT                         NOT NULL DEFAULT 0,
2121     state               TEXT                        NOT NULL DEFAULT 'new',
2122     CONSTRAINT picklist_or_po CHECK (picklist IS NOT NULL OR purchase_order IS NOT NULL)
2123 );
2124 CREATE INDEX li_po_idx ON acq.lineitem (purchase_order);
2125 CREATE INDEX li_pl_idx ON acq.lineitem (picklist);
2126
2127 CREATE TABLE acq.lineitem_note (
2128     id      SERIAL              PRIMARY KEY,
2129     lineitem    INT             NOT NULL REFERENCES acq.lineitem (id) DEFERRABLE INITIALLY DEFERRED,
2130     creator     INT             NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
2131     editor      INT             NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
2132     create_time TIMESTAMP WITH TIME ZONE    NOT NULL DEFAULT NOW(),
2133     edit_time   TIMESTAMP WITH TIME ZONE    NOT NULL DEFAULT NOW(),
2134     value       TEXT                NOT NULL
2135 );
2136 CREATE INDEX li_note_li_idx ON acq.lineitem_note (lineitem);
2137
2138 CREATE TABLE acq.lineitem_detail (
2139     id          BIGSERIAL   PRIMARY KEY,
2140     lineitem    INT         NOT NULL REFERENCES acq.lineitem (id) DEFERRABLE INITIALLY DEFERRED,
2141     fund        INT         REFERENCES acq.fund (id) DEFERRABLE INITIALLY DEFERRED,
2142     fund_debit  INT         REFERENCES acq.fund_debit (id) DEFERRABLE INITIALLY DEFERRED,
2143     eg_copy_id  BIGINT      REFERENCES asset.copy (id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
2144     barcode     TEXT,
2145     cn_label    TEXT,
2146     note        TEXT,
2147     collection_code TEXT,
2148     circ_modifier   TEXT    REFERENCES config.circ_modifier (code) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
2149     owning_lib  INT         REFERENCES actor.org_unit (id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
2150     location    INT         REFERENCES asset.copy_location (id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
2151     recv_time   TIMESTAMP WITH TIME ZONE
2152 );
2153
2154 CREATE INDEX li_detail_li_idx ON acq.lineitem_detail (lineitem);
2155
2156 CREATE TABLE acq.lineitem_attr_definition (
2157     id      BIGSERIAL   PRIMARY KEY,
2158     code        TEXT        NOT NULL,
2159     description TEXT        NOT NULL,
2160     remove      TEXT        NOT NULL DEFAULT '',
2161     ident       BOOL        NOT NULL DEFAULT FALSE
2162 );
2163
2164 CREATE TABLE acq.lineitem_marc_attr_definition (
2165     id      BIGINT  PRIMARY KEY DEFAULT NEXTVAL('acq.lineitem_attr_definition_id_seq'),
2166     xpath       TEXT        NOT NULL
2167 ) INHERITS (acq.lineitem_attr_definition);
2168
2169 CREATE TABLE acq.lineitem_provider_attr_definition (
2170     id      BIGINT  PRIMARY KEY DEFAULT NEXTVAL('acq.lineitem_attr_definition_id_seq'),
2171     xpath       TEXT        NOT NULL,
2172     provider    INT NOT NULL REFERENCES acq.provider (id) DEFERRABLE INITIALLY DEFERRED
2173 ) INHERITS (acq.lineitem_attr_definition);
2174
2175 CREATE TABLE acq.lineitem_generated_attr_definition (
2176     id      BIGINT  PRIMARY KEY DEFAULT NEXTVAL('acq.lineitem_attr_definition_id_seq'),
2177     xpath       TEXT        NOT NULL
2178 ) INHERITS (acq.lineitem_attr_definition);
2179
2180 CREATE TABLE acq.lineitem_usr_attr_definition (
2181     id      BIGINT  PRIMARY KEY DEFAULT NEXTVAL('acq.lineitem_attr_definition_id_seq'),
2182     usr     INT NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED
2183 ) INHERITS (acq.lineitem_attr_definition);
2184
2185 CREATE TABLE acq.lineitem_local_attr_definition (
2186     id      BIGINT  PRIMARY KEY DEFAULT NEXTVAL('acq.lineitem_attr_definition_id_seq')
2187 ) INHERITS (acq.lineitem_attr_definition);
2188
2189 CREATE TABLE acq.lineitem_attr (
2190     id      BIGSERIAL   PRIMARY KEY,
2191     definition  BIGINT      NOT NULL,
2192     lineitem    BIGINT      NOT NULL REFERENCES acq.lineitem (id) DEFERRABLE INITIALLY DEFERRED,
2193     attr_type   TEXT        NOT NULL,
2194     attr_name   TEXT        NOT NULL,
2195     attr_value  TEXT        NOT NULL
2196 );
2197
2198 CREATE INDEX li_attr_li_idx ON acq.lineitem_attr (lineitem);
2199 CREATE INDEX li_attr_value_idx ON acq.lineitem_attr (attr_value);
2200 CREATE INDEX li_attr_definition_idx ON acq.lineitem_attr (definition);
2201
2202
2203 -- Seed data
2204
2205
2206 INSERT INTO acq.lineitem_marc_attr_definition ( code, description, xpath ) VALUES ('title','Title of work','//*[@tag="245"]/*[contains("abcmnopr",@code)]');
2207 INSERT INTO acq.lineitem_marc_attr_definition ( code, description, xpath ) VALUES ('author','Author of work','//*[@tag="100" or @tag="110" or @tag="113"]/*[contains("ad",@code)]');
2208 INSERT INTO acq.lineitem_marc_attr_definition ( code, description, xpath ) VALUES ('language','Language of work','//*[@tag="240"]/*[@code="l"][1]');
2209 INSERT INTO acq.lineitem_marc_attr_definition ( code, description, xpath ) VALUES ('pagination','Pagination','//*[@tag="300"]/*[@code="a"][1]');
2210 INSERT INTO acq.lineitem_marc_attr_definition ( code, description, xpath, remove ) VALUES ('isbn','ISBN','//*[@tag="020"]/*[@code="a"]', $r$(?:-|\s.+$)$r$);
2211 INSERT INTO acq.lineitem_marc_attr_definition ( code, description, xpath, remove ) VALUES ('issn','ISSN','//*[@tag="022"]/*[@code="a"]', $r$(?:-|\s.+$)$r$);
2212 INSERT INTO acq.lineitem_marc_attr_definition ( code, description, xpath ) VALUES ('price','Price','//*[@tag="020" or @tag="022"]/*[@code="c"][1]');
2213 INSERT INTO acq.lineitem_marc_attr_definition ( code, description, xpath ) VALUES ('identifier','Identifier','//*[@tag="001"]');
2214 INSERT INTO acq.lineitem_marc_attr_definition ( code, description, xpath ) VALUES ('publisher','Publisher','//*[@tag="260"]/*[@code="b"][1]');
2215 INSERT INTO acq.lineitem_marc_attr_definition ( code, description, xpath ) VALUES ('pubdate','Publication Date','//*[@tag="260"]/*[@code="c"][1]');
2216 INSERT INTO acq.lineitem_marc_attr_definition ( code, description, xpath ) VALUES ('edition','Edition','//*[@tag="250"]/*[@code="a"][1]');
2217
2218 INSERT INTO acq.lineitem_local_attr_definition ( code, description ) VALUES ('estimated_price', 'Estimated Price');
2219
2220
2221 CREATE TABLE acq.distribution_formula (
2222     id      SERIAL PRIMARY KEY,
2223     owner   INT NOT NULL
2224             REFERENCES actor.org_unit(id) DEFERRABLE INITIALLY DEFERRED,
2225     name    TEXT NOT NULL,
2226     skip_count  INT NOT NULL DEFAULT 0,
2227     CONSTRAINT acqdf_name_once_per_owner UNIQUE (name, owner)
2228 );
2229
2230 CREATE TABLE acq.distribution_formula_entry (
2231     id          SERIAL PRIMARY KEY,
2232     formula     INTEGER NOT NULL REFERENCES acq.distribution_formula(id)
2233                 ON DELETE CASCADE
2234                 DEFERRABLE INITIALLY DEFERRED,
2235     position    INTEGER NOT NULL,
2236     item_count  INTEGER NOT NULL,
2237     owning_lib  INTEGER REFERENCES actor.org_unit(id)
2238                 DEFERRABLE INITIALLY DEFERRED,
2239     location    INTEGER REFERENCES asset.copy_location(id),
2240     CONSTRAINT acqdfe_lib_once_per_formula UNIQUE( formula, position ),
2241     CONSTRAINT acqdfe_must_be_somewhere
2242                 CHECK( owning_lib IS NOT NULL OR location IS NOT NULL )
2243 );
2244
2245 CREATE TABLE acq.fund_tag (
2246     id      SERIAL PRIMARY KEY,
2247     owner   INT NOT NULL
2248             REFERENCES actor.org_unit(id) DEFERRABLE INITIALLY DEFERRED,
2249     name    TEXT NOT NULL,
2250     CONSTRAINT acqft_tag_once_per_owner UNIQUE (name, owner)
2251 );
2252
2253 CREATE TABLE acq.fund_tag_map (
2254     id          SERIAL PRIMARY KEY,
2255     fund        INTEGER NOT NULL REFERENCES acq.fund(id)
2256                 DEFERRABLE INITIALLY DEFERRED,
2257     tag         INTEGER REFERENCES acq.fund_tag(id)
2258                 ON DELETE CASCADE
2259                 DEFERRABLE INITIALLY DEFERRED,
2260     CONSTRAINT acqftm_fund_once_per_tag UNIQUE( fund, tag )
2261 );
2262
2263 -- Functions
2264
2265 CREATE TYPE acq.flat_lineitem_holding_subfield AS (lineitem int, holding int, subfield text, data text);
2266 CREATE OR REPLACE FUNCTION acq.extract_holding_attr_table (lineitem int, tag text) RETURNS SETOF acq.flat_lineitem_holding_subfield AS $$
2267 DECLARE
2268     counter INT;
2269     lida    acq.flat_lineitem_holding_subfield%ROWTYPE;
2270 BEGIN
2271
2272     SELECT  COUNT(*) INTO counter
2273       FROM  xpath_table(
2274                 'id',
2275                 'marc',
2276                 'acq.lineitem',
2277                 '//*[@tag="' || tag || '"]',
2278                 'id=' || lineitem
2279             ) as t(i int,c text);
2280
2281     FOR i IN 1 .. counter LOOP
2282         FOR lida IN
2283             SELECT  *
2284               FROM  (   SELECT  id,i,t,v
2285                           FROM  xpath_table(
2286                                     'id',
2287                                     'marc',
2288                                     'acq.lineitem',
2289                                     '//*[@tag="' || tag || '"][position()=' || i || ']/*/@code|' ||
2290                                         '//*[@tag="' || tag || '"][position()=' || i || ']/*[@code]',
2291                                     'id=' || lineitem
2292                                 ) as t(id int,t text,v text)
2293                     )x
2294         LOOP
2295             RETURN NEXT lida;
2296         END LOOP;
2297     END LOOP;
2298
2299     RETURN;
2300 END;
2301 $$ LANGUAGE PLPGSQL;
2302
2303 CREATE TYPE acq.flat_lineitem_detail AS (lineitem int, holding int, attr text, data text);
2304 CREATE OR REPLACE FUNCTION acq.extract_provider_holding_data ( lineitem_i int ) RETURNS SETOF acq.flat_lineitem_detail AS $$
2305 DECLARE
2306     prov_i  INT;
2307     tag_t   TEXT;
2308     lida    acq.flat_lineitem_detail%ROWTYPE;
2309 BEGIN
2310     SELECT provider INTO prov_i FROM acq.lineitem WHERE id = lineitem_i;
2311     IF NOT FOUND THEN RETURN; END IF;
2312
2313     SELECT holding_tag INTO tag_t FROM acq.provider WHERE id = prov_i;
2314     IF NOT FOUND OR tag_t IS NULL THEN RETURN; END IF;
2315
2316     FOR lida IN
2317         SELECT  lineitem_i,
2318                 h.holding,
2319                 a.name,
2320                 h.data
2321           FROM  acq.extract_holding_attr_table( lineitem_i, tag_t ) h
2322                 JOIN acq.provider_holding_subfield_map a USING (subfield)
2323           WHERE a.provider = prov_i
2324     LOOP
2325         RETURN NEXT lida;
2326     END LOOP;
2327
2328     RETURN;
2329 END;
2330 $$ LANGUAGE PLPGSQL;
2331
2332 -- select * from acq.extract_provider_holding_data(699);
2333
2334 CREATE OR REPLACE FUNCTION public.extract_acq_marc_field ( BIGINT, TEXT, TEXT) RETURNS TEXT AS $$
2335     SELECT public.extract_marc_field('acq.lineitem', $1, $2, $3);
2336 $$ LANGUAGE SQL;
2337
2338 CREATE OR REPLACE FUNCTION public.ingest_acq_marc ( ) RETURNS TRIGGER AS $$
2339 DECLARE
2340     value       TEXT;
2341     atype       TEXT;
2342     prov        INT;
2343     adef        RECORD;
2344     xpath_string    TEXT;
2345 BEGIN
2346     FOR adef IN SELECT *,tableoid FROM acq.lineitem_attr_definition LOOP
2347
2348         SELECT relname::TEXT INTO atype FROM pg_class WHERE oid = adef.tableoid;
2349
2350         IF (atype NOT IN ('lineitem_usr_attr_definition','lineitem_local_attr_definition')) THEN
2351             IF (atype = 'lineitem_provider_attr_definition') THEN
2352                 SELECT provider INTO prov FROM acq.lineitem_provider_attr_definition WHERE id = adef.id;
2353                 CONTINUE WHEN NEW.provider IS NULL OR prov <> NEW.provider;
2354             END IF;
2355
2356             IF (atype = 'lineitem_provider_attr_definition') THEN
2357                 SELECT xpath INTO xpath_string FROM acq.lineitem_provider_attr_definition WHERE id = adef.id;
2358             ELSIF (atype = 'lineitem_marc_attr_definition') THEN
2359                 SELECT xpath INTO xpath_string FROM acq.lineitem_marc_attr_definition WHERE id = adef.id;
2360             ELSIF (atype = 'lineitem_generated_attr_definition') THEN
2361                 SELECT xpath INTO xpath_string FROM acq.lineitem_generated_attr_definition WHERE id = adef.id;
2362             END IF;
2363
2364             SELECT extract_acq_marc_field(id, xpath_string, adef.remove) INTO value FROM acq.lineitem WHERE id = NEW.id;
2365
2366             IF (value IS NOT NULL AND value <> '') THEN
2367                 INSERT INTO acq.lineitem_attr (lineitem, definition, attr_type, attr_name, attr_value)
2368                     VALUES (NEW.id, adef.id, atype, adef.code, value);
2369             END IF;
2370
2371         END IF;
2372
2373     END LOOP;
2374
2375     RETURN NULL;
2376 END;
2377 $$ LANGUAGE PLPGSQL;
2378
2379 CREATE OR REPLACE FUNCTION public.cleanup_acq_marc ( ) RETURNS TRIGGER AS $$
2380 BEGIN
2381     IF TG_OP = 'UPDATE' THEN
2382         DELETE FROM acq.lineitem_attr
2383                 WHERE lineitem = OLD.id AND attr_type IN ('lineitem_provider_attr_definition', 'lineitem_marc_attr_definition','lineitem_generated_attr_definition');
2384         RETURN NEW;
2385     ELSE
2386         DELETE FROM acq.lineitem_attr WHERE lineitem = OLD.id;
2387         RETURN OLD;
2388     END IF;
2389 END;
2390 $$ LANGUAGE PLPGSQL;
2391
2392 CREATE TRIGGER cleanup_lineitem_trigger
2393     BEFORE UPDATE OR DELETE ON acq.lineitem
2394     FOR EACH ROW EXECUTE PROCEDURE public.cleanup_acq_marc();
2395
2396 CREATE TRIGGER ingest_lineitem_trigger
2397     AFTER INSERT OR UPDATE ON acq.lineitem
2398     FOR EACH ROW EXECUTE PROCEDURE public.ingest_acq_marc();
2399
2400 CREATE OR REPLACE FUNCTION acq.exchange_ratio ( from_ex TEXT, to_ex TEXT ) RETURNS NUMERIC AS $$
2401 DECLARE
2402     rat NUMERIC;
2403 BEGIN
2404     IF from_ex = to_ex THEN
2405         RETURN 1.0;
2406     END IF;
2407
2408     SELECT ratio INTO rat FROM acq.exchange_rate WHERE from_currency = from_ex AND to_currency = to_ex;
2409
2410     IF FOUND THEN
2411         RETURN rat;
2412     ELSE
2413         SELECT ratio INTO rat FROM acq.exchange_rate WHERE from_currency = to_ex AND to_currency = from_ex;
2414         IF FOUND THEN
2415             RETURN 1.0/rat;
2416         END IF;
2417     END IF;
2418
2419     RETURN NULL;
2420
2421 END;
2422 $$ LANGUAGE PLPGSQL;
2423
2424 CREATE OR REPLACE FUNCTION acq.exchange_ratio ( TEXT, TEXT, NUMERIC ) RETURNS NUMERIC AS $$
2425     SELECT $3 * acq.exchange_ratio($1, $2);
2426 $$ LANGUAGE SQL;
2427
2428 CREATE OR REPLACE VIEW acq.funding_source_credit_total AS
2429     SELECT  funding_source,
2430             SUM(amount) AS amount
2431       FROM  acq.funding_source_credit
2432       GROUP BY 1;
2433
2434 CREATE OR REPLACE VIEW acq.funding_source_allocation_total AS
2435     SELECT  funding_source,
2436             SUM(amount)::NUMERIC(100,2) AS amount
2437       FROM (
2438             SELECT  funding_source,
2439                     SUM(a.amount)::NUMERIC(100,2) AS amount
2440               FROM  acq.fund_allocation a
2441               WHERE a.percent IS NULL
2442               GROUP BY 1
2443                             UNION ALL
2444             SELECT  funding_source,
2445                     SUM( (SELECT SUM(amount) FROM acq.funding_source_credit c WHERE c.funding_source = a.funding_source) * (a.percent/100.0) )::NUMERIC(100,2) AS amount
2446               FROM  acq.fund_allocation a
2447               WHERE a.amount IS NULL
2448               GROUP BY 1
2449         ) x
2450       GROUP BY 1;
2451
2452 CREATE OR REPLACE VIEW acq.funding_source_balance AS
2453     SELECT  COALESCE(c.funding_source, a.funding_source) AS funding_source,
2454             SUM(COALESCE(c.amount,0.0) - COALESCE(a.amount,0.0))::NUMERIC(100,2) AS amount
2455       FROM  acq.funding_source_credit_total c
2456             FULL JOIN acq.funding_source_allocation_total a USING (funding_source)
2457       GROUP BY 1;
2458
2459 CREATE OR REPLACE VIEW acq.fund_allocation_total AS
2460     SELECT  fund,
2461             SUM(amount)::NUMERIC(100,2) AS amount
2462       FROM (
2463             SELECT  fund,
2464                     SUM(a.amount * acq.exchange_ratio(s.currency_type, f.currency_type))::NUMERIC(100,2) AS amount
2465               FROM  acq.fund_allocation a
2466                     JOIN acq.fund f ON (a.fund = f.id)
2467                     JOIN acq.funding_source s ON (a.funding_source = s.id)
2468               WHERE a.percent IS NULL
2469               GROUP BY 1
2470                             UNION ALL
2471             SELECT  fund,
2472                     SUM( (SELECT SUM(amount) FROM acq.funding_source_credit c WHERE c.funding_source = a.funding_source) * acq.exchange_ratio(s.currency_type, f.currency_type) * (a.percent/100.0) )::NUMERIC(100,2) AS amount
2473               FROM  acq.fund_allocation a
2474                     JOIN acq.fund f ON (a.fund = f.id)
2475                     JOIN acq.funding_source s ON (a.funding_source = s.id)
2476               WHERE a.amount IS NULL
2477               GROUP BY 1
2478         ) x
2479       GROUP BY 1;
2480
2481 CREATE OR REPLACE VIEW acq.fund_debit_total AS
2482     SELECT  id AS fund,
2483             encumbrance,
2484             SUM(amount) AS amount
2485       FROM  acq.fund_debit
2486       GROUP BY 1,2;
2487
2488 CREATE OR REPLACE VIEW acq.fund_encumbrance_total AS
2489     SELECT  fund,
2490             SUM(amount) AS amount
2491       FROM  acq.fund_debit_total
2492       WHERE encumbrance IS TRUE
2493       GROUP BY 1;
2494
2495 CREATE OR REPLACE VIEW acq.fund_spent_total AS
2496     SELECT  fund,
2497             SUM(amount) AS amount
2498       FROM  acq.fund_debit_total
2499       WHERE encumbrance IS FALSE
2500       GROUP BY 1;
2501
2502 CREATE OR REPLACE VIEW acq.fund_combined_balance AS
2503     SELECT  c.fund,
2504             c.amount - COALESCE(d.amount,0.0) AS amount
2505       FROM  acq.fund_allocation_total c
2506             LEFT JOIN acq.fund_debit_total d USING (fund);
2507
2508 CREATE OR REPLACE VIEW acq.fund_spent_balance AS
2509     SELECT  c.fund,
2510             c.amount - COALESCE(d.amount,0.0) AS amount
2511       FROM  acq.fund_allocation_total c
2512             LEFT JOIN acq.fund_spent_total d USING (fund);
2513
2514 CREATE SCHEMA serial;
2515
2516 CREATE TABLE serial.record_entry (
2517     id      BIGSERIAL   PRIMARY KEY,
2518     record      BIGINT      REFERENCES biblio.record_entry (id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
2519     owning_lib  INT     NOT NULL DEFAULT 1 REFERENCES actor.org_unit (id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
2520     creator     INT     NOT NULL DEFAULT 1,
2521     editor      INT     NOT NULL DEFAULT 1,
2522     source      INT,
2523     create_date TIMESTAMP WITH TIME ZONE    NOT NULL DEFAULT now(),
2524     edit_date   TIMESTAMP WITH TIME ZONE    NOT NULL DEFAULT now(),
2525     active      BOOL        NOT NULL DEFAULT TRUE,
2526     deleted     BOOL        NOT NULL DEFAULT FALSE,
2527     marc        TEXT        NOT NULL,
2528     last_xact_id    TEXT        NOT NULL
2529 );
2530 CREATE INDEX serial_record_entry_creator_idx ON serial.record_entry ( creator );
2531 CREATE INDEX serial_record_entry_editor_idx ON serial.record_entry ( editor );
2532 CREATE INDEX serial_record_entry_owning_lib_idx ON serial.record_entry ( owning_lib, deleted );
2533
2534 CREATE TABLE serial.full_rec (
2535     id      BIGSERIAL   PRIMARY KEY,
2536     record      BIGINT      NOT NULL REFERENCES serial.record_entry(id) DEFERRABLE INITIALLY DEFERRED,
2537     tag     CHAR(3)     NOT NULL,
2538     ind1        TEXT,
2539     ind2        TEXT,
2540     subfield    TEXT,
2541     value       TEXT        NOT NULL,
2542     index_vector    tsvector    NOT NULL
2543 );
2544 CREATE INDEX serial_full_rec_record_idx ON serial.full_rec (record);
2545 CREATE INDEX serial_full_rec_tag_part_idx ON serial.full_rec (SUBSTRING(tag FROM 2));
2546 CREATE TRIGGER serial_full_rec_fti_trigger
2547     BEFORE UPDATE OR INSERT ON serial.full_rec
2548     FOR EACH ROW EXECUTE PROCEDURE tsearch2(index_vector, value);
2549
2550 CREATE INDEX serial_full_rec_index_vector_idx ON serial.full_rec USING GIST (index_vector);
2551 /* Enable LIKE to use an index for database clusters with locales other than C or POSIX */
2552 CREATE INDEX serial_full_rec_value_tpo_index ON serial.full_rec (value text_pattern_ops);
2553
2554 CREATE TABLE serial.subscription (
2555     id      SERIAL  PRIMARY KEY,
2556     callnumber  BIGINT  REFERENCES asset.call_number (id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
2557     uri     INT REFERENCES asset.uri (id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
2558     start_date  DATE    NOT NULL,
2559     end_date    DATE    -- interpret NULL as current subscription 
2560 );
2561
2562 CREATE TABLE serial.binding_unit (
2563     id      SERIAL  PRIMARY KEY,
2564     subscription    INT NOT NULL REFERENCES serial.subscription (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
2565     label       TEXT    NOT NULL,
2566     CONSTRAINT bu_label_once_per_sub UNIQUE (subscription, label)
2567 );
2568
2569 CREATE TABLE serial.issuance (
2570     id      SERIAL  PRIMARY KEY,
2571     subscription    INT NOT NULL REFERENCES serial.subscription (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
2572     target_copy BIGINT  REFERENCES asset.copy (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
2573     location    BIGINT  REFERENCES asset.copy_location(id) DEFERRABLE INITIALLY DEFERRED,
2574     binding_unit    INT REFERENCES serial.binding_unit (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
2575     label       TEXT
2576 );
2577
2578 CREATE TABLE serial.bib_summary (
2579     id          SERIAL  PRIMARY KEY,
2580     subscription        INT UNIQUE NOT NULL REFERENCES serial.subscription (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
2581     generated_coverage  TEXT    NOT NULL,
2582     textual_holdings    TEXT
2583 );
2584
2585 CREATE TABLE serial.sup_summary (
2586     id          SERIAL  PRIMARY KEY,
2587     subscription        INT UNIQUE NOT NULL REFERENCES serial.subscription (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
2588     generated_coverage  TEXT    NOT NULL,
2589     textual_holdings    TEXT
2590 );
2591
2592 CREATE TABLE serial.index_summary (
2593     id          SERIAL  PRIMARY KEY,
2594     subscription        INT UNIQUE NOT NULL REFERENCES serial.subscription (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
2595     generated_coverage  TEXT    NOT NULL,
2596     textual_holdings    TEXT
2597 );
2598
2599
2600 CREATE OR REPLACE FUNCTION search.staged_fts (
2601
2602     param_search_ou INT,
2603     param_depth     INT,
2604     param_searches  TEXT, -- JSON hash, to be turned into a resultset via search.parse_search_args
2605     param_statuses  INT[],
2606     param_locations INT[],
2607     param_audience  TEXT[],
2608     param_language  TEXT[],
2609     param_lit_form  TEXT[],
2610     param_types     TEXT[],
2611     param_forms     TEXT[],
2612     param_vformats  TEXT[],
2613     param_bib_level TEXT[],
2614     param_before    TEXT,
2615     param_after     TEXT,
2616     param_during    TEXT,
2617     param_between   TEXT[],
2618     param_pref_lang TEXT,
2619     param_pref_lang_multiplier REAL,
2620     param_sort      TEXT,
2621     param_sort_desc BOOL,
2622     metarecord      BOOL,
2623     staff           BOOL,
2624     param_rel_limit INT,
2625     param_chk_limit INT,
2626     param_skip_chk  INT
2627
2628 ) RETURNS SETOF search.search_result AS $func$
2629 DECLARE
2630
2631     current_res         search.search_result%ROWTYPE;
2632     query_part          search.search_args%ROWTYPE;
2633     phrase_query_part   search.search_args%ROWTYPE;
2634     rank_adjust_id      INT;
2635     core_rel_limit      INT;
2636     core_chk_limit      INT;
2637     core_skip_chk       INT;
2638     rank_adjust         search.relevance_adjustment%ROWTYPE;
2639     query_table         TEXT;
2640     tmp_text            TEXT;
2641     tmp_int             INT;
2642     current_rank        TEXT;
2643     ranks               TEXT[] := '{}';
2644     query_table_alias   TEXT;
2645     from_alias_array    TEXT[] := '{}';
2646     used_ranks          TEXT[] := '{}';
2647     mb_field            INT;
2648     mb_field_list       INT[];
2649     search_org_list     INT[];
2650     select_clause       TEXT := 'SELECT';
2651     from_clause         TEXT := ' FROM  metabib.metarecord_source_map m JOIN metabib.rec_descriptor mrd ON (m.source = mrd.record) ';
2652     where_clause        TEXT := ' WHERE 1=1 ';
2653     mrd_used            BOOL := FALSE;
2654     sort_desc           BOOL := FALSE;
2655
2656     core_result         RECORD;
2657     core_cursor         REFCURSOR;
2658     core_rel_query      TEXT;
2659     vis_limit_query     TEXT;
2660     inner_where_clause  TEXT;
2661
2662     total_count         INT := 0;
2663     check_count         INT := 0;
2664     deleted_count       INT := 0;
2665     visible_count       INT := 0;
2666     excluded_count      INT := 0;
2667
2668 BEGIN
2669
2670     core_rel_limit := COALESCE( param_rel_limit, 25000 );
2671     core_chk_limit := COALESCE( param_chk_limit, 1000 );
2672     core_skip_chk := COALESCE( param_skip_chk, 1 );
2673
2674     IF metarecord THEN
2675         select_clause := select_clause || ' m.metarecord as id, array_accum(distinct m.source) as records,';
2676     ELSE
2677         select_clause := select_clause || ' m.source as id, array_accum(distinct m.source) as records,';
2678     END IF;
2679
2680     -- first we need to construct the base query
2681     FOR query_part IN SELECT * FROM search.parse_search_args(param_searches) WHERE term_type = 'fts_query' LOOP
2682
2683         inner_where_clause := 'index_vector @@ ' || query_part.term;
2684
2685         IF query_part.field_name IS NOT NULL THEN
2686
2687            SELECT  id INTO mb_field
2688              FROM  config.metabib_field
2689              WHERE field_class = query_part.field_class
2690                    AND name = query_part.field_name;
2691
2692             IF FOUND THEN
2693                 inner_where_clause := inner_where_clause ||
2694                     ' AND ' || 'field = ' || mb_field;
2695             END IF;
2696
2697         END IF;
2698
2699         -- moving on to the rank ...
2700         SELECT  * INTO query_part
2701           FROM  search.parse_search_args(param_searches)
2702           WHERE term_type = 'fts_rank'
2703                 AND table_alias = query_part.table_alias;
2704
2705         current_rank := query_part.term || ' * ' || query_part.table_alias || '_weight.weight';
2706
2707         IF query_part.field_name IS NOT NULL THEN
2708
2709            SELECT  array_accum(distinct id) INTO mb_field_list
2710              FROM  config.metabib_field
2711              WHERE field_class = query_part.field_class
2712                    AND name = query_part.field_name;
2713
2714         ELSE
2715
2716            SELECT  array_accum(distinct id) INTO mb_field_list
2717              FROM  config.metabib_field
2718              WHERE field_class = query_part.field_class;
2719
2720         END IF;
2721
2722         FOR rank_adjust IN SELECT * FROM search.relevance_adjustment WHERE active AND field IN ( SELECT * FROM search.explode_array( mb_field_list ) ) LOOP
2723
2724             IF NOT rank_adjust.bump_type = ANY (used_ranks) THEN
2725
2726                 IF rank_adjust.bump_type = 'first_word' THEN
2727                     SELECT  term INTO tmp_text
2728                       FROM  search.parse_search_args(param_searches)
2729                       WHERE table_alias = query_part.table_alias AND term_type = 'word'
2730                       ORDER BY id
2731                       LIMIT 1;
2732
2733                     tmp_text := query_part.table_alias || '.value ILIKE ' || quote_literal( tmp_text || '%' );
2734
2735                 ELSIF rank_adjust.bump_type = 'word_order' THEN
2736                     SELECT  array_to_string( array_accum( term ), '%' ) INTO tmp_text
2737                       FROM  search.parse_search_args(param_searches)
2738                       WHERE table_alias = query_part.table_alias AND term_type = 'word';
2739
2740                     tmp_text := query_part.table_alias || '.value ILIKE ' || quote_literal( '%' || tmp_text || '%' );
2741
2742                 ELSIF rank_adjust.bump_type = 'full_match' THEN
2743                     SELECT  array_to_string( array_accum( term ), E'\\s+' ) INTO tmp_text
2744                       FROM  search.parse_search_args(param_searches)
2745                       WHERE table_alias = query_part.table_alias AND term_type = 'word';
2746
2747                     tmp_text := query_part.table_alias || '.value  ~ ' || quote_literal( '^' || tmp_text || E'\\W*$' );
2748
2749                 END IF;
2750
2751
2752                 IF tmp_text IS NOT NULL THEN
2753                     current_rank := current_rank || ' * ( CASE WHEN ' || tmp_text ||
2754                         ' THEN ' || rank_adjust.multiplier || '::REAL ELSE 1.0 END )';
2755                 END IF;
2756
2757                 used_ranks := array_append( used_ranks, rank_adjust.bump_type );
2758
2759             END IF;
2760
2761         END LOOP;
2762
2763         ranks := array_append( ranks, current_rank );
2764         used_ranks := '{}';
2765
2766         FOR phrase_query_part IN
2767             SELECT  *
2768               FROM  search.parse_search_args(param_searches)
2769               WHERE term_type = 'phrase'
2770                     AND table_alias = query_part.table_alias LOOP
2771
2772             tmp_text := replace( phrase_query_part.term, '*', E'\\*' );
2773             tmp_text := replace( tmp_text, '?', E'\\?' );
2774             tmp_text := replace( tmp_text, '+', E'\\+' );
2775             tmp_text := replace( tmp_text, '|', E'\\|' );
2776             tmp_text := replace( tmp_text, '(', E'\\(' );
2777             tmp_text := replace( tmp_text, ')', E'\\)' );
2778             tmp_text := replace( tmp_text, '[', E'\\[' );
2779             tmp_text := replace( tmp_text, ']', E'\\]' );
2780
2781             inner_where_clause := inner_where_clause || ' AND ' || 'value  ~* ' || quote_literal( E'(^|\\W+)' || regexp_replace(tmp_text, E'\\s+',E'\\\\s+','g') || E'(\\W+|\$)' );
2782
2783         END LOOP;
2784
2785         query_table := search.pick_table(query_part.field_class);
2786
2787         from_clause := from_clause ||
2788             ' JOIN ( SELECT * FROM ' || query_table || ' WHERE ' || inner_where_clause ||
2789                     CASE WHEN core_rel_limit > 0 THEN ' LIMIT ' || core_rel_limit::TEXT ELSE '' END || ' ) AS ' || query_part.table_alias ||
2790                 ' ON ( m.source = ' || query_part.table_alias || '.source )' ||
2791             ' JOIN config.metabib_field AS ' || query_part.table_alias || '_weight' ||
2792                 ' ON ( ' || query_part.table_alias || '.field = ' || query_part.table_alias || '_weight.id  AND  ' || query_part.table_alias || '_weight.search_field)';
2793
2794         from_alias_array := array_append(from_alias_array, query_part.table_alias);
2795
2796     END LOOP;
2797
2798     IF param_pref_lang IS NOT NULL AND param_pref_lang_multiplier IS NOT NULL THEN
2799         current_rank := ' CASE WHEN mrd.item_lang = ' || quote_literal( param_pref_lang ) ||
2800             ' THEN ' || param_pref_lang_multiplier || '::REAL ELSE 1.0 END ';
2801
2802         -- ranks := array_append( ranks, current_rank );
2803     END IF;
2804
2805     current_rank := ' AVG( ( (' || array_to_string( ranks, ') + (' ) || ') ) * ' || current_rank || ' ) ';
2806     select_clause := select_clause || current_rank || ' AS rel,';
2807
2808     sort_desc = param_sort_desc;
2809
2810     IF param_sort = 'pubdate' THEN
2811
2812         tmp_text := '999999';
2813         IF param_sort_desc THEN tmp_text := '0'; END IF;
2814
2815         current_rank := $$ COALESCE( FIRST(NULLIF(REGEXP_REPLACE(mrd.date1, E'\\D+', '9', 'g'),'')), $$ || quote_literal(tmp_text) || $$ )::INT $$;
2816
2817     ELSIF param_sort = 'title' THEN
2818
2819         tmp_text := 'zzzzzz';
2820         IF param_sort_desc THEN tmp_text := '    '; END IF;
2821
2822         current_rank := $$
2823             ( COALESCE( FIRST ((
2824                 SELECT  LTRIM(SUBSTR( frt.value, COALESCE(SUBSTRING(frt.ind2 FROM E'\\d+'),'0')::INT + 1 ))
2825                   FROM  metabib.full_rec frt
2826                   WHERE frt.record = m.source
2827                     AND frt.tag = '245'
2828                     AND frt.subfield = 'a'
2829                   LIMIT 1
2830             )),$$ || quote_literal(tmp_text) || $$))
2831         $$;
2832
2833     ELSIF param_sort = 'author' THEN
2834
2835         tmp_text := 'zzzzzz';
2836         IF param_sort_desc THEN tmp_text := '    '; END IF;
2837
2838         current_rank := $$
2839             ( COALESCE( FIRST ((
2840                 SELECT  LTRIM(fra.value)
2841                   FROM  metabib.full_rec fra
2842                   WHERE fra.record = m.source
2843                     AND fra.tag LIKE '1%'
2844                     AND fra.subfield = 'a'
2845                   ORDER BY fra.tag::text::int
2846                   LIMIT 1
2847             )),$$ || quote_literal(tmp_text) || $$))
2848         $$;
2849
2850     ELSIF param_sort = 'create_date' THEN
2851             current_rank := $$( FIRST (( SELECT create_date FROM biblio.record_entry rbr WHERE rbr.id = m.source)) )$$;
2852     ELSIF param_sort = 'edit_date' THEN
2853             current_rank := $$( FIRST (( SELECT edit_date FROM biblio.record_entry rbr WHERE rbr.id = m.source)) )$$;
2854     ELSE
2855         sort_desc := NOT COALESCE(param_sort_desc, FALSE);
2856     END IF;
2857
2858     select_clause := select_clause || current_rank || ' AS rank';
2859
2860     -- now add the other qualifiers
2861     IF param_audience IS NOT NULL AND array_upper(param_audience, 1) > 0 THEN
2862         where_clause = where_clause || $$ AND mrd.audience IN ('$$ || array_to_string(param_audience, $$','$$) || $$') $$;
2863     END IF;
2864
2865     IF param_language IS NOT NULL AND array_upper(param_language, 1) > 0 THEN
2866         where_clause = where_clause || $$ AND mrd.item_lang IN ('$$ || array_to_string(param_language, $$','$$) || $$') $$;
2867     END IF;
2868
2869     IF param_lit_form IS NOT NULL AND array_upper(param_lit_form, 1) > 0 THEN
2870         where_clause = where_clause || $$ AND mrd.lit_form IN ('$$ || array_to_string(param_lit_form, $$','$$) || $$') $$;
2871     END IF;
2872
2873     IF param_types IS NOT NULL AND array_upper(param_types, 1) > 0 THEN
2874         where_clause = where_clause || $$ AND mrd.item_type IN ('$$ || array_to_string(param_types, $$','$$) || $$') $$;
2875     END IF;
2876
2877     IF param_forms IS NOT NULL AND array_upper(param_forms, 1) > 0 THEN
2878         where_clause = where_clause || $$ AND mrd.item_form IN ('$$ || array_to_string(param_forms, $$','$$) || $$') $$;
2879     END IF;
2880
2881     IF param_vformats IS NOT NULL AND array_upper(param_vformats, 1) > 0 THEN
2882         where_clause = where_clause || $$ AND mrd.vr_format IN ('$$ || array_to_string(param_vformats, $$','$$) || $$') $$;
2883     END IF;
2884
2885     IF param_bib_level IS NOT NULL AND array_upper(param_bib_level, 1) > 0 THEN
2886         where_clause = where_clause || $$ AND mrd.bib_level IN ('$$ || array_to_string(param_bib_level, $$','$$) || $$') $$;
2887     END IF;
2888
2889     IF param_before IS NOT NULL AND param_before <> '' THEN
2890         where_clause = where_clause || $$ AND mrd.date1 <= $$ || quote_literal(param_before) || ' ';
2891     END IF;
2892
2893     IF param_after IS NOT NULL AND param_after <> '' THEN
2894         where_clause = where_clause || $$ AND mrd.date1 >= $$ || quote_literal(param_after) || ' ';
2895     END IF;
2896
2897     IF param_during IS NOT NULL AND param_during <> '' THEN
2898         where_clause = where_clause || $$ AND $$ || quote_literal(param_during) || $$ BETWEEN mrd.date1 AND mrd.date2 $$;
2899     END IF;
2900
2901     IF param_between IS NOT NULL AND array_upper(param_between, 1) > 1 THEN
2902         where_clause = where_clause || $$ AND mrd.date1 BETWEEN '$$ || array_to_string(param_between, $$' AND '$$) || $$' $$;
2903     END IF;
2904
2905     core_rel_query := select_clause || from_clause || where_clause ||
2906                         ' GROUP BY 1 ORDER BY 4' || CASE WHEN sort_desc THEN ' DESC' ELSE ' ASC' END || ';';
2907     --RAISE NOTICE 'Base Query:  %', core_rel_query;
2908
2909     IF param_search_ou > 0 THEN
2910         IF param_depth IS NOT NULL THEN
2911             SELECT array_accum(distinct id) INTO search_org_list FROM actor.org_unit_descendants( param_search_ou, param_depth );
2912         ELSE
2913             SELECT array_accum(distinct id) INTO search_org_list FROM actor.org_unit_descendants( param_search_ou );
2914         END IF;
2915     ELSIF param_search_ou < 0 THEN
2916         SELECT array_accum(distinct org_unit) INTO search_org_list FROM actor.org_lasso_map WHERE lasso = -param_search_ou;
2917     ELSIF param_search_ou = 0 THEN
2918         -- reserved for user lassos (ou_buckets/type='lasso') with ID passed in depth ... hack? sure.
2919     END IF;
2920
2921     OPEN core_cursor FOR EXECUTE core_rel_query;
2922
2923     LOOP
2924
2925         FETCH core_cursor INTO core_result;
2926         EXIT WHEN NOT FOUND;
2927
2928
2929         IF total_count % 1000 = 0 THEN
2930             -- RAISE NOTICE ' % total, % checked so far ... ', total_count, check_count;
2931         END IF;
2932
2933         IF core_chk_limit > 0 AND total_count - core_skip_chk + 1 >= core_chk_limit THEN
2934             total_count := total_count + 1;
2935             CONTINUE;
2936         END IF;
2937
2938         total_count := total_count + 1;
2939
2940         CONTINUE WHEN param_skip_chk IS NOT NULL and total_count < param_skip_chk;
2941
2942         check_count := check_count + 1;
2943
2944         PERFORM 1 FROM biblio.record_entry b WHERE NOT b.deleted AND b.id IN ( SELECT * FROM search.explode_array( core_result.records ) );
2945         IF NOT FOUND THEN
2946             -- RAISE NOTICE ' % were all deleted ... ', core_result.records;
2947             deleted_count := deleted_count + 1;
2948             CONTINUE;
2949         END IF;
2950
2951         PERFORM 1
2952           FROM  biblio.record_entry b
2953                 JOIN config.bib_source s ON (b.source = s.id)
2954           WHERE s.transcendant
2955                 AND b.id IN ( SELECT * FROM search.explode_array( core_result.records ) );
2956
2957         IF FOUND THEN
2958             -- RAISE NOTICE ' % were all transcendant ... ', core_result.records;
2959             visible_count := visible_count + 1;
2960
2961             current_res.id = core_result.id;
2962             current_res.rel = core_result.rel;
2963
2964             tmp_int := 1;
2965             IF metarecord THEN
2966                 SELECT COUNT(DISTINCT s.source) INTO tmp_int FROM metabib.metarecord_source_map s WHERE s.metarecord = core_result.id;
2967             END IF;
2968
2969             IF tmp_int = 1 THEN
2970                 current_res.record = core_result.records[1];
2971             ELSE
2972                 current_res.record = NULL;
2973             END IF;
2974
2975             RETURN NEXT current_res;
2976
2977             CONTINUE;
2978         END IF;
2979
2980         PERFORM 1
2981           FROM  asset.call_number cn
2982                 JOIN asset.uri_call_number_map map ON (map.call_number = cn.id)
2983                 JOIN asset.uri uri ON (map.uri = uri.id)
2984           WHERE NOT cn.deleted
2985                 AND cn.label = '##URI##'
2986                 AND uri.active
2987                 AND ( param_locations IS NULL OR array_upper(param_locations, 1) IS NULL )
2988                 AND cn.record IN ( SELECT * FROM search.explode_array( core_result.records ) )
2989                 AND cn.owning_lib IN ( SELECT * FROM search.explode_array( search_org_list ) )
2990           LIMIT 1;
2991
2992         IF FOUND THEN
2993             -- RAISE NOTICE ' % have at least one URI ... ', core_result.records;
2994             visible_count := visible_count + 1;
2995
2996             current_res.id = core_result.id;
2997             current_res.rel = core_result.rel;
2998
2999             tmp_int := 1;
3000             IF metarecord THEN
3001                 SELECT COUNT(DISTINCT s.source) INTO tmp_int FROM metabib.metarecord_source_map s WHERE s.metarecord = core_result.id;
3002             END IF;
3003
3004             IF tmp_int = 1 THEN
3005                 current_res.record = core_result.records[1];
3006             ELSE
3007                 current_res.record = NULL;
3008             END IF;
3009
3010             RETURN NEXT current_res;
3011
3012             CONTINUE;
3013         END IF;
3014
3015         IF param_statuses IS NOT NULL AND array_upper(param_statuses, 1) > 0 THEN
3016
3017             PERFORM 1
3018               FROM  asset.call_number cn
3019                     JOIN asset.copy cp ON (cp.call_number = cn.id)
3020               WHERE NOT cn.deleted
3021                     AND NOT cp.deleted
3022                     AND cp.status IN ( SELECT * FROM search.explode_array( param_statuses ) )
3023                     AND cn.record IN ( SELECT * FROM search.explode_array( core_result.records ) )
3024                     AND cp.circ_lib IN ( SELECT * FROM search.explode_array( search_org_list ) )
3025               LIMIT 1;
3026
3027             IF NOT FOUND THEN
3028                 -- RAISE NOTICE ' % were all status-excluded ... ', core_result.records;
3029                 excluded_count := excluded_count + 1;
3030                 CONTINUE;
3031             END IF;
3032
3033         END IF;
3034
3035         IF param_locations IS NOT NULL AND array_upper(param_locations, 1) > 0 THEN
3036
3037             PERFORM 1
3038               FROM  asset.call_number cn
3039                     JOIN asset.copy cp ON (cp.call_number = cn.id)
3040               WHERE NOT cn.deleted
3041                     AND NOT cp.deleted
3042                     AND cp.location IN ( SELECT * FROM search.explode_array( param_locations ) )
3043                     AND cn.record IN ( SELECT * FROM search.explode_array( core_result.records ) )
3044                     AND cp.circ_lib IN ( SELECT * FROM search.explode_array( search_org_list ) )
3045               LIMIT 1;
3046
3047             IF NOT FOUND THEN
3048                 -- RAISE NOTICE ' % were all copy_location-excluded ... ', core_result.records;
3049                 excluded_count := excluded_count + 1;
3050                 CONTINUE;
3051             END IF;
3052
3053         END IF;
3054
3055         IF staff IS NULL OR NOT staff THEN
3056
3057             PERFORM 1
3058               FROM  asset.call_number cn
3059                     JOIN asset.copy cp ON (cp.call_number = cn.id)
3060                     JOIN actor.org_unit a ON (cp.circ_lib = a.id)
3061                     JOIN asset.copy_location cl ON (cp.location = cl.id)
3062                     JOIN config.copy_status cs ON (cp.status = cs.id)
3063               WHERE NOT cn.deleted
3064                     AND NOT cp.deleted
3065                     AND cs.opac_visible
3066                     AND cl.opac_visible
3067                     AND cp.opac_visible
3068                     AND a.opac_visible
3069                     AND cp.circ_lib IN ( SELECT * FROM search.explode_array( search_org_list ) )
3070                     AND cn.record IN ( SELECT * FROM search.explode_array( core_result.records ) )
3071               LIMIT 1;
3072
3073             IF NOT FOUND THEN
3074                 -- RAISE NOTICE ' % were all visibility-excluded ... ', core_result.records;
3075                 excluded_count := excluded_count + 1;
3076                 CONTINUE;
3077             END IF;
3078
3079         ELSE
3080
3081             PERFORM 1
3082               FROM  asset.call_number cn
3083                     JOIN asset.copy cp ON (cp.call_number = cn.id)
3084                     JOIN actor.org_unit a ON (cp.circ_lib = a.id)
3085                     JOIN asset.copy_location cl ON (cp.location = cl.id)
3086               WHERE NOT cn.deleted
3087                     AND NOT cp.deleted
3088                     AND cp.circ_lib IN ( SELECT * FROM search.explode_array( search_org_list ) )
3089                     AND cn.record IN ( SELECT * FROM search.explode_array( core_result.records ) )
3090               LIMIT 1;
3091
3092             IF NOT FOUND THEN
3093
3094                 PERFORM 1
3095                   FROM  asset.call_number cn
3096                   WHERE cn.record IN ( SELECT * FROM search.explode_array( core_result.records ) )
3097                   LIMIT 1;
3098
3099                 IF FOUND THEN
3100                     -- RAISE NOTICE ' % were all visibility-excluded ... ', core_result.records;
3101                     excluded_count := excluded_count + 1;
3102                     CONTINUE;
3103                 END IF;
3104
3105             END IF;
3106
3107         END IF;
3108
3109         visible_count := visible_count + 1;
3110
3111         current_res.id = core_result.id;
3112         current_res.rel = core_result.rel;
3113
3114         tmp_int := 1;
3115         IF metarecord THEN
3116             SELECT COUNT(DISTINCT s.source) INTO tmp_int FROM metabib.metarecord_source_map s WHERE s.metarecord = core_result.id;
3117         END IF;
3118
3119         IF tmp_int = 1 THEN
3120             current_res.record = core_result.records[1];
3121         ELSE
3122             current_res.record = NULL;
3123         END IF;
3124
3125         RETURN NEXT current_res;
3126
3127         IF visible_count % 1000 = 0 THEN
3128             -- RAISE NOTICE ' % visible so far ... ', visible_count;
3129         END IF;
3130
3131     END LOOP;
3132
3133     current_res.id = NULL;
3134     current_res.rel = NULL;
3135     current_res.record = NULL;
3136     current_res.total = total_count;
3137     current_res.checked = check_count;
3138     current_res.deleted = deleted_count;
3139     current_res.visible = visible_count;
3140     current_res.excluded = excluded_count;
3141
3142     CLOSE core_cursor;
3143
3144     RETURN NEXT current_res;
3145
3146 END;
3147 $func$ LANGUAGE PLPGSQL;
3148
3149
3150 CREATE TABLE config.idl_field_doc (
3151     id              BIGSERIAL   PRIMARY KEY,
3152     fm_class        TEXT        NOT NULL,
3153     field           TEXT        NOT NULL,
3154     owner           INT         NOT NULL    REFERENCES actor.org_unit (id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
3155     string          TEXT        NOT NULL
3156 );
3157 CREATE UNIQUE INDEX idl_field_doc_identity ON config.idl_field_doc (fm_class,field,owner);
3158
3159
3160 INSERT INTO config.xml_transform VALUES ( 'mods33', 'http://www.loc.gov/mods/v3', 'mods33', '');
3161  
3162 INSERT INTO container.copy_bucket_type (code,label) VALUES ('misc', 'Miscellaneous');
3163 INSERT INTO container.copy_bucket_type (code,label) VALUES ('staff_client', 'General Staff Client container');
3164 INSERT INTO container.call_number_bucket_type (code,label) VALUES ('misc', 'Miscellaneous');
3165 INSERT INTO container.biblio_record_entry_bucket_type (code,label) VALUES ('misc', 'Miscellaneous');
3166 INSERT INTO container.biblio_record_entry_bucket_type (code,label) VALUES ('staff_client', 'General Staff Client container');
3167 INSERT INTO container.biblio_record_entry_bucket_type (code,label) VALUES ('bookbag', 'Book Bag');
3168 INSERT INTO container.biblio_record_entry_bucket_type (code,label) VALUES ('reading_list', 'Reading List');
3169
3170 INSERT INTO container.user_bucket_type (code,label) VALUES ('misc', 'Miscellaneous');
3171 INSERT INTO container.user_bucket_type (code,label) VALUES ('folks', 'Friends');
3172 INSERT INTO container.user_bucket_type (code,label) VALUES ('folks:pub_book_bags.view', 'List Published Book Bags');
3173 INSERT INTO container.user_bucket_type (code,label) VALUES ('folks:pub_book_bags.add', 'Add to Published Book Bags');
3174 INSERT INTO container.user_bucket_type (code,label) VALUES ('folks:circ.view', 'View Circulations');
3175 INSERT INTO container.user_bucket_type (code,label) VALUES ('folks:circ.renew', 'Renew Circulations');
3176 INSERT INTO container.user_bucket_type (code,label) VALUES ('folks:circ.checkout', 'Checkout Items');
3177 INSERT INTO container.user_bucket_type (code,label) VALUES ('folks:hold.view', 'View Holds');
3178 INSERT INTO container.user_bucket_type (code,label) VALUES ('folks:hold.cancel', 'Cancel Holds');
3179
3180
3181
3182 CREATE SCHEMA action_trigger;
3183
3184 CREATE TABLE action_trigger.hook (
3185     key         TEXT    PRIMARY KEY,
3186     core_type   TEXT    NOT NULL,
3187     description TEXT,
3188     passive     BOOL    NOT NULL DEFAULT FALSE
3189 );
3190 INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('checkout','circ','Item checked out to user');
3191 INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('checkin','circ','Item checked in');
3192 INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('lost','circ','Circulating Item marked Lost');
3193 INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('lost.found','circ','Lost Circulating Item checked in');
3194 INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('lost.auto','circ','Circulating Item automatically marked lost');
3195 INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('claims_returned','circ','Circulating Item marked Claims Returned');
3196 INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('claims_returned.found','circ','Claims Returned Circulating Item is checked in');
3197 INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('missing','acp','Item marked Missing');
3198 INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('missing.found','acp','Missing Item checked in');
3199 INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('transit.start','acp','An Item is placed into transit');
3200 INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('transit.finish','acp','An Item is received from a transit');
3201 INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('hold_request.success','ahr','A hold is succefully placed');
3202 INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('hold_request.failure','ahr','A hold is attempted by not succefully placed');
3203 INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('hold.capture','ahr','A targeted Item is captured for a hold');
3204 INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('hold.available','ahr','A held item is ready for pickup');
3205 INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('hold_transit.start','ahtc','A hold-captured Item is placed into transit');
3206 INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('hold_transit.finish','ahtc','A hold-captured Item is received from a transit');
3207 INSERT INTO action_trigger.hook (key,core_type,description,passive) VALUES ('checkout.due','circ','Checked out Item is Due',TRUE);
3208 INSERT INTO action_trigger.hook (key,core_type,description,passive) VALUES ('penalty.PATRON_EXCEEDS_FINES','ausp','Patron has exceeded allowed fines',TRUE);
3209 INSERT INTO action_trigger.hook (key,core_type,description,passive) VALUES ('penalty.PATRON_EXCEEDS_OVERDUE_COUNT','ausp','Patron has exceeded allowed overdue count',TRUE);
3210 INSERT INTO action_trigger.hook (key,core_type,description,passive) VALUES ('penalty.PATRON_EXCEEDS_CHECKOUT_COUNT','ausp','Patron has exceeded allowed checkout count',TRUE);
3211 INSERT INTO action_trigger.hook (key,core_type,description,passive) VALUES ('penalty.PATRON_EXCEEDS_COLLECTIONS_WARNING','ausp','Patron has exceeded maximum fine amount for collections department warning',TRUE);
3212 INSERT INTO action_trigger.hook (key,core_type,description,passive) VALUES ('format.po.jedi','acqpo','Formats a Purchase Order as a JEDI document',TRUE);
3213 INSERT INTO action_trigger.hook (key,core_type,description,passive) VALUES ('format.po.html','acqpo','Formats a Purchase Order as an HTML document',TRUE);
3214 INSERT INTO action_trigger.hook (key,core_type,description,passive) VALUES ('format.po.pdf','acqpo','Formats a Purchase Order as a PDF document',TRUE);
3215 INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('damaged','acp','Item marked damaged');
3216 INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('checkout.damaged','circ','A circulating item is marked damaged and the patron is fined');
3217 -- and much more, I'm sure
3218
3219 -- Specialized collection modules.  Given an FM object, gather some info and return a scalar or ref.
3220 CREATE TABLE action_trigger.collector (
3221     module      TEXT    PRIMARY KEY, -- All live under the OpenILS::Trigger::Collector:: namespace
3222     description TEXT
3223 );
3224 INSERT INTO action_trigger.collector (module,description) VALUES ('fourty_two','Returns the answer to life, the universe and everything');
3225 --INSERT INTO action_trigger.collector (module,description) VALUES ('CircCountsByCircMod','Count of Circulations for a User, broken down by circulation modifier');
3226
3227 -- Simple tests on an FM object from hook.core_type to test for "should we still do this."
3228 CREATE TABLE action_trigger.validator (
3229     module      TEXT    PRIMARY KEY, -- All live under the OpenILS::Trigger::Validator:: namespace
3230     description TEXT
3231 );
3232 INSERT INTO action_trigger.validator (module,description) VALUES ('fourty_two','Returns the answer to life, the universe and everything');
3233 INSERT INTO action_trigger.validator (module,description) VALUES ('NOOP_True','Always returns true -- validation always passes');
3234 INSERT INTO action_trigger.validator (module,description) VALUES ('NOOP_False','Always returns false -- validation always fails');
3235 INSERT INTO action_trigger.validator (module,description) VALUES ('CircIsOpen','Check that the circulation is still open');
3236 INSERT INTO action_trigger.validator (module,description) VALUES ('HoldIsAvailable','Check that an item is on the hold shelf');
3237 INSERT INTO action_trigger.validator (module,description) VALUES ('CircIsOverdue','Check that the circulation is overdue');
3238
3239 -- After an event passes validation (action_trigger.validator), the reactor processes it.
3240 CREATE TABLE action_trigger.reactor (
3241     module      TEXT    PRIMARY KEY, -- All live under the OpenILS::Trigger::Reactor:: namespace
3242     description TEXT
3243 );
3244 INSERT INTO action_trigger.reactor (module,description) VALUES ('fourty_two','Returns the answer to life, the universe and everything');
3245 INSERT INTO action_trigger.reactor (module,description) VALUES ('NOOP_True','Always returns true -- reaction always passes');
3246 INSERT INTO action_trigger.reactor (module,description) VALUES ('NOOP_False','Always returns false -- reaction always fails');
3247 INSERT INTO action_trigger.reactor (module,description) VALUES ('SendEmail','Send an email based on a user-defined template');
3248 INSERT INTO action_trigger.reactor (module,description) VALUES ('GenerateBatchOverduePDF','Output a batch PDF of overdue notices for printing');
3249 INSERT INTO action_trigger.reactor (module,description) VALUES ('MarkItemLost','Marks a circulation and associated item as lost');
3250 INSERT INTO action_trigger.reactor (module,description) VALUES ('ApplyCircFee','Applies a billing with a pre-defined amount to a circulation');
3251 INSERT INTO action_trigger.reactor (module,description) VALUES ('ProcessTemplate', 'Processes the configured template');
3252
3253 -- After an event is reacted to (either succes or failure) a cleanup module is run against the resulting environment
3254 CREATE TABLE action_trigger.cleanup (
3255     module      TEXT    PRIMARY KEY, -- All live under the OpenILS::Trigger::Cleanup:: namespace
3256     description TEXT
3257 );
3258 INSERT INTO action_trigger.cleanup (module,description) VALUES ('fourty_two','Returns the answer to life, the universe and everything');
3259 INSERT INTO action_trigger.cleanup (module,description) VALUES ('NOOP_True','Always returns true -- cleanup always passes');
3260 INSERT INTO action_trigger.cleanup (module,description) VALUES ('NOOP_False','Always returns false -- cleanup always fails');
3261 INSERT INTO action_trigger.cleanup (module,description) VALUES ('ClearAllPending','Remove all future, pending notifications for this target');
3262
3263 CREATE TABLE action_trigger.event_definition (
3264     id              SERIAL      PRIMARY KEY,
3265     active          BOOL        NOT NULL DEFAULT TRUE,
3266     owner           INT         NOT NULL REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED,
3267     name            TEXT        NOT NULL,
3268     hook            TEXT        NOT NULL REFERENCES action_trigger.hook (key) DEFERRABLE INITIALLY DEFERRED,
3269     validator       TEXT        NOT NULL REFERENCES action_trigger.validator (module) DEFERRABLE INITIALLY DEFERRED,
3270     reactor         TEXT        NOT NULL REFERENCES action_trigger.reactor (module) DEFERRABLE INITIALLY DEFERRED,
3271     cleanup_success TEXT        REFERENCES action_trigger.cleanup (module) DEFERRABLE INITIALLY DEFERRED,
3272     cleanup_failure TEXT        REFERENCES action_trigger.cleanup (module) DEFERRABLE INITIALLY DEFERRED,
3273     delay           INTERVAL    NOT NULL DEFAULT '5 minutes',
3274     delay_field     TEXT,                 -- for instance, xact_start on a circ hook ... look for fields on hook.core_type where datatype=timestamp? If not set, delay from now()
3275     group_field     TEXT,                 -- field from this.hook.core_type to batch event targets together on, fed into reactor a group at a time.
3276     template        TEXT,                 -- the TT block.  will have an 'environment' hash (or array of hashes, grouped events) built up by validator and collector(s), which can be modified.
3277     CONSTRAINT ev_def_owner_hook_val_react_clean_delay_once UNIQUE (owner, hook, validator, reactor, delay, delay_field),
3278     CONSTRAINT ev_def_name_owner_once UNIQUE (owner, name)
3279 );
3280
3281 CREATE TABLE action_trigger.environment (
3282     id          SERIAL  PRIMARY KEY,
3283     event_def   INT     NOT NULL REFERENCES action_trigger.event_definition (id) DEFERRABLE INITIALLY DEFERRED,
3284     path        TEXT,       -- fields to flesh. given a hook with a core_type of circ, imagine circ_lib.parent_ou expanding to
3285                             -- {flesh: 2, flesh_fields: {circ: ['circ_lib'], aou: ['parent_ou']}} ... default is to flesh all
3286                             -- at flesh depth 1
3287     collector   TEXT    REFERENCES action_trigger.collector (module) DEFERRABLE INITIALLY DEFERRED, -- if set, given the object at 'path', return some data
3288                                                                       -- to be stashed at environment.<label>
3289     label       TEXT    CHECK (label NOT IN ('result','target','event')),
3290     CONSTRAINT env_event_label_once UNIQUE (event_def,label)
3291 );
3292
3293 CREATE TABLE action_trigger.event_output (
3294     id              BIGSERIAL   PRIMARY KEY,
3295     create_time     TIMESTAMPTZ NOT NULL DEFAULT NOW(),
3296     is_error        BOOLEAN     NOT NULL DEFAULT FALSE,
3297     data            TEXT        NOT NULL
3298 );
3299
3300 CREATE TABLE action_trigger.event (
3301     id              BIGSERIAL   PRIMARY KEY,
3302     target          BIGINT      NOT NULL, -- points at the id from class defined by event_def.hook.core_type
3303     event_def       INT         REFERENCES action_trigger.event_definition (id) DEFERRABLE INITIALLY DEFERRED,
3304     add_time        TIMESTAMPTZ NOT NULL DEFAULT NOW(),
3305     run_time        TIMESTAMPTZ NOT NULL,
3306     start_time      TIMESTAMPTZ,
3307     update_time     TIMESTAMPTZ,
3308     complete_time   TIMESTAMPTZ,
3309     update_process  INT,
3310     state           TEXT        NOT NULL DEFAULT 'pending' CHECK (state IN ('pending','invalid','found','collecting','collected','validating','valid','reacting','reacted','cleaning','complete','error')),
3311     template_output BIGINT      REFERENCES action_trigger.event_output (id),
3312     error_output    BIGINT      REFERENCES action_trigger.event_output (id)
3313 );
3314
3315 CREATE TABLE action_trigger.event_params (
3316     id          BIGSERIAL   PRIMARY KEY,
3317     event_def   INT         NOT NULL REFERENCES action_trigger.event_definition (id) DEFERRABLE INITIALLY DEFERRED,
3318     param       TEXT        NOT NULL, -- the key under environment.event.params to store the output of ...
3319     value       TEXT        NOT NULL, -- ... the eval() output of this.  Has access to environment (and, well, all of perl)
3320     CONSTRAINT event_params_event_def_param_once UNIQUE (event_def,param)
3321 );
3322
3323
3324
3325 -- Trigger Event Definitions -------------------------------------------------
3326
3327 -- Sample Overdue Notice --
3328
3329 INSERT INTO action_trigger.event_definition (id, active, owner, name, hook, validator, reactor, delay, delay_field, group_field, template) 
3330     VALUES (1, 'f', 1, '7 Day Overdue Email Notification', 'checkout.due', 'CircIsOverdue', 'SendEmail', '7 days', 'due_date', 'usr', 
3331 $$
3332 [%- USE date -%]
3333 [%- user = target.0.usr -%]
3334 To: [%- params.recipient_email || user.email %]
3335 From: [%- params.sender_email || default_sender %]
3336 Subject: Overdue Notification
3337
3338 Dear [% user.family_name %], [% user.first_given_name %]
3339 Our records indicate the following items are overdue.
3340
3341 [% FOR circ IN target %]
3342     Title: [% circ.target_copy.call_number.record.simple_record.title %] 
3343     Barcode: [% circ.target_copy.barcode %] 
3344     Due: [% date.format(helpers.format_date(circ.due_date), '%Y-%m-%d') %]
3345     Item Cost: [% helpers.get_copy_price(circ.target_copy) %]
3346     Total Owed For Transaction: [% circ.billable_transaction.summary.total_owed %]
3347     Library: [% circ.circ_lib.name %]
3348 [% END %]
3349
3350 $$);
3351
3352 INSERT INTO action_trigger.environment (event_def, path) VALUES 
3353     (1, 'target_copy.call_number.record.simple_record'),
3354     (1, 'usr'),
3355     (1, 'billable_transaction.summary'),
3356     (1, 'circ_lib.billing_address');
3357   
3358
3359 -- Sample Mark Long-Overdue Item Lost --
3360
3361 INSERT INTO action_trigger.event_definition (id, active, owner, name, hook, validator, reactor, delay, delay_field) 
3362     VALUES (2, 'f', 1, '90 Day Overdue Mark Lost', 'checkout.due', 'CircIsOverdue', 'MarkItemLost', '90 days', 'due_date');
3363
3364 -- Sample Auto Mark Lost Notice --
3365
3366 INSERT INTO action_trigger.event_definition (id, active, owner, name, hook, validator, reactor, group_field, template) 
3367     VALUES (3, 'f', 1, '90 Day Overdue Mark Lost Notice', 'lost.auto', 'NOOP_True', 'SendEmail', 'usr',
3368 $$
3369 [%- USE date -%]
3370 [%- user = target.0.usr -%]
3371 To: [%- params.recipient_email || user.email %]
3372 From: [%- params.sender_email || default_sender %]
3373 Subject: Overdue Items Marked Lost
3374
3375 Dear [% user.family_name %], [% user.first_given_name %]
3376 The following items are 90 days overdue and have been marked LOST.
3377
3378 [% FOR circ IN target %]
3379     Title: [% circ.target_copy.call_number.record.simple_record.title %] 
3380     Barcode: [% circ.target_copy.barcode %] 
3381     Due: [% date.format(helpers.format_date(circ.due_date), '%Y-%m-%d') %]
3382     Item Cost: [% helpers.get_copy_price(circ.target_copy) %]
3383     Total Owed For Transaction: [% circ.billable_transaction.summary.total_owed %]
3384     Library: [% circ.circ_lib.name %]
3385 [% END %]
3386
3387 $$);
3388
3389
3390 INSERT INTO action_trigger.environment (event_def, path) VALUES 
3391     (3, 'target_copy.call_number.record.simple_record'),
3392     (3, 'usr'),
3393     (3, 'billable_transaction.summary'),
3394     (3, 'circ_lib.billing_address');
3395
3396 -- Sample Purchase Order HTML Template --
3397
3398 INSERT INTO action_trigger.event_definition (id, active, owner, name, hook, validator, reactor, template) 
3399     VALUES (4, 't', 1, 'PO HTML', 'format.po.html', 'NOOP_True', 'ProcessTemplate', 
3400 $$
3401 [%- USE date -%]
3402 [%-
3403     # find a lineitem attribute by name and optional type
3404     BLOCK get_li_attr;
3405         FOR attr IN li.attributes;
3406             IF attr.attr_name == attr_name;
3407                 IF !attr_type OR attr_type == attr.attr_type;
3408                     attr.attr_value;
3409                     LAST;
3410                 END;
3411             END;
3412         END;
3413     END
3414 -%]
3415
3416 <h2>Purchase Order [% target.id %]</h2>
3417 <br/>
3418 date <b>[% date.format(date.now, '%Y%m%d') %]</b>
3419 <br/>
3420
3421 <style>
3422     table td { padding:5px; border:1px solid #aaa;}
3423     table { width:95%; border-collapse:collapse; }
3424 </style>
3425 <table id='vendor-table'>
3426   <tr>
3427     <td valign='top'>Vendor</td>
3428     <td>
3429       <div>[% target.provider.name %]</div>
3430       <div>[% target.provider.addresses.0.street1 %]</div>
3431       <div>[% target.provider.addresses.0.street2 %]</div>
3432       <div>[% target.provider.addresses.0.city %]</div>
3433       <div>[% target.provider.addresses.0.state %]</div>
3434       <div>[% target.provider.addresses.0.country %]</div>
3435       <div>[% target.provider.addresses.0.post_code %]</div>
3436     </td>
3437     <td valign='top'>Ship to / Bill to</td>
3438     <td>
3439       <div>[% target.ordering_agency.name %]</div>
3440       <div>[% target.ordering_agency.billing_address.street1 %]</div>
3441       <div>[% target.ordering_agency.billing_address.street2 %]</div>
3442       <div>[% target.ordering_agency.billing_address.city %]</div>
3443       <div>[% target.ordering_agency.billing_address.state %]</div>
3444       <div>[% target.ordering_agency.billing_address.country %]</div>
3445       <div>[% target.ordering_agency.billing_address.post_code %]</div>
3446     </td>
3447   </tr>
3448 </table>
3449
3450 <br/><br/><br/>
3451
3452 <table>
3453   <thead>
3454     <tr>
3455       <th>PO#</th>
3456       <th>ISBN or Item #</th>
3457       <th>Title</th>
3458       <th>Quantity</th>
3459       <th>Unit Price</th>
3460       <th>Line Total</th>
3461     </tr>
3462   </thead>
3463   <tbody>
3464
3465   [% subtotal = 0 %]
3466   [% FOR li IN target.lineitems %]
3467
3468   <tr>
3469     [% count = li.lineitem_details.size %]
3470     [% price = PROCESS get_li_attr attr_name = 'estimated_price' %]
3471     [% litotal = (price * count) %]
3472     [% subtotal = subtotal + litotal %]
3473     [% isbn = PROCESS get_li_attr attr_name = 'isbn' %]
3474     [% ident = PROCESS get_li_attr attr_name = 'identifier' %]
3475
3476     <td>[% target.id %]</td>
3477     <td>[% isbn || ident %]</td>
3478     <td>[% PROCESS get_li_attr attr_name = 'title' %]</td>
3479     <td>[% count %]</td>
3480     <td>[% price %]</td>
3481     <td>[% litotal %]</td>
3482   </tr>
3483   [% END %]
3484   <tr>
3485     <td/><td/><td/><td/>
3486     <td>Sub Total</td>
3487     <td>[% subtotal %]</td>
3488   </tr>
3489   </tbody>
3490 </table>
3491
3492 <br/>
3493
3494 Total Line Item Count: [% target.lineitems.size %]
3495 $$);
3496
3497 INSERT INTO action_trigger.environment (event_def, path) VALUES 
3498     (4, 'lineitems.lineitem_details.fund'),
3499     (4, 'lineitems.lineitem_details.location'),
3500     (4, 'lineitems.lineitem_details.owning_lib'),
3501     (4, 'ordering_agency.mailing_address'),
3502     (4, 'ordering_agency.billing_address'),
3503     (4, 'provider.addresses'),
3504     (4, 'lineitems.attributes');
3505
3506 SELECT SETVAL('action_trigger.event_definition_id_seq'::TEXT, 100);
3507
3508
3509 CREATE OR REPLACE FUNCTION asset.merge_record_assets( target_record BIGINT, source_record BIGINT ) RETURNS INT AS $func$
3510 DECLARE
3511     moved_objects INT := 0;
3512     source_cn     asset.call_number%ROWTYPE;
3513     target_cn     asset.call_number%ROWTYPE;
3514     metarec       metabib.metarecord%ROWTYPE;
3515     hold          action.hold_request%ROWTYPE;
3516     ser_rec       serial.record_entry%ROWTYPE;
3517     uri_count     INT := 0;
3518     counter       INT := 0;
3519     uri_datafield TEXT;
3520     uri_text      TEXT := '';
3521 BEGIN
3522
3523     -- move any 856 entries on records that have at least one MARC-mapped URI entry
3524     SELECT  INTO uri_count COUNT(*)
3525       FROM  asset.uri_call_number_map m
3526             JOIN asset.call_number cn ON (m.call_number = cn.id)
3527       WHERE cn.record = source_record;
3528
3529     IF uri_count > 0 THEN
3530
3531         SELECT  COUNT(*) INTO counter
3532           FROM  xpath_table(
3533                     'id',
3534                     'marc',
3535                     'acq.lineitem',
3536                     '//*[@tag="856"]',
3537                     'id=' || lineitem
3538                 ) as t(i int,c text);
3539
3540         FOR i IN 1 .. counter LOOP
3541             SELECT  '<datafield xmlns="http://www.loc.gov/MARC21/slim" tag="856">' ||
3542                         array_to_string(
3543                             array_accum(
3544                                 '<subfield code="' || subfield || '">' ||
3545                                 regexp_replace(
3546                                     regexp_replace(
3547                                         regexp_replace(data,'&','&amp;','g'),
3548                                         '>', '&gt;', 'g'
3549                                     ),
3550                                     '<', '&lt;', 'g'
3551                                 ) || '</subfield>'
3552                             ), ''
3553                         ) || '</datafield>' INTO uri_datafield
3554               FROM  xpath_table(
3555                         'id',
3556                         'marc',
3557                         'biblio.record_entry',
3558                         '//*[@tag="856"][position()=' || i || ']/*/@code|' ||
3559                         '//*[@tag="856"][position()=' || i || ']/*[@code]',
3560                         'id=' || source_record
3561                     ) as t(id int,subfield text,data text);
3562
3563             uri_text := uri_text || uri_datafield;
3564         END LOOP;
3565
3566         IF uri_text <> '' THEN
3567             UPDATE  biblio.record_entry
3568               SET   marc = regexp_replace(marc,'(</[^>]*record>)', uri_text || E'\\1')
3569               WHERE id = target_record;
3570         END IF;
3571
3572     END IF;
3573
3574     -- Find and move metarecords to the target record
3575     SELECT  INTO metarec *
3576       FROM  metabib.metarecord
3577       WHERE master_record = source_record;
3578
3579     IF FOUND THEN
3580         UPDATE  metabib.metarecord
3581           SET   master_record = target_record,
3582             mods = NULL
3583           WHERE id = metarec.id;
3584
3585         moved_objects := moved_objects + 1;
3586     END IF;
3587
3588     -- Find call numbers attached to the source ...
3589     FOR source_cn IN SELECT * FROM asset.call_number WHERE record = source_record LOOP
3590
3591         SELECT  INTO target_cn *
3592           FROM  asset.call_number
3593           WHERE label = source_cn.label
3594             AND owning_lib = source_cn.owning_lib
3595             AND record = target_record;
3596
3597         -- ... and if there's a conflicting one on the target ...
3598         IF FOUND THEN
3599
3600             -- ... move the copies to that, and ...
3601             UPDATE  asset.copy
3602               SET   call_number = target_cn.id
3603               WHERE call_number = source_cn.id;
3604
3605             -- ... move V holds to the move-target call number
3606             FOR hold IN SELECT * FROM action.hold_request WHERE target = source_cn.id AND hold_type = 'V' LOOP
3607
3608                 UPDATE  action.hold_request
3609                   SET   target = target_cn.id
3610                   WHERE id = hold.id;
3611
3612                 moved_objects := moved_objects + 1;
3613             END LOOP;
3614
3615         -- ... if not ...
3616         ELSE
3617             -- ... just move the call number to the target record
3618             UPDATE  asset.call_number
3619               SET   record = target_record
3620               WHERE id = source_cn.id;
3621         END IF;
3622
3623         moved_objects := moved_objects + 1;
3624     END LOOP;
3625
3626     -- Find T holds targeting the source record ...
3627     FOR hold IN SELECT * FROM action.hold_request WHERE target = source_record AND hold_type = 'T' LOOP
3628
3629         -- ... and move them to the target record
3630         UPDATE  action.hold_request
3631           SET   target = target_record
3632           WHERE id = hold.id;
3633
3634         moved_objects := moved_objects + 1;
3635     END LOOP;
3636
3637     -- Find serial records targeting the source record ...
3638     FOR ser_rec IN SELECT * FROM serial.record_entry WHERE record = source_record LOOP
3639         -- ... and move them to the target record
3640         UPDATE  serial.record_entry
3641           SET   record = target_record
3642           WHERE id = ser_rec.id;
3643
3644         moved_objects := moved_objects + 1;
3645     END LOOP;
3646
3647     -- Finally, "delete" the source record
3648     DELETE FROM biblio.record_entry WHERE id = source_record;
3649
3650     -- That's all, folks!
3651     RETURN moved_objects;
3652 END;
3653 $func$ LANGUAGE plpgsql;
3654
3655
3656 CREATE OR REPLACE FUNCTION actor.usr_merge_rows( table_name TEXT, col_name TEXT, src_usr INT, dest_usr INT ) RETURNS VOID AS $$
3657 DECLARE
3658     sel TEXT;
3659     upd TEXT;
3660     del TEXT;
3661     cur_row RECORD;
3662 BEGIN
3663     sel := 'SELECT id::BIGINT FROM ' || table_name || ' WHERE ' || quote_ident(col_name) || ' = ' || quote_literal(src_usr);
3664     upd := 'UPDATE ' || table_name || ' SET ' || quote_ident(col_name) || ' = ' || quote_literal(dest_usr) || ' WHERE id = ';
3665     del := 'DELETE FROM ' || table_name || ' WHERE id = ';
3666     FOR cur_row IN EXECUTE sel LOOP
3667         BEGIN
3668             --RAISE NOTICE 'Attempting to merge % %', table_name, cur_row.id;
3669             EXECUTE upd || cur_row.id;
3670         EXCEPTION WHEN unique_violation THEN
3671             --RAISE NOTICE 'Deleting conflicting % %', table_name, cur_row.id;
3672             EXECUTE del || cur_row.id;
3673         END;
3674     END LOOP;
3675 END;
3676 $$ LANGUAGE plpgsql;
3677
3678 COMMENT ON FUNCTION actor.usr_merge_rows(TEXT, TEXT, INT, INT) IS $$
3679 /**
3680  * Attempts to move each row of the specified table from src_user to dest_user.  
3681  * Where conflicts exist, the conflicting "source" row is deleted.
3682  */
3683 $$;
3684
3685
3686 CREATE OR REPLACE FUNCTION actor.usr_merge( src_usr INT, dest_usr INT, del_addrs BOOLEAN, del_cards BOOLEAN, deactivate_cards BOOLEAN ) RETURNS VOID AS $$
3687 BEGIN
3688
3689     -- do some initial cleanup 
3690     UPDATE actor.usr SET card = NULL WHERE id = src_usr;
3691     UPDATE actor.usr SET mailing_address = NULL WHERE id = src_usr;
3692     UPDATE actor.usr SET billing_address = NULL WHERE id = src_usr;
3693
3694     -- actor.*
3695     IF del_cards THEN
3696         DELETE FROM actor.card where usr = src_usr;
3697     ELSE
3698         IF deactivate_cards THEN
3699             UPDATE actor.card SET active = 'f' WHERE usr = src_usr;
3700         END IF;
3701         UPDATE actor.card SET usr = dest_usr WHERE usr = src_usr;
3702     END IF;
3703
3704
3705     IF del_addrs THEN
3706         DELETE FROM actor.usr_address WHERE usr = src_usr;
3707     ELSE
3708         UPDATE actor.usr_address SET usr = dest_usr WHERE usr = src_usr;
3709     END IF;
3710
3711     UPDATE actor.usr_note SET usr = dest_usr WHERE usr = src_usr;
3712     -- dupes are technically OK in actor.usr_standing_penalty, should manually delete them...
3713     UPDATE actor.usr_standing_penalty SET usr = dest_usr WHERE usr = src_usr;
3714     PERFORM actor.usr_merge_rows('actor.usr_org_unit_opt_in', 'usr', src_usr, dest_usr);
3715     PERFORM actor.usr_merge_rows('actor.usr_setting', 'usr', src_usr, dest_usr);
3716
3717     -- permission.*
3718     PERFORM actor.usr_merge_rows('permission.usr_perm_map', 'usr', src_usr, dest_usr);
3719     PERFORM actor.usr_merge_rows('permission.usr_object_perm_map', 'usr', src_usr, dest_usr);
3720     PERFORM actor.usr_merge_rows('permission.usr_grp_map', 'usr', src_usr, dest_usr);
3721     PERFORM actor.usr_merge_rows('permission.usr_work_ou_map', 'usr', src_usr, dest_usr);
3722
3723
3724     -- container.*
3725     PERFORM actor.usr_merge_rows('container.biblio_record_entry_bucket', 'owner', src_usr, dest_usr);
3726     PERFORM actor.usr_merge_rows('container.call_number_bucket', 'owner', src_usr, dest_usr);
3727     PERFORM actor.usr_merge_rows('container.copy_bucket', 'owner', src_usr, dest_usr);
3728     PERFORM actor.usr_merge_rows('container.user_bucket', 'owner', src_usr, dest_usr);
3729     PERFORM actor.usr_merge_rows('container.user_bucket_item', 'target_user', src_usr, dest_usr);
3730
3731     -- vandelay.*
3732     PERFORM actor.usr_merge_rows('vandelay.queue', 'owner', src_usr, dest_usr);
3733
3734     -- money.*
3735     PERFORM actor.usr_merge_rows('money.collections_tracker', 'usr', src_usr, dest_usr);
3736     PERFORM actor.usr_merge_rows('money.collections_tracker', 'collector', src_usr, dest_usr);
3737     UPDATE money.billable_xact SET usr = dest_usr WHERE usr = src_usr;
3738     UPDATE money.billing SET voider = dest_usr WHERE voider = src_usr;
3739     UPDATE money.bnm_payment SET accepting_usr = dest_usr WHERE accepting_usr = src_usr;
3740
3741     -- action.*
3742     UPDATE action.circulation SET usr = dest_usr WHERE usr = src_usr;
3743     UPDATE action.circulation SET circ_staff = dest_usr WHERE circ_staff = src_usr;
3744     UPDATE action.circulation SET checkin_staff = dest_usr WHERE checkin_staff = src_usr;
3745
3746     UPDATE action.hold_request SET usr = dest_usr WHERE usr = src_usr;
3747     UPDATE action.hold_request SET fulfillment_staff = dest_usr WHERE fulfillment_staff = src_usr;
3748     UPDATE action.hold_request SET requestor = dest_usr WHERE requestor = src_usr;
3749     UPDATE action.hold_notification SET notify_staff = dest_usr WHERE notify_staff = src_usr;
3750
3751     UPDATE action.in_house_use SET staff = dest_usr WHERE staff = src_usr;
3752     UPDATE action.non_cataloged_circulation SET staff = dest_usr WHERE staff = src_usr;
3753     UPDATE action.non_cataloged_circulation SET patron = dest_usr WHERE patron = src_usr;
3754     UPDATE action.non_cat_in_house_use SET staff = dest_usr WHERE staff = src_usr;
3755     UPDATE action.survey_response SET usr = dest_usr WHERE usr = src_usr;
3756
3757     -- acq.*
3758     UPDATE acq.fund_allocation SET allocator = dest_usr WHERE allocator = src_usr;
3759     PERFORM actor.usr_merge_rows('acq.picklist', 'owner', src_usr, dest_usr);
3760     UPDATE acq.purchase_order SET owner = dest_usr WHERE owner = src_usr;
3761     UPDATE acq.po_note SET creator = dest_usr WHERE creator = src_usr;
3762     UPDATE acq.po_note SET editor = dest_usr WHERE editor = src_usr;
3763     UPDATE acq.lineitem_note SET creator = dest_usr WHERE creator = src_usr;
3764     UPDATE acq.lineitem_note SET editor = dest_usr WHERE editor = src_usr;
3765     UPDATE acq.lineitem_usr_attr_definition SET usr = dest_usr WHERE usr = src_usr;
3766
3767     -- asset.*
3768     UPDATE asset.copy SET creator = dest_usr WHERE creator = src_usr;
3769     UPDATE asset.copy SET editor = dest_usr WHERE editor = src_usr;
3770     UPDATE asset.copy_note SET creator = dest_usr WHERE creator = src_usr;
3771     UPDATE asset.call_number SET creator = dest_usr WHERE creator = src_usr;
3772     UPDATE asset.call_number SET editor = dest_usr WHERE editor = src_usr;
3773     UPDATE asset.call_number_note SET creator = dest_usr WHERE creator = src_usr;
3774
3775     -- serial.*
3776     UPDATE serial.record_entry SET creator = dest_usr WHERE creator = src_usr;
3777     UPDATE serial.record_entry SET editor = dest_usr WHERE editor = src_usr;
3778
3779     -- reporter.*
3780     -- It's not uncommon to define the reporter schema in a replica 
3781     -- DB only, so don't assume these tables exist in the write DB.
3782     BEGIN
3783         PERFORM actor.usr_merge_rows('reporter.template', 'owner', src_usr, dest_usr);
3784     EXCEPTION WHEN undefined_table THEN
3785         -- do nothing
3786     END;
3787     BEGIN
3788         PERFORM actor.usr_merge_rows('reporter.report', 'owner', src_usr, dest_usr);
3789     EXCEPTION WHEN undefined_table THEN
3790         -- do nothing
3791     END;
3792     BEGIN
3793         PERFORM actor.usr_merge_rows('reporter.schedule', 'runner', src_usr, dest_usr);
3794     EXCEPTION WHEN undefined_table THEN
3795         -- do nothing
3796     END;
3797     BEGIN
3798         PERFORM actor.usr_merge_rows('reporter.template_folder', 'owner', src_usr, dest_usr);
3799     EXCEPTION WHEN undefined_table THEN
3800         -- do nothing
3801     END;
3802     BEGIN
3803         PERFORM actor.usr_merge_rows('reporter.report_folder', 'owner', src_usr, dest_usr);
3804     EXCEPTION WHEN undefined_table THEN
3805         -- do nothing
3806     END;
3807     BEGIN
3808         PERFORM actor.usr_merge_rows('reporter.output_folder', 'owner', src_usr, dest_usr);
3809     EXCEPTION WHEN undefined_table THEN
3810         -- do nothing
3811     END;
3812
3813     -- Finally, delete the source user
3814     DELETE FROM actor.usr WHERE id = src_usr;
3815
3816 END;
3817 $$ LANGUAGE plpgsql;
3818
3819 COMMENT ON FUNCTION actor.usr_merge(INT, INT, BOOLEAN, BOOLEAN, BOOLEAN) IS $$
3820 /**
3821  * Merges all user date from src_usr to dest_usr.  When collisions occur, 
3822  * keep dest_usr's data and delete src_usr's data.
3823  */
3824 $$;
3825
3826
3827
3828 CREATE OR REPLACE FUNCTION actor.approve_pending_address(pending_id INT) RETURNS BIGINT AS $$
3829 DECLARE
3830     old_id INT;
3831 BEGIN
3832     SELECT INTO old_id replaces FROM actor.usr_address where id = pending_id;
3833     IF old_id IS NULL THEN
3834         UPDATE actor.usr_address SET pending = 'f' WHERE id = pending_id;
3835         RETURN pending_id;
3836     END IF;
3837     -- address replaces an existing address
3838     DELETE FROM actor.usr_address WHERE id = -old_id;
3839     UPDATE actor.usr_address SET id = -id WHERE id = old_id;
3840     UPDATE actor.usr_address SET replaces = NULL, id = old_id, pending = 'f' WHERE id = pending_id;
3841     RETURN old_id;
3842 END
3843 $$ LANGUAGE plpgsql;
3844
3845 COMMENT ON FUNCTION actor.approve_pending_address(INT) IS $$
3846 /**
3847  * Replaces an address with a pending address.  This is done by giving the pending 
3848  * address the ID of the old address.  The replaced address is retained with -id.
3849  */
3850 $$;
3851
3852 COMMIT;
3853
3854
3855 ---------!!!!!!!!!!!!!!!!!!!!!!---------------
3856 --  Must go after COMMIT!!
3857 ---------!!!!!!!!!!!!!!!!!!!!!!---------------
3858
3859 INSERT INTO config.z3950_source (name, label, host, port, db, auth)
3860         VALUES ('biblios', oils_i18n_gettext('biblios','biblios.net', 'czs', 'label'), 'z3950.biblios.net', 210, 'bibliographic', FALSE);
3861  
3862
3863 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
3864         VALUES (19, 'biblios','tcn', oils_i18n_gettext(19, 'Title Control Number', 'cza', 'label'), 12, 1);
3865 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
3866         VALUES (20, 'biblios', 'isbn', oils_i18n_gettext(20, 'ISBN', 'cza', 'label'), 7, 6);
3867 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
3868         VALUES (21, 'biblios', 'lccn', oils_i18n_gettext(21, 'LCCN', 'cza', 'label'), 9, 1);
3869 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
3870         VALUES (22, 'biblios', 'author', oils_i18n_gettext(22, 'Author', 'cza', 'label'), 1003, 6);
3871 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
3872         VALUES (23, 'biblios', 'title', oils_i18n_gettext(23, 'Title', 'cza', 'label'), 4, 6);
3873 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
3874         VALUES (24, 'biblios', 'issn', oils_i18n_gettext(24, 'ISSN', 'cza', 'label'), 8, 1);
3875 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
3876         VALUES (25, 'biblios', 'publisher', oils_i18n_gettext(25, 'Publisher', 'cza', 'label'), 1018, 6);
3877 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
3878         VALUES (26, 'biblios', 'pubdate', oils_i18n_gettext(26, 'Publication Date', 'cza', 'label'), 31, 1);
3879 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
3880         VALUES (27, 'biblios', 'item_type', oils_i18n_gettext(27, 'Item Type', 'cza', 'label'), 1001, 1);
3881
3882 INSERT INTO permission.perm_list (code, description) VALUES ('DELETE_FUNDING_SOURCE', 'Allow a user to delete a funding source');
3883 INSERT INTO permission.perm_list (code, description) VALUES ('VIEW_FUNDING_SOURCE', 'Allow a user to view a funding source');
3884 INSERT INTO permission.perm_list (code, description) VALUES ('UPDATE_FUNDING_SOURCE', 'Allow a user to update a funding source');
3885 INSERT INTO permission.perm_list (code, description) VALUES ('CREATE_FUND', 'Allow a user to create a new fund');
3886 INSERT INTO permission.perm_list (code, description) VALUES ('DELETE_FUND', 'Allow a user to delete a fund');
3887 INSERT INTO permission.perm_list (code, description) VALUES ('VIEW_FUND', 'Allow a user to view a fund');
3888 INSERT INTO permission.perm_list (code, description) VALUES ('UPDATE_FUND', 'Allow a user to update a fund');
3889 INSERT INTO permission.perm_list (code, description) VALUES ('CREATE_FUND_ALLOCATION', 'Allow a user to create a new fund allocation');
3890 INSERT INTO permission.perm_list (code, description) VALUES ('DELETE_FUND_ALLOCATION', 'Allow a user to delete a fund allocation');
3891 INSERT INTO permission.perm_list (code, description) VALUES ('VIEW_FUND_ALLOCATION', 'Allow a user to view a fund allocation');
3892 INSERT INTO permission.perm_list (code, description) VALUES ('UPDATE_FUND_ALLOCATION', 'Allow a user to update a fund allocation');
3893 INSERT INTO permission.perm_list (code, description) VALUES ('GENERAL_ACQ', 'Lowest level permission required to access the ACQ interface');
3894 INSERT INTO permission.perm_list (code, description) VALUES ('CREATE_PROVIDER', 'Allow a user to create a new provider');
3895 INSERT INTO permission.perm_list (code, description) VALUES ('DELETE_PROVIDER', 'Allow a user to delate a provider');
3896 INSERT INTO permission.perm_list (code, description) VALUES ('VIEW_PROVIDER', 'Allow a user to view a provider');
3897 INSERT INTO permission.perm_list (code, description) VALUES ('UPDATE_PROVIDER', 'Allow a user to update a provider');
3898 INSERT INTO permission.perm_list (code, description) VALUES ('ADMIN_FUNDING_SOURCE', 'Allow a user to create/view/update/delete a funding source');
3899 INSERT INTO permission.perm_list (code, description) VALUES ('ADMIN_FUND', 'Allow a user to create/view/update/delete a fund');
3900 INSERT INTO permission.perm_list (code, description) VALUES ('MANAGE_FUNDING_SOURCE', 'Allow a user to view/credit/debit a funding source');
3901 INSERT INTO permission.perm_list (code, description) VALUES ('MANAGE_FUND', 'Allow a user to view/credit/debit a fund');
3902 INSERT INTO permission.perm_list (code, description) VALUES ('CREATE_PICKLIST', 'Allows a user to create a picklist');
3903 INSERT INTO permission.perm_list (code, description) VALUES ('ADMIN_PROVIDER', 'Allow a user to create/view/update/delete a provider');
3904 INSERT INTO permission.perm_list (code, description) VALUES ('MANAGE_PROVIDER', 'Allow a user to view and purchase from a provider');
3905 INSERT INTO permission.perm_list (code, description) VALUES ('VIEW_PICKLIST', 'Allow a user to view another users picklist');
3906 INSERT INTO permission.perm_list (code, description) VALUES ('DELETE_RECORD', 'Allow a staff member to directly remove a bibliographic record');
3907 INSERT INTO permission.perm_list (code, description) VALUES ('ADMIN_CURRENCY_TYPE', 'Allow a user to create/view/update/delete a currency_type');
3908 INSERT INTO permission.perm_list (code, description) VALUES ('MARK_BAD_DEBT', 'Allow a user to mark a transaction as bad (unrecoverable) debt');
3909 INSERT INTO permission.perm_list (code, description) VALUES ('VIEW_BILLING_TYPE', 'Allow a user to view billing types');
3910 INSERT INTO permission.perm_list (code, description) VALUES ('MARK_ITEM_AVAILABLE', 'Allow a user to mark an item status as ''available''');
3911 INSERT INTO permission.perm_list (code, description) VALUES ('MARK_ITEM_CHECKED_OUT', 'Allow a user to mark an item status as ''checked out''');
3912 INSERT INTO permission.perm_list (code, description) VALUES ('MARK_ITEM_BINDERY', 'Allow a user to mark an item status as ''bindery''');
3913 INSERT INTO permission.perm_list (code, description) VALUES ('MARK_ITEM_LOST', 'Allow a user to mark an item status as ''lost''');
3914 INSERT INTO permission.perm_list (code, description) VALUES ('MARK_ITEM_MISSING', 'Allow a user to mark an item status as ''missing''');
3915 INSERT INTO permission.perm_list (code, description) VALUES ('MARK_ITEM_IN_PROCESS', 'Allow a user to mark an item status as ''in process''');
3916 INSERT INTO permission.perm_list (code, description) VALUES ('MARK_ITEM_IN_TRANSIT', 'Allow a user to mark an item status as ''in transit''');
3917 INSERT INTO permission.perm_list (code, description) VALUES ('MARK_ITEM_RESHELVING', 'Allow a user to mark an item status as ''reshelving''');
3918 INSERT INTO permission.perm_list (code, description) VALUES ('MARK_ITEM_ON_HOLDS_SHELF', 'Allow a user to mark an item status as ''on holds shelf''');
3919 INSERT INTO permission.perm_list (code, description) VALUES ('MARK_ITEM_ON_ORDER', 'Allow a user to mark an item status as ''on order''');
3920 INSERT INTO permission.perm_list (code, description) VALUES ('MARK_ITEM_ILL', 'Allow a user to mark an item status as ''inter-library loan''');
3921 INSERT INTO permission.perm_list (code, description) VALUES ('group_application.user.staff.acq', 'Allows a user to add/remove/edit users in the "ACQ" group');
3922 INSERT INTO permission.perm_list (code, description) VALUES ('CREATE_PURCHASE_ORDER', 'Allows a user to create a purchase order');
3923 INSERT INTO permission.perm_list (code, description) VALUES ('VIEW_PURCHASE_ORDER', 'Allows a user to view a purchase order');
3924 INSERT INTO permission.perm_list (code, description) VALUES ('IMPORT_ACQ_LINEITEM_BIB_RECORD', 'Allows a user to import a bib record from the acq staging area (on-order record) into the ILS bib data set');
3925 INSERT INTO permission.perm_list (code, description) VALUES ('RECEIVE_PURCHASE_ORDER', 'Allows a user to mark a purchase order, lineitem, or individual copy as received');
3926 INSERT INTO permission.perm_list (code, description) VALUES ('VIEW_ORG_SETTINGS','Allows a user to view all org settings at the specified level');
3927 INSERT INTO permission.perm_list (code, description) VALUES ('CREATE_MFHD_RECORD', 'Allows a user to create a new MFHD record');
3928 INSERT INTO permission.perm_list (code, description) VALUES ('UPDATE_MFHD_RECORD', 'Allows a user to update an MFHD record');
3929 INSERT INTO permission.perm_list (code, description) VALUES ('DELETE_MFHD_RECORD', 'Allows a user to delete an MFHD record');
3930 INSERT INTO permission.perm_list (code, description) VALUES ('CREATE_FUNDING_SOURCE', 'Allow a user to create a new funding source');
3931
3932 INSERT INTO permission.perm_list (code) VALUES ('CREATE_ACQ_FUNDING_SOURCE');
3933 INSERT INTO permission.perm_list (code) VALUES ('DELETE_ACQ_FUNDING_SOURCE');
3934 INSERT INTO permission.perm_list (code) VALUES ('UPDATE_ACQ_FUNDING_SOURCE');
3935 INSERT INTO permission.perm_list (code) VALUES ('VIEW_ACQ_FUNDING_SOURCE');
3936 INSERT INTO permission.perm_list (code) VALUES ('UPDATE_ORG_UNIT_SETTING.global.password_regex');
3937 INSERT INTO permission.perm_list (code) VALUES ('UPDATE_ORG_UNIT_SETTING.global.juvenile_age_threshold');
3938 INSERT INTO permission.perm_list (code) VALUES ('UPDATE_ORG_UNIT_SETTING.patron.password.use_phone');
3939
3940 INSERT INTO permission.grp_tree (name, parent, description, perm_interval, usergroup, application_perm) VALUES ('Acquisitions', 3, NULL, '3 years', TRUE, 'group_application.user.staff.acq');
3941
3942
3943 SELECT SETVAL('permission.perm_list_id_seq'::TEXT, (SELECT MAX(id) FROM permission.perm_list));
3944
3945 ALTER TABLE auditor.action_hold_request_history ADD COLUMN cancel_cause INT;
3946 ALTER TABLE auditor.action_hold_request_history ADD COLUMN cancel_note TEXT;
3947
3948 CREATE OR REPLACE FUNCTION tmp_populate_p_b_bt () RETURNS BOOL AS $$
3949 DECLARE
3950     p   RECORD;
3951 BEGIN
3952     FOR p IN
3953         SELECT  DISTINCT xact
3954           FROM  money.payment
3955           WHERE NOT voided
3956                 AND amount > 0.0
3957     LOOP
3958
3959         INSERT INTO money.materialized_payment_by_billing_type (
3960             xact, payment, billing, payment_ts, billing_ts,
3961             payment_type, billing_type, amount, billing_ou, payment_ou
3962         ) SELECT    xact, payment, billing, payment_ts, billing_ts,
3963                     payment_type, billing_type, amount, billing_ou, payment_ou
3964           FROM money.payment_by_billing_type( p.xact );
3965
3966     END LOOP;
3967
3968     RETURN TRUE;
3969 END;
3970 $$ LANGUAGE PLPGSQL;
3971
3972 SELECT tmp_populate_p_b_bt();
3973
3974 DROP FUNCTION tmp_populate_p_b_bt ();
3975
3976
3977 UPDATE config.xml_transform SET xslt=$$<xsl:stylesheet xmlns="http://www.loc.gov/mods/v3" xmlns:marc="http://www.loc.gov/MARC21/slim"
3978         xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
3979         exclude-result-prefixes="xlink marc" version="1.0">
3980         <xsl:output encoding="UTF-8" indent="yes" method="xml"/>
3981
3982         <xsl:variable name="ascii">
3983                 <xsl:text> !"#$%&amp;'()*+,-./0123456789:;&lt;=&gt;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~</xsl:text>
3984         </xsl:variable>
3985
3986         <xsl:variable name="latin1">
3987                 <xsl:text> ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ</xsl:text>
3988         </xsl:variable>
3989         <!-- Characters that usually don't need to be escaped -->
3990         <xsl:variable name="safe">
3991                 <xsl:text>!'()*-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~</xsl:text>
3992         </xsl:variable>
3993
3994         <xsl:variable name="hex">0123456789ABCDEF</xsl:variable>
3995
3996
3997         
3998         <!--MARC21slim2MODS3-3.xsl
3999 Revision 1.27 - Mapped 648 to <subject> 2009/03/13 tmee
4000 Revision 1.26 - Added subfield $s mapping for 130/240/730  2008/10/16 tmee
4001 Revision 1.25 - Mapped 040e to <descriptiveStandard> and Leader/18 to <descriptive standard>aacr2  2008/09/18 tmee
4002 Revision 1.24 - Mapped 852 subfields $h, $i, $j, $k, $l, $m, $t to <shelfLocation> and 852 subfield $u to <physicalLocation> with @xlink 2008/09/17 tmee
4003 Revision 1.23 - Commented out xlink/uri for subfield 0 for 130/240/730, 100/700, 110/710, 111/711 as these are currently unactionable  2008/09/17  tmee
4004 Revision 1.22 - Mapped 022 subfield $l to type "issn-l" subfield $m to output identifier element with corresponding @type and @invalid eq 'yes'2008/09/17  tmee
4005 Revision 1.21 - Mapped 856 ind2=1 or ind2=2 to <relatedItem><location><url>  2008/07/03  tmee
4006 Revision 1.20 - Added genre w/@auth="contents of 2" and type= "musical composition"  2008/07/01  tmee
4007 Revision 1.19 - Added genre offprint for 008/24+ BK code 2  2008/07/01  tmee
4008 Revision 1.18 - Added xlink/uri for subfield 0 for 130/240/730, 100/700, 110/710, 111/711  2008/06/26  tmee
4009 Revision 1.17 - Added mapping of 662 2008/05/14 tmee    
4010 Revision 1.16 - Changed @authority from "marc" to "marcgt" for 007 and 008 codes mapped to a term in <genre> 2007/07/10  tmee
4011 Revision 1.15 - For field 630, moved call to part template outside title element  2007/07/10  tmee
4012 Revision 1.14 - Fixed template isValid and fields 010, 020, 022, 024, 028, and 037 to output additional identifier elements with corresponding @type and @invalid eq 'yes' when subfields z or y (in the case of 022) exist in the MARCXML ::: 2007/01/04 17:35:20 cred
4013 Revision 1.13 - Changed order of output under cartographics to reflect schema  2006/11/28  tmee
4014 Revision 1.12 - Updated to reflect MODS 3.2 Mapping  2006/10/11  tmee
4015 Revision 1.11 - The attribute objectPart moved from <languageTerm> to <language>  2006/04/08  jrad
4016 Revision 1.10 - MODS 3.1 revisions to language and classification elements  (plus ability to find marc:collection embedded in wrapper elements such as SRU zs: wrappers)  2006/02/06  ggar
4017 Revision 1.9 - Subfield $y was added to field 242 2004/09/02 10:57 jrad
4018 Revision 1.8 - Subject chopPunctuation expanded and attribute fixes 2004/08/12 jrad
4019 Revision 1.7 - 2004/03/25 08:29 jrad
4020 Revision 1.6 - Various validation fixes 2004/02/20 ntra
4021 Revision 1.5 - MODS2 to MODS3 updates, language unstacking and de-duping, chopPunctuation expanded  2003/10/02 16:18:58  ntra
4022 Revision 1.3 - Additional Changes not related to MODS Version 2.0 by ntra
4023 Revision 1.2 - Added Log Comment  2003/03/24 19:37:42  ckeith
4024 -->
4025         <xsl:template match="/">
4026                 <xsl:choose>
4027                         <xsl:when test="//marc:collection">
4028                                 <modsCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4029                                         xsi:schemaLocation="http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-2.xsd">
4030                                         <xsl:for-each select="//marc:collection/marc:record">
4031                                                 <mods version="3.3">
4032                                                         <xsl:call-template name="marcRecord"/>
4033                                                 </mods>
4034                                         </xsl:for-each>
4035                                 </modsCollection>
4036                         </xsl:when>
4037                         <xsl:otherwise>
4038                                 <mods xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.3"
4039                                         xsi:schemaLocation="http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-2.xsd">
4040                                         <xsl:for-each select="//marc:record">
4041                                                 <xsl:call-template name="marcRecord"/>
4042                                         </xsl:for-each>
4043                                 </mods>
4044                         </xsl:otherwise>
4045                 </xsl:choose>
4046         </xsl:template>
4047         <xsl:template name="marcRecord">
4048                 <xsl:variable name="leader" select="marc:leader"/>
4049                 <xsl:variable name="leader6" select="substring($leader,7,1)"/>
4050                 <xsl:variable name="leader7" select="substring($leader,8,1)"/>
4051                 <xsl:variable name="controlField008" select="marc:controlfield[@tag='008']"/>
4052                 <xsl:variable name="typeOf008">
4053                         <xsl:choose>
4054                                 <xsl:when test="$leader6='a'">
4055                                         <xsl:choose>
4056                                                 <xsl:when
4057                                                         test="$leader7='a' or $leader7='c' or $leader7='d' or $leader7='m'">BK</xsl:when>
4058                                                 <xsl:when test="$leader7='b' or $leader7='i' or $leader7='s'">SE</xsl:when>
4059                                         </xsl:choose>
4060                                 </xsl:when>
4061                                 <xsl:when test="$leader6='t'">BK</xsl:when>
4062                                 <xsl:when test="$leader6='p'">MM</xsl:when>
4063                                 <xsl:when test="$leader6='m'">CF</xsl:when>
4064                                 <xsl:when test="$leader6='e' or $leader6='f'">MP</xsl:when>
4065                                 <xsl:when test="$leader6='g' or $leader6='k' or $leader6='o' or $leader6='r'">VM</xsl:when>
4066                                 <xsl:when test="$leader6='c' or $leader6='d' or $leader6='i' or $leader6='j'"
4067                                 >MU</xsl:when>
4068                         </xsl:choose>
4069                 </xsl:variable>
4070                 <xsl:for-each select="marc:datafield[@tag='245']">
4071                         <titleInfo>
4072                                 <xsl:variable name="title">
4073                                         <xsl:choose>
4074                                                 <xsl:when test="marc:subfield[@code='b']">
4075                                                         <xsl:call-template name="specialSubfieldSelect">
4076                                                                 <xsl:with-param name="axis">b</xsl:with-param>
4077                                                                 <xsl:with-param name="beforeCodes">afgk</xsl:with-param>
4078                                                         </xsl:call-template>
4079                                                 </xsl:when>
4080                                                 <xsl:otherwise>
4081                                                         <xsl:call-template name="subfieldSelect">
4082                                                                 <xsl:with-param name="codes">abfgk</xsl:with-param>
4083                                                         </xsl:call-template>
4084                                                 </xsl:otherwise>
4085                                         </xsl:choose>
4086                                 </xsl:variable>
4087                                 <xsl:variable name="titleChop">
4088                                         <xsl:call-template name="chopPunctuation">
4089                                                 <xsl:with-param name="chopString">
4090                                                         <xsl:value-of select="$title"/>
4091                                                 </xsl:with-param>
4092                                         </xsl:call-template>
4093                                 </xsl:variable>
4094                                 <xsl:choose>
4095                                         <xsl:when test="@ind2&gt;0">
4096                                                 <nonSort>
4097                                                         <xsl:value-of select="substring($titleChop,1,@ind2)"/>
4098                                                 </nonSort>
4099                                                 <title>
4100                                                         <xsl:value-of select="substring($titleChop,@ind2+1)"/>
4101                                                 </title>
4102                                         </xsl:when>
4103                                         <xsl:otherwise>
4104                                                 <title>
4105                                                         <xsl:value-of select="$titleChop"/>
4106                                                 </title>
4107                                         </xsl:otherwise>
4108                                 </xsl:choose>
4109                                 <xsl:if test="marc:subfield[@code='b']">
4110                                         <subTitle>
4111                                                 <xsl:call-template name="chopPunctuation">
4112                                                         <xsl:with-param name="chopString">
4113                                                                 <xsl:call-template name="specialSubfieldSelect">
4114                                                                         <xsl:with-param name="axis">b</xsl:with-param>
4115                                                                         <xsl:with-param name="anyCodes">b</xsl:with-param>
4116                                                                         <xsl:with-param name="afterCodes">afgk</xsl:with-param>
4117                                                                 </xsl:call-template>
4118                                                         </xsl:with-param>
4119                                                 </xsl:call-template>
4120                                         </subTitle>
4121                                 </xsl:if>
4122                                 <xsl:call-template name="part"/>
4123                         </titleInfo>
4124                 </xsl:for-each>
4125                 <xsl:for-each select="marc:datafield[@tag='210']">
4126                         <titleInfo type="abbreviated">
4127                                 <title>
4128                                         <xsl:call-template name="chopPunctuation">
4129                                                 <xsl:with-param name="chopString">
4130                                                         <xsl:call-template name="subfieldSelect">
4131                                                                 <xsl:with-param name="codes">a</xsl:with-param>
4132                                                         </xsl:call-template>
4133                                                 </xsl:with-param>
4134                                         </xsl:call-template>
4135                                 </title>
4136                                 <xsl:call-template name="subtitle"/>
4137                         </titleInfo>
4138                 </xsl:for-each>
4139                 <xsl:for-each select="marc:datafield[@tag='242']">
4140                         <titleInfo type="translated">
4141                                 <!--09/01/04 Added subfield $y-->
4142                                 <xsl:for-each select="marc:subfield[@code='y']">
4143                                         <xsl:attribute name="lang">
4144                                                 <xsl:value-of select="text()"/>
4145                                         </xsl:attribute>
4146                                 </xsl:for-each>
4147                                 <xsl:for-each select="marc:subfield[@code='i']">
4148                                         <xsl:attribute name="displayLabel">
4149                                                 <xsl:value-of select="text()"/>
4150                                         </xsl:attribute>
4151                                 </xsl:for-each>
4152                                 <title>
4153                                         <xsl:call-template name="chopPunctuation">
4154                                                 <xsl:with-param name="chopString">
4155                                                         <xsl:call-template name="subfieldSelect">
4156                                                                 <!-- 1/04 removed $h, b -->
4157                                                                 <xsl:with-param name="codes">a</xsl:with-param>
4158                                                         </xsl:call-template>
4159                                                 </xsl:with-param>
4160                                         </xsl:call-template>
4161                                 </title>
4162                                 <!-- 1/04 fix -->
4163                                 <xsl:call-template name="subtitle"/>
4164                                 <xsl:call-template name="part"/>
4165                         </titleInfo>
4166                 </xsl:for-each>
4167                 <xsl:for-each select="marc:datafield[@tag='246']">
4168                         <titleInfo type="alternative">
4169                                 <xsl:for-each select="marc:subfield[@code='i']">
4170                                         <xsl:attribute name="displayLabel">
4171                                                 <xsl:value-of select="text()"/>
4172                                         </xsl:attribute>
4173                                 </xsl:for-each>
4174                                 <title>
4175                                         <xsl:call-template name="chopPunctuation">
4176                                                 <xsl:with-param name="chopString">
4177                                                         <xsl:call-template name="subfieldSelect">
4178                                                                 <!-- 1/04 removed $h, $b -->
4179                                                                 <xsl:with-param name="codes">af</xsl:with-param>
4180                                                         </xsl:call-template>
4181                                                 </xsl:with-param>
4182                                         </xsl:call-template>
4183                                 </title>
4184                                 <xsl:call-template name="subtitle"/>
4185                                 <xsl:call-template name="part"/>
4186                         </titleInfo>
4187                 </xsl:for-each>
4188                 <xsl:for-each
4189                         select="marc:datafield[@tag='130']|marc:datafield[@tag='240']|marc:datafield[@tag='730'][@ind2!='2']">
4190                         <titleInfo type="uniform">
4191                                 <title>
4192                                         <!-- deleted uri for subfield 0
4193                                                 <xsl:call-template name="uri"/>
4194                                         -->
4195
4196                                         <xsl:variable name="str">
4197                                                 <xsl:for-each select="marc:subfield">
4198                                                         <xsl:if
4199                                                                 test="(contains('adfklmors',@code) and (not(../marc:subfield[@code='n' or @code='p']) or (following-sibling::marc:subfield[@code='n' or @code='p'])))">
4200                                                                 <xsl:value-of select="text()"/>
4201                                                                 <xsl:text> </xsl:text>
4202                                                         </xsl:if>
4203                                                 </xsl:for-each>
4204                                         </xsl:variable>
4205                                         <xsl:call-template name="chopPunctuation">
4206                                                 <xsl:with-param name="chopString">
4207                                                         <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
4208                                                 </xsl:with-param>
4209                                         </xsl:call-template>
4210                                 </title>
4211                                 <xsl:call-template name="part"/>
4212                         </titleInfo>
4213                 </xsl:for-each>
4214                 <xsl:for-each select="marc:datafield[@tag='740'][@ind2!='2']">
4215                         <titleInfo type="alternative">
4216                                 <title>
4217                                         <xsl:call-template name="chopPunctuation">
4218                                                 <xsl:with-param name="chopString">
4219                                                         <xsl:call-template name="subfieldSelect">
4220                                                                 <xsl:with-param name="codes">ah</xsl:with-param>
4221                                                         </xsl:call-template>
4222                                                 </xsl:with-param>
4223                                         </xsl:call-template>
4224                                 </title>
4225                                 <xsl:call-template name="part"/>
4226                         </titleInfo>
4227                 </xsl:for-each>
4228                 <xsl:for-each select="marc:datafield[@tag='100']">
4229                         <name type="personal">
4230
4231                                 <!-- deleted uri for subfield 0
4232                                 <xsl:call-template name="uri"/>
4233                                 -->
4234
4235                                 <xsl:call-template name="nameABCDQ"/>
4236                                 <xsl:call-template name="affiliation"/>
4237                                 <role>
4238                                         <roleTerm authority="marcrelator" type="text">creator</roleTerm>
4239                                 </role>
4240                                 <xsl:call-template name="role"/>
4241                         </name>
4242                 </xsl:for-each>
4243                 <xsl:for-each select="marc:datafield[@tag='110']">
4244                         <name type="corporate">
4245
4246                                 <!-- deleted uri for subfield 0
4247                                         <xsl:call-template name="uri"/>
4248                                 -->
4249
4250                                 <xsl:call-template name="nameABCDN"/>
4251                                 <role>
4252                                         <roleTerm authority="marcrelator" type="text">creator</roleTerm>
4253                                 </role>
4254                                 <xsl:call-template name="role"/>
4255                         </name>
4256                 </xsl:for-each>
4257                 <xsl:for-each select="marc:datafield[@tag='111']">
4258                         <name type="conference">
4259
4260                                 <!-- deleted uri for subfield 0
4261                                         <xsl:call-template name="uri"/>
4262                                 -->
4263
4264                                 <xsl:call-template name="nameACDEQ"/>
4265                                 <role>
4266                                         <roleTerm authority="marcrelator" type="text">creator</roleTerm>
4267                                 </role>
4268                                 <xsl:call-template name="role"/>
4269                         </name>
4270                 </xsl:for-each>
4271                 <xsl:for-each select="marc:datafield[@tag='700'][not(marc:subfield[@code='t'])]">
4272                         <name type="personal">
4273
4274                                 <!-- deleted uri for subfield 0
4275                                         <xsl:call-template name="uri"/>
4276                                 -->
4277
4278                                 <xsl:call-template name="nameABCDQ"/>
4279                                 <xsl:call-template name="affiliation"/>
4280                                 <xsl:call-template name="role"/>
4281                         </name>
4282                 </xsl:for-each>
4283                 <xsl:for-each select="marc:datafield[@tag='710'][not(marc:subfield[@code='t'])]">
4284                         <name type="corporate">
4285
4286                                 <!-- deleted uri for subfield 0
4287                                         <xsl:call-template name="uri"/>
4288                                 -->
4289
4290                                 <xsl:call-template name="nameABCDN"/>
4291                                 <xsl:call-template name="role"/>
4292                         </name>
4293                 </xsl:for-each>
4294                 <xsl:for-each select="marc:datafield[@tag='711'][not(marc:subfield[@code='t'])]">
4295                         <name type="conference">
4296
4297                                 <!-- deleted uri for subfield 0
4298                                         <xsl:call-template name="uri"/>
4299                                 -->
4300
4301                                 <xsl:call-template name="nameACDEQ"/>
4302                                 <xsl:call-template name="role"/>
4303                         </name>
4304                 </xsl:for-each>
4305                 <xsl:for-each select="marc:datafield[@tag='720'][not(marc:subfield[@code='t'])]">
4306                         <name>
4307                                 <xsl:if test="@ind1=1">
4308                                         <xsl:attribute name="type">
4309                                                 <xsl:text>personal</xsl:text>
4310                                         </xsl:attribute>
4311                                 </xsl:if>
4312                                 <namePart>
4313                                         <xsl:value-of select="marc:subfield[@code='a']"/>
4314                                 </namePart>
4315                                 <xsl:call-template name="role"/>
4316                         </name>
4317                 </xsl:for-each>
4318                 <typeOfResource>
4319                         <xsl:if test="$leader7='c'">
4320                                 <xsl:attribute name="collection">yes</xsl:attribute>
4321                         </xsl:if>
4322                         <xsl:if test="$leader6='d' or $leader6='f' or $leader6='p' or $leader6='t'">
4323                                 <xsl:attribute name="manuscript">yes</xsl:attribute>
4324                         </xsl:if>
4325                         <xsl:choose>
4326                                 <xsl:when test="$leader6='a' or $leader6='t'">text</xsl:when>
4327                                 <xsl:when test="$leader6='e' or $leader6='f'">cartographic</xsl:when>
4328                                 <xsl:when test="$leader6='c' or $leader6='d'">notated music</xsl:when>
4329                                 <xsl:when test="$leader6='i'">sound recording-nonmusical</xsl:when>
4330                                 <xsl:when test="$leader6='j'">sound recording-musical</xsl:when>
4331                                 <xsl:when test="$leader6='k'">still image</xsl:when>
4332                                 <xsl:when test="$leader6='g'">moving image</xsl:when>
4333                                 <xsl:when test="$leader6='r'">three dimensional object</xsl:when>
4334                                 <xsl:when test="$leader6='m'">software, multimedia</xsl:when>
4335                                 <xsl:when test="$leader6='p'">mixed material</xsl:when>
4336                         </xsl:choose>
4337                 </typeOfResource>
4338                 <xsl:if test="substring($controlField008,26,1)='d'">
4339                         <genre authority="marcgt">globe</genre>
4340                 </xsl:if>
4341                 <xsl:if
4342                         test="marc:controlfield[@tag='007'][substring(text(),1,1)='a'][substring(text(),2,1)='r']">
4343                         <genre authority="marcgt">remote-sensing image</genre>
4344                 </xsl:if>
4345                 <xsl:if test="$typeOf008='MP'">
4346                         <xsl:variable name="controlField008-25" select="substring($controlField008,26,1)"/>
4347                         <xsl:choose>
4348                                 <xsl:when
4349                                         test="$controlField008-25='a' or $controlField008-25='b' or $controlField008-25='c' or marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='j']">
4350                                         <genre authority="marcgt">map</genre>
4351                                 </xsl:when>
4352                                 <xsl:when
4353                                         test="$controlField008-25='e' or marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='d']">
4354                                         <genre authority="marcgt">atlas</genre>
4355                                 </xsl:when>
4356                         </xsl:choose>
4357                 </xsl:if>
4358                 <xsl:if test="$typeOf008='SE'">
4359                         <xsl:variable name="controlField008-21" select="substring($controlField008,22,1)"/>
4360                         <xsl:choose>
4361                                 <xsl:when test="$controlField008-21='d'">
4362                                         <genre authority="marcgt">database</genre>
4363                                 </xsl:when>
4364                                 <xsl:when test="$controlField008-21='l'">
4365                                         <genre authority="marcgt">loose-leaf</genre>
4366                                 </xsl:when>
4367                                 <xsl:when test="$controlField008-21='m'">
4368                                         <genre authority="marcgt">series</genre>
4369                                 </xsl:when>
4370                                 <xsl:when test="$controlField008-21='n'">
4371                                         <genre authority="marcgt">newspaper</genre>
4372                                 </xsl:when>
4373                                 <xsl:when test="$controlField008-21='p'">
4374                                         <genre authority="marcgt">periodical</genre>
4375                                 </xsl:when>
4376                                 <xsl:when test="$controlField008-21='w'">
4377                                         <genre authority="marcgt">web site</genre>
4378                                 </xsl:when>
4379                         </xsl:choose>
4380                 </xsl:if>
4381                 <xsl:if test="$typeOf008='BK' or $typeOf008='SE'">
4382                         <xsl:variable name="controlField008-24" select="substring($controlField008,25,4)"/>
4383                         <xsl:choose>
4384                                 <xsl:when test="contains($controlField008-24,'a')">
4385                                         <genre authority="marcgt">abstract or summary</genre>
4386                                 </xsl:when>
4387                                 <xsl:when test="contains($controlField008-24,'b')">
4388                                         <genre authority="marcgt">bibliography</genre>
4389                                 </xsl:when>
4390                                 <xsl:when test="contains($controlField008-24,'c')">
4391                                         <genre authority="marcgt">catalog</genre>
4392                                 </xsl:when>
4393                                 <xsl:when test="contains($controlField008-24,'d')">
4394                                         <genre authority="marcgt">dictionary</genre>
4395                                 </xsl:when>
4396                                 <xsl:when test="contains($controlField008-24,'e')">
4397                                         <genre authority="marcgt">encyclopedia</genre>
4398                                 </xsl:when>
4399                                 <xsl:when test="contains($controlField008-24,'f')">
4400                                         <genre authority="marcgt">handbook</genre>
4401                                 </xsl:when>
4402                                 <xsl:when test="contains($controlField008-24,'g')">
4403                                         <genre authority="marcgt">legal article</genre>
4404                                 </xsl:when>
4405                                 <xsl:when test="contains($controlField008-24,'i')">
4406                                         <genre authority="marcgt">index</genre>
4407                                 </xsl:when>
4408                                 <xsl:when test="contains($controlField008-24,'k')">
4409                                         <genre authority="marcgt">discography</genre>
4410                                 </xsl:when>
4411                                 <xsl:when test="contains($controlField008-24,'l')">
4412                                         <genre authority="marcgt">legislation</genre>
4413                                 </xsl:when>
4414                                 <xsl:when test="contains($controlField008-24,'m')">
4415                                         <genre authority="marcgt">theses</genre>
4416                                 </xsl:when>
4417                                 <xsl:when test="contains($controlField008-24,'n')">
4418                                         <genre authority="marcgt">survey of literature</genre>
4419                                 </xsl:when>
4420                                 <xsl:when test="contains($controlField008-24,'o')">
4421                                         <genre authority="marcgt">review</genre>
4422                                 </xsl:when>
4423                                 <xsl:when test="contains($controlField008-24,'p')">
4424                                         <genre authority="marcgt">programmed text</genre>
4425                                 </xsl:when>
4426                                 <xsl:when test="contains($controlField008-24,'q')">
4427                                         <genre authority="marcgt">filmography</genre>
4428                                 </xsl:when>
4429                                 <xsl:when test="contains($controlField008-24,'r')">
4430                                         <genre authority="marcgt">directory</genre>
4431                                 </xsl:when>
4432                                 <xsl:when test="contains($controlField008-24,'s')">
4433                                         <genre authority="marcgt">statistics</genre>
4434                                 </xsl:when>
4435                                 <xsl:when test="contains($controlField008-24,'t')">
4436                                         <genre authority="marcgt">technical report</genre>
4437                                 </xsl:when>
4438                                 <xsl:when test="contains($controlField008-24,'v')">
4439                                         <genre authority="marcgt">legal case and case notes</genre>
4440                                 </xsl:when>
4441                                 <xsl:when test="contains($controlField008-24,'w')">
4442                                         <genre authority="marcgt">law report or digest</genre>
4443                                 </xsl:when>
4444                                 <xsl:when test="contains($controlField008-24,'z')">
4445                                         <genre authority="marcgt">treaty</genre>
4446                                 </xsl:when>
4447                         </xsl:choose>
4448                         <xsl:variable name="controlField008-29" select="substring($controlField008,30,1)"/>
4449                         <xsl:choose>
4450                                 <xsl:when test="$controlField008-29='1'">
4451                                         <genre authority="marcgt">conference publication</genre>
4452                                 </xsl:when>
4453                         </xsl:choose>
4454                 </xsl:if>
4455                 <xsl:if test="$typeOf008='CF'">
4456                         <xsl:variable name="controlField008-26" select="substring($controlField008,27,1)"/>
4457                         <xsl:choose>
4458                                 <xsl:when test="$controlField008-26='a'">
4459                                         <genre authority="marcgt">numeric data</genre>
4460                                 </xsl:when>
4461                                 <xsl:when test="$controlField008-26='e'">
4462                                         <genre authority="marcgt">database</genre>
4463                                 </xsl:when>
4464                                 <xsl:when test="$controlField008-26='f'">
4465                                         <genre authority="marcgt">font</genre>
4466                                 </xsl:when>
4467                                 <xsl:when test="$controlField008-26='g'">
4468                                         <genre authority="marcgt">game</genre>
4469                                 </xsl:when>
4470                         </xsl:choose>
4471                 </xsl:if>
4472                 <xsl:if test="$typeOf008='BK'">
4473                         <xsl:if test="substring($controlField008,25,1)='j'">
4474                                 <genre authority="marcgt">patent</genre>
4475                         </xsl:if>
4476                         <xsl:if test="substring($controlField008,25,1)='2'">
4477                                 <genre authority="marcgt">offprint</genre>
4478                         </xsl:if>
4479                         <xsl:if test="substring($controlField008,31,1)='1'">
4480                                 <genre authority="marcgt">festschrift</genre>
4481                         </xsl:if>
4482                         <xsl:variable name="controlField008-34" select="substring($controlField008,35,1)"/>
4483                         <xsl:if
4484                                 test="$controlField008-34='a' or $controlField008-34='b' or $controlField008-34='c' or $controlField008-34='d'">
4485                                 <genre authority="marcgt">biography</genre>
4486                         </xsl:if>
4487                         <xsl:variable name="controlField008-33" select="substring($controlField008,34,1)"/>
4488                         <xsl:choose>
4489                                 <xsl:when test="$controlField008-33='e'">
4490                                         <genre authority="marcgt">essay</genre>
4491                                 </xsl:when>
4492                                 <xsl:when test="$controlField008-33='d'">
4493                                         <genre authority="marcgt">drama</genre>
4494                                 </xsl:when>
4495                                 <xsl:when test="$controlField008-33='c'">
4496                                         <genre authority="marcgt">comic strip</genre>
4497                                 </xsl:when>
4498                                 <xsl:when test="$controlField008-33='l'">
4499                                         <genre authority="marcgt">fiction</genre>
4500                                 </xsl:when>
4501                                 <xsl:when test="$controlField008-33='h'">
4502                                         <genre authority="marcgt">humor, satire</genre>
4503                                 </xsl:when>
4504                                 <xsl:when test="$controlField008-33='i'">
4505                                         <genre authority="marcgt">letter</genre>
4506                                 </xsl:when>
4507                                 <xsl:when test="$controlField008-33='f'">
4508                                         <genre authority="marcgt">novel</genre>
4509                                 </xsl:when>
4510                                 <xsl:when test="$controlField008-33='j'">
4511                                         <genre authority="marcgt">short story</genre>
4512                                 </xsl:when>
4513                                 <xsl:when test="$controlField008-33='s'">
4514                                         <genre authority="marcgt">speech</genre>
4515                                 </xsl:when>
4516                         </xsl:choose>
4517                 </xsl:if>
4518                 <xsl:if test="$typeOf008='MU'">
4519                         <xsl:variable name="controlField008-30-31" select="substring($controlField008,31,2)"/>
4520                         <xsl:if test="contains($controlField008-30-31,'b')">
4521                                 <genre authority="marcgt">biography</genre>
4522                         </xsl:if>
4523                         <xsl:if test="contains($controlField008-30-31,'c')">
4524                                 <genre authority="marcgt">conference publication</genre>
4525                         </xsl:if>
4526                         <xsl:if test="contains($controlField008-30-31,'d')">
4527                                 <genre authority="marcgt">drama</genre>
4528                         </xsl:if>
4529                         <xsl:if test="contains($controlField008-30-31,'e')">
4530                                 <genre authority="marcgt">essay</genre>
4531                         </xsl:if>
4532                         <xsl:if test="contains($controlField008-30-31,'f')">
4533                                 <genre authority="marcgt">fiction</genre>
4534                         </xsl:if>
4535                         <xsl:if test="contains($controlField008-30-31,'o')">
4536                                 <genre authority="marcgt">folktale</genre>
4537                         </xsl:if>
4538                         <xsl:if test="contains($controlField008-30-31,'h')">
4539                                 <genre authority="marcgt">history</genre>
4540                         </xsl:if>
4541                         <xsl:if test="contains($controlField008-30-31,'k')">
4542                                 <genre authority="marcgt">humor, satire</genre>
4543                         </xsl:if>
4544                         <xsl:if test="contains($controlField008-30-31,'m')">
4545                                 <genre authority="marcgt">memoir</genre>
4546                         </xsl:if>
4547                         <xsl:if test="contains($controlField008-30-31,'p')">
4548                                 <genre authority="marcgt">poetry</genre>
4549                         </xsl:if>
4550                         <xsl:if test="contains($controlField008-30-31,'r')">
4551                                 <genre authority="marcgt">rehearsal</genre>
4552                         </xsl:if>
4553                         <xsl:if test="contains($controlField008-30-31,'g')">
4554                                 <genre authority="marcgt">reporting</genre>
4555                         </xsl:if>
4556                         <xsl:if test="contains($controlField008-30-31,'s')">
4557                                 <genre authority="marcgt">sound</genre>
4558                         </xsl:if>
4559                         <xsl:if test="contains($controlField008-30-31,'l')">
4560                                 <genre authority="marcgt">speech</genre>
4561                         </xsl:if>
4562                 </xsl:if>
4563                 <xsl:if test="$typeOf008='VM'">
4564                         <xsl:variable name="controlField008-33" select="substring($controlField008,34,1)"/>
4565                         <xsl:choose>
4566                                 <xsl:when test="$controlField008-33='a'">
4567                                         <genre authority="marcgt">art original</genre>
4568                                 </xsl:when>
4569                                 <xsl:when test="$controlField008-33='b'">
4570                                         <genre authority="marcgt">kit</genre>
4571                                 </xsl:when>
4572                                 <xsl:when test="$controlField008-33='c'">
4573                                         <genre authority="marcgt">art reproduction</genre>
4574                                 </xsl:when>
4575                                 <xsl:when test="$controlField008-33='d'">
4576                                         <genre authority="marcgt">diorama</genre>
4577                                 </xsl:when>
4578                                 <xsl:when test="$controlField008-33='f'">
4579                                         <genre authority="marcgt">filmstrip</genre>
4580                                 </xsl:when>
4581                                 <xsl:when test="$controlField008-33='g'">
4582                                         <genre authority="marcgt">legal article</genre>
4583                                 </xsl:when>
4584                                 <xsl:when test="$controlField008-33='i'">
4585                                         <genre authority="marcgt">picture</genre>
4586                                 </xsl:when>
4587                                 <xsl:when test="$controlField008-33='k'">
4588                                         <genre authority="marcgt">graphic</genre>
4589                                 </xsl:when>
4590                                 <xsl:when test="$controlField008-33='l'">
4591                                         <genre authority="marcgt">technical drawing</genre>
4592                                 </xsl:when>
4593                                 <xsl:when test="$controlField008-33='m'">
4594                                         <genre authority="marcgt">motion picture</genre>
4595                                 </xsl:when>
4596                                 <xsl:when test="$controlField008-33='n'">
4597                                         <genre authority="marcgt">chart</genre>
4598                                 </xsl:when>
4599                                 <xsl:when test="$controlField008-33='o'">
4600                                         <genre authority="marcgt">flash card</genre>
4601                                 </xsl:when>
4602                                 <xsl:when test="$controlField008-33='p'">
4603                                         <genre authority="marcgt">microscope slide</genre>
4604                                 </xsl:when>
4605                                 <xsl:when
4606                                         test="$controlField008-33='q' or marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='q']">
4607                                         <genre authority="marcgt">model</genre>
4608                                 </xsl:when>
4609                                 <xsl:when test="$controlField008-33='r'">
4610                                         <genre authority="marcgt">realia</genre>
4611                                 </xsl:when>
4612                                 <xsl:when test="$controlField008-33='s'">
4613                                         <genre authority="marcgt">slide</genre>
4614                                 </xsl:when>
4615                                 <xsl:when test="$controlField008-33='t'">
4616                                         <genre authority="marcgt">transparency</genre>
4617                                 </xsl:when>
4618                                 <xsl:when test="$controlField008-33='v'">
4619                                         <genre authority="marcgt">videorecording</genre>
4620                                 </xsl:when>
4621                                 <xsl:when test="$controlField008-33='w'">
4622                                         <genre authority="marcgt">toy</genre>
4623                                 </xsl:when>
4624                         </xsl:choose>
4625                 </xsl:if>
4626
4627                 <!-- 1.20 047 genre tmee-->
4628
4629                 <xsl:for-each select="marc:datafield[@tag=047]">
4630                         <genre authority="marcgt">
4631                                 <xsl:attribute name="authority">
4632                                         <xsl:value-of select="marc:subfield[@code='2']"/>
4633                                 </xsl:attribute>
4634                                 <xsl:call-template name="subfieldSelect">
4635                                         <xsl:with-param name="codes">abcdef</xsl:with-param>
4636                                         <xsl:with-param name="delimeter">-</xsl:with-param>
4637                                 </xsl:call-template>
4638                         </genre>
4639                 </xsl:for-each>
4640                 <xsl:for-each select="marc:datafield[@tag=655]">
4641                         <genre authority="marcgt">
4642                                 <xsl:attribute name="authority">
4643                                         <xsl:value-of select="marc:subfield[@code='2']"/>
4644                                 </xsl:attribute>
4645                                 <xsl:call-template name="subfieldSelect">
4646                                         <xsl:with-param name="codes">abvxyz</xsl:with-param>
4647                                         <xsl:with-param name="delimeter">-</xsl:with-param>
4648                                 </xsl:call-template>
4649                         </genre>
4650                 </xsl:for-each>
4651                 <originInfo>
4652                         <xsl:variable name="MARCpublicationCode"
4653                                 select="normalize-space(substring($controlField008,16,3))"/>
4654                         <xsl:if test="translate($MARCpublicationCode,'|','')">
4655                                 <place>
4656                                         <placeTerm>
4657                                                 <xsl:attribute name="type">code</xsl:attribute>
4658                                                 <xsl:attribute name="authority">marccountry</xsl:attribute>
4659                                                 <xsl:value-of select="$MARCpublicationCode"/>
4660                                         </placeTerm>
4661                                 </place>
4662                         </xsl:if>
4663                         <xsl:for-each select="marc:datafield[@tag=044]/marc:subfield[@code='c']">
4664                                 <place>
4665                                         <placeTerm>
4666                                                 <xsl:attribute name="type">code</xsl:attribute>
4667                                                 <xsl:attribute name="authority">iso3166</xsl:attribute>
4668                                                 <xsl:value-of select="."/>
4669                                         </placeTerm>
4670                                 </place>
4671                         </xsl:for-each>
4672                         <xsl:for-each select="marc:datafield[@tag=260]/marc:subfield[@code='a']">
4673                                 <place>
4674                                         <placeTerm>
4675                                                 <xsl:attribute name="type">text</xsl:attribute>
4676                                                 <xsl:call-template name="chopPunctuationFront">
4677                                                         <xsl:with-param name="chopString">
4678                                                                 <xsl:call-template name="chopPunctuation">
4679                                                                         <xsl:with-param name="chopString" select="."/>
4680                                                                 </xsl:call-template>
4681                                                         </xsl:with-param>
4682                                                 </xsl:call-template>
4683                                         </placeTerm>
4684                                 </place>
4685                         </xsl:for-each>
4686                         <xsl:for-each select="marc:datafield[@tag=046]/marc:subfield[@code='m']">
4687                                 <dateValid point="start">
4688                                         <xsl:value-of select="."/>
4689                                 </dateValid>
4690                         </xsl:for-each>
4691                         <xsl:for-each select="marc:datafield[@tag=046]/marc:subfield[@code='n']">
4692                                 <dateValid point="end">
4693                                         <xsl:value-of select="."/>
4694                                 </dateValid>
4695                         </xsl:for-each>
4696                         <xsl:for-each select="marc:datafield[@tag=046]/marc:subfield[@code='j']">
4697                                 <dateModified>
4698                                         <xsl:value-of select="."/>
4699                                 </dateModified>
4700                         </xsl:for-each>
4701                         <xsl:for-each
4702                                 select="marc:datafield[@tag=260]/marc:subfield[@code='b' or @code='c' or @code='g']">
4703                                 <xsl:choose>
4704                                         <xsl:when test="@code='b'">
4705                                                 <publisher>
4706                                                         <xsl:call-template name="chopPunctuation">
4707                                                                 <xsl:with-param name="chopString" select="."/>
4708                                                                 <xsl:with-param name="punctuation">
4709                                                                         <xsl:text>:,;/ </xsl:text>
4710                                                                 </xsl:with-param>
4711                                                         </xsl:call-template>
4712                                                 </publisher>
4713                                         </xsl:when>
4714                                         <xsl:when test="@code='c'">
4715                                                 <dateIssued>
4716                                                         <xsl:call-template name="chopPunctuation">
4717                                                                 <xsl:with-param name="chopString" select="."/>
4718                                                         </xsl:call-template>
4719                                                 </dateIssued>
4720                                         </xsl:when>
4721                                         <xsl:when test="@code='g'">
4722                                                 <dateCreated>
4723                                                         <xsl:value-of select="."/>
4724                                                 </dateCreated>
4725                                         </xsl:when>
4726                                 </xsl:choose>
4727                         </xsl:for-each>
4728                         <xsl:variable name="dataField260c">
4729                                 <xsl:call-template name="chopPunctuation">
4730                                         <xsl:with-param name="chopString"
4731                                                 select="marc:datafield[@tag=260]/marc:subfield[@code='c']"/>
4732                                 </xsl:call-template>
4733                         </xsl:variable>
4734                         <xsl:variable name="controlField008-7-10"
4735                                 select="normalize-space(substring($controlField008, 8, 4))"/>
4736                         <xsl:variable name="controlField008-11-14"
4737                                 select="normalize-space(substring($controlField008, 12, 4))"/>
4738                         <xsl:variable name="controlField008-6"
4739                                 select="normalize-space(substring($controlField008, 7, 1))"/>
4740                         <xsl:if
4741                                 test="$controlField008-6='e' or $controlField008-6='p' or $controlField008-6='r' or $controlField008-6='t' or $controlField008-6='s'">
4742                                 <xsl:if test="$controlField008-7-10 and ($controlField008-7-10 != $dataField260c)">
4743                                         <dateIssued encoding="marc">
4744                                                 <xsl:value-of select="$controlField008-7-10"/>
4745                                         </dateIssued>
4746                                 </xsl:if>
4747                         </xsl:if>
4748                         <xsl:if
4749                                 test="$controlField008-6='c' or $controlField008-6='d' or $controlField008-6='i' or $controlField008-6='k' or $controlField008-6='m' or $controlField008-6='q' or $controlField008-6='u'">
4750                                 <xsl:if test="$controlField008-7-10">
4751                                         <dateIssued encoding="marc" point="start">
4752                                                 <xsl:value-of select="$controlField008-7-10"/>
4753                                         </dateIssued>
4754                                 </xsl:if>
4755                         </xsl:if>
4756                         <xsl:if
4757                                 test="$controlField008-6='c' or $controlField008-6='d' or $controlField008-6='i' or $controlField008-6='k' or $controlField008-6='m' or $controlField008-6='q' or $controlField008-6='u'">
4758                                 <xsl:if test="$controlField008-11-14">
4759                                         <dateIssued encoding="marc" point="end">
4760                                                 <xsl:value-of select="$controlField008-11-14"/>
4761                                         </dateIssued>
4762                                 </xsl:if>
4763                         </xsl:if>
4764                         <xsl:if test="$controlField008-6='q'">
4765                                 <xsl:if test="$controlField008-7-10">
4766                                         <dateIssued encoding="marc" point="start" qualifier="questionable">
4767                                                 <xsl:value-of select="$controlField008-7-10"/>
4768                                         </dateIssued>
4769                                 </xsl:if>
4770                         </xsl:if>
4771                         <xsl:if test="$controlField008-6='q'">
4772                                 <xsl:if test="$controlField008-11-14">
4773                                         <dateIssued encoding="marc" point="end" qualifier="questionable">
4774                                                 <xsl:value-of select="$controlField008-11-14"/>
4775                                         </dateIssued>
4776                                 </xsl:if>
4777                         </xsl:if>
4778                         <xsl:if test="$controlField008-6='t'">
4779                                 <xsl:if test="$controlField008-11-14">
4780                                         <copyrightDate encoding="marc">
4781                                                 <xsl:value-of select="$controlField008-11-14"/>
4782                                         </copyrightDate>
4783                                 </xsl:if>
4784                         </xsl:if>
4785                         <xsl:for-each
4786                                 select="marc:datafield[@tag=033][@ind1=0 or @ind1=1]/marc:subfield[@code='a']">
4787                                 <dateCaptured encoding="iso8601">
4788                                         <xsl:value-of select="."/>
4789                                 </dateCaptured>
4790                         </xsl:for-each>
4791                         <xsl:for-each select="marc:datafield[@tag=033][@ind1=2]/marc:subfield[@code='a'][1]">
4792                                 <dateCaptured encoding="iso8601" point="start">
4793                                         <xsl:value-of select="."/>
4794                                 </dateCaptured>
4795                         </xsl:for-each>
4796                         <xsl:for-each select="marc:datafield[@tag=033][@ind1=2]/marc:subfield[@code='a'][2]">
4797                                 <dateCaptured encoding="iso8601" point="end">
4798                                         <xsl:value-of select="."/>
4799                                 </dateCaptured>
4800                         </xsl:for-each>
4801                         <xsl:for-each select="marc:datafield[@tag=250]/marc:subfield[@code='a']">
4802                                 <edition>
4803                                         <xsl:value-of select="."/>
4804                                 </edition>
4805                         </xsl:for-each>
4806                         <xsl:for-each select="marc:leader">
4807                                 <issuance>
4808                                         <xsl:choose>
4809                                                 <xsl:when
4810                                                         test="$leader7='a' or $leader7='c' or $leader7='d' or $leader7='m'"
4811                                                         >monographic</xsl:when>
4812                                                 <xsl:when test="$leader7='b' or $leader7='i' or $leader7='s'"
4813                                                 >continuing</xsl:when>
4814                                         </xsl:choose>
4815                                 </issuance>
4816                         </xsl:for-each>
4817                         <xsl:for-each select="marc:datafield[@tag=310]|marc:datafield[@tag=321]">
4818                                 <frequency>
4819                                         <xsl:call-template name="subfieldSelect">
4820                                                 <xsl:with-param name="codes">ab</xsl:with-param>
4821                                         </xsl:call-template>
4822                                 </frequency>
4823                         </xsl:for-each>
4824                 </originInfo>
4825                 <xsl:variable name="controlField008-35-37"
4826                         select="normalize-space(translate(substring($controlField008,36,3),'|#',''))"/>
4827                 <xsl:if test="$controlField008-35-37">
4828                         <language>
4829                                 <languageTerm authority="iso639-2b" type="code">
4830                                         <xsl:value-of select="substring($controlField008,36,3)"/>
4831                                 </languageTerm>
4832                         </language>
4833                 </xsl:if>
4834                 <xsl:for-each select="marc:datafield[@tag=041]">
4835                         <xsl:for-each
4836                                 select="marc:subfield[@code='a' or @code='b' or @code='d' or @code='e' or @code='f' or @code='g' or @code='h']">
4837                                 <xsl:variable name="langCodes" select="."/>
4838                                 <xsl:choose>
4839                                         <xsl:when test="../marc:subfield[@code='2']='rfc3066'">
4840                                                 <!-- not stacked but could be repeated -->
4841                                                 <xsl:call-template name="rfcLanguages">
4842                                                         <xsl:with-param name="nodeNum">
4843                                                                 <xsl:value-of select="1"/>
4844                                                         </xsl:with-param>
4845                                                         <xsl:with-param name="usedLanguages">
4846                                                                 <xsl:text/>
4847                                                         </xsl:with-param>
4848                                                         <xsl:with-param name="controlField008-35-37">
4849                                                                 <xsl:value-of select="$controlField008-35-37"/>
4850                                                         </xsl:with-param>
4851                                                 </xsl:call-template>
4852                                         </xsl:when>
4853                                         <xsl:otherwise>
4854                                                 <!-- iso -->
4855                                                 <xsl:variable name="allLanguages">
4856                                                         <xsl:copy-of select="$langCodes"/>
4857                                                 </xsl:variable>
4858                                                 <xsl:variable name="currentLanguage">
4859                                                         <xsl:value-of select="substring($allLanguages,1,3)"/>
4860                                                 </xsl:variable>
4861                                                 <xsl:call-template name="isoLanguage">
4862                                                         <xsl:with-param name="currentLanguage">
4863                                                                 <xsl:value-of select="substring($allLanguages,1,3)"/>
4864                                                         </xsl:with-param>
4865                                                         <xsl:with-param name="remainingLanguages">
4866                                                                 <xsl:value-of
4867                                                                         select="substring($allLanguages,4,string-length($allLanguages)-3)"
4868                                                                 />
4869                                                         </xsl:with-param>
4870                                                         <xsl:with-param name="usedLanguages">
4871                                                                 <xsl:if test="$controlField008-35-37">
4872                                                                         <xsl:value-of select="$controlField008-35-37"/>
4873                                                                 </xsl:if>
4874                                                         </xsl:with-param>
4875                                                 </xsl:call-template>
4876                                         </xsl:otherwise>
4877                                 </xsl:choose>
4878                         </xsl:for-each>
4879                 </xsl:for-each>
4880                 <xsl:variable name="physicalDescription">
4881                         <!--3.2 change tmee 007/11 -->
4882                         <xsl:if test="$typeOf008='CF' and marc:controlfield[@tag=007][substring(.,12,1)='a']">
4883                                 <digitalOrigin>reformatted digital</digitalOrigin>
4884                         </xsl:if>
4885                         <xsl:if test="$typeOf008='CF' and marc:controlfield[@tag=007][substring(.,12,1)='b']">
4886                                 <digitalOrigin>digitized microfilm</digitalOrigin>
4887                         </xsl:if>
4888                         <xsl:if test="$typeOf008='CF' and marc:controlfield[@tag=007][substring(.,12,1)='d']">
4889                                 <digitalOrigin>digitized other analog</digitalOrigin>
4890                         </xsl:if>
4891                         <xsl:variable name="controlField008-23" select="substring($controlField008,24,1)"/>
4892                         <xsl:variable name="controlField008-29" select="substring($controlField008,30,1)"/>
4893                         <xsl:variable name="check008-23">
4894                                 <xsl:if
4895                                         test="$typeOf008='BK' or $typeOf008='MU' or $typeOf008='SE' or $typeOf008='MM'">
4896                                         <xsl:value-of select="true()"/>
4897                                 </xsl:if>
4898                         </xsl:variable>
4899                         <xsl:variable name="check008-29">
4900                                 <xsl:if test="$typeOf008='MP' or $typeOf008='VM'">
4901                                         <xsl:value-of select="true()"/>
4902                                 </xsl:if>
4903                         </xsl:variable>
4904                         <xsl:choose>
4905                                 <xsl:when
4906                                         test="($check008-23 and $controlField008-23='f') or ($check008-29 and $controlField008-29='f')">
4907                                         <form authority="marcform">braille</form>
4908                                 </xsl:when>
4909                                 <xsl:when
4910                                         test="($controlField008-23=' ' and ($leader6='c' or $leader6='d')) or (($typeOf008='BK' or $typeOf008='SE') and ($controlField008-23=' ' or $controlField008='r'))">
4911                                         <form authority="marcform">print</form>
4912                                 </xsl:when>
4913                                 <xsl:when
4914                                         test="$leader6 = 'm' or ($check008-23 and $controlField008-23='s') or ($check008-29 and $controlField008-29='s')">
4915                                         <form authority="marcform">electronic</form>
4916                                 </xsl:when>
4917                                 <xsl:when
4918                                         test="($check008-23 and $controlField008-23='b') or ($check008-29 and $controlField008-29='b')">
4919                                         <form authority="marcform">microfiche</form>
4920                                 </xsl:when>
4921                                 <xsl:when
4922                                         test="($check008-23 and $controlField008-23='a') or ($check008-29 and $controlField008-29='a')">
4923                                         <form authority="marcform">microfilm</form>
4924                                 </xsl:when>
4925                         </xsl:choose>
4926                         <!-- 1/04 fix -->
4927                         <xsl:if test="marc:datafield[@tag=130]/marc:subfield[@code='h']">
4928                                 <form authority="gmd">
4929                                         <xsl:call-template name="chopBrackets">
4930                                                 <xsl:with-param name="chopString">
4931                                                         <xsl:value-of select="marc:datafield[@tag=130]/marc:subfield[@code='h']"
4932                                                         />
4933                                                 </xsl:with-param>
4934                                         </xsl:call-template>
4935                                 </form>
4936                         </xsl:if>
4937                         <xsl:if test="marc:datafield[@tag=240]/marc:subfield[@code='h']">
4938                                 <form authority="gmd">
4939                                         <xsl:call-template name="chopBrackets">
4940                                                 <xsl:with-param name="chopString">
4941                                                         <xsl:value-of select="marc:datafield[@tag=240]/marc:subfield[@code='h']"
4942                                                         />
4943                                                 </xsl:with-param>
4944                                         </xsl:call-template>
4945                                 </form>
4946                         </xsl:if>
4947                         <xsl:if test="marc:datafield[@tag=242]/marc:subfield[@code='h']">
4948                                 <form authority="gmd">
4949                                         <xsl:call-template name="chopBrackets">
4950                                                 <xsl:with-param name="chopString">
4951                                                         <xsl:value-of select="marc:datafield[@tag=242]/marc:subfield[@code='h']"
4952                                                         />
4953                                                 </xsl:with-param>
4954                                         </xsl:call-template>
4955                                 </form>
4956                         </xsl:if>
4957                         <xsl:if test="marc:datafield[@tag=245]/marc:subfield[@code='h']">
4958                                 <form authority="gmd">
4959                                         <xsl:call-template name="chopBrackets">
4960                                                 <xsl:with-param name="chopString">
4961                                                         <xsl:value-of select="marc:datafield[@tag=245]/marc:subfield[@code='h']"
4962                                                         />
4963                                                 </xsl:with-param>
4964                                         </xsl:call-template>
4965                                 </form>
4966                         </xsl:if>
4967                         <xsl:if test="marc:datafield[@tag=246]/marc:subfield[@code='h']">
4968                                 <form authority="gmd">
4969                                         <xsl:call-template name="chopBrackets">
4970                                                 <xsl:with-param name="chopString">
4971                                                         <xsl:value-of select="marc:datafield[@tag=246]/marc:subfield[@code='h']"
4972                                                         />
4973                                                 </xsl:with-param>
4974                                         </xsl:call-template>
4975                                 </form>
4976                         </xsl:if>
4977                         <xsl:if test="marc:datafield[@tag=730]/marc:subfield[@code='h']">
4978                                 <form authority="gmd">
4979                                         <xsl:call-template name="chopBrackets">
4980                                                 <xsl:with-param name="chopString">
4981                                                         <xsl:value-of select="marc:datafield[@tag=730]/marc:subfield[@code='h']"
4982                                                         />
4983                                                 </xsl:with-param>
4984                                         </xsl:call-template>
4985                                 </form>
4986                         </xsl:if>
4987                         <xsl:for-each select="marc:datafield[@tag=256]/marc:subfield[@code='a']">
4988                                 <form>
4989                                         <xsl:value-of select="."/>
4990                                 </form>
4991                         </xsl:for-each>
4992                         <xsl:for-each select="marc:controlfield[@tag=007][substring(text(),1,1)='c']">
4993                                 <xsl:choose>
4994                                         <xsl:when test="substring(text(),14,1)='a'">
4995                                                 <reformattingQuality>access</reformattingQuality>
4996                                         </xsl:when>
4997                                         <xsl:when test="substring(text(),14,1)='p'">
4998                                                 <reformattingQuality>preservation</reformattingQuality>
4999                                         </xsl:when>
5000                                         <xsl:when test="substring(text(),14,1)='r'">
5001                                                 <reformattingQuality>replacement</reformattingQuality>
5002                                         </xsl:when>
5003                                 </xsl:choose>
5004                         </xsl:for-each>
5005                         <!--3.2 change tmee 007/01 -->
5006                         <xsl:if
5007                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='b']">
5008                                 <form authority="smd">chip cartridge</form>
5009                         </xsl:if>
5010                         <xsl:if
5011                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='c']">
5012                                 <form authority="smd">computer optical disc cartridge</form>
5013                         </xsl:if>
5014                         <xsl:if
5015                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='j']">
5016                                 <form authority="smd">magnetic disc</form>
5017                         </xsl:if>
5018                         <xsl:if
5019                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='m']">
5020                                 <form authority="smd">magneto-optical disc</form>
5021                         </xsl:if>
5022                         <xsl:if
5023                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='o']">
5024                                 <form authority="smd">optical disc</form>
5025                         </xsl:if>
5026                         <xsl:if
5027                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='r']">
5028                                 <form authority="smd">remote</form>
5029                         </xsl:if>
5030                         <xsl:if
5031                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='a']">
5032                                 <form authority="smd">tape cartridge</form>
5033                         </xsl:if>
5034                         <xsl:if
5035                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='f']">
5036                                 <form authority="smd">tape cassette</form>
5037                         </xsl:if>
5038                         <xsl:if
5039                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='h']">
5040                                 <form authority="smd">tape reel</form>
5041                         </xsl:if>
5042
5043                         <xsl:if
5044                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='d'][substring(text(),2,1)='a']">
5045                                 <form authority="smd">celestial globe</form>
5046                         </xsl:if>
5047                         <xsl:if
5048                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='d'][substring(text(),2,1)='e']">
5049                                 <form authority="smd">earth moon globe</form>
5050                         </xsl:if>
5051                         <xsl:if
5052                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='d'][substring(text(),2,1)='b']">
5053                                 <form authority="smd">planetary or lunar globe</form>
5054                         </xsl:if>
5055                         <xsl:if
5056                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='d'][substring(text(),2,1)='c']">
5057                                 <form authority="smd">terrestrial globe</form>
5058                         </xsl:if>
5059
5060                         <xsl:if
5061                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='o'][substring(text(),2,1)='o']">
5062                                 <form authority="smd">kit</form>
5063                         </xsl:if>
5064
5065                         <xsl:if
5066                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='d']">
5067                                 <form authority="smd">atlas</form>
5068                         </xsl:if>
5069                         <xsl:if
5070                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='g']">
5071                                 <form authority="smd">diagram</form>
5072                         </xsl:if>
5073                         <xsl:if
5074                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='j']">
5075                                 <form authority="smd">map</form>
5076                         </xsl:if>
5077                         <xsl:if
5078                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='q']">
5079                                 <form authority="smd">model</form>
5080                         </xsl:if>
5081                         <xsl:if
5082                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='k']">
5083                                 <form authority="smd">profile</form>
5084                         </xsl:if>
5085                         <xsl:if
5086                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='r']">
5087                                 <form authority="smd">remote-sensing image</form>
5088                         </xsl:if>
5089                         <xsl:if
5090                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='s']">
5091                                 <form authority="smd">section</form>
5092                         </xsl:if>
5093                         <xsl:if
5094                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='y']">
5095                                 <form authority="smd">view</form>
5096                         </xsl:if>
5097
5098                         <xsl:if
5099                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='a']">
5100                                 <form authority="smd">aperture card</form>
5101                         </xsl:if>
5102                         <xsl:if
5103                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='e']">
5104                                 <form authority="smd">microfiche</form>
5105                         </xsl:if>
5106                         <xsl:if
5107                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='f']">
5108                                 <form authority="smd">microfiche cassette</form>
5109                         </xsl:if>
5110                         <xsl:if
5111                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='b']">
5112                                 <form authority="smd">microfilm cartridge</form>
5113                         </xsl:if>
5114                         <xsl:if
5115                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='c']">
5116                                 <form authority="smd">microfilm cassette</form>
5117                         </xsl:if>
5118                         <xsl:if
5119                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='d']">
5120                                 <form authority="smd">microfilm reel</form>
5121                         </xsl:if>
5122                         <xsl:if
5123                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='g']">
5124                                 <form authority="smd">microopaque</form>
5125                         </xsl:if>
5126
5127                         <xsl:if
5128                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='m'][substring(text(),2,1)='c']">
5129                                 <form authority="smd">film cartridge</form>
5130                         </xsl:if>
5131                         <xsl:if
5132                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='m'][substring(text(),2,1)='f']">
5133                                 <form authority="smd">film cassette</form>
5134                         </xsl:if>
5135                         <xsl:if
5136                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='m'][substring(text(),2,1)='r']">
5137                                 <form authority="smd">film reel</form>
5138                         </xsl:if>
5139
5140                         <xsl:if
5141                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='n']">
5142                                 <form authority="smd">chart</form>
5143                         </xsl:if>
5144                         <xsl:if
5145                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='c']">
5146                                 <form authority="smd">collage</form>
5147                         </xsl:if>
5148                         <xsl:if
5149                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='d']">
5150                                 <form authority="smd">drawing</form>
5151                         </xsl:if>
5152                         <xsl:if
5153                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='o']">
5154                                 <form authority="smd">flash card</form>
5155                         </xsl:if>
5156                         <xsl:if
5157                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='e']">
5158                                 <form authority="smd">painting</form>
5159                         </xsl:if>
5160                         <xsl:if
5161                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='f']">
5162                                 <form authority="smd">photomechanical print</form>
5163                         </xsl:if>
5164                         <xsl:if
5165                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='g']">
5166                                 <form authority="smd">photonegative</form>
5167                         </xsl:if>
5168                         <xsl:if
5169                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='h']">
5170                                 <form authority="smd">photoprint</form>
5171                         </xsl:if>
5172                         <xsl:if
5173                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='i']">
5174                                 <form authority="smd">picture</form>
5175                         </xsl:if>
5176                         <xsl:if
5177                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='j']">
5178                                 <form authority="smd">print</form>
5179                         </xsl:if>
5180                         <xsl:if
5181                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='l']">
5182                                 <form authority="smd">technical drawing</form>
5183                         </xsl:if>
5184
5185                         <xsl:if
5186                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='q'][substring(text(),2,1)='q']">
5187                                 <form authority="smd">notated music</form>
5188                         </xsl:if>
5189
5190                         <xsl:if
5191                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='d']">
5192                                 <form authority="smd">filmslip</form>
5193                         </xsl:if>
5194                         <xsl:if
5195                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='c']">
5196                                 <form authority="smd">filmstrip cartridge</form>
5197                         </xsl:if>
5198                         <xsl:if
5199                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='o']">
5200                                 <form authority="smd">filmstrip roll</form>
5201                         </xsl:if>
5202                         <xsl:if
5203                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='f']">
5204                                 <form authority="smd">other filmstrip type</form>
5205                         </xsl:if>
5206                         <xsl:if
5207                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='s']">
5208                                 <form authority="smd">slide</form>
5209                         </xsl:if>
5210                         <xsl:if
5211                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='t']">
5212                                 <form authority="smd">transparency</form>
5213                         </xsl:if>
5214                         <xsl:if
5215                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='r'][substring(text(),2,1)='r']">
5216                                 <form authority="smd">remote-sensing image</form>
5217                         </xsl:if>
5218                         <xsl:if
5219                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='e']">
5220                                 <form authority="smd">cylinder</form>
5221                         </xsl:if>
5222                         <xsl:if
5223                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='q']">
5224                                 <form authority="smd">roll</form>
5225                         </xsl:if>
5226                         <xsl:if
5227                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='g']">
5228                                 <form authority="smd">sound cartridge</form>
5229                         </xsl:if>
5230                         <xsl:if
5231                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='s']">
5232                                 <form authority="smd">sound cassette</form>
5233                         </xsl:if>
5234                         <xsl:if
5235                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='d']">
5236                                 <form authority="smd">sound disc</form>
5237                         </xsl:if>
5238                         <xsl:if
5239                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='t']">
5240                                 <form authority="smd">sound-tape reel</form>
5241                         </xsl:if>
5242                         <xsl:if
5243                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='i']">
5244                                 <form authority="smd">sound-track film</form>
5245                         </xsl:if>
5246                         <xsl:if
5247                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='w']">
5248                                 <form authority="smd">wire recording</form>
5249                         </xsl:if>
5250
5251                         <xsl:if
5252                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='c']">
5253                                 <form authority="smd">braille</form>
5254                         </xsl:if>
5255                         <xsl:if
5256                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='b']">
5257                                 <form authority="smd">combination</form>
5258                         </xsl:if>
5259                         <xsl:if
5260                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='a']">
5261                                 <form authority="smd">moon</form>
5262                         </xsl:if>
5263                         <xsl:if
5264                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='d']">
5265                                 <form authority="smd">tactile, with no writing system</form>
5266                         </xsl:if>
5267
5268                         <xsl:if
5269                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='t'][substring(text(),2,1)='c']">
5270                                 <form authority="smd">braille</form>
5271                         </xsl:if>
5272                         <xsl:if
5273                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='t'][substring(text(),2,1)='b']">
5274                                 <form authority="smd">large print</form>
5275                         </xsl:if>
5276                         <xsl:if
5277                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='t'][substring(text(),2,1)='a']">
5278                                 <form authority="smd">regular print</form>
5279                         </xsl:if>
5280                         <xsl:if
5281                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='t'][substring(text(),2,1)='d']">
5282                                 <form authority="smd">text in looseleaf binder</form>
5283                         </xsl:if>
5284
5285                         <xsl:if
5286                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='c']">
5287                                 <form authority="smd">videocartridge</form>
5288                         </xsl:if>
5289                         <xsl:if
5290                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='f']">
5291                                 <form authority="smd">videocassette</form>
5292                         </xsl:if>
5293                         <xsl:if
5294                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='d']">
5295                                 <form authority="smd">videodisc</form>
5296                         </xsl:if>
5297                         <xsl:if
5298                                 test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='r']">
5299                                 <form authority="smd">videoreel</form>
5300                         </xsl:if>
5301
5302                         <xsl:for-each
5303                                 select="marc:datafield[@tag=856]/marc:subfield[@code='q'][string-length(.)&gt;1]">
5304                                 <internetMediaType>
5305                                         <xsl:value-of select="."/>
5306                                 </internetMediaType>
5307                         </xsl:for-each>
5308                         <xsl:for-each select="marc:datafield[@tag=300]">
5309                                 <extent>
5310                                         <xsl:call-template name="subfieldSelect">
5311                                                 <xsl:with-param name="codes">abce</xsl:with-param>
5312                                         </xsl:call-template>
5313                                 </extent>
5314                         </xsl:for-each>
5315                 </xsl:variable>
5316                 <xsl:if test="string-length(normalize-space($physicalDescription))">
5317                         <physicalDescription>
5318                                 <xsl:copy-of select="$physicalDescription"/>
5319                         </physicalDescription>
5320                 </xsl:if>
5321                 <xsl:for-each select="marc:datafield[@tag=520]">
5322                         <abstract>
5323                                 <xsl:call-template name="uri"/>
5324                                 <xsl:call-template name="subfieldSelect">
5325                                         <xsl:with-param name="codes">ab</xsl:with-param>
5326                                 </xsl:call-template>
5327                         </abstract>
5328                 </xsl:for-each>
5329                 <xsl:for-each select="marc:datafield[@tag=505]">
5330                         <tableOfContents>
5331                                 <xsl:call-template name="uri"/>
5332                                 <xsl:call-template name="subfieldSelect">
5333                                         <xsl:with-param name="codes">agrt</xsl:with-param>
5334                                 </xsl:call-template>
5335                         </tableOfContents>
5336                 </xsl:for-each>
5337                 <xsl:for-each select="marc:datafield[@tag=521]">
5338                         <targetAudience>
5339                                 <xsl:call-template name="subfieldSelect">
5340                                         <xsl:with-param name="codes">ab</xsl:with-param>
5341                                 </xsl:call-template>
5342                         </targetAudience>
5343                 </xsl:for-each>
5344                 <xsl:if test="$typeOf008='BK' or $typeOf008='CF' or $typeOf008='MU' or $typeOf008='VM'">
5345                         <xsl:variable name="controlField008-22" select="substring($controlField008,23,1)"/>
5346                         <xsl:choose>
5347                                 <!-- 01/04 fix -->
5348                                 <xsl:when test="$controlField008-22='d'">
5349                                         <targetAudience authority="marctarget">adolescent</targetAudience>
5350                                 </xsl:when>
5351                                 <xsl:when test="$controlField008-22='e'">
5352                                         <targetAudience authority="marctarget">adult</targetAudience>
5353                                 </xsl:when>
5354                                 <xsl:when test="$controlField008-22='g'">
5355                                         <targetAudience authority="marctarget">general</targetAudience>
5356                                 </xsl:when>
5357                                 <xsl:when
5358                                         test="$controlField008-22='b' or $controlField008-22='c' or $controlField008-22='j'">
5359                                         <targetAudience authority="marctarget">juvenile</targetAudience>
5360                                 </xsl:when>
5361                                 <xsl:when test="$controlField008-22='a'">
5362                                         <targetAudience authority="marctarget">preschool</targetAudience>
5363                                 </xsl:when>
5364                                 <xsl:when test="$controlField008-22='f'">
5365                                         <targetAudience authority="marctarget">specialized</targetAudience>
5366                                 </xsl:when>
5367                         </xsl:choose>
5368                 </xsl:if>
5369                 <xsl:for-each select="marc:datafield[@tag=245]/marc:subfield[@code='c']">
5370                         <note type="statement of responsibility">
5371                                 <xsl:value-of select="."/>
5372                         </note>
5373                 </xsl:for-each>
5374                 <xsl:for-each select="marc:datafield[@tag=500]">
5375                         <note>
5376                                 <xsl:value-of select="marc:subfield[@code='a']"/>
5377                                 <xsl:call-template name="uri"/>
5378                         </note>
5379                 </xsl:for-each>
5380
5381                 <!--3.2 change tmee additional note fields-->
5382
5383                 <xsl:for-each select="marc:datafield[@tag=506]">
5384                         <note type="restrictions">
5385                                 <xsl:call-template name="uri"/>
5386                                 <xsl:variable name="str">
5387                                         <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
5388                                                 <xsl:value-of select="."/>
5389                                                 <xsl:text> </xsl:text>
5390                                         </xsl:for-each>
5391                                 </xsl:variable>
5392                                 <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
5393                         </note>
5394                 </xsl:for-each>
5395
5396                 <xsl:for-each select="marc:datafield[@tag=510]">
5397                         <note type="citation/reference">
5398                                 <xsl:call-template name="uri"/>
5399                                 <xsl:variable name="str">
5400                                         <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
5401                                                 <xsl:value-of select="."/>
5402                                                 <xsl:text> </xsl:text>
5403                                         </xsl:for-each>
5404                                 </xsl:variable>
5405                                 <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
5406                         </note>
5407                 </xsl:for-each>
5408
5409
5410                 <xsl:for-each select="marc:datafield[@tag=511]">
5411                         <note type="performers">
5412                                 <xsl:call-template name="uri"/>
5413                                 <xsl:value-of select="marc:subfield[@code='a']"/>
5414                         </note>
5415                 </xsl:for-each>
5416                 <xsl:for-each select="marc:datafield[@tag=518]">
5417                         <note type="venue">
5418                                 <xsl:call-template name="uri"/>
5419                                 <xsl:value-of select="marc:subfield[@code='a']"/>
5420                         </note>
5421                 </xsl:for-each>
5422
5423                 <xsl:for-each select="marc:datafield[@tag=530]">
5424                         <note type="additional physical form">
5425                                 <xsl:call-template name="uri"/>
5426                                 <xsl:variable name="str">
5427                                         <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
5428                                                 <xsl:value-of select="."/>
5429                                                 <xsl:text> </xsl:text>
5430                                         </xsl:for-each>
5431                                 </xsl:variable>
5432                                 <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
5433                         </note>
5434                 </xsl:for-each>
5435
5436                 <xsl:for-each select="marc:datafield[@tag=533]">
5437                         <note type="reproduction">
5438                                 <xsl:call-template name="uri"/>
5439                                 <xsl:variable name="str">
5440                                         <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
5441                                                 <xsl:value-of select="."/>
5442                                                 <xsl:text> </xsl:text>
5443                                         </xsl:for-each>
5444                                 </xsl:variable>
5445                                 <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
5446                         </note>
5447                 </xsl:for-each>
5448
5449                 <xsl:for-each select="marc:datafield[@tag=534]">
5450                         <note type="original version">
5451                                 <xsl:call-template name="uri"/>
5452                                 <xsl:variable name="str">
5453                                         <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
5454                                                 <xsl:value-of select="."/>
5455                                                 <xsl:text> </xsl:text>
5456                                         </xsl:for-each>
5457                                 </xsl:variable>
5458                                 <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
5459                         </note>
5460                 </xsl:for-each>
5461
5462                 <xsl:for-each select="marc:datafield[@tag=538]">
5463                         <note type="system details">
5464                                 <xsl:call-template name="uri"/>
5465                                 <xsl:variable name="str">
5466                                         <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
5467                                                 <xsl:value-of select="."/>
5468                                                 <xsl:text> </xsl:text>
5469                                         </xsl:for-each>
5470                                 </xsl:variable>
5471                                 <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
5472                         </note>
5473                 </xsl:for-each>
5474
5475                 <xsl:for-each select="marc:datafield[@tag=583]">
5476                         <note type="action">
5477                                 <xsl:call-template name="uri"/>
5478                                 <xsl:variable name="str">
5479                                         <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
5480                                                 <xsl:value-of select="."/>
5481                                                 <xsl:text> </xsl:text>
5482                                         </xsl:for-each>
5483                                 </xsl:variable>
5484                                 <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
5485                         </note>
5486                 </xsl:for-each>
5487
5488                 <xsl:for-each
5489                         select="marc:datafield[@tag=501 or @tag=502 or @tag=504 or @tag=507 or @tag=508 or  @tag=513 or @tag=514 or @tag=515 or @tag=516 or @tag=522 or @tag=524 or @tag=525 or @tag=526 or @tag=535 or @tag=536 or @tag=540 or @tag=541 or @tag=544 or @tag=545 or @tag=546 or @tag=547 or @tag=550 or @tag=552 or @tag=555 or @tag=556 or @tag=561 or @tag=562 or @tag=565 or @tag=567 or @tag=580 or @tag=581 or @tag=584 or @tag=585 or @tag=586]">
5490                         <note>
5491                                 <xsl:call-template name="uri"/>
5492                                 <xsl:variable name="str">
5493                                         <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
5494                                                 <xsl:value-of select="."/>
5495                                                 <xsl:text> </xsl:text>
5496                                         </xsl:for-each>
5497                                 </xsl:variable>
5498                                 <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
5499                         </note>
5500                 </xsl:for-each>
5501                 <xsl:for-each
5502                         select="marc:datafield[@tag=034][marc:subfield[@code='d' or @code='e' or @code='f' or @code='g']]">
5503                         <subject>
5504                                 <cartographics>
5505                                         <coordinates>
5506                                                 <xsl:call-template name="subfieldSelect">
5507                                                         <xsl:with-param name="codes">defg</xsl:with-param>
5508                                                 </xsl:call-template>
5509                                         </coordinates>
5510                                 </cartographics>
5511                         </subject>
5512                 </xsl:for-each>
5513                 <xsl:for-each select="marc:datafield[@tag=043]">
5514                         <subject>
5515                                 <xsl:for-each select="marc:subfield[@code='a' or @code='b' or @code='c']">
5516                                         <geographicCode>
5517                                                 <xsl:attribute name="authority">
5518                                                         <xsl:if test="@code='a'">
5519                                                                 <xsl:text>marcgac</xsl:text>
5520                                                         </xsl:if>
5521                                                         <xsl:if test="@code='b'">
5522                                                                 <xsl:value-of select="following-sibling::marc:subfield[@code=2]"/>
5523                                                         </xsl:if>
5524                                                         <xsl:if test="@code='c'">
5525                                                                 <xsl:text>iso3166</xsl:text>
5526                                                         </xsl:if>
5527                                                 </xsl:attribute>
5528                                                 <xsl:value-of select="self::marc:subfield"/>
5529                                         </geographicCode>
5530                                 </xsl:for-each>
5531                         </subject>
5532                 </xsl:for-each>
5533                 <!-- tmee 2006/11/27 -->
5534                 <xsl:for-each select="marc:datafield[@tag=255]">
5535                         <subject>
5536                                 <xsl:for-each select="marc:subfield[@code='a' or @code='b' or @code='c']">
5537                                         <cartographics>
5538                                                 <xsl:if test="@code='a'">
5539                                                         <scale>
5540                                                                 <xsl:value-of select="."/>
5541                                                         </scale>
5542                                                 </xsl:if>
5543                                                 <xsl:if test="@code='b'">
5544                                                         <projection>
5545                                                                 <xsl:value-of select="."/>
5546                                                         </projection>
5547                                                 </xsl:if>
5548                                                 <xsl:if test="@code='c'">
5549                                                         <coordinates>
5550                                                                 <xsl:value-of select="."/>
5551                                                         </coordinates>
5552                                                 </xsl:if>
5553                                         </cartographics>
5554                                 </xsl:for-each>
5555                         </subject>
5556                 </xsl:for-each>
5557
5558                 <xsl:apply-templates select="marc:datafield[653 &gt;= @tag and @tag &gt;= 600]"/>
5559                 <xsl:apply-templates select="marc:datafield[@tag=656]"/>
5560                 <xsl:for-each select="marc:datafield[@tag=752 or @tag=662]">
5561                         <subject>
5562                                 <hierarchicalGeographic>
5563                                         <xsl:for-each select="marc:subfield[@code='a']">
5564                                                 <country>
5565                                                         <xsl:call-template name="chopPunctuation">
5566                                                                 <xsl:with-param name="chopString" select="."/>
5567                                                         </xsl:call-template>
5568                                                 </country>
5569                                         </xsl:for-each>
5570                                         <xsl:for-each select="marc:subfield[@code='b']">
5571                                                 <state>
5572                                                         <xsl:call-template name="chopPunctuation">
5573                                                                 <xsl:with-param name="chopString" select="."/>
5574                                                         </xsl:call-template>
5575                                                 </state>
5576                                         </xsl:for-each>
5577                                         <xsl:for-each select="marc:subfield[@code='c']">
5578                                                 <county>
5579                                                         <xsl:call-template name="chopPunctuation">
5580                                                                 <xsl:with-param name="chopString" select="."/>
5581                                                         </xsl:call-template>
5582                                                 </county>
5583                                         </xsl:for-each>
5584                                         <xsl:for-each select="marc:subfield[@code='d']">
5585                                                 <city>
5586                                                         <xsl:call-template name="chopPunctuation">
5587                                                                 <xsl:with-param name="chopString" select="."/>
5588                                                         </xsl:call-template>
5589                                                 </city>
5590                                         </xsl:for-each>
5591                                         <xsl:for-each select="marc:subfield[@code='e']">
5592                                                 <citySection>
5593                                                         <xsl:call-template name="chopPunctuation">
5594                                                                 <xsl:with-param name="chopString" select="."/>
5595                                                         </xsl:call-template>
5596                                                 </citySection>
5597                                         </xsl:for-each>
5598                                         <xsl:for-each select="marc:subfield[@code='g']">
5599                                                 <region>
5600                                                         <xsl:call-template name="chopPunctuation">
5601                                                                 <xsl:with-param name="chopString" select="."/>
5602                                                         </xsl:call-template>
5603                                                 </region>
5604                                         </xsl:for-each>
5605                                         <xsl:for-each select="marc:subfield[@code='h']">
5606                                                 <extraterrestrialArea>
5607                                                         <xsl:call-template name="chopPunctuation">
5608                                                                 <xsl:with-param name="chopString" select="."/>
5609                                                         </xsl:call-template>
5610                                                 </extraterrestrialArea>
5611                                         </xsl:for-each>
5612                                 </hierarchicalGeographic>
5613                         </subject>
5614                 </xsl:for-each>
5615                 <xsl:for-each select="marc:datafield[@tag=045][marc:subfield[@code='b']]">
5616                         <subject>
5617                                 <xsl:choose>
5618                                         <xsl:when test="@ind1=2">
5619                                                 <temporal encoding="iso8601" point="start">
5620                                                         <xsl:call-template name="chopPunctuation">
5621                                                                 <xsl:with-param name="chopString">
5622                                                                         <xsl:value-of select="marc:subfield[@code='b'][1]"/>
5623                                                                 </xsl:with-param>
5624                                                         </xsl:call-template>
5625                                                 </temporal>
5626                                                 <temporal encoding="iso8601" point="end">
5627                                                         <xsl:call-template name="chopPunctuation">
5628                                                                 <xsl:with-param name="chopString">
5629                                                                         <xsl:value-of select="marc:subfield[@code='b'][2]"/>
5630                                                                 </xsl:with-param>
5631                                                         </xsl:call-template>
5632                                                 </temporal>
5633                                         </xsl:when>
5634                                         <xsl:otherwise>
5635                                                 <xsl:for-each select="marc:subfield[@code='b']">
5636                                                         <temporal encoding="iso8601">
5637                                                                 <xsl:call-template name="chopPunctuation">
5638                                                                         <xsl:with-param name="chopString" select="."/>
5639                                                                 </xsl:call-template>
5640                                                         </temporal>
5641                                                 </xsl:for-each>
5642                                         </xsl:otherwise>
5643                                 </xsl:choose>
5644                         </subject>
5645                 </xsl:for-each>
5646                 <xsl:for-each select="marc:datafield[@tag=050]">
5647                         <xsl:for-each select="marc:subfield[@code='b']">
5648                                 <classification authority="lcc">
5649                                         <xsl:if test="../marc:subfield[@code='3']">
5650                                                 <xsl:attribute name="displayLabel">
5651                                                         <xsl:value-of select="../marc:subfield[@code='3']"/>
5652                                                 </xsl:attribute>
5653                                         </xsl:if>
5654                                         <xsl:value-of select="preceding-sibling::marc:subfield[@code='a'][1]"/>
5655                                         <xsl:text> </xsl:text>
5656                                         <xsl:value-of select="text()"/>
5657                                 </classification>
5658                         </xsl:for-each>
5659                         <xsl:for-each
5660                                 select="marc:subfield[@code='a'][not(following-sibling::marc:subfield[@code='b'])]">
5661                                 <classification authority="lcc">
5662                                         <xsl:if test="../marc:subfield[@code='3']">
5663                                                 <xsl:attribute name="displayLabel">
5664                                                         <xsl:value-of select="../marc:subfield[@code='3']"/>
5665                                                 </xsl:attribute>
5666                                         </xsl:if>
5667                                         <xsl:value-of select="text()"/>
5668                                 </classification>
5669                         </xsl:for-each>
5670                 </xsl:for-each>
5671                 <xsl:for-each select="marc:datafield[@tag=082]">
5672                         <classification authority="ddc">
5673                                 <xsl:if test="marc:subfield[@code='2']">
5674                                         <xsl:attribute name="edition">
5675                                                 <xsl:value-of select="marc:subfield[@code='2']"/>
5676                                         </xsl:attribute>
5677                                 </xsl:if>
5678                                 <xsl:call-template name="subfieldSelect">
5679                                         <xsl:with-param name="codes">ab</xsl:with-param>
5680                                 </xsl:call-template>
5681                         </classification>
5682                 </xsl:for-each>
5683                 <xsl:for-each select="marc:datafield[@tag=080]">
5684                         <classification authority="udc">
5685                                 <xsl:call-template name="subfieldSelect">
5686                                         <xsl:with-param name="codes">abx</xsl:with-param>
5687                                 </xsl:call-template>
5688                         </classification>
5689                 </xsl:for-each>
5690                 <xsl:for-each select="marc:datafield[@tag=060]">
5691                         <classification authority="nlm">
5692                                 <xsl:call-template name="subfieldSelect">
5693                                         <xsl:with-param name="codes">ab</xsl:with-param>
5694                                 </xsl:call-template>
5695                         </classification>
5696                 </xsl:for-each>
5697                 <xsl:for-each select="marc:datafield[@tag=086][@ind1=0]">
5698                         <classification authority="sudocs">
5699                                 <xsl:value-of select="marc:subfield[@code='a']"/>
5700                         </classification>
5701                 </xsl:for-each>
5702                 <xsl:for-each select="marc:datafield[@tag=086][@ind1=1]">
5703                         <classification authority="candoc">
5704                                 <xsl:value-of select="marc:subfield[@code='a']"/>
5705                         </classification>
5706                 </xsl:for-each>
5707                 <xsl:for-each select="marc:datafield[@tag=086]">
5708                         <classification>
5709                                 <xsl:attribute name="authority">
5710                                         <xsl:value-of select="marc:subfield[@code='2']"/>
5711                                 </xsl:attribute>
5712                                 <xsl:value-of select="marc:subfield[@code='a']"/>
5713                         </classification>
5714                 </xsl:for-each>
5715                 <xsl:for-each select="marc:datafield[@tag=084]">
5716                         <classification>
5717                                 <xsl:attribute name="authority">
5718                                         <xsl:value-of select="marc:subfield[@code='2']"/>
5719                                 </xsl:attribute>
5720                                 <xsl:call-template name="subfieldSelect">
5721                                         <xsl:with-param name="codes">ab</xsl:with-param>
5722                                 </xsl:call-template>
5723                         </classification>
5724                 </xsl:for-each>
5725                 <xsl:for-each select="marc:datafield[@tag=440]">
5726                         <relatedItem type="series">
5727                                 <titleInfo>
5728                                         <title>
5729                                                 <xsl:call-template name="chopPunctuation">
5730                                                         <xsl:with-param name="chopString">
5731                                                                 <xsl:call-template name="subfieldSelect">
5732                                                                         <xsl:with-param name="codes">av</xsl:with-param>
5733                                                                 </xsl:call-template>
5734                                                         </xsl:with-param>
5735                                                 </xsl:call-template>
5736                                         </title>
5737                                         <xsl:call-template name="part"/>
5738                                 </titleInfo>
5739                         </relatedItem>
5740                 </xsl:for-each>
5741                 <xsl:for-each select="marc:datafield[@tag=490][@ind1=0]">
5742                         <relatedItem type="series">
5743                                 <titleInfo>
5744                                         <title>
5745                                                 <xsl:call-template name="chopPunctuation">
5746                                                         <xsl:with-param name="chopString">
5747                                                                 <xsl:call-template name="subfieldSelect">
5748                                                                         <xsl:with-param name="codes">av</xsl:with-param>
5749                                                                 </xsl:call-template>
5750                                                         </xsl:with-param>
5751                                                 </xsl:call-template>
5752                                         </title>
5753                                         <xsl:call-template name="part"/>
5754                                 </titleInfo>
5755                         </relatedItem>
5756                 </xsl:for-each>
5757                 <xsl:for-each select="marc:datafield[@tag=510]">
5758                         <relatedItem type="isReferencedBy">
5759                                 <note>
5760                                         <xsl:call-template name="subfieldSelect">
5761                                                 <xsl:with-param name="codes">abcx3</xsl:with-param>
5762                                         </xsl:call-template>
5763                                 </note>
5764                         </relatedItem>
5765                 </xsl:for-each>
5766                 <xsl:for-each select="marc:datafield[@tag=534]">
5767                         <relatedItem type="original">
5768                                 <xsl:call-template name="relatedTitle"/>
5769                                 <xsl:call-template name="relatedName"/>
5770                                 <xsl:if test="marc:subfield[@code='b' or @code='c']">
5771                                         <originInfo>
5772                                                 <xsl:for-each select="marc:subfield[@code='c']">
5773                                                         <publisher>
5774                                                                 <xsl:value-of select="."/>
5775                                                         </publisher>
5776                                                 </xsl:for-each>
5777                                                 <xsl:for-each select="marc:subfield[@code='b']">
5778                                                         <edition>
5779                                                                 <xsl:value-of select="."/>
5780                                                         </edition>
5781                                                 </xsl:for-each>
5782                                         </originInfo>
5783                                 </xsl:if>
5784                                 <xsl:call-template name="relatedIdentifierISSN"/>
5785                                 <xsl:for-each select="marc:subfield[@code='z']">
5786                                         <identifier type="isbn">
5787                                                 <xsl:value-of select="."/>
5788                                         </identifier>
5789                                 </xsl:for-each>
5790                                 <xsl:call-template name="relatedNote"/>
5791                         </relatedItem>
5792                 </xsl:for-each>
5793                 <xsl:for-each select="marc:datafield[@tag=700][marc:subfield[@code='t']]">
5794                         <relatedItem>
5795                                 <xsl:call-template name="constituentOrRelatedType"/>
5796                                 <titleInfo>
5797                                         <title>
5798                                                 <xsl:call-template name="chopPunctuation">
5799                                                         <xsl:with-param name="chopString">
5800                                                                 <xsl:call-template name="specialSubfieldSelect">
5801                                                                         <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
5802                                                                         <xsl:with-param name="axis">t</xsl:with-param>
5803                                                                         <xsl:with-param name="afterCodes">g</xsl:with-param>
5804                                                                 </xsl:call-template>
5805                                                         </xsl:with-param>
5806                                                 </xsl:call-template>
5807                                         </title>
5808                                         <xsl:call-template name="part"/>
5809                                 </titleInfo>
5810                                 <name type="personal">
5811                                         <namePart>
5812                                                 <xsl:call-template name="specialSubfieldSelect">
5813                                                         <xsl:with-param name="anyCodes">aq</xsl:with-param>
5814                                                         <xsl:with-param name="axis">t</xsl:with-param>
5815                                                         <xsl:with-param name="beforeCodes">g</xsl:with-param>
5816                                                 </xsl:call-template>
5817                                         </namePart>
5818                                         <xsl:call-template name="termsOfAddress"/>
5819                                         <xsl:call-template name="nameDate"/>
5820                                         <xsl:call-template name="role"/>
5821                                 </name>
5822                                 <xsl:call-template name="relatedForm"/>
5823                                 <xsl:call-template name="relatedIdentifierISSN"/>
5824                         </relatedItem>
5825                 </xsl:for-each>
5826                 <xsl:for-each select="marc:datafield[@tag=710][marc:subfield[@code='t']]">
5827                         <relatedItem>
5828                                 <xsl:call-template name="constituentOrRelatedType"/>
5829                                 <titleInfo>
5830                                         <title>
5831                                                 <xsl:call-template name="chopPunctuation">
5832                                                         <xsl:with-param name="chopString">
5833                                                                 <xsl:call-template name="specialSubfieldSelect">
5834                                                                         <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
5835                                                                         <xsl:with-param name="axis">t</xsl:with-param>
5836                                                                         <xsl:with-param name="afterCodes">dg</xsl:with-param>
5837                                                                 </xsl:call-template>
5838                                                         </xsl:with-param>
5839                                                 </xsl:call-template>
5840                                         </title>
5841                                         <xsl:call-template name="relatedPartNumName"/>
5842                                 </titleInfo>
5843                                 <name type="corporate">
5844                                         <xsl:for-each select="marc:subfield[@code='a']">
5845                                                 <namePart>
5846                                                         <xsl:value-of select="."/>
5847                                                 </namePart>
5848                                         </xsl:for-each>
5849                                         <xsl:for-each select="marc:subfield[@code='b']">
5850                                                 <namePart>
5851                                                         <xsl:value-of select="."/>
5852                                                 </namePart>
5853                                         </xsl:for-each>
5854                                         <xsl:variable name="tempNamePart">
5855                                                 <xsl:call-template name="specialSubfieldSelect">
5856                                                         <xsl:with-param name="anyCodes">c</xsl:with-param>
5857                                                         <xsl:with-param name="axis">t</xsl:with-param>
5858                                                         <xsl:with-param name="beforeCodes">dgn</xsl:with-param>
5859                                                 </xsl:call-template>
5860                                         </xsl:variable>
5861                                         <xsl:if test="normalize-space($tempNamePart)">
5862                                                 <namePart>
5863                                                         <xsl:value-of select="$tempNamePart"/>
5864                                                 </namePart>
5865                                         </xsl:if>
5866                                         <xsl:call-template name="role"/>
5867                                 </name>
5868                                 <xsl:call-template name="relatedForm"/>
5869                                 <xsl:call-template name="relatedIdentifierISSN"/>
5870                         </relatedItem>
5871                 </xsl:for-each>
5872                 <xsl:for-each select="marc:datafield[@tag=711][marc:subfield[@code='t']]">
5873                         <relatedItem>
5874                                 <xsl:call-template name="constituentOrRelatedType"/>
5875                                 <titleInfo>
5876                                         <title>
5877                                                 <xsl:call-template name="chopPunctuation">
5878                                                         <xsl:with-param name="chopString">
5879                                                                 <xsl:call-template name="specialSubfieldSelect">
5880                                                                         <xsl:with-param name="anyCodes">tfklsv</xsl:with-param>
5881                                                                         <xsl:with-param name="axis">t</xsl:with-param>
5882                                                                         <xsl:with-param name="afterCodes">g</xsl:with-param>
5883                                                                 </xsl:call-template>
5884                                                         </xsl:with-param>
5885                                                 </xsl:call-template>
5886                                         </title>
5887                                         <xsl:call-template name="relatedPartNumName"/>
5888                                 </titleInfo>
5889                                 <name type="conference">
5890                                         <namePart>
5891                                                 <xsl:call-template name="specialSubfieldSelect">
5892                                                         <xsl:with-param name="anyCodes">aqdc</xsl:with-param>
5893                                                         <xsl:with-param name="axis">t</xsl:with-param>
5894                                                         <xsl:with-param name="beforeCodes">gn</xsl:with-param>
5895                                                 </xsl:call-template>
5896                                         </namePart>
5897                                 </name>
5898                                 <xsl:call-template name="relatedForm"/>
5899                                 <xsl:call-template name="relatedIdentifierISSN"/>
5900                         </relatedItem>
5901                 </xsl:for-each>
5902                 <xsl:for-each select="marc:datafield[@tag=730][@ind2=2]">
5903                         <relatedItem>
5904                                 <xsl:call-template name="constituentOrRelatedType"/>
5905                                 <titleInfo>
5906                                         <title>
5907                                                 <xsl:call-template name="chopPunctuation">
5908                                                         <xsl:with-param name="chopString">
5909                                                                 <xsl:call-template name="subfieldSelect">
5910                                                                         <xsl:with-param name="codes">adfgklmorsv</xsl:with-param>
5911                                                                 </xsl:call-template>
5912                                                         </xsl:with-param>
5913                                                 </xsl:call-template>
5914                                         </title>
5915                                         <xsl:call-template name="part"/>
5916                                 </titleInfo>
5917                                 <xsl:call-template name="relatedForm"/>
5918                                 <xsl:call-template name="relatedIdentifierISSN"/>
5919                         </relatedItem>
5920                 </xsl:for-each>
5921                 <xsl:for-each select="marc:datafield[@tag=740][@ind2=2]">
5922                         <relatedItem>
5923                                 <xsl:call-template name="constituentOrRelatedType"/>
5924                                 <titleInfo>
5925                                         <title>
5926                                                 <xsl:call-template name="chopPunctuation">
5927                                                         <xsl:with-param name="chopString">
5928                                                                 <xsl:value-of select="marc:subfield[@code='a']"/>
5929                                                         </xsl:with-param>
5930                                                 </xsl:call-template>
5931                                         </title>
5932                                         <xsl:call-template name="part"/>
5933                                 </titleInfo>
5934                                 <xsl:call-template name="relatedForm"/>
5935                         </relatedItem>
5936                 </xsl:for-each>
5937                 <xsl:for-each select="marc:datafield[@tag=760]|marc:datafield[@tag=762]">
5938                         <relatedItem type="series">
5939                                 <xsl:call-template name="relatedItem76X-78X"/>
5940                         </relatedItem>
5941                 </xsl:for-each>
5942                 <xsl:for-each
5943                         select="marc:datafield[@tag=765]|marc:datafield[@tag=767]|marc:datafield[@tag=777]|marc:datafield[@tag=787]">
5944                         <relatedItem>
5945                                 <xsl:call-template name="relatedItem76X-78X"/>
5946                         </relatedItem>
5947                 </xsl:for-each>
5948                 <xsl:for-each select="marc:datafield[@tag=775]">
5949                         <relatedItem type="otherVersion">
5950                                 <xsl:call-template name="relatedItem76X-78X"/>
5951                         </relatedItem>
5952                 </xsl:for-each>
5953                 <xsl:for-each select="marc:datafield[@tag=770]|marc:datafield[@tag=774]">
5954                         <relatedItem type="constituent">
5955                                 <xsl:call-template name="relatedItem76X-78X"/>
5956                         </relatedItem>
5957                 </xsl:for-each>
5958                 <xsl:for-each select="marc:datafield[@tag=772]|marc:datafield[@tag=773]">
5959                         <relatedItem type="host">
5960                                 <xsl:call-template name="relatedItem76X-78X"/>
5961                         </relatedItem>
5962                 </xsl:for-each>
5963                 <xsl:for-each select="marc:datafield[@tag=776]">
5964                         <relatedItem type="otherFormat">
5965                                 <xsl:call-template name="relatedItem76X-78X"/>
5966                         </relatedItem>
5967                 </xsl:for-each>
5968                 <xsl:for-each select="marc:datafield[@tag=780]">
5969                         <relatedItem type="preceding">
5970                                 <xsl:call-template name="relatedItem76X-78X"/>
5971                         </relatedItem>
5972                 </xsl:for-each>
5973                 <xsl:for-each select="marc:datafield[@tag=785]">
5974                         <relatedItem type="succeeding">
5975                                 <xsl:call-template name="relatedItem76X-78X"/>
5976                         </relatedItem>
5977                 </xsl:for-each>
5978                 <xsl:for-each select="marc:datafield[@tag=786]">
5979                         <relatedItem type="original">
5980                                 <xsl:call-template name="relatedItem76X-78X"/>
5981                         </relatedItem>
5982                 </xsl:for-each>
5983                 <xsl:for-each select="marc:datafield[@tag=800]">
5984                         <relatedItem type="series">
5985                                 <titleInfo>
5986                                         <title>
5987                                                 <xsl:call-template name="chopPunctuation">
5988                                                         <xsl:with-param name="chopString">
5989                                                                 <xsl:call-template name="specialSubfieldSelect">
5990                                                                         <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
5991                                                                         <xsl:with-param name="axis">t</xsl:with-param>
5992                                                                         <xsl:with-param name="afterCodes">g</xsl:with-param>
5993                                                                 </xsl:call-template>
5994                                                         </xsl:with-param>
5995                                                 </xsl:call-template>
5996                                         </title>
5997                                         <xsl:call-template name="part"/>
5998                                 </titleInfo>
5999                                 <name type="personal">
6000                                         <namePart>
6001                                                 <xsl:call-template name="chopPunctuation">
6002                                                         <xsl:with-param name="chopString">
6003                                                                 <xsl:call-template name="specialSubfieldSelect">
6004                                                                         <xsl:with-param name="anyCodes">aq</xsl:with-param>
6005                                                                         <xsl:with-param name="axis">t</xsl:with-param>
6006                                                                         <xsl:with-param name="beforeCodes">g</xsl:with-param>
6007                                                                 </xsl:call-template>
6008                                                         </xsl:with-param>
6009                                                 </xsl:call-template>
6010                                         </namePart>
6011                                         <xsl:call-template name="termsOfAddress"/>
6012                                         <xsl:call-template name="nameDate"/>
6013                                         <xsl:call-template name="role"/>
6014                                 </name>
6015                                 <xsl:call-template name="relatedForm"/>
6016                         </relatedItem>
6017                 </xsl:for-each>
6018                 <xsl:for-each select="marc:datafield[@tag=810]">
6019                         <relatedItem type="series">
6020                                 <titleInfo>
6021                                         <title>
6022                                                 <xsl:call-template name="chopPunctuation">
6023                                                         <xsl:with-param name="chopString">
6024                                                                 <xsl:call-template name="specialSubfieldSelect">
6025                                                                         <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
6026                                                                         <xsl:with-param name="axis">t</xsl:with-param>
6027                                                                         <xsl:with-param name="afterCodes">dg</xsl:with-param>
6028                                                                 </xsl:call-template>
6029                                                         </xsl:with-param>
6030                                                 </xsl:call-template>
6031                                         </title>
6032                                         <xsl:call-template name="relatedPartNumName"/>
6033                                 </titleInfo>
6034                                 <name type="corporate">
6035                                         <xsl:for-each select="marc:subfield[@code='a']">
6036                                                 <namePart>
6037                                                         <xsl:value-of select="."/>
6038                                                 </namePart>
6039                                         </xsl:for-each>
6040                                         <xsl:for-each select="marc:subfield[@code='b']">
6041                                                 <namePart>
6042                                                         <xsl:value-of select="."/>
6043                                                 </namePart>
6044                                         </xsl:for-each>
6045                                         <namePart>
6046                                                 <xsl:call-template name="specialSubfieldSelect">
6047                                                         <xsl:with-param name="anyCodes">c</xsl:with-param>
6048                                                         <xsl:with-param name="axis">t</xsl:with-param>
6049                                                         <xsl:with-param name="beforeCodes">dgn</xsl:with-param>
6050                                                 </xsl:call-template>
6051                                         </namePart>
6052                                         <xsl:call-template name="role"/>
6053                                 </name>
6054                                 <xsl:call-template name="relatedForm"/>
6055                         </relatedItem>
6056                 </xsl:for-each>
6057                 <xsl:for-each select="marc:datafield[@tag=811]">
6058                         <relatedItem type="series">
6059                                 <titleInfo>
6060                                         <title>
6061                                                 <xsl:call-template name="chopPunctuation">
6062                                                         <xsl:with-param name="chopString">
6063                                                                 <xsl:call-template name="specialSubfieldSelect">
6064                                                                         <xsl:with-param name="anyCodes">tfklsv</xsl:with-param>
6065                                                                         <xsl:with-param name="axis">t</xsl:with-param>
6066                                                                         <xsl:with-param name="afterCodes">g</xsl:with-param>
6067                                                                 </xsl:call-template>
6068                                                         </xsl:with-param>
6069                                                 </xsl:call-template>
6070                                         </title>
6071                                         <xsl:call-template name="relatedPartNumName"/>
6072                                 </titleInfo>
6073                                 <name type="conference">
6074                                         <namePart>
6075                                                 <xsl:call-template name="specialSubfieldSelect">
6076                                                         <xsl:with-param name="anyCodes">aqdc</xsl:with-param>
6077                                                         <xsl:with-param name="axis">t</xsl:with-param>
6078                                                         <xsl:with-param name="beforeCodes">gn</xsl:with-param>
6079                                                 </xsl:call-template>
6080                                         </namePart>
6081                                         <xsl:call-template name="role"/>
6082                                 </name>
6083                                 <xsl:call-template name="relatedForm"/>
6084                         </relatedItem>
6085                 </xsl:for-each>
6086                 <xsl:for-each select="marc:datafield[@tag='830']">
6087                         <relatedItem type="series">
6088                                 <titleInfo>
6089                                         <title>
6090                                                 <xsl:call-template name="chopPunctuation">
6091                                                         <xsl:with-param name="chopString">
6092                                                                 <xsl:call-template name="subfieldSelect">
6093                                                                         <xsl:with-param name="codes">adfgklmorsv</xsl:with-param>
6094                                                                 </xsl:call-template>
6095                                                         </xsl:with-param>
6096                                                 </xsl:call-template>
6097                                         </title>
6098                                         <xsl:call-template name="part"/>
6099                                 </titleInfo>
6100                                 <xsl:call-template name="relatedForm"/>
6101                         </relatedItem>
6102                 </xsl:for-each>
6103                 <xsl:for-each select="marc:datafield[@tag='856'][@ind2='2']/marc:subfield[@code='q']">
6104                         <relatedItem>
6105                                 <internetMediaType>
6106                                         <xsl:value-of select="."/>
6107                                 </internetMediaType>
6108                         </relatedItem>
6109                 </xsl:for-each>
6110                 <xsl:for-each select="marc:datafield[@tag='020']">
6111                         <xsl:call-template name="isInvalid">
6112                                 <xsl:with-param name="type">isbn</xsl:with-param>
6113                         </xsl:call-template>
6114                         <xsl:if test="marc:subfield[@code='a']">
6115                                 <identifier type="isbn">
6116                                         <xsl:value-of select="marc:subfield[@code='a']"/>
6117                                 </identifier>
6118                         </xsl:if>
6119                 </xsl:for-each>
6120                 <xsl:for-each select="marc:datafield[@tag='024'][@ind1='0']">
6121                         <xsl:call-template name="isInvalid">
6122                                 <xsl:with-param name="type">isrc</xsl:with-param>
6123                         </xsl:call-template>
6124                         <xsl:if test="marc:subfield[@code='a']">
6125                                 <identifier type="isrc">
6126                                         <xsl:value-of select="marc:subfield[@code='a']"/>
6127                                 </identifier>
6128                         </xsl:if>
6129                 </xsl:for-each>
6130                 <xsl:for-each select="marc:datafield[@tag='024'][@ind1='2']">
6131                         <xsl:call-template name="isInvalid">
6132                                 <xsl:with-param name="type">ismn</xsl:with-param>
6133                         </xsl:call-template>
6134                         <xsl:if test="marc:subfield[@code='a']">
6135                                 <identifier type="ismn">
6136                                         <xsl:value-of select="marc:subfield[@code='a']"/>
6137                                 </identifier>
6138                         </xsl:if>
6139                 </xsl:for-each>
6140                 <xsl:for-each select="marc:datafield[@tag='024'][@ind1='4']">
6141                         <xsl:call-template name="isInvalid">
6142                                 <xsl:with-param name="type">sici</xsl:with-param>
6143                         </xsl:call-template>
6144                         <identifier type="sici">
6145                                 <xsl:call-template name="subfieldSelect">
6146                                         <xsl:with-param name="codes">ab</xsl:with-param>
6147                                 </xsl:call-template>
6148                         </identifier>
6149                 </xsl:for-each>
6150                 <xsl:for-each select="marc:datafield[@tag='022']">
6151                         <xsl:if test="marc:subfield[@code='a']">
6152                                 <xsl:call-template name="isInvalid">
6153                                         <xsl:with-param name="type">issn</xsl:with-param>
6154                                 </xsl:call-template>
6155                                 <identifier type="issn">
6156                                         <xsl:value-of select="marc:subfield[@code='a']"/>
6157                                 </identifier>
6158                         </xsl:if>
6159                         <xsl:if test="marc:subfield[@code='l']">
6160                                 <xsl:call-template name="isInvalid">
6161                                         <xsl:with-param name="type">issn-l</xsl:with-param>
6162                                 </xsl:call-template>
6163                                 <identifier type="issn-l">
6164                                         <xsl:value-of select="marc:subfield[@code='l']"/>
6165                                 </identifier>
6166                         </xsl:if>
6167                 </xsl:for-each>
6168
6169
6170
6171                 <xsl:for-each select="marc:datafield[@tag='010']">
6172                         <xsl:call-template name="isInvalid">
6173                                 <xsl:with-param name="type">lccn</xsl:with-param>
6174                         </xsl:call-template>
6175                         <identifier type="lccn">
6176                                 <xsl:value-of select="normalize-space(marc:subfield[@code='a'])"/>
6177                         </identifier>
6178                 </xsl:for-each>
6179                 <xsl:for-each select="marc:datafield[@tag='028']">
6180                         <identifier>
6181                                 <xsl:attribute name="type">
6182                                         <xsl:choose>
6183                                                 <xsl:when test="@ind1='0'">issue number</xsl:when>
6184                                                 <xsl:when test="@ind1='1'">matrix number</xsl:when>
6185                                                 <xsl:when test="@ind1='2'">music plate</xsl:when>
6186                                                 <xsl:when test="@ind1='3'">music publisher</xsl:when>
6187                                                 <xsl:when test="@ind1='4'">videorecording identifier</xsl:when>
6188                                         </xsl:choose>
6189                                 </xsl:attribute>
6190                                 <!--<xsl:call-template name="isInvalid"/>-->
6191                                 <!-- no $z in 028 -->
6192                                 <xsl:call-template name="subfieldSelect">
6193                                         <xsl:with-param name="codes">
6194                                                 <xsl:choose>
6195                                                         <xsl:when test="@ind1='0'">ba</xsl:when>
6196                                                         <xsl:otherwise>ab</xsl:otherwise>
6197                                                 </xsl:choose>
6198                                         </xsl:with-param>
6199                                 </xsl:call-template>
6200                         </identifier>
6201                 </xsl:for-each>
6202                 <xsl:for-each select="marc:datafield[@tag='037']">
6203                         <identifier type="stock number">
6204                                 <!--<xsl:call-template name="isInvalid"/>-->
6205                                 <!-- no $z in 037 -->
6206                                 <xsl:call-template name="subfieldSelect">
6207                                         <xsl:with-param name="codes">ab</xsl:with-param>
6208                                 </xsl:call-template>
6209                         </identifier>
6210                 </xsl:for-each>
6211                 <xsl:for-each select="marc:datafield[@tag='856'][marc:subfield[@code='u']]">
6212                         <identifier>
6213                                 <xsl:attribute name="type">
6214                                         <xsl:choose>
6215                                                 <xsl:when
6216                                                         test="starts-with(marc:subfield[@code='u'],'urn:doi') or starts-with(marc:subfield[@code='u'],'doi')"
6217                                                         >doi</xsl:when>
6218                                                 <xsl:when
6219                                                         test="starts-with(marc:subfield[@code='u'],'urn:hdl') or starts-with(marc:subfield[@code='u'],'hdl') or starts-with(marc:subfield[@code='u'],'http://hdl.loc.gov')"
6220                                                         >hdl</xsl:when>
6221                                                 <xsl:otherwise>uri</xsl:otherwise>
6222                                         </xsl:choose>
6223                                 </xsl:attribute>
6224                                 <xsl:choose>
6225                                         <xsl:when
6226                                                 test="starts-with(marc:subfield[@code='u'],'urn:hdl') or starts-with(marc:subfield[@code='u'],'hdl') or starts-with(marc:subfield[@code='u'],'http://hdl.loc.gov') ">
6227                                                 <xsl:value-of
6228                                                         select="concat('hdl:',substring-after(marc:subfield[@code='u'],'http://hdl.loc.gov/'))"
6229                                                 />
6230                                         </xsl:when>
6231                                         <xsl:otherwise>
6232                                                 <xsl:value-of select="marc:subfield[@code='u']"/>
6233                                         </xsl:otherwise>
6234                                 </xsl:choose>
6235                         </identifier>
6236                         <xsl:if
6237                                 test="starts-with(marc:subfield[@code='u'],'urn:hdl') or starts-with(marc:subfield[@code='u'],'hdl')">
6238                                 <identifier type="hdl">
6239                                         <xsl:if test="marc:subfield[@code='y' or @code='3' or @code='z']">
6240                                                 <xsl:attribute name="displayLabel">
6241                                                         <xsl:call-template name="subfieldSelect">
6242                                                                 <xsl:with-param name="codes">y3z</xsl:with-param>
6243                                                         </xsl:call-template>
6244                                                 </xsl:attribute>
6245                                         </xsl:if>
6246                                         <xsl:value-of
6247                                                 select="concat('hdl:',substring-after(marc:subfield[@code='u'],'http://hdl.loc.gov/'))"
6248                                         />
6249                                 </identifier>
6250                         </xsl:if>
6251                 </xsl:for-each>
6252                 <xsl:for-each select="marc:datafield[@tag=024][@ind1=1]">
6253                         <identifier type="upc">
6254                                 <xsl:call-template name="isInvalid"/>
6255                                 <xsl:value-of select="marc:subfield[@code='a']"/>
6256                         </identifier>
6257                 </xsl:for-each>
6258
6259                 <!-- 1/04 fix added $y -->
6260
6261                 <!-- 1.21  tmee-->
6262                 <xsl:for-each select="marc:datafield[@tag=856][@ind2=1][marc:subfield[@code='u']]">
6263                         <relatedItem type="otherVersion">
6264                                 <location>
6265                                         <url>
6266                                                 <xsl:if test="marc:subfield[@code='y' or @code='3']">
6267                                                         <xsl:attribute name="displayLabel">
6268                                                                 <xsl:call-template name="subfieldSelect">
6269                                                                         <xsl:with-param name="codes">y3</xsl:with-param>
6270                                                                 </xsl:call-template>
6271                                                         </xsl:attribute>
6272                                                 </xsl:if>
6273                                                 <xsl:if test="marc:subfield[@code='z' ]">
6274                                                         <xsl:attribute name="note">
6275                                                                 <xsl:call-template name="subfieldSelect">
6276                                                                         <xsl:with-param name="codes">z</xsl:with-param>
6277                                                                 </xsl:call-template>
6278                                                         </xsl:attribute>
6279                                                 </xsl:if>
6280                                                 <xsl:value-of select="marc:subfield[@code='u']"/>
6281                                         </url>
6282                                 </location>
6283                         </relatedItem>
6284                 </xsl:for-each>
6285                 <xsl:for-each select="marc:datafield[@tag=856][@ind2=2][marc:subfield[@code='u']]">
6286                         <relatedItem>
6287                                 <location>
6288                                         <url>
6289                                                 <xsl:if test="marc:subfield[@code='y' or @code='3']">
6290                                                         <xsl:attribute name="displayLabel">
6291                                                                 <xsl:call-template name="subfieldSelect">
6292                                                                         <xsl:with-param name="codes">y3</xsl:with-param>
6293                                                                 </xsl:call-template>
6294                                                         </xsl:attribute>
6295                                                 </xsl:if>
6296                                                 <xsl:if test="marc:subfield[@code='z' ]">
6297                                                         <xsl:attribute name="note">
6298                                                                 <xsl:call-template name="subfieldSelect">
6299                                                                         <xsl:with-param name="codes">z</xsl:with-param>
6300                                                                 </xsl:call-template>
6301                                                         </xsl:attribute>
6302                                                 </xsl:if>
6303                                                 <xsl:value-of select="marc:subfield[@code='u']"/>
6304                                         </url>
6305                                 </location>
6306                         </relatedItem>
6307                 </xsl:for-each>
6308
6309                 <!-- 3.2 change tmee 856z  -->
6310
6311                 <!-- 1.24  tmee  -->
6312                 <xsl:for-each select="marc:datafield[@tag=852]">
6313                         <location>
6314                                 <xsl:if test="marc:subfield[@code='a' or @code='b' or @code='e']">
6315                                         <physicalLocation>
6316                                                 <xsl:call-template name="subfieldSelect">
6317                                                         <xsl:with-param name="codes">abe</xsl:with-param>
6318                                                 </xsl:call-template>
6319                                         </physicalLocation>
6320                                 </xsl:if>
6321
6322                                 <xsl:if test="marc:subfield[@code='u']">
6323                                         <physicalLocation>
6324                                                 <xsl:call-template name="uri"/>
6325                                                 <xsl:call-template name="subfieldSelect">
6326                                                         <xsl:with-param name="codes">u</xsl:with-param>
6327                                                 </xsl:call-template>
6328                                         </physicalLocation>
6329                                 </xsl:if>
6330
6331                                 <xsl:if
6332                                         test="marc:subfield[@code='h' or @code='i' or @code='j' or @code='k' or @code='l' or @code='m' or @code='t']">
6333                                         <shelfLocation>
6334                                                 <xsl:call-template name="subfieldSelect">
6335                                                         <xsl:with-param name="codes">hijklmt</xsl:with-param>
6336                                                 </xsl:call-template>
6337                                         </shelfLocation>
6338                                 </xsl:if>
6339                         </location>
6340                 </xsl:for-each>
6341
6342                 <xsl:for-each select="marc:datafield[@tag=506]">
6343                         <accessCondition type="restrictionOnAccess">
6344                                 <xsl:call-template name="subfieldSelect">
6345                                         <xsl:with-param name="codes">abcd35</xsl:with-param>
6346                                 </xsl:call-template>
6347                         </accessCondition>
6348                 </xsl:for-each>
6349                 <xsl:for-each select="marc:datafield[@tag=540]">
6350                         <accessCondition type="useAndReproduction">
6351                                 <xsl:call-template name="subfieldSelect">
6352                                         <xsl:with-param name="codes">abcde35</xsl:with-param>
6353                                 </xsl:call-template>
6354                         </accessCondition>
6355                 </xsl:for-each>
6356
6357                 <recordInfo>
6358                         <!-- 1.25  tmee-->
6359
6360
6361                         <xsl:for-each select="marc:leader[substring($leader,19,1)='a']">
6362                                 <descriptionStandard>aacr2</descriptionStandard>
6363                         </xsl:for-each>
6364
6365                         <xsl:for-each select="marc:datafield[@tag=040]">
6366                                 <xsl:if test="marc:subfield[@code='e']">
6367                                         <descriptionStandard>
6368                                                 <xsl:value-of select="marc:subfield[@code='e']"/>
6369                                         </descriptionStandard>
6370                                 </xsl:if>
6371                                 <recordContentSource authority="marcorg">
6372                                         <xsl:value-of select="marc:subfield[@code='a']"/>
6373                                 </recordContentSource>
6374                         </xsl:for-each>
6375                         <xsl:for-each select="marc:controlfield[@tag=008]">
6376                                 <recordCreationDate encoding="marc">
6377                                         <xsl:value-of select="substring(.,1,6)"/>
6378                                 </recordCreationDate>
6379                         </xsl:for-each>
6380
6381                         <xsl:for-each select="marc:controlfield[@tag=005]">
6382                                 <recordChangeDate encoding="iso8601">
6383                                         <xsl:value-of select="."/>
6384                                 </recordChangeDate>
6385                         </xsl:for-each>
6386                         <xsl:for-each select="marc:controlfield[@tag=001]">
6387                                 <recordIdentifier>
6388                                         <xsl:if test="../marc:controlfield[@tag=003]">
6389                                                 <xsl:attribute name="source">
6390                                                         <xsl:value-of select="../marc:controlfield[@tag=003]"/>
6391                                                 </xsl:attribute>
6392                                         </xsl:if>
6393                                         <xsl:value-of select="."/>
6394                                 </recordIdentifier>
6395                         </xsl:for-each>
6396                         <xsl:for-each select="marc:datafield[@tag=040]/marc:subfield[@code='b']">
6397                                 <languageOfCataloging>
6398                                         <languageTerm authority="iso639-2b" type="code">
6399                                                 <xsl:value-of select="."/>
6400                                         </languageTerm>
6401                                 </languageOfCataloging>
6402                         </xsl:for-each>
6403                 </recordInfo>
6404         </xsl:template>
6405         <xsl:template name="displayForm">
6406                 <xsl:for-each select="marc:subfield[@code='c']">
6407                         <displayForm>
6408                                 <xsl:value-of select="."/>
6409                         </displayForm>
6410                 </xsl:for-each>
6411         </xsl:template>
6412         <xsl:template name="affiliation">
6413                 <xsl:for-each select="marc:subfield[@code='u']">
6414                         <affiliation>
6415                                 <xsl:value-of select="."/>
6416                         </affiliation>
6417                 </xsl:for-each>
6418         </xsl:template>
6419         <xsl:template name="uri">
6420                 <xsl:for-each select="marc:subfield[@code='u']|marc:subfield[@code='0']">
6421                         <xsl:attribute name="xlink:href">
6422                                 <xsl:value-of select="."/>
6423                         </xsl:attribute>
6424                 </xsl:for-each>
6425         </xsl:template>
6426         <xsl:template name="role">
6427                 <xsl:for-each select="marc:subfield[@code='e']">
6428                         <role>
6429                                 <roleTerm type="text">
6430                                         <xsl:value-of select="."/>
6431                                 </roleTerm>
6432                         </role>
6433                 </xsl:for-each>
6434                 <xsl:for-each select="marc:subfield[@code='4']">
6435                         <role>
6436                                 <roleTerm authority="marcrelator" type="code">
6437                                         <xsl:value-of select="."/>
6438                                 </roleTerm>
6439                         </role>
6440                 </xsl:for-each>
6441         </xsl:template>
6442         <xsl:template name="part">
6443                 <xsl:variable name="partNumber">
6444                         <xsl:call-template name="specialSubfieldSelect">
6445                                 <xsl:with-param name="axis">n</xsl:with-param>
6446                                 <xsl:with-param name="anyCodes">n</xsl:with-param>
6447                                 <xsl:with-param name="afterCodes">fgkdlmor</xsl:with-param>
6448                         </xsl:call-template>
6449                 </xsl:variable>
6450                 <xsl:variable name="partName">
6451                         <xsl:call-template name="specialSubfieldSelect">
6452                                 <xsl:with-param name="axis">p</xsl:with-param>
6453                                 <xsl:with-param name="anyCodes">p</xsl:with-param>
6454                                 <xsl:with-param name="afterCodes">fgkdlmor</xsl:with-param>
6455                         </xsl:call-template>
6456                 </xsl:variable>
6457                 <xsl:if test="string-length(normalize-space($partNumber))">
6458                         <partNumber>
6459                                 <xsl:call-template name="chopPunctuation">
6460                                         <xsl:with-param name="chopString" select="$partNumber"/>
6461                                 </xsl:call-template>
6462                         </partNumber>
6463                 </xsl:if>
6464                 <xsl:if test="string-length(normalize-space($partName))">
6465                         <partName>
6466                                 <xsl:call-template name="chopPunctuation">
6467                                         <xsl:with-param name="chopString" select="$partName"/>
6468                                 </xsl:call-template>
6469                         </partName>
6470                 </xsl:if>
6471         </xsl:template>
6472         <xsl:template name="relatedPart">
6473                 <xsl:if test="@tag=773">
6474                         <xsl:for-each select="marc:subfield[@code='g']">
6475                                 <part>
6476                                         <text>
6477                                                 <xsl:value-of select="."/>
6478                                         </text>
6479                                 </part>
6480                         </xsl:for-each>
6481                         <xsl:for-each select="marc:subfield[@code='q']">
6482                                 <part>
6483                                         <xsl:call-template name="parsePart"/>
6484                                 </part>
6485                         </xsl:for-each>
6486                 </xsl:if>
6487         </xsl:template>
6488         <xsl:template name="relatedPartNumName">
6489                 <xsl:variable name="partNumber">
6490                         <xsl:call-template name="specialSubfieldSelect">
6491                                 <xsl:with-param name="axis">g</xsl:with-param>
6492                                 <xsl:with-param name="anyCodes">g</xsl:with-param>
6493                                 <xsl:with-param name="afterCodes">pst</xsl:with-param>
6494                         </xsl:call-template>
6495                 </xsl:variable>
6496                 <xsl:variable name="partName">
6497                         <xsl:call-template name="specialSubfieldSelect">
6498                                 <xsl:with-param name="axis">p</xsl:with-param>
6499                                 <xsl:with-param name="anyCodes">p</xsl:with-param>
6500                                 <xsl:with-param name="afterCodes">fgkdlmor</xsl:with-param>
6501                         </xsl:call-template>
6502                 </xsl:variable>
6503                 <xsl:if test="string-length(normalize-space($partNumber))">
6504                         <partNumber>
6505                                 <xsl:value-of select="$partNumber"/>
6506                         </partNumber>
6507                 </xsl:if>
6508                 <xsl:if test="string-length(normalize-space($partName))">
6509                         <partName>
6510                                 <xsl:value-of select="$partName"/>
6511                         </partName>
6512                 </xsl:if>
6513         </xsl:template>
6514         <xsl:template name="relatedName">
6515                 <xsl:for-each select="marc:subfield[@code='a']">
6516                         <name>
6517                                 <namePart>
6518                                         <xsl:value-of select="."/>
6519                                 </namePart>
6520                         </name>
6521                 </xsl:for-each>
6522         </xsl:template>
6523         <xsl:template name="relatedForm">
6524                 <xsl:for-each select="marc:subfield[@code='h']">
6525                         <physicalDescription>
6526                                 <form>
6527                                         <xsl:value-of select="."/>
6528                                 </form>
6529                         </physicalDescription>
6530                 </xsl:for-each>
6531         </xsl:template>
6532         <xsl:template name="relatedExtent">
6533                 <xsl:for-each select="marc:subfield[@code='h']">
6534                         <physicalDescription>
6535                                 <extent>
6536                                         <xsl:value-of select="."/>
6537                                 </extent>
6538                         </physicalDescription>
6539                 </xsl:for-each>
6540         </xsl:template>
6541         <xsl:template name="relatedNote">
6542                 <xsl:for-each select="marc:subfield[@code='n']">
6543                         <note>
6544                                 <xsl:value-of select="."/>
6545                         </note>
6546                 </xsl:for-each>
6547         </xsl:template>
6548         <xsl:template name="relatedSubject">
6549                 <xsl:for-each select="marc:subfield[@code='j']">
6550                         <subject>
6551                                 <temporal encoding="iso8601">
6552                                         <xsl:call-template name="chopPunctuation">
6553                                                 <xsl:with-param name="chopString" select="."/>
6554                                         </xsl:call-template>
6555                                 </temporal>
6556                         </subject>
6557                 </xsl:for-each>
6558         </xsl:template>
6559         <xsl:template name="relatedIdentifierISSN">
6560                 <xsl:for-each select="marc:subfield[@code='x']">
6561                         <identifier type="issn">
6562                                 <xsl:value-of select="."/>
6563                         </identifier>
6564                 </xsl:for-each>
6565         </xsl:template>
6566         <xsl:template name="relatedIdentifierLocal">
6567                 <xsl:for-each select="marc:subfield[@code='w']">
6568                         <identifier type="local">
6569                                 <xsl:value-of select="."/>
6570                         </identifier>
6571                 </xsl:for-each>
6572         </xsl:template>
6573         <xsl:template name="relatedIdentifier">
6574                 <xsl:for-each select="marc:subfield[@code='o']">
6575                         <identifier>
6576                                 <xsl:value-of select="."/>
6577                         </identifier>
6578                 </xsl:for-each>
6579         </xsl:template>
6580         <xsl:template name="relatedItem76X-78X">
6581                 <xsl:call-template name="displayLabel"/>
6582                 <xsl:call-template name="relatedTitle76X-78X"/>
6583                 <xsl:call-template name="relatedName"/>
6584                 <xsl:call-template name="relatedOriginInfo"/>
6585                 <xsl:call-template name="relatedLanguage"/>
6586                 <xsl:call-template name="relatedExtent"/>
6587                 <xsl:call-template name="relatedNote"/>
6588                 <xsl:call-template name="relatedSubject"/>
6589                 <xsl:call-template name="relatedIdentifier"/>
6590                 <xsl:call-template name="relatedIdentifierISSN"/>
6591                 <xsl:call-template name="relatedIdentifierLocal"/>
6592                 <xsl:call-template name="relatedPart"/>
6593         </xsl:template>
6594         <xsl:template name="subjectGeographicZ">
6595                 <geographic>
6596                         <xsl:call-template name="chopPunctuation">
6597                                 <xsl:with-param name="chopString" select="."/>
6598                         </xsl:call-template>
6599                 </geographic>
6600         </xsl:template>
6601         <xsl:template name="subjectTemporalY">
6602                 <temporal>
6603                         <xsl:call-template name="chopPunctuation">
6604                                 <xsl:with-param name="chopString" select="."/>
6605                         </xsl:call-template>
6606                 </temporal>
6607         </xsl:template>
6608         <xsl:template name="subjectTopic">
6609                 <topic>
6610                         <xsl:call-template name="chopPunctuation">
6611                                 <xsl:with-param name="chopString" select="."/>
6612                         </xsl:call-template>
6613                 </topic>
6614         </xsl:template>
6615         <!-- 3.2 change tmee 6xx $v genre -->
6616         <xsl:template name="subjectGenre">
6617                 <genre>
6618                         <xsl:call-template name="chopPunctuation">
6619                                 <xsl:with-param name="chopString" select="."/>
6620                         </xsl:call-template>
6621                 </genre>
6622         </xsl:template>
6623
6624         <xsl:template name="nameABCDN">
6625                 <xsl:for-each select="marc:subfield[@code='a']">
6626                         <namePart>
6627                                 <xsl:call-template name="chopPunctuation">
6628                                         <xsl:with-param name="chopString" select="."/>
6629                                 </xsl:call-template>
6630                         </namePart>
6631                 </xsl:for-each>
6632                 <xsl:for-each select="marc:subfield[@code='b']">
6633                         <namePart>
6634                                 <xsl:value-of select="."/>
6635                         </namePart>
6636                 </xsl:for-each>
6637                 <xsl:if
6638                         test="marc:subfield[@code='c'] or marc:subfield[@code='d'] or marc:subfield[@code='n']">
6639                         <namePart>
6640                                 <xsl:call-template name="subfieldSelect">
6641                                         <xsl:with-param name="codes">cdn</xsl:with-param>
6642                                 </xsl:call-template>
6643                         </namePart>
6644                 </xsl:if>
6645         </xsl:template>
6646         <xsl:template name="nameABCDQ">
6647                 <namePart>
6648                         <xsl:call-template name="chopPunctuation">
6649                                 <xsl:with-param name="chopString">
6650                                         <xsl:call-template name="subfieldSelect">
6651                                                 <xsl:with-param name="codes">aq</xsl:with-param>
6652                                         </xsl:call-template>
6653                                 </xsl:with-param>
6654                                 <xsl:with-param name="punctuation">
6655                                         <xsl:text>:,;/ </xsl:text>
6656                                 </xsl:with-param>
6657                         </xsl:call-template>
6658                 </namePart>
6659                 <xsl:call-template name="termsOfAddress"/>
6660                 <xsl:call-template name="nameDate"/>
6661         </xsl:template>
6662         <xsl:template name="nameACDEQ">
6663                 <namePart>
6664                         <xsl:call-template name="subfieldSelect">
6665                                 <xsl:with-param name="codes">acdeq</xsl:with-param>
6666                         </xsl:call-template>
6667                 </namePart>
6668         </xsl:template>
6669         <xsl:template name="constituentOrRelatedType">
6670                 <xsl:if test="@ind2=2">
6671                         <xsl:attribute name="type">constituent</xsl:attribute>
6672                 </xsl:if>
6673         </xsl:template>
6674         <xsl:template name="relatedTitle">
6675                 <xsl:for-each select="marc:subfield[@code='t']">
6676                         <titleInfo>
6677                                 <title>
6678                                         <xsl:call-template name="chopPunctuation">
6679                                                 <xsl:with-param name="chopString">
6680                                                         <xsl:value-of select="."/>
6681                                                 </xsl:with-param>
6682                                         </xsl:call-template>
6683                                 </title>
6684                         </titleInfo>
6685                 </xsl:for-each>
6686         </xsl:template>
6687         <xsl:template name="relatedTitle76X-78X">
6688                 <xsl:for-each select="marc:subfield[@code='t']">
6689                         <titleInfo>
6690                                 <title>
6691                                         <xsl:call-template name="chopPunctuation">
6692                                                 <xsl:with-param name="chopString">
6693                                                         <xsl:value-of select="."/>
6694                                                 </xsl:with-param>
6695                                         </xsl:call-template>
6696                                 </title>
6697                                 <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
6698                                         <xsl:call-template name="relatedPartNumName"/>
6699                                 </xsl:if>
6700                         </titleInfo>
6701                 </xsl:for-each>
6702                 <xsl:for-each select="marc:subfield[@code='p']">
6703                         <titleInfo type="abbreviated">
6704                                 <title>
6705                                         <xsl:call-template name="chopPunctuation">
6706                                                 <xsl:with-param name="chopString">
6707                                                         <xsl:value-of select="."/>
6708                                                 </xsl:with-param>
6709                                         </xsl:call-template>
6710                                 </title>
6711                                 <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
6712                                         <xsl:call-template name="relatedPartNumName"/>
6713                                 </xsl:if>
6714                         </titleInfo>
6715                 </xsl:for-each>
6716                 <xsl:for-each select="marc:subfield[@code='s']">
6717                         <titleInfo type="uniform">
6718                                 <title>
6719                                         <xsl:call-template name="chopPunctuation">
6720                                                 <xsl:with-param name="chopString">
6721                                                         <xsl:value-of select="."/>
6722                                                 </xsl:with-param>
6723                                         </xsl:call-template>
6724                                 </title>
6725                                 <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
6726                                         <xsl:call-template name="relatedPartNumName"/>
6727                                 </xsl:if>
6728                         </titleInfo>
6729                 </xsl:for-each>
6730         </xsl:template>
6731         <xsl:template name="relatedOriginInfo">
6732                 <xsl:if test="marc:subfield[@code='b' or @code='d'] or marc:subfield[@code='f']">
6733                         <originInfo>
6734                                 <xsl:if test="@tag=775">
6735                                         <xsl:for-each select="marc:subfield[@code='f']">
6736                                                 <place>
6737                                                         <placeTerm>
6738                                                                 <xsl:attribute name="type">code</xsl:attribute>
6739                                                                 <xsl:attribute name="authority">marcgac</xsl:attribute>
6740                                                                 <xsl:value-of select="."/>
6741                                                         </placeTerm>
6742                                                 </place>
6743                                         </xsl:for-each>
6744                                 </xsl:if>
6745                                 <xsl:for-each select="marc:subfield[@code='d']">
6746                                         <publisher>
6747                                                 <xsl:value-of select="."/>
6748                                         </publisher>
6749                                 </xsl:for-each>
6750                                 <xsl:for-each select="marc:subfield[@code='b']">
6751                                         <edition>
6752                                                 <xsl:value-of select="."/>
6753                                         </edition>
6754                                 </xsl:for-each>
6755                         </originInfo>
6756                 </xsl:if>
6757         </xsl:template>
6758         <xsl:template name="relatedLanguage">
6759                 <xsl:for-each select="marc:subfield[@code='e']">
6760                         <xsl:call-template name="getLanguage">
6761                                 <xsl:with-param name="langString">
6762                                         <xsl:value-of select="."/>
6763                                 </xsl:with-param>
6764                         </xsl:call-template>
6765                 </xsl:for-each>
6766         </xsl:template>
6767         <xsl:template name="nameDate">
6768                 <xsl:for-each select="marc:subfield[@code='d']">
6769                         <namePart type="date">
6770                                 <xsl:call-template name="chopPunctuation">
6771                                         <xsl:with-param name="chopString" select="."/>
6772                                 </xsl:call-template>
6773                         </namePart>
6774                 </xsl:for-each>
6775         </xsl:template>
6776         <xsl:template name="subjectAuthority">
6777                 <xsl:if test="@ind2!=4">
6778                         <xsl:if test="@ind2!=' '">
6779                                 <xsl:if test="@ind2!=8">
6780                                         <xsl:if test="@ind2!=9">
6781                                                 <xsl:attribute name="authority">
6782                                                         <xsl:choose>
6783                                                                 <xsl:when test="@ind2=0">lcsh</xsl:when>
6784                                                                 <xsl:when test="@ind2=1">lcshac</xsl:when>
6785                                                                 <xsl:when test="@ind2=2">mesh</xsl:when>
6786                                                                 <!-- 1/04 fix -->
6787                                                                 <xsl:when test="@ind2=3">nal</xsl:when>
6788                                                                 <xsl:when test="@ind2=5">csh</xsl:when>
6789                                                                 <xsl:when test="@ind2=6">rvm</xsl:when>
6790                                                                 <xsl:when test="@ind2=7">
6791                                                                         <xsl:value-of select="marc:subfield[@code='2']"/>
6792                                                                 </xsl:when>
6793                                                         </xsl:choose>
6794                                                 </xsl:attribute>
6795                                         </xsl:if>
6796                                 </xsl:if>
6797                         </xsl:if>
6798                 </xsl:if>
6799         </xsl:template>
6800         <xsl:template name="subjectAnyOrder">
6801                 <xsl:for-each select="marc:subfield[@code='v' or @code='x' or @code='y' or @code='z']">
6802                         <xsl:choose>
6803                                 <xsl:when test="@code='v'">
6804                                         <xsl:call-template name="subjectGenre"/>
6805                                 </xsl:when>
6806                                 <xsl:when test="@code='x'">
6807                                         <xsl:call-template name="subjectTopic"/>
6808                                 </xsl:when>
6809                                 <xsl:when test="@code='y'">
6810                                         <xsl:call-template name="subjectTemporalY"/>
6811                                 </xsl:when>
6812                                 <xsl:when test="@code='z'">
6813                                         <xsl:call-template name="subjectGeographicZ"/>
6814                                 </xsl:when>
6815                         </xsl:choose>
6816                 </xsl:for-each>
6817         </xsl:template>
6818         <xsl:template name="specialSubfieldSelect">
6819                 <xsl:param name="anyCodes"/>
6820                 <xsl:param name="axis"/>
6821                 <xsl:param name="beforeCodes"/>
6822                 <xsl:param name="afterCodes"/>
6823                 <xsl:variable name="str">
6824                         <xsl:for-each select="marc:subfield">
6825                                 <xsl:if
6826                                         test="contains($anyCodes, @code)      or (contains($beforeCodes,@code) and following-sibling::marc:subfield[@code=$axis])      or (contains($afterCodes,@code) and preceding-sibling::marc:subfield[@code=$axis])">
6827                                         <xsl:value-of select="text()"/>
6828                                         <xsl:text> </xsl:text>
6829                                 </xsl:if>
6830                         </xsl:for-each>
6831                 </xsl:variable>
6832                 <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
6833         </xsl:template>
6834
6835         <!-- 3.2 change tmee 6xx $v genre -->
6836         <xsl:template match="marc:datafield[@tag=600]">
6837                 <subject>
6838                         <xsl:call-template name="subjectAuthority"/>
6839                         <name type="personal">
6840                                 <xsl:call-template name="termsOfAddress"/>
6841                                 <namePart>
6842                                         <xsl:call-template name="chopPunctuation">
6843                                                 <xsl:with-param name="chopString">
6844                                                         <xsl:call-template name="subfieldSelect">
6845                                                                 <xsl:with-param name="codes">aq</xsl:with-param>
6846                                                         </xsl:call-template>
6847                                                 </xsl:with-param>
6848                                         </xsl:call-template>
6849                                 </namePart>
6850                                 <xsl:call-template name="nameDate"/>
6851                                 <xsl:call-template name="affiliation"/>
6852                                 <xsl:call-template name="role"/>
6853                         </name>
6854                         <xsl:call-template name="subjectAnyOrder"/>
6855                 </subject>
6856         </xsl:template>
6857         <xsl:template match="marc:datafield[@tag=610]">
6858                 <subject>
6859                         <xsl:call-template name="subjectAuthority"/>
6860                         <name type="corporate">
6861                                 <xsl:for-each select="marc:subfield[@code='a']">
6862                                         <namePart>
6863                                                 <xsl:value-of select="."/>
6864                                         </namePart>
6865                                 </xsl:for-each>
6866                                 <xsl:for-each select="marc:subfield[@code='b']">
6867                                         <namePart>
6868                                                 <xsl:value-of select="."/>
6869                                         </namePart>
6870                                 </xsl:for-each>
6871                                 <xsl:if test="marc:subfield[@code='c' or @code='d' or @code='n' or @code='p']">
6872                                         <namePart>
6873                                                 <xsl:call-template name="subfieldSelect">
6874                                                         <xsl:with-param name="codes">cdnp</xsl:with-param>
6875                                                 </xsl:call-template>
6876                                         </namePart>
6877                                 </xsl:if>
6878                                 <xsl:call-template name="role"/>
6879                         </name>
6880                         <xsl:call-template name="subjectAnyOrder"/>
6881                 </subject>
6882         </xsl:template>
6883         <xsl:template match="marc:datafield[@tag=611]">
6884                 <subject>
6885                         <xsl:call-template name="subjectAuthority"/>
6886                         <name type="conference">
6887                                 <namePart>
6888                                         <xsl:call-template name="subfieldSelect">
6889                                                 <xsl:with-param name="codes">abcdeqnp</xsl:with-param>
6890                                         </xsl:call-template>
6891                                 </namePart>
6892                                 <xsl:for-each select="marc:subfield[@code='4']">
6893                                         <role>
6894                                                 <roleTerm authority="marcrelator" type="code">
6895                                                         <xsl:value-of select="."/>
6896                                                 </roleTerm>
6897                                         </role>
6898                                 </xsl:for-each>
6899                         </name>
6900                         <xsl:call-template name="subjectAnyOrder"/>
6901                 </subject>
6902         </xsl:template>
6903         <xsl:template match="marc:datafield[@tag=630]">
6904                 <subject>
6905                         <xsl:call-template name="subjectAuthority"/>
6906                         <titleInfo>
6907                                 <title>
6908                                         <xsl:call-template name="chopPunctuation">
6909                                                 <xsl:with-param name="chopString">
6910                                                         <xsl:call-template name="subfieldSelect">
6911                                                                 <xsl:with-param name="codes">adfhklor</xsl:with-param>
6912                                                         </xsl:call-template>
6913                                                 </xsl:with-param>
6914                                         </xsl:call-template>
6915                                 </title>
6916                                 <xsl:call-template name="part"/>
6917                         </titleInfo>
6918                         <xsl:call-template name="subjectAnyOrder"/>
6919                 </subject>
6920         </xsl:template>
6921         <!-- 1.27 648 tmee-->
6922         <xsl:template match="marc:datafield[@tag=648]">
6923                 <subject>
6924                         <xsl:if test="marc:subfield[@code=2]">
6925                                 <xsl:attribute name="authority">
6926                                         <xsl:value-of select="marc:subfield[@code=2]"/>
6927                                 </xsl:attribute>
6928                         </xsl:if>
6929                         <xsl:call-template name="uri"/>
6930
6931                         <xsl:call-template name="subjectAuthority"/>
6932                         <temporal>
6933                                 <xsl:call-template name="chopPunctuation">
6934                                         <xsl:with-param name="chopString">
6935                                                 <xsl:call-template name="subfieldSelect">
6936                                                         <xsl:with-param name="codes">abcd</xsl:with-param>
6937                                                 </xsl:call-template>
6938                                         </xsl:with-param>
6939                                 </xsl:call-template>
6940                         </temporal>
6941                         <xsl:call-template name="subjectAnyOrder"/>
6942
6943                 </subject>
6944         </xsl:template>
6945         <xsl:template match="marc:datafield[@tag=650]">
6946                 <subject>
6947                         <xsl:call-template name="subjectAuthority"/>
6948                         <topic>
6949                                 <xsl:call-template name="chopPunctuation">
6950                                         <xsl:with-param name="chopString">
6951                                                 <xsl:call-template name="subfieldSelect">
6952                                                         <xsl:with-param name="codes">abcd</xsl:with-param>
6953                                                 </xsl:call-template>
6954                                         </xsl:with-param>
6955                                 </xsl:call-template>
6956                         </topic>
6957                         <xsl:call-template name="subjectAnyOrder"/>
6958                 </subject>
6959         </xsl:template>
6960         <xsl:template match="marc:datafield[@tag=651]">
6961                 <subject>
6962                         <xsl:call-template name="subjectAuthority"/>
6963                         <xsl:for-each select="marc:subfield[@code='a']">
6964                                 <geographic>
6965                                         <xsl:call-template name="chopPunctuation">
6966                                                 <xsl:with-param name="chopString" select="."/>
6967                                         </xsl:call-template>
6968                                 </geographic>
6969                         </xsl:for-each>
6970                         <xsl:call-template name="subjectAnyOrder"/>
6971                 </subject>
6972         </xsl:template>
6973         <xsl:template match="marc:datafield[@tag=653]">
6974                 <subject>
6975                         <xsl:for-each select="marc:subfield[@code='a']">
6976                                 <topic>
6977                                         <xsl:value-of select="."/>
6978                                 </topic>
6979                         </xsl:for-each>
6980                 </subject>
6981         </xsl:template>
6982         <xsl:template match="marc:datafield[@tag=656]">
6983                 <subject>
6984                         <xsl:if test="marc:subfield[@code=2]">
6985                                 <xsl:attribute name="authority">
6986                                         <xsl:value-of select="marc:subfield[@code=2]"/>
6987                                 </xsl:attribute>
6988                         </xsl:if>
6989                         <occupation>
6990                                 <xsl:call-template name="chopPunctuation">
6991                                         <xsl:with-param name="chopString">
6992                                                 <xsl:value-of select="marc:subfield[@code='a']"/>
6993                                         </xsl:with-param>
6994                                 </xsl:call-template>
6995                         </occupation>
6996                 </subject>
6997         </xsl:template>
6998         <xsl:template name="termsOfAddress">
6999                 <xsl:if test="marc:subfield[@code='b' or @code='c']">
7000                         <namePart type="termsOfAddress">
7001                                 <xsl:call-template name="chopPunctuation">
7002                                         <xsl:with-param name="chopString">
7003                                                 <xsl:call-template name="subfieldSelect">
7004                                                         <xsl:with-param name="codes">bc</xsl:with-param>
7005                                                 </xsl:call-template>
7006                                         </xsl:with-param>
7007                                 </xsl:call-template>
7008                         </namePart>
7009                 </xsl:if>
7010         </xsl:template>
7011         <xsl:template name="displayLabel">
7012                 <xsl:if test="marc:subfield[@code='i']">
7013                         <xsl:attribute name="displayLabel">
7014                                 <xsl:value-of select="marc:subfield[@code='i']"/>
7015                         </xsl:attribute>
7016                 </xsl:if>
7017                 <xsl:if test="marc:subfield[@code='3']">
7018                         <xsl:attribute name="displayLabel">
7019                                 <xsl:value-of select="marc:subfield[@code='3']"/>
7020                         </xsl:attribute>
7021                 </xsl:if>
7022         </xsl:template>
7023         <xsl:template name="isInvalid">
7024                 <xsl:param name="type"/>
7025                 <xsl:if
7026                         test="marc:subfield[@code='z'] or marc:subfield[@code='y']  or marc:subfield[@code='m']">
7027                         <identifier>
7028                                 <xsl:attribute name="type">
7029                                         <xsl:value-of select="$type"/>
7030                                 </xsl:attribute>
7031                                 <xsl:attribute name="invalid">
7032                                         <xsl:text>yes</xsl:text>
7033                                 </xsl:attribute>
7034                                 <xsl:if test="marc:subfield[@code='z']">
7035                                         <xsl:value-of select="marc:subfield[@code='z']"/>
7036                                 </xsl:if>
7037                                 <xsl:if test="marc:subfield[@code='y']">
7038                                         <xsl:value-of select="marc:subfield[@code='y']"/>
7039                                 </xsl:if>
7040                                 <xsl:if test="marc:subfield[@code='m']">
7041                                         <xsl:value-of select="marc:subfield[@code='m']"/>
7042                                 </xsl:if>
7043                         </identifier>
7044                 </xsl:if>
7045         </xsl:template>
7046         <xsl:template name="subtitle">
7047                 <xsl:if test="marc:subfield[@code='b']">
7048                         <subTitle>
7049                                 <xsl:call-template name="chopPunctuation">
7050                                         <xsl:with-param name="chopString">
7051                                                 <xsl:value-of select="marc:subfield[@code='b']"/>
7052                                                 <!--<xsl:call-template name="subfieldSelect">
7053                                                         <xsl:with-param name="codes">b</xsl:with-param>                                                                 
7054                                                 </xsl:call-template>-->
7055                                         </xsl:with-param>
7056                                 </xsl:call-template>
7057                         </subTitle>
7058                 </xsl:if>
7059         </xsl:template>
7060         <xsl:template name="script">
7061                 <xsl:param name="scriptCode"/>
7062                 <xsl:attribute name="script">
7063                         <xsl:choose>
7064                                 <xsl:when test="$scriptCode='(3'">Arabic</xsl:when>
7065                                 <xsl:when test="$scriptCode='(B'">Latin</xsl:when>
7066                                 <xsl:when test="$scriptCode='$1'">Chinese, Japanese, Korean</xsl:when>
7067                                 <xsl:when test="$scriptCode='(N'">Cyrillic</xsl:when>
7068                                 <xsl:when test="$scriptCode='(2'">Hebrew</xsl:when>
7069                                 <xsl:when test="$scriptCode='(S'">Greek</xsl:when>
7070                         </xsl:choose>
7071                 </xsl:attribute>
7072         </xsl:template>
7073         <xsl:template name="parsePart">
7074                 <!-- assumes 773$q= 1:2:3<4
7075                      with up to 3 levels and one optional start page
7076                 -->
7077                 <xsl:variable name="level1">
7078                         <xsl:choose>
7079                                 <xsl:when test="contains(text(),':')">
7080                                         <!-- 1:2 -->
7081                                         <xsl:value-of select="substring-before(text(),':')"/>
7082                                 </xsl:when>
7083                                 <xsl:when test="not(contains(text(),':'))">
7084                                         <!-- 1 or 1<3 -->
7085                                         <xsl:if test="contains(text(),'&lt;')">
7086                                                 <!-- 1<3 -->
7087                                                 <xsl:value-of select="substring-before(text(),'&lt;')"/>
7088                                         </xsl:if>
7089                                         <xsl:if test="not(contains(text(),'&lt;'))">
7090                                                 <!-- 1 -->
7091                                                 <xsl:value-of select="text()"/>
7092                                         </xsl:if>
7093                                 </xsl:when>
7094                         </xsl:choose>
7095                 </xsl:variable>
7096                 <xsl:variable name="sici2">
7097                         <xsl:choose>
7098                                 <xsl:when test="starts-with(substring-after(text(),$level1),':')">
7099                                         <xsl:value-of select="substring(substring-after(text(),$level1),2)"/>
7100                                 </xsl:when>
7101                                 <xsl:otherwise>
7102                                         <xsl:value-of select="substring-after(text(),$level1)"/>
7103                                 </xsl:otherwise>
7104                         </xsl:choose>
7105                 </xsl:variable>
7106                 <xsl:variable name="level2">
7107                         <xsl:choose>
7108                                 <xsl:when test="contains($sici2,':')">
7109                                         <!--  2:3<4  -->
7110                                         <xsl:value-of select="substring-before($sici2,':')"/>
7111                                 </xsl:when>
7112                                 <xsl:when test="contains($sici2,'&lt;')">
7113                                         <!-- 1: 2<4 -->
7114                                         <xsl:value-of select="substring-before($sici2,'&lt;')"/>
7115                                 </xsl:when>
7116                                 <xsl:otherwise>
7117                                         <xsl:value-of select="$sici2"/>
7118                                         <!-- 1:2 -->
7119                                 </xsl:otherwise>
7120                         </xsl:choose>
7121                 </xsl:variable>
7122                 <xsl:variable name="sici3">
7123                         <xsl:choose>
7124                                 <xsl:when test="starts-with(substring-after($sici2,$level2),':')">
7125                                         <xsl:value-of select="substring(substring-after($sici2,$level2),2)"/>
7126                                 </xsl:when>
7127                                 <xsl:otherwise>
7128                                         <xsl:value-of select="substring-after($sici2,$level2)"/>
7129                                 </xsl:otherwise>
7130                         </xsl:choose>
7131                 </xsl:variable>
7132                 <xsl:variable name="level3">
7133                         <xsl:choose>
7134                                 <xsl:when test="contains($sici3,'&lt;')">
7135                                         <!-- 2<4 -->
7136                                         <xsl:value-of select="substring-before($sici3,'&lt;')"/>
7137                                 </xsl:when>
7138                                 <xsl:otherwise>
7139                                         <xsl:value-of select="$sici3"/>
7140                                         <!-- 3 -->
7141                                 </xsl:otherwise>
7142                         </xsl:choose>
7143                 </xsl:variable>
7144                 <xsl:variable name="page">
7145                         <xsl:if test="contains(text(),'&lt;')">
7146                                 <xsl:value-of select="substring-after(text(),'&lt;')"/>
7147                         </xsl:if>
7148                 </xsl:variable>
7149                 <xsl:if test="$level1">
7150                         <detail level="1">
7151                                 <number>
7152                                         <xsl:value-of select="$level1"/>
7153                                 </number>
7154                         </detail>
7155                 </xsl:if>
7156                 <xsl:if test="$level2">
7157                         <detail level="2">
7158                                 <number>
7159                                         <xsl:value-of select="$level2"/>
7160                                 </number>
7161                         </detail>
7162                 </xsl:if>
7163                 <xsl:if test="$level3">
7164                         <detail level="3">
7165                                 <number>
7166                                         <xsl:value-of select="$level3"/>
7167                                 </number>
7168                         </detail>
7169                 </xsl:if>
7170                 <xsl:if test="$page">
7171                         <extent unit="page">
7172                                 <start>
7173                                         <xsl:value-of select="$page"/>
7174                                 </start>
7175                         </extent>
7176                 </xsl:if>
7177         </xsl:template>
7178         <xsl:template name="getLanguage">
7179                 <xsl:param name="langString"/>
7180                 <xsl:param name="controlField008-35-37"/>
7181                 <xsl:variable name="length" select="string-length($langString)"/>
7182                 <xsl:choose>
7183                         <xsl:when test="$length=0"/>
7184                         <xsl:when test="$controlField008-35-37=substring($langString,1,3)">
7185                                 <xsl:call-template name="getLanguage">
7186                                         <xsl:with-param name="langString" select="substring($langString,4,$length)"/>
7187                                         <xsl:with-param name="controlField008-35-37" select="$controlField008-35-37"/>
7188                                 </xsl:call-template>
7189                         </xsl:when>
7190                         <xsl:otherwise>
7191                                 <language>
7192                                         <languageTerm authority="iso639-2b" type="code">
7193                                                 <xsl:value-of select="substring($langString,1,3)"/>
7194                                         </languageTerm>
7195                                 </language>
7196                                 <xsl:call-template name="getLanguage">
7197                                         <xsl:with-param name="langString" select="substring($langString,4,$length)"/>
7198                                         <xsl:with-param name="controlField008-35-37" select="$controlField008-35-37"/>
7199                                 </xsl:call-template>
7200                         </xsl:otherwise>
7201                 </xsl:choose>
7202         </xsl:template>
7203         <xsl:template name="isoLanguage">
7204                 <xsl:param name="currentLanguage"/>
7205                 <xsl:param name="usedLanguages"/>
7206                 <xsl:param name="remainingLanguages"/>
7207                 <xsl:choose>
7208                         <xsl:when test="string-length($currentLanguage)=0"/>
7209                         <xsl:when test="not(contains($usedLanguages, $currentLanguage))">
7210                                 <language>
7211                                         <xsl:if test="@code!='a'">
7212                                                 <xsl:attribute name="objectPart">
7213                                                         <xsl:choose>
7214                                                                 <xsl:when test="@code='b'">summary or subtitle</xsl:when>
7215                                                                 <xsl:when test="@code='d'">sung or spoken text</xsl:when>
7216                                                                 <xsl:when test="@code='e'">libretto</xsl:when>
7217                                                                 <xsl:when test="@code='f'">table of contents</xsl:when>
7218                                                                 <xsl:when test="@code='g'">accompanying material</xsl:when>
7219                                                                 <xsl:when test="@code='h'">translation</xsl:when>
7220                                                         </xsl:choose>
7221                                                 </xsl:attribute>
7222                                         </xsl:if>
7223                                         <languageTerm authority="iso639-2b" type="code">
7224                                                 <xsl:value-of select="$currentLanguage"/>
7225                                         </languageTerm>
7226                                 </language>
7227                                 <xsl:call-template name="isoLanguage">
7228                                         <xsl:with-param name="currentLanguage">
7229                                                 <xsl:value-of select="substring($remainingLanguages,1,3)"/>
7230                                         </xsl:with-param>
7231                                         <xsl:with-param name="usedLanguages">
7232                                                 <xsl:value-of select="concat($usedLanguages,$currentLanguage)"/>
7233                                         </xsl:with-param>
7234                                         <xsl:with-param name="remainingLanguages">
7235                                                 <xsl:value-of
7236                                                         select="substring($remainingLanguages,4,string-length($remainingLanguages))"
7237                                                 />
7238                                         </xsl:with-param>
7239                                 </xsl:call-template>
7240                         </xsl:when>
7241                         <xsl:otherwise>
7242                                 <xsl:call-template name="isoLanguage">
7243                                         <xsl:with-param name="currentLanguage">
7244                                                 <xsl:value-of select="substring($remainingLanguages,1,3)"/>
7245                                         </xsl:with-param>
7246                                         <xsl:with-param name="usedLanguages">
7247                                                 <xsl:value-of select="concat($usedLanguages,$currentLanguage)"/>
7248                                         </xsl:with-param>
7249                                         <xsl:with-param name="remainingLanguages">
7250                                                 <xsl:value-of
7251                                                         select="substring($remainingLanguages,4,string-length($remainingLanguages))"
7252                                                 />
7253                                         </xsl:with-param>
7254                                 </xsl:call-template>
7255                         </xsl:otherwise>
7256                 </xsl:choose>
7257         </xsl:template>
7258         <xsl:template name="chopBrackets">
7259                 <xsl:param name="chopString"/>
7260                 <xsl:variable name="string">
7261                         <xsl:call-template name="chopPunctuation">
7262                                 <xsl:with-param name="chopString" select="$chopString"/>
7263                         </xsl:call-template>
7264                 </xsl:variable>
7265                 <xsl:if test="substring($string, 1,1)='['">
7266                         <xsl:value-of select="substring($string,2, string-length($string)-2)"/>
7267                 </xsl:if>
7268                 <xsl:if test="substring($string, 1,1)!='['">
7269                         <xsl:value-of select="$string"/>
7270                 </xsl:if>
7271         </xsl:template>
7272         <xsl:template name="rfcLanguages">
7273                 <xsl:param name="nodeNum"/>
7274                 <xsl:param name="usedLanguages"/>
7275                 <xsl:param name="controlField008-35-37"/>
7276                 <xsl:variable name="currentLanguage" select="."/>
7277                 <xsl:choose>
7278                         <xsl:when test="not($currentLanguage)"/>
7279                         <xsl:when
7280                                 test="$currentLanguage!=$controlField008-35-37 and $currentLanguage!='rfc3066'">
7281                                 <xsl:if test="not(contains($usedLanguages,$currentLanguage))">
7282                                         <language>
7283                                                 <xsl:if test="@code!='a'">
7284                                                         <xsl:attribute name="objectPart">
7285                                                                 <xsl:choose>
7286                                                                         <xsl:when test="@code='b'">summary or subtitle</xsl:when>
7287                                                                         <xsl:when test="@code='d'">sung or spoken text</xsl:when>
7288                                                                         <xsl:when test="@code='e'">libretto</xsl:when>
7289                                                                         <xsl:when test="@code='f'">table of contents</xsl:when>
7290                                                                         <xsl:when test="@code='g'">accompanying material</xsl:when>
7291                                                                         <xsl:when test="@code='h'">translation</xsl:when>
7292                                                                 </xsl:choose>
7293                                                         </xsl:attribute>
7294                                                 </xsl:if>
7295                                                 <languageTerm authority="rfc3066" type="code">
7296                                                         <xsl:value-of select="$currentLanguage"/>
7297                                                 </languageTerm>
7298                                         </language>
7299                                 </xsl:if>
7300                         </xsl:when>
7301                         <xsl:otherwise> </xsl:otherwise>
7302                 </xsl:choose>
7303         </xsl:template>
7304
7305     <xsl:template name="datafield">
7306                 <xsl:param name="tag"/>
7307                 <xsl:param name="ind1">
7308                         <xsl:text> </xsl:text>
7309                 </xsl:param>
7310                 <xsl:param name="ind2">
7311                         <xsl:text> </xsl:text>
7312                 </xsl:param>
7313                 <xsl:param name="subfields"/>
7314                 <xsl:element name="marc:datafield">
7315                         <xsl:attribute name="tag">
7316                                 <xsl:value-of select="$tag"/>
7317                         </xsl:attribute>
7318                         <xsl:attribute name="ind1">
7319                                 <xsl:value-of select="$ind1"/>
7320                         </xsl:attribute>
7321                         <xsl:attribute name="ind2">
7322                                 <xsl:value-of select="$ind2"/>
7323                         </xsl:attribute>
7324                         <xsl:copy-of select="$subfields"/>
7325                 </xsl:element>
7326         </xsl:template>
7327
7328         <xsl:template name="subfieldSelect">
7329                 <xsl:param name="codes">abcdefghijklmnopqrstuvwxyz</xsl:param>
7330                 <xsl:param name="delimeter">
7331                         <xsl:text> </xsl:text>
7332                 </xsl:param>
7333                 <xsl:variable name="str">
7334                         <xsl:for-each select="marc:subfield">
7335                                 <xsl:if test="contains($codes, @code)">
7336                                         <xsl:value-of select="text()"/>
7337                                         <xsl:value-of select="$delimeter"/>
7338                                 </xsl:if>
7339                         </xsl:for-each>
7340                 </xsl:variable>
7341                 <xsl:value-of select="substring($str,1,string-length($str)-string-length($delimeter))"/>
7342         </xsl:template>
7343
7344         <xsl:template name="buildSpaces">
7345                 <xsl:param name="spaces"/>
7346                 <xsl:param name="char">
7347                         <xsl:text> </xsl:text>
7348                 </xsl:param>
7349                 <xsl:if test="$spaces>0">
7350                         <xsl:value-of select="$char"/>
7351                         <xsl:call-template name="buildSpaces">
7352                                 <xsl:with-param name="spaces" select="$spaces - 1"/>
7353                                 <xsl:with-param name="char" select="$char"/>
7354                         </xsl:call-template>
7355                 </xsl:if>
7356         </xsl:template>
7357
7358         <xsl:template name="chopPunctuation">
7359                 <xsl:param name="chopString"/>
7360                 <xsl:param name="punctuation">
7361                         <xsl:text>.:,;/ </xsl:text>
7362                 </xsl:param>
7363                 <xsl:variable name="length" select="string-length($chopString)"/>
7364                 <xsl:choose>
7365                         <xsl:when test="$length=0"/>
7366                         <xsl:when test="contains($punctuation, substring($chopString,$length,1))">
7367                                 <xsl:call-template name="chopPunctuation">
7368                                         <xsl:with-param name="chopString" select="substring($chopString,1,$length - 1)"/>
7369                                         <xsl:with-param name="punctuation" select="$punctuation"/>
7370                                 </xsl:call-template>
7371                         </xsl:when>
7372                         <xsl:when test="not($chopString)"/>
7373                         <xsl:otherwise>
7374                                 <xsl:value-of select="$chopString"/>
7375                         </xsl:otherwise>
7376                 </xsl:choose>
7377         </xsl:template>
7378
7379         <xsl:template name="chopPunctuationFront">
7380                 <xsl:param name="chopString"/>
7381                 <xsl:variable name="length" select="string-length($chopString)"/>
7382                 <xsl:choose>
7383                         <xsl:when test="$length=0"/>
7384                         <xsl:when test="contains('.:,;/[ ', substring($chopString,1,1))">
7385                                 <xsl:call-template name="chopPunctuationFront">
7386                                         <xsl:with-param name="chopString" select="substring($chopString,2,$length - 1)"
7387                                         />
7388                                 </xsl:call-template>
7389                         </xsl:when>
7390                         <xsl:when test="not($chopString)"/>
7391                         <xsl:otherwise>
7392                                 <xsl:value-of select="$chopString"/>
7393                         </xsl:otherwise>
7394                 </xsl:choose>
7395         </xsl:template>
7396
7397         <xsl:template name="chopPunctuationBack">
7398                 <xsl:param name="chopString"/>
7399                 <xsl:param name="punctuation">
7400                         <xsl:text>.:,;/] </xsl:text>
7401                 </xsl:param>
7402                 <xsl:variable name="length" select="string-length($chopString)"/>
7403                 <xsl:choose>
7404                         <xsl:when test="$length=0"/>
7405                         <xsl:when test="contains($punctuation, substring($chopString,$length,1))">
7406                                 <xsl:call-template name="chopPunctuation">
7407                                         <xsl:with-param name="chopString" select="substring($chopString,1,$length - 1)"/>
7408                                         <xsl:with-param name="punctuation" select="$punctuation"/>
7409                                 </xsl:call-template>
7410                         </xsl:when>
7411                         <xsl:when test="not($chopString)"/>
7412                         <xsl:otherwise>
7413                                 <xsl:value-of select="$chopString"/>
7414                         </xsl:otherwise>
7415                 </xsl:choose>
7416         </xsl:template>
7417
7418         <!-- nate added 12/14/2007 for lccn.loc.gov: url encode ampersand, etc. -->
7419         <xsl:template name="url-encode">
7420
7421                 <xsl:param name="str"/>
7422
7423                 <xsl:if test="$str">
7424                         <xsl:variable name="first-char" select="substring($str,1,1)"/>
7425                         <xsl:choose>
7426                                 <xsl:when test="contains($safe,$first-char)">
7427                                         <xsl:value-of select="$first-char"/>
7428                                 </xsl:when>
7429                                 <xsl:otherwise>
7430                                         <xsl:variable name="codepoint">
7431                                                 <xsl:choose>
7432                                                         <xsl:when test="contains($ascii,$first-char)">
7433                                                                 <xsl:value-of
7434                                                                         select="string-length(substring-before($ascii,$first-char)) + 32"
7435                                                                 />
7436                                                         </xsl:when>
7437                                                         <xsl:when test="contains($latin1,$first-char)">
7438                                                                 <xsl:value-of
7439                                                                         select="string-length(substring-before($latin1,$first-char)) + 160"/>
7440                                                                 <!-- was 160 -->
7441                                                         </xsl:when>
7442                                                         <xsl:otherwise>
7443                                                                 <xsl:message terminate="no">Warning: string contains a character
7444                                                                         that is out of range! Substituting "?".</xsl:message>
7445                                                                 <xsl:text>63</xsl:text>
7446                                                         </xsl:otherwise>
7447                                                 </xsl:choose>
7448                                         </xsl:variable>
7449                                         <xsl:variable name="hex-digit1"
7450                                                 select="substring($hex,floor($codepoint div 16) + 1,1)"/>
7451                                         <xsl:variable name="hex-digit2" select="substring($hex,$codepoint mod 16 + 1,1)"/>
7452                                         <!-- <xsl:value-of select="concat('%',$hex-digit2)"/> -->
7453                                         <xsl:value-of select="concat('%',$hex-digit1,$hex-digit2)"/>
7454                                 </xsl:otherwise>
7455                         </xsl:choose>
7456                         <xsl:if test="string-length($str) &gt; 1">
7457                                 <xsl:call-template name="url-encode">
7458                                         <xsl:with-param name="str" select="substring($str,2)"/>
7459                                 </xsl:call-template>
7460                         </xsl:if>
7461                 </xsl:if>
7462         </xsl:template>
7463 </xsl:stylesheet>$$ WHERE name = 'mods33';
7464
7465 ALTER TABLE actor.usr ALTER COLUMN juvenile SET NOT NULL;
7466 ALTER TABLE actor.usr_address ALTER COLUMN pending SET NOT NULL;
7467 ALTER TABLE config.circ_matrix_matchpoint ALTER COLUMN duration_rule SET NOT NULL;
7468 ALTER TABLE config.circ_matrix_matchpoint ALTER COLUMN recurring_fine_rule SET NOT NULL;
7469 ALTER TABLE config.circ_matrix_matchpoint ALTER COLUMN max_fine_rule SET NOT NULL;
7470