]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher/biblio.pm
bug fixes to the ranged record tree
[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 $loc_table = asset::copy_location->table;
21         my $out_table = actor::org_unit_type->table;
22
23         my $descendants = "actor.org_unit_descendants(u.id)";
24         my $ancestors = "actor.org_unit_ancestors(?)";
25
26         my $visible = 'AND st.holdable = TRUE AND loc.opac_visible = TRUE AND cp.opac_visible = TRUE';
27         if ($self->api_name =~ /staff/o) {
28                 $visible = ''
29         }
30
31         my $sql = <<"   SQL";
32                 SELECT  t.depth,
33                         u.id AS org_unit,
34                         sum(
35                                 (SELECT count(cp.id)
36                                   FROM  $cn_table cn
37                                         JOIN $cp_table cp ON (cn.id = cp.call_number)
38                                         JOIN $descendants a ON (cp.circ_lib = a.id)
39                                         JOIN $st_table st ON (cp.status = st.id)
40                                         JOIN $loc_table loc ON (cp.location = loc.id)
41                                   WHERE cn.record = ?
42                                         $visible
43                                         AND cn.deleted IS FALSE
44                                         AND cp.deleted IS FALSE)
45                         ) AS count,
46                         sum(
47                                 (SELECT count(cp.id)
48                                   FROM  $cn_table cn
49                                         JOIN $cp_table cp ON (cn.id = cp.call_number)
50                                         JOIN $descendants a ON (cp.circ_lib = a.id)
51                                         JOIN $st_table st ON (cp.status = st.id)
52                                         JOIN $loc_table loc ON (cp.location = loc.id)
53                                   WHERE cn.record = ?
54                                         $visible
55                                         AND cn.deleted IS FALSE
56                                         AND cp.deleted IS FALSE
57                                         AND cp.status = 0)
58                         ) AS available,
59                         sum(
60                                 (SELECT count(cp.id)
61                                   FROM  $cn_table cn
62                                         JOIN $cp_table cp ON (cn.id = cp.call_number)
63                                         JOIN $st_table st ON (cp.status = st.id)
64                                         JOIN $loc_table loc ON (cp.location = loc.id)
65                                   WHERE cn.record = ?
66                                         AND st.holdable = TRUE
67                                         AND loc.opac_visible = TRUE
68                                         AND cp.opac_visible = TRUE
69                                         AND cn.deleted IS FALSE
70                                         AND cp.deleted IS FALSE)
71                         ) AS unshadow
72                   FROM  $ancestors u
73                         JOIN $out_table t ON (u.ou_type = t.id)
74                   GROUP BY 1,2
75         SQL
76
77         my $sth = biblio::record_entry->db_Main->prepare_cached($sql);
78         $sth->execute(''.$args{record}, ''.$args{record}, ''.$args{record}, ''.$args{org_unit});
79         while ( my $row = $sth->fetchrow_hashref ) {
80                 $client->respond( $row );
81         }
82         return undef;
83 }
84 __PACKAGE__->register_method(
85         api_name        => 'open-ils.storage.biblio.record_entry.copy_count',
86         method          => 'record_copy_count',
87         api_level       => 1,
88         stream          => 1,
89         cachable        => 1,
90 );
91 __PACKAGE__->register_method(
92         api_name        => 'open-ils.storage.biblio.record_entry.copy_count.staff',
93         method          => 'record_copy_count',
94         api_level       => 1,
95         stream          => 1,
96         cachable        => 1,
97 );
98
99 sub record_ranged_tree {
100         my $self = shift;
101         my $client = shift;
102         my $r = shift;
103         my $ou = shift;
104         my $depth = shift;
105         my $limit = shift || 0;
106         my $offset = shift || 0;
107
108         my $ou_sql = defined($depth) ?
109                         "SELECT id FROM actor.org_unit_descendants(?,?)":
110                         "SELECT id FROM actor.org_unit_descendants(?)";
111
112         my $ou_list =
113                 actor::org_unit
114                         ->db_Main
115                         ->selectcol_arrayref(
116                                 $ou_sql,
117                                 {},
118                                 $ou,
119                                 (defined($depth) ? ($depth) : ()),
120                         );
121
122         return undef unless ($ou_list and @$ou_list);
123
124         $r = biblio::record_entry->retrieve( $r );
125         return undef unless ($r);
126
127         my $rec = $r->to_fieldmapper;
128         $rec->call_numbers([]);
129
130         $rec->fixed_fields( $r->record_descriptor->next->to_fieldmapper );
131
132         my $offset_count = 0;
133         my $limit_count = 0;
134         for my $cn ( $r->call_numbers  ) {
135                 my $call_number = $cn->to_fieldmapper;
136                 $call_number->copies([]);
137
138
139                 for my $cp ( $cn->copies(circ_lib => $ou_list) ) {
140                         if ($offset > 0 && $offset_count < $offset) {
141                                 $offset_count++;
142                                 next;
143                         }
144                         
145                         last if ($limit > 0 && $limit_count >= $limit);
146
147                         my $copy = $cp->to_fieldmapper;
148                         $copy->status( $cp->status->to_fieldmapper );
149                         $copy->location( $cp->location->to_fieldmapper );
150                         push @{ $call_number->copies }, $copy;
151
152                         $limit_count++;
153                 }
154
155                 last if ($limit > 0 && $limit_count >= $limit);
156
157                 push @{ $rec->call_numbers }, $call_number if (@{ $call_number->copies });
158         }
159
160         return $rec;
161 }
162 __PACKAGE__->register_method(
163         api_name        => 'open-ils.storage.biblio.record_entry.ranged_tree',
164         method          => 'record_ranged_tree',
165         argc            => 1,
166         api_level       => 1,
167 );
168
169 sub record_by_barcode {
170         my $self = shift;
171         my $client = shift;
172
173         my $cn_table = asset::call_number->table;
174         my $cp_table = asset::copy->table;
175
176         my $id = ''.shift;
177         my ($r) = biblio::record_entry->db_Main->selectrow_array( <<"   SQL", {}, $id );
178                 SELECT  cn.record
179                   FROM  $cn_table cn
180                         JOIN $cp_table cp ON (cp.call_number = cn.id)
181                   WHERE cp.barcode = ?
182         SQL
183
184         my $rec = biblio::record_entry->retrieve( $r );
185
186         return $rec->to_fieldmapper if ($rec);
187         return undef;
188 }
189 __PACKAGE__->register_method(
190         api_name        => 'open-ils.storage.biblio.record_entry.retrieve_by_barcode',
191         method          => 'record_by_barcode',
192         api_level       => 1,
193         cachable        => 1,
194 );
195
196 sub record_by_copy {
197         my $self = shift;
198         my $client = shift;
199
200         my $cn_table = asset::call_number->table;
201         my $cp_table = asset::copy->table;
202
203         my $id = ''.shift;
204         my ($r) = biblio::record_entry->db_Main->selectrow_array( <<"   SQL", {}, $id );
205                 SELECT  cn.record
206                   FROM  $cn_table cn
207                         JOIN $cp_table cp ON (cp.call_number = cn.id)
208                   WHERE cp.id = ?
209         SQL
210
211         my $rec = biblio::record_entry->retrieve( $r );
212         return undef unless ($rec);
213
214         my $r_fm = $rec->to_fieldmapper;
215         my $ff = $rec->record_descriptor->next;
216         $r_fm->fixed_fields( $ff->to_fieldmapper ) if ($ff);
217
218         return $r_fm;
219 }
220 __PACKAGE__->register_method(
221         api_name        => 'open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy',
222         method          => 'record_by_copy',
223         api_level       => 1,
224         cachable        => 1,
225 );
226
227
228 =comment Old version
229
230 my $org_unit_lookup;
231 sub record_copy_count {
232         my $self = shift;
233         my $client = shift;
234         my $oid = shift;
235         my @recs = @_;
236
237         if ($self->api_name !~ /batch/o) {
238                 @recs = ($recs[0]);
239         }
240
241         throw OpenSRF::EX::InvalidArg ( "No org_unit id passed!" )
242                 unless ($oid);
243
244         throw OpenSRF::EX::InvalidArg ( "No record id passed!" )
245                 unless (@recs);
246
247         $org_unit_lookup ||= $self->method_lookup('open-ils.storage.direct.actor.org_unit.retrieve');
248         my ($org_unit) = $org_unit_lookup->run($oid);
249
250         # XXX Use descendancy tree here!!!
251         my $short_name_hack = $org_unit->shortname;
252         $short_name_hack = '' if (!$org_unit->parent_ou);
253         $short_name_hack .= '%';
254         # XXX Use descendancy tree here!!!
255
256         my $rec_list = join(',',@recs);
257
258         my $cp_table = asset::copy->table;
259         my $cn_table = asset::call_number->table;
260
261         my $select =<<" SQL";
262                 SELECT  count(cp.*) as copies
263                   FROM  $cn_table cn
264                         JOIN $cp_table cp ON (cp.call_number = cn.id)
265                   WHERE cn.owning_lib LIKE ? AND
266                         cn.record IN ($rec_list)
267         SQL
268
269         my $sth = asset::copy->db_Main->prepare_cached($select);
270         $sth->execute($short_name_hack);
271
272         my $results = $sth->fetchall_hashref('record');
273
274         $client->respond($$results{$_}{copies} || 0) for (@recs);
275
276         return undef;
277 }
278 __PACKAGE__->register_method(
279         method          => 'record_copy_count',
280         api_name        => 'open-ils.storage.direct.biblio.record_copy_count',
281         api_level       => 1,
282         argc            => 1,
283 );
284 __PACKAGE__->register_method(
285         method          => 'record_copy_count',
286         api_name        => 'open-ils.storage.direct.biblio.record_copy_count.batch',
287         api_level       => 1,
288         argc            => 1,
289         stream          => 1,
290 );
291
292 =cut
293
294 sub global_record_copy_count {
295         my $self = shift;
296         my $client = shift;
297
298         my $rec = shift;
299
300         my $cn_table = asset::call_number->table;
301         my $cp_table = asset::copy->table;
302         my $cl_table = asset::copy_location->table;
303         my $cs_table = config::copy_status->table;
304
305         my $copies_visible = 'AND cp.opac_visible IS TRUE AND cs.holdable IS TRUE AND cl.opac_visible IS TRUE';
306         $copies_visible = '' if ($self->api_name =~ /staff/o);
307
308         my $sql = <<"   SQL";
309
310                 SELECT  owning_lib, sum(avail), sum(tot)
311                   FROM  (
312                                 SELECT  cn.owning_lib, count(cp.id) as avail, 0 as tot
313                                   FROM  $cn_table cn
314                                         JOIN $cp_table cp ON (cn.id = cp.call_number)
315                                         JOIN $cs_table cs ON (cs.id = cp.status)
316                                         JOIN $cl_table cl ON (cl.id = cp.location)
317                                   WHERE cn.record = ?
318                                         AND cp.status = 0
319                                         $copies_visible
320                                   GROUP BY 1
321                                                 UNION
322                                 SELECT  cn.owning_lib, 0 as avail, count(cp.id) as tot
323                                   FROM  $cn_table cn
324                                         JOIN $cp_table cp ON (cn.id = cp.call_number)
325                                         JOIN $cs_table cs ON (cs.id = cp.status)
326                                         JOIN $cl_table cl ON (cl.id = cp.location)
327                                   WHERE cn.record = ?
328                                         $copies_visible
329                                   GROUP BY 1
330                         ) x
331                   GROUP BY 1
332         SQL
333
334         my $sth = biblio::record_entry->db_Main->prepare_cached($sql);
335         $sth->execute("$rec", "$rec");
336
337         $client->respond( $_ ) for (@{$sth->fetchall_arrayref});
338         return undef;
339 }
340 __PACKAGE__->register_method(
341         api_name        => 'open-ils.storage.biblio.record_entry.global_copy_count',
342         method          => 'global_record_copy_count',
343         api_level       => 1,
344         stream          => 1,
345         cachable        => 1,
346 );
347 __PACKAGE__->register_method(
348         api_name        => 'open-ils.storage.biblio.record_entry.global_copy_count.staff',
349         method          => 'global_record_copy_count',
350         api_level       => 1,
351         stream          => 1,
352         cachable        => 1,
353 );
354
355 sub record_copy_status_count {
356         my $self = shift;
357         my $client = shift;
358
359         my $rec = shift;
360         my $ou = shift || 1;
361         my $depth = shift || 0;
362
363
364         my $descendants = "actor.org_unit_descendants(?,?)";
365
366         my $cn_table = asset::call_number->table;
367         my $cp_table = asset::copy->table;
368         my $cl_table = asset::copy_location->table;
369         my $cs_table = config::copy_status->table;
370
371         my $sql = <<"   SQL";
372
373                 SELECT  cp.circ_lib, cn.label, cp.status, count(cp.id)
374                   FROM  $cp_table cp,
375                         $cn_table cn,
376                         $cl_table cl,
377                         $cs_table cs,
378                         $descendants d
379                   WHERE cn.record = ?
380                         AND cp.call_number = cn.id
381                         AND cp.location = cl.id
382                         AND cp.circ_lib = d.id
383                         AND cp.status = cs.id
384                         AND cl.opac_visible IS TRUE
385                         AND cp.opac_visible IS TRUE
386                         AND cp.deleted IS FALSE
387                         AND cs.holdable
388                   GROUP BY 1,2,3;
389         SQL
390
391         my $sth = biblio::record_entry->db_Main->prepare_cached($sql);
392         $sth->execute($ou, $depth, "$rec" );
393
394         my %data = ();
395         for my $row (@{$sth->fetchall_arrayref}) {
396                 $data{$$row[0]}{$$row[1]}{$$row[2]} += $$row[3];
397         }
398         
399         for my $ou (keys %data) {
400                 for my $cn (keys %{$data{$ou}}) {
401                         $client->respond( [$ou, $cn, $data{$ou}{$cn}] );
402                 }
403         }
404         return undef;
405 }
406 __PACKAGE__->register_method(
407         api_name        => 'open-ils.storage.biblio.record_entry.status_copy_count',
408         method          => 'record_copy_status_count',
409         api_level       => 1,
410         stream          => 1,
411         cachable        => 1,
412 );
413
414 1;