a6cf784c353b6faff4c5b541b6f20b908ad8a415
[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 my $logger = "OpenSRF::Utils::Logger";
11
12
13 my $cache_client = "OpenSRF::Utils::Cache";
14
15 # ---------------------------------------------------------------------------
16 # Pile of utilty methods used accross applications.
17 # ---------------------------------------------------------------------------
18
19
20 # ---------------------------------------------------------------------------
21 # on sucess, returns the created session, on failure throws ERROR exception
22 # ---------------------------------------------------------------------------
23 sub start_db_session {
24
25         my $self = shift;
26         my $session = OpenSRF::AppSession->connect( "open-ils.storage" );
27         my $trans_req = $session->request( "open-ils.storage.transaction.begin" );
28
29         my $trans_resp = $trans_req->recv();
30         if(ref($trans_resp) and UNIVERSAL::isa($trans_resp,"Error")) { throw $trans_resp; }
31         if( ! $trans_resp->content() ) {
32                 throw OpenSRF::ERROR 
33                         ("Unable to Begin Transaction with database" );
34         }
35         $trans_req->finish();
36         return $session;
37 }
38
39
40 # returns undef if user has all of the perms provided
41 # returns the first failed perm on failure
42 sub check_user_perms {
43         my($self, $user_id, $org_id, @perm_types ) = @_;
44
45         $logger->debug("Checking perms with user : $user_id , org: $org_id, @perm_types");
46
47         throw OpenSRF::EX::ERROR ("Invalid call to check_user_perms()")
48                 unless( defined($user_id) and defined($org_id) and @perm_types); 
49
50         my $session = OpenSRF::AppSession->create("open-ils.storage");
51         for my $type (@perm_types) {
52                 my $req = $session->request(
53                         "open-ils.storage.permission.user_has_perm", 
54                         $user_id, $type, $org_id );
55                 my $resp = $req->gather(1);
56                 if(!$resp) { 
57                         $session->disconnect();
58                         return $type; 
59                 }
60         }
61
62         $session->disconnect();
63         return undef;
64 }
65
66 # checks the list of user perms.  The first one that fails returns a new
67 # OpenILS::Perm object of that type.  Returns undef if all perms are allowed
68 sub check_perms {
69         my( $self, $user_id, $org_id, @perm_types ) = @_;
70         my $t = $self->check_user_perms( $user_id, $org_id, @perm_types );
71         return OpenILS::Event->new('PERM_FAILURE', ilsperm => $t, ilspermloc => $org_id ) if $t;
72         return undef;
73 }
74
75
76
77 # ---------------------------------------------------------------------------
78 # commits and destroys the session
79 # ---------------------------------------------------------------------------
80 sub commit_db_session {
81         my( $self, $session ) = @_;
82
83         my $req = $session->request( "open-ils.storage.transaction.commit" );
84         my $resp = $req->recv();
85
86         if(!$resp) {
87                 throw OpenSRF::EX::ERROR ("Unable to commit db session");
88         }
89
90         if(UNIVERSAL::isa($resp,"Error")) { 
91                 throw $resp ($resp->stringify); 
92         }
93
94         if(!$resp->content) {
95                 throw OpenSRF::EX::ERROR ("Unable to commit db session");
96         }
97
98         $session->finish();
99         $session->disconnect();
100         $session->kill_me();
101 }
102
103 sub rollback_db_session {
104         my( $self, $session ) = @_;
105
106         my $req = $session->request("open-ils.storage.transaction.rollback");
107         my $resp = $req->recv();
108         if(UNIVERSAL::isa($resp,"Error")) { throw $resp;  }
109
110         $session->finish();
111         $session->disconnect();
112         $session->kill_me();
113 }
114
115
116 # returns undef it the event is not an ILS event
117 # returns the event code otherwise
118 sub event_code {
119         my( $self, $evt ) = @_;
120         return $evt->{ilsevent} if( ref($evt) eq 'HASH' and defined($evt->{ilsevent})) ;
121         return undef;
122 }
123
124 # ---------------------------------------------------------------------------
125 # Checks to see if a user is logged in.  Returns the user record on success,
126 # throws an exception on error.
127 # ---------------------------------------------------------------------------
128 sub check_user_session {
129
130         my( $self, $user_session ) = @_;
131
132         my $content = $self->simplereq( 
133                 'open-ils.auth', 
134                 'open-ils.auth.session.retrieve', $user_session );
135
136
137         if(! $content or $self->event_code($content)) {
138                 throw OpenSRF::EX::ERROR 
139                         ("Session [$user_session] cannot be authenticated" );
140         }
141
142         $logger->debug("Fetch user session $user_session found user " . $content->id );
143
144         return $content;
145 }
146
147 # generic simple request returning a scalar value
148 sub simplereq {
149         my($self, $service, $method, @params) = @_;
150         return $self->simple_scalar_request($service, $method, @params);
151 }
152
153
154 sub simple_scalar_request {
155         my($self, $service, $method, @params) = @_;
156
157         my $session = OpenSRF::AppSession->create( $service );
158         my $request = $session->request( $method, @params );
159         my $response = $request->recv(30);
160
161         $request->wait_complete;
162
163         if(!$request->complete) {
164                 throw OpenSRF::EX::ERROR ("Call to $service for method $method with params @params" . 
165                                 "\n did not complete successfully");
166         }
167
168         if(!$response) {
169                 warn "No response from $service for method $method with params @params";
170         }
171
172         if(UNIVERSAL::isa($response,"Error")) {
173                 throw $response ("Call to $service for method $method with params @params" . 
174                                 "\n failed with exception: " . $response->stringify );
175         }
176
177
178         $request->finish();
179         $session->finish();
180         $session->disconnect();
181
182         my $value;
183
184         if($response) { $value = $response->content; }
185         else { $value = undef; }
186
187         return $value;
188 }
189
190
191
192
193
194 my $tree                                                = undef;
195 my $orglist                                     = undef;
196 my $org_typelist                        = undef;
197 my $org_typelist_hash   = {};
198
199 sub get_org_tree {
200
201         my $self = shift;
202         if($tree) { return $tree; }
203
204         # see if it's in the cache
205         $tree = $cache_client->new()->get_cache('_orgtree');
206         if($tree) { return $tree; }
207
208         if(!$orglist) {
209                 warn "Retrieving Org Tree\n";
210                 $orglist = $self->simple_scalar_request( 
211                         "open-ils.storage", 
212                         "open-ils.storage.direct.actor.org_unit.retrieve.all.atomic" );
213         }
214
215         if( ! $org_typelist ) {
216                 warn "Retrieving org types\n";
217                 $org_typelist = $self->simple_scalar_request( 
218                         "open-ils.storage", 
219                         "open-ils.storage.direct.actor.org_unit_type.retrieve.all.atomic" );
220                 $self->build_org_type($org_typelist);
221         }
222
223         $tree = $self->build_org_tree($orglist,1);
224         $cache_client->new()->put_cache('_orgtree', $tree);
225         return $tree;
226
227 }
228
229 my $slimtree = undef;
230 sub get_slim_org_tree {
231
232         my $self = shift;
233         if($slimtree) { return $slimtree; }
234
235         # see if it's in the cache
236         $slimtree = $cache_client->new()->get_cache('slimorgtree');
237         if($slimtree) { return $slimtree; }
238
239         if(!$orglist) {
240                 warn "Retrieving Org Tree\n";
241                 $orglist = $self->simple_scalar_request( 
242                         "open-ils.storage", 
243                         "open-ils.storage.direct.actor.org_unit.retrieve.all.atomic" );
244         }
245
246         $slimtree = $self->build_org_tree($orglist);
247         $cache_client->new->put_cache('slimorgtree', $slimtree);
248         return $slimtree;
249
250 }
251
252
253 sub build_org_type { 
254         my($self, $org_typelist)  = @_;
255         for my $type (@$org_typelist) {
256                 $org_typelist_hash->{$type->id()} = $type;
257         }
258 }
259
260
261
262 sub build_org_tree {
263
264         my( $self, $orglist, $add_types ) = @_;
265
266         return $orglist unless ( 
267                         ref($orglist) and @$orglist > 1 );
268
269         my @list = sort { 
270                 $a->ou_type <=> $b->ou_type ||
271                 $a->name cmp $b->name } @$orglist;
272
273         for my $org (@list) {
274
275                 next unless ($org);
276
277                 if(!ref($org->ou_type()) and $add_types) {
278                         $org->ou_type( $org_typelist_hash->{$org->ou_type()});
279                 }
280
281                 next unless (defined($org->parent_ou));
282
283                 my ($parent) = grep { $_->id == $org->parent_ou } @list;
284                 next unless $parent;
285                 $parent->children([]) unless defined($parent->children); 
286                 push( @{$parent->children}, $org );
287         }
288
289         return $list[0];
290
291 }
292
293 sub fetch_user {
294         my( $self, $userid ) = @_;
295         my( $user, $evt );
296
297         $logger->debug("Fetching user $userid from storage");
298
299         $user = $self->simplereq(
300                 'open-ils.storage',
301                 'open-ils.storage.direct.actor.user.retrieve', $userid );
302
303         if(!$user) {
304                 $logger->info("User $userid not found in the db");
305                 $evt = OpenILS::Event->new('USER_NOT_FOUND');
306         }
307
308         return ($user, $evt);
309 }
310
311 sub checkses {
312         my( $self, $session ) = @_;
313         my $user; my $evt; my $e; 
314
315         $logger->debug("Checking user session $session");
316
317         try {
318                 $user = $self->check_user_session($session);
319         } catch Error with { $e = 1; };
320
321         if( $e or !$user ) { $evt = OpenILS::Event->new('NO_SESSION'); }
322         return ( $user, $evt );
323 }
324
325
326 # verifiese the session and checks the permissions agains the
327 # session user and the user's home_ou as the org id
328 sub checksesperm {
329         my( $self, $session, @perms ) = @_;
330         my $user; my $evt; my $e; 
331         $logger->debug("Checking user session $session and perms @perms");
332         ($user, $evt) = $self->checkses($session);
333         return (undef, $evt) if $evt;
334         $evt = $self->check_perms($user->id, $user->home_ou, @perms);
335         return ($user, $evt);
336 }
337
338
339 sub checkrequestor {
340         my( $self, $staffobj, $userid, @perms ) = @_;
341         my $user; my $evt;
342         $userid = $staffobj->id unless defined $userid;
343
344         $logger->debug("checkrequestor(): requestor => " . $staffobj->id . ", target => $userid");
345
346         if( $userid ne $staffobj->id ) {
347                 ($user, $evt) = $self->fetch_user($userid);
348                 return (undef, $evt) if $evt;
349                 $evt = $self->check_perms( $staffobj->id, $user->home_ou, @perms );
350
351         } else {
352                 $user = $staffobj;
353         }
354
355         return ($user, $evt);
356 }
357
358 sub checkses_requestor {
359         my( $self, $authtoken, $targetid, @perms ) = @_;
360         my( $requestor, $target, $evt );
361
362         ($requestor, $evt) = $self->checkses($authtoken);
363         return (undef, undef, $evt) if $evt;
364
365         ($target, $evt) = $self->checkrequestor( $requestor, $targetid, @perms );
366         return( $requestor, $target, $evt);
367 }
368
369 sub fetch_copy {
370         my( $self, $copyid ) = @_;
371         my( $copy, $evt );
372
373         $logger->debug("Fetching copy $copyid from storage");
374
375         $copy = $self->simplereq(
376                 'open-ils.storage',
377                 'open-ils.storage.direct.asset.copy.retrieve', $copyid );
378
379         if(!$copy) { $evt = OpenILS::Event->new('COPY_NOT_FOUND'); }
380
381         return( $copy, $evt );
382 }
383
384
385 # retrieves a circ object by id
386 sub fetch_circulation {
387         my( $self, $circid ) = @_;
388         my $circ; my $evt;
389         
390         $logger->debug("Fetching circ $circid from storage");
391
392         $circ = $self->simplereq(
393                 'open-ils.storage',
394                 "open-ils.storage.direct.action.circulation.retrieve", $circid );
395
396         if(!$circ) {
397                 $evt = OpenILS::Event->new('CIRCULATION_NOT_FOUND', circid => $circid );
398         }
399
400         return ( $circ, $evt );
401 }
402
403 sub fetch_record_by_copy {
404         my( $self, $copyid ) = @_;
405         my( $record, $evt );
406
407         $logger->debug("Fetching record by copy $copyid from storage");
408
409         $record = $self->simplereq(
410                 'open-ils.storage',
411                 'open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy', $copyid );
412
413         if(!$record) {
414                 $evt = OpenILS::Event->new('BIBLIO_RECORD_NOT_FOUND');
415         }
416
417         return ($record, $evt);
418 }
419
420 # turns a record object into an mvr (mods) object
421 sub record_to_mvr {
422         my( $self, $record ) = @_;
423         my $u = OpenILS::Utils::ModsParser->new();
424         $u->start_mods_batch( $record->marc );
425         my $mods = $u->finish_mods_batch();
426         $mods->doc_id($record->id);
427         return $mods;
428 }
429
430 sub fetch_hold {
431         my( $self, $holdid ) = @_;
432         my( $hold, $evt );
433
434         $logger->debug("Fetching hold $holdid from storage");
435
436         $hold = $self->simplereq(
437                 'open-ils.storage',
438                 'open-ils.storage.direct.action.hold_request.retrieve', $holdid);
439
440         $evt = OpenILS::Event->new('HOLD_NOT_FOUND', holdid => $holdid) unless $hold;
441
442         return ($hold, $evt);
443 }
444
445
446 sub fetch_hold_transit_by_hold {
447         my( $self, $holdid ) = @_;
448         my( $transit, $evt );
449
450         $logger->debug("Fetching transit by hold $holdid from storage");
451
452         $transit = $self->simplereq(
453                 'open-ils.storage',
454                 'open-ils.storage.direct.action.hold_transit_copy.search.hold', $holdid );
455
456         $evt = OpenILS::Event->new('TRANSIT_NOT_FOUND', holdid => $holdid) unless $transit;
457
458         return ($transit, $evt );
459 }
460
461
462 sub fetch_copy_by_barcode {
463         my( $self, $barcode ) = @_;
464         my( $copy, $evt );
465
466         $logger->debug("Fetching copy by barcode $barcode from storage");
467
468         $copy = $self->simplereq( 'open-ils.storage',
469                 'open-ils.storage.direct.asset.copy.search.barcode', $barcode );
470
471         $evt = OpenILS::Event->new('COPY_NOT_FOUND', barcode => $barcode) unless $copy;
472
473         return ($copy, $evt);
474 }
475
476 sub fetch_open_billable_transaction {
477         my( $self, $transid ) = @_;
478         my( $transaction, $evt );
479
480         $logger->debug("Fetching open billable transaction $transid from storage");
481
482         $transaction = $self->simplereq(
483                 'open-ils.storage',
484                 'open-ils.storage.direct.money.open_billable_transaction_summary.retrieve',  $transid);
485
486         $evt = OpenILS::Event->new(
487                 'TRANSACTION_NOT_FOUND', transid => $transid ) unless $transaction;
488
489         return ($transaction, $evt);
490 }
491
492
493
494 my %buckets;
495 $buckets{'biblio'} = 'biblio_record_entry_bucket';
496 $buckets{'callnumber'} = 'call_number_bucket';
497 $buckets{'copy'} = 'copy_bucket';
498 $buckets{'user'} = 'user_bucket';
499
500 sub fetch_container {
501         my( $self, $id, $type ) = @_;
502         my( $bucket, $evt );
503
504         $logger->debug("Fetching container $id with type $type");
505
506         my $meth = $buckets{$type};
507         $bucket = $self->simplereq(
508                 'open-ils.storage',
509                 "open-ils.storage.direct.container.$meth.retrieve", $id );
510
511         $evt = OpenILS::Event->new(
512                 'CONTAINER_NOT_FOUND', container => $id, 
513                         container_type => $type ) unless $bucket;
514
515         return ($bucket, $evt);
516 }
517
518
519 sub fetch_container_item {
520         my( $self, $id, $type ) = @_;
521         my( $bucket, $evt );
522
523         $logger->debug("Fetching container item $id with type $type");
524
525         my $meth = $buckets{$type} . "_item";
526
527         $bucket = $self->simplereq(
528                 'open-ils.storage',
529                 "open-ils.storage.direct.container.$meth.retrieve", $id );
530
531         $evt = OpenILS::Event->new(
532                 'CONTAINER_ITEM_NOT_FOUND', itemid => $id, 
533                         container_type => $type ) unless $bucket;
534
535         return ($bucket, $evt);
536 }
537
538
539 sub fetch_patron_standings {
540         my $self = shift;
541         $logger->debug("Fetching patron standings");    
542         return $self->simplereq(
543                 'open-ils.storage', 
544                 'open-ils.storage.direct.config.standing.retrieve.all.atomic');
545 }
546
547
548 sub fetch_permission_group_tree {
549         my $self = shift;
550         $logger->debug("Fetching patron profiles");     
551         return $self->simplereq(
552                 'open-ils.actor', 
553                 'open-ils.actor.groups.tree.retrieve' );
554 }
555
556
557 sub fetch_patron_circ_summary {
558         my( $self, $userid ) = @_;
559         $logger->debug("Fetching patron summary for $userid");
560         my $summary = $self->simplereq(
561                 'open-ils.storage', 
562                 "open-ils.storage.action.circulation.patron_summary", $userid );
563
564         if( $summary ) {
565                 $summary->[0] ||= 0;
566                 $summary->[1] ||= 0.0;
567                 return $summary;
568         }
569         return undef;
570 }
571
572
573 sub fetch_copy_statuses {
574         my( $self ) = @_;
575         $logger->debug("Fetching copy statuses");
576         return $self->simplereq(
577                 'open-ils.storage', 
578                 'open-ils.storage.direct.config.copy_status.retrieve.all.atomic' );
579 }
580
581 sub fetch_copy_location {
582         my( $self, $id ) = @_;
583         my $evt;
584         my $cl = $self->storagereq(
585                 'open-ils.storage.direct.asset.copy_location.retrieve', $id );
586         $evt = OpenILS::Event->new('COPY_LOCATION_NOT_FOUND') unless $cl;
587         return ($cl, $evt);
588 }
589
590 sub fetch_copy_locations {
591         my $self = shift; 
592         return $self->simplereq(
593                 'open-ils.storage', 
594                 'open-ils.storage.direct.asset.copy_location.retrieve.all.atomic');
595 }
596
597 sub fetch_copy_location_by_name {
598         my( $self, $name, $org ) = @_;
599         my $evt;
600         my $cl = $self->storagereq(
601                 'open-ils.storage.direct.asset.copy_location.search_where',
602                         { name => $name, owning_lib => $org } );
603         $evt = OpenILS::Event->new('COPY_LOCATION_NOT_FOUND') unless $cl;
604         return ($cl, $evt);
605 }
606
607 sub fetch_callnumber {
608         my( $self, $id ) = @_;
609         my $evt = undef;
610         $logger->debug("Fetching callnumber $id");
611
612         my $cn = $self->simplereq(
613                 'open-ils.storage',
614                 'open-ils.storage.direct.asset.call_number.retrieve', $id );
615         $evt = OpenILS::Event->new( 'VOLUME_NOT_FOUND', id => $id ) unless $cn;
616
617         return ( $cn, $evt );
618 }
619
620 sub fetch_org_unit {
621         my( $self, $id ) = @_;
622         return $id if( ref($id) eq 'Fieldmapper::actor::org_unit' );
623         $logger->debug("Fetching org unit $id");
624         my $evt = undef;
625
626         my $org = $self->simplereq(
627                 'open-ils.storage', 
628                 'open-ils.storage.direct.actor.org_unit.retrieve', $id );
629         $evt = OpenILS::Event->new( 'ORG_UNIT_NOT_FOUND', id => $id ) unless $org;
630
631         return ($org, $evt);
632 }
633
634 sub fetch_stat_cat {
635         my( $self, $type, $id ) = @_;
636         my( $cat, $evt );
637         $logger->debug("Fetching $type stat cat: $id");
638         $cat = $self->simplereq(
639                 'open-ils.storage', 
640                 "open-ils.storage.direct.$type.stat_cat.retrieve", $id );
641         $evt = OpenILS::Event->new( 'STAT_CAT_NOT_FOUND', id => $id ) unless $cat;
642         return ( $cat, $evt );
643 }
644
645 sub fetch_stat_cat_entry {
646         my( $self, $type, $id ) = @_;
647         my( $entry, $evt );
648         $logger->debug("Fetching $type stat cat entry: $id");
649         $entry = $self->simplereq(
650                 'open-ils.storage', 
651                 "open-ils.storage.direct.$type.stat_cat_entry.retrieve", $id );
652         $evt = OpenILS::Event->new( 'STAT_CAT_ENTRY_NOT_FOUND', id => $id ) unless $entry;
653         return ( $entry, $evt );
654 }
655
656
657 sub find_org {
658         my( $self, $org_tree, $orgid )  = @_;
659         return $org_tree if ( $org_tree->id eq $orgid );
660         return undef unless ref($org_tree->children);
661         for my $c (@{$org_tree->children}) {
662                 my $o = $self->find_org($c, $orgid);
663                 return $o if $o;
664         }
665         return undef;
666 }
667
668 sub fetch_non_cat_type_by_name_and_org {
669         my( $self, $name, $orgId ) = @_;
670         $logger->debug("Fetching non cat type $name at org $orgId");
671         my $types = $self->simplereq(
672                 'open-ils.storage',
673                 'open-ils.storage.direct.config.non_cataloged_type.search_where.atomic',
674                 { name => $name, owning_lib => $orgId } );
675         return ($types->[0], undef) if($types and @$types);
676         return (undef, OpenILS::Event->new('NON_CAT_TYPE_NOT_FOUND') );
677 }
678
679 sub fetch_non_cat_type {
680         my( $self, $id ) = @_;
681         $logger->debug("Fetching non cat type $id");
682         my( $type, $evt );
683         $type = $self->simplereq(
684                 'open-ils.storage', 
685                 'open-ils.storage.direct.config.non_cataloged_type.retrieve', $id );
686         $evt = OpenILS::Event->new('NON_CAT_TYPE_NOT_FOUND') unless $type;
687         return ($type, $evt);
688 }
689
690 sub DB_UPDATE_FAILED { 
691         my( $self, $payload ) = @_;
692         return OpenILS::Event->new('DATABASE_UPDATE_FAILED', 
693                 payload => ($payload) ? $payload : undef ); 
694 }
695
696 sub fetch_circ_duration_by_name {
697         my( $self, $name ) = @_;
698         my( $dur, $evt );
699         $dur = $self->simplereq(
700                 'open-ils.storage', 
701                 'open-ils.storage.direct.config.rules.circ_duration.search.name.atomic', $name );
702         $dur = $dur->[0];
703         $evt = OpenILS::Event->new('CIRC_DURATION_NOT_FOUND') unless $dur;
704         return ($dur, $evt);
705 }
706
707 sub fetch_recurring_fine_by_name {
708         my( $self, $name ) = @_;
709         my( $obj, $evt );
710         $obj = $self->simplereq(
711                 'open-ils.storage', 
712                 'open-ils.storage.direct.config.rules.recuring_fine.search.name.atomic', $name );
713         $obj = $obj->[0];
714         $evt = OpenILS::Event->new('RECURRING_FINE_NOT_FOUND') unless $obj;
715         return ($obj, $evt);
716 }
717
718 sub fetch_max_fine_by_name {
719         my( $self, $name ) = @_;
720         my( $obj, $evt );
721         $obj = $self->simplereq(
722                 'open-ils.storage', 
723                 'open-ils.storage.direct.config.rules.max_fine.search.name.atomic', $name );
724         $obj = $obj->[0];
725         $evt = OpenILS::Event->new('MAX_FINE_NOT_FOUND') unless $obj;
726         return ($obj, $evt);
727 }
728
729 sub storagereq {
730         my( $self, $method, @params ) = @_;
731         return $self->simplereq(
732                 'open-ils.storage', $method, @params );
733 }
734
735 sub event_equals {
736         my( $self, $e, $name ) =  @_;
737         if( $e and ref($e) eq 'HASH' and 
738                 defined($e->{textcode}) and $e->{textcode} eq $name ) {
739                 return 1 ;
740         }
741         return 0;
742 }
743
744 sub logmark {
745         my( undef, $f, $l ) = caller(0);
746         my( undef, undef, undef, $s ) = caller(1);
747         $s =~ s/.*:://g;
748         $f =~ s/.*\///g;
749         $logger->debug("LOGMARK: $f:$l:$s");
750 }
751
752 # takes a copy id 
753 sub fetch_open_circulation {
754         my( $self, $cid ) = @_;
755         my $evt;
756         $self->logmark;
757         my $circ = $self->storagereq(
758                 'open-ils.storage.direct.action.open_circulation.search_where',
759                 { target_copy => $cid, stop_fines_time => undef } );
760         $evt = OpenILS::Event->new('CIRCULATION_NOT_FOUND') unless $circ;       
761         return ($circ, $evt);
762 }
763
764
765 1;
766