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