Bug 12478 - pile of elasticsearch code
[koha.git] / C4 / Suggestions.pm
blob63e10ed2faca491af11c13d4eb421e97a1db8999
1 package C4::Suggestions;
3 # Copyright 2000-2002 Katipo Communications
4 # Parts Copyright Biblibre 2011
6 # This file is part of Koha.
8 # Koha is free software; you can redistribute it and/or modify it
9 # under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 3 of the License, or
11 # (at your option) any later version.
13 # Koha is distributed in the hope that it will be useful, but
14 # WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with Koha; if not, see <http://www.gnu.org/licenses>.
21 use strict;
23 #use warnings; FIXME - Bug 2505
24 use CGI qw ( -utf8 );
26 use C4::Context;
27 use C4::Output;
28 use C4::Debug;
29 use C4::Letters;
30 use Koha::DateUtils;
32 use List::MoreUtils qw(any);
33 use base qw(Exporter);
35 our @EXPORT = qw(
36 ConnectSuggestionAndBiblio
37 CountSuggestion
38 DelSuggestion
39 GetSuggestion
40 GetSuggestionByStatus
41 GetSuggestionFromBiblionumber
42 GetSuggestionInfoFromBiblionumber
43 GetSuggestionInfo
44 ModStatus
45 ModSuggestion
46 NewSuggestion
47 SearchSuggestion
48 DelSuggestionsOlderThan
49 GetUnprocessedSuggestions
52 =head1 NAME
54 C4::Suggestions - Some useful functions for dealings with aqorders.
56 =head1 SYNOPSIS
58 use C4::Suggestions;
60 =head1 DESCRIPTION
62 The functions in this module deal with the aqorders in OPAC and in librarian interface
64 A suggestion is done in the OPAC. It has the status "ASKED"
66 When a librarian manages the suggestion, he can set the status to "REJECTED" or "ACCEPTED".
68 When the book is ordered, the suggestion status becomes "ORDERED"
70 When a book is ordered and arrived in the library, the status becomes "AVAILABLE"
72 All aqorders of a borrower can be seen by the borrower itself.
73 Suggestions done by other borrowers can be seen when not "AVAILABLE"
75 =head1 FUNCTIONS
77 =head2 SearchSuggestion
79 (\@array) = &SearchSuggestion($suggestionhashref_to_search)
81 searches for a suggestion
83 return :
84 C<\@array> : the aqorders found. Array of hash.
85 Note the status is stored twice :
86 * in the status field
87 * as parameter ( for example ASKED => 1, or REJECTED => 1) . This is for template & translation purposes.
89 =cut
91 sub SearchSuggestion {
92 my ($suggestion) = @_;
93 my $dbh = C4::Context->dbh;
94 my @sql_params;
95 my @query = (
97 SELECT suggestions.*,
98 U1.branchcode AS branchcodesuggestedby,
99 B1.branchname AS branchnamesuggestedby,
100 U1.surname AS surnamesuggestedby,
101 U1.firstname AS firstnamesuggestedby,
102 U1.cardnumber AS cardnumbersuggestedby,
103 U1.email AS emailsuggestedby,
104 U1.borrowernumber AS borrnumsuggestedby,
105 U1.categorycode AS categorycodesuggestedby,
106 C1.description AS categorydescriptionsuggestedby,
107 U2.surname AS surnamemanagedby,
108 U2.firstname AS firstnamemanagedby,
109 B2.branchname AS branchnamesuggestedby,
110 U2.email AS emailmanagedby,
111 U2.branchcode AS branchcodemanagedby,
112 U2.borrowernumber AS borrnummanagedby
113 FROM suggestions
114 LEFT JOIN borrowers AS U1 ON suggestedby=U1.borrowernumber
115 LEFT JOIN branches AS B1 ON B1.branchcode=U1.branchcode
116 LEFT JOIN categories AS C1 ON C1.categorycode=U1.categorycode
117 LEFT JOIN borrowers AS U2 ON managedby=U2.borrowernumber
118 LEFT JOIN branches AS B2 ON B2.branchcode=U2.branchcode
119 LEFT JOIN categories AS C2 ON C2.categorycode=U2.categorycode
120 WHERE 1=1
124 # filter on biblio informations
125 foreach my $field (
126 qw( title author isbn publishercode copyrightdate collectiontitle ))
128 if ( $suggestion->{$field} ) {
129 push @sql_params, '%' . $suggestion->{$field} . '%';
130 push @query, qq{ AND suggestions.$field LIKE ? };
134 # filter on user branch
135 if ( C4::Context->preference('IndependentBranches') ) {
136 my $userenv = C4::Context->userenv;
137 if ($userenv) {
138 if ( !C4::Context->IsSuperLibrarian() && !$suggestion->{branchcode} )
140 push @sql_params, $$userenv{branch};
141 push @query, q{
142 AND (suggestions.branchcode=? OR suggestions.branchcode='')
146 } else {
147 if ( defined $suggestion->{branchcode} && $suggestion->{branchcode} ) {
148 unless ( $suggestion->{branchcode} eq '__ANY__' ) {
149 push @sql_params, $suggestion->{branchcode};
150 push @query, qq{ AND suggestions.branchcode=? };
155 # filter on nillable fields
156 foreach my $field (
157 qw( STATUS itemtype suggestedby managedby acceptedby budgetid biblionumber )
160 if ( exists $suggestion->{$field}
161 and defined $suggestion->{$field}
162 and $suggestion->{$field} ne '__ANY__'
163 and $suggestion->{$field} ne q||
165 if ( $suggestion->{$field} eq '__NONE__' ) {
166 push @query, qq{ AND (suggestions.$field = '' OR suggestions.$field IS NULL) };
168 else {
169 push @sql_params, $suggestion->{$field};
170 push @query, qq{ AND suggestions.$field = ? };
175 # filter on date fields
176 foreach my $field (qw( suggesteddate manageddate accepteddate )) {
177 my $from = $field . "_from";
178 my $to = $field . "_to";
179 my $from_dt;
180 $from_dt = eval { dt_from_string( $suggestion->{$from} ) } if ( $suggestion->{$from} );
181 my $from_sql = '0000-00-00';
182 $from_sql = output_pref({ dt => $from_dt, dateformat => 'iso', dateonly => 1 })
183 if ($from_dt);
184 $debug && warn "SQL for start date ($field): $from_sql";
185 if ( $suggestion->{$from} || $suggestion->{$to} ) {
186 push @query, qq{ AND suggestions.$field BETWEEN ? AND ? };
187 push @sql_params, $from_sql;
188 push @sql_params,
189 output_pref({ dt => dt_from_string( $suggestion->{$to} ), dateformat => 'iso', dateonly => 1 }) || output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 });
193 $debug && warn "@query";
194 my $sth = $dbh->prepare("@query");
195 $sth->execute(@sql_params);
196 my @results;
198 # add status as field
199 while ( my $data = $sth->fetchrow_hashref ) {
200 $data->{ $data->{STATUS} } = 1;
201 push( @results, $data );
204 return ( \@results );
207 =head2 GetSuggestion
209 \%sth = &GetSuggestion($suggestionid)
211 this function get the detail of the suggestion $suggestionid (input arg)
213 return :
214 the result of the SQL query as a hash : $sth->fetchrow_hashref.
216 =cut
218 sub GetSuggestion {
219 my ($suggestionid) = @_;
220 my $dbh = C4::Context->dbh;
221 my $query = q{
222 SELECT *
223 FROM suggestions
224 WHERE suggestionid=?
226 my $sth = $dbh->prepare($query);
227 $sth->execute($suggestionid);
228 return ( $sth->fetchrow_hashref );
231 =head2 GetSuggestionFromBiblionumber
233 $ordernumber = &GetSuggestionFromBiblionumber($biblionumber)
235 Get a suggestion from it's biblionumber.
237 return :
238 the id of the suggestion which is related to the biblionumber given on input args.
240 =cut
242 sub GetSuggestionFromBiblionumber {
243 my ($biblionumber) = @_;
244 my $query = q{
245 SELECT suggestionid
246 FROM suggestions
247 WHERE biblionumber=? LIMIT 1
249 my $dbh = C4::Context->dbh;
250 my $sth = $dbh->prepare($query);
251 $sth->execute($biblionumber);
252 my ($suggestionid) = $sth->fetchrow;
253 return $suggestionid;
256 =head2 GetSuggestionInfoFromBiblionumber
258 Get a suggestion and borrower's informations from it's biblionumber.
260 return :
261 all informations (suggestion and borrower) of the suggestion which is related to the biblionumber given.
263 =cut
265 sub GetSuggestionInfoFromBiblionumber {
266 my ($biblionumber) = @_;
267 my $query = q{
268 SELECT suggestions.*,
269 U1.surname AS surnamesuggestedby,
270 U1.firstname AS firstnamesuggestedby,
271 U1.borrowernumber AS borrnumsuggestedby
272 FROM suggestions
273 LEFT JOIN borrowers AS U1 ON suggestedby=U1.borrowernumber
274 WHERE biblionumber=?
275 LIMIT 1
277 my $dbh = C4::Context->dbh;
278 my $sth = $dbh->prepare($query);
279 $sth->execute($biblionumber);
280 return $sth->fetchrow_hashref;
283 =head2 GetSuggestionInfo
285 Get a suggestion and borrower's informations from it's suggestionid
287 return :
288 all informations (suggestion and borrower) of the suggestion which is related to the suggestionid given.
290 =cut
292 sub GetSuggestionInfo {
293 my ($suggestionid) = @_;
294 my $query = q{
295 SELECT suggestions.*,
296 U1.surname AS surnamesuggestedby,
297 U1.firstname AS firstnamesuggestedby,
298 U1.borrowernumber AS borrnumsuggestedby
299 FROM suggestions
300 LEFT JOIN borrowers AS U1 ON suggestedby=U1.borrowernumber
301 WHERE suggestionid=?
302 LIMIT 1
304 my $dbh = C4::Context->dbh;
305 my $sth = $dbh->prepare($query);
306 $sth->execute($suggestionid);
307 return $sth->fetchrow_hashref;
310 =head2 GetSuggestionByStatus
312 $aqorders = &GetSuggestionByStatus($status,[$branchcode])
314 Get a suggestion from it's status
316 return :
317 all the suggestion with C<$status>
319 =cut
321 sub GetSuggestionByStatus {
322 my $status = shift;
323 my $branchcode = shift;
324 my $dbh = C4::Context->dbh;
325 my @sql_params = ($status);
326 my $query = q{
327 SELECT suggestions.*,
328 U1.surname AS surnamesuggestedby,
329 U1.firstname AS firstnamesuggestedby,
330 U1.branchcode AS branchcodesuggestedby,
331 B1.branchname AS branchnamesuggestedby,
332 U1.borrowernumber AS borrnumsuggestedby,
333 U1.categorycode AS categorycodesuggestedby,
334 C1.description AS categorydescriptionsuggestedby,
335 U2.surname AS surnamemanagedby,
336 U2.firstname AS firstnamemanagedby,
337 U2.borrowernumber AS borrnummanagedby
338 FROM suggestions
339 LEFT JOIN borrowers AS U1 ON suggestedby=U1.borrowernumber
340 LEFT JOIN borrowers AS U2 ON managedby=U2.borrowernumber
341 LEFT JOIN categories AS C1 ON C1.categorycode=U1.categorycode
342 LEFT JOIN branches AS B1 on B1.branchcode=U1.branchcode
343 WHERE status = ?
346 # filter on branch
347 if ( C4::Context->preference("IndependentBranches") || $branchcode ) {
348 my $userenv = C4::Context->userenv;
349 if ($userenv) {
350 unless ( C4::Context->IsSuperLibrarian() ) {
351 push @sql_params, $userenv->{branch};
352 $query .= q{ AND (U1.branchcode = ? OR U1.branchcode ='') };
355 if ($branchcode) {
356 push @sql_params, $branchcode;
357 $query .= q{ AND (U1.branchcode = ? OR U1.branchcode ='') };
361 my $sth = $dbh->prepare($query);
362 $sth->execute(@sql_params);
363 my $results;
364 $results = $sth->fetchall_arrayref( {} );
365 return $results;
368 =head2 CountSuggestion
370 &CountSuggestion($status)
372 Count the number of aqorders with the status given on input argument.
373 the arg status can be :
375 =over 2
377 =item * ASKED : asked by the user, not dealed by the librarian
379 =item * ACCEPTED : accepted by the librarian, but not yet ordered
381 =item * REJECTED : rejected by the librarian (definitive status)
383 =item * ORDERED : ordered by the librarian (acquisition module)
385 =back
387 return :
388 the number of suggestion with this status.
390 =cut
392 sub CountSuggestion {
393 my ($status) = @_;
394 my $dbh = C4::Context->dbh;
395 my $sth;
396 my $userenv = C4::Context->userenv;
397 if ( C4::Context->preference("IndependentBranches")
398 && !C4::Context->IsSuperLibrarian() )
400 my $query = q{
401 SELECT count(*)
402 FROM suggestions
403 LEFT JOIN borrowers ON borrowers.borrowernumber=suggestions.suggestedby
404 WHERE STATUS=?
405 AND (borrowers.branchcode='' OR borrowers.branchcode=?)
407 $sth = $dbh->prepare($query);
408 $sth->execute( $status, $userenv->{branch} );
410 else {
411 my $query = q{
412 SELECT count(*)
413 FROM suggestions
414 WHERE STATUS=?
416 $sth = $dbh->prepare($query);
417 $sth->execute($status);
419 my ($result) = $sth->fetchrow;
420 return $result;
423 =head2 NewSuggestion
426 &NewSuggestion($suggestion);
428 Insert a new suggestion on database with value given on input arg.
430 =cut
432 sub NewSuggestion {
433 my ($suggestion) = @_;
435 for my $field ( qw(
436 suggestedby
437 managedby
438 manageddate
439 acceptedby
440 accepteddate
441 rejectedby
442 rejecteddate
443 budgetid
444 ) ) {
445 # Set the fields to NULL if not given.
446 $suggestion->{$field} ||= undef;
449 $suggestion->{STATUS} = "ASKED" unless $suggestion->{STATUS};
451 $suggestion->{suggesteddate} = dt_from_string unless $suggestion->{suggesteddate};
453 my $rs = Koha::Database->new->schema->resultset('Suggestion');
454 return $rs->create($suggestion)->id;
457 =head2 ModSuggestion
459 &ModSuggestion($suggestion)
461 Modify the suggestion according to the hash passed by ref.
462 The hash HAS to contain suggestionid
463 Data not defined is not updated unless it is a note or sort1
464 Send a mail to notify the user that did the suggestion.
466 Note that there is no function to modify a suggestion.
468 =cut
470 sub ModSuggestion {
471 my ($suggestion) = @_;
472 return unless( $suggestion and defined($suggestion->{suggestionid}) );
474 for my $field ( qw(
475 suggestedby
476 managedby
477 manageddate
478 acceptedby
479 accepteddate
480 rejectedby
481 rejecteddate
482 budgetid
483 ) ) {
484 # Set the fields to NULL if not given.
485 $suggestion->{$field} = undef
486 if exists $suggestion->{$field}
487 and ($suggestion->{$field} eq '0'
488 or $suggestion->{$field} eq '' );
491 my $rs = Koha::Database->new->schema->resultset('Suggestion')->find($suggestion->{suggestionid});
492 my $status_update_table = 1;
493 eval {
494 $rs->update($suggestion);
496 $status_update_table = 0 if( $@ );
498 if ( $suggestion->{STATUS} ) {
500 # fetch the entire updated suggestion so that we can populate the letter
501 my $full_suggestion = GetSuggestion( $suggestion->{suggestionid} );
502 if (
503 my $letter = C4::Letters::GetPreparedLetter(
504 module => 'suggestions',
505 letter_code => $full_suggestion->{STATUS},
506 branchcode => $full_suggestion->{branchcode},
507 tables => {
508 'branches' => $full_suggestion->{branchcode},
509 'borrowers' => $full_suggestion->{suggestedby},
510 'suggestions' => $full_suggestion,
511 'biblio' => $full_suggestion->{biblionumber},
516 C4::Letters::EnqueueLetter(
518 letter => $letter,
519 borrowernumber => $full_suggestion->{suggestedby},
520 suggestionid => $full_suggestion->{suggestionid},
521 LibraryName => C4::Context->preference("LibraryName"),
522 message_transport_type => 'email',
524 ) or warn "can't enqueue letter $letter";
527 return $status_update_table;
530 =head2 ConnectSuggestionAndBiblio
532 &ConnectSuggestionAndBiblio($ordernumber,$biblionumber)
534 connect a suggestion to an existing biblio
536 =cut
538 sub ConnectSuggestionAndBiblio {
539 my ( $suggestionid, $biblionumber ) = @_;
540 my $dbh = C4::Context->dbh;
541 my $query = q{
542 UPDATE suggestions
543 SET biblionumber=?
544 WHERE suggestionid=?
546 my $sth = $dbh->prepare($query);
547 $sth->execute( $biblionumber, $suggestionid );
550 =head2 DelSuggestion
552 &DelSuggestion($borrowernumber,$ordernumber)
554 Delete a suggestion. A borrower can delete a suggestion only if he is its owner.
556 =cut
558 sub DelSuggestion {
559 my ( $borrowernumber, $suggestionid, $type ) = @_;
560 my $dbh = C4::Context->dbh;
562 # check that the suggestion comes from the suggestor
563 my $query = q{
564 SELECT suggestedby
565 FROM suggestions
566 WHERE suggestionid=?
568 my $sth = $dbh->prepare($query);
569 $sth->execute($suggestionid);
570 my ($suggestedby) = $sth->fetchrow;
571 if ( $type eq 'intranet' || $suggestedby eq $borrowernumber ) {
572 my $queryDelete = q{
573 DELETE FROM suggestions
574 WHERE suggestionid=?
576 $sth = $dbh->prepare($queryDelete);
577 my $suggestiondeleted = $sth->execute($suggestionid);
578 return $suggestiondeleted;
582 =head2 DelSuggestionsOlderThan
583 &DelSuggestionsOlderThan($days)
585 Delete all suggestions older than TODAY-$days , that have be accepted or rejected.
587 =cut
589 sub DelSuggestionsOlderThan {
590 my ($days) = @_;
591 return unless $days;
592 my $dbh = C4::Context->dbh;
593 my $sth = $dbh->prepare(
595 DELETE FROM suggestions
596 WHERE STATUS<>'ASKED'
597 AND date < ADDDATE(NOW(), ?)
600 $sth->execute("-$days");
603 sub GetUnprocessedSuggestions {
604 my ( $number_of_days_since_the_last_modification ) = @_;
606 $number_of_days_since_the_last_modification ||= 0;
608 my $dbh = C4::Context->dbh;
610 my $s = $dbh->selectall_arrayref(q|
611 SELECT *
612 FROM suggestions
613 WHERE STATUS = 'ASKED'
614 AND budgetid IS NOT NULL
615 AND CAST(NOW() AS DATE) - INTERVAL ? DAY = CAST(suggesteddate AS DATE)
616 |, { Slice => {} }, $number_of_days_since_the_last_modification );
617 return $s;
621 __END__
624 =head1 AUTHOR
626 Koha Development Team <http://koha-community.org/>
628 =cut