1 package OpenILS::Application::Storage::CDBI;
2 use UNIVERSAL::require;
4 'Class::DBI::Frozen::301'->use or 'Class::DBI'->use or die $@;
6 use base qw/Class::DBI/;
7 use Class::DBI::AbstractSearch;
9 # The following modules add, or use, subroutines in modules that are
10 # not available when this module is compiled. We therefore "require"
11 # these modules rather than "use" them. Everything is available at
13 require OpenILS::Application::Storage::CDBI::actor;
14 require OpenILS::Application::Storage::CDBI::action;
15 require OpenILS::Application::Storage::CDBI::booking;
16 require OpenILS::Application::Storage::CDBI::asset;
17 require OpenILS::Application::Storage::CDBI::serial;
18 require OpenILS::Application::Storage::CDBI::authority;
19 require OpenILS::Application::Storage::CDBI::biblio;
20 require OpenILS::Application::Storage::CDBI::config;
21 require OpenILS::Application::Storage::CDBI::metabib;
22 require OpenILS::Application::Storage::CDBI::money;
23 require OpenILS::Application::Storage::CDBI::permission;
24 require OpenILS::Application::Storage::CDBI::container;
26 use OpenSRF::Utils::JSON;
27 use OpenSRF::Utils::Logger qw(:level);
28 use OpenSRF::EX qw/:try/;
31 my $log = 'OpenSRF::Utils::Logger';
33 if ($Class::DBI::VERSION gt '3.0.1') {
34 $log->error("Your version of Class::DBI, $Class::DBI::VERSION, is too new and incompatible with Evergreen. You will need to downgrade to version 3.0.1 or install Class::DBI::Frozen::301");
35 die("Your version of Class::DBI, $Class::DBI::VERSION, is too new and incompatible with Evergreen. You will need to downgrade to version 3.0.1 or install Class::DBI::Frozen::301");
41 $log->debug("Creating ImaDBI Querys", DEBUG);
42 __PACKAGE__->set_sql( 'OILSFastSearch', <<" SQL", 'Main');
48 __PACKAGE__->set_sql( 'OILSFastOrderedSearchLike', <<" SQL", 'Main');
55 __PACKAGE__->set_sql( 'OILSFastOrderedSearch', <<" SQL", 'Main');
62 $log->debug("Calling Driver child_init", DEBUG);
63 $self->SUPER::child_init(@_);
69 $class = ref($class) || $class;
77 if (!(defined($order) and ref($order) and ref($order) eq 'HASH')) {
78 if (defined($value) and ref($value) and ref($value) eq 'HASH') {
82 $order = { order_by => $class->columns('Primary') }
86 unless (defined $value) {
88 ($field) = $class->columns('Primary');
91 unless (defined $field) {
92 ($field) = $class->columns('Primary');
95 unless ($order->{order_by}) {
96 $order = { order_by => $class->columns('Primary') }
99 my $fm_class = 'Fieldmapper::'.$class;
100 my $field_list = join ',', $class->columns('Essential');
104 $sth = $class->sql_OILSFastOrderedSearch( $field_list, $class->table, $field, $order->{order_by});
106 $sth = $class->sql_OILSFastOrderedSearchLike( $field_list, $class->table, $field, $order->{order_by});
108 $sth->execute($value);
114 return map $class->construct($_), $self->fast_flesh_sth(@_)->fetchall_hash;
117 sub fast_fieldmapper {
123 my $class = ref($self) || $self;
124 my $fm_class = 'Fieldmapper::'.$class;
126 $log->debug("fast_fieldmapper() ==> Retrieving $fm_class", INTERNAL);
128 for my $hash ($self->fast_flesh_sth( $col, "$id", { order_by => $col }, $like )->fetchall_hash) {
129 my $fm = $fm_class->new;
130 for my $field ( $fm_class->real_fields ) {
131 $fm->$field( $$hash{$field} );
136 my $search_type = 'search';
138 $search_type = 'search_fts'
139 } elsif ($like == 3) {
140 $search_type = 'search_regex'
143 for my $obj ($class->$search_type({ $col => $id}, $options)) {
144 push @fms, $obj->to_fieldmapper;
154 (UNIVERSAL::isa($arg => 'Fieldmapper') ||
155 UNIVERSAL::isa($arg => 'Class::DBI')) ) {
156 my ($col) = $self->primary_column;
157 $log->debug("Using field $col as the primary key", INTERNAL);
160 my ($col) = $self->primary_column;
161 $log->debug("Using field $col as the primary key", INTERNAL);
165 $log->debug("Retrieving $self with $arg", INTERNAL);
168 $rec = $self->SUPER::retrieve("$arg");
170 $log->debug("Could not retrieve $self with $arg! -- ".shift(), DEBUG);
178 my $class = ref($obj) || $obj;
180 my $fm_class = 'Fieldmapper::'.$class;
181 my $fm = $fm_class->new;
184 for my $field ( $fm->real_fields ) {
185 $fm->$field( ''.$obj->$field ) if $obj->find_column($field) && defined $obj->$field;
197 delete $$arg{$_} for (keys %$search);
199 $log->debug("CDBI->merge: \$search is $search (".ref($search)." : ".join(',',map{"$_ => $$search{$_}"}keys(%$search)).")",DEBUG);
200 $log->debug("CDBI->merge: \$arg is $arg (".ref($arg)." : ".join(',',map{"$_ => $$arg{$_}"}keys(%$arg)).")",DEBUG);
203 @objs = $self->search_where($search) unless (ref $self);
206 $objs[0]->update($arg);
208 } elsif (@objs == 0) {
209 return $self->create({%$search,%$arg});
211 throw OpenSRF::EX::WARN ("Non-unique search key for merge. Perhaps you meant to use remote_update?");
220 delete $$arg{$_} for (keys %$search);
222 $log->debug("CDBI->remote_update: \$search is $search (".ref($search)." : ".join(',',map{"$_ => $$search{$_}"}keys(%$search)).")",DEBUG);
223 $log->debug("CDBI->remote_update: \$arg is $arg (".ref($arg)." : ".join(',',map{"$_ => $$arg{$_}"}keys(%$arg)).")",DEBUG);
225 my @finds = sort keys %$search;
226 my @sets = sort keys %$arg;
228 my @find_vals = @$search{@finds};
229 my @set_vals = @$arg{@sets};
231 my $sql = 'UPDATE %s SET %s WHERE %s';
233 my $table = $self->table;
234 my $set = join(', ', map { "$_=?" } @sets);
235 my $where = join(', ', map { "$_=?" } @finds);
237 my $sth = $self->db_Main->prepare(sprintf($sql, $table, $set, $where));
238 $sth->execute(@set_vals,@find_vals);
247 $log->debug("CDBI->create: \$arg is $arg (".ref($arg)." : ".OpenSRF::Utils::JSON->perl2JSON($arg).")",DEBUG);
249 if (ref($arg) && UNIVERSAL::isa($arg => 'Fieldmapper')) {
250 return $self->create_from_fieldmapper($arg,@_);
253 return $self->SUPER::create($arg,@_);
256 sub create_from_fieldmapper {
261 $log->debug("Creating node of type ".ref($fm), DEBUG);
263 my $class = ref($obj) || $obj;
264 my ($primary) = $class->columns('Primary');
266 if (ref($fm) &&UNIVERSAL::isa($fm => 'Fieldmapper')) {
267 my %hash = map { defined $fm->$_ ?
270 } grep { $_ ne $primary } $class->columns('Essential');
272 if ($class->find_column( 'last_xact_id' )) {
273 if ($OpenILS::Application::Storage::IGNORE_XACT_ID_FAILURE) {
274 $hash{last_xact_id} = 'unknown.'.time.'.'.$$.'.'.rand($$);
276 my $xact_id = $class->current_xact_id;
277 throw Error unless ($xact_id);
278 $hash{last_xact_id} = $xact_id;
282 return $class->create( \%hash, @params );
293 my $class = ref($self) || $self;
295 $self = $self->retrieve($arg) if (!ref($self));
296 unless (defined $self) {
297 $log->debug("ARG! Couldn't retrieve record ".$arg->id, DEBUG);
298 throw OpenSRF::EX::WARN ("ARG! Couldn't retrieve record ");
301 if ($class->find_column( 'last_xact_id' )) {
302 my $xact_id = $self->current_xact_id;
304 throw Error ("Deleting from $class requires a transaction be established")
307 throw Error ("The row you are attempting to delete has been changed since you read it")
308 unless ( $orig->last_xact_id eq $self->last_xact_id);
310 $self->last_xact_id( $class->current_xact_id );
311 $self->SUPER::update;
314 $self->SUPER::delete;
323 $string .= "Object type:\t".ref($obj)."\n";
324 $string .= "Object string:\t$obj\n";
326 if (ref($obj) && UNIVERSAL::isa($obj => 'Fieldmapper')) {
327 $string .= "Object fields:\n";
328 for my $col ($obj->real_fields()) {
329 $string .= "\t$col\t=> ".$obj->$col."\n";
331 } elsif (ref($obj) && UNIVERSAL::isa($obj => 'Class::DBI')) {
332 $string .= "Object cols:\n";
333 for my $col ($obj->columns('All')) {
334 $string .= "\t$col\t=> ".$obj->$col."\n";
336 } elsif (ref($obj) && UNIVERSAL::isa($obj => 'HASH')) {
337 $string .= "Object keys and vals:\n";
338 for my $col (keys %$obj) {
339 $string .= "\t$col\t=> $$obj{$col}\n";
345 $log->debug($string,DEBUG);
353 $log->debug("Attempting to update using $arg", DEBUG) if ($arg);
356 $self = $self->modify_from_fieldmapper($arg);
357 unless (defined $self) {
358 $log->debug("Modification of $arg seems to have failed....", DEBUG);
363 $log->debug("Calling Class::DBI->update on modified object $self", DEBUG);
365 #debug_object($self);
367 return $self->SUPER::update if ($self->is_changed);
371 sub modify_from_fieldmapper {
379 $log->debug("Modifying object using fieldmapper", DEBUG);
381 my $class = ref($obj) || $obj;
382 my ($primary) = $class->columns('Primary');
386 $obj = $class->retrieve($fm);
389 $log->debug("Retrieve of $class using $fm (".$fm->id.") failed! -- ".shift(), ERROR);
390 throw OpenSRF::EX::WARN ("No $class with id of ".$fm->id."!!");
396 if (ref($fm) and UNIVERSAL::isa($fm => 'Fieldmapper')) {
397 %hash = map { ($_ => $fm->$_) } grep { $_ ne $primary } $class->columns('Essential');
398 delete $hash{passwd} if ($fm->isa('Fieldmapper::actor::user'));
403 my $au = $obj->autoupdate;
408 for my $field ( keys %hash ) {
409 $obj->$field( $hash{$field} ) if ($obj->$field ne $hash{$field});
410 $log->debug("Setting field $field on $obj to $hash{$field}",INTERNAL);
413 if ($class->find_column( 'last_xact_id' ) and $obj->is_changed) {
414 my ($xact_id) = OpenILS::Application::Storage->method_lookup('open-ils.storage.transaction.current')->run();
415 throw Error ("Updating $class requires a transaction be established")
417 throw Error ("The row you are attempting to delete has been changed since you read it")
418 unless ( $fm->last_xact_id eq $obj->last_xact_id);
419 $obj->last_xact_id( $xact_id );
421 $obj->autoupdate($au)
429 #-------------------------------------------------------------------------------
430 actor::user->has_a( home_ou => 'actor::org_unit' );
431 actor::user->has_a( card => 'actor::card' );
432 actor::user->has_a( standing => 'config::standing' );
433 actor::user->has_a( profile => 'permission::grp_tree' );
434 actor::user->has_a( mailing_address => 'actor::user_address' );
435 actor::user->has_a( billing_address => 'actor::user_address' );
436 actor::user->has_a( ident_type => 'config::identification_type' );
437 actor::user->has_a( ident_type2 => 'config::identification_type' );
438 actor::user->has_a( net_access_level => 'config::net_access_level' );
440 actor::user_address->has_a( usr => 'actor::user' );
442 actor::card->has_a( usr => 'actor::user' );
444 actor::workstation->has_a( owning_lib => 'actor::org_unit' );
445 actor::org_unit::closed_date->has_a( org_unit => 'actor::org_unit' );
446 actor::org_unit_setting->has_a( org_unit => 'actor::org_unit' );
448 actor::usr_message->has_a( usr => 'actor::user' );
449 actor::user->has_many( notes => 'actor::usr_message' );
451 actor::user_standing_penalty->has_a( usr => 'actor::user' );
452 actor::user->has_many( standing_penalties => 'actor::user_standing_penalty' );
454 actor::org_unit->has_a( parent_ou => 'actor::org_unit' );
455 actor::org_unit->has_a( ou_type => 'actor::org_unit_type' );
456 actor::org_unit->has_a( ill_address => 'actor::org_address' );
457 actor::org_unit->has_a( holds_address => 'actor::org_address' );
458 actor::org_unit->has_a( mailing_address => 'actor::org_address' );
459 actor::org_unit->has_a( billing_address => 'actor::org_address' );
460 actor::org_unit->has_many( children => 'actor::org_unit' => 'parent_ou' );
461 actor::org_unit->has_many( workstations => 'actor::workstation' );
462 actor::org_unit->has_many( closed_dates => 'actor::org_unit::closed_date' );
463 actor::org_unit->has_many( settings => 'actor::org_unit_setting' );
464 #actor::org_unit->might_have( hours_of_operation => 'actor::org_unit::hours_of_operation' );
466 actor::org_unit_type->has_a( parent => 'actor::org_unit_type' );
467 actor::org_unit_type->has_many( children => 'actor::org_unit_type' => 'parent' );
469 actor::org_address->has_a( org_unit => 'actor::org_unit' );
470 actor::org_unit->has_many( addresses => 'actor::org_address' );
472 action::transit_copy->has_a( source => 'actor::org_unit' );
473 action::transit_copy->has_a( dest => 'actor::org_unit' );
474 action::transit_copy->has_a( copy_status => 'config::copy_status' );
476 action::hold_transit_copy->has_a( source => 'actor::org_unit' );
477 action::hold_transit_copy->has_a( dest => 'actor::org_unit' );
478 action::hold_transit_copy->has_a( copy_status => 'config::copy_status' );
479 action::hold_transit_copy->has_a( hold => 'action::hold_request' );
481 action::hold_request->has_many( transits => 'action::hold_transit_copy' );
483 actor::stat_cat_entry->has_a( stat_cat => 'actor::stat_cat' );
484 actor::stat_cat_entry->has_many( default_entries => 'actor::stat_cat_entry_default' );
485 actor::stat_cat_entry_default->has_a( stat_cat => 'actor::stat_cat' );
486 actor::stat_cat_entry_default->has_a( stat_cat_entry => 'actor::stat_cat_entry' );
487 actor::stat_cat->has_a( owner => 'actor::org_unit' );
488 actor::stat_cat->has_many( entries => 'actor::stat_cat_entry' );
489 actor::stat_cat->has_many( default_entries => 'actor::stat_cat_entry_default' );
490 actor::stat_cat_entry_user_map->has_a( stat_cat => 'actor::stat_cat' );
491 actor::stat_cat_entry_user_map->has_a( stat_cat_entry => 'actor::stat_cat_entry' );
492 actor::stat_cat_entry_user_map->has_a( target_usr => 'actor::user' );
494 asset::stat_cat_entry->has_a( stat_cat => 'asset::stat_cat' );
495 asset::stat_cat->has_a( owner => 'actor::org_unit' );
496 asset::stat_cat->has_many( entries => 'asset::stat_cat_entry' );
497 asset::stat_cat_entry_copy_map->has_a( stat_cat => 'asset::stat_cat' );
498 asset::stat_cat_entry_copy_map->has_a( stat_cat_entry => 'asset::stat_cat_entry' );
499 asset::stat_cat_entry_copy_map->has_a( owning_copy => 'asset::copy' );
501 action::survey_response->has_a( usr => 'actor::user' );
502 action::survey_response->has_a( survey => 'action::survey' );
503 action::survey_response->has_a( question => 'action::survey_question' );
504 action::survey_response->has_a( answer => 'action::survey_answer' );
506 action::survey_question->has_a( survey => 'action::survey' );
508 action::survey_answer->has_a( question => 'action::survey_question' );
510 biblio::peer_bib_copy_map->has_a( target_copy => 'asset::copy' );
511 biblio::peer_bib_copy_map->has_a( peer_record => 'biblio::record_entry' );
512 biblio::peer_bib_copy_map->has_a( peer_type => 'biblio::peer_type' );
514 asset::copy_part_map->has_a( target_copy => 'asset::copy' );
515 asset::copy_part_map->has_a( part => 'biblio::monograph_part' );
517 biblio::peer_type->has_many( records => 'biblio::record_entry' );
519 asset::copy_note->has_a( owning_copy => 'asset::copy' );
520 asset::copy_note->has_a( creator => 'actor::user' );
522 actor::user->has_many( stat_cat_entries => [ 'actor::stat_cat_entry_user_map' => 'stat_cat_entry' ] );
523 actor::user->has_many( stat_cat_entry_user_maps => 'actor::stat_cat_entry_user_map' );
525 asset::copy->has_many( stat_cat_entries => [ 'asset::stat_cat_entry_copy_map' => 'stat_cat_entry' ] );
526 asset::copy->has_many( stat_cat_entry_copy_maps => 'asset::stat_cat_entry_copy_map' );
527 asset::copy->has_many( peer_bib_copy_maps => 'biblio::peer_bib_copy_map' );
529 asset::copy->has_many( part_maps => 'asset::copy_part_map' );
531 asset::copy->has_a( call_number => 'asset::call_number' );
532 asset::copy->has_a( creator => 'actor::user' );
533 asset::copy->has_a( editor => 'actor::user' );
534 asset::copy->has_a( status => 'config::copy_status' );
535 asset::copy->has_a( location => 'asset::copy_location' );
536 asset::copy->has_a( circ_lib => 'actor::org_unit' );
538 serial::unit->has_a( call_number => 'asset::call_number' );
539 serial::unit->has_a( creator => 'actor::user' );
540 serial::unit->has_a( editor => 'actor::user' );
541 serial::unit->has_a( status => 'config::copy_status' );
542 serial::unit->has_a( location => 'asset::copy_location' );
543 serial::unit->has_a( circ_lib => 'actor::org_unit' );
545 serial::item->has_a( unit => 'serial::unit' );
546 serial::item->has_a( issuance => 'serial::issuance' );
547 serial::item->has_a( uri => 'asset::uri' );
549 serial::unit->has_many( items => 'serial::item' );
551 serial::issuance->has_a( subscription => 'serial::subscription' );
552 serial::issuance->has_many( items => 'serial::item' );
554 serial::subscription->has_a( record_entry => 'biblio::record_entry' );
555 serial::subscription->has_many( issuances => 'serial::issuance' );
557 asset::call_number_note->has_a( call_number => 'asset::call_number' );
559 asset::call_number->has_a( record => 'biblio::record_entry' );
560 asset::call_number->has_a( creator => 'actor::user' );
561 asset::call_number->has_a( editor => 'actor::user' );
562 asset::call_number->has_a( owning_lib => 'actor::org_unit' );
564 authority::record_note->has_a( record => 'authority::record_entry' );
565 biblio::record_note->has_a( record => 'biblio::record_entry' );
567 authority::record_entry->has_a( creator => 'actor::user' );
568 authority::record_entry->has_a( editor => 'actor::user' );
569 biblio::record_entry->has_a( creator => 'actor::user' );
570 biblio::record_entry->has_a( editor => 'actor::user' );
572 metabib::metarecord->has_a( master_record => 'biblio::record_entry' );
574 authority::record_descriptor->has_a( record => 'authority::record_entry' );
575 metabib::record_descriptor->has_a( record => 'biblio::record_entry' );
577 authority::full_rec->has_a( record => 'authority::record_entry' );
578 metabib::full_rec->has_a( record => 'biblio::record_entry' );
580 metabib::title_field_entry->has_a( source => 'biblio::record_entry' );
581 metabib::title_field_entry->has_a( field => 'config::metabib_field' );
583 metabib::identifier_field_entry->has_a( source => 'biblio::record_entry' );
584 metabib::identifier_field_entry->has_a( field => 'config::metabib_field' );
586 metabib::author_field_entry->has_a( source => 'biblio::record_entry' );
587 metabib::author_field_entry->has_a( field => 'config::metabib_field' );
589 metabib::subject_field_entry->has_a( source => 'biblio::record_entry' );
590 metabib::subject_field_entry->has_a( field => 'config::metabib_field' );
592 metabib::keyword_field_entry->has_a( source => 'biblio::record_entry' );
593 metabib::keyword_field_entry->has_a( field => 'config::metabib_field' );
595 metabib::series_field_entry->has_a( source => 'biblio::record_entry' );
596 metabib::series_field_entry->has_a( field => 'config::metabib_field' );
598 metabib::metarecord_source_map->has_a( metarecord => 'metabib::metarecord' );
599 metabib::metarecord_source_map->has_a( source => 'biblio::record_entry' );
601 action::circulation->has_a( usr => 'actor::user' );
602 actor::user->has_many( circulations => 'action::circulation' => 'usr' );
604 booking::resource_attr_map->has_a( resource => 'booking::resource' );
606 booking::resource->has_a( owner => 'actor::org_unit' );
607 booking::resource->has_a( type => 'booking::resource_type' );
608 booking::resource_type->has_a( owner => 'actor::org_unit' );
610 booking::reservation->has_a( usr => 'actor::user' );
611 actor::user->has_many( reservations => 'booking::reservation' => 'usr' );
613 action::circulation->has_a( circ_staff => 'actor::user' );
614 actor::user->has_many( performed_circulations => 'action::circulation' => 'circ_staff' );
616 action::circulation->has_a( checkin_staff => 'actor::user' );
617 actor::user->has_many( checkins => 'action::circulation' => 'checkin_staff' );
619 action::circulation->has_a( target_copy => 'asset::copy' );
620 asset::copy->has_many( circulations => 'action::circulation' => 'target_copy' );
621 serial::unit->has_many( circulations => 'action::circulation' => 'target_copy' );
623 booking::reservation->has_a( pickup_lib => 'actor::org_unit' );
625 action::circulation->has_a( circ_lib => 'actor::org_unit' );
626 actor::org_unit->has_many( circulations => 'action::circulation' => 'circ_lib' );
628 action::circulation->has_a( checkin_lib => 'actor::org_unit' );
629 actor::org_unit->has_many( checkins => 'action::circulation' => 'checkin_lib' );
631 money::billable_transaction->has_a( usr => 'actor::user' );
632 #money::billable_transaction->might_have( circulation => 'action::circulation' );
633 #money::billable_transaction->might_have( grocery => 'money::grocery' );
634 actor::user->has_many( billable_transactions => 'action::circulation' => 'usr' );
637 #-------------------------------------------------------------------------------
638 actor::user->has_many( survey_responses => 'action::survey_response' );
639 actor::user->has_many( addresses => 'actor::user_address' );
640 actor::user->has_many( cards => 'actor::card' );
642 actor::org_unit->has_many( users => 'actor::user' );
644 action::survey->has_many( questions => 'action::survey_question' );
645 action::survey->has_many( responses => 'action::survey_response' );
647 action::survey_question->has_many( answers => 'action::survey_answer' );
648 action::survey_question->has_many( responses => 'action::survey_response' );
650 action::survey_answer->has_many( responses => 'action::survey_response' );
652 asset::copy->has_many( notes => 'asset::copy_note' );
653 asset::call_number->has_many( copies => 'asset::copy' );
654 asset::call_number->has_many( notes => 'asset::call_number_note' );
656 asset::call_number->has_a( prefix => 'asset::call_number_prefix' );
657 asset::call_number->has_a( suffix => 'asset::call_number_suffix' );
659 asset::call_number_prefix->has_a( owning_lib => 'actor::org_unit' );
660 asset::call_number_suffix->has_a( owning_lib => 'actor::org_unit' );
662 asset::call_number_prefix->has_many( call_numbers => 'asset::call_number' );
663 asset::call_number_suffix->has_many( call_numbers => 'asset::call_number' );
665 authority::record_entry->has_many( record_descriptor => 'authority::record_descriptor' );
666 authority::record_entry->has_many( notes => 'authority::record_note' );
668 biblio::record_entry->has_many( record_descriptor => 'metabib::record_descriptor' );
669 biblio::record_entry->has_many( notes => 'biblio::record_note' );
670 biblio::record_entry->has_many( call_numbers => 'asset::call_number' );
671 biblio::record_entry->has_many( full_record_entries => 'metabib::full_rec' );
672 biblio::record_entry->has_many( title_field_entries => 'metabib::title_field_entry' );
673 biblio::record_entry->has_many( identifier_field_entries => 'metabib::identifier_field_entry' );
674 biblio::record_entry->has_many( author_field_entries => 'metabib::author_field_entry' );
675 biblio::record_entry->has_many( subject_field_entries => 'metabib::subject_field_entry' );
676 biblio::record_entry->has_many( keyword_field_entries => 'metabib::keyword_field_entry' );
677 biblio::record_entry->has_many( series_field_entries => 'metabib::series_field_entry' );
679 metabib::metarecord->has_many( source_records => [ 'metabib::metarecord_source_map' => 'source'] );
680 biblio::record_entry->has_many( metarecords => [ 'metabib::metarecord_source_map' => 'metarecord'] );
682 money::billing->has_a( xact => 'money::billable_transaction' );
683 money::payment->has_a( xact => 'money::billable_transaction' );
685 money::billable_transaction->has_many( billings => 'money::billing' );
686 money::billable_transaction->has_many( payments => 'money::payment' );
688 action::circulation->has_many( billings => 'money::billing' => 'xact' );
689 action::circulation->has_many( payments => 'money::payment' => 'xact' );
690 #action::circulation->might_have( billable_transaction => 'money::billable_transaction' );
691 #action::open_circulation->might_have( circulation => 'action::circulation' );
693 booking::reservation->has_many( billings => 'money::billing' => 'xact' );
694 booking::reservation->has_many( payments => 'money::payment' => 'xact' );
696 action::in_house_use->has_a( org_unit => 'actor::org_unit' );
697 action::in_house_use->has_a( staff => 'actor::user' );
698 action::in_house_use->has_a( workstation => 'actor::workstation' );
699 action::in_house_use->has_a( item => 'asset::copy' );
701 action::non_cataloged_circulation->has_a( circ_lib => 'actor::org_unit' );
702 action::non_cataloged_circulation->has_a( item_type => 'config::non_cataloged_type' );
703 action::non_cataloged_circulation->has_a( patron => 'actor::user' );
704 action::non_cataloged_circulation->has_a( staff => 'actor::user' );
706 money::grocery->has_many( billings => 'money::billing' => 'xact' );
707 money::grocery->has_many( payments => 'money::payment' => 'xact' );
708 #money::grocery->might_have( billable_transaction => 'money::billable_transaction' );
710 #money::payment->might_have( cash_payment => 'money::cash_payment' );
711 #money::payment->might_have( check_payment => 'money::check_payment' );
712 #money::payment->might_have( credit_card_payment => 'money::credit_card_payment' );
713 #money::payment->might_have( debit_card_payment => 'money::debit_card_payment' );
714 #money::payment->might_have( forgive_payment => 'money::forgive_payment' );
715 #money::payment->might_have( work_payment => 'money::work_payment' );
716 #money::payment->might_have( credit_payment => 'money::credit_payment' );
718 money::cash_payment->has_a( xact => 'money::billable_transaction' );
719 money::cash_payment->has_a( accepting_usr => 'actor::user' );
720 #money::cash_payment->might_have( payment => 'money::payment' );
722 money::check_payment->has_a( xact => 'money::billable_transaction' );
723 money::check_payment->has_a( accepting_usr => 'actor::user' );
724 #money::check_payment->might_have( payment => 'money::payment' );
726 money::credit_card_payment->has_a( xact => 'money::billable_transaction' );
727 money::credit_card_payment->has_a( accepting_usr => 'actor::user' );
728 #money::credit_card_payment->might_have( payment => 'money::payment' );
730 money::debit_card_payment->has_a( xact => 'money::billable_transaction' );
731 money::debit_card_payment->has_a( accepting_usr => 'actor::user' );
732 #money::debit_card_payment->might_have( payment => 'money::payment' );
734 money::forgive_payment->has_a( xact => 'money::billable_transaction' );
735 money::forgive_payment->has_a( accepting_usr => 'actor::user' );
736 #money::forgive_payment->might_have( payment => 'money::payment' );
738 money::work_payment->has_a( xact => 'money::billable_transaction' );
739 money::work_payment->has_a( accepting_usr => 'actor::user' );
740 #money::work_payment->might_have( payment => 'money::payment' );
742 money::goods_payment->has_a( xact => 'money::billable_transaction' );
743 money::goods_payment->has_a( accepting_usr => 'actor::user' );
744 #money::goods_payment->might_have( payment => 'money::payment' );
746 money::credit_payment->has_a( xact => 'money::billable_transaction' );
747 money::credit_payment->has_a( accepting_usr => 'actor::user' );
748 #money::credit_payment->might_have( payment => 'money::payment' );
750 permission::grp_tree->has_a( parent => 'permission::grp_tree' );
751 permission::grp_tree->has_many( children => 'permission::grp_tree' => 'parent' );
753 permission::grp_perm_map->has_a( grp => 'permission::grp_tree' );
754 permission::grp_perm_map->has_a( perm => 'permission::perm_list' );
755 permission::grp_perm_map->has_a( depth => 'actor::org_unit_type' );
757 permission::usr_perm_map->has_a( usr => 'actor::user' );
758 permission::usr_perm_map->has_a( perm => 'permission::perm_list' );
759 permission::usr_perm_map->has_a( depth => 'actor::org_unit_type' );
761 permission::usr_grp_map->has_a( usr => 'actor::user' );
762 permission::usr_grp_map->has_a( grp => 'permission::grp_tree' );
764 action::hold_notification->has_a( hold => 'action::hold_request' );
766 action::hold_copy_map->has_a( hold => 'action::hold_request' );
767 action::hold_copy_map->has_a( target_copy => 'asset::copy' );
769 action::unfulfilled_hold_list->has_a( current_copy => 'asset::copy' );
770 action::unfulfilled_hold_list->has_a( hold => 'action::hold_request' );
771 action::unfulfilled_hold_list->has_a( circ_lib => 'actor::org_unit' );
773 action::hold_request->has_a( current_copy => 'asset::copy' );
774 action::hold_request->has_a( requestor => 'actor::user' );
775 action::hold_request->has_a( usr => 'actor::user' );
776 action::hold_request->has_a( fulfillment_staff => 'actor::user' );
777 action::hold_request->has_a( pickup_lib => 'actor::org_unit' );
778 action::hold_request->has_a( request_lib => 'actor::org_unit' );
779 action::hold_request->has_a( fulfillment_lib => 'actor::org_unit' );
780 action::hold_request->has_a( selection_ou => 'actor::org_unit' );
782 action::hold_request->has_many( notifications => 'action::hold_notification' );
783 action::hold_request->has_many( eligible_copies => [ 'action::hold_copy_map' => 'target_copy' ] );
785 asset::copy->has_many( holds => [ 'action::hold_copy_map' => 'hold' ] );
786 serial::unit->has_many( holds => [ 'action::hold_copy_map' => 'hold' ] );
788 container::biblio_record_entry_bucket->has_a( owner => 'actor::user' );
789 container::biblio_record_entry_bucket_item->has_a( bucket => 'container::biblio_record_entry_bucket' );
790 container::biblio_record_entry_bucket_item->has_a( target_biblio_record_entry => 'biblio::record_entry' );
791 container::biblio_record_entry_bucket->has_many( items => 'container::biblio_record_entry_bucket_item' );
793 container::user_bucket->has_a( owner => 'actor::user' );
794 container::user_bucket_item->has_a( bucket => 'container::user_bucket' );
795 container::user_bucket_item->has_a( target_user => 'actor::user' );
796 container::user_bucket->has_many( items => 'container::user_bucket_item' );
798 container::call_number_bucket->has_a( owner => 'actor::user' );
799 container::call_number_bucket_item->has_a( bucket => 'container::call_number_bucket' );
800 container::call_number_bucket_item->has_a( target_call_number => 'asset::call_number' );
801 container::call_number_bucket->has_many( items => 'container::call_number_bucket_item' );
803 container::copy_bucket->has_a( owner => 'actor::user' );
804 container::copy_bucket_item->has_a( bucket => 'container::copy_bucket' );
805 container::copy_bucket_item->has_a( target_copy => 'asset::copy' );
806 container::copy_bucket->has_many( items => 'container::copy_bucket_item' );