From a1f786dd8fc2779edfcef3eb06a751b9873cf8dd Mon Sep 17 00:00:00 2001 From: Robin Sheat Date: Thu, 15 Dec 2011 13:50:39 +1300 Subject: [PATCH] Bug 7362 - allow checkout by item number This adds a system preference (CircFallbackItemnumber) that allows the item number to be used instead of a barcode when issuing items. It will check the barcode first, but if it isn't found, it'll attempt to use the item number. There is also a bit of related refactoring going on, removing some of the assumption from Koha that every item has a barcode, and using that as a primary key in the circulatory system. --- C4/Circulation.pm | 73 ++++++++++++------- C4/Dates.pm | 2 +- C4/SIP/ILS/Transaction/Checkout.pm | 4 +- C4/SIP/ILS/Transaction/Renew.pm | 2 +- circ/circulation.pl | 35 ++++++---- installer/data/mysql/sysprefs.sql | 1 + .../en/modules/admin/preferences/circulation.pref | 6 ++ .../prog/en/modules/circ/circulation.tt | 4 +- offline_circ/process_koc.pl | 4 +- opac/sco/sco-main.pl | 2 +- t/db_dependent/lib/KohaTest/Circulation.pm | 3 +- .../lib/KohaTest/Circulation/AddIssue.pm | 4 +- .../lib/KohaTest/Overdues/GetOverdues.pm | 2 +- t/db_dependent/lib/KohaTest/Scripts/longoverdue.pm | 2 +- 14 files changed, 88 insertions(+), 56 deletions(-) diff --git a/C4/Circulation.pm b/C4/Circulation.pm index 3d63224..7e8b972 100644 --- a/C4/Circulation.pm +++ b/C4/Circulation.pm @@ -2,6 +2,7 @@ package C4::Circulation; # Copyright 2000-2002 Katipo Communications # copyright 2010 BibLibre +# Copyright 2011 Catalyst IT # # This file is part of Koha. # @@ -569,8 +570,8 @@ sub itemissues { =head2 CanBookBeIssued - ( $issuingimpossible, $needsconfirmation ) = CanBookBeIssued( $borrower, - $barcode, $duedatespec, $inprocess ); + ( $issuingimpossible, $needsconfirmation, $itemnumber ) = + CanBookBeIssued( $borrower, $barcode, $duedatespec, $inprocess, $itemnumber ); Check if a book can be issued. @@ -586,6 +587,10 @@ C<$issuingimpossible> and C<$needsconfirmation> are some hashref. =item C<$inprocess> +=item C<$itemnumber> is used to look up the record by item number if the barcode +doesn't match, based on the C syspref. If C<$itemnumber> +is unset, then C<$barcode> will be tried as an item number instead. + =back Returns : @@ -658,23 +663,33 @@ sticky due date is invalid or due date in the past if the borrower borrows to much things +C<$itemnumber> if the itemnumber was found. + =cut sub CanBookBeIssued { - my ( $borrower, $barcode, $duedate, $inprocess ) = @_; + my ( $borrower, $barcode, $duedate, $inprocess, $itemnumber ) = @_; my %needsconfirmation; # filled with problems that needs confirmations my %issuingimpossible; # filled with problems that causes the issue to be IMPOSSIBLE - my $item = GetItem(GetItemnumberFromBarcode( $barcode )); - my $issue = GetItemIssue($item->{itemnumber}); - my $biblioitem = GetBiblioItemData($item->{biblioitemnumber}); - $item->{'itemtype'}=$item->{'itype'}; - my $dbh = C4::Context->dbh; - + my $item = GetItem( GetItemnumberFromBarcode($barcode) ); + # If we should fall back to searching by item number... + my $fallback_itemnumber = C4::Context->preference('CircFallbackItemnumber'); + if ( !defined( $item->{biblioitemnumber} ) + && $fallback_itemnumber) + { + $item = GetItem( $itemnumber // $barcode ); + } # MANDATORY CHECKS - unless item exists, nothing else matters - unless ( $item->{barcode} ) { + unless ( defined($item->{biblioitemnumber}) ) { $issuingimpossible{UNKNOWN_BARCODE} = 1; } - return ( \%issuingimpossible, \%needsconfirmation ) if %issuingimpossible; + return ( \%issuingimpossible, \%needsconfirmation, undef ) + if %issuingimpossible; + + my $issue = GetItemIssue( $item->{itemnumber} ); + my $biblioitem = GetBiblioItemData( $item->{biblioitemnumber} ); + $item->{'itemtype'} = $item->{'itype'}; + my $dbh = C4::Context->dbh; # # DUE DATE is OK ? -- should already have checked. @@ -699,11 +714,16 @@ sub CanBookBeIssued { # # BORROWER STATUS # - if ( $borrower->{'category_type'} eq 'X' && ( $item->{barcode} )) { - # stats only borrower -- add entry to statistics table, and return issuingimpossible{STATS} = 1 . - &UpdateStats(C4::Context->userenv->{'branch'},'localuse','','',$item->{'itemnumber'},$item->{'itemtype'},$borrower->{'borrowernumber'}); + if ( $borrower->{'category_type'} eq 'X' + && ( defined( $item->{itemnumber} ) ) ) + { + +# stats only borrower -- add entry to statistics table, and return issuingimpossible{STATS} = 1 . + &UpdateStats( C4::Context->userenv->{'branch'}, + 'localuse', '', '', $item->{'itemnumber'}, $item->{'itemtype'}, + $borrower->{'borrowernumber'} ); ModDateLastSeen( $item->{'itemnumber'} ); - return( { STATS => 1 }, {}); + return ( { STATS => 1 }, {}, $item->{itemnumber} ); } if ( $borrower->{flags}->{GNA} ) { $issuingimpossible{GNA} = 1; @@ -720,7 +740,7 @@ sub CanBookBeIssued { my @expirydate= split /-/,$borrower->{'dateexpiry'}; if($expirydate[0]==0 || $expirydate[1]==0|| $expirydate[2]==0 || Date_to_Days(Today) > Date_to_Days( @expirydate )) { - $issuingimpossible{EXPIRED} = 1; + $issuingimpossible{EXPIRED} = 1; } } # @@ -898,12 +918,12 @@ sub CanBookBeIssued { $needsconfirmation{'resreservedate'} = format_date($res->{'reservedate'}); } } - return ( \%issuingimpossible, \%needsconfirmation ); + return ( \%issuingimpossible, \%needsconfirmation, $item->{itemnumber} ); } =head2 AddIssue - &AddIssue($borrower, $barcode, [$datedue], [$cancelreserve], [$issuedate]) + &AddIssue($borrower, $itemnumber, [$datedue], [$cancelreserve], [$issuedate]) Issue a book. Does no check, they are done in CanBookBeIssued. If we reach this sub, it means the user confirmed if needed. @@ -911,7 +931,7 @@ Issue a book. Does no check, they are done in CanBookBeIssued. If we reach this =item C<$borrower> is a hash with borrower informations (from GetMember or GetMemberDetails). -=item C<$barcode> is the barcode of the item being issued. +=item C<$itemnumber> is the itemnumber of the item being issued. =item C<$datedue> is a C4::Dates object for the max date of return, i.e. the date due (optional). Calculated if empty. @@ -923,7 +943,7 @@ Defaults to today. Unlike C<$datedue>, NOT a C4::Dates object, unfortunately. AddIssue does the following things : - - step 01: check that there is a borrowernumber & a barcode provided + - step 01: check that there is a borrowernumber & an itemnumber provided - check for RENEWAL (book issued & being issued to the same patron) - renewal YES = Calculate Charge & renew - renewal NO = @@ -940,26 +960,25 @@ AddIssue does the following things : =cut sub AddIssue { - my ( $borrower, $barcode, $datedue, $cancelreserve, $issuedate, $sipmode) = @_; + my ( $borrower, $itemnumber, $datedue, $cancelreserve, $issuedate, $sipmode) = @_; my $dbh = C4::Context->dbh; - my $barcodecheck=CheckValidBarcode($barcode); # $issuedate defaults to today. if ( ! defined $issuedate ) { $issuedate = strftime( "%Y-%m-%d", localtime ); # TODO: for hourly circ, this will need to be a C4::Dates object # and all calls to AddIssue including issuedate will need to pass a Dates object. } - if ($borrower and $barcode and $barcodecheck ne '0'){ + if (defined($borrower) and defined($itemnumber)){ # find which item we issue - my $item = GetItem('', $barcode) or return undef; # if we don't get an Item, abort. + my $item = GetItem($itemnumber) or return undef; # if we don't get an Item, abort. my $branch = _GetCircControlBranch($item,$borrower); - + # get actual issuing if there is one my $actualissue = GetItemIssue( $item->{itemnumber}); - + # get biblioinformation for this item my $biblio = GetBiblioFromItemNumber($item->{itemnumber}); - + # # check if we just renew the issue. # diff --git a/C4/Dates.pm b/C4/Dates.pm index 8b29264..e61fc19 100644 --- a/C4/Dates.pm +++ b/C4/Dates.pm @@ -167,7 +167,7 @@ sub init ($;$$) { $self->{'dateformat'} = $dformat = ( scalar(@_) >= 2 ) ? $_[1] : _prefformat(); ( $format_map{$dformat} ) or croak "Invalid date format '$dformat' from " . ( ( scalar(@_) >= 2 ) ? 'argument' : 'system preferences' ); $self->{'dmy_arrayref'} = [ ( (@_) ? $self->dmy_map(shift) : localtime ) ]; - if ($debug > 1) { warn "(during init) \@\$self->{'dmy_arrayref'}: " . join( ' ', @{ $self->{'dmy_arrayref'} } ) . "\n"; } + if ($debug && $debug > 1) { warn "(during init) \@\$self->{'dmy_arrayref'}: " . join( ' ', @{ $self->{'dmy_arrayref'} } ) . "\n"; } return $self; } diff --git a/C4/SIP/ILS/Transaction/Checkout.pm b/C4/SIP/ILS/Transaction/Checkout.pm index 8a14877..4fe382f 100644 --- a/C4/SIP/ILS/Transaction/Checkout.pm +++ b/C4/SIP/ILS/Transaction/Checkout.pm @@ -113,10 +113,10 @@ sub do_checkout { # TODO: adjust representation in $self->item } # can issue - $debug and warn "do_checkout: calling AddIssue(\$borrower,$barcode, undef, 0)\n" + $debug and warn "do_checkout: calling AddIssue(\$borrower,$itemnumber, undef, 0)\n" # . "w/ \$borrower: " . Dumper($borrower) . "w/ C4::Context->userenv: " . Dumper(C4::Context->userenv); - my $c4due = AddIssue($borrower, $barcode, undef, 0); + my $c4due = AddIssue($borrower, $itemnumber, undef, 0); my $due = $c4due->output('iso') || undef; $debug and warn "Item due: $due"; $self->{'due'} = $due; diff --git a/C4/SIP/ILS/Transaction/Renew.pm b/C4/SIP/ILS/Transaction/Renew.pm index 73acaa3..f297575 100644 --- a/C4/SIP/ILS/Transaction/Renew.pm +++ b/C4/SIP/ILS/Transaction/Renew.pm @@ -37,7 +37,7 @@ sub do_renew_for ($$) { my $borrower = shift; my ($renewokay,$renewerror) = CanBookBeRenewed($borrower->{borrowernumber},$self->{item}->{itemnumber}); if ($renewokay){ - my $datedue = AddIssue( $borrower, $self->{item}->id, undef, 0 ); + my $datedue = AddIssue( $borrower, $self->{item}->{itemnumber}, undef, 0 ); $self->{due} = $datedue; $self->renewal_ok(1); } else { diff --git a/circ/circulation.pl b/circ/circulation.pl index ad6773e..b4a2423 100755 --- a/circ/circulation.pl +++ b/circ/circulation.pl @@ -4,6 +4,7 @@ # Copyright 2000-2002 Katipo Communications # copyright 2010 BibLibre +# Copyright 2011 Catalyst IT # # This file is part of Koha. # @@ -116,10 +117,10 @@ if (C4::Context->preference("UseTablesortForCirc")) { $template->param(UseTablesortForCirc => 1); } -my $barcode = $query->param('barcode') || ''; -$barcode =~ s/^\s*|\s*$//g; # remove leading/trailing whitespace - -$barcode = barcodedecode($barcode) if( $barcode && C4::Context->preference('itemBarcodeInputFilter')); +my $orig_barcode = $query->param('barcode') || ''; +$orig_barcode =~ s/^\s*|\s*$//g; # remove leading/trailing whitespace +my $barcode = $orig_barcode; +$barcode = barcodedecode($orig_barcode) if( $orig_barcode && C4::Context->preference('itemBarcodeInputFilter')); my $stickyduedate = $query->param('stickyduedate') || $session->param('stickyduedate'); my $duedatespec = $query->param('duedatespec') || $session->param('stickyduedate'); my $issueconfirmed = $query->param('issueconfirmed'); @@ -278,30 +279,33 @@ if ($borrowernumber) { # # if ($barcode) { + # always check for blockers on issuing - my ( $error, $question ) = - CanBookBeIssued( $borrower, $barcode, $datedue , $inprocess ); + my ( $error, $question, $itemnumber ) = + CanBookBeIssued( $borrower, $barcode, $datedue, $inprocess, + $orig_barcode ); my $blocker = $invalidduedate ? 1 : 0; delete $question->{'DEBT'} if ($debt_confirmed); foreach my $impossible ( keys %$error ) { $template->param( - $impossible => $$error{$impossible}, - IMPOSSIBLE => 1 + $impossible => $error->{$impossible}, + IMPOSSIBLE => 1, ); $blocker = 1; } if( !$blocker ){ my $confirm_required = 0; - unless($issueconfirmed){ + unless ($issueconfirmed) { # Get the item title for more information - my $getmessageiteminfo = GetBiblioFromItemNumber(undef,$barcode); - $template->param( itemhomebranch => $getmessageiteminfo->{'homebranch'} ); - + my $getmessageiteminfo = + GetBiblioFromItemNumber( $itemnumber, $barcode ); + $template->param( + itemhomebranch => $getmessageiteminfo->{'homebranch'} ); # pass needsconfirmation to template if issuing is possible and user hasn't yet confirmed. foreach my $needsconfirmation ( keys %$question ) { $template->param( - $needsconfirmation => $$question{$needsconfirmation}, + $needsconfirmation => $question->{$needsconfirmation}, getTitleMessageIteminfo => $getmessageiteminfo->{'title'}, getBarcodeMessageIteminfo => $getmessageiteminfo->{'barcode'}, NEEDSCONFIRMATION => 1 @@ -310,11 +314,11 @@ if ($barcode) { } } unless($confirm_required) { - AddIssue( $borrower, $barcode, $datedue, $cancelreserve ); + AddIssue( $borrower, $itemnumber, $datedue, $cancelreserve ); $inprocess = 1; } } - + # FIXME If the issue is confirmed, we launch another time GetMemberIssuesAndFines, now display the issue count after issue my ( $od, $issue, $fines ) = GetMemberIssuesAndFines( $borrowernumber ); $template->param( issuecount => $issue ); @@ -656,6 +660,7 @@ $template->param( lib_messages_loop => $lib_messages_loop, bor_messages_loop => $bor_messages_loop, all_messages_del => C4::Context->preference('AllowAllMessageDeletion'), + can_be_itemnumber => C4::Context->preference('CircFallbackItemnumber'), findborrower => $findborrower, borrower => $borrower, borrowernumber => $borrowernumber, diff --git a/installer/data/mysql/sysprefs.sql b/installer/data/mysql/sysprefs.sql index 128c9b2..deb10a2 100755 --- a/installer/data/mysql/sysprefs.sql +++ b/installer/data/mysql/sysprefs.sql @@ -328,4 +328,5 @@ INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES(' INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES ('OpacKohaUrl','1',"Show 'Powered by Koha' text on OPAC footer.",NULL,NULL); INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('EasyAnalyticalRecords','0','If on, display in the catalogue screens tools to easily setup analytical record relationships','','YesNo'); INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacShowRecentComments',0,'If ON a link to recent comments will appear in the OPAC masthead',NULL,'YesNo'); +INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('CircFallbackItemnumber',0,'If ON then checking out will look for a matching item number if a barcode is not found',NULL,'YesNo'); diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref index f4946b5..8c9ff84 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref @@ -91,6 +91,12 @@ Circulation: yes: Record no: "Don't record" - local use when an unissued item is checked in. + - + - pref: CircFallbackItemnumber + choices: + yes: Do + no: "Don't" + - fall back to search by itemnumber if a matching barcode isn't found. Checkout Policy: - - pref: AllowNotForLoanOverride diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt index 5627109..ea19bc6 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt @@ -343,7 +343,7 @@ function refocus(calendar) { [% END %] [% IF ( UNKNOWN_BARCODE ) %] -
  • The barcode was not found [% barcode %]
  • +
  • The barcode [% IF (can_be_itemnumber) %]or item number [% END %]was not found: [% barcode %]
  • [% IF ( fast_cataloging ) %] [% IF ( CAN_user_editcatalogue_fast_cataloging ) %] Fast cataloging @@ -458,7 +458,7 @@ No patron matched [% message %] -
    Enter item barcode:
    +
    Enter item [% IF (can_be_itemnumber) %]number or [% END %]barcode:
    [% IF ( NEEDSCONFIRMATION ) %] diff --git a/offline_circ/process_koc.pl b/offline_circ/process_koc.pl index 6c48ffb..73accca 100755 --- a/offline_circ/process_koc.pl +++ b/offline_circ/process_koc.pl @@ -281,7 +281,7 @@ sub kocIssueItem { my ( $c_y, $c_m, $c_d ) = split( /-/, $circ->{'date'} ); if ( Date_to_Days( $i_y, $i_m, $i_d ) < Date_to_Days( $c_y, $c_m, $c_d ) ) { ## Current issue to a different persion is older than this issue, return and issue. - C4::Circulation::AddIssue( $borrower, $circ->{'barcode'}, undef, undef, $circ->{'date'} ) unless ( DEBUG ); + C4::Circulation::AddIssue( $borrower, $item->{itemnumber}, undef, undef, $circ->{'date'} ) unless ( DEBUG ); push @output, { issue => 1, title => $item->{ 'title' }, @@ -301,7 +301,7 @@ sub kocIssueItem { } } } else { ## Item is not checked out to anyone at the moment, go ahead and issue it - C4::Circulation::AddIssue( $borrower, $circ->{'barcode'}, undef, undef, $circ->{'date'} ) unless ( DEBUG ); + C4::Circulation::AddIssue( $borrower, $item->{itemnumber}, undef, undef, $circ->{'date'} ) unless ( DEBUG ); push @output, { issue => 1, title => $item->{ 'title' }, diff --git a/opac/sco/sco-main.pl b/opac/sco/sco-main.pl index a1a3ce6..92b49fa 100755 --- a/opac/sco/sco-main.pl +++ b/opac/sco/sco-main.pl @@ -186,7 +186,7 @@ elsif ( $op eq "checkout" ) { } else { if ( $confirmed || $issuenoconfirm ) { # we'll want to call getpatroninfo again to get updated issues. # warn "issuing book?"; - AddIssue( $borrower, $barcode ); + AddIssue( $borrower, $item->{itemnumber} ); # ($borrower, $flags) = getpatroninformation(undef,undef, $patronid); # $template->param( # patronid => $patronid, diff --git a/t/db_dependent/lib/KohaTest/Circulation.pm b/t/db_dependent/lib/KohaTest/Circulation.pm index b3a1ff8..cddbd45 100644 --- a/t/db_dependent/lib/KohaTest/Circulation.pm +++ b/t/db_dependent/lib/KohaTest/Circulation.pm @@ -97,6 +97,7 @@ sub checkout_first_item { $barcode = $self->get_barcode_from_itemnumber( $self->{'items'}[0]{'itemnumber'} ); } + my $itemnumber = $self->{'items'}[0]{'itemnumber'}; # get issuedate from parameters. Default to undef, which will be interpreted as today my $issuedate = $params->{'issuedate'}; @@ -104,7 +105,7 @@ sub checkout_first_item { my $datedue = C4::Circulation::AddIssue( $borrower, # borrower - $barcode, # barcode + $itemnumber, # itemnumber undef, # datedue undef, # cancelreserve $issuedate # issuedate diff --git a/t/db_dependent/lib/KohaTest/Circulation/AddIssue.pm b/t/db_dependent/lib/KohaTest/Circulation/AddIssue.pm index 2c3e393..e6e4711 100644 --- a/t/db_dependent/lib/KohaTest/Circulation/AddIssue.pm +++ b/t/db_dependent/lib/KohaTest/Circulation/AddIssue.pm @@ -49,7 +49,7 @@ sub basic_usage : Test( 13 ) { my $dbh = C4::Context->dbh; $dbh->do("UPDATE systempreferences SET value = 1 WHERE variable = 'IssuingInProcess'"); C4::Context->clear_syspref_cache(); # FIXME not needed after a syspref mutator is written - ( $issuingimpossible, $needsconfirmation ) = C4::Circulation::CanBookBeIssued( $borrower, $barcode ); + ( $issuingimpossible, $needsconfirmation, $itemnumber ) = C4::Circulation::CanBookBeIssued( $borrower, $barcode ); is( scalar keys %$issuingimpossible, 0, 'the item CanBookBeIssued with IssuingInProcess ON (bug 2758)' ) or diag( Data::Dumper->Dump( [ $issuingimpossible, $needsconfirmation ], [ qw( issuingimpossible needsconfirmation ) ] ) ); is( scalar keys %$needsconfirmation, 0, @@ -58,7 +58,7 @@ sub basic_usage : Test( 13 ) { $dbh->do("UPDATE systempreferences SET value = ? WHERE variable = 'IssuingInProcess'", {}, $orig_issuing_in_process); C4::Context->clear_syspref_cache(); # FIXME not needed after a syspref mutator is written - my $datedue = C4::Circulation::AddIssue( $borrower, $barcode ); + my $datedue = C4::Circulation::AddIssue( $borrower, $itemnumber ); ok( $datedue, "the item has been issued and it is due: $datedue" ); my $after_issues = C4::Circulation::GetItemIssue( $self->{'items'}[0]{'itemnumber'} ); diff --git a/t/db_dependent/lib/KohaTest/Overdues/GetOverdues.pm b/t/db_dependent/lib/KohaTest/Overdues/GetOverdues.pm index 3cfc438..6bbf785 100644 --- a/t/db_dependent/lib/KohaTest/Overdues/GetOverdues.pm +++ b/t/db_dependent/lib/KohaTest/Overdues/GetOverdues.pm @@ -52,7 +52,7 @@ sub startup_60_create_overdue_item : Test( startup => 17 ) { is( keys %$issuingimpossible, 0, 'issuing is not impossible' ); is( keys %$needsconfirmation, 0, 'issuing needs no confirmation' ); - C4::Circulation::AddIssue( $borrower, $item->{'barcode'}, $duedate ); + C4::Circulation::AddIssue( $borrower, $item->{'itemnumber'}, $duedate ); } sub basic_usage : Test( 2 ) { diff --git a/t/db_dependent/lib/KohaTest/Scripts/longoverdue.pm b/t/db_dependent/lib/KohaTest/Scripts/longoverdue.pm index e00fb0c..ddb0d8f 100644 --- a/t/db_dependent/lib/KohaTest/Scripts/longoverdue.pm +++ b/t/db_dependent/lib/KohaTest/Scripts/longoverdue.pm @@ -68,7 +68,7 @@ sub set_overdue_item_lost : Test( 13 ) { is( keys %$issuingimpossible, 0, 'issuing is not impossible' ); is( keys %$needsconfirmation, 0, 'issuing needs no confirmation' ); - my $issue_due_date = C4::Circulation::AddIssue( $borrower, $item->{'barcode'}, $duedate ); + my $issue_due_date = C4::Circulation::AddIssue( $borrower, $item->{'itemnumber'}, $duedate ); ok( $issue_due_date, 'due date' ); is( $issue_due_date, $duedate, 'AddIssue returned the same date we passed to it' ); -- 1.7.5.4