]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/container.pm
LP1906858 Carousels Ignore Deleted Flag
[Evergreen.git] / Open-ILS / src / perlmods / lib / OpenILS / Application / Storage / Publisher / container.pm
1 package OpenILS::Application::Storage::Publisher::container;
2 use base qw/OpenILS::Application::Storage/;
3 use vars qw/$VERSION/;
4 use OpenSRF::EX qw/:try/;
5 use OpenSRF::Utils::Logger qw/:level :logger/;
6 use OpenILS::Utils::CStoreEditor;
7 #use OpenILS::Application::Storage::CDBI::config;
8
9 my $new_items_query = q(
10     WITH c_attr AS (SELECT c_attrs::query_int AS vis_test FROM asset.patron_default_visibility_mask() x)
11     SELECT acn.record AS bib
12     FROM asset.call_number acn
13     JOIN asset.copy acp ON (acp.call_number = acn.id)
14     JOIN asset.copy_location acpl ON (acp.location = acpl.id)
15     JOIN config.copy_status ccs ON (acp.status = ccs.id)
16     , c_attr
17     WHERE acn.owning_lib IN (ORG_LIST)
18     AND acp.circ_lib IN (ORG_LIST)
19     AND acp.holdable
20     AND acp.circulate
21     AND acp.deleted is false
22     AND ccs.holdable
23     AND acpl.holdable
24     AND acpl.circulate
25     AND acp.active_date > NOW() - ?::INTERVAL
26     -- LOC AND acp.location IN (LOC_LIST)
27     AND (EXISTS (SELECT 1 FROM asset.copy_vis_attr_cache WHERE record = acn.record AND vis_attr_vector @@ c_attr.vis_test))
28     AND (NOT EXISTS (SELECT 1 FROM metabib.record_attr_vector_list WHERE source = acn.record AND vlist @@ metabib.compile_composite_attr(' {"1":[{"_val":"s","_attr":"bib_level"}]}')::query_int))
29     GROUP BY acn.record
30     ORDER BY MIN(AGE(acp.active_date))
31     LIMIT ? 
32 );
33 my $recently_returned_query = q(
34 WITH c_attr AS (SELECT c_attrs::query_int AS vis_test FROM asset.patron_default_visibility_mask() x)
35     SELECT acn.record AS bib
36     FROM asset.call_number acn
37     JOIN asset.copy acp ON (acp.call_number = acn.id)
38     JOIN asset.copy_location acpl ON (acp.location = acpl.id)
39     JOIN config.copy_status ccs ON (acp.status = ccs.id)
40     JOIN action.circulation circ ON (circ.target_copy = acp.id)
41     , c_attr
42     WHERE acn.owning_lib IN (ORG_LIST)
43     AND acp.circ_lib IN (ORG_LIST)
44     AND acp.holdable
45     AND acp.circulate
46     AND acp.deleted is false
47     AND ccs.holdable
48     AND acpl.holdable
49     AND acpl.circulate
50     AND circ.checkin_time > NOW() - ?::INTERVAL
51     AND circ.checkin_time IS NOT NULL
52     -- LOC AND acp.location IN (LOC_LIST)
53     AND (EXISTS (SELECT 1 FROM asset.copy_vis_attr_cache WHERE record = acn.record AND vis_attr_vector @@ c_attr.vis_test))
54     AND (NOT EXISTS (SELECT 1 FROM metabib.record_attr_vector_list WHERE source = acn.record AND vlist @@ metabib.compile_composite_attr(' {"1":[{"_val":"s","_attr":"bib_level"}]}')::query_int))
55     GROUP BY acn.record
56     ORDER BY MIN(AGE(circ.checkin_time))
57     LIMIT ?
58 );
59 my $top_circs_query = q(
60     WITH c_attr AS (SELECT c_attrs::query_int AS vis_test FROM asset.patron_default_visibility_mask() x)
61     SELECT acn.record AS bib
62     FROM asset.call_number acn
63     JOIN asset.copy acp ON (acp.call_number = acn.id)
64     JOIN asset.copy_location acpl ON (acp.location = acpl.id)
65     JOIN config.copy_status ccs ON (acp.status = ccs.id)
66     JOIN action.circulation circ ON (circ.target_copy = acp.id)
67     , c_attr
68     WHERE acn.owning_lib IN (ORG_LIST)
69     AND acp.circ_lib IN (ORG_LIST)
70     AND acp.holdable
71     AND acp.circulate
72     AND acp.deleted is false
73     AND ccs.holdable
74     AND acpl.holdable
75     AND acpl.circulate
76     AND circ.xact_start > NOW() - ?::INTERVAL
77     -- LOC AND acp.location IN (LOC_LIST)
78     AND (EXISTS (SELECT 1 FROM asset.copy_vis_attr_cache WHERE record = acn.record AND vis_attr_vector @@ c_attr.vis_test))
79     AND (NOT EXISTS (SELECT 1 FROM metabib.record_attr_vector_list WHERE source = acn.record AND vlist @@ metabib.compile_composite_attr(' {"1":[{"_val":"s","_attr":"bib_level"}]}')::query_int))
80     GROUP BY acn.record
81     ORDER BY COUNT(circ.id) DESC
82     LIMIT ?
83 );
84 my $new_by_loc_query = q(
85     WITH c_attr AS (SELECT c_attrs::query_int AS vis_test FROM asset.patron_default_visibility_mask() x)
86     SELECT acn.record AS bib
87     FROM asset.call_number acn
88     JOIN asset.copy acp ON (acp.call_number = acn.id)
89     JOIN asset.copy_location acpl ON (acp.location = acpl.id)
90     JOIN config.copy_status ccs ON (acp.status = ccs.id)
91     , c_attr
92     WHERE acn.owning_lib IN (ORG_LIST)
93     AND acp.circ_lib IN (ORG_LIST)
94     AND acp.active_date > NOW() - ?::INTERVAL
95     -- LOC AND acp.location IN (LOC_LIST)
96     AND acp.holdable
97     AND acp.circulate
98     AND acp.deleted is false
99     AND ccs.holdable
100     AND acpl.holdable
101     AND acpl.circulate
102     AND (EXISTS (SELECT 1 FROM asset.copy_vis_attr_cache WHERE record = acn.record AND vis_attr_vector @@ c_attr.vis_test))
103     AND (NOT EXISTS (SELECT 1 FROM metabib.record_attr_vector_list WHERE source = acn.record AND vlist @@ metabib.compile_composite_attr(' {"1":[{"_val":"s","_attr":"bib_level"}]}')::query_int))
104     GROUP BY acn.record
105     ORDER BY MIN(AGE(acp.active_date))
106     LIMIT ?
107 );
108
109 my %TYPE_QUERY_MAP = (
110     2 => $new_items_query,
111     3 => $recently_returned_query,
112     4 => $top_circs_query,
113     5 => $new_by_loc_query,
114 );
115
116 sub refresh_container_from_carousel_definition {
117     my $self = shift;
118     my $client = shift;
119     my $bucket = shift;
120     my $carousel_type = shift;
121     my $age = shift // '15 days';
122     my $libs = shift // [];
123     my $locs = shift // [];
124     my $limit = shift // 50;
125
126     my $e = OpenILS::Utils::CStoreEditor->new;
127     my $ctype = $e->retrieve_config_carousel_type($carousel_type) or return $e->die_event;
128     $e->disconnect;
129
130     unless (exists($TYPE_QUERY_MAP{$carousel_type})) {
131         $logger->error("Carousel for bucket $bucket is misconfigured; type $carousel_type is not recognized");
132         return 0;
133     }
134
135     my $query = $TYPE_QUERY_MAP{$carousel_type};
136
137     if ($ctype->filter_by_copy_owning_lib eq 't') {
138         if (scalar(@$libs) < 1) {
139             $logger->error("Carousel for bucket $bucket is misconfigured; owning library filter expected but none specified");
140             return 0;
141         }
142         my $org_placeholders = join(',', map { '?' } @$libs);
143         $query =~ s/ORG_LIST/$org_placeholders/g;
144     } else {
145         $libs = []; # we'll ignore any superflous supplied values
146     }
147
148     if ($ctype->filter_by_copy_location eq 't') {
149         if (scalar(@$locs) < 1) {
150             $logger->error("Carousel for bucket $bucket is misconfigured; copy location filter expected but none specified");
151             return 0;
152         }
153         my $loc_placeholders = join(',', map { '?' } @$locs);
154         $query =~ s/-- LOC //g;
155         $query =~ s/LOC_LIST/$loc_placeholders/g;
156     } else {
157         $locs = []; # we'll ignore any superflous supplied values
158     }
159
160     my $sth = container::biblio_record_entry_bucket_item->db_Main->prepare_cached($query);
161
162     $sth->execute(@$libs, @$libs, $age, @$locs, $limit);
163     my @bibs = ();
164     while (my $row = $sth->fetchrow_hashref ) {
165         push @bibs, $row->{bib};
166     }
167     container::biblio_record_entry_bucket_item->search( bucket => $bucket )->delete_all;
168     my $i = 0;
169     foreach my $bib (@bibs) {
170         container::biblio_record_entry_bucket_item->create({ bucket => $bucket, target_biblio_record_entry => $bib, pos => $i++ });
171     }
172     return scalar(@bibs);
173 }
174
175 __PACKAGE__->register_method(
176     api_name    => 'open-ils.storage.container.refresh_from_carousel',
177     method      => 'refresh_container_from_carousel_definition',
178     api_level   => 1,
179     cachable    => 1,
180 );
181
182 sub refresh_all_carousels {
183     my $self = shift;
184     my $client = shift;
185
186     my $e = OpenILS::Utils::CStoreEditor->new;
187
188     my $automatic_types = $e->search_config_carousel_type({ automatic => 't' });
189     my $carousels = $e->search_container_carousel({ type => [ map { $_->id } @$automatic_types ], active => 't' });
190
191     my $meth = $self->method_lookup('open-ils.storage.container.refresh_from_carousel');
192
193     foreach my $carousel (@$carousels) {
194
195         my $orgs = [];
196         my $locs = [];
197         if (defined($carousel->owning_lib_filter)) {
198             my $ou_filter = $carousel->owning_lib_filter;
199             $ou_filter =~ s/[{}]//g;
200             @$orgs = split /,/, $ou_filter;
201         }
202         if (defined($carousel->copy_location_filter)) {
203             my $loc_filter = $carousel->copy_location_filter;
204             $loc_filter =~ s/[{}]//g;
205             @$locs = split /,/, $loc_filter;
206         }
207
208         my @res = $meth->run($carousel->bucket, $carousel->type, $carousel->age_filter, $orgs, $locs, $carousel->max_items);
209         my $ct = scalar(@res) ? $res[0] : 0;
210
211         $e->xact_begin;
212         $carousel->last_refresh_time('now');
213         $e->update_container_carousel($carousel);
214         $e->xact_commit;
215
216         $client->respond({
217             carousel => $carousel->id,
218             bucket   => $carousel->bucket,
219             updated  => $ct
220         });
221
222     }
223     $e->disconnect;
224     return undef;
225 }
226
227 __PACKAGE__->register_method(
228     api_name    => 'open-ils.storage.carousel.refresh_all',
229     method      => 'refresh_all_carousels',
230     api_level   => 1,
231     stream      => 1,
232     cachable    => 1,
233 );
234
235
236 1;