further item-level itype changes
[koha.git] / C4 / Overdues.pm
1 package C4::Overdues;
2
3
4 # Copyright 2000-2002 Katipo Communications
5 #
6 # This file is part of Koha.
7 #
8 # Koha is free software; you can redistribute it and/or modify it under the
9 # terms of the GNU General Public License as published by the Free Software
10 # Foundation; either version 2 of the License, or (at your option) any later
11 # version.
12 #
13 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
14 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License along with
18 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
19 # Suite 330, Boston, MA  02111-1307 USA
20
21 use strict;
22 require Exporter;
23 use C4::Context;
24 use Date::Calc qw/Today/;
25 use vars qw($VERSION @ISA @EXPORT);
26 use C4::Accounts;
27 use Date::Manip qw/UnixDate/;
28 use C4::Log; # logaction
29
30 # set the version for version checking
31 $VERSION = 3.00;
32
33 =head1 NAME
34
35 C4::Circulation::Fines - Koha module dealing with fines
36
37 =head1 SYNOPSIS
38
39   use C4::Overdues;
40
41 =head1 DESCRIPTION
42
43 This module contains several functions for dealing with fines for
44 overdue items. It is primarily used by the 'misc/fines2.pl' script.
45
46 =head1 FUNCTIONS
47
48 =over 2
49
50 =cut
51
52 @ISA    = qw(Exporter);
53 # subs to rename (and maybe merge some...)
54 push @EXPORT, qw(
55         &CalcFine
56         &Getoverdues
57         &checkoverdues
58         &CheckAccountLineLevelInfo
59         &CheckAccountLineItemInfo
60         &CheckExistantNotifyid
61         &GetNextIdNotify
62         &GetNotifyId
63         &NumberNotifyId
64         &AmountNotify
65         &UpdateAccountLines
66         &UpdateFine
67         &GetOverdueDelays
68         &GetOverduerules
69         &GetFine
70         &CreateItemAccountLine
71         &ReplacementCost2
72         
73         &CheckItemNotify
74         &GetOverduesForBranch
75         &RemoveNotifyLine
76         &AddNotifyLine
77 );
78 # subs to remove
79 push @EXPORT, qw(
80         &BorType
81 );
82
83 #
84 # All subs to move : check that an equivalent don't exist already before moving
85 #
86
87 # subs to move to Circulation.pm
88 push @EXPORT, qw(
89         &GetIssuingRules
90         &GetIssuesIteminfo
91 );
92 # subs to move to Members.pm
93 push @EXPORT, qw(
94         &CheckBorrowerDebarred
95         &UpdateBorrowerDebarred
96 );
97 # subs to move to Biblio.pm
98 push @EXPORT, qw(
99         &GetItems
100         &ReplacementCost
101 );
102
103 =item Getoverdues
104
105   ($overdues) = &Getoverdues();
106
107 Returns the list of all overdue books, with their itemtype.
108
109 C<$overdues> is a reference-to-array. Each element is a
110 reference-to-hash whose keys are the fields of the issues table in the
111 Koha database.
112
113 =cut
114
115 #'
116 sub Getoverdues {
117     my $dbh = C4::Context->dbh;
118         my $itype_q = (C4::context->preference('item-level_itype')) ? " items.ccode as itemtype "
119     my $sth =  (C4::context->preference('item-level_itype')) ? 
120                                 $dbh->prepare(
121                                 "SELECT issues.*,items.ccode as itemtype FROM issues 
122                         LEFT JOIN items USING (itemnumber)
123                         WHERE date_due < now() 
124                             AND returndate IS NULL ORDER BY borrowernumber " )
125                                 :
126                                 $dbh->prepare(
127                     "SELECT issues.*,biblioitems.itemtype,items.ccode FROM issues 
128                     LEFT JOIN items USING (itemnumber)
129                     LEFT JOIN biblioitems USING (biblioitemnumber)
130                     WHERE date_due < now() 
131                         AND returndate IS 
132                         NULL ORDER BY borrowernumber " );
133     $sth->execute;
134
135     my @results;
136     while ( my $data = $sth->fetchrow_hashref ) {
137         push @results, $data;
138     }
139     $sth->finish;
140
141     return \@results;
142 }
143
144 =head2 checkoverdues
145
146 ( $count, $overdueitems )=checkoverdues( $borrowernumber, $dbh );
147
148 Not exported
149
150 =cut
151
152 sub checkoverdues {
153
154 # From Main.pm, modified to return a list of overdueitems, in addition to a count
155 #checks whether a borrower has overdue items
156     my ( $borrowernumber, $dbh ) = @_;
157     my @datearr = localtime;
158     my $today   =
159       ( $datearr[5] + 1900 ) . "-" . ( $datearr[4] + 1 ) . "-" . $datearr[3];
160     my @overdueitems;
161     my $count = 0;
162     my $sth   = $dbh->prepare(
163         "SELECT * FROM issues
164          LEFT JOIN items ON issues.itemnumber      = items.itemnumber
165          LEFT JOIN biblio ON items.biblionumber=biblio.biblionumber
166          LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber
167             WHERE issues.borrowernumber  = ?
168                 AND issues.returndate is NULL
169                 AND issues.date_due < ?"
170     );
171     $sth->execute( $borrowernumber, $today );
172     while ( my $data = $sth->fetchrow_hashref ) {
173         push( @overdueitems, $data );
174         $count++;
175     }
176     $sth->finish;
177     return ( $count, \@overdueitems );
178 }
179
180 =item CalcFine
181
182   ($amount, $chargename, $message) =
183     &CalcFine($itemnumber, $borrowercode, $days_overdue);
184
185 Calculates the fine for a book.
186
187 The issuingrules table in the Koha database is a fine matrix, listing
188 the penalties for each type of patron for each type of item and each branch (e.g., the
189 standard fine for books might be $0.50, but $1.50 for DVDs, or staff
190 members might get a longer grace period between the first and second
191 reminders that a book is overdue).
192
193 The fine is calculated as follows: if it is time for the first
194 reminder, the fine is the value listed for the given (branch, item type,
195 borrower code) combination. If it is time for the second reminder, the
196 fine is doubled. Finally, if it is time to send the account to a
197 collection agency, the fine is set to 5 local monetary units (a really
198 good deal for the patron if the library is in Italy). Otherwise, the
199 fine is 0.
200
201 Note that the way this function is currently implemented, it only
202 returns a nonzero value on the notable days listed above. That is, if
203 the categoryitems entry says to send a first reminder 7 days after the
204 book is due, then if you call C<&CalcFine> 7 days after the book is
205 due, it will give a nonzero fine. If you call C<&CalcFine> the next
206 day, however, it will say that the fine is 0.
207
208 C<$itemnumber> is the book's item number.
209
210 C<$borrowercode> is the borrower code of the patron who currently has
211 the book.
212
213 C<$days_overdue> is the number of days elapsed since the book's due
214 date.
215
216 C<&CalcFine> returns a list of three values:
217
218 C<$amount> is the fine owed by the patron (see above).
219
220 C<$chargename> is the chargename field from the applicable record in
221 the categoryitem table, whatever that is.
222
223 C<$message> is a text message, either "First Notice", "Second Notice",
224 or "Final Notice".
225
226 =cut
227
228 #'
229 sub CalcFine {
230     my ( $item, $bortype, $difference , $dues  ) = @_;
231     my $dbh = C4::Context->dbh;
232     my $amount = 0;
233     my $printout;
234     # calculate how many days the patron is late
235     my $countspecialday=&GetSpecialHolidays($dues,$item->{itemnumber});
236     my $countrepeatableday=&GetRepeatableHolidays($dues,$item->{itemnumber},$difference);    
237     my $countalldayclosed = $countspecialday + $countrepeatableday;
238     my $daycount = $difference - $countalldayclosed;
239     # get issuingrules (fines part will be used)
240     my $data = GetIssuingRules($item->{'itemtype'},$bortype);
241     my $daycounttotal = $daycount - $data->{'firstremind'};
242     if ($data->{'chargeperiod'} >0) { # if there is a rule for this bortype
243         if ($data->{'firstremind'} < $daycount)
244             {
245             $amount   = int($daycounttotal/$data->{'chargeperiod'})*$data->{'fine'};
246         }
247     } else {
248         # get fines default rules
249         my $data = GetIssuingRules($item->{'itemtype'},'*');
250         $daycounttotal = $daycount - $data->{'firstremind'};
251         if ($data->{'firstremind'} < $daycount)
252             {
253                 if ($data->{'chargeperiod'} >0) { # if there is a rule for this bortype
254                     $amount   = int($daycounttotal/$data->{'chargeperiod'})*$data->{'fine'};
255                 }
256             }
257     }
258     
259     warn "Calc Fine for $item->{'itemnumber'}, $bortype, $difference , $dues = $amount / $daycount";
260  return ( $amount, $data->{'chargename'}, $printout ,$daycounttotal ,$daycount );
261 }
262
263
264 =item GetSpecialHolidays
265
266 &GetSpecialHolidays($date_dues,$itemnumber);
267
268 return number of special days  between date of the day and date due
269
270 C<$date_dues> is the envisaged date of book return.
271
272 C<$itemnumber> is the book's item number.
273
274 =cut
275
276 sub GetSpecialHolidays {
277 my ($date_dues,$itemnumber) = @_;
278 # calcul the today date
279 my $today = join "-", &Today();
280
281 # return the holdingbranch
282 my $iteminfo=GetIssuesIteminfo($itemnumber);
283 # use sql request to find all date between date_due and today
284 my $dbh = C4::Context->dbh;
285 my $query=qq|SELECT DATE_FORMAT(concat(year,'-',month,'-',day),'%Y-%m-%d')as date 
286 FROM `special_holidays`
287 WHERE DATE_FORMAT(concat(year,'-',month,'-',day),'%Y-%m-%d') >= ?
288 AND   DATE_FORMAT(concat(year,'-',month,'-',day),'%Y-%m-%d') <= ?
289 AND branchcode=?
290 |;
291 my @result=GetWdayFromItemnumber($itemnumber);
292 my @result_date;
293 my $wday;
294 my $dateinsec;
295 my $sth = $dbh->prepare($query);
296 $sth->execute($date_dues,$today,$iteminfo->{'branchcode'});
297
298 while ( my $special_date=$sth->fetchrow_hashref){
299     push (@result_date,$special_date);
300 }
301
302 my $specialdaycount=scalar(@result_date);
303
304     for (my $i=0;$i<scalar(@result_date);$i++){
305         $dateinsec=UnixDate($result_date[$i]->{'date'},"%o");
306         (undef,undef,undef,undef,undef,undef,$wday,undef,undef) =localtime($dateinsec);
307         for (my $j=0;$j<scalar(@result);$j++){
308             if ($wday == ($result[$j]->{'weekday'})){
309             $specialdaycount --;
310             }
311         }
312     }
313
314 return $specialdaycount;
315 }
316
317 =item GetRepeatableHolidays
318
319 &GetRepeatableHolidays($date_dues, $itemnumber, $difference,);
320
321 return number of day closed between date of the day and date due
322
323 C<$date_dues> is the envisaged date of book return.
324
325 C<$itemnumber> is item number.
326
327 C<$difference> numbers of between day date of the day and date due
328
329 =cut
330
331 sub GetRepeatableHolidays{
332 my ($date_dues,$itemnumber,$difference) = @_;
333 my $dateinsec=UnixDate($date_dues,"%o");
334 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =localtime($dateinsec);
335 my @result=GetWdayFromItemnumber($itemnumber);
336 my @dayclosedcount;
337 my $j;
338
339 for (my $i=0;$i<scalar(@result);$i++){
340     my $k=$wday;
341
342         for ( $j=0;$j<$difference;$j++){
343             if ($result[$i]->{'weekday'} == $k)
344                     {
345                     push ( @dayclosedcount ,$k);
346             }
347         $k++;
348         ($k=0) if($k eq 7);
349         }
350     }
351 return scalar(@dayclosedcount);
352 }
353
354
355 =item GetWayFromItemnumber
356
357 &Getwdayfromitemnumber($itemnumber);
358
359 return the different week day from repeatable_holidays table
360
361 C<$itemnumber> is  item number.
362
363 =cut
364
365 sub GetWdayFromItemnumber{
366 my($itemnumber)=@_;
367 my $iteminfo=GetIssuesIteminfo($itemnumber);
368 my @result;
369 my $dbh = C4::Context->dbh;
370 my $query = qq|SELECT weekday  
371     FROM repeatable_holidays
372     WHERE branchcode=?
373 |;
374 my $sth = $dbh->prepare($query);
375     #  print $query;
376
377 $sth->execute($iteminfo->{'branchcode'});
378 while ( my $weekday=$sth->fetchrow_hashref){
379     push (@result,$weekday);
380     }
381 return @result;
382 }
383
384
385 =item GetIssuesIteminfo
386
387 &GetIssuesIteminfo($itemnumber);
388
389 return all data from issues about item
390
391 C<$itemnumber> is  item number.
392
393 =cut
394
395 sub GetIssuesIteminfo{
396 my($itemnumber)=@_;
397 my $dbh = C4::Context->dbh;
398 my $query = qq|SELECT *  
399     FROM issues
400     WHERE itemnumber=?
401 |;
402 my $sth = $dbh->prepare($query);
403 $sth->execute($itemnumber);
404 my ($issuesinfo)=$sth->fetchrow_hashref;
405 return $issuesinfo;
406 }
407
408
409 =item UpdateFine
410
411   &UpdateFine($itemnumber, $borrowernumber, $amount, $type, $description);
412
413 (Note: the following is mostly conjecture and guesswork.)
414
415 Updates the fine owed on an overdue book.
416
417 C<$itemnumber> is the book's item number.
418
419 C<$borrowernumber> is the borrower number of the patron who currently
420 has the book on loan.
421
422 C<$amount> is the current amount owed by the patron.
423
424 C<$type> will be used in the description of the fine.
425
426 C<$description> is a string that must be present in the description of
427 the fine. I think this is expected to be a date in DD/MM/YYYY format.
428
429 C<&UpdateFine> looks up the amount currently owed on the given item
430 and sets it to C<$amount>, creating, if necessary, a new entry in the
431 accountlines table of the Koha database.
432
433 =cut
434
435 #'
436 # FIXME - This API doesn't look right: why should the caller have to
437 # specify both the item number and the borrower number? A book can't
438 # be on loan to two different people, so the item number should be
439 # sufficient.
440 sub UpdateFine {
441     my ( $itemnum, $borrowernumber, $amount, $type, $due ) = @_;
442     my $dbh = C4::Context->dbh;
443     # FIXME - What exactly is this query supposed to do? It looks up an
444     # entry in accountlines that matches the given item and borrower
445     # numbers, where the description contains $due, and where the
446     # account type has one of several values, but what does this _mean_?
447     # Does it look up existing fines for this item?
448     # FIXME - What are these various account types? ("FU", "O", "F", "M")
449     my $sth = $dbh->prepare(
450         "Select * from accountlines where itemnumber=? and
451   borrowernumber=? and (accounttype='FU' or accounttype='O' or
452   accounttype='F' or accounttype='M') and description like ?"
453     );
454     $sth->execute( $itemnum, $borrowernumber, "%$due%" );
455
456     if ( my $data = $sth->fetchrow_hashref ) {
457
458         # I think this if-clause deals with the case where we're updating
459         # an existing fine.
460         #    print "in accounts ...";
461     if ( $data->{'amount'} != $amount ) {
462            
463         #      print "updating";
464             my $diff = $amount - $data->{'amount'};
465             my $out  = $data->{'amountoutstanding'} + $diff;
466             my $sth2 = $dbh->prepare(
467                 "UPDATE accountlines SET date=now(), amount=?,
468       amountoutstanding=?,accounttype='FU' WHERE
469       borrowernumber=? AND itemnumber=?
470       AND (accounttype='FU' OR accounttype='O') AND description LIKE ?"
471             );
472             $sth2->execute( $amount, $out, $data->{'borrowernumber'},
473                 $data->{'itemnumber'}, "%$due%" );
474             $sth2->finish;
475         }
476         else {
477
478             #      print "no update needed $data->{'amount'}"
479         }
480     }
481     else {
482
483         # I think this else-clause deals with the case where we're adding
484         # a new fine.
485         my $sth4 = $dbh->prepare(
486             "SELECT title FROM biblio LEFT JOIN items ON biblio.biblionumber=items.biblionumber WHERE items.itemnumber=?"
487         );
488         $sth4->execute($itemnum);
489         my $title = $sth4->fetchrow_hashref;
490         $sth4->finish;
491
492 #         #   print "not in account";
493 #         my $sth3 = $dbh->prepare("Select max(accountno) from accountlines");
494 #         $sth3->execute;
495
496 #         # FIXME - Make $accountno a scalar.
497 #         my @accountno = $sth3->fetchrow_array;
498 #         $sth3->finish;
499 #         $accountno[0]++;
500 # begin transaction
501   my $nextaccntno = C4::Accounts::getnextacctno($borrowernumber);
502     my $sth2 = $dbh->prepare(
503             "INSERT INTO accountlines
504     (borrowernumber,itemnumber,date,amount,
505     description,accounttype,amountoutstanding,accountno) VALUES
506     (?,?,now(),?,?,'FU',?,?)"
507         );
508         $sth2->execute( $borrowernumber, $itemnum, $amount,
509             "$type $title->{'title'} $due",
510             $amount, $nextaccntno);
511         $sth2->finish;
512     }
513     # logging action
514     &logaction(
515         C4::Context->userenv->{'number'},
516         "FINES",
517         $type,
518         $borrowernumber,
519         "due=".$due."  amount=".$amount." itemnumber=".$itemnum
520         ) if C4::Context->preference("FinesLog");
521
522     $sth->finish;
523 }
524
525 =item BorType
526
527   $borrower = &BorType($borrowernumber);
528
529 Looks up a patron by borrower number.
530
531 C<$borrower> is a reference-to-hash whose keys are all of the fields
532 from the borrowers and categories tables of the Koha database. Thus,
533 C<$borrower> contains all information about both the borrower and
534 category he or she belongs to.
535
536 =cut
537
538 #'
539 sub BorType {
540     my ($borrowernumber) = @_;
541     my $dbh              = C4::Context->dbh;
542     my $sth              = $dbh->prepare(
543         "SELECT * from borrowers 
544       LEFT JOIN categories ON borrowers.categorycode=categories.categorycode 
545       WHERE borrowernumber=?"
546     );
547     $sth->execute($borrowernumber);
548     my $data = $sth->fetchrow_hashref;
549     $sth->finish;
550     return ($data);
551 }
552
553 =item ReplacementCost
554
555   $cost = &ReplacementCost($itemnumber);
556
557 Returns the replacement cost of the item with the given item number.
558
559 =cut
560
561 #'
562 sub ReplacementCost {
563     my ($itemnum) = @_;
564     my $dbh       = C4::Context->dbh;
565     my $sth       =
566       $dbh->prepare("Select replacementprice from items where itemnumber=?");
567     $sth->execute($itemnum);
568
569     # FIXME - Use fetchrow_array or something.
570     my $data = $sth->fetchrow_hashref;
571     $sth->finish;
572     return ( $data->{'replacementprice'} );
573 }
574
575 =item GetFine
576
577 $data->{'sum(amountoutstanding)'} = &GetFine($itemnum,$borrowernumber);
578
579 return the total of fine
580
581 C<$itemnum> is item number
582
583 C<$borrowernumber> is the borrowernumber
584
585 =cut 
586
587
588 sub GetFine {
589     my ( $itemnum, $borrowernumber ) = @_;
590     my $dbh   = C4::Context->dbh();
591     my $query = "SELECT sum(amountoutstanding) FROM accountlines 
592     where accounttype like 'F%'  
593   AND amountoutstanding > 0 AND itemnumber = ? AND borrowernumber=?";
594     my $sth = $dbh->prepare($query);
595     $sth->execute( $itemnum, $borrowernumber );
596     my $data = $sth->fetchrow_hashref();
597     $sth->finish();
598     $dbh->disconnect();
599     return ( $data->{'sum(amountoutstanding)'} );
600 }
601
602
603
604
605 =item GetIssuingRules
606
607 $data = &GetIssuingRules($itemtype,$categorycode);
608
609 Looks up for all issuingrules an item info 
610
611 C<$itemnumber> is a reference-to-hash whose keys are all of the fields
612 from the borrowers and categories tables of the Koha database. Thus,
613
614 C<$categorycode> contains  information about borrowers category 
615
616 C<$data> contains all information about both the borrower and
617 category he or she belongs to.
618 =cut 
619
620 sub GetIssuingRules {
621    my ($itemtype,$categorycode)=@_;
622    my $dbh   = C4::Context->dbh();    
623    my $query=qq|SELECT * 
624         FROM issuingrules
625         WHERE issuingrules.itemtype=?
626             AND issuingrules.categorycode=?
627         |;
628     my $sth = $dbh->prepare($query);
629     #  print $query;
630     $sth->execute($itemtype,$categorycode);
631     my ($data) = $sth->fetchrow_hashref;
632    $sth->finish;
633 return ($data);
634
635 }
636
637
638 sub ReplacementCost2 {
639     my ( $itemnum, $borrowernumber ) = @_;
640     my $dbh   = C4::Context->dbh();
641     my $query = "SELECT amountoutstanding 
642          FROM accountlines
643              WHERE accounttype like 'L'
644          AND amountoutstanding > 0
645          AND itemnumber = ?
646          AND borrowernumber= ?";
647     my $sth = $dbh->prepare($query);
648     $sth->execute( $itemnum, $borrowernumber );
649     my $data = $sth->fetchrow_hashref();
650     $sth->finish();
651     $dbh->disconnect();
652     return ( $data->{'amountoutstanding'} );
653 }
654
655
656 =item GetNextIdNotify
657
658 ($result) = &GetNextIdNotify($reference);
659
660 Returns the new file number
661
662 C<$result> contains the next file number
663
664 C<$reference> contains the beggining of file number
665
666 =cut
667
668
669
670 sub GetNextIdNotify {
671 my ($reference)=@_;
672 my $query=qq|SELECT max(notify_id) 
673          FROM accountlines
674          WHERE notify_id  like \"$reference%\"
675          |;
676 # AND borrowernumber=?|;   
677 my $dbh = C4::Context->dbh;
678 my $sth=$dbh->prepare($query);
679 $sth->execute();
680 my $result=$sth->fetchrow;
681 $sth->finish;
682 my $count;
683     if ($result eq '')
684     {
685     ($result=$reference."01")  ;
686     }else
687     {
688     $count=substr($result,6)+1;
689      
690     if($count<10){
691      ($count = "0".$count);
692      }
693      $result=$reference.$count;
694      }
695 return $result;
696 }
697
698
699 =item AmountNotify
700
701 (@notify) = &AmountNotify($borrowernumber);
702
703 Returns amount for all file per borrowers
704 C<@notify> array contains all file per borrowers
705
706 C<$notify_id> contains the file number for the borrower number nad item number
707
708 =cut
709
710 sub NumberNotifyId{
711     my ($borrowernumber)=@_;
712     my $dbh = C4::Context->dbh;
713     my $query=qq|    SELECT distinct(notify_id)
714             FROM accountlines
715             WHERE borrowernumber=?|;
716     my @notify;
717     my $sth=$dbh->prepare($query);
718         $sth->execute($borrowernumber);
719           while ( my ($numberofnotify)=$sth->fetchrow){
720     push (@notify,$numberofnotify);
721     }
722     $sth->finish;
723
724     return (@notify);
725
726 }
727
728 =item AmountNotify
729
730 ($totalnotify) = &AmountNotify($notifyid);
731
732 Returns amount for all file per borrowers
733 C<$notifyid> is the file number
734
735 C<$totalnotify> contains amount of a file
736
737 C<$notify_id> contains the file number for the borrower number nad item number
738
739 =cut
740
741 sub AmountNotify{
742     my ($notifyid)=@_;
743     my $dbh = C4::Context->dbh;
744     my $query=qq|    SELECT sum(amountoutstanding)
745             FROM accountlines
746             WHERE notify_id=?|;
747     my $sth=$dbh->prepare($query);
748         $sth->execute($notifyid);
749           my $totalnotify=$sth->fetchrow;
750     $sth->finish;
751     return ($totalnotify);
752 }
753
754
755 =item GetNotifyId
756
757 ($notify_id) = &GetNotifyId($borrowernumber,$itemnumber);
758
759 Returns the file number per borrower and itemnumber
760
761 C<$borrowernumber> is a reference-to-hash whose keys are all of the fields
762 from the items tables of the Koha database. Thus,
763
764 C<$itemnumber> contains the borrower categorycode
765
766 C<$notify_id> contains the file number for the borrower number nad item number
767
768 =cut
769
770  sub GetNotifyId {
771  my ($borrowernumber,$itemnumber)=@_;
772  my $query=qq|SELECT notify_id 
773            FROM accountlines
774            WHERE borrowernumber=?
775           AND itemnumber=?
776            AND (accounttype='FU' or accounttype='O')|;
777  my $dbh = C4::Context->dbh;
778  my $sth=$dbh->prepare($query);
779  $sth->execute($borrowernumber,$itemnumber);
780  my ($notify_id)=$sth->fetchrow;
781  $sth->finish;
782  return ($notify_id);
783
784  }
785
786 =item CreateItemAccountLine
787
788 () = &CreateItemAccountLine($borrowernumber,$itemnumber,$date,$amount,$description,$accounttype,$amountoutstanding,$timestamp,$notify_id,$level);
789
790 update the account lines with file number or with file level
791
792 C<$items> is a reference-to-hash whose keys are all of the fields
793 from the items tables of the Koha database. Thus,
794
795 C<$itemnumber> contains the item number
796
797 C<$borrowernumber> contains the borrower number
798
799 C<$date> contains the date of the day
800
801 C<$amount> contains item price
802
803 C<$description> contains the descritpion of accounttype 
804
805 C<$accounttype> contains the account type
806
807 C<$amountoutstanding> contains the $amountoutstanding 
808
809 C<$timestamp> contains the timestamp with time and the date of the day
810
811 C<$notify_id> contains the file number
812
813 C<$level> contains the file level
814
815
816 =cut
817
818  sub CreateItemAccountLine {
819   my ($borrowernumber,$itemnumber,$date,$amount,$description,$accounttype,$amountoutstanding,$timestamp,$notify_id,$level)=@_;
820   my $dbh = C4::Context->dbh;
821   my $nextaccntno = getnextacctno($borrowernumber);
822    my $query= "INSERT into accountlines  
823          (borrowernumber,accountno,itemnumber,date,amount,description,accounttype,amountoutstanding,timestamp,notify_id,notify_level)
824           VALUES
825              (?,?,?,?,?,?,?,?,?,?,?)";
826   
827   
828   my $sth=$dbh->prepare($query);
829   $sth->execute($borrowernumber,$nextaccntno,$itemnumber,$date,$amount,$description,$accounttype,$amountoutstanding,$timestamp,$notify_id,$level);
830   $sth->finish;
831  }
832
833 =item UpdateAccountLines
834
835 () = &UpdateAccountLines($notify_id,$notify_level,$borrowernumber,$itemnumber);
836
837 update the account lines with file number or with file level
838
839 C<$items> is a reference-to-hash whose keys are all of the fields
840 from the items tables of the Koha database. Thus,
841
842 C<$itemnumber> contains the item number
843
844 C<$notify_id> contains the file number
845
846 C<$notify_level> contains the file level
847
848 C<$borrowernumber> contains the borrowernumber
849
850 =cut
851
852 sub UpdateAccountLines {
853 my ($notify_id,$notify_level,$borrowernumber,$itemnumber)=@_;
854 my $query;
855 if ($notify_id eq '')
856 {
857
858     $query=qq|UPDATE accountlines
859     SET  notify_level=?
860     WHERE borrowernumber=? AND itemnumber=?
861     AND (accounttype='FU' or accounttype='O')|;
862 }else
863 {
864     $query=qq|UPDATE accountlines
865      SET notify_id=?, notify_level=?
866            WHERE borrowernumber=?
867     AND itemnumber=?
868         AND (accounttype='FU' or accounttype='O')|;
869 }
870  my $dbh = C4::Context->dbh;
871  my $sth=$dbh->prepare($query);
872
873 if ($notify_id eq '')
874 {
875     $sth->execute($notify_level,$borrowernumber,$itemnumber);
876 }else
877 {
878     $sth->execute($notify_id,$notify_level,$borrowernumber,$itemnumber);
879 }
880  $sth->finish;
881
882 }
883
884
885 =item GetItems
886
887 ($items) = &GetItems($itemnumber);
888
889 Returns the list of all delays from overduerules.
890
891 C<$items> is a reference-to-hash whose keys are all of the fields
892 from the items tables of the Koha database. Thus,
893
894 C<$itemnumber> contains the borrower categorycode
895
896 =cut
897
898 sub GetItems {
899     my($itemnumber) = @_;
900     my $query=qq|SELECT *
901              FROM items
902               WHERE itemnumber=?|;
903         my $dbh = C4::Context->dbh;
904         my $sth=$dbh->prepare($query);
905         $sth->execute($itemnumber);
906         my ($items)=$sth->fetchrow_hashref;
907         $sth->finish;
908     return($items);
909 }
910
911 =item GetOverdueDelays
912
913 (@delays) = &GetOverdueDelays($categorycode);
914
915 Returns the list of all delays from overduerules.
916
917 C<@delays> it's an array contains the three delays from overduerules table
918
919 C<$categorycode> contains the borrower categorycode
920
921 =cut
922
923 sub GetOverdueDelays {
924     my($category) = @_;
925     my $dbh = C4::Context->dbh;
926         my $query=qq|SELECT delay1,delay2,delay3
927                 FROM overduerules
928                 WHERE categorycode=?|;
929     my $sth=$dbh->prepare($query);
930         $sth->execute($category);
931         my (@delays)=$sth->fetchrow_array;
932         $sth->finish;
933         return(@delays);
934 }
935
936 =item CheckAccountLineLevelInfo
937
938 ($exist) = &CheckAccountLineLevelInfo($borrowernumber,$itemnumber,$accounttype,notify_level);
939
940 Check and Returns the list of all overdue books.
941
942 C<$exist> contains number of line in accounlines
943 with the same .biblionumber,itemnumber,accounttype,and notify_level
944
945 C<$borrowernumber> contains the borrower number
946
947 C<$itemnumber> contains item number
948
949 C<$accounttype> contains account type
950
951 C<$notify_level> contains the accountline level 
952
953
954 =cut
955
956 sub CheckAccountLineLevelInfo {
957     my($borrowernumber,$itemnumber,$level) = @_;
958     my $dbh = C4::Context->dbh;
959         my $query=    qq|SELECT count(*)
960             FROM accountlines
961             WHERE borrowernumber =?
962             AND itemnumber = ?
963             AND notify_level=?|;
964     my $sth=$dbh->prepare($query);
965         $sth->execute($borrowernumber,$itemnumber,$level);
966         my ($exist)=$sth->fetchrow;
967         $sth->finish;
968         return($exist);
969 }
970
971 =item GetOverduerules
972
973 ($overduerules) = &GetOverduerules($categorycode);
974
975 Returns the value of borrowers (debarred or not) with notify level
976
977 C<$overduerules> return value of debbraed field in overduerules table
978
979 C<$category> contains the borrower categorycode
980
981 C<$notify_level> contains the notify level
982 =cut
983
984
985 sub GetOverduerules{
986     my($category,$notify_level) = @_;
987     my $dbh = C4::Context->dbh;
988         my $query=qq|SELECT debarred$notify_level
989              FROM overduerules
990              WHERE categorycode=?|;
991     my $sth=$dbh->prepare($query);
992         $sth->execute($category);
993         my ($overduerules)=$sth->fetchrow;
994         $sth->finish;
995         return($overduerules);
996 }
997
998
999 =item CheckBorrowerDebarred
1000
1001 ($debarredstatus) = &CheckBorrowerDebarred($borrowernumber);
1002
1003 Check if the borrowers is already debarred
1004
1005 C<$debarredstatus> return 0 for not debarred and return 1 for debarred
1006
1007 C<$borrowernumber> contains the borrower number
1008
1009 =cut
1010
1011
1012 sub CheckBorrowerDebarred{
1013     my($borrowernumber) = @_;
1014     my $dbh = C4::Context->dbh;
1015         my $query=qq|SELECT debarred
1016               FROM borrowers
1017              WHERE borrowernumber=?
1018             |;
1019     my $sth=$dbh->prepare($query);
1020         $sth->execute($borrowernumber);
1021         my ($debarredstatus)=$sth->fetchrow;
1022         $sth->finish;
1023         if ($debarredstatus eq '1'){
1024     return(1);}
1025     else{
1026     return(0);
1027     }
1028 }
1029
1030 =item UpdateBorrowerDebarred
1031
1032 ($borrowerstatut) = &UpdateBorrowerDebarred($borrowernumber);
1033
1034 update status of borrowers in borrowers table (field debarred)
1035
1036 C<$borrowernumber> borrower number
1037
1038 =cut
1039
1040 sub UpdateBorrowerDebarred{
1041     my($borrowernumber) = @_;
1042     my $dbh = C4::Context->dbh;
1043         my $query=qq|UPDATE borrowers
1044              SET debarred='1'
1045                      WHERE borrowernumber=?
1046             |;
1047     my $sth=$dbh->prepare($query);
1048         $sth->execute($borrowernumber);
1049         $sth->finish;
1050         return 1;
1051 }
1052
1053 =item CheckExistantNotifyid
1054
1055   ($exist) = &CheckExistantNotifyid($borrowernumber,$itemnumber,$accounttype,$notify_id);
1056
1057 Check and Returns the notify id if exist else return 0.
1058
1059 C<$exist> contains a notify_id 
1060
1061 C<$borrowernumber> contains the borrower number
1062
1063 C<$date_due> contains the date of item return 
1064
1065
1066 =cut
1067
1068 sub CheckExistantNotifyid {
1069      my($borrowernumber,$date_due) = @_;
1070      my $dbh = C4::Context->dbh;
1071          my $query =  qq|SELECT notify_id FROM accountlines 
1072              LEFT JOIN issues ON issues.itemnumber= accountlines.itemnumber
1073              WHERE accountlines.borrowernumber =?
1074               AND date_due = ?|;
1075     my $sth=$dbh->prepare($query);
1076          $sth->execute($borrowernumber,$date_due);
1077          my ($exist)=$sth->fetchrow;
1078          $sth->finish;
1079          if ($exist eq '')
1080     {
1081     return(0);
1082     }else
1083         {
1084     return($exist);
1085     }
1086 }
1087
1088 =item CheckAccountLineItemInfo
1089
1090   ($exist) = &CheckAccountLineItemInfo($borrowernumber,$itemnumber,$accounttype,$notify_id);
1091
1092 Check and Returns the list of all overdue items from the same file number(notify_id).
1093
1094 C<$exist> contains number of line in accounlines
1095 with the same .biblionumber,itemnumber,accounttype,notify_id
1096
1097 C<$borrowernumber> contains the borrower number
1098
1099 C<$itemnumber> contains item number
1100
1101 C<$accounttype> contains account type
1102
1103 C<$notify_id> contains the file number 
1104
1105 =cut
1106
1107 sub CheckAccountLineItemInfo {
1108      my($borrowernumber,$itemnumber,$accounttype,$notify_id) = @_;
1109      my $dbh = C4::Context->dbh;
1110          my $query =  qq|SELECT count(*) FROM accountlines
1111              WHERE borrowernumber =?
1112              AND itemnumber = ?
1113               AND accounttype= ?
1114             AND notify_id = ?|;
1115     my $sth=$dbh->prepare($query);
1116          $sth->execute($borrowernumber,$itemnumber,$accounttype,$notify_id);
1117          my ($exist)=$sth->fetchrow;
1118          $sth->finish;
1119          return($exist);
1120  }
1121
1122 =head2 CheckItemNotify
1123
1124 Sql request to check if the document has alreday been notified
1125 this function is not exported, only used with GetOverduesForBranch
1126
1127 =cut
1128
1129 sub CheckItemNotify {
1130         my ($notify_id,$notify_level,$itemnumber) = @_;
1131         my $dbh = C4::Context->dbh;
1132         my $sth = $dbh->prepare("
1133           SELECT COUNT(*) FROM notifys
1134  WHERE notify_id  = ?
1135  AND notify_level  = ? 
1136   AND  itemnumber  =  ? ");
1137  $sth->execute($notify_id,$notify_level,$itemnumber);
1138         my $notified = $sth->fetchrow;
1139 $sth->finish;
1140 return ($notified);
1141 }
1142
1143 =head2 GetOverduesForBranch
1144
1145 Sql request for display all information for branchoverdues.pl
1146 2 possibilities : with or without location .
1147 display is filtered by branch
1148
1149 =cut
1150
1151 sub GetOverduesForBranch {
1152     my ( $branch, $location) = @_;
1153         my $itype_link =  (C4::context->preference('item-level_itype')) ?  " items.ccode " :  " biblioitems.itemtype ";
1154     if ( not $location ) {
1155         my $dbh = C4::Context->dbh;
1156         my $sth = $dbh->prepare("
1157             SELECT 
1158                 borrowers.surname,
1159                 borrowers.firstname,
1160                 biblio.title,
1161                 itemtypes.description,
1162                 issues.date_due,
1163                 issues.returndate,
1164                 branches.branchname,
1165                 items.barcode,
1166                 borrowers.phone,
1167                 borrowers.email,
1168                 items.itemcallnumber,
1169                 borrowers.borrowernumber,
1170                 items.itemnumber,
1171                 biblio.biblionumber,
1172                 issues.branchcode,
1173                 accountlines.notify_id,
1174                 accountlines.notify_level,
1175                 items.location,
1176                 accountlines.amountoutstanding
1177             FROM  accountlines
1178             LEFT JOIN issues ON issues.itemnumber = accountlines.itemnumber AND issues.borrowernumber = accountlines.borrowernumber
1179             LEFT JOIN borrowers ON borrowers.borrowernumber = accountlines.borrowernumber
1180             LEFT JOIN items ON items.itemnumber = issues.itemnumber
1181             LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber
1182             LEFT JOIN biblioitems ON biblioitems.biblioitemnumber=items.biblioitemnumber
1183             LEFT JOIN itemtypes ON itemtypes.itemtype = $itype_link
1184             LEFT JOIN branches ON branches.branchcode = issues.branchcode
1185             WHERE ( issues.returndate  is null)
1186               AND ( accountlines.amountoutstanding  != '0.000000')
1187               AND ( accountlines.accounttype  = 'FU')
1188               AND (issues.branchcode = ?)
1189               AND (issues.date_due <= NOW())
1190             ORDER BY  borrowers.surname
1191         ");
1192         $sth->execute($branch);
1193         my @getoverdues;
1194         my $i = 0;
1195         while ( my $data = $sth->fetchrow_hashref ) {
1196         #check if the document has already been notified
1197         my $countnotify = CheckItemNotify($data->{'notify_id'},$data->{'notify_level'},$data->{'itemnumber'});
1198         if ($countnotify eq '0'){
1199             $getoverdues[$i] = $data;
1200             $i++;
1201          }
1202         }
1203         return (@getoverdues);
1204         $sth->finish;
1205     }
1206     else {
1207         my $dbh = C4::Context->dbh;
1208         my $sth = $dbh->prepare( "
1209             SELECT  borrowers.surname,
1210                     borrowers.firstname,
1211                     biblio.title,
1212                     itemtypes.description,
1213                     issues.date_due,
1214                     issues.returndate,
1215                     branches.branchname,
1216                     items.barcode,
1217                     borrowers.phone,
1218                     borrowers.email,
1219                     items.itemcallnumber,
1220                     borrowers.borrowernumber,
1221                     items.itemnumber,
1222                     biblio.biblionumber,
1223                     issues.branchcode,
1224                     accountlines.notify_id,
1225                     accountlines.notify_level,
1226                     items.location,
1227                     accountlines.amountoutstanding
1228             FROM  accountlines
1229             LEFT JOIN issues ON issues.itemnumber = accountlines.itemnumber AND issues.borrowernumber = accountlines.borrowernumber
1230             LEFT JOIN borrowers ON borrowers.borrowernumber = accountlines.borrowernumber
1231             LEFT JOIN items ON items.itemnumber = issues.itemnumber
1232             LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber
1233             LEFT JOIN biblioitems ON biblioitems.biblioitemnumber=items.biblioitemnumber
1234             LEFT JOIN itemtypes ON itemtypes.itemtype = $itype_link
1235             LEFT JOIN branches ON branches.branchcode = issues.branchcode
1236            WHERE ( issues.returndate  is null )
1237              AND ( accountlines.amountoutstanding  != '0.000000')
1238              AND ( accountlines.accounttype  = 'FU')
1239              AND (issues.branchcode = ? AND items.location = ?)
1240              AND (issues.date_due <= NOW())
1241            ORDER BY  borrowers.surname
1242         " );
1243         $sth->execute( $branch, $location);
1244         my @getoverdues;
1245         my $i = 0;
1246         while ( my $data = $sth->fetchrow_hashref ) {
1247         #check if the document has already been notified
1248           my $countnotify = CheckItemNotify($data->{'notify_id'},$data->{'notify_level'},$data->{'itemnumber'});
1249           if ($countnotify eq '0'){                     
1250                 $getoverdues[$i] = $data;
1251                  $i++;
1252          }
1253         }
1254         $sth->finish;
1255         return (@getoverdues); 
1256     }
1257 }
1258
1259
1260 =head2 AddNotifyLine
1261
1262 &AddNotifyLine($borrowernumber, $itemnumber, $overduelevel, $method, $notifyId)
1263
1264 Creat a line into notify, if the method is phone, the notification_send_date is implemented to
1265
1266 =cut
1267
1268 sub AddNotifyLine {
1269     my ( $borrowernumber, $itemnumber, $overduelevel, $method, $notifyId ) = @_;
1270     if ( $method eq "phone" ) {
1271         my $dbh = C4::Context->dbh;
1272         my $sth = $dbh->prepare(
1273             "INSERT INTO notifys (borrowernumber,itemnumber,notify_date,notify_send_date,notify_level,method,notify_id)
1274         VALUES (?,?,now(),now(),?,?,?)"
1275         );
1276         $sth->execute( $borrowernumber, $itemnumber, $overduelevel, $method,
1277             $notifyId );
1278         $sth->finish;
1279     }
1280     else {
1281         my $dbh = C4::Context->dbh;
1282         my $sth = $dbh->prepare(
1283             "INSERT INTO notifys (borrowernumber,itemnumber,notify_date,notify_level,method,notify_id)
1284         VALUES (?,?,now(),?,?,?)"
1285         );
1286         $sth->execute( $borrowernumber, $itemnumber, $overduelevel, $method,
1287             $notifyId );
1288         $sth->finish;
1289     }
1290     return 1;
1291 }
1292
1293 =head2 RemoveNotifyLine
1294
1295 &RemoveNotifyLine( $borrowernumber, $itemnumber, $notify_date );
1296
1297 Cancel a notification
1298
1299 =cut
1300
1301 sub RemoveNotifyLine {
1302     my ( $borrowernumber, $itemnumber, $notify_date ) = @_;
1303     my $dbh = C4::Context->dbh;
1304     my $sth = $dbh->prepare(
1305         "DELETE FROM notifys 
1306             WHERE
1307             borrowernumber=?
1308             AND itemnumber=?
1309             AND notify_date=?"
1310     );
1311     $sth->execute( $borrowernumber, $itemnumber, $notify_date );
1312     $sth->finish;
1313     return 1;
1314 }
1315
1316 1;
1317 __END__
1318
1319 =back
1320
1321 =head1 AUTHOR
1322
1323 Koha Developement team <info@koha.org>
1324
1325 =cut