1 package OpenILS::Application::Storage::Publisher::container;
2 use base qw/OpenILS::Application::Storage/;
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;
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)
17 WHERE acn.owning_lib IN (ORG_LIST)
18 AND acp.circ_lib IN (ORG_LIST)
21 AND acp.deleted is false
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))
30 ORDER BY MIN(AGE(acp.active_date))
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)
42 WHERE acn.owning_lib IN (ORG_LIST)
43 AND acp.circ_lib IN (ORG_LIST)
46 AND acp.deleted is false
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))
56 ORDER BY MIN(AGE(circ.checkin_time))
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)
68 WHERE acn.owning_lib IN (ORG_LIST)
69 AND acp.circ_lib IN (ORG_LIST)
72 AND acp.deleted is false
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))
81 ORDER BY COUNT(circ.id) DESC
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)
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)
98 AND acp.deleted is false
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))
105 ORDER BY MIN(AGE(acp.active_date))
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,
116 sub refresh_container_from_carousel_definition {
120 my $carousel_type = shift;
121 my $age = shift // '15 days';
122 my $libs = shift // [];
123 my $locs = shift // [];
124 my $limit = shift // 50;
126 my $e = OpenILS::Utils::CStoreEditor->new;
127 my $ctype = $e->retrieve_config_carousel_type($carousel_type) or return $e->die_event;
130 unless (exists($TYPE_QUERY_MAP{$carousel_type})) {
131 $logger->error("Carousel for bucket $bucket is misconfigured; type $carousel_type is not recognized");
135 my $query = $TYPE_QUERY_MAP{$carousel_type};
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");
142 my $org_placeholders = join(',', map { '?' } @$libs);
143 $query =~ s/ORG_LIST/$org_placeholders/g;
145 $libs = []; # we'll ignore any superflous supplied values
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");
153 my $loc_placeholders = join(',', map { '?' } @$locs);
154 $query =~ s/-- LOC //g;
155 $query =~ s/LOC_LIST/$loc_placeholders/g;
157 $locs = []; # we'll ignore any superflous supplied values
160 my $sth = container::biblio_record_entry_bucket_item->db_Main->prepare_cached($query);
162 $sth->execute(@$libs, @$libs, $age, @$locs, $limit);
164 while (my $row = $sth->fetchrow_hashref ) {
165 push @bibs, $row->{bib};
167 container::biblio_record_entry_bucket_item->search( bucket => $bucket )->delete_all;
169 foreach my $bib (@bibs) {
170 container::biblio_record_entry_bucket_item->create({ bucket => $bucket, target_biblio_record_entry => $bib, pos => $i++ });
172 return scalar(@bibs);
175 __PACKAGE__->register_method(
176 api_name => 'open-ils.storage.container.refresh_from_carousel',
177 method => 'refresh_container_from_carousel_definition',
182 sub refresh_all_carousels {
186 my $e = OpenILS::Utils::CStoreEditor->new;
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' });
191 my $meth = $self->method_lookup('open-ils.storage.container.refresh_from_carousel');
193 foreach my $carousel (@$carousels) {
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;
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;
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;
212 $carousel->last_refresh_time('now');
213 $e->update_container_carousel($carousel);
217 carousel => $carousel->id,
218 bucket => $carousel->bucket,
227 __PACKAGE__->register_method(
228 api_name => 'open-ils.storage.carousel.refresh_all',
229 method => 'refresh_all_carousels',