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