]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/AppUtils.pm
moved script building to a generic framework using cstore as the base - standardizing...
[Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / AppUtils.pm
1 package OpenILS::Application::AppUtils;
2 use strict; use warnings;
3 use base qw/OpenSRF::Application/;
4 use OpenSRF::Utils::Cache;
5 use OpenSRF::EX qw(:try);
6 use OpenILS::Perm;
7 use OpenSRF::Utils::Logger;
8 use OpenILS::Utils::ModsParser;
9 use OpenILS::Event;
10 use Data::Dumper;
11 my $logger = "OpenSRF::Utils::Logger";
12
13
14 my $cache_client = "OpenSRF::Utils::Cache";
15
16 my $storage_session = undef;
17
18 # ---------------------------------------------------------------------------
19 # Pile of utilty methods used accross applications.
20 # ---------------------------------------------------------------------------
21
22
23 # ---------------------------------------------------------------------------
24 # on sucess, returns the created session, on failure throws ERROR exception
25 # ---------------------------------------------------------------------------
26 sub start_db_session {
27
28         my $self = shift;
29         my $session = OpenSRF::AppSession->connect( "open-ils.storage" );
30         my $trans_req = $session->request( "open-ils.storage.transaction.begin" );
31
32         my $trans_resp = $trans_req->recv();
33         if(ref($trans_resp) and UNIVERSAL::isa($trans_resp,"Error")) { throw $trans_resp; }
34         if( ! $trans_resp->content() ) {
35                 throw OpenSRF::ERROR 
36                         ("Unable to Begin Transaction with database" );
37         }
38         $trans_req->finish();
39
40         $logger->debug("Setting global storage session to ".
41                 "session: " . $session->session_id . " : " . $session->app );
42
43         $storage_session = $session;
44         return $session;
45 }
46
47
48 # returns undef if user has all of the perms provided
49 # returns the first failed perm on failure
50 sub check_user_perms {
51         my($self, $user_id, $org_id, @perm_types ) = @_;
52         $logger->debug("Checking perms with user : $user_id , org: $org_id, @perm_types");
53         for my $type (@perm_types) {
54                 return $type unless ($self->storagereq(
55                         "open-ils.storage.permission.user_has_perm", 
56                         $user_id, $type, $org_id ));
57         }
58         return undef;
59 }
60
61 # checks the list of user perms.  The first one that fails returns a new
62 # OpenILS::Perm object of that type.  Returns undef if all perms are allowed
63 sub check_perms {
64         my( $self, $user_id, $org_id, @perm_types ) = @_;
65         my $t = $self->check_user_perms( $user_id, $org_id, @perm_types );
66         return OpenILS::Event->new('PERM_FAILURE', ilsperm => $t, ilspermloc => $org_id ) if $t;
67         return undef;
68 }
69
70
71
72 # ---------------------------------------------------------------------------
73 # commits and destroys the session
74 # ---------------------------------------------------------------------------
75 sub commit_db_session {
76         my( $self, $session ) = @_;
77
78         my $req = $session->request( "open-ils.storage.transaction.commit" );
79         my $resp = $req->recv();
80
81         if(!$resp) {
82                 throw OpenSRF::EX::ERROR ("Unable to commit db session");
83         }
84
85         if(UNIVERSAL::isa($resp,"Error")) { 
86                 throw $resp ($resp->stringify); 
87         }
88
89         if(!$resp->content) {
90                 throw OpenSRF::EX::ERROR ("Unable to commit db session");
91         }
92
93         $session->finish();
94         $session->disconnect();
95         $session->kill_me();
96         $storage_session = undef;
97 }
98
99 sub rollback_db_session {
100         my( $self, $session ) = @_;
101
102         my $req = $session->request("open-ils.storage.transaction.rollback");
103         my $resp = $req->recv();
104         if(UNIVERSAL::isa($resp,"Error")) { throw $resp;  }
105
106         $session->finish();
107         $session->disconnect();
108         $session->kill_me();
109         $storage_session = undef;
110 }
111
112
113 # returns undef it the event is not an ILS event
114 # returns the event code otherwise
115 sub event_code {
116         my( $self, $evt ) = @_;
117         return $evt->{ilsevent} if( ref($evt) eq 'HASH' and defined($evt->{ilsevent})) ;
118         return undef;
119 }
120
121 # ---------------------------------------------------------------------------
122 # Checks to see if a user is logged in.  Returns the user record on success,
123 # throws an exception on error.
124 # ---------------------------------------------------------------------------
125 sub check_user_session {
126
127         my( $self, $user_session ) = @_;
128
129         my $content = $self->simplereq( 
130                 'open-ils.auth', 
131                 'open-ils.auth.session.retrieve', $user_session );
132
133
134         if(! $content or $self->event_code($content)) {
135                 throw OpenSRF::EX::ERROR 
136                         ("Session [$user_session] cannot be authenticated" );
137         }
138
139         $logger->debug("Fetch user session $user_session found user " . $content->id );
140
141         return $content;
142 }
143
144 # generic simple request returning a scalar value
145 sub simplereq {
146         my($self, $service, $method, @params) = @_;
147         return $self->simple_scalar_request($service, $method, @params);
148 }
149
150 sub get_storage_session {
151
152         return undef; # XXX testing
153
154         if(     $storage_session and 
155                         $storage_session->connected and
156                         $storage_session->transport_connected and
157                         $storage_session->app eq 'open-ils.storage' ) {
158
159                 $logger->debug("get_storage_session(): returning existing session");
160                 return $storage_session;
161         }
162         $logger->debug("get_storage_session(): returning undef");
163         $storage_session = undef;
164         return undef;
165 }
166
167
168 sub simple_scalar_request {
169         my($self, $service, $method, @params) = @_;
170
171         my $session = undef;
172
173         if( $service eq 'open-ils.storage' ) {
174                 if( $session = get_storage_session() ) {
175                         $logger->debug("simple request using existing storage session ".$session->session_id);
176                 } else { $session = undef; }
177         }
178
179         $session = OpenSRF::AppSession->create( $service ) unless $session;
180
181         $logger->debug("simple request for service $service using session " .$session->app);
182
183         my $request = $session->request( $method, @params );
184         my $response = $request->recv(60);
185
186 #       $request->wait_complete;
187
188 #       if(!$request->complete) {
189 #               warn "request did not complete : service=$service : method=$method\n";
190 #               throw OpenSRF::EX::ERROR 
191 #                       ("Call to $service for method $method with params ". Dumper(\@params) . 
192 #                               "\n did not complete successfully");
193 #       }
194
195
196         if(!$response) {
197                 warn "No response from $service for method $method with params " . Dumper(\@params);
198                 $logger->error("No response from $service for method $method with params " . Dumper(\@params));
199                 return undef;
200         }
201
202         if(UNIVERSAL::isa($response,"Error")) {
203                 warn "received error : service=$service : method=$method : params=".Dumper(\@params) . "\n $response";
204                 throw $response ("Call to $service for method $method with params @params" . 
205                                 "\n failed with exception: $response : " . Dumper(\@params) );
206         }
207
208
209         $request->finish();
210
211         if($service ne 'open-ils.storage' or !get_storage_session() ) {
212                 $session->finish();
213                 $session->disconnect();
214         }
215
216         return $response->content;
217 }
218
219
220
221
222
223 my $tree                                                = undef;
224 my $orglist                                     = undef;
225 my $org_typelist                        = undef;
226 my $org_typelist_hash   = {};
227
228 sub get_org_tree {
229
230         my $self = shift;
231         if($tree) { return $tree; }
232
233         # see if it's in the cache
234         $tree = $cache_client->new()->get_cache('_orgtree');
235         if($tree) { return $tree; }
236
237         if(!$orglist) {
238                 warn "Retrieving Org Tree\n";
239                 $orglist = $self->simple_scalar_request( 
240                         "open-ils.storage", 
241                         "open-ils.storage.direct.actor.org_unit.retrieve.all.atomic" );
242         }
243
244         if( ! $org_typelist ) {
245                 warn "Retrieving org types\n";
246                 $org_typelist = $self->simple_scalar_request( 
247                         "open-ils.storage", 
248                         "open-ils.storage.direct.actor.org_unit_type.retrieve.all.atomic" );
249                 $self->build_org_type($org_typelist);
250         }
251
252         $tree = $self->build_org_tree($orglist,1);
253         $cache_client->new()->put_cache('_orgtree', $tree);
254         return $tree;
255
256 }
257
258 my $slimtree = undef;
259 sub get_slim_org_tree {
260
261         my $self = shift;
262         if($slimtree) { return $slimtree; }
263
264         # see if it's in the cache
265         $slimtree = $cache_client->new()->get_cache('slimorgtree');
266         if($slimtree) { return $slimtree; }
267
268         if(!$orglist) {
269                 warn "Retrieving Org Tree\n";
270                 $orglist = $self->simple_scalar_request( 
271                         "open-ils.storage", 
272                         "open-ils.storage.direct.actor.org_unit.retrieve.all.atomic" );
273         }
274
275         $slimtree = $self->build_org_tree($orglist);
276         $cache_client->new->put_cache('slimorgtree', $slimtree);
277         return $slimtree;
278
279 }
280
281
282 sub build_org_type { 
283         my($self, $org_typelist)  = @_;
284         for my $type (@$org_typelist) {
285                 $org_typelist_hash->{$type->id()} = $type;
286         }
287 }
288
289
290
291 sub build_org_tree {
292
293         my( $self, $orglist, $add_types ) = @_;
294
295         return $orglist unless ( 
296                         ref($orglist) and @$orglist > 1 );
297
298         my @list = sort { 
299                 $a->ou_type <=> $b->ou_type ||
300                 $a->name cmp $b->name } @$orglist;
301
302         for my $org (@list) {
303
304                 next unless ($org);
305
306                 if(!ref($org->ou_type()) and $add_types) {
307                         $org->ou_type( $org_typelist_hash->{$org->ou_type()});
308                 }
309
310                 next unless (defined($org->parent_ou));
311
312                 my ($parent) = grep { $_->id == $org->parent_ou } @list;
313                 next unless $parent;
314                 $parent->children([]) unless defined($parent->children); 
315                 push( @{$parent->children}, $org );
316         }
317
318         return $list[0];
319
320 }
321
322 sub fetch_closed_date {
323         my( $self, $cd ) = @_;
324         my $evt;
325         
326         $logger->debug("Fetching closed_date $cd from storage");
327
328         my $cd_obj = $self->simplereq(
329                 'open-ils.storage',
330                 'open-ils.storage.direct.actor.org_unit.closed_date.retrieve', $cd );
331
332         if(!$cd_obj) {
333                 $logger->info("closed_date $cd not found in the db");
334                 $evt = OpenILS::Event->new('ACTOR_USER_NOT_FOUND');
335         }
336
337         return ($cd_obj, $evt);
338 }
339
340 sub fetch_user {
341         my( $self, $userid ) = @_;
342         my( $user, $evt );
343         
344         $logger->debug("Fetching user $userid from storage");
345
346         $user = $self->simplereq(
347                 'open-ils.storage',
348                 'open-ils.storage.direct.actor.user.retrieve', $userid );
349
350         if(!$user) {
351                 $logger->info("User $userid not found in the db");
352                 $evt = OpenILS::Event->new('ACTOR_USER_NOT_FOUND');
353         }
354
355         return ($user, $evt);
356 }
357
358 sub checkses {
359         my( $self, $session ) = @_;
360         my $user; my $evt; my $e; 
361
362         $logger->debug("Checking user session $session");
363
364         try {
365                 $user = $self->check_user_session($session);
366         } catch Error with { $e = 1; };
367
368         if( $e or !$user ) { $evt = OpenILS::Event->new('NO_SESSION'); }
369         return ( $user, $evt );
370 }
371
372
373 # verifiese the session and checks the permissions agains the
374 # session user and the user's home_ou as the org id
375 sub checksesperm {
376         my( $self, $session, @perms ) = @_;
377         my $user; my $evt; my $e; 
378         $logger->debug("Checking user session $session and perms @perms");
379         ($user, $evt) = $self->checkses($session);
380         return (undef, $evt) if $evt;
381         $evt = $self->check_perms($user->id, $user->home_ou, @perms);
382         return ($user, $evt);
383 }
384
385
386 sub checkrequestor {
387         my( $self, $staffobj, $userid, @perms ) = @_;
388         my $user; my $evt;
389         $userid = $staffobj->id unless defined $userid;
390
391         $logger->debug("checkrequestor(): requestor => " . $staffobj->id . ", target => $userid");
392
393         if( $userid ne $staffobj->id ) {
394                 ($user, $evt) = $self->fetch_user($userid);
395                 return (undef, $evt) if $evt;
396                 $evt = $self->check_perms( $staffobj->id, $user->home_ou, @perms );
397
398         } else {
399                 $user = $staffobj;
400         }
401
402         return ($user, $evt);
403 }
404
405 sub checkses_requestor {
406         my( $self, $authtoken, $targetid, @perms ) = @_;
407         my( $requestor, $target, $evt );
408
409         ($requestor, $evt) = $self->checkses($authtoken);
410         return (undef, undef, $evt) if $evt;
411
412         ($target, $evt) = $self->checkrequestor( $requestor, $targetid, @perms );
413         return( $requestor, $target, $evt);
414 }
415
416 sub fetch_copy {
417         my( $self, $copyid ) = @_;
418         my( $copy, $evt );
419
420         $logger->debug("Fetching copy $copyid from storage");
421
422         $copy = $self->simplereq(
423                 'open-ils.storage',
424                 'open-ils.storage.direct.asset.copy.retrieve', $copyid );
425
426         if(!$copy) { $evt = OpenILS::Event->new('ASSET_COPY_NOT_FOUND'); }
427
428         return( $copy, $evt );
429 }
430
431
432 # retrieves a circ object by id
433 sub fetch_circulation {
434         my( $self, $circid ) = @_;
435         my $circ; my $evt;
436         
437         $logger->debug("Fetching circ $circid from storage");
438
439         $circ = $self->simplereq(
440                 'open-ils.storage',
441                 "open-ils.storage.direct.action.circulation.retrieve", $circid );
442
443         if(!$circ) {
444                 $evt = OpenILS::Event->new('ACTION_CIRCULATION_NOT_FOUND', circid => $circid );
445         }
446
447         return ( $circ, $evt );
448 }
449
450 sub fetch_record_by_copy {
451         my( $self, $copyid ) = @_;
452         my( $record, $evt );
453
454         $logger->debug("Fetching record by copy $copyid from storage");
455
456         $record = $self->simplereq(
457                 'open-ils.storage',
458                 'open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy', $copyid );
459
460         if(!$record) {
461                 $evt = OpenILS::Event->new('BIBLIO_RECORD_ENTRY_NOT_FOUND');
462         }
463
464         return ($record, $evt);
465 }
466
467 # turns a record object into an mvr (mods) object
468 sub record_to_mvr {
469         my( $self, $record ) = @_;
470         my $u = OpenILS::Utils::ModsParser->new();
471         $u->start_mods_batch( $record->marc );
472         my $mods = $u->finish_mods_batch();
473         $mods->doc_id($record->id);
474         return $mods;
475 }
476
477 sub fetch_hold {
478         my( $self, $holdid ) = @_;
479         my( $hold, $evt );
480
481         $logger->debug("Fetching hold $holdid from storage");
482
483         $hold = $self->simplereq(
484                 'open-ils.storage',
485                 'open-ils.storage.direct.action.hold_request.retrieve', $holdid);
486
487         $evt = OpenILS::Event->new('ACTION_HOLD_REQUEST_NOT_FOUND', holdid => $holdid) unless $hold;
488
489         return ($hold, $evt);
490 }
491
492
493 sub fetch_hold_transit_by_hold {
494         my( $self, $holdid ) = @_;
495         my( $transit, $evt );
496
497         $logger->debug("Fetching transit by hold $holdid from storage");
498
499         $transit = $self->simplereq(
500                 'open-ils.storage',
501                 'open-ils.storage.direct.action.hold_transit_copy.search.hold', $holdid );
502
503         $evt = OpenILS::Event->new('ACTION_HOLD_TRANSIT_COPY_NOT_FOUND', holdid => $holdid) unless $transit;
504
505         return ($transit, $evt );
506 }
507
508 # fetches the captured, but not fulfilled hold attached to a given copy
509 sub fetch_open_hold_by_copy {
510         my( $self, $copyid ) = @_;
511         $logger->debug("Searching for active hold for copy $copyid");
512         my( $hold, $evt );
513
514         $hold = $self->storagereq(
515                 'open-ils.storage.direct.action.hold_request.search_where',
516                 { 
517                         current_copy            => $copyid , 
518                         capture_time            => { "!=" => undef }, 
519                         fulfillment_time        => undef 
520                 } );
521
522         $evt = OpenILS::Event->new('ACTION_HOLD_REQUEST_NOT_FOUND', copyid => $copyid) unless $hold;
523         return ($hold, $evt);
524 }
525
526 sub fetch_hold_transit {
527         my( $self, $transid ) = @_;
528         my( $htransit, $evt );
529         $logger->debug("Fetching hold transit with hold id $transid");
530         $htransit = $self->storagereq(
531                 'open-ils.storage.direct.action.hold_transit_copy.retrieve', $transid );
532         $evt = OpenILS::Event->new('ACTION_HOLD_TRANSIT_COPY_NOT_FOUND', id => $transid) unless $htransit;
533         return ($htransit, $evt);
534 }
535
536 sub fetch_copy_by_barcode {
537         my( $self, $barcode ) = @_;
538         my( $copy, $evt );
539
540         $logger->debug("Fetching copy by barcode $barcode from storage");
541
542         $copy = $self->simplereq( 'open-ils.storage',
543                 'open-ils.storage.direct.asset.copy.search_where', { barcode => $barcode, deleted => 'f'} );
544                 #'open-ils.storage.direct.asset.copy.search.barcode', $barcode );
545
546         $evt = OpenILS::Event->new('ASSET_COPY_NOT_FOUND', barcode => $barcode) unless $copy;
547
548         return ($copy, $evt);
549 }
550
551 sub fetch_open_billable_transaction {
552         my( $self, $transid ) = @_;
553         my( $transaction, $evt );
554
555         $logger->debug("Fetching open billable transaction $transid from storage");
556
557         $transaction = $self->simplereq(
558                 'open-ils.storage',
559                 'open-ils.storage.direct.money.open_billable_transaction_summary.retrieve',  $transid);
560
561         $evt = OpenILS::Event->new(
562                 'MONEY_OPEN_BILLABLE_TRANSACTION_SUMMARY_NOT_FOUND', transid => $transid ) unless $transaction;
563
564         return ($transaction, $evt);
565 }
566
567
568
569 my %buckets;
570 $buckets{'biblio'} = 'biblio_record_entry_bucket';
571 $buckets{'callnumber'} = 'call_number_bucket';
572 $buckets{'copy'} = 'copy_bucket';
573 $buckets{'user'} = 'user_bucket';
574
575 sub fetch_container {
576         my( $self, $id, $type ) = @_;
577         my( $bucket, $evt );
578
579         $logger->debug("Fetching container $id with type $type");
580
581         my $e = 'CONTAINER_CALL_NUMBER_BUCKET_NOT_FOUND';
582         $e = 'CONTAINER_BIBLIO_RECORD_ENTRY_BUCKET_NOT_FOUND' if $type eq 'biblio';
583         $e = 'CONTAINER_USER_BUCKET_NOT_FOUND' if $type eq 'user';
584         $e = 'CONTAINER_COPY_BUCKET_NOT_FOUND' if $type eq 'copy';
585
586         my $meth = $buckets{$type};
587         $bucket = $self->simplereq(
588                 'open-ils.storage',
589                 "open-ils.storage.direct.container.$meth.retrieve", $id );
590
591         $evt = OpenILS::Event->new(
592                 $e, container => $id, container_type => $type ) unless $bucket;
593
594         return ($bucket, $evt);
595 }
596
597
598 sub fetch_container_item {
599         my( $self, $id, $type ) = @_;
600         my( $bucket, $evt );
601
602         $logger->debug("Fetching container item $id with type $type");
603
604         my $meth = $buckets{$type} . "_item";
605
606         $bucket = $self->simplereq(
607                 'open-ils.storage',
608                 "open-ils.storage.direct.container.$meth.retrieve", $id );
609
610
611         my $e = 'CONTAINER_CALL_NUMBER_BUCKET_ITEM_NOT_FOUND';
612         $e = 'CONTAINER_BIBLIO_RECORD_ENTRY_BUCKET_ITEM_NOT_FOUND' if $type eq 'biblio';
613         $e = 'CONTAINER_USER_BUCKET_ITEM_NOT_FOUND' if $type eq 'user';
614         $e = 'CONTAINER_COPY_BUCKET_ITEM_NOT_FOUND' if $type eq 'copy';
615
616
617         $evt = OpenILS::Event->new(
618                 $e, itemid => $id, container_type => $type ) unless $bucket;
619
620         return ($bucket, $evt);
621 }
622
623
624 sub fetch_patron_standings {
625         my $self = shift;
626         $logger->debug("Fetching patron standings");    
627         return $self->simplereq(
628                 'open-ils.storage', 
629                 'open-ils.storage.direct.config.standing.retrieve.all.atomic');
630 }
631
632
633 sub fetch_permission_group_tree {
634         my $self = shift;
635         $logger->debug("Fetching patron profiles");     
636         return $self->simplereq(
637                 'open-ils.actor', 
638                 'open-ils.actor.groups.tree.retrieve' );
639 }
640
641
642 sub fetch_patron_circ_summary {
643         my( $self, $userid ) = @_;
644         $logger->debug("Fetching patron summary for $userid");
645         my $summary = $self->simplereq(
646                 'open-ils.storage', 
647                 "open-ils.storage.action.circulation.patron_summary", $userid );
648
649         if( $summary ) {
650                 $summary->[0] ||= 0;
651                 $summary->[1] ||= 0.0;
652                 return $summary;
653         }
654         return undef;
655 }
656
657
658 sub fetch_copy_statuses {
659         my( $self ) = @_;
660         $logger->debug("Fetching copy statuses");
661         return $self->simplereq(
662                 'open-ils.storage', 
663                 'open-ils.storage.direct.config.copy_status.retrieve.all.atomic' );
664 }
665
666 sub fetch_copy_location {
667         my( $self, $id ) = @_;
668         my $evt;
669         my $cl = $self->storagereq(
670                 'open-ils.storage.direct.asset.copy_location.retrieve', $id );
671         $evt = OpenILS::Event->new('ASSET_COPY_LOCATION_NOT_FOUND') unless $cl;
672         return ($cl, $evt);
673 }
674
675 sub fetch_copy_locations {
676         my $self = shift; 
677         return $self->simplereq(
678                 'open-ils.storage', 
679                 'open-ils.storage.direct.asset.copy_location.retrieve.all.atomic');
680 }
681
682 sub fetch_copy_location_by_name {
683         my( $self, $name, $org ) = @_;
684         my $evt;
685         my $cl = $self->storagereq(
686                 'open-ils.storage.direct.asset.copy_location.search_where',
687                         { name => $name, owning_lib => $org } );
688         $evt = OpenILS::Event->new('ASSET_COPY_LOCATION_NOT_FOUND') unless $cl;
689         return ($cl, $evt);
690 }
691
692 sub fetch_callnumber {
693         my( $self, $id ) = @_;
694         my $evt = undef;
695         $logger->debug("Fetching callnumber $id");
696
697         my $cn = $self->simplereq(
698                 'open-ils.storage',
699                 'open-ils.storage.direct.asset.call_number.retrieve', $id );
700         $evt = OpenILS::Event->new( 'ASSET_CALL_NUMBER_NOT_FOUND', id => $id ) unless $cn;
701
702         return ( $cn, $evt );
703 }
704
705 my %ORG_CACHE; # - these rarely change, so cache them..
706 sub fetch_org_unit {
707         my( $self, $id ) = @_;
708         return $id if( ref($id) eq 'Fieldmapper::actor::org_unit' );
709         return $ORG_CACHE{$id} if $ORG_CACHE{$id};
710         $logger->debug("Fetching org unit $id");
711         my $evt = undef;
712
713         my $org = $self->simplereq(
714                 'open-ils.storage', 
715                 'open-ils.storage.direct.actor.org_unit.retrieve', $id );
716         $evt = OpenILS::Event->new( 'ACTOR_ORG_UNIT_NOT_FOUND', id => $id ) unless $org;
717         $ORG_CACHE{$id}  = $org;
718
719         return ($org, $evt);
720 }
721
722 sub fetch_stat_cat {
723         my( $self, $type, $id ) = @_;
724         my( $cat, $evt );
725         $logger->debug("Fetching $type stat cat: $id");
726         $cat = $self->simplereq(
727                 'open-ils.storage', 
728                 "open-ils.storage.direct.$type.stat_cat.retrieve", $id );
729
730         my $e = 'ASSET_STAT_CAT_NOT_FOUND';
731         $e = 'ACTOR_STAT_CAT_NOT_FOUND' if $type eq 'actor';
732
733         $evt = OpenILS::Event->new( $e, id => $id ) unless $cat;
734         return ( $cat, $evt );
735 }
736
737 sub fetch_stat_cat_entry {
738         my( $self, $type, $id ) = @_;
739         my( $entry, $evt );
740         $logger->debug("Fetching $type stat cat entry: $id");
741         $entry = $self->simplereq(
742                 'open-ils.storage', 
743                 "open-ils.storage.direct.$type.stat_cat_entry.retrieve", $id );
744
745         my $e = 'ASSET_STAT_CAT_ENTRY_NOT_FOUND';
746         $e = 'ACTOR_STAT_CAT_ENTRY_NOT_FOUND' if $type eq 'actor';
747
748         $evt = OpenILS::Event->new( $e, id => $id ) unless $entry;
749         return ( $entry, $evt );
750 }
751
752
753 sub find_org {
754         my( $self, $org_tree, $orgid )  = @_;
755         return $org_tree if ( $org_tree->id eq $orgid );
756         return undef unless ref($org_tree->children);
757         for my $c (@{$org_tree->children}) {
758                 my $o = $self->find_org($c, $orgid);
759                 return $o if $o;
760         }
761         return undef;
762 }
763
764 sub fetch_non_cat_type_by_name_and_org {
765         my( $self, $name, $orgId ) = @_;
766         $logger->debug("Fetching non cat type $name at org $orgId");
767         my $types = $self->simplereq(
768                 'open-ils.storage',
769                 'open-ils.storage.direct.config.non_cataloged_type.search_where.atomic',
770                 { name => $name, owning_lib => $orgId } );
771         return ($types->[0], undef) if($types and @$types);
772         return (undef, OpenILS::Event->new('CONFIG_NON_CATALOGED_TYPE_NOT_FOUND') );
773 }
774
775 sub fetch_non_cat_type {
776         my( $self, $id ) = @_;
777         $logger->debug("Fetching non cat type $id");
778         my( $type, $evt );
779         $type = $self->simplereq(
780                 'open-ils.storage', 
781                 'open-ils.storage.direct.config.non_cataloged_type.retrieve', $id );
782         $evt = OpenILS::Event->new('CONFIG_NON_CATALOGED_TYPE_NOT_FOUND') unless $type;
783         return ($type, $evt);
784 }
785
786 sub DB_UPDATE_FAILED { 
787         my( $self, $payload ) = @_;
788         return OpenILS::Event->new('DATABASE_UPDATE_FAILED', 
789                 payload => ($payload) ? $payload : undef ); 
790 }
791
792 sub fetch_circ_duration_by_name {
793         my( $self, $name ) = @_;
794         my( $dur, $evt );
795         $dur = $self->simplereq(
796                 'open-ils.storage', 
797                 'open-ils.storage.direct.config.rules.circ_duration.search.name.atomic', $name );
798         $dur = $dur->[0];
799         $evt = OpenILS::Event->new('CONFIG_RULES_CIRC_DURATION_NOT_FOUND') unless $dur;
800         return ($dur, $evt);
801 }
802
803 sub fetch_recurring_fine_by_name {
804         my( $self, $name ) = @_;
805         my( $obj, $evt );
806         $obj = $self->simplereq(
807                 'open-ils.storage', 
808                 'open-ils.storage.direct.config.rules.recuring_fine.search.name.atomic', $name );
809         $obj = $obj->[0];
810         $evt = OpenILS::Event->new('CONFIG_RULES_RECURING_FINE_NOT_FOUND') unless $obj;
811         return ($obj, $evt);
812 }
813
814 sub fetch_max_fine_by_name {
815         my( $self, $name ) = @_;
816         my( $obj, $evt );
817         $obj = $self->simplereq(
818                 'open-ils.storage', 
819                 'open-ils.storage.direct.config.rules.max_fine.search.name.atomic', $name );
820         $obj = $obj->[0];
821         $evt = OpenILS::Event->new('CONFIG_RULES_MAX_FINE_NOT_FOUND') unless $obj;
822         return ($obj, $evt);
823 }
824
825 sub storagereq {
826         my( $self, $method, @params ) = @_;
827         return $self->simplereq(
828                 'open-ils.storage', $method, @params );
829 }
830
831 sub event_equals {
832         my( $self, $e, $name ) =  @_;
833         if( $e and ref($e) eq 'HASH' and 
834                 defined($e->{textcode}) and $e->{textcode} eq $name ) {
835                 return 1 ;
836         }
837         return 0;
838 }
839
840 sub logmark {
841         my( undef, $f, $l ) = caller(0);
842         my( undef, undef, undef, $s ) = caller(1);
843         $s =~ s/.*:://g;
844         $f =~ s/.*\///g;
845         $logger->debug("LOGMARK: $f:$l:$s");
846 }
847
848 # takes a copy id 
849 sub fetch_open_circulation {
850         my( $self, $cid ) = @_;
851         my $evt;
852         $self->logmark;
853         my $circ = $self->storagereq(
854                 'open-ils.storage.direct.action.open_circulation.search_where',
855                 { target_copy => $cid, stop_fines_time => undef } );
856         $evt = OpenILS::Event->new('ACTION_CIRCULATION_NOT_FOUND') unless $circ;        
857         return ($circ, $evt);
858 }
859
860 sub fetch_all_open_circulation {
861         my( $self, $cid ) = @_;
862         my $evt;
863         $self->logmark;
864         my $circ = $self->storagereq(
865                 'open-ils.storage.direct.action.open_circulation.search_where',
866                 { target_copy => $cid, xact_finish => undef } );
867         $evt = OpenILS::Event->new('ACTION_CIRCULATION_NOT_FOUND') unless $circ;        
868         return ($circ, $evt);
869 }
870
871 my $copy_statuses;
872 sub copy_status_from_name {
873         my( $self, $name ) = @_;
874         $copy_statuses = $self->fetch_copy_statuses unless $copy_statuses;
875         for my $status (@$copy_statuses) { 
876                 return $status if( $status->name =~ /$name/i );
877         }
878         return undef;
879 }
880
881 sub copy_status_to_name {
882         my( $self, $sid ) = @_;
883         $copy_statuses = $self->fetch_copy_statuses unless $copy_statuses;
884         for my $status (@$copy_statuses) { 
885                 return $status->name if( $status->id == $sid );
886         }
887         return undef;
888 }
889
890 sub fetch_open_transit_by_copy {
891         my( $self, $copyid ) = @_;
892         my($transit, $evt);
893         $transit = $self->storagereq(
894                 'open-ils.storage.direct.action.transit_copy.search_where',
895                 { target_copy => $copyid, dest_recv_time => undef });
896         $evt = OpenILS::Event->new('ACTION_TRANSIT_COPY_NOT_FOUND') unless $transit;
897         return ($transit, $evt);
898 }
899
900 sub unflesh_copy {
901         my( $self, $copy ) = @_;
902         return undef unless $copy;
903         $copy->status( $copy->status->id ) if ref($copy->status);
904         $copy->location( $copy->location->id ) if ref($copy->location);
905         $copy->circ_lib( $copy->circ_lib->id ) if ref($copy->circ_lib);
906         return $copy;
907 }
908
909 # un-fleshes a copy and updates it in the DB
910 # returns a DB_UPDATE_FAILED event on error
911 # returns undef on success
912 sub update_copy {
913         my( $self, %params ) = @_;
914
915         my $copy                = $params{copy} || die "update_copy(): copy required";
916         my $editor      = $params{editor} || die "update_copy(): copy editor required";
917         my $session = $params{session};
918
919         $logger->debug("Updating copy in the database: " . $copy->id);
920
921         $self->unflesh_copy($copy);
922         $copy->editor( $editor );
923         $copy->edit_date( 'now' );
924
925         my $s;
926         my $meth = 'open-ils.storage.direct.asset.copy.update';
927
928         $s = $session->request( $meth, $copy )->gather(1) if $session;
929         $s = $self->storagereq( $meth, $copy ) unless $session;
930
931         $logger->debug("Update of copy ".$copy->id." returned: $s");
932
933         return $self->DB_UPDATE_FAILED($copy) unless $s;
934         return undef;
935 }
936
937 sub fetch_billable_xact {
938         my( $self, $id ) = @_;
939         my($xact, $evt);
940         $logger->debug("Fetching billable transaction %id");
941         $xact = $self->storagereq(
942                 'open-ils.storage.direct.money.billable_transaction.retrieve', $id );
943         $evt = OpenILS::Event->new('MONEY_BILLABLE_TRANSACTION_NOT_FOUND') unless $xact;
944         return ($xact, $evt);
945 }
946
947
948 sub fetch_fleshed_copy {
949         my( $self, $id ) = @_;
950         my( $copy, $evt );
951         $logger->info("Fetching fleshed copy $id");
952         $copy = $self->storagereq(
953                 "open-ils.storage.fleshed.asset.copy.retrieve", $id );
954         $evt = OpenILS::Event->new('ASSET_COPY_NOT_FOUND', id => $id) unless $copy;
955         return ($copy, $evt);
956 }
957
958
959 # returns the org that owns the callnumber that the copy
960 # is attached to
961 sub fetch_copy_owner {
962         my( $self, $copyid ) = @_;
963         my( $copy, $cn, $evt );
964         $logger->debug("Fetching copy owner $copyid");
965         ($copy, $evt) = $self->fetch_copy($copyid);
966         return (undef,$evt) if $evt;
967         ($cn, $evt) = $self->fetch_callnumber($copy->call_number);
968         return (undef,$evt) if $evt;
969         return ($cn->owning_lib);
970 }
971
972 sub fetch_copy_note {
973         my( $self, $id ) = @_;
974         my( $note, $evt );
975         $logger->debug("Fetching copy note $id");
976         $note = $self->storagereq(
977                 'open-ils.storage.direct.asset.copy_note.retrieve', $id );
978         $evt = OpenILS::Event->new('ASSET_COPY_NOTE_NOT_FOUND', id => $id ) unless $note;
979         return ($note, $evt);
980 }
981
982 sub fetch_call_numbers_by_title {
983         my( $self, $titleid ) = @_;
984         $logger->info("Fetching call numbers by title $titleid");
985         return $self->storagereq(
986                 'open-ils.storage.direct.asset.call_number.search_where.atomic', 
987                 { record => $titleid, deleted => 'f' });
988                 #'open-ils.storage.direct.asset.call_number.search.record.atomic', $titleid);
989 }
990
991 sub fetch_copies_by_call_number {
992         my( $self, $cnid ) = @_;
993         $logger->info("Fetching copies by call number $cnid");
994         return $self->storagereq(
995                 'open-ils.storage.direct.asset.copy.search_where.atomic', { call_number => $cnid, deleted => 'f' } );
996                 #'open-ils.storage.direct.asset.copy.search.call_number.atomic', $cnid );
997 }
998
999 sub fetch_user_by_barcode {
1000         my( $self, $bc ) = @_;
1001         my $cardid = $self->storagereq(
1002                 'open-ils.storage.id_list.actor.card.search.barcode', $bc );
1003         return (undef, OpenILS::Event->new('ACTOR_CARD_NOT_FOUND', barcode => $bc)) unless $cardid;
1004         my $user = $self->storagereq(
1005                 'open-ils.storage.direct.actor.user.search.card', $cardid );
1006         return (undef, OpenILS::Event->new('ACTOR_USER_NOT_FOUND', card => $cardid)) unless $user;
1007         return ($user);
1008         
1009 }
1010
1011
1012 # ---------------------------------------------------------------------
1013 # Updates and returns the patron penalties
1014 # ---------------------------------------------------------------------
1015 sub update_patron_penalties {
1016         my( $self, %args ) = @_;
1017         return $self->simplereq(
1018                 'open-ils.penalty',
1019                 'open-ils.penalty.patron_penalty.calculate', 
1020                 { update => 1, %args }
1021         );
1022 }
1023
1024 sub fetch_bill {
1025         my( $self, $billid ) = @_;
1026         $logger->debug("Fetching billing $billid");
1027         my $bill = $self->storagereq(
1028                 'open-ils.storage.direct.money.billing.retrieve', $billid );
1029         my $evt = OpenILS::Event->new('MONEY_BILLING_NOT_FOUND') unless $bill;
1030         return($bill, $evt);
1031 }
1032
1033
1034
1035
1036 1;
1037