]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI.pm
LP2045292 Color contrast for AngularJS patron bills
[working/Evergreen.git] / Open-ILS / src / perlmods / lib / OpenILS / Application / Storage / CDBI.pm
1 package OpenILS::Application::Storage::CDBI;
2 use UNIVERSAL::require; 
3 BEGIN {                 
4     'Class::DBI::Frozen::301'->use or 'Class::DBI'->use or die $@;
5 }     
6 use base qw/Class::DBI/;
7 use Class::DBI::AbstractSearch;
8
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
12 # run time.
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;
25
26 use OpenSRF::Utils::JSON;
27 use OpenSRF::Utils::Logger qw(:level);
28 use OpenSRF::EX qw/:try/;
29
30 our $VERSION = 1;
31 my $log = 'OpenSRF::Utils::Logger';
32
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"); 
36 }
37
38 sub child_init {
39     my $self = shift;
40
41     $log->debug("Creating ImaDBI Querys", DEBUG);
42     __PACKAGE__->set_sql( 'OILSFastSearch', <<"    SQL", 'Main');
43         SELECT  %s
44           FROM  %s
45           WHERE %s = ?
46     SQL
47
48     __PACKAGE__->set_sql( 'OILSFastOrderedSearchLike', <<"    SQL", 'Main');
49         SELECT  %s
50           FROM  %s
51           WHERE %s LIKE ?
52           ORDER BY %s
53     SQL
54
55     __PACKAGE__->set_sql( 'OILSFastOrderedSearch', <<"    SQL", 'Main');
56         SELECT  %s
57           FROM  %s
58           WHERE %s = ?
59           ORDER BY %s
60     SQL
61
62     $log->debug("Calling Driver child_init", DEBUG);
63     $self->SUPER::child_init(@_);
64
65 }
66
67 sub fast_flesh_sth {
68     my $class = shift;
69     $class = ref($class) || $class;
70
71     my $field = shift;
72     my $value = shift;
73     my $order = shift;
74     my $like = shift;
75
76
77     if (!(defined($order) and ref($order) and ref($order) eq 'HASH')) {
78         if (defined($value) and ref($value) and ref($value) eq 'HASH') {
79             $order = $value;
80             $value = undef;
81         } else {
82             $order = { order_by => $class->columns('Primary') }
83         }
84     }
85
86     unless (defined $value) {
87         $value = $field;
88         ($field) = $class->columns('Primary');
89     }
90
91     unless (defined $field) {
92         ($field) = $class->columns('Primary');
93     }
94
95     unless ($order->{order_by}) {
96         $order = { order_by => $class->columns('Primary') }
97     }
98
99     my $fm_class = 'Fieldmapper::'.$class;
100     my $field_list = join ',', $class->columns('Essential');
101     
102     my $sth;
103     if (!$like) {
104         $sth = $class->sql_OILSFastOrderedSearch( $field_list, $class->table, $field, $order->{order_by});
105     } else {
106         $sth = $class->sql_OILSFastOrderedSearchLike( $field_list, $class->table, $field, $order->{order_by});
107     }
108     $sth->execute($value);
109     return $sth;
110 }
111
112 sub fast_flesh {
113     my $self = shift;
114     return map $class->construct($_), $self->fast_flesh_sth(@_)->fetchall_hash;
115 }
116
117 sub fast_fieldmapper {
118     my $self = shift;
119     my $id = shift;
120     my $col = shift;
121     my $like = shift;
122     my $options = shift;
123     my $class = ref($self) || $self;
124     my $fm_class = 'Fieldmapper::'.$class;
125     my @fms;
126     $log->debug("fast_fieldmapper() ==> Retrieving $fm_class", INTERNAL);
127     if ($like < 2) {
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} );
132             }
133             push @fms, $fm;
134         }
135     } else {
136         my $search_type = 'search';
137         if ($like == 2) {
138             $search_type = 'search_fts'
139         } elsif ($like == 3) {
140             $search_type = 'search_regex'
141         }
142
143         for my $obj ($class->$search_type({ $col => $id}, $options)) {
144             push @fms, $obj->to_fieldmapper;
145         }
146     }
147     return @fms;
148 }
149
150 sub retrieve {
151     my $self = shift;
152     my $arg = shift;
153     if (ref($arg) &&
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);
158         $arg = $arg->$col;
159     } elsif (ref $arg) {
160         my ($col) = $self->primary_column;
161         $log->debug("Using field $col as the primary key", INTERNAL);
162         $arg = $arg->{$col};
163     }
164         
165     $log->debug("Retrieving $self with $arg", INTERNAL);
166     my $rec;
167     try {
168         $rec = $self->SUPER::retrieve("$arg");
169     } catch Error with {
170         $log->debug("Could not retrieve $self with $arg! -- ".shift(), DEBUG);
171         return undef;
172     };
173     return $rec;
174 }
175
176 sub to_fieldmapper {
177     my $obj = shift;
178     my $class = ref($obj) || $obj;
179
180     my $fm_class = 'Fieldmapper::'.$class;
181     my $fm = $fm_class->new;
182
183     if (ref($obj)) {
184         for my $field ( $fm->real_fields ) {
185             $fm->$field( ''.$obj->$field ) if $obj->find_column($field) && defined $obj->$field;
186         }
187     }
188
189     return $fm;
190 }
191
192 sub merge {
193     my $self = shift;
194     my $search = shift;
195     my $arg = shift;
196
197     delete $$arg{$_} for (keys %$search);
198
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);
201
202     my @objs = ($self);
203     @objs = $self->search_where($search) unless (ref $self);
204
205     if (@objs == 1) {
206         $objs[0]->update($arg);
207         return $objs[0];
208     } elsif (@objs == 0) {
209         return $self->create({%$search,%$arg});
210     } else {
211         throw OpenSRF::EX::WARN ("Non-unique search key for merge.  Perhaps you meant to use remote_update?");
212     }
213 }
214
215 sub remote_update {
216     my $self = shift;
217     my $search = shift;
218     my $arg = shift;
219
220     delete $$arg{$_} for (keys %$search);
221
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);
224
225     my @finds = sort keys %$search;
226     my @sets = sort keys %$arg;
227
228     my @find_vals = @$search{@finds};
229     my @set_vals = @$arg{@sets};
230
231     my $sql = 'UPDATE %s SET %s WHERE %s';
232
233     my $table = $self->table;
234     my $set = join(', ', map { "$_=?" } @sets);
235     my $where = join(', ', map { "$_=?" } @finds);
236
237     my $sth = $self->db_Main->prepare(sprintf($sql, $table, $set, $where));
238     $sth->execute(@set_vals,@find_vals);
239     return $sth->rows;
240
241 }
242
243 sub create {
244     my $self = shift;
245     my $arg = shift;
246
247     $log->debug("CDBI->create: \$arg is $arg (".ref($arg)." : ".OpenSRF::Utils::JSON->perl2JSON($arg).")",DEBUG);
248
249     if (ref($arg) && UNIVERSAL::isa($arg => 'Fieldmapper')) {
250         return $self->create_from_fieldmapper($arg,@_);
251     }
252
253     return $self->SUPER::create($arg,@_);
254 }
255
256 sub create_from_fieldmapper {
257     my $obj = shift;
258     my $fm = shift;
259     my @params = @_;
260
261     $log->debug("Creating node of type ".ref($fm), DEBUG);
262
263     my $class = ref($obj) || $obj;
264     my ($primary) = $class->columns('Primary');
265
266     if (ref($fm) &&UNIVERSAL::isa($fm => 'Fieldmapper')) {
267         my %hash = map { defined $fm->$_ ?
268                     ($_ => $fm->$_) :
269                     ()
270                 } grep { $_ ne $primary } $class->columns('Essential');
271
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($$);
275             } else {
276                 my $xact_id = $class->current_xact_id;
277                 throw Error unless ($xact_id);
278                 $hash{last_xact_id} = $xact_id;
279             }
280         }
281
282         return $class->create( \%hash, @params );
283     } else {
284         return undef;
285     }
286 }
287
288 sub delete {
289     my $self = shift;
290     my $arg = shift;
291     my $orig = $self;
292
293     my $class = ref($self) || $self;
294
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 ");
299     }
300
301     if ($class->find_column( 'last_xact_id' )) {
302         my $xact_id = $self->current_xact_id;
303         
304         throw Error ("Deleting from $class requires a transaction be established")
305             unless ($xact_id);
306         
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);
309
310         $self->last_xact_id( $class->current_xact_id );
311         $self->SUPER::update;
312     }
313
314     $self->SUPER::delete;
315
316     return 1;
317 }
318
319 sub debug_object {
320     my $obj = shift;
321     my $string = '';
322
323     $string .= "Object type:\t".ref($obj)."\n";
324     $string .= "Object string:\t$obj\n";
325
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";
330         }
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";
335         }
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";
340         }
341     }
342
343     $string .= "\n";
344     
345     $log->debug($string,DEBUG);
346 }
347
348
349 sub update {
350     my $self = shift;
351     my $arg = shift;
352
353     $log->debug("Attempting to update using $arg", DEBUG) if ($arg);
354
355     if (ref($arg)) {
356         $self = $self->modify_from_fieldmapper($arg);
357         unless (defined $self) {
358             $log->debug("Modification of $arg seems to have failed....", DEBUG);
359             return undef;
360         }
361     }
362
363     $log->debug("Calling Class::DBI->update on modified object $self", DEBUG);
364
365     #debug_object($self);
366
367     return $self->SUPER::update if ($self->is_changed);
368     return 0;
369 }
370
371 sub modify_from_fieldmapper {
372     my $obj = shift;
373     my $fm = shift;
374     my $orig = $obj;
375
376     #debug_object($obj);
377     #debug_object($fm);
378
379     $log->debug("Modifying object using fieldmapper", DEBUG);
380
381     my $class = ref($obj) || $obj;
382     my ($primary) = $class->columns('Primary');
383
384
385     if (!ref($obj)) {
386         $obj = $class->retrieve($fm);
387         #debug_object($obj);
388         unless ($obj) {
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."!!");
391         }
392     }
393
394     my %hash;
395     
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'));
399     } else {
400         %hash = %{$fm};
401     }
402
403     my $au = $obj->autoupdate;
404     $obj->autoupdate(0);
405     
406     #debug_object($obj);
407
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);
411     }
412
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")
416             unless ($xact_id);
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 );
420     } else {
421         $obj->autoupdate($au)
422     }
423
424     return $obj;
425 }
426
427
428
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' );
439
440     actor::user_address->has_a( usr => 'actor::user' );
441     
442     actor::card->has_a( usr => 'actor::user' );
443     
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' );
447
448     actor::usr_message->has_a( usr => 'actor::user' );
449     actor::user->has_many( notes => 'actor::usr_message' );
450
451     actor::user_standing_penalty->has_a( usr => 'actor::user' );
452     actor::user->has_many( standing_penalties => 'actor::user_standing_penalty' );
453
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' );
465
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' );
468
469     actor::org_address->has_a( org_unit => 'actor::org_unit' );
470     actor::org_unit->has_many( addresses => 'actor::org_address' );
471
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' );
475
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' );
480
481     action::hold_request->has_many( transits => 'action::hold_transit_copy' );
482
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' );
493
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' );
500
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' );
505
506     action::survey_question->has_a( survey => 'action::survey' );
507
508     action::survey_answer->has_a( question => 'action::survey_question' );
509
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' );
513
514     asset::copy_part_map->has_a( target_copy => 'asset::copy' );
515     asset::copy_part_map->has_a( part => 'biblio::monograph_part' );
516
517     biblio::peer_type->has_many( records => 'biblio::record_entry' );
518
519     asset::copy_note->has_a( owning_copy => 'asset::copy' );
520     asset::copy_note->has_a( creator => 'actor::user' );
521
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' );
524
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' );
528
529     asset::copy->has_many( part_maps => 'asset::copy_part_map' );
530
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' );
537
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' );
544
545     serial::item->has_a( unit => 'serial::unit' );
546     serial::item->has_a( issuance => 'serial::issuance' );
547     serial::item->has_a( uri => 'asset::uri' );
548
549     serial::unit->has_many( items => 'serial::item' );
550
551     serial::issuance->has_a( subscription => 'serial::subscription' );
552     serial::issuance->has_many( items => 'serial::item' );
553
554     serial::subscription->has_a( record_entry => 'biblio::record_entry' );
555     serial::subscription->has_many( issuances => 'serial::issuance' );
556
557     asset::call_number_note->has_a( call_number => 'asset::call_number' );
558
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' );
563
564     authority::record_note->has_a( record => 'authority::record_entry' );
565     biblio::record_note->has_a( record => 'biblio::record_entry' );
566     
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' );
571     
572     metabib::metarecord->has_a( master_record => 'biblio::record_entry' );
573     
574     authority::record_descriptor->has_a( record => 'authority::record_entry' );
575     metabib::record_descriptor->has_a( record => 'biblio::record_entry' );
576     
577     authority::full_rec->has_a( record => 'authority::record_entry' );
578     metabib::full_rec->has_a( record => 'biblio::record_entry' );
579     
580     metabib::title_field_entry->has_a( source => 'biblio::record_entry' );
581     metabib::title_field_entry->has_a( field => 'config::metabib_field' );
582
583     metabib::identifier_field_entry->has_a( source => 'biblio::record_entry' );
584     metabib::identifier_field_entry->has_a( field => 'config::metabib_field' );
585     
586     metabib::author_field_entry->has_a( source => 'biblio::record_entry' );
587     metabib::author_field_entry->has_a( field => 'config::metabib_field' );
588     
589     metabib::subject_field_entry->has_a( source => 'biblio::record_entry' );
590     metabib::subject_field_entry->has_a( field => 'config::metabib_field' );
591     
592     metabib::keyword_field_entry->has_a( source => 'biblio::record_entry' );
593     metabib::keyword_field_entry->has_a( field => 'config::metabib_field' );
594     
595     metabib::series_field_entry->has_a( source => 'biblio::record_entry' );
596     metabib::series_field_entry->has_a( field => 'config::metabib_field' );
597     
598     metabib::metarecord_source_map->has_a( metarecord => 'metabib::metarecord' );
599     metabib::metarecord_source_map->has_a( source => 'biblio::record_entry' );
600
601     action::circulation->has_a( usr => 'actor::user' );
602     actor::user->has_many( circulations => 'action::circulation' => 'usr' );
603
604     booking::resource_attr_map->has_a( resource => 'booking::resource' );
605
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' );
609
610     booking::reservation->has_a( usr => 'actor::user' );
611     actor::user->has_many( reservations => 'booking::reservation' => 'usr' );
612     
613     action::circulation->has_a( circ_staff => 'actor::user' );
614     actor::user->has_many( performed_circulations => 'action::circulation' => 'circ_staff' );
615
616     action::circulation->has_a( checkin_staff => 'actor::user' );
617     actor::user->has_many( checkins => 'action::circulation' => 'checkin_staff' );
618
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' );
622
623     booking::reservation->has_a( pickup_lib => 'actor::org_unit' );
624
625     action::circulation->has_a( circ_lib => 'actor::org_unit' );
626     actor::org_unit->has_many( circulations => 'action::circulation' => 'circ_lib' );
627     
628     action::circulation->has_a( checkin_lib => 'actor::org_unit' );
629     actor::org_unit->has_many( checkins => 'action::circulation' => 'checkin_lib' );
630
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' );
635     
636     
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' );
641
642     actor::org_unit->has_many( users => 'actor::user' );
643
644     action::survey->has_many( questions => 'action::survey_question' );
645     action::survey->has_many( responses => 'action::survey_response' );
646     
647     action::survey_question->has_many( answers => 'action::survey_answer' );
648     action::survey_question->has_many( responses => 'action::survey_response' );
649
650     action::survey_answer->has_many( responses => 'action::survey_response' );
651
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' );
655
656     asset::call_number->has_a( prefix => 'asset::call_number_prefix' );
657     asset::call_number->has_a( suffix => 'asset::call_number_suffix' );
658
659     asset::call_number_prefix->has_a( owning_lib => 'actor::org_unit' );
660     asset::call_number_suffix->has_a( owning_lib => 'actor::org_unit' );
661
662     asset::call_number_prefix->has_many( call_numbers => 'asset::call_number' );
663     asset::call_number_suffix->has_many( call_numbers => 'asset::call_number' );
664
665     authority::record_entry->has_many( record_descriptor => 'authority::record_descriptor' );
666     authority::record_entry->has_many( notes => 'authority::record_note' );
667
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' );
678
679     metabib::metarecord->has_many( source_records => [ 'metabib::metarecord_source_map' => 'source'] );
680     biblio::record_entry->has_many( metarecords => [ 'metabib::metarecord_source_map' => 'metarecord'] );
681
682     money::billing->has_a( xact => 'money::billable_transaction' );
683     money::payment->has_a( xact => 'money::billable_transaction' );
684
685     money::billable_transaction->has_many( billings => 'money::billing' );
686     money::billable_transaction->has_many( payments => 'money::payment' );
687
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' );
692
693     booking::reservation->has_many( billings => 'money::billing' => 'xact' );
694     booking::reservation->has_many( payments => 'money::payment' => 'xact' );
695
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' );
700
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' );
705
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' );
709
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' );
717
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' );
721
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' );
725
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' );
729
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' );
733
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' );
737
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' );
741
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' );
745
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' );
749
750     permission::grp_tree->has_a( parent => 'permission::grp_tree' );
751     permission::grp_tree->has_many( children => 'permission::grp_tree' => 'parent' );
752
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' );
756     
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' );
760     
761     permission::usr_grp_map->has_a(  usr => 'actor::user' );
762     permission::usr_grp_map->has_a(  grp => 'permission::grp_tree' );
763
764     action::hold_notification->has_a(  hold => 'action::hold_request' );
765     
766     action::hold_copy_map->has_a(  hold => 'action::hold_request' );
767     action::hold_copy_map->has_a(  target_copy => 'asset::copy' );
768
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' );
772
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' );
781
782     action::hold_request->has_many(  notifications => 'action::hold_notification' );
783     action::hold_request->has_many(  eligible_copies => [ 'action::hold_copy_map' => 'target_copy' ] );
784
785     asset::copy->has_many(  holds => [ 'action::hold_copy_map' => 'hold' ] );
786     serial::unit->has_many(  holds => [ 'action::hold_copy_map' => 'hold' ] );
787
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' );
792
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' );
797
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' );
802
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' );
807
808
809 1;