From: Jason Boyer Date: Thu, 25 Sep 2014 14:53:11 +0000 (-0400) Subject: LP#121054: Add Deleted Flag to asset.copy_location X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=f0a598ea0974c0db5b2f358910100b25b9418840;p=evergreen%2Fmasslnc.git LP#121054: Add Deleted Flag to asset.copy_location Signed-off-by: Jason Boyer Signed-off-by: Michele Morgan Signed-off-by: Kathy Lussier Signed-off-by: Ben Shum --- diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml index c7f05e407f..18ccb4b3c4 100644 --- a/Open-ILS/examples/fm_IDL.xml +++ b/Open-ILS/examples/fm_IDL.xml @@ -4494,6 +4494,7 @@ SELECT usr, + diff --git a/Open-ILS/src/extras/ils_events.xml b/Open-ILS/src/extras/ils_events.xml index 80892ad5cf..63385f3f82 100644 --- a/Open-ILS/src/extras/ils_events.xml +++ b/Open-ILS/src/extras/ils_events.xml @@ -712,6 +712,12 @@ The copy location object already exists + + The copy location is not empty + + + The copy location does not exist + There is an open circulation on the requested item diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Order.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Order.pm index 69ecdf6421..6883a0d61d 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Order.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Order.pm @@ -1700,7 +1700,7 @@ sub extract_lineitem_detail_data { my $org = $cp_base_org; while ($org) { $loc = $mgr->editor->search_asset_copy_location( - {owning_lib => $org, name => $name}, {idlist => 1})->[0]; + {owning_lib => $org, name => $name, deleted => 'f'}, {idlist => 1})->[0]; last if $loc; $org = $mgr->editor->retrieve_actor_org_unit($org)->parent_ou; } diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm index c8ae3c21fc..09c30ee570 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm @@ -640,7 +640,7 @@ sub fetch_copy_locations { my $self = shift; return $self->simplereq( 'open-ils.cstore', - 'open-ils.cstore.direct.asset.copy_location.search.atomic', { id => { '!=' => undef } }); + 'open-ils.cstore.direct.asset.copy_location.search.atomic', { id => { '!=' => undef }, deleted => 'f' }); } sub fetch_copy_location_by_name { @@ -648,7 +648,7 @@ sub fetch_copy_location_by_name { my $evt; my $cl = $self->cstorereq( 'open-ils.cstore.direct.asset.copy_location.search', - { name => $name, owning_lib => $org } ); + { name => $name, owning_lib => $org, deleted => 'f' } ); $evt = OpenILS::Event->new('ASSET_COPY_LOCATION_NOT_FOUND') unless $cl; return ($cl, $evt); } diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat/AssetCommon.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat/AssetCommon.pm index 869894f205..07357ea70f 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat/AssetCommon.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat/AssetCommon.pm @@ -55,6 +55,11 @@ sub create_copy { return OpenILS::Event->new('ITEM_BARCODE_EXISTS') if @$existing; + my $copy_loc = $editor->search_asset_copy_location( + { id => $copy->location, deleted => 'f' } ); + + return OpenILS::Event->new('COPY_LOCATION_NOT_FOUND') unless @$copy_loc; + # see if the volume this copy references is marked as deleted return OpenILS::Event->new('VOLUME_DELETED', vol => $vol->id) if $U->is_true($vol->deleted); @@ -198,6 +203,12 @@ sub update_copy { $override = { all => 1 } if($override && !ref $override); $override = { all => 0 } if(!ref $override); + # Duplicated check from create_copy in case a copy template with a deleted location is applied later + my $copy_loc = $editor->search_asset_copy_location( + { id => $copy->location, deleted => 'f' } ); + + return OpenILS::Event->new('COPY_LOCATION_NOT_FOUND') unless @$copy_loc; + my $evt; my $org = (ref $copy->circ_lib) ? $copy->circ_lib->id : $copy->circ_lib; return $evt if ( $evt = $class->org_cannot_have_vols($editor, $org) ); diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/CopyLocations.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/CopyLocations.pm index a72e13c482..23061ca748 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/CopyLocations.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/CopyLocations.pm @@ -40,7 +40,8 @@ sub cl_retrieve_all { } return new_editor()->search_asset_copy_location([{ - owning_lib => $U->get_org_full_path($org_id) + owning_lib => $U->get_org_full_path($org_id), + deleted => "f" }, $second_cstore_arg]); } @@ -60,7 +61,8 @@ sub cl_retrieve_distinct { "select" => { "acpl" => [{"transform" => "distinct", "column" => "name"}] }, - "from" => {"acpl" => {}} + "from" => {"acpl" => {}}, + "where" => {"deleted" => "f"} }) or return $e->die_event; $e->disconnect; @@ -91,7 +93,7 @@ sub cl_create { # make sure there is no copy_location with the same name in the same place my $existing = $e->search_asset_copy_location( - {owning_lib => $location->owning_lib, name => $location->name}, {idlist=>1}); + {owning_lib => $location->owning_lib, name => $location->name, deleted => "f"}, {idlist=>1}); return OpenILS::Event->new('COPY_LOCATION_EXISTS') if @$existing; $e->create_asset_copy_location($location) or return $e->die_event; @@ -120,6 +122,9 @@ sub cl_delete { my $e = new_editor(authtoken=>$auth, xact=>1); return $e->die_event unless $e->checkauth; + my $cps = $e->search_asset_copy({location=>$id, deleted=>'f'}); + return OpenILS::Event->new('COPY_LOCATION_NOT_EMPTY', payload=>$id) if @$cps; + my $cloc = $e->retrieve_asset_copy_location($id) or return $e->die_event; return $e->die_event unless diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm index 22c0966966..5c8449363e 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm @@ -2719,7 +2719,7 @@ sub rec_to_mr_rec_descriptors { deleted => 'f' }, "+ccs" => { holdable => 't' }, - "+acpl" => { holdable => 't' } + "+acpl" => { holdable => 't', deleted => 'f' } } }; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/asset.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/asset.pm index 30109dbf27..b9f6354de7 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/asset.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/asset.pm @@ -10,7 +10,7 @@ use base qw/asset/; __PACKAGE__->table( 'asset_copy_location' ); __PACKAGE__->columns( Primary => qw/id/ ); -__PACKAGE__->columns( Essential => qw/name owning_lib holdable hold_verify opac_visible circulate label_prefix label_suffix checkin_alert/ ); +__PACKAGE__->columns( Essential => qw/name owning_lib holdable hold_verify opac_visible circulate label_prefix label_suffix checkin_alert deleted/ ); #------------------------------------------------------------------------------- package asset::copy_location_order; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/asset.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/asset.pm index 435f104f1d..f5e3279a3b 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/asset.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/asset.pm @@ -409,6 +409,7 @@ sub asset_copy_location_all { my $client = shift; for my $rec ( asset::copy_location->retrieve_all ) { + next if $rec->deleted eq "t"; $client->respond( $rec->to_fieldmapper ); } @@ -439,6 +440,7 @@ sub ranged_asset_copy_location { FROM $ctable c JOIN $descendants d ON (d.id = c.owning_lib) + WHERE deleted IS FALSE ORDER BY name SQL diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/biblio.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/biblio.pm index 8d8648d52e..c2854897b0 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/biblio.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/biblio.pm @@ -48,7 +48,8 @@ sub record_copy_count { WHERE cn.record = ? $visible AND cn.deleted IS FALSE - AND cp.deleted IS FALSE) + AND cp.deleted IS FALSE + AND loc.deleted IS FALSE) ) AS count, sum( (SELECT count(cp.id) @@ -61,6 +62,7 @@ sub record_copy_count { $visible AND cn.deleted IS FALSE AND cp.deleted IS FALSE + AND loc.deleted IS FALSE AND cp.status IN (0,7,12)) ) AS available, sum( @@ -74,7 +76,8 @@ sub record_copy_count { AND loc.opac_visible = TRUE AND cp.opac_visible = TRUE AND cn.deleted IS FALSE - AND cp.deleted IS FALSE) + AND cp.deleted IS FALSE + AND loc.deleted IS FALSE) ) AS unshadow, sum( (SELECT sum(1) @@ -411,6 +414,7 @@ sub record_copy_status_count { AND cl.opac_visible IS TRUE AND cp.opac_visible IS TRUE AND cp.deleted IS FALSE + AND cl.deleted IS FALSE AND cs.opac_visible IS TRUE GROUP BY 1,2,3,4,5; SQL @@ -490,6 +494,7 @@ sub record_copy_status_location_count { AND cl.opac_visible IS TRUE AND cp.opac_visible IS TRUE AND cp.deleted IS FALSE + AND cl.deleted IS FALSE AND cs.opac_visible IS TRUE GROUP BY 1,2,3,4,5,6; SQL diff --git a/Open-ILS/src/sql/Pg/040.schema.asset.sql b/Open-ILS/src/sql/Pg/040.schema.asset.sql index e7b1daa944..4375013400 100644 --- a/Open-ILS/src/sql/Pg/040.schema.asset.sql +++ b/Open-ILS/src/sql/Pg/040.schema.asset.sql @@ -32,8 +32,9 @@ CREATE TABLE asset.copy_location ( label_prefix TEXT, label_suffix TEXT, checkin_alert BOOL NOT NULL DEFAULT FALSE, - CONSTRAINT acl_name_once_per_lib UNIQUE (name, owning_lib) + deleted BOOL NOT NULL DEFAULT FALSE ); +CREATE UNIQUE INDEX acl_name_once_per_lib ON asset.copy_location (name, owning_lib) WHERE deleted = FALSE OR deleted IS FALSE; CREATE TABLE asset.copy_location_order ( @@ -67,7 +68,6 @@ CREATE TABLE asset.copy_location_group_map ( CONSTRAINT lgroup_once_per_group UNIQUE (lgroup,location) ); - CREATE TABLE asset.copy ( id BIGSERIAL PRIMARY KEY, circ_lib INT NOT NULL REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED, @@ -179,9 +179,9 @@ BEGIN RETURN NEW; END IF; END IF; - SELECT INTO new_copy_location acpl.id FROM asset.copy_location acpl JOIN actor.org_unit_ancestors_distance((SELECT owning_lib FROM asset.call_number WHERE id = NEW.call_number)) aouad ON acpl.owning_lib = aouad.id WHERE name = (SELECT name FROM asset.copy_location WHERE id = NEW.location) ORDER BY distance LIMIT 1; + SELECT INTO new_copy_location acpl.id FROM asset.copy_location acpl JOIN actor.org_unit_ancestors_distance((SELECT owning_lib FROM asset.call_number WHERE id = NEW.call_number)) aouad ON acpl.owning_lib = aouad.id WHERE deleted IS FALSE AND name = (SELECT name FROM asset.copy_location WHERE id = NEW.location) ORDER BY distance LIMIT 1; IF new_copy_location IS NULL THEN - SELECT INTO new_copy_location acpl.id FROM asset.copy_location acpl JOIN actor.org_unit_ancestors_distance(NEW.circ_lib) aouad ON acpl.owning_lib = aouad.id WHERE name = (SELECT name FROM asset.copy_location WHERE id = NEW.location) ORDER BY distance LIMIT 1; + SELECT INTO new_copy_location acpl.id FROM asset.copy_location acpl JOIN actor.org_unit_ancestors_distance(NEW.circ_lib) aouad ON acpl.owning_lib = aouad.id WHERE deleted IS FALSE AND name = (SELECT name FROM asset.copy_location WHERE id = NEW.location) ORDER BY distance LIMIT 1; END IF; IF new_copy_location IS NOT NULL THEN NEW.location = new_copy_location; @@ -615,7 +615,7 @@ BEGIN FROM actor.org_unit_descendants(ans.id) d JOIN asset.copy cp ON (cp.circ_lib = d.id AND NOT cp.deleted) - JOIN asset.copy_location cl ON (cp.location = cl.id) + JOIN asset.copy_location cl ON (cp.location = cl.id AND NOT cl.deleted) JOIN asset.call_number cn ON (cn.record = rid AND cn.id = cp.call_number AND NOT cn.deleted) GROUP BY 1,2,6; @@ -647,7 +647,7 @@ BEGIN FROM actor.org_unit_descendants(ans.id) d JOIN asset.copy cp ON (cp.circ_lib = d.id AND NOT cp.deleted) - JOIN asset.copy_location cl ON (cp.location = cl.id) + JOIN asset.copy_location cl ON (cp.location = cl.id AND NOT cl.deleted) JOIN asset.call_number cn ON (cn.record = rid AND cn.id = cp.call_number AND NOT cn.deleted) GROUP BY 1,2,6; @@ -695,6 +695,7 @@ BEGIN AND acpl.holdable = true AND ccs.holdable = true AND acp.deleted = false + AND acpl.deleted = false AND acp.circ_lib IN (SELECT id FROM actor.org_unit_descendants(COALESCE($2,(SELECT id FROM evergreen.org_top())))) LIMIT 1; IF FOUND THEN @@ -867,6 +868,7 @@ BEGIN AND acpl.holdable = true AND ccs.holdable = true AND acp.deleted = false + AND acpl.deleted = false AND acp.circ_lib IN (SELECT id FROM actor.org_unit_descendants(COALESCE($2,(SELECT id FROM evergreen.org_top())))) LIMIT 1; IF FOUND THEN diff --git a/Open-ILS/src/sql/Pg/800.fkeys.sql b/Open-ILS/src/sql/Pg/800.fkeys.sql index ee9886d8f4..009b915960 100644 --- a/Open-ILS/src/sql/Pg/800.fkeys.sql +++ b/Open-ILS/src/sql/Pg/800.fkeys.sql @@ -26,6 +26,15 @@ CREATE RULE protect_bib_rec_delete AS WHERE OLD.id = biblio.record_entry.id ); +CREATE RULE protect_copy_location_delete AS + ON DELETE TO asset.copy_location DO INSTEAD ( + UPDATE asset.copy_location SET deleted = TRUE WHERE OLD.id = asset.copy_location.id; + UPDATE acq.lineitem_detail SET location = NULL WHERE location = OLD.id; + DELETE FROM asset.copy_location_order WHERE location = OLD.id; + DELETE FROM asset.copy_location_group_map WHERE location = OLD.id; + DELETE FROM config.circ_limit_set_copy_loc_map WHERE copy_loc = OLD.id; + ); + ALTER TABLE actor.usr ADD CONSTRAINT actor_usr_mailing_address_fkey FOREIGN KEY (mailing_address) REFERENCES actor.usr_address (id) DEFERRABLE INITIALLY DEFERRED; ALTER TABLE actor.usr ADD CONSTRAINT actor_usr_billing_address_fkey FOREIGN KEY (billing_address) REFERENCES actor.usr_address (id) DEFERRABLE INITIALLY DEFERRED; ALTER TABLE actor.usr ADD CONSTRAINT actor_usr_home_ou_fkey FOREIGN KEY (home_ou) REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED; diff --git a/Open-ILS/src/sql/Pg/999.functions.global.sql b/Open-ILS/src/sql/Pg/999.functions.global.sql index d724afca65..bb87a6b1fb 100644 --- a/Open-ILS/src/sql/Pg/999.functions.global.sql +++ b/Open-ILS/src/sql/Pg/999.functions.global.sql @@ -1229,6 +1229,7 @@ CREATE OR REPLACE FUNCTION asset.refresh_opac_visible_copies_mat_view () RETURNS JOIN config.copy_status cs ON (cp.status = cs.id) JOIN biblio.record_entry b ON (cn.record = b.id) WHERE NOT cp.deleted + AND NOT cl.deleted AND NOT cn.deleted AND NOT b.deleted AND cs.opac_visible @@ -1243,6 +1244,7 @@ CREATE OR REPLACE FUNCTION asset.refresh_opac_visible_copies_mat_view () RETURNS JOIN asset.copy_location cl ON (cp.location = cl.id) JOIN config.copy_status cs ON (cp.status = cs.id) WHERE NOT cp.deleted + AND NOT cl.deleted AND cs.opac_visible AND cl.opac_visible AND cp.opac_visible @@ -1272,6 +1274,7 @@ BEGIN JOIN config.copy_status cs ON (cp.status = cs.id) JOIN biblio.record_entry b ON (cn.record = b.id) WHERE NOT cp.deleted + AND NOT cl.deleted AND NOT cn.deleted AND NOT b.deleted AND cs.opac_visible @@ -1287,6 +1290,7 @@ BEGIN JOIN asset.copy_location cl ON (cp.location = cl.id) JOIN config.copy_status cs ON (cp.status = cs.id) WHERE NOT cp.deleted + AND NOT cl.deleted AND cs.opac_visible AND cl.opac_visible AND cp.opac_visible @@ -1372,7 +1376,7 @@ BEGIN END IF; - IF TG_TABLE_NAME IN ('call_number', 'record_entry') THEN -- these have a 'deleted' column + IF TG_TABLE_NAME IN ('call_number', 'copy_location', 'record_entry') THEN -- these have a 'deleted' column IF OLD.deleted AND NEW.deleted THEN -- do nothing @@ -1382,6 +1386,8 @@ BEGIN IF TG_TABLE_NAME = 'call_number' THEN DELETE FROM asset.opac_visible_copies WHERE copy_id IN (SELECT id FROM asset.copy WHERE call_number = NEW.id); + ELSIF TG_TABLE_NAME = 'copy_location' THEN + DELETE FROM asset.opac_visible_copies WHERE copy_id IN (SELECT id FROM asset.copy WHERE location = NEW.id); ELSIF TG_TABLE_NAME = 'record_entry' THEN DELETE FROM asset.opac_visible_copies WHERE record = NEW.id; END IF; @@ -1393,6 +1399,9 @@ BEGIN IF TG_TABLE_NAME = 'call_number' THEN add_base_query := add_base_query || ' AND cn.id = ' || NEW.id; EXECUTE add_front || add_base_query || add_back; + ELSIF TG_TABLE_NAME = 'copy_location' THEN + add_base_query := add_base_query || 'AND cl.id = ' || NEW.id; + EXECUTE add_front || add_base_query || add_back; ELSIF TG_TABLE_NAME = 'record_entry' THEN add_base_query := add_base_query || ' AND cn.record = ' || NEW.id; add_peer_query := add_peer_query || ' AND pbcm.peer_record = ' || NEW.id; @@ -2017,7 +2026,8 @@ BEGIN ); -- make sure the value from the org setting is still valid - PERFORM 1 FROM asset.copy_location WHERE id = attr_set.location; + PERFORM 1 FROM asset.copy_location + WHERE id = attr_set.location AND NOT deleted; IF NOT FOUND THEN attr_set.import_error := 'import.item.invalid.location'; attr_set.error_detail := tmp_attr_set.cs; @@ -2043,7 +2053,8 @@ BEGIN ) SELECT cpl.id INTO attr_set.location FROM anscestor_depth a JOIN asset.copy_location cpl ON (cpl.owning_lib = a.id) - WHERE LOWER(cpl.name) = LOWER(tmp_attr_set.cl) + WHERE LOWER(cpl.name) = LOWER(tmp_attr_set.cl) + AND NOT cpl.deleted ORDER BY a.depth DESC LIMIT 1; diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.asset.copy_location-delete-rule.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.asset.copy_location-delete-rule.sql new file mode 100644 index 0000000000..16cc585663 --- /dev/null +++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.asset.copy_location-delete-rule.sql @@ -0,0 +1,811 @@ +BEGIN; + +SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version); + +ALTER TABLE asset.copy_location ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE; + +CREATE OR REPLACE RULE protect_copy_location_delete AS + ON DELETE TO asset.copy_location DO INSTEAD ( + UPDATE asset.copy_location SET deleted = TRUE WHERE OLD.id = asset.copy_location.id; + UPDATE acq.lineitem_detail SET location = NULL WHERE location = OLD.id; + DELETE FROM asset.copy_location_order WHERE location = OLD.id; + DELETE FROM asset.copy_location_group_map WHERE location = OLD.id; + DELETE FROM config.circ_limit_set_copy_loc_map WHERE copy_loc = OLD.id; + ); + +ALTER TABLE asset.copy_location DROP CONSTRAINT acl_name_once_per_lib; +CREATE UNIQUE INDEX acl_name_once_per_lib ON asset.copy_location (name, owning_lib) WHERE deleted = FALSE OR deleted IS FALSE; + +CREATE OR REPLACE FUNCTION asset.acp_location_fixer() +RETURNS TRIGGER AS $$ +DECLARE + new_copy_location INT; +BEGIN + IF (TG_OP = 'UPDATE') THEN + IF NEW.location = OLD.location AND NEW.call_number = OLD.call_number AND NEW.circ_lib = OLD.circ_lib THEN + RETURN NEW; + END IF; + END IF; + SELECT INTO new_copy_location acpl.id FROM asset.copy_location acpl JOIN actor.org_unit_ancestors_distance((SELECT owning_lib FROM asset.call_number WHERE id = NEW.call_number)) aouad ON acpl.owning_lib = aouad.id WHERE deleted IS FALSE AND name = (SELECT name FROM asset.copy_location WHERE id = NEW.location) ORDER BY distance LIMIT 1; + IF new_copy_location IS NULL THEN + SELECT INTO new_copy_location acpl.id FROM asset.copy_location acpl JOIN actor.org_unit_ancestors_distance(NEW.circ_lib) aouad ON acpl.owning_lib = aouad.id WHERE deleted IS FALSE AND name = (SELECT name FROM asset.copy_location WHERE id = NEW.location) ORDER BY distance LIMIT 1; + END IF; + IF new_copy_location IS NOT NULL THEN + NEW.location = new_copy_location; + END IF; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION asset.staff_ou_record_copy_count (org INT, rid BIGINT) RETURNS TABLE (depth INT, org_unit INT, visible BIGINT, available BIGINT, unshadow BIGINT, transcendant INT) AS $f$ +DECLARE + ans RECORD; + trans INT; +BEGIN + SELECT 1 INTO trans FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) WHERE src.transcendant AND b.id = rid; + + FOR ans IN SELECT u.id, t.depth FROM actor.org_unit_ancestors(org) AS u JOIN actor.org_unit_type t ON (u.ou_type = t.id) LOOP + RETURN QUERY + SELECT ans.depth, + ans.id, + COUNT( cp.id ), + SUM( CASE WHEN cp.status IN (0,7,12) THEN 1 ELSE 0 END ), + SUM( CASE WHEN cl.opac_visible AND cp.opac_visible THEN 1 ELSE 0 END), + trans + FROM + actor.org_unit_descendants(ans.id) d + JOIN asset.copy cp ON (cp.circ_lib = d.id AND NOT cp.deleted) + JOIN asset.copy_location cl ON (cp.location = cl.id AND NOT cl.deleted) + JOIN asset.call_number cn ON (cn.record = rid AND cn.id = cp.call_number AND NOT cn.deleted) + GROUP BY 1,2,6; + + IF NOT FOUND THEN + RETURN QUERY SELECT ans.depth, ans.id, 0::BIGINT, 0::BIGINT, 0::BIGINT, trans; + END IF; + + END LOOP; + + RETURN; +END; +$f$ LANGUAGE PLPGSQL; + +CREATE OR REPLACE FUNCTION asset.staff_lasso_record_copy_count (i_lasso INT, rid BIGINT) RETURNS TABLE (depth INT, org_unit INT, visible BIGINT, available BIGINT, unshadow BIGINT, transcendant INT) AS $f$ +DECLARE + ans RECORD; + trans INT; +BEGIN + SELECT 1 INTO trans FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) WHERE src.transcendant AND b.id = rid; + + FOR ans IN SELECT u.org_unit AS id FROM actor.org_lasso_map AS u WHERE lasso = i_lasso LOOP + RETURN QUERY + SELECT -1, + ans.id, + COUNT( cp.id ), + SUM( CASE WHEN cp.status IN (0,7,12) THEN 1 ELSE 0 END ), + SUM( CASE WHEN cl.opac_visible AND cp.opac_visible THEN 1 ELSE 0 END), + trans + FROM + actor.org_unit_descendants(ans.id) d + JOIN asset.copy cp ON (cp.circ_lib = d.id AND NOT cp.deleted) + JOIN asset.copy_location cl ON (cp.location = cl.id AND NOT cl.deleted) + JOIN asset.call_number cn ON (cn.record = rid AND cn.id = cp.call_number AND NOT cn.deleted) + GROUP BY 1,2,6; + + IF NOT FOUND THEN + RETURN QUERY SELECT -1, ans.id, 0::BIGINT, 0::BIGINT, 0::BIGINT, trans; + END IF; + + END LOOP; + + RETURN; +END; +$f$ LANGUAGE PLPGSQL; + +CREATE OR REPLACE FUNCTION asset.record_has_holdable_copy ( rid BIGINT, ou INT DEFAULT NULL) RETURNS BOOL AS $f$ +BEGIN + PERFORM 1 + FROM + asset.copy acp + JOIN asset.call_number acn ON acp.call_number = acn.id + JOIN asset.copy_location acpl ON acp.location = acpl.id + JOIN config.copy_status ccs ON acp.status = ccs.id + WHERE + acn.record = rid + AND acp.holdable = true + AND acpl.holdable = true + AND ccs.holdable = true + AND acp.deleted = false + AND acpl.deleted = false + AND acp.circ_lib IN (SELECT id FROM actor.org_unit_descendants(COALESCE($2,(SELECT id FROM evergreen.org_top())))) + LIMIT 1; + IF FOUND THEN + RETURN true; + END IF; + RETURN FALSE; +END; +$f$ LANGUAGE PLPGSQL; + +CREATE OR REPLACE FUNCTION asset.metarecord_has_holdable_copy ( rid BIGINT, ou INT DEFAULT NULL) RETURNS BOOL AS $f$ +BEGIN + PERFORM 1 + FROM + asset.copy acp + JOIN asset.call_number acn ON acp.call_number = acn.id + JOIN asset.copy_location acpl ON acp.location = acpl.id + JOIN config.copy_status ccs ON acp.status = ccs.id + JOIN metabib.metarecord_source_map mmsm ON acn.record = mmsm.source + WHERE + mmsm.metarecord = rid + AND acp.holdable = true + AND acpl.holdable = true + AND ccs.holdable = true + AND acp.deleted = false + AND acpl.deleted = false + AND acp.circ_lib IN (SELECT id FROM actor.org_unit_descendants(COALESCE($2,(SELECT id FROM evergreen.org_top())))) + LIMIT 1; + IF FOUND THEN + RETURN true; + END IF; + RETURN FALSE; +END; +$f$ LANGUAGE PLPGSQL; + +CREATE OR REPLACE FUNCTION asset.refresh_opac_visible_copies_mat_view () RETURNS VOID AS $$ + + TRUNCATE TABLE asset.opac_visible_copies; + + INSERT INTO asset.opac_visible_copies (copy_id, circ_lib, record) + SELECT cp.id, cp.circ_lib, cn.record + FROM asset.copy cp + JOIN asset.call_number cn ON (cn.id = cp.call_number) + JOIN actor.org_unit a ON (cp.circ_lib = a.id) + JOIN asset.copy_location cl ON (cp.location = cl.id) + JOIN config.copy_status cs ON (cp.status = cs.id) + JOIN biblio.record_entry b ON (cn.record = b.id) + WHERE NOT cp.deleted + AND NOT cl.deleted + AND NOT cn.deleted + AND NOT b.deleted + AND cs.opac_visible + AND cl.opac_visible + AND cp.opac_visible + AND a.opac_visible + UNION + SELECT cp.id, cp.circ_lib, pbcm.peer_record AS record + FROM asset.copy cp + JOIN biblio.peer_bib_copy_map pbcm ON (pbcm.target_copy = cp.id) + JOIN actor.org_unit a ON (cp.circ_lib = a.id) + JOIN asset.copy_location cl ON (cp.location = cl.id) + JOIN config.copy_status cs ON (cp.status = cs.id) + WHERE NOT cp.deleted + AND NOT cl.deleted + AND cs.opac_visible + AND cl.opac_visible + AND cp.opac_visible + AND a.opac_visible; + +$$ LANGUAGE SQL; + +CREATE OR REPLACE FUNCTION asset.cache_copy_visibility () RETURNS TRIGGER as $func$ +DECLARE + add_front TEXT; + add_back TEXT; + add_base_query TEXT; + add_peer_query TEXT; + remove_query TEXT; + do_add BOOLEAN := false; + do_remove BOOLEAN := false; +BEGIN + add_base_query := $$ + SELECT cp.id, cp.circ_lib, cn.record, cn.id AS call_number, cp.location, cp.status + FROM asset.copy cp + JOIN asset.call_number cn ON (cn.id = cp.call_number) + JOIN actor.org_unit a ON (cp.circ_lib = a.id) + JOIN asset.copy_location cl ON (cp.location = cl.id) + JOIN config.copy_status cs ON (cp.status = cs.id) + JOIN biblio.record_entry b ON (cn.record = b.id) + WHERE NOT cp.deleted + AND NOT cl.deleted + AND NOT cn.deleted + AND NOT b.deleted + AND cs.opac_visible + AND cl.opac_visible + AND cp.opac_visible + AND a.opac_visible + $$; + add_peer_query := $$ + SELECT cp.id, cp.circ_lib, pbcm.peer_record AS record, NULL AS call_number, cp.location, cp.status + FROM asset.copy cp + JOIN biblio.peer_bib_copy_map pbcm ON (pbcm.target_copy = cp.id) + JOIN actor.org_unit a ON (cp.circ_lib = a.id) + JOIN asset.copy_location cl ON (cp.location = cl.id) + JOIN config.copy_status cs ON (cp.status = cs.id) + WHERE NOT cp.deleted + AND NOT cl.deleted + AND cs.opac_visible + AND cl.opac_visible + AND cp.opac_visible + AND a.opac_visible + $$; + add_front := $$ + INSERT INTO asset.opac_visible_copies (copy_id, circ_lib, record) + SELECT DISTINCT ON (id, record) id, circ_lib, record FROM ( + $$; + add_back := $$ + ) AS x + $$; + + remove_query := $$ DELETE FROM asset.opac_visible_copies WHERE copy_id IN ( SELECT id FROM asset.copy WHERE $$; + + IF TG_TABLE_NAME = 'peer_bib_copy_map' THEN + IF TG_OP = 'INSERT' THEN + add_peer_query := add_peer_query || ' AND cp.id = ' || NEW.target_copy || ' AND pbcm.peer_record = ' || NEW.peer_record; + EXECUTE add_front || add_peer_query || add_back; + RETURN NEW; + ELSE + remove_query := 'DELETE FROM asset.opac_visible_copies WHERE copy_id = ' || OLD.target_copy || ' AND record = ' || OLD.peer_record || ';'; + EXECUTE remove_query; + RETURN OLD; + END IF; + END IF; + + IF TG_OP = 'INSERT' THEN + + IF TG_TABLE_NAME IN ('copy', 'unit') THEN + add_base_query := add_base_query || ' AND cp.id = ' || NEW.id; + EXECUTE add_front || add_base_query || add_back; + END IF; + + RETURN NEW; + + END IF; + + -- handle items first, since with circulation activity + -- their statuses change frequently + IF TG_TABLE_NAME IN ('copy', 'unit') THEN + + IF OLD.location <> NEW.location OR + OLD.call_number <> NEW.call_number OR + OLD.status <> NEW.status OR + OLD.circ_lib <> NEW.circ_lib THEN + -- any of these could change visibility, but + -- we'll save some queries and not try to calculate + -- the change directly + do_remove := true; + do_add := true; + ELSE + + IF OLD.deleted <> NEW.deleted THEN + IF NEW.deleted THEN + do_remove := true; + ELSE + do_add := true; + END IF; + END IF; + + IF OLD.opac_visible <> NEW.opac_visible THEN + IF OLD.opac_visible THEN + do_remove := true; + ELSIF NOT do_remove THEN -- handle edge case where deleted item + -- is also marked opac_visible + do_add := true; + END IF; + END IF; + + END IF; + + IF do_remove THEN + DELETE FROM asset.opac_visible_copies WHERE copy_id = NEW.id; + END IF; + IF do_add THEN + add_base_query := add_base_query || ' AND cp.id = ' || NEW.id; + add_peer_query := add_peer_query || ' AND cp.id = ' || NEW.id; + EXECUTE add_front || add_base_query || ' UNION ' || add_peer_query || add_back; + END IF; + + RETURN NEW; + + END IF; + + IF TG_TABLE_NAME IN ('call_number', 'copy_location', 'record_entry') THEN -- these have a 'deleted' column + + IF OLD.deleted AND NEW.deleted THEN -- do nothing + + RETURN NEW; + + ELSIF NEW.deleted THEN -- remove rows + + IF TG_TABLE_NAME = 'call_number' THEN + DELETE FROM asset.opac_visible_copies WHERE copy_id IN (SELECT id FROM asset.copy WHERE call_number = NEW.id); + ELSIF TG_TABLE_NAME = 'copy_location' THEN + DELETE FROM asset.opac_visible_copies WHERE copy_id IN (SELECT id FROM asset.copy WHERE location = NEW.id); + ELSIF TG_TABLE_NAME = 'record_entry' THEN + DELETE FROM asset.opac_visible_copies WHERE record = NEW.id; + END IF; + + RETURN NEW; + + ELSIF OLD.deleted THEN -- add rows + + IF TG_TABLE_NAME = 'call_number' THEN + add_base_query := add_base_query || ' AND cn.id = ' || NEW.id; + EXECUTE add_front || add_base_query || add_back; + ELSIF TG_TABLE_NAME = 'copy_location' THEN + add_base_query := add_base_query || 'AND cl.id = ' || NEW.id; + EXECUTE add_front || add_base_query || add_back; + ELSIF TG_TABLE_NAME = 'record_entry' THEN + add_base_query := add_base_query || ' AND cn.record = ' || NEW.id; + add_peer_query := add_peer_query || ' AND pbcm.peer_record = ' || NEW.id; + EXECUTE add_front || add_base_query || ' UNION ' || add_peer_query || add_back; + END IF; + + RETURN NEW; + + END IF; + + END IF; + + IF TG_TABLE_NAME = 'call_number' THEN + + IF OLD.record <> NEW.record THEN + -- call number is linked to different bib + remove_query := remove_query || 'call_number = ' || NEW.id || ');'; + EXECUTE remove_query; + add_base_query := add_base_query || ' AND cn.id = ' || NEW.id; + EXECUTE add_front || add_base_query || add_back; + END IF; + + RETURN NEW; + + END IF; + + IF TG_TABLE_NAME IN ('record_entry') THEN + RETURN NEW; -- don't have 'opac_visible' + END IF; + + -- actor.org_unit, asset.copy_location, asset.copy_status + IF NEW.opac_visible = OLD.opac_visible THEN -- do nothing + + RETURN NEW; + + ELSIF NEW.opac_visible THEN -- add rows + + IF TG_TABLE_NAME = 'org_unit' THEN + add_base_query := add_base_query || ' AND cp.circ_lib = ' || NEW.id; + add_peer_query := add_peer_query || ' AND cp.circ_lib = ' || NEW.id; + ELSIF TG_TABLE_NAME = 'copy_location' THEN + add_base_query := add_base_query || ' AND cp.location = ' || NEW.id; + add_peer_query := add_peer_query || ' AND cp.location = ' || NEW.id; + ELSIF TG_TABLE_NAME = 'copy_status' THEN + add_base_query := add_base_query || ' AND cp.status = ' || NEW.id; + add_peer_query := add_peer_query || ' AND cp.status = ' || NEW.id; + END IF; + + EXECUTE add_front || add_base_query || ' UNION ' || add_peer_query || add_back; + + ELSE -- delete rows + + IF TG_TABLE_NAME = 'org_unit' THEN + remove_query := 'DELETE FROM asset.opac_visible_copies WHERE circ_lib = ' || NEW.id || ';'; + ELSIF TG_TABLE_NAME = 'copy_location' THEN + remove_query := remove_query || 'location = ' || NEW.id || ');'; + ELSIF TG_TABLE_NAME = 'copy_status' THEN + remove_query := remove_query || 'status = ' || NEW.id || ');'; + END IF; + + EXECUTE remove_query; + + END IF; + + RETURN NEW; +END; +$func$ LANGUAGE PLPGSQL; + +-- updated copy location validity test to disallow deleted locations +CREATE OR REPLACE FUNCTION vandelay.ingest_items ( import_id BIGINT, attr_def_id BIGINT ) RETURNS SETOF vandelay.import_item AS $$ +DECLARE + + owning_lib TEXT; + circ_lib TEXT; + call_number TEXT; + copy_number TEXT; + status TEXT; + location TEXT; + circulate TEXT; + deposit TEXT; + deposit_amount TEXT; + ref TEXT; + holdable TEXT; + price TEXT; + barcode TEXT; + circ_modifier TEXT; + circ_as_type TEXT; + alert_message TEXT; + opac_visible TEXT; + pub_note TEXT; + priv_note TEXT; + internal_id TEXT; + + attr_def RECORD; + tmp_attr_set RECORD; + attr_set vandelay.import_item%ROWTYPE; + + xpath TEXT; + tmp_str TEXT; + +BEGIN + + SELECT * INTO attr_def FROM vandelay.import_item_attr_definition WHERE id = attr_def_id; + + IF FOUND THEN + + attr_set.definition := attr_def.id; + + -- Build the combined XPath + + owning_lib := + CASE + WHEN attr_def.owning_lib IS NULL THEN 'null()' + WHEN LENGTH( attr_def.owning_lib ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.owning_lib || '"]' + ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.owning_lib + END; + + circ_lib := + CASE + WHEN attr_def.circ_lib IS NULL THEN 'null()' + WHEN LENGTH( attr_def.circ_lib ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circ_lib || '"]' + ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circ_lib + END; + + call_number := + CASE + WHEN attr_def.call_number IS NULL THEN 'null()' + WHEN LENGTH( attr_def.call_number ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.call_number || '"]' + ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.call_number + END; + + copy_number := + CASE + WHEN attr_def.copy_number IS NULL THEN 'null()' + WHEN LENGTH( attr_def.copy_number ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.copy_number || '"]' + ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.copy_number + END; + + status := + CASE + WHEN attr_def.status IS NULL THEN 'null()' + WHEN LENGTH( attr_def.status ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.status || '"]' + ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.status + END; + + location := + CASE + WHEN attr_def.location IS NULL THEN 'null()' + WHEN LENGTH( attr_def.location ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.location || '"]' + ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.location + END; + + circulate := + CASE + WHEN attr_def.circulate IS NULL THEN 'null()' + WHEN LENGTH( attr_def.circulate ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circulate || '"]' + ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circulate + END; + + deposit := + CASE + WHEN attr_def.deposit IS NULL THEN 'null()' + WHEN LENGTH( attr_def.deposit ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.deposit || '"]' + ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.deposit + END; + + deposit_amount := + CASE + WHEN attr_def.deposit_amount IS NULL THEN 'null()' + WHEN LENGTH( attr_def.deposit_amount ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.deposit_amount || '"]' + ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.deposit_amount + END; + + ref := + CASE + WHEN attr_def.ref IS NULL THEN 'null()' + WHEN LENGTH( attr_def.ref ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.ref || '"]' + ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.ref + END; + + holdable := + CASE + WHEN attr_def.holdable IS NULL THEN 'null()' + WHEN LENGTH( attr_def.holdable ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.holdable || '"]' + ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.holdable + END; + + price := + CASE + WHEN attr_def.price IS NULL THEN 'null()' + WHEN LENGTH( attr_def.price ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.price || '"]' + ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.price + END; + + barcode := + CASE + WHEN attr_def.barcode IS NULL THEN 'null()' + WHEN LENGTH( attr_def.barcode ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.barcode || '"]' + ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.barcode + END; + + circ_modifier := + CASE + WHEN attr_def.circ_modifier IS NULL THEN 'null()' + WHEN LENGTH( attr_def.circ_modifier ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circ_modifier || '"]' + ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circ_modifier + END; + + circ_as_type := + CASE + WHEN attr_def.circ_as_type IS NULL THEN 'null()' + WHEN LENGTH( attr_def.circ_as_type ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circ_as_type || '"]' + ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circ_as_type + END; + + alert_message := + CASE + WHEN attr_def.alert_message IS NULL THEN 'null()' + WHEN LENGTH( attr_def.alert_message ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.alert_message || '"]' + ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.alert_message + END; + + opac_visible := + CASE + WHEN attr_def.opac_visible IS NULL THEN 'null()' + WHEN LENGTH( attr_def.opac_visible ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.opac_visible || '"]' + ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.opac_visible + END; + + pub_note := + CASE + WHEN attr_def.pub_note IS NULL THEN 'null()' + WHEN LENGTH( attr_def.pub_note ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.pub_note || '"]' + ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.pub_note + END; + priv_note := + CASE + WHEN attr_def.priv_note IS NULL THEN 'null()' + WHEN LENGTH( attr_def.priv_note ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.priv_note || '"]' + ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.priv_note + END; + + internal_id := + CASE + WHEN attr_def.internal_id IS NULL THEN 'null()' + WHEN LENGTH( attr_def.internal_id ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.internal_id || '"]' + ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.internal_id + END; + + + + xpath := + owning_lib || '|' || + circ_lib || '|' || + call_number || '|' || + copy_number || '|' || + status || '|' || + location || '|' || + circulate || '|' || + deposit || '|' || + deposit_amount || '|' || + ref || '|' || + holdable || '|' || + price || '|' || + barcode || '|' || + circ_modifier || '|' || + circ_as_type || '|' || + alert_message || '|' || + pub_note || '|' || + priv_note || '|' || + internal_id || '|' || + opac_visible; + + FOR tmp_attr_set IN + SELECT * + FROM oils_xpath_table( 'id', 'marc', 'vandelay.queued_bib_record', xpath, 'id = ' || import_id ) + AS t( id INT, ol TEXT, clib TEXT, cn TEXT, cnum TEXT, cs TEXT, cl TEXT, circ TEXT, + dep TEXT, dep_amount TEXT, r TEXT, hold TEXT, pr TEXT, bc TEXT, circ_mod TEXT, + circ_as TEXT, amessage TEXT, note TEXT, pnote TEXT, internal_id TEXT, opac_vis TEXT ) + LOOP + + attr_set.import_error := NULL; + attr_set.error_detail := NULL; + attr_set.deposit_amount := NULL; + attr_set.copy_number := NULL; + attr_set.price := NULL; + attr_set.circ_modifier := NULL; + attr_set.location := NULL; + attr_set.barcode := NULL; + attr_set.call_number := NULL; + + IF tmp_attr_set.pr != '' THEN + tmp_str = REGEXP_REPLACE(tmp_attr_set.pr, E'[^0-9\\.]', '', 'g'); + IF tmp_str = '' THEN + attr_set.import_error := 'import.item.invalid.price'; + attr_set.error_detail := tmp_attr_set.pr; -- original value + RETURN NEXT attr_set; CONTINUE; + END IF; + attr_set.price := tmp_str::NUMERIC(8,2); + END IF; + + IF tmp_attr_set.dep_amount != '' THEN + tmp_str = REGEXP_REPLACE(tmp_attr_set.dep_amount, E'[^0-9\\.]', '', 'g'); + IF tmp_str = '' THEN + attr_set.import_error := 'import.item.invalid.deposit_amount'; + attr_set.error_detail := tmp_attr_set.dep_amount; + RETURN NEXT attr_set; CONTINUE; + END IF; + attr_set.deposit_amount := tmp_str::NUMERIC(8,2); + END IF; + + IF tmp_attr_set.cnum != '' THEN + tmp_str = REGEXP_REPLACE(tmp_attr_set.cnum, E'[^0-9]', '', 'g'); + IF tmp_str = '' THEN + attr_set.import_error := 'import.item.invalid.copy_number'; + attr_set.error_detail := tmp_attr_set.cnum; + RETURN NEXT attr_set; CONTINUE; + END IF; + attr_set.copy_number := tmp_str::INT; + END IF; + + IF tmp_attr_set.ol != '' THEN + SELECT id INTO attr_set.owning_lib FROM actor.org_unit WHERE shortname = UPPER(tmp_attr_set.ol); -- INT + IF NOT FOUND THEN + attr_set.import_error := 'import.item.invalid.owning_lib'; + attr_set.error_detail := tmp_attr_set.ol; + RETURN NEXT attr_set; CONTINUE; + END IF; + END IF; + + IF tmp_attr_set.clib != '' THEN + SELECT id INTO attr_set.circ_lib FROM actor.org_unit WHERE shortname = UPPER(tmp_attr_set.clib); -- INT + IF NOT FOUND THEN + attr_set.import_error := 'import.item.invalid.circ_lib'; + attr_set.error_detail := tmp_attr_set.clib; + RETURN NEXT attr_set; CONTINUE; + END IF; + END IF; + + IF tmp_attr_set.cs != '' THEN + SELECT id INTO attr_set.status FROM config.copy_status WHERE LOWER(name) = LOWER(tmp_attr_set.cs); -- INT + IF NOT FOUND THEN + attr_set.import_error := 'import.item.invalid.status'; + attr_set.error_detail := tmp_attr_set.cs; + RETURN NEXT attr_set; CONTINUE; + END IF; + END IF; + + IF COALESCE(tmp_attr_set.circ_mod, '') = '' THEN + + -- no circ mod defined, see if we should apply a default + SELECT INTO attr_set.circ_modifier TRIM(BOTH '"' FROM value) + FROM actor.org_unit_ancestor_setting( + 'vandelay.item.circ_modifier.default', + attr_set.owning_lib + ); + + -- make sure the value from the org setting is still valid + PERFORM 1 FROM config.circ_modifier WHERE code = attr_set.circ_modifier; + IF NOT FOUND THEN + attr_set.import_error := 'import.item.invalid.circ_modifier'; + attr_set.error_detail := tmp_attr_set.circ_mod; + RETURN NEXT attr_set; CONTINUE; + END IF; + + ELSE + + SELECT code INTO attr_set.circ_modifier FROM config.circ_modifier WHERE code = tmp_attr_set.circ_mod; + IF NOT FOUND THEN + attr_set.import_error := 'import.item.invalid.circ_modifier'; + attr_set.error_detail := tmp_attr_set.circ_mod; + RETURN NEXT attr_set; CONTINUE; + END IF; + END IF; + + IF tmp_attr_set.circ_as != '' THEN + SELECT code INTO attr_set.circ_as_type FROM config.coded_value_map WHERE ctype = 'item_type' AND code = tmp_attr_set.circ_as; + IF NOT FOUND THEN + attr_set.import_error := 'import.item.invalid.circ_as_type'; + attr_set.error_detail := tmp_attr_set.circ_as; + RETURN NEXT attr_set; CONTINUE; + END IF; + END IF; + + IF COALESCE(tmp_attr_set.cl, '') = '' THEN + -- no location specified, see if we should apply a default + + SELECT INTO attr_set.location TRIM(BOTH '"' FROM value) + FROM actor.org_unit_ancestor_setting( + 'vandelay.item.copy_location.default', + attr_set.owning_lib + ); + + -- make sure the value from the org setting is still valid + PERFORM 1 FROM asset.copy_location + WHERE id = attr_set.location AND NOT deleted; + IF NOT FOUND THEN + attr_set.import_error := 'import.item.invalid.location'; + attr_set.error_detail := tmp_attr_set.cs; + RETURN NEXT attr_set; CONTINUE; + END IF; + ELSE + + -- search up the org unit tree for a matching copy location + WITH RECURSIVE anscestor_depth AS ( + SELECT ou.id, + out.depth AS depth, + ou.parent_ou + FROM actor.org_unit ou + JOIN actor.org_unit_type out ON (out.id = ou.ou_type) + WHERE ou.id = COALESCE(attr_set.owning_lib, attr_set.circ_lib) + UNION ALL + SELECT ou.id, + out.depth, + ou.parent_ou + FROM actor.org_unit ou + JOIN actor.org_unit_type out ON (out.id = ou.ou_type) + JOIN anscestor_depth ot ON (ot.parent_ou = ou.id) + ) SELECT cpl.id INTO attr_set.location + FROM anscestor_depth a + JOIN asset.copy_location cpl ON (cpl.owning_lib = a.id) + WHERE LOWER(cpl.name) = LOWER(tmp_attr_set.cl) + AND NOT cpl.deleted + ORDER BY a.depth DESC + LIMIT 1; + + IF NOT FOUND THEN + attr_set.import_error := 'import.item.invalid.location'; + attr_set.error_detail := tmp_attr_set.cs; + RETURN NEXT attr_set; CONTINUE; + END IF; + END IF; + + attr_set.circulate := + LOWER( SUBSTRING( tmp_attr_set.circ, 1, 1)) IN ('t','y','1') + OR LOWER(tmp_attr_set.circ) = 'circulating'; -- BOOL + + attr_set.deposit := + LOWER( SUBSTRING( tmp_attr_set.dep, 1, 1 ) ) IN ('t','y','1') + OR LOWER(tmp_attr_set.dep) = 'deposit'; -- BOOL + + attr_set.holdable := + LOWER( SUBSTRING( tmp_attr_set.hold, 1, 1 ) ) IN ('t','y','1') + OR LOWER(tmp_attr_set.hold) = 'holdable'; -- BOOL + + attr_set.opac_visible := + LOWER( SUBSTRING( tmp_attr_set.opac_vis, 1, 1 ) ) IN ('t','y','1') + OR LOWER(tmp_attr_set.opac_vis) = 'visible'; -- BOOL + + attr_set.ref := + LOWER( SUBSTRING( tmp_attr_set.r, 1, 1 ) ) IN ('t','y','1') + OR LOWER(tmp_attr_set.r) = 'reference'; -- BOOL + + attr_set.call_number := tmp_attr_set.cn; -- TEXT + attr_set.barcode := tmp_attr_set.bc; -- TEXT, + attr_set.alert_message := tmp_attr_set.amessage; -- TEXT, + attr_set.pub_note := tmp_attr_set.note; -- TEXT, + attr_set.priv_note := tmp_attr_set.pnote; -- TEXT, + attr_set.alert_message := tmp_attr_set.amessage; -- TEXT, + attr_set.internal_id := tmp_attr_set.internal_id::BIGINT; + + RETURN NEXT attr_set; + + END LOOP; + + END IF; + + RETURN; + +END; +$$ LANGUAGE PLPGSQL; + + + +COMMIT; + diff --git a/Open-ILS/web/js/dojo/openils/widget/AutoFieldWidget.js b/Open-ILS/web/js/dojo/openils/widget/AutoFieldWidget.js index 6738ffd63c..9ae36f2b93 100644 --- a/Open-ILS/web/js/dojo/openils/widget/AutoFieldWidget.js +++ b/Open-ILS/web/js/dojo/openils/widget/AutoFieldWidget.js @@ -705,7 +705,7 @@ if(!dojo._hasResource['openils.widget.AutoFieldWidget']) { orgs = orgs.concat(fieldmapper.aou.descendantNodeList(ws_ou).map(function (i) { return i.id() })); var self = this; - var search = {owning_lib : orgs}; + var search = {owning_lib : orgs, deleted : 'f'}; if(this.cache.copyLocStore) { var store = this.cache.copyLocStore; @@ -744,7 +744,7 @@ if(!dojo._hasResource['openils.widget.AutoFieldWidget']) { } else { // cached IDs plus id of this.widgetValue; locIds.push(this.widgetValue); - search = {id : locIds}; + search = {id : locIds, deleted: 'f'}; } } diff --git a/Open-ILS/web/js/ui/default/conify/global/asset/copy_location_group.js b/Open-ILS/web/js/ui/default/conify/global/asset/copy_location_group.js index 9a9770b083..634e40356b 100644 --- a/Open-ILS/web/js/ui/default/conify/global/asset/copy_location_group.js +++ b/Open-ILS/web/js/ui/default/conify/global/asset/copy_location_group.js @@ -64,7 +64,7 @@ function fetchCopyLocations() { var pcrud = new openils.PermaCrud({authtoken : user.authtoken}); pcrud.search('acpl', // this can take some time... - {owning_lib : ownerOrgList}, + {owning_lib : ownerOrgList, deleted: 'f'}, { async : true, join : 'aou', diff --git a/Open-ILS/web/js/ui/default/conify/global/asset/copy_location_order.js b/Open-ILS/web/js/ui/default/conify/global/asset/copy_location_order.js index e11f34fbfb..22b60ebc39 100644 --- a/Open-ILS/web/js/ui/default/conify/global/asset/copy_location_order.js +++ b/Open-ILS/web/js/ui/default/conify/global/asset/copy_location_order.js @@ -38,7 +38,7 @@ function filterGrid(org) { var pcrud = new openils.PermaCrud({authtoken : user.authtoken}); orders = pcrud.search('acplo', {org : org}, {order_by : {acplo : 'position'}}); locations = pcrud.search('acpl', - {owning_lib : fieldmapper.aou.orgNodeTrail(fieldmapper.aou.findOrgUnit(org), true)}, + {owning_lib : fieldmapper.aou.orgNodeTrail(fieldmapper.aou.findOrgUnit(org), true), deleted : 'f'}, {order_by : {acpl : 'name'}} ); } diff --git a/Open-ILS/web/js/ui/default/conify/global/config/circ_limit_set.js b/Open-ILS/web/js/ui/default/conify/global/config/circ_limit_set.js index eca7c988f1..4bc6f4ba19 100644 --- a/Open-ILS/web/js/ui/default/conify/global/config/circ_limit_set.js +++ b/Open-ILS/web/js/ui/default/conify/global/config/circ_limit_set.js @@ -34,7 +34,7 @@ function load(){ new openils.User().getPermOrgList( 'ADMIN_CIRC_MATRIX_MATCHPOINT', function (orgList) { - temp = pcrud.search('acpl', {owning_lib : orgList}); + temp = pcrud.search('acpl', {owning_lib : orgList, deleted: 'f'}); dojo.forEach(temp, function(g) { copyLocCache[g.id()] = g; } ); }, true, true diff --git a/Open-ILS/web/js/ui/default/opac/copyloc.js b/Open-ILS/web/js/ui/default/opac/copyloc.js index 1eaae20c3f..ddd1a5cf4f 100644 --- a/Open-ILS/web/js/ui/default/opac/copyloc.js +++ b/Open-ILS/web/js/ui/default/opac/copyloc.js @@ -44,7 +44,7 @@ function fetch_adv_copy_locations(org_ids) { var params = [{ cache : 1, fields : ['name', 'id', 'owning_lib'], - query : {owning_lib : org_ids, opac_visible : 't'} + query : {owning_lib : org_ids, opac_visible : 't', deleted : 'f'} }]; new OpenSRF.ClientSession('open-ils.fielder').request({