cb5a66c56c8cc391cfaff89e9d1b6b885d4b0b5f
[Evergreen.git] / Open-ILS / src / perlmods / 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.holdable = 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))
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.holdable = 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 =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.holdable 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)
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 $cp_table = asset::copy->table;
384         my $cl_table = asset::copy_location->table;
385         my $cs_table = config::copy_status->table;
386
387         my $sql = <<"   SQL";
388
389                 SELECT  cp.circ_lib, cn.label, cp.status, count(cp.id)
390                   FROM  $cp_table cp,
391                         $cn_table cn,
392                         $cl_table cl,
393                         $cs_table cs,
394                         $descendants d
395                   WHERE cn.record = ?
396                         AND cp.call_number = cn.id
397                         AND cp.location = cl.id
398                         AND cp.circ_lib = d.id
399                         AND cp.status = cs.id
400                         AND cl.opac_visible IS TRUE
401                         AND cp.opac_visible IS TRUE
402                         AND cp.deleted IS FALSE
403                         AND cs.holdable
404                   GROUP BY 1,2,3;
405         SQL
406
407         my $sth = biblio::record_entry->db_Main->prepare_cached($sql);
408         $sth->execute($ou, $depth, "$rec" );
409
410         my %data = ();
411         for my $row (@{$sth->fetchall_arrayref}) {
412                 $data{$$row[0]}{$$row[1]}{$$row[2]} += $$row[3];
413         }
414         
415         for my $ou (keys %data) {
416                 for my $cn (keys %{$data{$ou}}) {
417                         $client->respond( [$ou, $cn, $data{$ou}{$cn}] );
418                 }
419         }
420         return undef;
421 }
422 __PACKAGE__->register_method(
423         api_name        => 'open-ils.storage.biblio.record_entry.status_copy_count',
424         method          => 'record_copy_status_count',
425         api_level       => 1,
426         stream          => 1,
427         cachable        => 1,
428 );
429
430 1;