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