From 2541e390bec8bd67dc6f8d866c4c7df42babaea0 Mon Sep 17 00:00:00 2001 From: "A. Sassmannshausen" Date: Fri, 4 Apr 2014 09:55:07 +0000 Subject: [PATCH] Bug 5670: Housebound Readers Module New module to handle management of circulation to Housebound readers. - Ability to record users as housebound (HB category), volunteers (combined deliverers and choosers, VOL category), deliverers (DELIV category) choosers (CHO category). - Ability to link users to individual delivery runs. - Ability to check on issuing to housebound users flagging if title has previously been issued to this user, to aid choosers. - 'Delivery Days' and 'Delivery Frequencies' are customizable through authorised values ('Day' and 'Frequency' categories respectively. Sponsored by Halton Borough Council * C4/Auth.pm: Add check: useHouseboundModule. * C4/Circulation.pm: use Housebound to check for previous issue. * koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc: add Housebound menu if appropriate. * koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt: add 'previous checkout' warning. * C4/Housebound.pm: new. * koha-tmpl/intranet-tmpl/prog/en/modules/members/housebound.tt: new. * koha-tmpl/intranet-tmpl/prog/en/modules/members/houseboundedit.tt: new. * koha-tmpl/intranet-tmpl/prog/en/modules/members/houseboundinstances.tt: new. * members/housebound.pl: new. * members/houseboundedit.pl: new. * members/houseboundinstances.pl: new. * installer/data/mysql/atomicupdate/housebound_tables.sql: new. - create 'housebound', 'housebound_instance' tables, - create 'HB', 'VOL', 'DELIV', 'CHO' borrower categories, - create sample 'Day', 'Frequency' authorised values, - add 'useHouseboundModule', 'useHouseboundCheckPrevious' syspref. * t/Housebound.t: new. Test plan: - Apply patch. - Run atomic update script. - Optionally, run Unit Tests (t/Housebound.t) - Create at least 1 of each: 'HB', 'VOL', 'DELIV', 'CHO' borrower. - Optionally, add additional authorised values of 'Day' and 'Frequency' categories. - Verify 'useHouseboundModule' & 'useHouseboundCheckPrevious' sysprefs are on. - On the page of the 'HB' borrower, open the new 'Housebound' menu. - create housebound profile + ensure Day and Frequency values are from correct authorised values - create 'housebound instances' (deliveries) + ensure chooser/deliverer lists are populated with VOL, DELIV, CHO borrowers - edit the profile/instances. - delete the profile/instances. - For a borrower with a housebound profile, issue an item, then - return that item - attempt to re-issue that item (you should get a warning) - Switch off 'useHouseboundCheckPrevious', repeat last test - the warning should not appear - Switch off 'useHouseboundModule' - the Housebound menu should disappear - the issue warnings should no longer appear. Largely based on prior work from Mark Gavillet and Colin Campbell. --- C4/Auth.pm | 1 + C4/Circulation.pm | 12 + C4/Housebound.pm | 377 ++++++++++++++++++++ .../data/mysql/atomicupdate/housebound_tables.sql | 41 +++ .../intranet-tmpl/prog/en/includes/circ-menu.inc | 3 + .../prog/en/modules/circ/circulation.tt | 4 + .../prog/en/modules/members/housebound.tt | 69 ++++ .../prog/en/modules/members/houseboundedit.tt | 102 ++++++ .../prog/en/modules/members/houseboundinstances.tt | 133 +++++++ members/housebound.pl | 91 +++++ members/houseboundedit.pl | 114 ++++++ members/houseboundinstances.pl | 138 +++++++ t/Housebound.t | 292 +++++++++++++++ 13 files changed, 1377 insertions(+) create mode 100644 C4/Housebound.pm create mode 100644 installer/data/mysql/atomicupdate/housebound_tables.sql create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/members/housebound.tt create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/members/houseboundedit.tt create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/members/houseboundinstances.tt create mode 100755 members/housebound.pl create mode 100755 members/houseboundedit.pl create mode 100755 members/houseboundinstances.pl create mode 100755 t/Housebound.t diff --git a/C4/Auth.pm b/C4/Auth.pm index 44edf67..d47ee0f 100644 --- a/C4/Auth.pm +++ b/C4/Auth.pm @@ -328,6 +328,7 @@ sub get_template_and_user { ); if ( $in->{'type'} eq "intranet" ) { $template->param( + useHouseboundModule => C4::Context->preference("useHouseboundModule"), AmazonCoverImages => C4::Context->preference("AmazonCoverImages"), AutoLocation => C4::Context->preference("AutoLocation"), "BiblioDefaultView".C4::Context->preference("IntranetBiblioDefaultView") => 1, diff --git a/C4/Circulation.pm b/C4/Circulation.pm index f8b204a..2ad74d8 100644 --- a/C4/Circulation.pm +++ b/C4/Circulation.pm @@ -58,6 +58,8 @@ use Date::Calc qw( Day_of_Week Add_Delta_Days ); +use C4::Housebound qw( CheckPrevIssue ); + use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); BEGIN { @@ -840,6 +842,16 @@ sub CanBookBeIssued { } } + # If Housebound patron and useHouseboundCheckPrev syspref is ON + # check for previous issue of item to patron. + if ( C4::Context->preference('useHouseboundCheckPrevious') == 1 + && $borrower->{categorycode} eq 'HB' ) + { + $needsconfirmation{HOUSEBOUNDPREVISSUE} = 1 + if CheckPrevIssue( $borrower->{borrowernumber}, + $item->{biblionumber} ); + } + # # ITEM CHECKING # diff --git a/C4/Housebound.pm b/C4/Housebound.pm new file mode 100644 index 0000000..879334b --- /dev/null +++ b/C4/Housebound.pm @@ -0,0 +1,377 @@ +package C4::Housebound; + +# Copyright 2011 Mark Gavillet +# Copyright 2014 PTFS-Europe Ltd +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; +use C4::Context; +use base qw(Exporter); + +our $VERSION = 3.02; +our @EXPORT_OK = qw( + GetHouseboundDetails + CreateHouseboundDetails + UpdateHouseboundDetails + GetCurrentHouseboundInstanceList + GetHouseboundInstanceDetails + UpdateHouseboundInstanceDetails + CreateHouseboundInstanceDetails + DeleteHouseboundInstanceDetails + GetVolunteerNameAndID + GetVolunteerList + GetChooserList + GetDelivererList + CheckPrevIssue +); + +=head1 NAME + +C4::Housebound - Koha housebound patrons module. + +=head1 SYNOPSIS + +use C4::Housebound; + +=head1 DESCRIPTION + +This module contains routines for adding, modifying and deleting +housebound details for patrons, and instances of item delivery by +volunteers. + +=head1 FUNCTIONS + +=head2 GetHouseboundDetails + + $housebound = GetHouseboundDetails( $borrowernumber ); + +Return a hashref containing the housebound table's row associated with +$BORROWERNUMBER or undef. + +=cut + +sub GetHouseboundDetails { + my ($borrowernumber) = @_; + if ($borrowernumber) { + my $dbh = C4::Context->dbh; + return $dbh->selectrow_hashref( + 'select * from housebound where borrowernumber=?', + {}, $borrowernumber ); + } + return; +} + +=head2 CreateHouseboundDetails + + CreateHouseboundDetails( $borrowernumber, $day, $frequency, + $Itype_quant, $Item_subject, $Item_authors, + $referral, $notes ); + +Create a new entry in the housebound table containing our arguments. +The return value is undef. + +=cut + +sub CreateHouseboundDetails { + my ( $borrowernumber, $day, $frequency, $Itype_quant, $Item_subject, + $Item_authors, $referral, $notes ) + = @_; + if ($borrowernumber) { + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare( +'insert into housebound (day, frequency, borrowernumber, Itype_quant, Item_subject, Item_authors, referral, notes) values (?,?,?,?,?,?,?,?)' + ); + $sth->execute( $day, $frequency, $borrowernumber, $Itype_quant, + $Item_subject, $Item_authors, $referral, $notes ); + } + return; +} + +=head2 UpdateHouseboundDetails + + UpdateHouseboundDetails( $hbnumber, $borrowernumber, $day, + $frequency, $Itype_quant, $Item_subject, + $Item_authors, $referral, $notes ); + +Update housebound table's row matching $hbnumber with our arguments. +The return value is undef. + +=cut + +sub UpdateHouseboundDetails { + my ( + $hbnumber, $borrowernumber, $day, + $frequency, $Itype_quant, $Item_subject, + $Item_authors, $referral, $notes + ) = @_; + if ($hbnumber) { + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare( +'update housebound set day=?,frequency=?,borrowernumber=?,Itype_quant=?,Item_subject=?,Item_authors=?,referral=?,notes=? where hbnumber=?' + ); + $sth->execute( + $day, $frequency, $borrowernumber, + $Itype_quant, $Item_subject, $Item_authors, + $referral, $notes, $hbnumber + ); + } + return; +} + +=head2 GetCurrentHouseboundInstanceList + + $hb_instances = GetCurrentHouseboundInstanceList( $borrowernumber ); + +Return an arrayref containing all Housebound_Instances associated with +$BORROWERNUMBER, or undef. + +=cut + +sub GetCurrentHouseboundInstanceList { + my ($borrowernumber) = @_; + if ($borrowernumber) { + my $dbh = C4::Context->dbh; + my $sql =<<'END_SQL'; +SELECT housebound_instance . * , concat( volunteer.firstname, ' ', volunteer.surname ) AS vol, + concat(chooser.firstname, ' ', chooser.surname) as cho, + concat(deliverer.firstname, ' ', deliverer.surname) as del + FROM housebound_instance + left JOIN borrowers volunteer ON volunteer.borrowernumber = housebound_instance.volunteer + left join borrowers chooser on chooser.borrowernumber = housebound_instance.chooser + left join borrowers deliverer on deliverer.borrowernumber = housebound_instance.deliverer + where housebound_instance.borrowernumber=? + order by housebound_instance.dmy desc +END_SQL + return $dbh->selectall_arrayref( $sql, { Slice => {} }, + $borrowernumber ); + } + return; +} + +=head2 GetVolunteerNameAndID + + $volunteer = GetVolunteerNameAndID( $borrowernumber ); + +Return a hashref containing details of the volunteer identified by +$BORROWERNUMBER, or undef. + +=cut + +sub GetVolunteerNameAndID { + my ($borrowernumber) = @_; + if ($borrowernumber) { + my $dbh = C4::Context->dbh; + return $dbh->selectrow_hashref( +'select borrowernumber,title,firstname,surname from borrowers where borrowernumber=?', + {}, $borrowernumber + ); + } + return; +} + +=head2 GetVolunteerList + + $volunteers = GetVolunteerList(); + +Return an arrayref containing borrowernumbers and names of all known +volunteers, or undef. + +=cut + +sub GetVolunteerList { + return GetHouseboundList("VOL"); +} + +=head2 GetDelivererList + + $deliverers = GetDelivererList(); + +Return an arrayref containing borrowernumbers and names of all known +deliverers, or undef. + +=cut + +sub GetDelivererList { + return GetHouseboundList("DELIV"); +} + +=head2 GetChooserList + + $choosers = GetChooserList(); + +Return an arrayref containing borrowernumbers and names of all known +choosers, or undef. + +=cut + +sub GetChooserList { + return GetHouseboundList("CHO"); +} + +=head2 GetHouseboundList + + $patrons = GetHouseboundList( $brw_cat_code ); + +Return an arrayref containing borrowernumbers and names of all +borrowers with $BRW_CAT_CODE, or undef. + +=cut + +sub GetHouseboundList { + my ( $cat_code ) = @_; + my $dbh = C4::Context->dbh; + my $sql = "SELECT borrowernumber as volbornumber, + concat(title, ' ', firstname, ' ', surname) as fullname + from borrowers where categorycode=? + order by surname, firstname asc"; + return $dbh->selectall_arrayref( $sql, { Slice => {} }, $cat_code ); +} + +=head2 GetHouseboundInstanceDetails + + $housebound = GetHouseboundInstanceDetails( $instance_id ); + +Return a hashref containing all details of the housebound_instance +associated with $INSTANCE_ID or undef. + +=cut + +sub GetHouseboundInstanceDetails { + my ($instanceid) = @_; + if ($instanceid) { + my $dbh = C4::Context->dbh; + return $dbh->selectrow_hashref( + 'SELECT * from housebound_instance where instanceid=?', + {}, $instanceid ); + } + return; +} + +=head2 UpdateHouseboundInstanceDetails + + UpdateHouseboundInstanceDetails( $instanceid, $hbnumber, $dmy, + $time, $borrowernumber, $volunteer, + $chooser, $deliverer ); + +Update housebound_instance table's row matching $instanceid with our +arguments. The return value is undef. + +=cut + +sub UpdateHouseboundInstanceDetails { + my ( $instanceid, $hbnumber, $dmy, $time, $borrowernumber, $volunteer, + $chooser, $deliverer ) + = @_; + if ($hbnumber) { + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare( +'update housebound_instance set hbnumber=?, dmy=?, time=?, borrowernumber=?, volunteer=?, chooser=?, deliverer=? where instanceid=?' + ); + $sth->execute( $hbnumber, $dmy, $time, $borrowernumber, $volunteer, + $chooser, $deliverer, $instanceid ); + } + return; +} + +=head2 CreateHouseboundInstanceDetails + + CreateHouseboundInstanceDetails( $hbnumber, $dmy, $time, + $borrowernumber, $volunteer, + $chooser, $deliverer ); + +Create a new housebound_instance table row containing our +arguments. The return value is undef. + +=cut + +sub CreateHouseboundInstanceDetails { + my ( $hbnumber, $dmy, $time, $borrowernumber, $volunteer, $chooser, + $deliverer ) + = @_; + if ($borrowernumber) { + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare( +'insert into housebound_instance (hbnumber, dmy, time, borrowernumber, volunteer, chooser, deliverer) values (?,?,?,?,?,?,?)' + ); + $sth->execute( $hbnumber, $dmy, $time, $borrowernumber, $volunteer, + $chooser, $deliverer ); + } + return; +} + +=head2 DeleteHouseboundInstanceDetails + + DeleteHouseboundInstanceDetails( $instanceid ); + +Delete the row from housebound_instance identified by +$INSTANCEID. The return value is undef. + +=cut + +sub DeleteHouseboundInstanceDetails { + my ($instanceid) = @_; + if ($instanceid) { + my $dbh = C4::Context->dbh; + my $sth = + $dbh->prepare('delete from housebound_instance where instanceid=?'); + $sth->execute($instanceid); + } + return; +} + +=head2 CheckPrevIssue + + CheckPrevIssue( $borrowernumber, $biblionumber ); + +Return 1 if $BIBLIONUMBER has previously been issued to +$BORROWERNUMBER, 0 otherwise. + +=cut + +sub CheckPrevIssue { + my ( $borrowernumber, $biblionumber ) = @_; + my $dbh = C4::Context->dbh; + my $previssue = 0; + my $sth = + $dbh->prepare('select itemnumber from items where biblionumber=?'); + $sth->execute($biblionumber); + + my $query = $dbh->prepare( +'select count(itemnumber) from old_issues where borrowernumber=? and itemnumber=?' + ); + while ( my @row = $sth->fetchrow_array() ) { + $query->execute( $borrowernumber, $row[0] ); + while ( my @matches = $query->fetchrow_array() ) { + if ( $matches[0] > 0 ) { + $previssue = 1; + } + } + } + return $previssue; +} + +1; + +__END__ + +=head1 AUTHOR + +Mark Gavillet +Alex Sassmannshausen + +=cut diff --git a/installer/data/mysql/atomicupdate/housebound_tables.sql b/installer/data/mysql/atomicupdate/housebound_tables.sql new file mode 100644 index 0000000..ee509f8 --- /dev/null +++ b/installer/data/mysql/atomicupdate/housebound_tables.sql @@ -0,0 +1,41 @@ +CREATE TABLE IF NOT EXISTS `housebound` ( + `hbnumber` int(11) NOT NULL auto_increment, + `day` text NOT NULL, + `frequency` text, + `borrowernumber` int(11) default NULL, + `Itype_quant` varchar(10) default NULL, + `Item_subject` text, + `Item_authors` text, + `referral` text, + `notes` text, + PRIMARY KEY (`hbnumber`), + KEY `borrowernumber` (`borrowernumber`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ; + + + +CREATE TABLE IF NOT EXISTS `housebound_instance` ( + `instanceid` int(11) NOT NULL auto_increment, + `hbnumber` int(11) NOT NULL, + `dmy` date default NULL, + `time` text, + `borrowernumber` int(11) NOT NULL, + `volunteer` int(11) default NULL, + `chooser` int(11) default NULL, + `deliverer` int(11) default NULL, + PRIMARY KEY (`instanceid`), + KEY `hbnumber` (`hbnumber`,`borrowernumber`,`volunteer`,`chooser`,`deliverer`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ; + +insert into systempreferences (variable,value,options,explanation,type) values +('useHouseboundModule',1,'','If ON, use the Housebound module','YesNo'); + +insert into systempreferences (variable,value,options,explanation,type) values +('useHouseboundCheckPrevious',1,'','If ON, checks if Housebound patrons have previous issued items to be checked out', +'YesNo'); + +insert into categories (categorycode, description, enrolmentperiod, upperagelimit, dateofbirthrequired, category_type) +values ('VOL','Housebound volunteer','99','999','1','A'),('HB','Housebound patron','99','999','1','A'),('DELIV','Housebound deliverer','99','999','1','A'),('CHO','Housebound chooser','99','999','1','A'); + +insert into authorised_values (category, authorised_value, lib) +values ('Day','Example_Day','Change Me In Authorised Values (Day)'), ('Frequency','Example_Freq','Change Me In Authorised Values (Frequency)'); diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc index 6162293..8331639 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc @@ -76,6 +76,9 @@ [% IF ( CAN_user_parameters ) %] [% IF ( logview ) %]
  • [% ELSE %]
  • [% END %]Modification log
  • [% END %] + [% IF useHouseboundModule %] + [% IF houseboundview %]
  • [% ELSE %]
  • [% END %]Housebound
  • + [% END %] [% IF ( EnhancedMessagingPreferences ) %] [% IF ( sentnotices ) %]
  • [% ELSE %]
  • [% END %]Notices
  • [% END %] 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 7c611dd..293aa6b 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt @@ -273,6 +273,10 @@ var MSG_EXPORT_SELECT_CHECKOUTS = _("You must select checkout(s) to export"); [% IF HIGHHOLDS %]
  • High demand item. Loan period shortened to [% HIGHHOLDS.duration %] days (due [% HIGHHOLDS.returndate %]). Check out anyway?
  • [% END %] + +[% IF HOUSEBOUNDPREVISSUE %] +
  • Housebound patron has previously issued this item. Check out anyway?
  • +[% END %] [% IF HIGHHOLDS %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/housebound.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/housebound.tt new file mode 100644 index 0000000..4311668 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/housebound.tt @@ -0,0 +1,69 @@ +[% USE AuthorisedValues %] +[% INCLUDE 'doc-head-open.inc' %] +Koha Housebound - [% surname %], [% firstname %] +[% INCLUDE 'doc-head-close.inc' %] + + + +[% INCLUDE 'header.inc' %] +[% INCLUDE 'patron-search.inc' %] + + + +
    +
    +
    +
    Housebound details for [% title %] [% firstname %] [% surname %] [% IF ( cardnumber ) %]([% cardnumber %])[% END %] + [% IF ( housebound.hbnumber ) %] + +
    +
      +
    1. + Delivery day: + [% AuthorisedValues.GetByCode( 'day', housebound.day, 0 ) + || housebound.day %] +
    2. +
    3. + Frequency: + [% AuthorisedValues.GetByCode( 'frequency', housebound.frequency, 0 ) + || housebound.frequency %] +
    4. +
    5. Material:[% housebound.Itype_quant %]
    6. +
    7. Subjects:[% housebound.Item_subject %]
    8. +
    9. Authors:[% housebound.Item_authors %]
    10. +
    11. Referral:[% housebound.referral %]
    12. +
    13. Notes:[% housebound.notes %]
    14. +
    +
    +
    +

    Deliveries

    + + + + + + + [% FOREACH instance IN instanceloop %] + + + + + + + + + [% END %] +
    IDDateVolunteerChooserDelivererActions
    [% instance.instanceid %][% instance.dmy %] ([% instance.time %])[% instance.vol %][% instance.cho %][% instance.del %]Edit | Delete
    +
    + [% ELSE %] +

    This patron does not currently have registered housebound details. To add these details click here.

    + [% END %] +
    +
    +
    + [% INCLUDE 'circ-menu.inc' %] +
    +
    +
    +[% INCLUDE 'intranet-bottom.inc' %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/houseboundedit.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/houseboundedit.tt new file mode 100644 index 0000000..3668fac --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/houseboundedit.tt @@ -0,0 +1,102 @@ +[% INCLUDE 'doc-head-open.inc' %] +Koha Housebound - [% surname %], [% firstname %] +[% INCLUDE 'doc-head-close.inc' %] + + + + [% INCLUDE 'header.inc' %] + [% INCLUDE 'patron-search.inc' %] + + + +
    +
    +
    +
    +

    Edit housebound details for [% title %] [% firstname %] [% surname %] [% IF ( cardnumber ) %]([% cardnumber %])[% END %]

    + +
    + + + +
    + Housebound details +
      +
    1. + + +
    2. +
    3. + + +
    4. +
    5. + + +
    6. +
    7. + + +
    8. +
    9. + + +
    10. +
    11. + + +
    12. +
    13. + + +
    14. +
    +
    +
    + + Cancel +
    +
    +
    +
    +
    + [% INCLUDE 'circ-menu.inc' %] +
    +
    +
    + [% INCLUDE 'intranet-bottom.inc' %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/houseboundinstances.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/houseboundinstances.tt new file mode 100644 index 0000000..460ef5c --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/houseboundinstances.tt @@ -0,0 +1,133 @@ +[% USE KohaDates %] +[% INCLUDE 'doc-head-open.inc' %] +Koha Housebound - [% surname %], [% firstname %] +[% INCLUDE 'doc-head-close.inc' %] +[% INCLUDE 'calendar.inc' %] + + + + [% INCLUDE 'header.inc' %] + [% INCLUDE 'patron-search.inc' %] + + +
    +
    +
    +
    +

    Housebound deliveries for [% title %] [% firstname %] [% surname %] [% IF ( cardnumber ) %]([% cardnumber %])[% END %]

    +
    + + + + + [% IF ( opdel ) %] +

    Are you sure you want to delete this delivery?

    +

      

    + [% ELSE %] +
    + Delivery details +
      +
    1. + + +
    2. +
    3. + + +
    4. +
    5. + + +
    6. +
    7. + + +
    8. +
    9. + + +
    10. +
    +
    +
    + + Cancel +
    + [% END %] +
    +
    +
    +
    + [% INCLUDE 'circ-menu.inc' %] +
    +
    +
    + [% INCLUDE 'intranet-bottom.inc' %] diff --git a/members/housebound.pl b/members/housebound.pl new file mode 100755 index 0000000..2b1bccb --- /dev/null +++ b/members/housebound.pl @@ -0,0 +1,91 @@ +#!/usr/bin/perl + +# Copyright 2011 Mark Gavillet +# Copyright 2014 PTFS-Europe Ltd +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; +use CGI; +use C4::Context; +use C4::Auth; +use C4::Output; +use C4::Members; +use C4::Koha; +use C4::Branch; +use C4::Housebound qw( GetHouseboundDetails + GetCurrentHouseboundInstanceList ); + +my $input = CGI->new(); + +sub nl2br { + my ($t) = shift or return; + $t =~ s/\n/\n
    /g; + return ($t); +} + +my $dbh = C4::Context->dbh; + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { + template_name => 'members/housebound.tmpl', + query => $input, + type => 'intranet', + authnotrequired => 0, + flagsrequired => { borrowers => 1 }, + debug => $ENV{DEBUG}, + } +); + +my $borrowernumber = $input->param('borrowernumber'); + +my $borrowerdetails = C4::Members::GetMemberDetails($borrowernumber); +my $branchdetail = GetBranchDetail( $borrowerdetails->{branchcode} ); +my $categorydetail = GetMember( borrowernumber => $borrowernumber); +my $housebound = GetHouseboundDetails($borrowernumber); +my $housebound_instances = GetCurrentHouseboundInstanceList($borrowernumber); + +$template->param( + surname => $borrowerdetails->{surname}, + firstname => $borrowerdetails->{firstname}, + cardnumber => $borrowerdetails->{cardnumber}, + borrowernumber => $borrowerdetails->{borrowernumber}, + houseboundview => 'on', + address => $borrowerdetails->{address}, + address2 => $borrowerdetails->{address2}, + city => $borrowerdetails->{city}, + phone => $borrowerdetails->{phone}, + phonepro => $borrowerdetails->{phonepro}, + mobile => $borrowerdetails->{mobile}, + email => $borrowerdetails->{email}, + emailpro => $borrowerdetails->{emailpro}, + categoryname => $categorydetail->{description}, + categorycode => $borrowerdetails->{categorycode}, + branch => $borrowerdetails->{branch}, + branchname => $branchdetail->{branchname}, + zipcode => $borrowerdetails->{zipcode} +); + +$template->param( + housebound => $housebound +); + +if ($housebound_instances) { + $template->param( instanceloop => $housebound_instances ); +} + +output_html_with_http_headers $input, $cookie, $template->output; diff --git a/members/houseboundedit.pl b/members/houseboundedit.pl new file mode 100755 index 0000000..ced3cfb --- /dev/null +++ b/members/houseboundedit.pl @@ -0,0 +1,114 @@ +#!/usr/bin/perl + +# Copyright 2011 Mark Gavillet +# Copyright 2014 PTFS-Europe Ltd +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; +use CGI; +use C4::Context; +use C4::Auth; +use C4::Output; +use C4::Members; +use C4::Koha; +use C4::Branch; +use C4::Housebound qw( GetHouseboundDetails + UpdateHouseboundDetails + CreateHouseboundDetails ); + +my $input = CGI->new(); + +my $dbh = C4::Context->dbh; + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { + template_name => 'members/houseboundedit.tmpl', + query => $input, + type => 'intranet', + authnotrequired => 0, + flagsrequired => { borrowers => 1 }, + debug => $ENV{DEBUG}, + } +); + +my $borrowernumber = $input->param('borrowernumber'); +my $op = $input->param('op'); +if ( $op eq 'editsubmit' ) { + UpdateHouseboundDetails( + $input->param('hbnumber'), $input->param('borrowernumber'), + $input->param('day'), $input->param('frequency'), + $input->param('Itype_quant'), $input->param('Item_subject'), + $input->param('Item_authors'), $input->param('referral'), + $input->param('notes') + ); + my $url = + "/cgi-bin/koha/members/housebound.pl?borrowernumber=$borrowernumber"; + print "Location: $url"; +} +if ( $op eq 'addsubmit' ) { + CreateHouseboundDetails( + $input->param('borrowernumber'), $input->param('day'), + $input->param('frequency'), $input->param('Itype_quant'), + $input->param('Item_subject'), $input->param('Item_authors'), + $input->param('referral'), $input->param('notes') + ); + my $url = + "/cgi-bin/koha/members/housebound.pl?borrowernumber=$borrowernumber"; + print "Location: $url"; +} +if ( $op eq 'edit' ) { + $template->param( opeditsubmit => 'editsubmit' ); +} +if ( $op eq 'add' ) { + $template->param( opaddsubmit => 'addsubmit' ); +} + +my $borrowerdetails = C4::Members::GetMemberDetails($borrowernumber); +my $branchdetail = GetBranchDetail( $borrowerdetails->{branchcode} ); +my $categorydetail = GetMember( borrowernumber => $borrowernumber ); +my $housebound = GetHouseboundDetails($borrowernumber); + + +$template->param( + surname => $borrowerdetails->{surname}, + firstname => $borrowerdetails->{firstname}, + cardnumber => $borrowerdetails->{cardnumber}, + borrowernumber => $borrowerdetails->{borrowernumber}, + address => $borrowerdetails->{address}, + address2 => $borrowerdetails->{address2}, + city => $borrowerdetails->{city}, + phone => $borrowerdetails->{phone}, + phonepro => $borrowerdetails->{phonepro}, + mobile => $borrowerdetails->{mobile}, + email => $borrowerdetails->{email}, + emailpro => $borrowerdetails->{emailpro}, + categoryname => $categorydetail->{description}, + categorycode => $borrowerdetails->{categorycode}, + branch => $borrowerdetails->{branch}, + branchname => $branchdetail->{branchname}, + zipcode => $borrowerdetails->{zipcode} +); + +$template->param( + housebound => $housebound, + houseboundview => 'on', + days => GetAuthorisedValues('day'), + frequencies => GetAuthorisedValues('frequency'), +); + +output_html_with_http_headers $input, $cookie, $template->output; diff --git a/members/houseboundinstances.pl b/members/houseboundinstances.pl new file mode 100755 index 0000000..ec64e8f --- /dev/null +++ b/members/houseboundinstances.pl @@ -0,0 +1,138 @@ +#!/usr/bin/perl + +# Copyright 2011 Mark Gavillet +# Copyright 2014 PTFS-Europe Ltd +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; +use CGI; +use C4::Context; +use C4::Auth; +use C4::Output; +use C4::Members; +use C4::Koha; +use C4::Branch; +use C4::Dates; +use C4::Housebound qw( GetHouseboundDetails + GetHouseboundInstanceDetails + CreateHouseboundInstanceDetails + DeleteHouseboundInstanceDetails + UpdateHouseboundInstanceDetails + GetVolunteerList GetChooserList + GetDelivererList ); + +my $input = CGI->new(); + +my $dbh = C4::Context->dbh; + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { + template_name => 'members/houseboundinstances.tmpl', + query => $input, + type => 'intranet', + authnotrequired => 0, + flagsrequired => { borrowers => 1 }, + debug => $ENV{DEBUG}, + } +); + +my $borrowernumber = $input->param('borrowernumber'); + +my $op = $input->param('op'); +if ( $op eq 'add' ) { + $template->param( opadd => 1, op => 'addsubmit' ); +} +if ( $op eq 'edit' ) { + $template->param( opedit => 1, op => 'editsubmit' ); +} +if ( $op eq 'del' ) { + $template->param( opdel => 1, op => 'delsubmit' ); +} +if ( $op eq 'addsubmit' ) { + CreateHouseboundInstanceDetails( + $input->param('hbnumber'), $input->param('dmy'), + $input->param('time'), $input->param('borrowernumber'), + $input->param('volunteer'), $input->param('chooser'), + $input->param('deliverer') + ); + my $url = + "/cgi-bin/koha/members/housebound.pl?borrowernumber=$borrowernumber"; + print "Location: $url"; +} +if ( $op eq 'delsubmit' ) { + DeleteHouseboundInstanceDetails( $input->param('instanceid') ); + my $url = + "/cgi-bin/koha/members/housebound.pl?borrowernumber=$borrowernumber"; + print "Location: $url"; +} +if ( $op eq 'editsubmit' ) { + UpdateHouseboundInstanceDetails( + $input->param('instanceid'), $input->param('hbnumber'), + $input->param('dmy'), $input->param('time'), + $input->param('borrowernumber'), $input->param('volunteer'), + $input->param('chooser'), $input->param('deliverer') + ); + my $url = + "/cgi-bin/koha/members/housebound.pl?borrowernumber=$borrowernumber"; + print "Location: $url"; +} + +my $borrowerdetails = C4::Members::GetMemberDetails($borrowernumber); +my $branchdetail = GetBranchDetail( $borrowerdetails->{branchcode} ); +my $categorydetail = GetMember( $borrowernumber, 'borrowernumber' ); +my $housebound = GetHouseboundDetails($borrowernumber); +my $volunteerlist = GetVolunteerList(); +my $chooserlist = GetChooserList(); +my $delivererlist = GetDelivererList(); +my $delinstanceid = $input->param('instanceid'); +my $instanceid = $input->param('instanceid'); +my $instancedetails = GetHouseboundInstanceDetails($instanceid); + +$template->param( + surname => $borrowerdetails->{surname}, + firstname => $borrowerdetails->{firstname}, + cardnumber => $borrowerdetails->{cardnumber}, + borrowernumber => $borrowerdetails->{borrowernumber}, + address => $borrowerdetails->{address}, + address2 => $borrowerdetails->{address2}, + city => $borrowerdetails->{city}, + phone => $borrowerdetails->{phone}, + phonepro => $borrowerdetails->{phonepro}, + mobile => $borrowerdetails->{mobile}, + email => $borrowerdetails->{email}, + emailpro => $borrowerdetails->{emailpro}, + categoryname => $categorydetail->{description}, + categorycode => $borrowerdetails->{categorycode}, + branch => $borrowerdetails->{branch}, + branchname => $branchdetail->{branchname}, + zipcode => $borrowerdetails->{zipcode} +); + +$template->param( + houseboundview => 'on', + housebound => $housebound, + DHTMLcalendar_dateformat => C4::Dates->DHTMLcalendar(), + volunteerlist => $volunteerlist, + chooserlist => $chooserlist, + delivererlist => $delivererlist, + delinstanceid => $delinstanceid, + instanceid => $instanceid, + instance => $instancedetails, +); + +output_html_with_http_headers $input, $cookie, $template->output; diff --git a/t/Housebound.t b/t/Housebound.t new file mode 100755 index 0000000..afbd98e --- /dev/null +++ b/t/Housebound.t @@ -0,0 +1,292 @@ +#!/usr/bin/perl +use strict; +use warnings; + +use C4::Context; +use Test::More tests => 29; +use Test::MockModule; +use DBD::Mock; + +use_ok('C4::Housebound'); + +use C4::Housebound qw( GetHouseboundDetails CreateHouseboundDetails + UpdateHouseboundDetails + GetCurrentHouseboundInstanceList + GetHouseboundInstanceDetails + UpdateHouseboundInstanceDetails + CreateHouseboundInstanceDetails + DeleteHouseboundInstanceDetails + GetVolunteerNameAndID GetVolunteerList + GetChooserList GetDelivererList CheckPrevIssue + ); + +# Setup mock db +my $module_context = new Test::MockModule('C4::Context'); +$module_context->mock( + '_new_dbh', + sub { + my $dbh = DBI->connect( 'DBI:Mock:', '', '' ) + || die "Cannot create handle: $DBI::errstr\n"; + return $dbh; + } +); + +my $dbh = C4::Context->dbh(); + +# convenience variables +my $name; +# mock_add_resultset vars +my ( $sql, $sql2, @bound_params, @keys, @values, %result ) = ( ); +# mock_history_verification vars +my ( $history, $params, $query ) = ( ); + +sub clean_vars { + ( $name, $sql, $sql2, @bound_params, @keys, @values, %result, + $history, $params, $query ) = ( ); + $dbh->{mock_clear_history} = 1; +} + +# Tests +## GetHouseboundDetails +$name = 'GetHouseboundDetails'; +$sql = 'select * from housebound where borrowernumber=?'; +@bound_params = ( 101 ); +@keys = qw< hbnumber day frequency borrowernumber Itype_quant + Item_subject Item_authors referral notes >; +@values = qw< 5 Monday Week-2/4 101 books dvd thrillers cooke + alex none >; +foreach my $i ( 0 .. $#keys) { + $result{$keys[$i]} = $values[$i]; +} + +is( GetHouseboundDetails('unknown'), undef, + $name . ': Return value "undefined".' ); + +$dbh->{mock_add_resultset} = + { + sql => $sql, + bound_params => [ @bound_params ], + results => [ [ @keys ], [ @values ] ], + }; + +is_deeply( GetHouseboundDetails($bound_params[0]), \%result, + $name . ': Return value "$result".' ); + +clean_vars(); + +## CreateHouseboundDetails +$name = 'CreateHouseboundDetails'; +$sql = 'insert into housebound' + . ' (day, frequency, borrowernumber, Itype_quant, Item_subject,' + . ' Item_authors, referral, notes) values (?,?,?,?,?,?,?,?)'; +@keys = qw< day frequency borrowernumber Itype_quant Item_subject + Item_authors referral notes >; +@values = qw< Tuesday Week-3/4 103 journals psychology sam bob $name >; + +is( CreateHouseboundDetails($values[2], $values[0], $values[1], $values[3], + $values[4], $values[5], $values[6], $values[7]), + undef, $name . ': Return value "undefined".'); + +$history = $dbh->{mock_all_history}; +$query = $history->[0]; +$params = $query->bound_params; + +is($query->statement, $sql, $name . ': Correct statement generated' ); +is(scalar(@{$params}), scalar(@values), + $name . ': Correct number of parameters bound.' ); +is_deeply( $params, \@values, + $name . ': Correct parameter values passed.' ); + +clean_vars(); + +## UpdateHouseboundDetails +$name = 'UpdateHouseboundDetails'; +$sql = 'update housebound set day=?,frequency=?,borrowernumber=?,' + . 'Itype_quant=?,Item_subject=?,Item_authors=?,referral=?,notes=?' + . ' where hbnumber=?', +@keys = qw< day frequency borrowernumber Itype_quant Item_subject + Item_authors referral notes hbnumber>; +@values = qw< Tuesday Week-3/4 103 journals psychology sam bob $name 1>; +is( UpdateHouseboundDetails( $values[8], $values[2], $values[0], $values[1], + $values[3], $values[4], $values[5], $values[6], + $values[7] ), + undef, $name . ': Return value "undefined".'); + +$history = $dbh->{mock_all_history}; +$query = $history->[0]; +$params = $query->bound_params; + +is($query->statement, $sql, $name . ': Correct statement generated' ); +is(scalar(@{$params}), scalar(@values), + $name . ': Correct number of parameters bound.'); +is_deeply( $params, \@values, + $name . ': Correct parameter values passed.'); + +clean_vars(); + +## GetCurrentHouseboundInstanceList +### GetcurrentHouseboundInstanceList's Slice causes +### mock dbd to fail +### Cannot test. + +## GetVolunteerNameAndID +$name = "GetVolunteerNameAndID"; +$sql = 'select borrowernumber,title,firstname,surname' + . ' from borrowers where borrowernumber=?'; +@bound_params = ( 101 ); +@keys = qw< borrowernumber title firstname surname >; +@values = qw< 101 Mr John Doe >; +foreach my $i ( 0 .. $#keys) { + $result{$keys[$i]} = $values[$i]; +} + +is( GetVolunteerNameAndID($bound_params[0]), undef, + $name . ': Return value "undefined".' ); + +$dbh->{mock_add_resultset} = + { + sql => $sql, + bound_params => [ @bound_params ], + results => [ [ @keys ], [ @values ] ], + }; + +is_deeply( GetVolunteerNameAndID($bound_params[0]), + \%result, $name . ': Return value "$result".' ); + +clean_vars(); + +## GetVolunteerList +### GetVolunteerList's Slice causes mock dbd to fail +### Cannot test. + +## GetHouseboundInstanceDetails +$name = 'GetHouseboundInstanceDetails'; +$sql = 'SELECT * from housebound_instance where instanceid=?'; +@bound_params = ( 1 ); +@keys = qw< instanceid hbnumber dmy time borrowernumber volunteer + chooser deliverer >; +@values = qw< 1 5 2014-03-31 am 101 102 103 104 >; +foreach my $i ( 0 .. $#keys) { + $result{$keys[$i]} = $values[$i]; +} + +is( GetHouseboundInstanceDetails('1'), undef, + $name . ': Return value "undefined".' ); + +$dbh->{mock_add_resultset} = + { + sql => $sql, + bound_params => [ @bound_params ], + results => [ [ @keys ], [ @values ] ], + }; + +is_deeply( GetHouseboundInstanceDetails('1'), \%result, + $name . ': Return value "$result".' ); + +clean_vars(); + +## UpdateHouseboundInstanceDetails +$name = "UpdateHouseboundInstanceDetails"; +$sql = 'update housebound_instance set hbnumber=?, dmy=?,' + . ' time=?, borrowernumber=?, volunteer=?, chooser=?, deliverer=?' + . ' where instanceid=?'; +@keys = qw< hbnumber dmy time borrowernumber volunteer chooser + deliverer instanceid >; +@values = qw< 5 2014-03-31 am 101 102 103 104 1 >; + +is( UpdateHouseboundInstanceDetails( $values[7], $values[0], $values[1], + $values[2], $values[3], $values[4], + $values[5], $values[6] ), undef, + $name . ': Return value "undefined".' ); + +$history = $dbh->{mock_all_history}; +$query = $history->[0]; +$params = $query->bound_params; + +is($query->statement, $sql, $name . ': Correct statement generated' ); +is(scalar(@{$params}), scalar(@values), + $name . ': Correct number of parameters bound.'); +is_deeply( $params, \@values, + $name . ': Correct parameter values passed.'); + +clean_vars(); + +## CreateHouseboundInstanceDetails +$name = "CreateHouseboundInstanceDetails"; +$sql = 'insert into housebound_instance' + . ' (hbnumber, dmy, time, borrowernumber, volunteer, chooser, deliverer)' + . ' values (?,?,?,?,?,?,?)'; +@keys = qw< hbnumber dmy time borrowernumber volunteer chooser + deliverer >; +@values = qw< 5 2014-03-31 am 101 102 103 104 >; + +is( CreateHouseboundInstanceDetails( @values ), undef, + $name . ': Return value "undefined".'); + +$history = $dbh->{mock_all_history}; +$query = $history->[0]; +$params = $query->bound_params; + +is($query->statement, $sql, $name . ': Correct statement generated' ); +is(scalar(@{$params}), scalar(@values), + $name . ': Correct number of parameters bound.' ); +is_deeply( $params, \@values, + $name . ': Correct parameter values passed.' ); + +$dbh->{mock_clear_history} = 1; + +## DeleteHouseboundInstanceDetails +$name = 'DeleteHouseboundInstanceDetails'; +$sql = 'delete from housebound_instance where instanceid=?'; +@keys = qw< instanceid >; +@values = qw< 1 >; + +is( DeleteHouseboundInstanceDetails( @values ), undef, + $name . ': Return value "undefined".'); + +$history = $dbh->{mock_all_history}; +$query = $history->[0]; +$params = $query->bound_params; + +is($query->statement, $sql, $name . ': Correct statement generated' ); +is(scalar(@{$params}), scalar(@values), + $name . ': Correct number of parameters bound.' ); +is_deeply( $params, \@values, + $name . ': Correct parameter values passed.' ); + +clean_vars(); + +## CheckPrevIssue +$name = 'CheckPrevIssue'; +$sql = 'select itemnumber from items where biblionumber=?'; +$sql2 = 'select count(itemnumber) from old_issues' + . ' where borrowernumber=? and itemnumber=?'; +@keys = qw< borrowernumber biblionumber itemnumber >; +@values = qw< 101 3576 5043 >; + +# 1) Prepop items with itemnumber for result +$dbh->{mock_add_resultset} = { + sql => $sql, + bound_params => $keys[1], + results => [ [ ( $keys[2] ) ], [ ( $values[2] ) ] ], + }; +# 2) Test if never issued before (expect 0) +is( CheckPrevIssue( $keys[0], $keys[1] ), 0, + $name . ': Return value "no matches".' ); +# 3) Prepop old_issues with itemnumber and borrowernumber +$dbh->{mock_add_resultset} = { + sql => $sql2, + bound_params => [ $keys[0], $keys[2] ], + results => [ + [ ( $keys[0], $keys[2] ) ], + [ ( $values[0], $values[2] ) ], + [ ( $values[0], $values[2] ) ], + [ ( $values[0], $values[2] ) ], + [ ( $values[0], $values[2] ) ], + ], + }; +# 4) Test if issued before (e.g. 7 times — expect 1) +is( CheckPrevIssue( $keys[0], $keys[1] ), 1, + $name . ': Return value "> 0 matches".' ); + +clean_vars(); -- 1.7.10.4