reintroducing fixaccountforlostandreturned as requested by rosalie
[koha.git] / C4 / Circulation.pm
1 package C4::Circulation;
2
3 # Copyright 2000-2002 Katipo Communications
4 #
5 # This file is part of Koha.
6 #
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
10 # version.
11 #
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License along with
17 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18 # Suite 330, Boston, MA  02111-1307 USA
19
20 # $Id$
21
22 use strict;
23 require Exporter;
24 use C4::Context;
25 use C4::Stats;
26 use C4::Reserves2;
27 use C4::Koha;
28 use C4::Biblio;
29 use C4::Reserves2;
30 use C4::Members;
31 use C4::Date;
32 use Date::Calc qw(
33   Today
34   Today_and_Now
35   Add_Delta_YM
36   Add_Delta_DHMS
37   Date_to_Days
38 );
39 use POSIX qw(strftime);
40 use C4::Branch; # GetBranches
41 use C4::Log; # logaction
42
43 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
44
45 # set the version for version checking
46 $VERSION = do { my @v = '$Revision$' =~ /\d+/g; shift(@v).".".join( "_", map { sprintf "%03d", $_ } @v ); };
47
48 =head1 NAME
49
50 C4::Circulation::Circ2 - Koha circulation module
51
52 =head1 SYNOPSIS
53
54 use C4::Circulation;
55
56 =head1 DESCRIPTION
57
58 The functions in this module deal with circulation, issues, and
59 returns, as well as general information about the library.
60 Also deals with stocktaking.
61
62 =head1 FUNCTIONS
63
64 =cut
65
66 @ISA    = qw(Exporter);
67
68 # FIXME subs that should probably be elsewhere
69 push @EXPORT, qw(
70   &FixOverduesOnReturn
71 );
72
73 # subs to deal with issuing a book
74 push @EXPORT, qw(
75   &CanBookBeIssued
76   &CanBookBeRenewed
77   &AddIssue
78   &AddRenewal
79   &GetItemIssue
80   &GetItemIssues
81   &GetBorrowerIssues
82   &GetIssuingCharges
83   &GetBiblioIssues
84   &AnonymiseIssueHistory
85 );
86 # subs to deal with returns
87 push @EXPORT, qw(
88   &AddReturn
89 );
90
91 # subs to deal with transfers
92 push @EXPORT, qw(
93   &transferbook
94   &GetTransfers
95   &GetTransfersFromTo
96   &updateWrongTransfer
97   &DeleteTransfer
98 );
99
100 # subs to remove
101 push @EXPORT, qw(
102   &decode
103   &dotransfer
104 );
105
106 =head2 decode
107
108 =head3 $str = &decode($chunk);
109
110 =over 4
111
112 =item Decodes a segment of a string emitted by a CueCat barcode scanner and
113 returns it.
114
115 =back
116
117 =cut
118
119 # FIXME - At least, I'm pretty sure this is for decoding CueCat stuff.
120
121 # FIXME From Paul : i don't understand what this sub does & why it has to be called on every circ. Speak of this with chris maybe ?
122 sub decode {
123     my ($encoded) = @_;
124     my $seq =
125       'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-';
126     my @s = map { index( $seq, $_ ); } split( //, $encoded );
127     my $l = ( $#s + 1 ) % 4;
128     if ($l) {
129         if ( $l == 1 ) {
130             warn "Error!";
131             return;
132         }
133         $l = 4 - $l;
134         $#s += $l;
135     }
136     my $r = '';
137     while ( $#s >= 0 ) {
138         my $n = ( ( $s[0] << 6 | $s[1] ) << 6 | $s[2] ) << 6 | $s[3];
139         $r .=
140             chr( ( $n >> 16 ) ^ 67 )
141          .chr( ( $n >> 8 & 255 ) ^ 67 )
142          .chr( ( $n & 255 ) ^ 67 );
143         @s = @s[ 4 .. $#s ];
144     }
145     $r = substr( $r, 0, length($r) - $l );
146     return $r;
147 }
148
149 =head2 transferbook
150
151 ($dotransfer, $messages, $iteminformation) = &transferbook($newbranch, $barcode, $ignore_reserves);
152
153 Transfers an item to a new branch. If the item is currently on loan, it is automatically returned before the actual transfer.
154
155 C<$newbranch> is the code for the branch to which the item should be transferred.
156
157 C<$barcode> is the barcode of the item to be transferred.
158
159 If C<$ignore_reserves> is true, C<&transferbook> ignores reserves.
160 Otherwise, if an item is reserved, the transfer fails.
161
162 Returns three values:
163
164 =head3 $dotransfer 
165
166 is true if the transfer was successful.
167
168 =head3 $messages
169
170 is a reference-to-hash which may have any of the following keys:
171
172 =over 4
173
174 =item C<BadBarcode>
175
176 There is no item in the catalog with the given barcode. The value is C<$barcode>.
177
178 =item C<IsPermanent>
179
180 The item's home branch is permanent. This doesn't prevent the item from being transferred, though. The value is the code of the item's home branch.
181
182 =item C<DestinationEqualsHolding>
183
184 The item is already at the branch to which it is being transferred. The transfer is nonetheless considered to have failed. The value should be ignored.
185
186 =item C<WasReturned>
187
188 The item was on loan, and C<&transferbook> automatically returned it before transferring it. The value is the borrower number of the patron who had the item.
189
190 =item C<ResFound>
191
192 The item was reserved. The value is a reference-to-hash whose keys are fields from the reserves table of the Koha database, and C<biblioitemnumber>. It also has the key C<ResFound>, whose value is either C<Waiting> or C<Reserved>.
193
194 =item C<WasTransferred>
195
196 The item was eligible to be transferred. Barring problems communicating with the database, the transfer should indeed have succeeded. The value should be ignored.
197
198 =back
199
200 =cut
201
202 sub transferbook {
203     my ( $tbr, $barcode, $ignoreRs ) = @_;
204     my $messages;
205     my $dotransfer      = 1;
206     my $branches        = GetBranches();
207     my $itemnumber = GetItemnumberFromBarcode( $barcode );
208     my $issue      = GetItemIssue($itemnumber);
209     my $biblio = GetBiblioFromItemNumber($itemnumber);
210
211     # bad barcode..
212     if ( not $itemnumber ) {
213         $messages->{'BadBarcode'} = $barcode;
214         $dotransfer = 0;
215     }
216
217     # get branches of book...
218     my $hbr = $biblio->{'homebranch'};
219     my $fbr = $biblio->{'holdingbranch'};
220
221     # if is permanent...
222     if ( $hbr && $branches->{$hbr}->{'PE'} ) {
223         $messages->{'IsPermanent'} = $hbr;
224     }
225
226     # can't transfer book if is already there....
227     if ( $fbr eq $tbr ) {
228         $messages->{'DestinationEqualsHolding'} = 1;
229         $dotransfer = 0;
230     }
231
232     # check if it is still issued to someone, return it...
233     if ($issue->{borrowernumber}) {
234         AddReturn( $barcode, $fbr );
235         $messages->{'WasReturned'} = $issue->{borrowernumber};
236     }
237
238     # find reserves.....
239     # That'll save a database query.
240     my ( $resfound, $resrec ) =
241       CheckReserves( $itemnumber );
242     if ( $resfound and not $ignoreRs ) {
243         $resrec->{'ResFound'} = $resfound;
244
245         #         $messages->{'ResFound'} = $resrec;
246         $dotransfer = 1;
247     }
248
249     #actually do the transfer....
250     if ($dotransfer) {
251         dotransfer( $itemnumber, $fbr, $tbr );
252
253         # don't need to update MARC anymore, we do it in batch now
254         $messages->{'WasTransfered'} = 1;
255     }
256     return ( $dotransfer, $messages, $biblio );
257 }
258
259 # Not exported
260 # FIXME - This is only used in &transferbook. Why bother making it a
261 # separate function?
262 sub dotransfer {
263     my ( $itm, $fbr, $tbr ) = @_;
264     
265     my $dbh = C4::Context->dbh;
266     $itm = $dbh->quote($itm);
267     $fbr = $dbh->quote($fbr);
268     $tbr = $dbh->quote($tbr);
269     
270     #new entry in branchtransfers....
271     $dbh->do(
272 "INSERT INTO branchtransfers (itemnumber, frombranch, datesent, tobranch)
273                     VALUES ($itm, $fbr, now(), $tbr)"
274     );
275
276     #update holdingbranch in items .....
277       $dbh->do(
278           "UPDATE items set holdingbranch = $tbr WHERE items.itemnumber = $itm");
279     &ModDateLastSeen($itm);
280     &domarctransfer( $dbh, $itm );
281     return;
282 }
283
284 ##New sub to dotransfer in marc tables as well. Not exported -TG 10/04/2006
285 sub domarctransfer {
286     my ( $dbh, $itemnumber ) = @_;
287     $itemnumber =~ s /\'//g;    ##itemnumber seems to come with quotes-TG
288     my $sth =
289       $dbh->prepare(
290         "select biblionumber,holdingbranch from items where itemnumber=$itemnumber"
291       );
292     $sth->execute();
293     while ( my ( $biblionumber, $holdingbranch ) = $sth->fetchrow ) {
294         &ModItemInMarconefield( $biblionumber, $itemnumber,
295             'items.holdingbranch', $holdingbranch );
296     }
297     return;
298 }
299
300 =head2 CanBookBeIssued
301
302 Check if a book can be issued.
303
304 my ($issuingimpossible,$needsconfirmation) = CanBookBeIssued($borrower,$barcode,$year,$month,$day);
305
306 =over 4
307
308 =item C<$borrower> hash with borrower informations (from GetMemberDetails)
309
310 =item C<$barcode> is the bar code of the book being issued.
311
312 =item C<$year> C<$month> C<$day> contains the date of the return (in case it's forced by "stickyduedate".
313
314 =back
315
316 Returns :
317
318 =over 4
319
320 =item C<$issuingimpossible> a reference to a hash. It contains reasons why issuing is impossible.
321 Possible values are :
322
323 =back
324
325 =head3 INVALID_DATE 
326
327 sticky due date is invalid
328
329 =head3 GNA
330
331 borrower gone with no address
332
333 =head3 CARD_LOST
334
335 borrower declared it's card lost
336
337 =head3 DEBARRED
338
339 borrower debarred
340
341 =head3 UNKNOWN_BARCODE
342
343 barcode unknown
344
345 =head3 NOT_FOR_LOAN
346
347 item is not for loan
348
349 =head3 WTHDRAWN
350
351 item withdrawn.
352
353 =head3 RESTRICTED
354
355 item is restricted (set by ??)
356
357 C<$issuingimpossible> a reference to a hash. It contains reasons why issuing is impossible.
358 Possible values are :
359
360 =head3 DEBT
361
362 borrower has debts.
363
364 =head3 RENEW_ISSUE
365
366 renewing, not issuing
367
368 =head3 ISSUED_TO_ANOTHER
369
370 issued to someone else.
371
372 =head3 RESERVED
373
374 reserved for someone else.
375
376 =head3 INVALID_DATE
377
378 sticky due date is invalid
379
380 =head3 TOO_MANY
381
382 if the borrower borrows to much things
383
384 =cut
385
386 # check if a book can be issued.
387 # returns an array with errors if any
388
389 sub TooMany ($$) {
390     my $borrower        = shift;
391     my $biblionumber = shift;
392     my $cat_borrower    = $borrower->{'categorycode'};
393     my $branch_borrower = $borrower->{'branchcode'};
394     my $dbh             = C4::Context->dbh;
395
396     my $sth =
397       $dbh->prepare('select itemtype from biblioitems where biblionumber = ?');
398     $sth->execute($biblionumber);
399     my $type = $sth->fetchrow;
400     $sth =
401       $dbh->prepare(
402 'select * from issuingrules where categorycode = ? and itemtype = ? and branchcode = ?'
403       );
404
405 #     my $sth2 = $dbh->prepare("select COUNT(*) from issues i, biblioitems s where i.borrowernumber = ? and i.returndate is null and i.itemnumber = s.biblioitemnumber and s.itemtype like ?");
406     my $sth2 =
407       $dbh->prepare(
408 "select COUNT(*) from issues i, biblioitems s1, items s2 where i.borrowernumber = ? and i.returndate is null and i.itemnumber = s2.itemnumber and s1.itemtype like ? and s1.biblioitemnumber = s2.biblioitemnumber"
409       );
410     my $sth3 =
411       $dbh->prepare(
412 'select COUNT(*) from issues where borrowernumber = ? and returndate is null'
413       );
414     my $alreadyissued;
415
416     # check the 3 parameters
417     $sth->execute( $cat_borrower, $type, $branch_borrower );
418     my $result = $sth->fetchrow_hashref;
419
420     #    warn "==>".$result->{maxissueqty};
421
422 # Currently, using defined($result) ie on an entire hash reports whether memory
423 # for that aggregate has ever been allocated. As $result is used all over the place
424 # it would rarely return as undefined.
425     if ( defined( $result->{maxissueqty} ) ) {
426         $sth2->execute( $borrower->{'borrowernumber'}, "%$type%" );
427         my $alreadyissued = $sth2->fetchrow;
428         if ( $result->{'maxissueqty'} <= $alreadyissued ) {
429             return ( "a $alreadyissued / ".( $result->{maxissueqty} + 0 ) );
430         }
431         else {
432             return;
433         }
434     }
435
436     # check for branch=*
437     $sth->execute( $cat_borrower, $type, "" );
438     $result = $sth->fetchrow_hashref;
439     if ( defined( $result->{maxissueqty} ) ) {
440         $sth2->execute( $borrower->{'borrowernumber'}, "%$type%" );
441         my $alreadyissued = $sth2->fetchrow;
442         if ( $result->{'maxissueqty'} <= $alreadyissued ) {
443             return ( "b $alreadyissued / ".( $result->{maxissueqty} + 0 ) );
444         }
445         else {
446             return;
447         }
448     }
449
450     # check for itemtype=*
451     $sth->execute( $cat_borrower, "*", $branch_borrower );
452     $result = $sth->fetchrow_hashref;
453     if ( defined( $result->{maxissueqty} ) ) {
454         $sth3->execute( $borrower->{'borrowernumber'} );
455         my ($alreadyissued) = $sth3->fetchrow;
456         if ( $result->{'maxissueqty'} <= $alreadyissued ) {
457
458 #        warn "HERE : $alreadyissued / ($result->{maxissueqty} for $borrower->{'borrowernumber'}";
459             return ( "c $alreadyissued / " . ( $result->{maxissueqty} + 0 ) );
460         }
461         else {
462             return;
463         }
464     }
465
466     # check for borrowertype=*
467     $sth->execute( "*", $type, $branch_borrower );
468     $result = $sth->fetchrow_hashref;
469     if ( defined( $result->{maxissueqty} ) ) {
470         $sth2->execute( $borrower->{'borrowernumber'}, "%$type%" );
471         my $alreadyissued = $sth2->fetchrow;
472         if ( $result->{'maxissueqty'} <= $alreadyissued ) {
473             return ( "d $alreadyissued / " . ( $result->{maxissueqty} + 0 ) );
474         }
475         else {
476             return;
477         }
478     }
479
480     $sth->execute( "*", "*", $branch_borrower );
481     $result = $sth->fetchrow_hashref;
482     if ( defined( $result->{maxissueqty} ) ) {
483         $sth3->execute( $borrower->{'borrowernumber'} );
484         my $alreadyissued = $sth3->fetchrow;
485         if ( $result->{'maxissueqty'} <= $alreadyissued ) {
486             return ( "e $alreadyissued / " . ( $result->{maxissueqty} + 0 ) );
487         }
488         else {
489             return;
490         }
491     }
492
493     $sth->execute( "*", $type, "" );
494     $result = $sth->fetchrow_hashref;
495     if ( defined( $result->{maxissueqty} ) && $result->{maxissueqty} >= 0 ) {
496         $sth2->execute( $borrower->{'borrowernumber'}, "%$type%" );
497         my $alreadyissued = $sth2->fetchrow;
498         if ( $result->{'maxissueqty'} <= $alreadyissued ) {
499             return ( "f $alreadyissued / " . ( $result->{maxissueqty} + 0 ) );
500         }
501         else {
502             return;
503         }
504     }
505
506     $sth->execute( $cat_borrower, "*", "" );
507     $result = $sth->fetchrow_hashref;
508     if ( defined( $result->{maxissueqty} ) ) {
509         $sth2->execute( $borrower->{'borrowernumber'}, "%$type%" );
510         my $alreadyissued = $sth2->fetchrow;
511         if ( $result->{'maxissueqty'} <= $alreadyissued ) {
512             return ( "g $alreadyissued / " . ( $result->{maxissueqty} + 0 ) );
513         }
514         else {
515             return;
516         }
517     }
518
519     $sth->execute( "*", "*", "" );
520     $result = $sth->fetchrow_hashref;
521     if ( defined( $result->{maxissueqty} ) ) {
522         $sth3->execute( $borrower->{'borrowernumber'} );
523         my $alreadyissued = $sth3->fetchrow;
524         if ( $result->{'maxissueqty'} <= $alreadyissued ) {
525             return ( "h $alreadyissued / " . ( $result->{maxissueqty} + 0 ) );
526         }
527         else {
528             return;
529         }
530     }
531     return;
532 }
533
534 =head2 itemissues
535
536   @issues = &itemissues($biblioitemnumber, $biblio);
537
538 Looks up information about who has borrowed the bookZ<>(s) with the
539 given biblioitemnumber.
540
541 C<$biblio> is ignored.
542
543 C<&itemissues> returns an array of references-to-hash. The keys
544 include the fields from the C<items> table in the Koha database.
545 Additional keys include:
546
547 =over 4
548
549 =item C<date_due>
550
551 If the item is currently on loan, this gives the due date.
552
553 If the item is not on loan, then this is either "Available" or
554 "Cancelled", if the item has been withdrawn.
555
556 =item C<card>
557
558 If the item is currently on loan, this gives the card number of the
559 patron who currently has the item.
560
561 =item C<timestamp0>, C<timestamp1>, C<timestamp2>
562
563 These give the timestamp for the last three times the item was
564 borrowed.
565
566 =item C<card0>, C<card1>, C<card2>
567
568 The card number of the last three patrons who borrowed this item.
569
570 =item C<borrower0>, C<borrower1>, C<borrower2>
571
572 The borrower number of the last three patrons who borrowed this item.
573
574 =back
575
576 =cut
577
578 #'
579 sub itemissues {
580     my ( $bibitem, $biblio ) = @_;
581     my $dbh = C4::Context->dbh;
582
583     # FIXME - If this function die()s, the script will abort, and the
584     # user won't get anything; depending on how far the script has
585     # gotten, the user might get a blank page. It would be much better
586     # to at least print an error message. The easiest way to do this
587     # is to set $SIG{__DIE__}.
588     my $sth =
589       $dbh->prepare("Select * from items where items.biblioitemnumber = ?")
590       || die $dbh->errstr;
591     my $i = 0;
592     my @results;
593
594     $sth->execute($bibitem) || die $sth->errstr;
595
596     while ( my $data = $sth->fetchrow_hashref ) {
597
598         # Find out who currently has this item.
599         # FIXME - Wouldn't it be better to do this as a left join of
600         # some sort? Currently, this code assumes that if
601         # fetchrow_hashref() fails, then the book is on the shelf.
602         # fetchrow_hashref() can fail for any number of reasons (e.g.,
603         # database server crash), not just because no items match the
604         # search criteria.
605         my $sth2 = $dbh->prepare(
606             "SELECT * FROM issues
607                 LEFT JOIN borrowers ON issues.borrowernumber = borrowers.borrowernumber
608                 WHERE itemnumber = ?
609                     AND returndate IS NULL
610             "
611         );
612
613         $sth2->execute( $data->{'itemnumber'} );
614         if ( my $data2 = $sth2->fetchrow_hashref ) {
615             $data->{'date_due'} = $data2->{'date_due'};
616             $data->{'card'}     = $data2->{'cardnumber'};
617             $data->{'borrower'} = $data2->{'borrowernumber'};
618         }
619         else {
620             if ( $data->{'wthdrawn'} eq '1' ) {
621                 $data->{'date_due'} = 'Cancelled';
622             }
623             else {
624                 $data->{'date_due'} = 'Available';
625             }    # else
626         }    # else
627
628         $sth2->finish;
629
630         # Find the last 3 people who borrowed this item.
631         $sth2 = $dbh->prepare(
632             "SELECT * FROM issues, borrowers
633                 LEFT JOIN borrowers ON  issues.borrowernumber = borrowers.borrowernumber
634                 WHERE itemnumber = ?
635                 AND returndate IS NOT NULL
636                 ORDER BY returndate DESC,timestamp DESC"
637         );
638
639 #        $sth2 = $dbh->prepare("
640 #            SELECT *
641 #            FROM issues
642 #                LEFT JOIN borrowers ON issues.borrowernumber = borrowers.borrowernumber
643 #            WHERE   itemnumber = ?
644 #                AND returndate is not NULL
645 #            ORDER BY returndate DESC,timestamp DESC
646 #        ");
647
648         $sth2->execute( $data->{'itemnumber'} );
649         for ( my $i2 = 0 ; $i2 < 2 ; $i2++ )
650         {    # FIXME : error if there is less than 3 pple borrowing this item
651             if ( my $data2 = $sth2->fetchrow_hashref ) {
652                 $data->{"timestamp$i2"} = $data2->{'timestamp'};
653                 $data->{"card$i2"}      = $data2->{'cardnumber'};
654                 $data->{"borrower$i2"}  = $data2->{'borrowernumber'};
655             }    # if
656         }    # for
657
658         $sth2->finish;
659         $results[$i] = $data;
660         $i++;
661     }
662
663     $sth->finish;
664     return (@results);
665 }
666
667 =head2 CanBookBeIssued
668
669 $issuingimpossible, $needsconfirmation = 
670         CanBookBeIssued( $borrower, $barcode, $year, $month, $day, $inprocess );
671
672 C<$issuingimpossible> and C<$needsconfirmation> are some hashref.
673
674 =cut
675
676 sub CanBookBeIssued {
677     my ( $borrower, $barcode, $year, $month, $day, $inprocess ) = @_;
678     my %needsconfirmation;    # filled with problems that needs confirmations
679     my %issuingimpossible;    # filled with problems that causes the issue to be IMPOSSIBLE
680     my $item = GetItem(GetItemnumberFromBarcode( $barcode ));
681     my $issue = GetItemIssue($item->{itemnumber});
682     my $dbh             = C4::Context->dbh;
683
684     #
685     # DUE DATE is OK ?
686     #
687     my ( $duedate, $invalidduedate ) = fixdate( $year, $month, $day );
688     $issuingimpossible{INVALID_DATE} = 1 if ($invalidduedate);
689
690     #
691     # BORROWER STATUS
692     #
693     if ( $borrower->{flags}->{GNA} ) {
694         $issuingimpossible{GNA} = 1;
695     }
696     if ( $borrower->{flags}->{'LOST'} ) {
697         $issuingimpossible{CARD_LOST} = 1;
698     }
699     if ( $borrower->{flags}->{'DBARRED'} ) {
700         $issuingimpossible{DEBARRED} = 1;
701     }
702     if ( Date_to_Days(Today) > 
703         Date_to_Days( split "-", $borrower->{'dateexpiry'} ) )
704     {
705
706         #
707         #if (&Date_Cmp(&ParseDate($borrower->{expiry}),&ParseDate("today"))<0) {
708         $issuingimpossible{EXPIRED} = 1;
709     }
710
711     #
712     # BORROWER STATUS
713     #
714
715     # DEBTS
716     my ($amount) =
717       GetBorrowerAcctRecord( $borrower->{'borrowernumber'}, $duedate );
718     if ( C4::Context->preference("IssuingInProcess") ) {
719         my $amountlimit = C4::Context->preference("noissuescharge");
720         if ( $amount > $amountlimit && !$inprocess ) {
721             $issuingimpossible{DEBT} = sprintf( "%.2f", $amount );
722         }
723         elsif ( $amount <= $amountlimit && !$inprocess ) {
724             $needsconfirmation{DEBT} = sprintf( "%.2f", $amount );
725         }
726     }
727     else {
728         if ( $amount > 0 ) {
729             $needsconfirmation{DEBT} = $amount;
730         }
731     }
732
733     #
734     # JB34 CHECKS IF BORROWERS DONT HAVE ISSUE TOO MANY BOOKS
735     #
736     my $toomany = TooMany( $borrower, $item->{biblionumber} );
737     $needsconfirmation{TOO_MANY} = $toomany if $toomany;
738
739     #
740     # ITEM CHECKING
741     #
742     unless ( $item->{barcode} ) {
743         $issuingimpossible{UNKNOWN_BARCODE} = 1;
744     }
745     if (   $item->{'notforloan'}
746         && $item->{'notforloan'} > 0 )
747     {
748         $issuingimpossible{NOT_FOR_LOAN} = 1;
749     }
750     if ( $item->{'wthdrawn'} && $item->{'wthdrawn'} == 1 )
751     {
752         $issuingimpossible{WTHDRAWN} = 1;
753     }
754     if (   $item->{'restricted'}
755         && $item->{'restricted'} == 1 )
756     {
757         $issuingimpossible{RESTRICTED} = 1;
758     }
759     if ( C4::Context->preference("IndependantBranches") ) {
760         my $userenv = C4::Context->userenv;
761         if ( ($userenv) && ( $userenv->{flags} != 1 ) ) {
762             $issuingimpossible{NOTSAMEBRANCH} = 1
763               if ( $item->{'holdingbranch'} ne $userenv->{branch} );
764         }
765     }
766
767     #
768     # CHECK IF BOOK ALREADY ISSUED TO THIS BORROWER
769     #
770     if ( $issue->{borrowernumber} && $issue->{borrowernumber} eq $borrower->{'borrowernumber'} )
771     {
772
773         # Already issued to current borrower. Ask whether the loan should
774         # be renewed.
775         my ($CanBookBeRenewed) = CanBookBeRenewed(
776             $borrower->{'borrowernumber'},
777             $item->{'itemnumber'}
778         );
779         if ( $CanBookBeRenewed == 0 ) {    # no more renewals allowed
780             $issuingimpossible{NO_MORE_RENEWALS} = 1;
781         }
782         else {
783
784             #        $needsconfirmation{RENEW_ISSUE} = 1;
785         }
786     }
787     elsif ($issue->{borrowernumber}) {
788
789         # issued to someone else
790         my $currborinfo = GetMemberDetails( $issue->{borrowernumber} );
791
792 #        warn "=>.$currborinfo->{'firstname'} $currborinfo->{'surname'} ($currborinfo->{'cardnumber'})";
793         $needsconfirmation{ISSUED_TO_ANOTHER} =
794 "$currborinfo->{'reservedate'} : $currborinfo->{'firstname'} $currborinfo->{'surname'} ($currborinfo->{'cardnumber'})";
795     }
796
797     # See if the item is on reserve.
798     my ( $restype, $res ) = CheckReserves( $item->{'itemnumber'} );
799     if ($restype) {
800         my $resbor = $res->{'borrowernumber'};
801         if ( $resbor ne $borrower->{'borrowernumber'} && $restype eq "Waiting" )
802         {
803
804             # The item is on reserve and waiting, but has been
805             # reserved by some other patron.
806             my ( $resborrower, $flags ) =
807               GetMemberDetails( $resbor, 0 );
808             my $branches   = GetBranches();
809             my $branchname =
810               $branches->{ $res->{'branchcode'} }->{'branchname'};
811             $needsconfirmation{RESERVE_WAITING} =
812 "$resborrower->{'firstname'} $resborrower->{'surname'} ($resborrower->{'cardnumber'}, $branchname)";
813
814 # CancelReserve(0, $res->{'itemnumber'}, $res->{'borrowernumber'}); Doesn't belong in a checking subroutine.
815         }
816         elsif ( $restype eq "Reserved" ) {
817
818             # The item is on reserve for someone else.
819             my ( $resborrower, $flags ) =
820               GetMemberDetails( $resbor, 0 );
821             my $branches   = GetBranches();
822             my $branchname =
823               $branches->{ $res->{'branchcode'} }->{'branchname'};
824             $needsconfirmation{RESERVED} =
825 "$res->{'reservedate'} : $resborrower->{'firstname'} $resborrower->{'surname'} ($resborrower->{'cardnumber'})";
826         }
827     }
828     if ( C4::Context->preference("LibraryName") eq "Horowhenua Library Trust" )
829     {
830         if ( $borrower->{'categorycode'} eq 'W' ) {
831             my %issuingimpossible;
832             return ( \%issuingimpossible, \%needsconfirmation );
833         }
834         else {
835             return ( \%issuingimpossible, \%needsconfirmation );
836         }
837     }
838     else {
839         return ( \%issuingimpossible, \%needsconfirmation );
840     }
841 }
842
843 =head2 AddIssue
844
845 Issue a book. Does no check, they are done in CanBookBeIssued. If we reach this sub, it means the user confirmed if needed.
846
847 &AddIssue($borrower,$barcode,$date)
848
849 =over 4
850
851 =item C<$borrower> hash with borrower informations (from GetMemberDetails)
852
853 =item C<$barcode> is the bar code of the book being issued.
854
855 =item C<$date> contains the max date of return. calculated if empty.
856
857 AddIssue does the following things :
858 - step 0�: check that there is a borrowernumber & a barcode provided
859 - check for RENEWAL (book issued & being issued to the same patron)
860     - renewal YES = Calculate Charge & renew
861     - renewal NO  = 
862         * BOOK ACTUALLY ISSUED ? do a return if book is actually issued (but to someone else)
863         * RESERVE PLACED ?
864             - fill reserve if reserve to this patron
865             - cancel reserve or not, otherwise
866         * TRANSFERT PENDING ?
867             - complete the transfert
868         * ISSUE THE BOOK
869
870 =back
871
872 =cut
873
874 sub AddIssue {
875     my ( $borrower, $barcode, $date, $cancelreserve ) = @_;
876     
877     my $dbh = C4::Context->dbh;
878 if ($borrower and $barcode){
879 #   my ($borrower, $flags) = &GetMemberDetails($borrowernumber, 0);
880     # find which item we issue
881     my $item = GetItem('', $barcode);
882     
883     # get actual issuing if there is one
884     my $actualissue = GetItemIssue( $item->{itemnumber});
885     
886     # get biblioinformation for this item
887     my $biblio = GetBiblioFromItemNumber($item->{itemnumber});
888
889 #
890 # check if we just renew the issue.
891 #
892     if ( $actualissue->{borrowernumber} eq $borrower->{'borrowernumber'} ) {
893         # we renew, do we need to add some charge ?
894         my ( $charge, $itemtype ) = GetIssuingCharges(
895             $item->{'itemnumber'},
896             $borrower->{'borrowernumber'}
897         );
898         if ( $charge > 0 ) {
899             AddIssuingCharge(
900                 $item->{'itemnumber'},
901                 $borrower->{'borrowernumber'}, $charge
902             );
903             $item->{'charge'} = $charge;
904         }
905         &UpdateStats(
906             C4::Context->userenv->{'branch'},
907             'renew',                        $charge,
908             '',                             $item->{'itemnumber'},
909             $biblio->{'itemtype'}, $borrower->{'borrowernumber'}
910         );
911         AddRenewal(
912             $borrower->{'borrowernumber'},
913             $item->{'itemnumber'}
914         );
915     }
916     else {# it's NOT a renewal
917         if ( $actualissue->{borrowernumber}) {
918             # This book is currently on loan, but not to the person
919             # who wants to borrow it now. mark it returned before issuing to the new borrower
920             AddReturn(
921                 $item->{'barcode'},
922                 C4::Context->userenv->{'branch'}
923             );
924         }
925
926         # See if the item is on reserve.
927         my ( $restype, $res ) =
928           CheckReserves( $item->{'itemnumber'} );
929         if ($restype) {
930             my $resbor = $res->{'borrowernumber'};
931             if ( $resbor eq $borrower->{'borrowernumber'} ) {
932
933                 # The item is reserved by the current patron
934                 FillReserve($res);
935             }
936             elsif ( $restype eq "Waiting" ) {
937
938                 # warn "Waiting";
939                 # The item is on reserve and waiting, but has been
940                 # reserved by some other patron.
941                 my ( $resborrower, $flags ) = GetMemberDetails( $resbor, 0 );
942                 my $branches   = GetBranches();
943                 my $branchname =
944                   $branches->{ $res->{'branchcode'} }->{'branchname'};
945                 if ($cancelreserve) {
946                     CancelReserve( 0, $res->{'itemnumber'},
947                         $res->{'borrowernumber'} );
948                 }
949                 else {
950
951        # set waiting reserve to first in reserve queue as book isn't waiting now
952                     UpdateReserve(
953                         1,
954                         $res->{'biblionumber'},
955                         $res->{'borrowernumber'},
956                         $res->{'branchcode'}
957                     );
958                 }
959             }
960             elsif ( $restype eq "Reserved" ) {
961
962                 # warn "Reserved";
963                 # The item is reserved by someone else.
964                 my ( $resborrower, $flags ) =
965                   GetMemberDetails( $resbor, 0 );
966                 my $branches   = GetBranches();
967                 my $branchname =
968                   $branches->{ $res->{'branchcode'} }->{'branchname'};
969                 if ($cancelreserve) { # cancel reserves on this item
970                     CancelReserve( 0, $res->{'itemnumber'},
971                         $res->{'borrowernumber'} );
972                 }
973             }
974         }
975
976         # Starting process for transfer job (checking transfert and validate it if we have one)
977             my ($datesent) = GetTransfers($item->{'itemnumber'});
978             if ($datesent) {
979         #       updating line of branchtranfert to finish it, and changing the to branch value, implement a comment for lisibility of this case (maybe for stats ....)
980             my $sth =
981                     $dbh->prepare(
982                     "UPDATE branchtransfers 
983                         SET datearrived = now(),
984                         tobranch = ?,
985                         comments = 'Forced branchtransfert'
986                     WHERE itemnumber= ? AND datearrived IS NULL"
987                     );
988                     $sth->execute(C4::Context->userenv->{'branch'},$item->{'itemnumber'});
989                     $sth->finish;
990             }
991
992         # Record in the database the fact that the book was issued.
993         my $sth =
994           $dbh->prepare(
995                 "INSERT INTO issues 
996                     (borrowernumber, itemnumber,issuedate, date_due, branchcode)
997                 VALUES (?,?,?,?,?)"
998           );
999         my $loanlength = GetLoanLength(
1000             $borrower->{'categorycode'},
1001             $biblio->{'itemtype'},
1002             $borrower->{'branchcode'}
1003         );
1004         my $datedue  = time + ($loanlength) * 86400;
1005         my @datearr  = localtime($datedue);
1006         my $dateduef =
1007             ( 1900 + $datearr[5] ) . "-"
1008           . ( $datearr[4] + 1 ) . "-"
1009           . $datearr[3];
1010         if ($date) {
1011             $dateduef = $date;
1012         }
1013
1014        # if ReturnBeforeExpiry ON the datedue can't be after borrower expirydate
1015         if ( C4::Context->preference('ReturnBeforeExpiry')
1016             && $dateduef gt $borrower->{dateexpiry} )
1017         {
1018             $dateduef = $borrower->{dateexpiry};
1019         }
1020         $sth->execute(
1021             $borrower->{'borrowernumber'},
1022             $item->{'itemnumber'},
1023             strftime( "%Y-%m-%d", localtime ),$dateduef, C4::Context->userenv->{'branch'}
1024         );
1025         $sth->finish;
1026         $item->{'issues'}++;
1027         $sth =
1028           $dbh->prepare(
1029             "UPDATE items SET issues=?, holdingbranch=?, itemlost=0, datelastborrowed  = now() WHERE itemnumber=?");
1030         $sth->execute(
1031             $item->{'issues'},
1032             C4::Context->userenv->{'branch'},
1033             $item->{'itemnumber'}
1034         );
1035         $sth->finish;
1036         &ModDateLastSeen( $item->{'itemnumber'} );
1037         # If it costs to borrow this book, charge it to the patron's account.
1038         my ( $charge, $itemtype ) = GetIssuingCharges(
1039             $item->{'itemnumber'},
1040             $borrower->{'borrowernumber'}
1041         );
1042         if ( $charge > 0 ) {
1043             AddIssuingCharge(
1044                 $item->{'itemnumber'},
1045                 $borrower->{'borrowernumber'}, $charge
1046             );
1047             $item->{'charge'} = $charge;
1048         }
1049
1050         # Record the fact that this book was issued.
1051         &UpdateStats(
1052             C4::Context->userenv->{'branch'},
1053             'issue',                        $charge,
1054             '',                             $item->{'itemnumber'},
1055             $item->{'itemtype'}, $borrower->{'borrowernumber'}
1056         );
1057     }
1058     
1059     &logaction(C4::Context->userenv->{'number'},"CIRCULATION","ISSUE",$borrower->{'borrowernumber'},$biblio->{'biblionumber'}) 
1060         if C4::Context->preference("IssueLog");
1061   }  
1062 }
1063
1064 =head2 GetLoanLength
1065
1066 Get loan length for an itemtype, a borrower type and a branch
1067
1068 my $loanlength = &GetLoanLength($borrowertype,$itemtype,branchcode)
1069
1070 =cut
1071
1072 sub GetLoanLength {
1073     my ( $borrowertype, $itemtype, $branchcode ) = @_;
1074     my $dbh = C4::Context->dbh;
1075     my $sth =
1076       $dbh->prepare(
1077 "select issuelength from issuingrules where categorycode=? and itemtype=? and branchcode=?"
1078       );
1079
1080 # try to find issuelength & return the 1st available.
1081 # check with borrowertype, itemtype and branchcode, then without one of those parameters
1082     $sth->execute( $borrowertype, $itemtype, $branchcode );
1083     my $loanlength = $sth->fetchrow_hashref;
1084     return $loanlength->{issuelength}
1085       if defined($loanlength) && $loanlength->{issuelength} ne 'NULL';
1086
1087     $sth->execute( $borrowertype, $itemtype, "" );
1088     $loanlength = $sth->fetchrow_hashref;
1089     return $loanlength->{issuelength}
1090       if defined($loanlength) && $loanlength->{issuelength} ne 'NULL';
1091
1092     $sth->execute( $borrowertype, "*", $branchcode );
1093     $loanlength = $sth->fetchrow_hashref;
1094     return $loanlength->{issuelength}
1095       if defined($loanlength) && $loanlength->{issuelength} ne 'NULL';
1096
1097     $sth->execute( "*", $itemtype, $branchcode );
1098     $loanlength = $sth->fetchrow_hashref;
1099     return $loanlength->{issuelength}
1100       if defined($loanlength) && $loanlength->{issuelength} ne 'NULL';
1101
1102     $sth->execute( $borrowertype, "*", "" );
1103     $loanlength = $sth->fetchrow_hashref;
1104     return $loanlength->{issuelength}
1105       if defined($loanlength) && $loanlength->{issuelength} ne 'NULL';
1106
1107     $sth->execute( "*", "*", $branchcode );
1108     $loanlength = $sth->fetchrow_hashref;
1109     return $loanlength->{issuelength}
1110       if defined($loanlength) && $loanlength->{issuelength} ne 'NULL';
1111
1112     $sth->execute( "*", $itemtype, "" );
1113     $loanlength = $sth->fetchrow_hashref;
1114     return $loanlength->{issuelength}
1115       if defined($loanlength) && $loanlength->{issuelength} ne 'NULL';
1116
1117     $sth->execute( "*", "*", "" );
1118     $loanlength = $sth->fetchrow_hashref;
1119     return $loanlength->{issuelength}
1120       if defined($loanlength) && $loanlength->{issuelength} ne 'NULL';
1121
1122     # if no rule is set => 21 days (hardcoded)
1123     return 21;
1124 }
1125
1126 =head2 AddReturn
1127
1128 ($doreturn, $messages, $iteminformation, $borrower) =
1129     &AddReturn($barcode, $branch);
1130
1131 Returns a book.
1132
1133 C<$barcode> is the bar code of the book being returned. C<$branch> is
1134 the code of the branch where the book is being returned.
1135
1136 C<&AddReturn> returns a list of four items:
1137
1138 C<$doreturn> is true iff the return succeeded.
1139
1140 C<$messages> is a reference-to-hash giving the reason for failure:
1141
1142 =over 4
1143
1144 =item C<BadBarcode>
1145
1146 No item with this barcode exists. The value is C<$barcode>.
1147
1148 =item C<NotIssued>
1149
1150 The book is not currently on loan. The value is C<$barcode>.
1151
1152 =item C<IsPermanent>
1153
1154 The book's home branch is a permanent collection. If you have borrowed
1155 this book, you are not allowed to return it. The value is the code for
1156 the book's home branch.
1157
1158 =item C<wthdrawn>
1159
1160 This book has been withdrawn/cancelled. The value should be ignored.
1161
1162 =item C<ResFound>
1163
1164 The item was reserved. The value is a reference-to-hash whose keys are
1165 fields from the reserves table of the Koha database, and
1166 C<biblioitemnumber>. It also has the key C<ResFound>, whose value is
1167 either C<Waiting>, C<Reserved>, or 0.
1168
1169 =back
1170
1171 C<$borrower> is a reference-to-hash, giving information about the
1172 patron who last borrowed the book.
1173
1174 =cut
1175
1176 # FIXME - This API is bogus. There's no need to return $borrower and
1177 # $iteminformation; the caller can ask about those separately, if it
1178 # cares (it'd be inefficient to make two database calls instead of
1179 # one, but &GetMemberDetails and &getiteminformation can be
1180 # memoized if this is an issue).
1181 #
1182 # The ($doreturn, $messages) tuple is redundant: if the return
1183 # succeeded, that's all the caller needs to know. So &AddReturn can
1184 # return 1 and 0 on success and failure, and set
1185 # $C4::Circulation::Circ2::errmsg to indicate the error. Or it can
1186 # return undef for success, and an error message on error (though this
1187 # is more C-ish than Perl-ish).
1188
1189 sub AddReturn {
1190     my ( $barcode, $branch ) = @_;
1191     my $dbh      = C4::Context->dbh;
1192     my $messages;
1193     my $doreturn = 1;
1194     my $borrower;
1195     my $validTransfert = 0;
1196     my $reserveDone = 0;
1197     
1198     # get information on item
1199     my $iteminformation = GetItemIssue( GetItemnumberFromBarcode($barcode));
1200     unless ($iteminformation->{'itemnumber'} ) {
1201         $messages->{'BadBarcode'} = $barcode;
1202         $doreturn = 0;
1203     } else {
1204         # find the borrower
1205         if ( ( not $iteminformation->{borrowernumber} ) && $doreturn ) {
1206             $messages->{'NotIssued'} = $barcode;
1207             $doreturn = 0;
1208         }
1209     
1210         # check if the book is in a permanent collection....
1211         my $hbr      = $iteminformation->{'homebranch'};
1212         my $branches = GetBranches();
1213         if ( $hbr && $branches->{$hbr}->{'PE'} ) {
1214             $messages->{'IsPermanent'} = $hbr;
1215         }
1216     
1217         # check that the book has been cancelled
1218         if ( $iteminformation->{'wthdrawn'} ) {
1219             $messages->{'wthdrawn'} = 1;
1220             $doreturn = 0;
1221         }
1222     
1223     #     new op dev : if the book returned in an other branch update the holding branch
1224     
1225     # update issues, thereby returning book (should push this out into another subroutine
1226         $borrower = GetMemberDetails( $iteminformation->{borrowernumber}, 0 );
1227     
1228     # case of a return of document (deal with issues and holdingbranch)
1229     
1230         if ($doreturn) {
1231             my $sth =
1232             $dbh->prepare(
1233     "update issues set returndate = now() where (borrowernumber = ?) and (itemnumber = ?) and (returndate is null)"
1234             );
1235             $sth->execute( $borrower->{'borrowernumber'},
1236                 $iteminformation->{'itemnumber'} );
1237             $messages->{'WasReturned'} = 1;    # FIXME is the "= 1" right?
1238         }
1239     
1240     # continue to deal with returns cases, but not only if we have an issue
1241     
1242     # the holdingbranch is updated if the document is returned in an other location .
1243     if ( $iteminformation->{'holdingbranch'} ne C4::Context->userenv->{'branch'} )
1244             {
1245                     UpdateHoldingbranch(C4::Context->userenv->{'branch'},$iteminformation->{'itemnumber'});     
1246     #           reload iteminformation holdingbranch with the userenv value
1247                     $iteminformation->{'holdingbranch'} = C4::Context->userenv->{'branch'};
1248             }
1249         ModDateLastSeen( $iteminformation->{'itemnumber'} );
1250         ($borrower) = GetMemberDetails( $iteminformation->{borrowernumber}, 0 );
1251         
1252         # fix up the accounts.....
1253         if ( $iteminformation->{'itemlost'} ) {
1254             $messages->{'WasLost'} = 1;
1255         }
1256     
1257     # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
1258     #     check if we have a transfer for this document
1259         my ($datesent,$frombranch,$tobranch) = GetTransfers( $iteminformation->{'itemnumber'} );
1260     
1261     #     if we have a transfer to do, we update the line of transfers with the datearrived
1262         if ($datesent) {
1263             if ( $tobranch eq C4::Context->userenv->{'branch'} ) {
1264                     my $sth =
1265                     $dbh->prepare(
1266                             "update branchtransfers set datearrived = now() where itemnumber= ? AND datearrived IS NULL"
1267                     );
1268                     $sth->execute( $iteminformation->{'itemnumber'} );
1269                     $sth->finish;
1270     #         now we check if there is a reservation with the validate of transfer if we have one, we can         set it with the status 'W'
1271             SetWaitingStatus( $iteminformation->{'itemnumber'} );
1272             }
1273         else {
1274             $messages->{'WrongTransfer'} = $tobranch;
1275             $messages->{'WrongTransferItem'} = $iteminformation->{'itemnumber'};
1276         }
1277         $validTransfert = 1;
1278         }
1279     
1280     # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
1281         # fix up the accounts.....
1282         if ($iteminformation->{'itemlost'}) {
1283                 FixAccountForLostAndReturned($iteminformation, $borrower);
1284                 $messages->{'WasLost'} = 1;
1285         }
1286         # fix up the overdues in accounts...
1287         FixOverduesOnReturn( $borrower->{'borrowernumber'},
1288             $iteminformation->{'itemnumber'} );
1289     
1290     # find reserves.....
1291     #     if we don't have a reserve with the status W, we launch the Checkreserves routine
1292         my ( $resfound, $resrec ) =
1293         CheckReserves( $iteminformation->{'itemnumber'} );
1294         if ($resfound) {
1295             $resrec->{'ResFound'}   = $resfound;
1296             $messages->{'ResFound'} = $resrec;
1297             $reserveDone = 1;
1298         }
1299     
1300         # update stats?
1301         # Record the fact that this book was returned.
1302         UpdateStats(
1303             $branch, 'return', '0', '',
1304             $iteminformation->{'itemnumber'},
1305             $iteminformation->{'itemtype'},
1306             $borrower->{'borrowernumber'}
1307         );
1308         
1309         &logaction(C4::Context->userenv->{'number'},"CIRCULATION","RETURN",$iteminformation->{borrowernumber},$iteminformation->{'biblionumber'}) 
1310             if C4::Context->preference("ReturnLog");
1311         
1312         #adding message if holdingbranch is non equal a userenv branch to return the document to homebranch
1313         #we check, if we don't have reserv or transfert for this document, if not, return it to homebranch .
1314         
1315         if ( ($iteminformation->{'holdingbranch'} ne $iteminformation->{'homebranch'}) and not $messages->{'WrongTransfer'} and ($validTransfert ne 1) and ($reserveDone ne 1) ){
1316                     if (C4::Context->preference("AutomaticItemReturn") == 1) {
1317                     dotransfer($iteminformation->{'itemnumber'}, C4::Context->userenv->{'branch'}, $iteminformation->{'homebranch'});
1318                     $messages->{'WasTransfered'} = 1;
1319                     warn "was transfered";
1320                     }
1321         }
1322     }
1323     return ( $doreturn, $messages, $iteminformation, $borrower );
1324 }
1325
1326 =head2 FixOverduesOnReturn
1327
1328     &FixOverduesOnReturn($brn,$itm);
1329
1330 C<$brn> borrowernumber
1331
1332 C<$itm> itemnumber
1333
1334 internal function, called only by AddReturn
1335
1336 =cut
1337
1338 sub FixOverduesOnReturn {
1339     my ( $borrowernumber, $item ) = @_;
1340     my $dbh = C4::Context->dbh;
1341
1342     # check for overdue fine
1343     my $sth =
1344       $dbh->prepare(
1345 "SELECT * FROM accountlines WHERE (borrowernumber = ?) AND (itemnumber = ?) AND (accounttype='FU' OR accounttype='O')"
1346       );
1347     $sth->execute( $borrowernumber, $item );
1348
1349     # alter fine to show that the book has been returned
1350     if ( my $data = $sth->fetchrow_hashref ) {
1351         my $usth =
1352           $dbh->prepare(
1353 "UPDATE accountlines SET accounttype='F' WHERE (borrowernumber = ?) AND (itemnumber = ?) AND (accountno = ?)"
1354           );
1355         $usth->execute( $borrowernumber, $item, $data->{'accountno'} );
1356         $usth->finish();
1357     }
1358     $sth->finish();
1359     return;
1360 }
1361
1362 =head2 FixAccountForLostAndReturned
1363
1364         &FixAccountForLostAndReturned($iteminfo,$borrower);
1365
1366 Calculates the charge for a book lost and returned (Not exported & used only once)
1367
1368 C<$iteminfo> is a hashref to iteminfo. Only {itemnumber} is used.
1369
1370 C<$borrower> is a hashref to borrower. Only {borrowernumber is used.
1371
1372 Internal function, called by AddReturn
1373
1374 =cut
1375
1376 sub FixAccountForLostAndReturned {
1377         my ($iteminfo, $borrower) = @_;
1378         my %env;
1379         my $dbh = C4::Context->dbh;
1380         my $itm = $iteminfo->{'itemnumber'};
1381         # check for charge made for lost book
1382         my $sth = $dbh->prepare("SELECT * FROM accountlines WHERE (itemnumber = ?) AND (accounttype='L' OR accounttype='Rep') ORDER BY date DESC");
1383         $sth->execute($itm);
1384         if (my $data = $sth->fetchrow_hashref) {
1385         # writeoff this amount
1386                 my $offset;
1387                 my $amount = $data->{'amount'};
1388                 my $acctno = $data->{'accountno'};
1389                 my $amountleft;
1390                 if ($data->{'amountoutstanding'} == $amount) {
1391                 $offset = $data->{'amount'};
1392                 $amountleft = 0;
1393                 } else {
1394                 $offset = $amount - $data->{'amountoutstanding'};
1395                 $amountleft = $data->{'amountoutstanding'} - $amount;
1396                 }
1397                 my $usth = $dbh->prepare("UPDATE accountlines SET accounttype = 'LR',amountoutstanding='0'
1398                         WHERE (borrowernumber = ?)
1399                         AND (itemnumber = ?) AND (accountno = ?) ");
1400                 $usth->execute($data->{'borrowernumber'},$itm,$acctno);
1401                 $usth->finish;
1402         #check if any credit is left if so writeoff other accounts
1403                 my $nextaccntno = getnextacctno(\%env,$data->{'borrowernumber'},$dbh);
1404                 if ($amountleft < 0){
1405                 $amountleft*=-1;
1406                 }
1407                 if ($amountleft > 0){
1408                 my $msth = $dbh->prepare("SELECT * FROM accountlines WHERE (borrowernumber = ?)
1409                                                         AND (amountoutstanding >0) ORDER BY date");
1410                 $msth->execute($data->{'borrowernumber'});
1411         # offset transactions
1412                 my $newamtos;
1413                 my $accdata;
1414                 while (($accdata=$msth->fetchrow_hashref) and ($amountleft>0)){
1415                         if ($accdata->{'amountoutstanding'} < $amountleft) {
1416                         $newamtos = 0;
1417                         $amountleft -= $accdata->{'amountoutstanding'};
1418                         }  else {
1419                         $newamtos = $accdata->{'amountoutstanding'} - $amountleft;
1420                         $amountleft = 0;
1421                         }
1422                         my $thisacct = $accdata->{'accountno'};
1423                         my $usth = $dbh->prepare("UPDATE accountlines SET amountoutstanding= ?
1424                                         WHERE (borrowernumber = ?)
1425                                         AND (accountno=?)");
1426                         $usth->execute($newamtos,$data->{'borrowernumber'},'$thisacct');
1427                         $usth->finish;
1428                         $usth = $dbh->prepare("INSERT INTO accountoffsets
1429                                 (borrowernumber, accountno, offsetaccount,  offsetamount)
1430                                 VALUES
1431                                 (?,?,?,?)");
1432                         $usth->execute($data->{'borrowernumber'},$accdata->{'accountno'},$nextaccntno,$newamtos);
1433                         $usth->finish;
1434                 }
1435                 $msth->finish;
1436                 }
1437                 if ($amountleft > 0){
1438                         $amountleft*=-1;
1439                 }
1440                 my $desc="Book Returned ".$iteminfo->{'barcode'};
1441                 $usth = $dbh->prepare("INSERT INTO accountlines
1442                         (borrowernumber,accountno,date,amount,description,accounttype,amountoutstanding)
1443                         VALUES (?,?,now(),?,?,'CR',?)");
1444                 $usth->execute($data->{'borrowernumber'},$nextaccntno,0-$amount,$desc,$amountleft);
1445                 $usth->finish;
1446                 $usth = $dbh->prepare("INSERT INTO accountoffsets
1447                         (borrowernumber, accountno, offsetaccount,  offsetamount)
1448                         VALUES (?,?,?,?)");
1449                 $usth->execute($borrower->{'borrowernumber'},$data->{'accountno'},$nextaccntno,$offset);
1450                 $usth->finish;
1451                 $usth = $dbh->prepare("UPDATE items SET paidfor='' WHERE itemnumber=?");
1452                 $usth->execute($itm);
1453                 $usth->finish;
1454         }
1455         $sth->finish;
1456         return;
1457 }
1458
1459 =head2 GetItemIssue
1460
1461 $issues = &GetBorrowerIssue($itemnumber);
1462
1463 Returns patrons currently having a book. nothing if item is not issued atm
1464
1465 C<$itemnumber> is the itemnumber
1466
1467 Returns an array of hashes
1468 =cut
1469
1470 sub GetItemIssue {
1471     my ( $itemnumber) = @_;
1472     return unless $itemnumber;
1473     my $dbh = C4::Context->dbh;
1474     my @GetItemIssues;
1475     
1476     # get today date
1477     my $today = POSIX::strftime("%Y%m%d", localtime);
1478
1479     my $sth = $dbh->prepare(
1480         "SELECT * FROM issues 
1481         LEFT JOIN items ON issues.itemnumber=items.itemnumber
1482     WHERE
1483     issues.itemnumber=?  AND returndate IS NULL ");
1484     $sth->execute($itemnumber);
1485     my $data = $sth->fetchrow_hashref;
1486     my $datedue = $data->{'date_due'};
1487     $datedue =~ s/-//g;
1488     if ( $datedue < $today ) {
1489         $data->{'overdue'} = 1;
1490     }
1491     $data->{'itemnumber'} = $itemnumber; # fill itemnumber, in case item is not on issue
1492     $sth->finish;
1493     return ($data);
1494 }
1495
1496 =head2 GetItemIssues
1497
1498 $issues = &GetBorrowerIssues($itemnumber, $history);
1499
1500 Returns patrons that have issued a book
1501
1502 C<$itemnumber> is the itemnumber
1503 C<$history> is 0 if you want actuel "issuer" (if it exist) and 1 if you want issues history
1504
1505 Returns an array of hashes
1506 =cut
1507
1508 sub GetItemIssues {
1509     my ( $itemnumber,$history ) = @_;
1510     my $dbh = C4::Context->dbh;
1511     my @GetItemIssues;
1512     
1513     # get today date
1514     my $today = POSIX::strftime("%Y%m%d", localtime);
1515
1516     my $sth = $dbh->prepare(
1517         "SELECT * FROM issues 
1518     WHERE
1519     itemnumber=?".($history?"":" AND returndate IS NULL ").
1520     "ORDER BY issues.date_due DESC"
1521     );
1522     $sth->execute($itemnumber);
1523     while ( my $data = $sth->fetchrow_hashref ) {
1524         my $datedue = $data->{'date_due'};
1525         $datedue =~ s/-//g;
1526         if ( $datedue < $today ) {
1527             $data->{'overdue'} = 1;
1528         }
1529         my $itemnumber = $data->{'itemnumber'};
1530
1531         push @GetItemIssues, $data;
1532     }
1533     $sth->finish;
1534     return ( \@GetItemIssues );
1535 }
1536
1537 =head2 GetBorrowerIssues
1538
1539 $issues = &GetBorrowerIssues($borrower);
1540
1541 Returns a list of books currently on loan to a patron.
1542
1543 C<$borrower->{borrowernumber}> is the borrower number of the patron
1544 whose issues we want to list.
1545
1546 C<&GetBorrowerIssues> returns a PHP-style array: C<$issues> is a
1547 reference-to-hash whose keys are integers in the range 1...I<n>, where
1548 I<n> is the number of items on issue (either today or before today).
1549 C<$issues-E<gt>{I<n>}> is a reference-to-hash whose keys are all of
1550 the fields of the biblio, biblioitems, items, and issues fields of the
1551 Koha database for that particular item.
1552
1553 =cut
1554
1555 sub GetBorrowerIssues {
1556     my ( $borrower ) = @_;
1557     my $dbh = C4::Context->dbh;
1558     my @GetBorrowerIssues;
1559     # get today date
1560     my $today = POSIX::strftime("%Y%m%d", localtime);
1561
1562     my $sth = $dbh->prepare(
1563         "SELECT * FROM issues 
1564     LEFT JOIN items ON issues.itemnumber=items.itemnumber
1565     LEFT JOIN biblio ON     items.biblionumber=biblio.biblionumber 
1566     LEFT JOIN biblioitems ON items.biblioitemnumber=biblioitems.biblioitemnumber
1567     WHERE
1568     borrowernumber=? AND returndate IS NULL
1569     ORDER BY issues.date_due"
1570     );
1571     $sth->execute($borrower->{'borrowernumber'});
1572     while ( my $data = $sth->fetchrow_hashref ) {
1573         my $datedue = $data->{'date_due'};
1574         $datedue =~ s/-//g;
1575         if ( $datedue < $today ) {
1576             $data->{'overdue'} = 1;
1577         }
1578         my $itemnumber = $data->{'itemnumber'};
1579
1580         push @GetBorrowerIssues, $data;
1581     }
1582     $sth->finish;
1583     return ( \@GetBorrowerIssues );
1584 }
1585
1586 =head2 GetBiblioIssues
1587
1588 $issues = GetBiblioIssues($biblionumber);
1589
1590 this function get all issues from a biblionumber.
1591
1592 Return:
1593 C<$issues> is a reference to array which each value is ref-to-hash. This ref-to-hash containts all column from
1594 tables issues and the firstname,surname & cardnumber from borrowers.
1595
1596 =cut
1597
1598 sub GetBiblioIssues {
1599     my $biblionumber = shift;
1600     return undef unless $biblionumber;
1601     my $dbh   = C4::Context->dbh;
1602     my $query = "
1603         SELECT issues.*,biblio.biblionumber,biblio.title, biblio.author,borrowers.cardnumber,borrowers.surname,borrowers.firstname
1604         FROM issues
1605             LEFT JOIN borrowers ON borrowers.borrowernumber = issues.borrowernumber
1606             LEFT JOIN items ON issues.itemnumber = items.itemnumber
1607             LEFT JOIN biblioitems ON items.itemnumber = biblioitems.biblioitemnumber
1608             LEFT JOIN biblio ON biblio.biblionumber = items.biblioitemnumber
1609         WHERE biblio.biblionumber = ?
1610         ORDER BY issues.timestamp
1611     ";
1612     my $sth = $dbh->prepare($query);
1613     $sth->execute($biblionumber);
1614
1615     my @issues;
1616     while ( my $data = $sth->fetchrow_hashref ) {
1617         push @issues, $data;
1618     }
1619     return \@issues;
1620 }
1621
1622 =head2 CanBookBeRenewed
1623
1624 $ok = &CanBookBeRenewed($borrowernumber, $itemnumber);
1625
1626 Find out whether a borrowed item may be renewed.
1627
1628 C<$dbh> is a DBI handle to the Koha database.
1629
1630 C<$borrowernumber> is the borrower number of the patron who currently
1631 has the item on loan.
1632
1633 C<$itemnumber> is the number of the item to renew.
1634
1635 C<$CanBookBeRenewed> returns a true value iff the item may be renewed. The
1636 item must currently be on loan to the specified borrower; renewals
1637 must be allowed for the item's type; and the borrower must not have
1638 already renewed the loan.
1639
1640 =cut
1641
1642 sub CanBookBeRenewed {
1643
1644     # check renewal status
1645     my ( $borrowernumber, $itemnumber ) = @_;
1646     my $dbh       = C4::Context->dbh;
1647     my $renews    = 1;
1648     my $renewokay = 0;
1649
1650     # Look in the issues table for this item, lent to this borrower,
1651     # and not yet returned.
1652
1653     # FIXME - I think this function could be redone to use only one SQL call.
1654     my $sth1 = $dbh->prepare(
1655         "SELECT * FROM issues
1656             WHERE borrowernumber = ?
1657             AND itemnumber = ?
1658             AND returndate IS NULL"
1659     );
1660     $sth1->execute( $borrowernumber, $itemnumber );
1661     if ( my $data1 = $sth1->fetchrow_hashref ) {
1662
1663         # Found a matching item
1664
1665         # See if this item may be renewed. This query is convoluted
1666         # because it's a bit messy: given the item number, we need to find
1667         # the biblioitem, which gives us the itemtype, which tells us
1668         # whether it may be renewed.
1669         my $sth2 = $dbh->prepare(
1670             "SELECT renewalsallowed FROM items
1671                 LEFT JOIN biblioitems on items.biblioitemnumber = biblioitems.biblioitemnumber
1672                 LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype
1673                 WHERE items.itemnumber = ?
1674                 "
1675         );
1676         $sth2->execute($itemnumber);
1677         if ( my $data2 = $sth2->fetchrow_hashref ) {
1678             $renews = $data2->{'renewalsallowed'};
1679         }
1680         if ( $renews && $renews > $data1->{'renewals'} ) {
1681             $renewokay = 1;
1682         }
1683         $sth2->finish;
1684         my ( $resfound, $resrec ) = C4::Reserves2::CheckReserves($itemnumber);
1685         if ($resfound) {
1686             $renewokay = 0;
1687         }
1688         ( $resfound, $resrec ) = C4::Reserves2::CheckReserves($itemnumber);
1689         if ($resfound) {
1690             $renewokay = 0;
1691         }
1692
1693     }
1694     $sth1->finish;
1695     return ($renewokay);
1696 }
1697
1698 =head2 AddRenewal
1699
1700 &AddRenewal($borrowernumber, $itemnumber, $datedue);
1701
1702 Renews a loan.
1703
1704 C<$borrowernumber> is the borrower number of the patron who currently
1705 has the item.
1706
1707 C<$itemnumber> is the number of the item to renew.
1708
1709 C<$datedue> can be used to set the due date. If C<$datedue> is the
1710 empty string, C<&AddRenewal> will calculate the due date automatically
1711 from the book's item type. If you wish to set the due date manually,
1712 C<$datedue> should be in the form YYYY-MM-DD.
1713
1714 =cut
1715
1716 sub AddRenewal {
1717
1718     my ( $borrowernumber, $itemnumber, $datedue ) = @_;
1719     my $dbh = C4::Context->dbh;
1720
1721     # If the due date wasn't specified, calculate it by adding the
1722     # book's loan length to today's date.
1723     if ( $datedue eq "" ) {
1724
1725         my $biblio = GetBiblioFromItemNumber($itemnumber);
1726         my $borrower = GetMemberDetails( $borrowernumber, 0 );
1727         my $loanlength = GetLoanLength(
1728             $borrower->{'categorycode'},
1729             $biblio->{'itemtype'},
1730             $borrower->{'branchcode'}
1731         );
1732         my ( $due_year, $due_month, $due_day ) =
1733           Add_Delta_DHMS( Today_and_Now(), $loanlength, 0, 0, 0 );
1734         $datedue = "$due_year-$due_month-$due_day";
1735
1736     }
1737
1738     # Find the issues record for this book
1739     my $sth =
1740       $dbh->prepare("SELECT * FROM issues
1741                         WHERE borrowernumber=? 
1742                         AND itemnumber=? 
1743                         AND returndate IS NULL"
1744       );
1745     $sth->execute( $borrowernumber, $itemnumber );
1746     my $issuedata = $sth->fetchrow_hashref;
1747     $sth->finish;
1748
1749     # Update the issues record to have the new due date, and a new count
1750     # of how many times it has been renewed.
1751     my $renews = $issuedata->{'renewals'} + 1;
1752     $sth = $dbh->prepare("UPDATE issues SET date_due = ?, renewals = ?
1753                             WHERE borrowernumber=? 
1754                             AND itemnumber=? 
1755                             AND returndate IS NULL"
1756     );
1757     $sth->execute( $datedue, $renews, $borrowernumber, $itemnumber );
1758     $sth->finish;
1759
1760     # Log the renewal
1761     UpdateStats( C4::Context->userenv->{'branchcode'}, 'renew', '', '', $itemnumber );
1762
1763     # Charge a new rental fee, if applicable?
1764     my ( $charge, $type ) = GetIssuingCharges( $itemnumber, $borrowernumber );
1765     if ( $charge > 0 ) {
1766         my $accountno = getnextacctno( $borrowernumber );
1767         my $item = GetBiblioFromItemNumber($itemnumber);
1768         $sth = $dbh->prepare(
1769                 "INSERT INTO accountlines
1770                     (borrowernumber,accountno,date,amount,
1771                         description,accounttype,amountoutstanding,
1772                     itemnumber)
1773                     VALUES (?,?,now(),?,?,?,?,?)"
1774         );
1775         $sth->execute( $borrowernumber, $accountno, $charge,
1776             "Renewal of Rental Item $item->{'title'} $item->{'barcode'}",
1777             'Rent', $charge, $itemnumber );
1778         $sth->finish;
1779     }
1780 }
1781
1782 =head2 GetIssuingCharges
1783
1784 ($charge, $item_type) = &GetIssuingCharges($itemnumber, $borrowernumber);
1785
1786 Calculate how much it would cost for a given patron to borrow a given
1787 item, including any applicable discounts.
1788
1789 C<$itemnumber> is the item number of item the patron wishes to borrow.
1790
1791 C<$borrowernumber> is the patron's borrower number.
1792
1793 C<&GetIssuingCharges> returns two values: C<$charge> is the rental charge,
1794 and C<$item_type> is the code for the item's item type (e.g., C<VID>
1795 if it's a video).
1796
1797 =cut
1798
1799 sub GetIssuingCharges {
1800
1801     # calculate charges due
1802     my ( $itemnumber, $borrowernumber ) = @_;
1803     my $charge = 0;
1804     my $dbh    = C4::Context->dbh;
1805     my $item_type;
1806
1807     # Get the book's item type and rental charge (via its biblioitem).
1808     my $sth1 = $dbh->prepare(
1809         "SELECT itemtypes.itemtype,rentalcharge FROM items
1810             LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber
1811             LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype
1812             WHERE items.itemnumber =?
1813         "
1814     );
1815     $sth1->execute($itemnumber);
1816     if ( my $data1 = $sth1->fetchrow_hashref ) {
1817         $item_type = $data1->{'itemtype'};
1818         $charge    = $data1->{'rentalcharge'};
1819         my $q2 = "SELECT rentaldiscount FROM borrowers
1820             LEFT JOIN issuingrules ON borrowers.categorycode = issuingrules.categorycode
1821             WHERE borrowers.borrowernumber = ?
1822             AND issuingrules.itemtype = ?";
1823         my $sth2 = $dbh->prepare($q2);
1824         $sth2->execute( $borrowernumber, $item_type );
1825         if ( my $data2 = $sth2->fetchrow_hashref ) {
1826             my $discount = $data2->{'rentaldiscount'};
1827             if ( $discount eq 'NULL' ) {
1828                 $discount = 0;
1829             }
1830             $charge = ( $charge * ( 100 - $discount ) ) / 100;
1831         }
1832         $sth2->finish;
1833     }
1834
1835     $sth1->finish;
1836     return ( $charge, $item_type );
1837 }
1838
1839 =head2 AddIssuingCharge
1840
1841 &AddIssuingCharge( $itemno, $borrowernumber, $charge )
1842
1843 =cut
1844
1845 sub AddIssuingCharge {
1846     my ( $itemnumber, $borrowernumber, $charge ) = @_;
1847     my $dbh = C4::Context->dbh;
1848     my $nextaccntno = getnextacctno( $borrowernumber );
1849     my $query ="
1850         INSERT INTO accountlines
1851             (borrowernumber, itemnumber, accountno,
1852             date, amount, description, accounttype,
1853             amountoutstanding)
1854         VALUES (?, ?, ?,now(), ?, 'Rental', 'Rent',?)
1855     ";
1856     my $sth = $dbh->prepare($query);
1857     $sth->execute( $borrowernumber, $itemnumber, $nextaccntno, $charge, $charge );
1858     $sth->finish;
1859 }
1860
1861 =head2 GetTransfers
1862
1863 GetTransfers($itemnumber);
1864
1865 =cut
1866
1867 sub GetTransfers {
1868     my ($itemnumber) = @_;
1869
1870     my $dbh = C4::Context->dbh;
1871
1872     my $query = '
1873         SELECT datesent,
1874                frombranch,
1875                tobranch
1876         FROM branchtransfers
1877         WHERE itemnumber = ?
1878           AND datearrived IS NULL
1879         ';
1880     my $sth = $dbh->prepare($query);
1881     $sth->execute($itemnumber);
1882     my @row = $sth->fetchrow_array();
1883     $sth->finish;
1884     return @row;
1885 }
1886
1887
1888 =head2 GetTransfersFromTo
1889
1890 @results = GetTransfersFromTo($frombranch,$tobranch);
1891
1892 Returns the list of pending transfers between $from and $to branch
1893
1894 =cut
1895
1896 sub GetTransfersFromTo {
1897     my ( $frombranch, $tobranch ) = @_;
1898     return unless ( $frombranch && $tobranch );
1899     my $dbh   = C4::Context->dbh;
1900     my $query = "
1901         SELECT itemnumber,datesent,frombranch
1902         FROM   branchtransfers
1903         WHERE  frombranch=?
1904           AND  tobranch=?
1905           AND datearrived IS NULL
1906     ";
1907     my $sth = $dbh->prepare($query);
1908     $sth->execute( $frombranch, $tobranch );
1909     my @gettransfers;
1910
1911     while ( my $data = $sth->fetchrow_hashref ) {
1912         push @gettransfers, $data;
1913     }
1914     $sth->finish;
1915     return (@gettransfers);
1916 }
1917
1918 =head2 DeleteTransfer
1919
1920 &DeleteTransfer($itemnumber);
1921
1922 =cut
1923
1924 sub DeleteTransfer {
1925     my ($itemnumber) = @_;
1926     my $dbh          = C4::Context->dbh;
1927     my $sth          = $dbh->prepare(
1928         "DELETE FROM branchtransfers
1929          WHERE itemnumber=?
1930          AND datearrived IS NULL "
1931     );
1932     $sth->execute($itemnumber);
1933     $sth->finish;
1934 }
1935
1936 =head2 AnonymiseIssueHistory
1937
1938 $rows = AnonymiseIssueHistory($borrowernumber,$date)
1939
1940 This function write NULL instead of C<$borrowernumber> given on input arg into the table issues.
1941 if C<$borrowernumber> is not set, it will delete the issue history for all borrower older than C<$date>.
1942
1943 return the number of affected rows.
1944
1945 =cut
1946
1947 sub AnonymiseIssueHistory {
1948     my $date           = shift;
1949     my $borrowernumber = shift;
1950     my $dbh            = C4::Context->dbh;
1951     my $query          = "
1952         UPDATE issues
1953         SET    borrowernumber = NULL
1954         WHERE  returndate < '".$date."'
1955           AND borrowernumber IS NOT NULL
1956     ";
1957     $query .= " AND borrowernumber = '".$borrowernumber."'" if defined $borrowernumber;
1958     my $rows_affected = $dbh->do($query);
1959     return $rows_affected;
1960 }
1961
1962 =head2 updateWrongTransfer
1963
1964 $items = updateWrongTransfer($itemNumber,$borrowernumber,$waitingAtLibrary,$FromLibrary);
1965
1966 This function validate the line of brachtransfer but with the wrong destination (mistake from a librarian ...), and create a new line in branchtransfer from the actual library to the original library of reservation 
1967
1968 =cut
1969
1970 sub updateWrongTransfer {
1971         my ( $itemNumber,$waitingAtLibrary,$FromLibrary ) = @_;
1972         my $dbh = C4::Context->dbh;     
1973 # first step validate the actual line of transfert .
1974         my $sth =
1975                 $dbh->prepare(
1976                         "update branchtransfers set datearrived = now(),tobranch=?,comments='wrongtransfer' where itemnumber= ? AND datearrived IS NULL"
1977                 );
1978                 $sth->execute($FromLibrary,$itemNumber);
1979                 $sth->finish;
1980
1981 # second step create a new line of branchtransfer to the right location .
1982         dotransfer($itemNumber, $FromLibrary, $waitingAtLibrary);
1983
1984 #third step changing holdingbranch of item
1985         UpdateHoldingbranch($FromLibrary,$itemNumber);
1986 }
1987
1988 =head2 UpdateHoldingbranch
1989
1990 $items = UpdateHoldingbranch($branch,$itmenumber);
1991 Simple methode for updating hodlingbranch in items BDD line
1992 =cut
1993
1994 sub UpdateHoldingbranch {
1995         my ( $branch,$itmenumber ) = @_;
1996         my $dbh = C4::Context->dbh;     
1997 # first step validate the actual line of transfert .
1998         my $sth =
1999                 $dbh->prepare(
2000                         "update items set holdingbranch = ? where itemnumber= ?"
2001                 );
2002                 $sth->execute($branch,$itmenumber);
2003                 $sth->finish;
2004         
2005         
2006 }
2007
2008 1;
2009
2010 __END__
2011
2012 =head1 AUTHOR
2013
2014 Koha Developement team <info@koha.org>
2015
2016 =cut
2017