]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/biblio.pm
Merge branch 'master' of git.evergreen-ils.org:Evergreen-DocBook into doc_consolidati...
[Evergreen.git] / Open-ILS / src / perlmods / lib / OpenILS / Application / Storage / Publisher / biblio.pm
1 package OpenILS::Application::Storage::Publisher::biblio;
2 use base qw/OpenILS::Application::Storage/;
3 use vars qw/$VERSION/;
4 use OpenSRF::EX qw/:try/;
5 #use OpenILS::Application::Storage::CDBI::biblio;
6 #use OpenILS::Application::Storage::CDBI::asset;
7 use OpenILS::Utils::Fieldmapper;
8
9 $VERSION = 1;
10
11 sub record_copy_count {
12         my $self = shift;
13         my $client = shift;
14
15         my %args = @_;
16
17         my $cn_table = asset::call_number->table;
18         my $cp_table = asset::copy->table;
19         my $st_table = config::copy_status->table;
20         my $src_table = config::bib_source->table;
21         my $br_table = biblio::record_entry->table;
22         my $loc_table = asset::copy_location->table;
23         my $out_table = actor::org_unit_type->table;
24
25         my $descendants = "actor.org_unit_descendants(u.id)";
26         my $ancestors = "actor.org_unit_ancestors(?) u JOIN $out_table t ON (u.ou_type = t.id)";
27
28     if ($args{org_unit} < 0) {
29         $args{org_unit} *= -1;
30             $ancestors = "(select org_unit as id from actor.org_lasso_map where lasso = ?) u CROSS JOIN (SELECT -1 AS depth) t";
31     }
32
33         my $visible = 'AND a.opac_visible = TRUE AND st.opac_visible = TRUE AND loc.opac_visible = TRUE AND cp.opac_visible = TRUE';
34         if ($self->api_name =~ /staff/o) {
35                 $visible = ''
36         }
37
38         my $sql = <<"   SQL";
39                 SELECT  t.depth,
40                         u.id AS org_unit,
41                         sum(
42                                 (SELECT count(cp.id)
43                                   FROM  $cn_table cn
44                                         JOIN $cp_table cp ON (cn.id = cp.call_number)
45                                         JOIN $descendants a ON (cp.circ_lib = a.id)
46                                         JOIN $st_table st ON (cp.status = st.id)
47                                         JOIN $loc_table loc ON (cp.location = loc.id)
48                                   WHERE cn.record = ?
49                                         $visible
50                                         AND cn.deleted IS FALSE
51                                         AND cp.deleted IS FALSE)
52                         ) AS count,
53                         sum(
54                                 (SELECT count(cp.id)
55                                   FROM  $cn_table cn
56                                         JOIN $cp_table cp ON (cn.id = cp.call_number)
57                                         JOIN $descendants a ON (cp.circ_lib = a.id)
58                                         JOIN $st_table st ON (cp.status = st.id)
59                                         JOIN $loc_table loc ON (cp.location = loc.id)
60                                   WHERE cn.record = ?
61                                         $visible
62                                         AND cn.deleted IS FALSE
63                                         AND cp.deleted IS FALSE
64                                         AND cp.status IN (0,7,12))
65                         ) AS available,
66                         sum(
67                                 (SELECT count(cp.id)
68                                   FROM  $cn_table cn
69                                         JOIN $cp_table cp ON (cn.id = cp.call_number)
70                                         JOIN $st_table st ON (cp.status = st.id)
71                                         JOIN $loc_table loc ON (cp.location = loc.id)
72                                   WHERE cn.record = ?
73                                         AND st.opac_visible = TRUE
74                                         AND loc.opac_visible = TRUE
75                                         AND cp.opac_visible = TRUE
76                                         AND cn.deleted IS FALSE
77                                         AND cp.deleted IS FALSE)
78                         ) AS unshadow,
79                         sum(    
80                                 (SELECT sum(1)
81                                   FROM  $br_table br
82                                         JOIN $src_table src ON (src.id = br.source)
83                                   WHERE br.id = ?
84                                         AND src.transcendant IS TRUE
85                                 )
86                         ) AS transcendant
87                   FROM  $ancestors
88                   GROUP BY 1,2
89         SQL
90
91         my $sth = biblio::record_entry->db_Main->prepare_cached($sql);
92         $sth->execute(''.$args{record}, ''.$args{record}, ''.$args{record}, ''.$args{record}, ''.$args{org_unit});
93         while ( my $row = $sth->fetchrow_hashref ) {
94                 $client->respond( $row );
95         }
96         return undef;
97 }
98 __PACKAGE__->register_method(
99         api_name        => 'open-ils.storage.biblio.record_entry.copy_count',
100         method          => 'record_copy_count',
101         api_level       => 1,
102         stream          => 1,
103         cachable        => 1,
104 );
105 __PACKAGE__->register_method(
106         api_name        => 'open-ils.storage.biblio.record_entry.copy_count.staff',
107         method          => 'record_copy_count',
108         api_level       => 1,
109         stream          => 1,
110         cachable        => 1,
111 );
112
113 sub record_ranged_tree {
114         my $self = shift;
115         my $client = shift;
116         my $r = shift;
117         my $ou = shift;
118         my $depth = shift;
119         my $limit = shift || 0;
120         my $offset = shift || 0;
121
122         my $ou_sql = defined($depth) ?
123                         "SELECT id FROM actor.org_unit_descendants(?,?)":
124                         "SELECT id FROM actor.org_unit_descendants(?)";
125
126         my $ou_list =
127                 actor::org_unit
128                         ->db_Main
129                         ->selectcol_arrayref(
130                                 $ou_sql,
131                                 {},
132                                 $ou,
133                                 (defined($depth) ? ($depth) : ()),
134                         );
135
136         return undef unless ($ou_list and @$ou_list);
137
138         $r = biblio::record_entry->retrieve( $r );
139         return undef unless ($r);
140
141         my $rec = $r->to_fieldmapper;
142         $rec->call_numbers([]);
143
144         $rec->fixed_fields( $r->record_descriptor->next->to_fieldmapper );
145
146         my $offset_count = 0;
147         my $limit_count = 0;
148         for my $cn ( $r->call_numbers  ) {
149                 next if ($cn->deleted);
150                 my $call_number = $cn->to_fieldmapper;
151                 $call_number->copies([]);
152
153
154                 for my $cp ( $cn->copies(circ_lib => $ou_list) ) {
155                         next if ($cp->deleted);
156                         if ($offset > 0 && $offset_count < $offset) {
157                                 $offset_count++;
158                                 next;
159                         }
160                         
161                         last if ($limit > 0 && $limit_count >= $limit);
162
163                         my $copy = $cp->to_fieldmapper;
164                         $copy->status( $cp->status->to_fieldmapper );
165                         $copy->location( $cp->location->to_fieldmapper );
166                         push @{ $call_number->copies }, $copy;
167
168                         $limit_count++;
169                 }
170
171                 last if ($limit > 0 && $limit_count >= $limit);
172
173                 push @{ $rec->call_numbers }, $call_number if (@{ $call_number->copies });
174         }
175
176         return $rec;
177 }
178 __PACKAGE__->register_method(
179         api_name        => 'open-ils.storage.biblio.record_entry.ranged_tree',
180         method          => 'record_ranged_tree',
181         argc            => 1,
182         api_level       => 1,
183 );
184
185 sub record_by_barcode {
186         my $self = shift;
187         my $client = shift;
188
189         my $cn_table = asset::call_number->table;
190         my $cp_table = asset::copy->table;
191
192         my $id = ''.shift;
193         my ($r) = biblio::record_entry->db_Main->selectrow_array( <<"   SQL", {}, $id );
194                 SELECT  cn.record
195                   FROM  $cn_table cn
196                         JOIN $cp_table cp ON (cp.call_number = cn.id)
197                   WHERE cp.barcode = ?
198         SQL
199
200         my $rec = biblio::record_entry->retrieve( $r );
201
202         return $rec->to_fieldmapper if ($rec);
203         return undef;
204 }
205 __PACKAGE__->register_method(
206         api_name        => 'open-ils.storage.biblio.record_entry.retrieve_by_barcode',
207         method          => 'record_by_barcode',
208         api_level       => 1,
209         cachable        => 1,
210 );
211
212 sub record_by_copy {
213         my $self = shift;
214         my $client = shift;
215
216         my $cn_table = asset::call_number->table;
217         my $cp_table = asset::copy->table;
218
219         my $id = ''.shift;
220         my ($r) = biblio::record_entry->db_Main->selectrow_array( <<"   SQL", {}, $id );
221                 SELECT  cn.record
222                   FROM  $cn_table cn
223                         JOIN $cp_table cp ON (cp.call_number = cn.id)
224                   WHERE cp.id = ?
225         SQL
226
227         my $rec = biblio::record_entry->retrieve( $r );
228         return undef unless ($rec);
229
230         my $r_fm = $rec->to_fieldmapper;
231         my $ff = $rec->record_descriptor->next;
232         $r_fm->fixed_fields( $ff->to_fieldmapper ) if ($ff);
233
234         return $r_fm;
235 }
236 __PACKAGE__->register_method(
237         api_name        => 'open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy',
238         method          => 'record_by_copy',
239         api_level       => 1,
240         cachable        => 1,
241 );
242
243
244 =head1 comment Old version
245
246 my $org_unit_lookup;
247 sub record_copy_count {
248         my $self = shift;
249         my $client = shift;
250         my $oid = shift;
251         my @recs = @_;
252
253         if ($self->api_name !~ /batch/o) {
254                 @recs = ($recs[0]);
255         }
256
257         throw OpenSRF::EX::InvalidArg ( "No org_unit id passed!" )
258                 unless ($oid);
259
260         throw OpenSRF::EX::InvalidArg ( "No record id passed!" )
261                 unless (@recs);
262
263         $org_unit_lookup ||= $self->method_lookup('open-ils.storage.direct.actor.org_unit.retrieve');
264         my ($org_unit) = $org_unit_lookup->run($oid);
265
266         # XXX Use descendancy tree here!!!
267         my $short_name_hack = $org_unit->shortname;
268         $short_name_hack = '' if (!$org_unit->parent_ou);
269         $short_name_hack .= '%';
270         # XXX Use descendancy tree here!!!
271
272         my $rec_list = join(',',@recs);
273
274         my $cp_table = asset::copy->table;
275         my $cn_table = asset::call_number->table;
276
277         my $select =<<" SQL";
278                 SELECT  count(cp.*) as copies
279                   FROM  $cn_table cn
280                         JOIN $cp_table cp ON (cp.call_number = cn.id)
281                   WHERE cn.owning_lib LIKE ? AND
282                         cn.record IN ($rec_list)
283         SQL
284
285         my $sth = asset::copy->db_Main->prepare_cached($select);
286         $sth->execute($short_name_hack);
287
288         my $results = $sth->fetchall_hashref('record');
289
290         $client->respond($$results{$_}{copies} || 0) for (@recs);
291
292         return undef;
293 }
294 __PACKAGE__->register_method(
295         method          => 'record_copy_count',
296         api_name        => 'open-ils.storage.direct.biblio.record_copy_count',
297         api_level       => 1,
298         argc            => 1,
299 );
300 __PACKAGE__->register_method(
301         method          => 'record_copy_count',
302         api_name        => 'open-ils.storage.direct.biblio.record_copy_count.batch',
303         api_level       => 1,
304         argc            => 1,
305         stream          => 1,
306 );
307
308 =cut
309
310 sub global_record_copy_count {
311         my $self = shift;
312         my $client = shift;
313
314         my $rec = shift;
315
316         my $cn_table = asset::call_number->table;
317         my $cp_table = asset::copy->table;
318         my $cl_table = asset::copy_location->table;
319         my $cs_table = config::copy_status->table;
320
321         my $copies_visible = 'AND cp.opac_visible IS TRUE AND cs.opac_visible IS TRUE AND cl.opac_visible IS TRUE';
322         $copies_visible = '' if ($self->api_name =~ /staff/o);
323
324         my $sql = <<"   SQL";
325
326                 SELECT  owning_lib, sum(avail), sum(tot)
327                   FROM  (
328                                 SELECT  cn.owning_lib, count(cp.id) as avail, 0 as tot
329                                   FROM  $cn_table cn
330                                         JOIN $cp_table cp ON (cn.id = cp.call_number)
331                                         JOIN $cs_table cs ON (cs.id = cp.status)
332                                         JOIN $cl_table cl ON (cl.id = cp.location)
333                                   WHERE cn.record = ?
334                                         AND cp.status IN (0,7,12)
335                                         $copies_visible
336                                   GROUP BY 1
337                                                 UNION
338                                 SELECT  cn.owning_lib, 0 as avail, count(cp.id) as tot
339                                   FROM  $cn_table cn
340                                         JOIN $cp_table cp ON (cn.id = cp.call_number)
341                                         JOIN $cs_table cs ON (cs.id = cp.status)
342                                         JOIN $cl_table cl ON (cl.id = cp.location)
343                                   WHERE cn.record = ?
344                                         $copies_visible
345                                   GROUP BY 1
346                         ) x
347                   GROUP BY 1
348         SQL
349
350         my $sth = biblio::record_entry->db_Main->prepare_cached($sql);
351         $sth->execute("$rec", "$rec");
352
353         $client->respond( $_ ) for (@{$sth->fetchall_arrayref});
354         return undef;
355 }
356 __PACKAGE__->register_method(
357         api_name        => 'open-ils.storage.biblio.record_entry.global_copy_count',
358         method          => 'global_record_copy_count',
359         api_level       => 1,
360         stream          => 1,
361         cachable        => 1,
362 );
363 __PACKAGE__->register_method(
364         api_name        => 'open-ils.storage.biblio.record_entry.global_copy_count.staff',
365         method          => 'global_record_copy_count',
366         api_level       => 1,
367         stream          => 1,
368         cachable        => 1,
369 );
370
371 sub record_copy_status_count {
372         my $self = shift;
373         my $client = shift;
374
375         my $rec = shift;
376         my $ou = shift || 1;
377         my $depth = shift || 0;
378
379
380         my $descendants = "actor.org_unit_descendants(?,?)";
381
382         my $cn_table = asset::call_number->table;
383         my $cnp_table = asset::call_number_prefix->table;
384         my $cns_table = asset::call_number_suffix->table;
385         my $cp_table = asset::copy->table;
386         my $cl_table = asset::copy_location->table;
387         my $cs_table = config::copy_status->table;
388
389         my $sql = <<"   SQL";
390
391                 SELECT  cp.circ_lib,
392                                 CASE WHEN cnp.id > -1 THEN cnp.label ELSE '' END,
393                 cn.label,
394                 CASE WHEN cns.id > -1 THEN cns.label ELSE '' END,
395                                 cp.status,
396                                 count(cp.id)
397                   FROM  $cp_table cp,
398                         $cn_table cn,
399                         $cns_table cns,
400                         $cnp_table cnp,
401                         $cl_table cl,
402                         $cs_table cs,
403                         $descendants d
404                   WHERE cn.record = ?
405                         AND cnp.id = cn.prefix
406                         AND cns.id = cn.suffix
407                         AND cp.call_number = cn.id
408                         AND cp.location = cl.id
409                         AND cp.circ_lib = d.id
410                         AND cp.status = cs.id
411                         AND cl.opac_visible IS TRUE
412                         AND cp.opac_visible IS TRUE
413                         AND cp.deleted IS FALSE
414                         AND cs.opac_visible IS TRUE
415                   GROUP BY 1,2,3,4,5;
416         SQL
417
418         my $sth = biblio::record_entry->db_Main->prepare_cached($sql);
419         $sth->execute($ou, $depth, "$rec" );
420
421         my %data = ();
422         for my $row (@{$sth->fetchall_arrayref}) {
423                 $data{$$row[0]}{$$row[1]}{$$row[2]}{$$row[3]}{$$row[4]} += $$row[5];
424         }
425         
426         for my $ou (keys %data) {
427                 for my $cn_prefix (keys %{$data{$ou}}) {
428                     for my $cn (keys %{$data{$ou}{$cn_prefix}}) {
429                         for my $cn_suffix (keys %{$data{$ou}{$cn_prefix}{$cn}}) {
430                                 $client->respond( [$ou, $cn_prefix, $cn, $cn_suffix, $data{$ou}{$cn}{$cn_prefix}{$cn}{$cn_suffix}] );
431                         }
432             }
433         }
434         }
435         return undef;
436 }
437 __PACKAGE__->register_method(
438         api_name        => 'open-ils.storage.biblio.record_entry.status_copy_count',
439         method          => 'record_copy_status_count',
440         api_level       => 1,
441         stream          => 1,
442         cachable        => 1,
443 );
444
445
446 sub record_copy_status_location_count {
447         my $self = shift;
448         my $client = shift;
449
450         my $rec = shift;
451         my $ou = shift || 1;
452         my $depth = shift || 0;
453
454
455         my $descendants = "actor.org_unit_descendants(?,?)";
456
457         my $cn_table = asset::call_number->table;
458         my $cnp_table = asset::call_number_prefix->table;
459         my $cns_table = asset::call_number_suffix->table;
460         my $cp_table = asset::copy->table;
461         my $cl_table = asset::copy_location->table;
462         my $cs_table = config::copy_status->table;
463
464         # FIXME using oils_i18n_xlate here is exposing a hitherto unexposed
465         # implementation detail of json_query; doing it this way because
466         # json_query currently doesn't grok joining a function to tables
467         my $sql = <<"   SQL";
468
469                 SELECT  cp.circ_lib,
470                                 CASE WHEN cnp.id > -1 THEN cnp.label ELSE '' END,
471                 cn.label,
472                 CASE WHEN cns.id > -1 THEN cns.label ELSE '' END,
473                                 oils_i18n_xlate('asset.copy_location', 'acpl', 'name', 'id', cl.id::TEXT, ?),
474                                 cp.status,
475                                 count(cp.id)
476                   FROM  $cp_table cp,
477                         $cn_table cn,
478                         $cns_table cns,
479                         $cnp_table cnp,
480                         $cl_table cl,
481                         $cs_table cs,
482                         $descendants d
483                   WHERE cn.record = ?
484                         AND cnp.id = cn.prefix
485                         AND cns.id = cn.suffix
486                         AND cp.call_number = cn.id
487                         AND cp.location = cl.id
488                         AND cp.circ_lib = d.id
489                         AND cp.status = cs.id
490                         AND cl.opac_visible IS TRUE
491                         AND cp.opac_visible IS TRUE
492                         AND cp.deleted IS FALSE
493                         AND cs.opac_visible IS TRUE
494                   GROUP BY 1,2,3,4,5,6;
495         SQL
496
497         my $sth = biblio::record_entry->db_Main->prepare_cached($sql);
498         my $ses_locale = $client->session ? $client->session->session_locale : 'en-US';
499         $sth->execute($ses_locale, $ou, $depth, "$rec" );
500
501         my %data = ();
502         for my $row (@{$sth->fetchall_arrayref}) {
503                 $data{$$row[0]}{$$row[1]}{$$row[2]}{$$row[3]}{$$row[4]}{$$row[5]} += $$row[6];
504         }
505         
506         for my $ou (keys %data) {
507                 for my $cn_prefix (keys %{$data{$ou}}) {
508                     for my $cn (keys %{$data{$ou}{$cn_prefix}}) {
509                         for my $cn_suffix (keys %{$data{$ou}{$cn_prefix}{$cn}}) {
510                     for my $cl (keys %{$data{$ou}{$cn_prefix}{$cn}{$cn_suffix}}) {
511                         $client->respond( [$ou, $cn_prefix, $cn, $cn_suffix, $cl, $data{$ou}{$cn_prefix}{$cn}{$cn_suffix}{$cl}] );
512                     }
513                         }
514                     }
515                 }
516         }
517         return undef;
518 }
519 __PACKAGE__->register_method(
520         api_name        => 'open-ils.storage.biblio.record_entry.status_copy_location_count',
521         method          => 'record_copy_status_location_count',
522         api_level       => 1,
523         stream          => 1,
524         cachable        => 1,
525 );
526
527 1;