]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher/actor.pm
lost/expired/barred/blocked lists are now streaming, as they could be huge
[Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Storage / Publisher / actor.pm
1 package OpenILS::Application::Storage::Publisher::actor;
2 use base qw/OpenILS::Application::Storage/;
3 use OpenILS::Application::Storage::CDBI::actor;
4 use OpenSRF::Utils::Logger qw/:level/;
5 use OpenILS::Utils::Fieldmapper;
6
7 my $log = 'OpenSRF::Utils::Logger';
8
9 sub user_by_barcode {
10         my $self = shift;
11         my $client = shift;
12         my @barcodes = shift;
13
14         return undef unless @barcodes;
15
16         for my $card ( actor::card->search( { barcode => @barcodes } ) ) {
17                 next unless $card;
18                 if (@barcodes == 1) {
19                         return $card->usr->to_fieldmapper;
20                 }
21                 $client->respond( $card->usr->to_fieldmapper);
22         }
23         return undef;
24 }
25 __PACKAGE__->register_method(
26         api_name        => 'open-ils.storage.direct.actor.user.search.barcode',
27         api_level       => 1,
28         method          => 'user_by_barcode',
29         stream          => 1,
30         cachable        => 1,
31 );
32
33 sub lost_barcodes {
34         my $self = shift;
35         my $client = shift;
36
37         my $c = actor::card->table;
38         my $p = actor::user->table;
39
40         my $sql = "SELECT c.barcode FROM $c c JOIN $p p ON (c.usr = p.id) WHERE p.card <> c.id";
41
42         my $list = actor::user->db_Main->selectcol_arrayref($sql);
43         for my $bc ( @$list ) {
44                 $client->respond($bc);
45         }
46         return undef;
47 }
48 __PACKAGE__->register_method(
49         api_name        => 'open-ils.storage.actor.user.lost_barcodes',
50         api_level       => 1,
51         stream          => 1,
52         method          => 'lost_barcodes',
53         signature       => <<'  NOTE',
54                 Returns an array of barcodes that belong to lost cards.
55                 @return array of barcodes
56         NOTE
57 );
58
59 sub expired_barcodes {
60         my $self = shift;
61         my $client = shift;
62
63         my $c = actor::card->table;
64         my $p = actor::user->table;
65
66         my $sql = "SELECT c.barcode FROM $c c JOIN $p p ON (c.usr = p.id) WHERE p.expire_date < CURRENT_DATE";
67
68         my $list = actor::user->db_Main->selectcol_arrayref($sql);
69         for my $bc ( @$list ) {
70                 $client->respond($bc);
71         }
72         return undef;
73 }
74 __PACKAGE__->register_method(
75         api_name        => 'open-ils.storage.actor.user.expired_barcodes',
76         api_level       => 1,
77         stream          => 1,
78         method          => 'expired_barcodes',
79         signature       => <<'  NOTE',
80                 Returns an array of barcodes that are currently expired.
81                 @return array of barcodes
82         NOTE
83 );
84
85 sub barred_barcodes {
86         my $self = shift;
87         my $client = shift;
88
89         my $c = actor::card->table;
90         my $p = actor::user->table;
91
92         my $sql = "SELECT c.barcode FROM $c c JOIN $p p ON (c.usr = p.id) WHERE p.barred IS TRUE";
93
94         my $list = actor::user->db_Main->selectcol_arrayref($sql);
95         for my $bc ( @$list ) {
96                 $client->respond($bc);
97         }
98         return undef;
99 }
100 __PACKAGE__->register_method(
101         api_name        => 'open-ils.storage.actor.user.barred_barcodes',
102         api_level       => 1,
103         stream          => 1,
104         method          => 'barred_barcodes',
105         signature       => <<'  NOTE',
106                 Returns an array of barcodes that are currently barred.
107                 @return array of barcodes
108         NOTE
109 );
110
111 sub penalized_barcodes {
112         my $self = shift;
113         my $client = shift;
114         my @ignore = @_;
115
116         my $c = actor::card->table;
117         my $p = actor::user_standing_penalty->table;
118
119         my $sql = "SELECT c.barcode FROM $c c JOIN $p p USING (usr)";
120
121         if (@ignore) {
122                 $sql .= ' WHERE penalty_type NOT IN ('. join(',', map { '?' } @ignore) . ')';
123         }
124
125         $sql .= ' GROUP BY c.barcode;';
126
127         my $list = actor::user->db_Main->selectcol_arrayref($sql, {}, @ignore);
128         for my $bc ( @$list ) {
129                 $client->respond($bc);
130         }
131         return undef;
132 }
133 __PACKAGE__->register_method(
134         api_name        => 'open-ils.storage.actor.user.penalized_barcodes',
135         api_level       => 1,
136         stream          => 1,
137         method          => 'penalized_barcodes',
138         signature       => <<'  NOTE',
139                 Returns an array of barcodes that have penalties not listed
140                 as a parameter.  Supply a list of any penalty types that should
141                 not stop a patron from checking out materials.
142
143                 @param ignore_list Penalty type to ignore
144                 @return array of barcodes
145         NOTE
146 );
147
148
149 sub patron_search {
150         my $self = shift;
151         my $client = shift;
152         my $search = shift;
153         my $limit = shift || 1000;
154         my $sort = shift;
155         $sort = ['family_name','first_given_name'] unless ($$sort[0]);
156
157         # group 0 = user
158         # group 1 = address
159         # group 2 = phone, ident
160
161         my $usr = join ' AND ', map { "LOWER($_) ~ ?" } grep { ''.$$search{$_}{group} eq '0' } keys %$search;
162         my @usrv = map { "^$$search{$_}{value}" } grep { ''.$$search{$_}{group} eq '0' } keys %$search;
163
164         my $addr = join ' AND ', map { "LOWER($_) ~ ?" } grep { ''.$$search{$_}{group} eq '1' } keys %$search;
165         my @addrv = map { "^$$search{$_}{value}" } grep { ''.$$search{$_}{group} eq '1' } keys %$search;
166
167         my $pv = $$search{phone}{value};
168         my $iv = $$search{ident}{value};
169         my $nv = $$search{name}{value};
170
171         my $phone = '';
172         my @ps;
173         my @phonev;
174         if ($pv) {
175                 for my $p ( qw/day_phone evening_phone other_phone/ ) {
176                         push @ps, "LOWER($p) ~ ?";
177                         push @phonev, "^$pv";
178                 }
179                 $phone = '(' . join(' OR ', @ps) . ')';
180         }
181
182         my $ident = '';
183         my @is;
184         my @identv;
185         if ($iv) {
186                 for my $i ( qw/ident_value ident_value2/ ) {
187                         push @is, "LOWER($i) ~ ?";
188                         push @identv, "^$iv";
189                 }
190                 $ident = '(' . join(' OR ', @is) . ')';
191         }
192
193         my $name = '';
194         my @ns;
195         my @namev;
196         if (0 && $nv) {
197                 for my $n ( qw/first_given_name second_given_name family_name/ ) {
198                         push @ns, "LOWER($i) ~ ?";
199                         push @namev, "^$nv";
200                 }
201                 $name = '(' . join(' OR ', @ns) . ')';
202         }
203
204         my $usr_where = join ' AND ', grep { $_ } ($usr,$phone,$ident,$name);
205         my $addr_where = $addr;
206
207
208         my $u_table = actor::user->table;
209         my $a_table = actor::user_address->table;
210
211         my $u_select = "SELECT id as id FROM $u_table u WHERE $usr_where";
212         my $a_select = "SELECT usr as id FROM $a_table a WHERE $addr_where";
213
214         my $select = '';
215         if ($usr_where) {
216                 if ($addr_where) {
217                         $select = "$u_select INTERSECT $a_select";
218                 } else {
219                         $select = $u_select;
220                 }
221         } elsif ($addr_where) {
222                 $select = $a_select;
223         } else {
224                 return undef;
225         }
226
227         my $order_by = join ', ', map { 'users.'. $_} @$sort;
228                 
229         $select = "SELECT users.id FROM $u_table AS users JOIN ($select) AS search USING (id) ORDER BY $order_by LIMIT $limit";
230
231         return actor::user->db_Main->selectcol_arrayref($select, {}, map {lc($_)} (@usrv,@phonev,@identv,@namev,@addrv));
232 }
233 __PACKAGE__->register_method(
234         api_name        => 'open-ils.storage.actor.user.crazy_search',
235         api_level       => 1,
236         method          => 'patron_search',
237 );
238
239 =comment not gonna use it...
240
241 sub fleshed_search {
242         my $self = shift;
243         my $client = shift;
244         my $searches = shift;
245
246         return undef unless (defined $searches);
247
248         for my $usr ( actor::user->search( $searches ) ) {
249                 next unless $usr;
250                 $client->respond( flesh_user( $usr ) );
251         }
252         return undef;
253 }
254 __PACKAGE__->register_method(
255         api_name        => 'open-ils.storage.fleshed.actor.user.search',
256         api_level       => 1,
257         method          => 'fleshed_search',
258         stream          => 1,
259         cachable        => 1,
260 );
261
262 sub fleshed_search_like {
263         my $self = shift;
264         my $client = shift;
265         my $searches = shift;
266
267         return undef unless (defined $searches);
268
269         for my $usr ( actor::user->search_like( $searches ) ) {
270                 next unless $usr;
271                 $client->respond( flesh_user( $usr ) );
272         }
273         return undef;
274 }
275 __PACKAGE__->register_method(
276         api_name        => 'open-ils.storage.fleshed.actor.user.search_like',
277         api_level       => 1,
278         method          => 'user_by_barcode',
279         stream          => 1,
280         cachable        => 1,
281 );
282
283 sub retrieve_fleshed_user {
284         my $self = shift;
285         my $client = shift;
286         my @ids = shift;
287
288         return undef unless @ids;
289
290         @ids = ($ids[0]) unless ($self->api_name =~ /batch/o); 
291
292         $client->respond( flesh_user( actor::user->retrieve( $_ ) ) ) for ( @ids );
293
294         return undef;
295 }
296 __PACKAGE__->register_method(
297         api_name        => 'open-ils.storage.fleshed.actor.user.retrieve',
298         api_level       => 1,
299         method          => 'retrieve_fleshed_user',
300         cachable        => 1,
301 );
302 __PACKAGE__->register_method(
303         api_name        => 'open-ils.storage.fleshed.actor.user.batch.retrieve',
304         api_level       => 1,
305         method          => 'retrieve_fleshed_user',
306         stream          => 1,
307         cachable        => 1,
308 );
309
310 sub flesh_user {
311         my $usr = shift;
312
313
314         my $standing = $usr->standing;
315         my $profile = $usr->profile;
316         my $ident_type = $usr->ident_type;
317                 
318         my $maddress = $usr->mailing_address;
319         my $baddress = $usr->billing_address;
320         my $card = $usr->card;
321
322         my @addresses = $usr->addresses;
323         my @cards = $usr->cards;
324
325         my $usr_fm = $usr->to_fieldmapper;
326         $usr_fm->standing( $standing->to_fieldmapper );
327         $usr_fm->profile( $profile->to_fieldmapper );
328         $usr_fm->ident_type( $ident_type->to_fieldmapper );
329
330         $usr_fm->card( $card->to_fieldmapper );
331         $usr_fm->mailing_address( $maddress->to_fieldmapper ) if ($maddress);
332         $usr_fm->billing_address( $baddress->to_fieldmapper ) if ($baddress);
333
334         $usr_fm->cards( [ map { $_->to_fieldmapper } @cards ] );
335         $usr_fm->addresses( [ map { $_->to_fieldmapper } @addresses ] );
336
337         return $usr_fm;
338 }
339
340 =cut
341
342 sub org_unit_list {
343         my $self = shift;
344         my $client = shift;
345
346         my $select =<<" SQL";
347         SELECT  *
348           FROM  actor.org_unit
349           ORDER BY CASE WHEN parent_ou IS NULL THEN 0 ELSE 1 END, name;
350         SQL
351
352         my $sth = actor::org_unit->db_Main->prepare_cached($select);
353         $sth->execute;
354
355         $client->respond( $_->to_fieldmapper ) for ( map { actor::org_unit->construct($_) } $sth->fetchall_hash );
356
357         return undef;
358 }
359 __PACKAGE__->register_method(
360         api_name        => 'open-ils.storage.direct.actor.org_unit.retrieve.all',
361         api_level       => 1,
362         stream          => 1,
363         method          => 'org_unit_list',
364 );
365
366 sub org_unit_type_list {
367         my $self = shift;
368         my $client = shift;
369
370         my $select =<<" SQL";
371         SELECT  *
372           FROM  actor.org_unit_type
373           ORDER BY depth, name;
374         SQL
375
376         my $sth = actor::org_unit_type->db_Main->prepare_cached($select);
377         $sth->execute;
378
379         $client->respond( $_->to_fieldmapper ) for ( map { actor::org_unit_type->construct($_) } $sth->fetchall_hash );
380
381         return undef;
382 }
383 __PACKAGE__->register_method(
384         api_name        => 'open-ils.storage.direct.actor.org_unit_type.retrieve.all',
385         api_level       => 1,
386         stream          => 1,
387         method          => 'org_unit_type_list',
388 );
389
390 sub org_unit_full_path {
391         my $self = shift;
392         my $client = shift;
393         my @binds = @_;
394
395         return undef unless (@binds);
396
397         my $func = 'actor.org_unit_full_path(?)';
398         $func = 'actor.org_unit_full_path(?,?)' if (@binds > 1);
399
400         my $sth = actor::org_unit->db_Main->prepare_cached("SELECT * FROM $func");
401         $sth->execute(@binds);
402
403         $client->respond( $_->to_fieldmapper ) for ( map { actor::org_unit->construct($_) } $sth->fetchall_hash );
404
405         return undef;
406 }
407 __PACKAGE__->register_method(
408         api_name        => 'open-ils.storage.actor.org_unit.full_path',
409         api_level       => 1,
410         stream          => 1,
411         method          => 'org_unit_full_path',
412 );
413
414 sub org_unit_ancestors {
415         my $self = shift;
416         my $client = shift;
417         my $id = shift;
418
419         return undef unless ($id);
420
421         my $func = 'actor.org_unit_ancestors(?)';
422
423         my $sth = actor::org_unit->db_Main->prepare_cached(<<"  SQL");
424                 SELECT  f.*
425                   FROM  $func f
426                         JOIN actor.org_unit_type t ON (f.ou_type = t.id)
427                   ORDER BY t.depth, f.name;
428         SQL
429         $sth->execute(''.$id);
430
431         $client->respond( $_->to_fieldmapper ) for ( map { actor::org_unit->construct($_) } $sth->fetchall_hash );
432
433         return undef;
434 }
435 __PACKAGE__->register_method(
436         api_name        => 'open-ils.storage.actor.org_unit.ancestors',
437         api_level       => 1,
438         stream          => 1,
439         method          => 'org_unit_ancestors',
440 );
441
442 sub org_unit_descendants {
443         my $self = shift;
444         my $client = shift;
445         my $id = shift;
446         my $depth = shift;
447
448         return undef unless ($id);
449
450         my $func = 'actor.org_unit_descendants(?)';
451         if (defined $depth) {
452                 $func = 'actor.org_unit_descendants(?,?)';
453         }
454
455         my $sth = actor::org_unit->db_Main->prepare_cached("SELECT * FROM $func");
456         $sth->execute(''.$id, ''.$depth) if (defined $depth);
457         $sth->execute(''.$id) unless (defined $depth);
458
459         $client->respond( $_->to_fieldmapper ) for ( map { actor::org_unit->construct($_) } $sth->fetchall_hash );
460
461         return undef;
462 }
463 __PACKAGE__->register_method(
464         api_name        => 'open-ils.storage.actor.org_unit.descendants',
465         api_level       => 1,
466         stream          => 1,
467         method          => 'org_unit_descendants',
468 );
469
470 sub profile_all {
471         my $self = shift;
472         my $client = shift;
473
474         for my $rec ( actor::profile->retrieve_all ) {
475                 $client->respond( $rec->to_fieldmapper );
476         }
477
478         return undef;
479 }
480 __PACKAGE__->register_method(
481         method          => 'profile_all',
482         api_name        => 'open-ils.storage.direct.actor.profile.retrieve.all',
483         argc            => 0,
484         stream          => 1,
485 );
486
487 sub fleshed_actor_stat_cat {
488         my $self = shift;
489         my $client = shift;
490         my @list = @_;
491         
492         @list = ($list[0]) unless ($self->api_name =~ /batch/o);
493
494         for my $sc (@list) {
495                 my $cat = actor::stat_cat->retrieve($sc);
496                 next unless ($cat);
497
498                 my $sc_fm = $cat->to_fieldmapper;
499                 $sc_fm->entries( [ map { $_->to_fieldmapper } $cat->entries ] );
500
501                 $client->respond( $sc_fm );
502
503         }
504
505         return undef;
506 }
507 __PACKAGE__->register_method(
508         api_name        => 'open-ils.storage.fleshed.actor.stat_cat.retrieve',
509         api_level       => 1,
510         argc            => 1,
511         method          => 'fleshed_actor_stat_cat',
512 );
513
514 __PACKAGE__->register_method(
515         api_name        => 'open-ils.storage.fleshed.actor.stat_cat.retrieve.batch',
516         api_level       => 1,
517         argc            => 1,
518         stream          => 1,
519         method          => 'fleshed_actor_stat_cat',
520 );
521
522 #XXX Fix stored proc calls
523 sub ranged_actor_stat_cat_all {
524         my $self = shift;
525         my $client = shift;
526         my $ou = ''.shift();
527         
528         return undef unless ($ou);
529         my $s_table = actor::stat_cat->table;
530
531         my $select = <<"        SQL";
532                 SELECT  s.*
533                   FROM  $s_table s
534                         JOIN actor.org_unit_full_path(?) p ON (p.id = s.owner)
535                   ORDER BY name
536         SQL
537
538         $fleshed = 0;
539         $fleshed = 1 if ($self->api_name =~ /fleshed/o);
540
541         my $sth = actor::stat_cat->db_Main->prepare_cached($select);
542         $sth->execute($ou);
543
544         for my $sc ( map { actor::stat_cat->construct($_) } $sth->fetchall_hash ) {
545                 my $sc_fm = $sc->to_fieldmapper;
546                 $sc_fm->entries(
547                         [ $self->method_lookup( 'open-ils.storage.ranged.actor.stat_cat_entry.search.stat_cat' )->run($ou,$sc->id) ]
548                 ) if ($fleshed);
549                 $client->respond( $sc_fm );
550         }
551
552         return undef;
553 }
554 __PACKAGE__->register_method(
555         api_name        => 'open-ils.storage.ranged.fleshed.actor.stat_cat.all',
556         api_level       => 1,
557         argc            => 1,
558         stream          => 1,
559         method          => 'ranged_actor_stat_cat_all',
560 );
561
562 __PACKAGE__->register_method(
563         api_name        => 'open-ils.storage.ranged.actor.stat_cat.all',
564         api_level       => 1,
565         argc            => 1,
566         stream          => 1,
567         method          => 'ranged_actor_stat_cat_all',
568 );
569
570 #XXX Fix stored proc calls
571 sub ranged_actor_stat_cat_entry {
572         my $self = shift;
573         my $client = shift;
574         my $ou = ''.shift();
575         my $sc = ''.shift();
576         
577         return undef unless ($ou);
578         my $s_table = actor::stat_cat_entry->table;
579
580         my $select = <<"        SQL";
581                 SELECT  s.*
582                   FROM  $s_table s
583                         JOIN actor.org_unit_full_path(?) p ON (p.id = s.owner)
584                   WHERE stat_cat = ?
585                   ORDER BY name
586         SQL
587
588         my $sth = actor::stat_cat->db_Main->prepare_cached($select);
589         $sth->execute($ou,$sc);
590
591         for my $sce ( map { actor::stat_cat_entry->construct($_) } $sth->fetchall_hash ) {
592                 $client->respond( $sce->to_fieldmapper );
593         }
594
595         return undef;
596 }
597 __PACKAGE__->register_method(
598         api_name        => 'open-ils.storage.ranged.actor.stat_cat_entry.search.stat_cat',
599         api_level       => 1,
600         stream          => 1,
601         method          => 'ranged_actor_stat_cat_entry',
602 );
603
604
605 1;