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