From 4c00eb47b1c55b943c5760a2acc43fc73b3896d6 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 create housebound profiles & scheduled visits for patrons. - Ability to record users as Deliverers or Choosers (or both), using extended patron attributes. - Ability to link choosers and deliverers to individual delivery runs. - 'Delivery Frequencies' are customizable through authorised values ('HSBND_FREQ'). * koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc: add Housebound menu if appropriate. * Koha/Patron.pm (housebound_profile): New method. * Koha/Patrons.pm (housebound_choosers, housebound_deliverers): New methods. * Koha/Patron/HouseboundProfile.pm: New File. * Koha/Patron/HouseboundProfiles.pm: New File. * Koha/Patron/HouseboundVisits.pm: New File. * Koha/Patron/HouseboundVisit.pm: New File. * koha-tmpl/intranet-tmpl/prog/en/modules/members/housebound.tt: New file. * members/housebound.pl: New file. * installer/data/mysql/kohastructure.sql: Add housebound_* tables. * installer/data/mysql/sysprefs.sql: Add HouseboundModule syspref. * koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref: Add HouseboundModule syspref. * installer/data/mysql/atomicupdate/housebound_tables.sql: New file. * t/db_dependent/Patron/Borrower_Housebound.t: New file. * t/db_dependent/Patron/Borrower_HouseboundProfiles.t: New file. * t/db_dependent/Patron/Borrower_HouseboundVisits.t: New file. Test plan: - Apply patch. - Run atomic update script. - Run Unit Tests (t/db_dependent/Patron/Housebound*) - Optionally, add additional authorised values to 'HSBND_FREQ'. - Switch on 'HouseboundModule' syspref. - Ensure 'ExtendedPatronAttributes syspref is on. - On patron pages, when editing, add some to the Housebound deliverer and chooser groups. - On a patron page, the Housebound menu should now be present. - create housebound profile + ensure Frequency values seem pulled from 'HSBND_FREQ'. - create 'housebound visits' (deliveries) + ensure chooser/deliverer lists are populated with patrons that have the Chooser or Deliverer Attribute type. - edit visits. - delete visits. - Switch off 'HouseboundModule' - the Housebound menu should disappear Signed-off-by: Chris Cormack Signed-off-by: Claire Gravely Bug 5670: [Followup] Rename test files. * t/db_dependent/Patron/Borrower_Housebound.t: Rename to t/db_dependent/Patron/Housebound.t. * t/db_dependent/Patron/Borrower_HouseboundProfiles.t: Rename to t/db_dependent/Patron/HouseboundProfiles.t. * t/db_dependent/Patron/Borrower_HouseboundVisits.t: Rename to t/db_dependent/Patron/HouseboundVisits.t. Signed-off-by: Claire Gravely Bug 5670: [QA Followup] Fix category_type ref. * koha-tmpl/intranet-tmpl/prog/en/modules/members/housebound.tt: Replace references to `category_type` with `categorycode`. Signed-off-by: Claire Gravely --- Koha/Patron.pm | 13 + Koha/Patron/HouseboundProfile.pm | 72 ++++ Koha/Patron/HouseboundProfiles.pm | 61 +++ Koha/Patron/HouseboundVisit.pm | 83 ++++ Koha/Patron/HouseboundVisits.pm | 102 +++++ Koha/Patrons.pm | 32 ++ .../data/mysql/atomicupdate/housebound_tables.sql | 52 +++ installer/data/mysql/en/mandatory/auth_values.sql | 4 + .../data/mysql/en/mandatory/patron_attributes.sql | 4 + .../data/mysql/en/mandatory/patron_attributes.txt | 2 + installer/data/mysql/kohastructure.sql | 48 +++ installer/data/mysql/sysprefs.sql | 1 + .../intranet-tmpl/prog/en/includes/circ-menu.inc | 3 + .../en/modules/admin/preferences/circulation.pref | 7 + .../prog/en/modules/members/housebound.tt | 434 +++++++++++++++++++++ members/housebound.pl | 150 +++++++ t/db_dependent/Patron/Housebound.t | 75 ++++ t/db_dependent/Patron/HouseboundProfiles.t | 75 ++++ t/db_dependent/Patron/HouseboundVisits.t | 92 +++++ 19 files changed, 1310 insertions(+) create mode 100644 Koha/Patron/HouseboundProfile.pm create mode 100644 Koha/Patron/HouseboundProfiles.pm create mode 100644 Koha/Patron/HouseboundVisit.pm create mode 100644 Koha/Patron/HouseboundVisits.pm create mode 100644 installer/data/mysql/atomicupdate/housebound_tables.sql create mode 100644 installer/data/mysql/en/mandatory/patron_attributes.sql create mode 100644 installer/data/mysql/en/mandatory/patron_attributes.txt create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/members/housebound.tt create mode 100755 members/housebound.pl create mode 100755 t/db_dependent/Patron/Housebound.t create mode 100644 t/db_dependent/Patron/HouseboundProfiles.t create mode 100644 t/db_dependent/Patron/HouseboundVisits.t diff --git a/Koha/Patron.pm b/Koha/Patron.pm index b5449a3..6ef5b92 100644 --- a/Koha/Patron.pm +++ b/Koha/Patron.pm @@ -29,6 +29,7 @@ use Koha::DateUtils; use Koha::Issues; use Koha::OldIssues; use Koha::Patron::Categories; +use Koha::Patron::HouseboundProfiles; use Koha::Patron::Images; use Koha::Patrons; @@ -76,6 +77,18 @@ sub guarantees { return Koha::Patrons->search( { guarantorid => $self->borrowernumber } ); } +=head3 housebound_profile + +Returns the HouseboundProfile associated with this patron. + +=cut + +sub housebound_profile { + my ( $self ) = @_; + + return Koha::Patron::HouseboundProfiles->find($self->borrowernumber); +} + =head3 siblings Returns the siblings of this patron. diff --git a/Koha/Patron/HouseboundProfile.pm b/Koha/Patron/HouseboundProfile.pm new file mode 100644 index 0000000..5ce87f8 --- /dev/null +++ b/Koha/Patron/HouseboundProfile.pm @@ -0,0 +1,72 @@ +package Koha::Patron::HouseboundProfile; + +# 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 Modern::Perl; + +use Koha::Database; +use Koha::Patron::HouseboundVisits; + +use base qw(Koha::Object); + +=head1 NAME + +Koha::Patron::HouseboundProfile - Koha Patron HouseboundProfile Object class + +=head1 SYNOPSIS + +HouseboundProfile class used primarily by members/housebound.pl. + +=head1 DESCRIPTION + +Standard Koha::Objects definitions, and additional methods. + +=head1 API + +=head2 Class Methods + +=cut + +=head3 housebound_visits + + my $visits = Koha::Patron::HouseboundProfile->housebound_visits; + +Returns an arrayref of all visits associated this houseboundProfile. + +=cut + +sub housebound_visits { + my ( $self ) = @_; + my @visits = Koha::Patron::HouseboundVisits + ->special_search({ borrowernumber => $self->borrowernumber }); + return \@visits; +} + +=head3 _type + +=cut + +sub _type { + return 'HouseboundProfile'; +} + +1; + +=head1 AUTHOR + +Alex Sassmannshausen + +=cut diff --git a/Koha/Patron/HouseboundProfiles.pm b/Koha/Patron/HouseboundProfiles.pm new file mode 100644 index 0000000..65cc771 --- /dev/null +++ b/Koha/Patron/HouseboundProfiles.pm @@ -0,0 +1,61 @@ +package Koha::Patron::HouseboundProfiles; + +# 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 Modern::Perl; + +use Koha::Database; +use Koha::Patron::HouseboundProfile; + +use base qw(Koha::Objects); + +=head1 NAME + +Koha::Patron::HouseboundProfiles - Koha Patron HouseboundProfiles Object class + +=head1 SYNOPSIS + +HouseboundProfiles class used primarily by members/housebound.pl. + +=head1 DESCRIPTION + +Standard Koha::Objects definitions, and additional methods. + +=head1 API + +=head2 Class Methods + +=cut + +=head3 _type + +=cut + +sub _type { + return 'HouseboundProfile'; +} + +sub object_class { + return 'Koha::Patron::HouseboundProfile'; +} + +1; + +=head1 AUTHOR + +Alex Sassmannshausen + +=cut diff --git a/Koha/Patron/HouseboundVisit.pm b/Koha/Patron/HouseboundVisit.pm new file mode 100644 index 0000000..a7dc0c6 --- /dev/null +++ b/Koha/Patron/HouseboundVisit.pm @@ -0,0 +1,83 @@ +package Koha::Patron::HouseboundVisit; + +# 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 Modern::Perl; + +use Koha::Database; + +use base qw(Koha::Object); + +=head1 NAME + +Koha::Patron::HouseboundVisit - Koha Patron HouseboundVisit Object class + +=head1 SYNOPSIS + +HouseboundVisit class used primarily by members/housebound.pl. + +=head1 DESCRIPTION + +Standard Koha::Objects definitions, and additional methods. + +=head1 API + +=head2 Class Methods + +=cut + +=head3 chooser + + my $chooser = Koha::Patron::HouseboundVisit->chooser; + +Returns the prefetched chooser for this visit. + +=cut + +sub chooser { + my ( $self ) = @_; + return $self->_result->chooser_brwnumber; +} + +=head3 deliverer + + my $deliverer = Koha::Patron::HouseboundVisit->deliverer; + +Returns the prefetched deliverer for this visit. + +=cut + +sub deliverer { + my ( $self ) = @_; + return $self->_result->deliverer_brwnumber; + +} + +=head3 _type + +=cut + +sub _type { + return 'HouseboundVisit'; +} + +1; + +=head1 AUTHOR + +Alex Sassmannshausen + +=cut diff --git a/Koha/Patron/HouseboundVisits.pm b/Koha/Patron/HouseboundVisits.pm new file mode 100644 index 0000000..5a31f60 --- /dev/null +++ b/Koha/Patron/HouseboundVisits.pm @@ -0,0 +1,102 @@ +package Koha::Patron::HouseboundVisits; + +# 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 Modern::Perl; + +use Koha::Database; +use Koha::Patron::HouseboundVisit; + +use base qw(Koha::Objects); + +=head1 NAME + +Koha::Patron::HouseboundVisits - Koha Patron HouseboundVisits Object class + +=head1 SYNOPSIS + +HouseboundVisits class used primarily by members/housebound.pl. + +=head1 DESCRIPTION + +Standard Koha::Objects definitions, and additional methods. + +=head1 API + +=head2 Class Methods + +=cut + +=head3 special_search; + + my @houseboundVisits = Koha::HouseboundVisits->special_search($params, $attributes); + +Perform a search for housebound visits. This method overrides standard search +to prefetch deliverers and choosers as we always need them anyway. + +If $attributes contains a prefetch entry, we defer to it, otherwise we add the +prefetch attribute and also augment $params with explicit 'me.' prefixes. + +This is intended to make search behave as most people would expect it to +behave. + +Should the user want to do complicated searches involving joins, without +specifying their own prefetch, the naive 'me.' augmentation will break in +hilarious ways. In this case the user should supply their own prefetch +clause. + +=cut + +sub special_search { + my ( $self, $params, $attributes ) = @_; + unless (exists $attributes->{prefetch}) { + # No explicit prefetch has been passed in -> automatic optimisation. + $attributes->{prefetch} = [ + 'chooser_brwnumber', 'deliverer_brwnumber' + ]; + # So we must ensure our $params use the 'me.' prefix. + my $oldparams = $params; + $params = {}; + while (my ($k, $v) = each %{$oldparams}) { + if ($k =~ /^me\..*/) { + $params->{$k} = $v; + } else { + $params->{"me." . $k} = $v; + } + } + } + $self->SUPER::search($params, $attributes); +} + +=head3 _type + +=cut + +sub _type { + return 'HouseboundVisit'; +} + +sub object_class { + return 'Koha::Patron::HouseboundVisit'; +} + +1; + +=head1 AUTHOR + +Alex Sassmannshausen + +=cut diff --git a/Koha/Patrons.pm b/Koha/Patrons.pm index e001b84..384a25c 100644 --- a/Koha/Patrons.pm +++ b/Koha/Patrons.pm @@ -37,6 +37,38 @@ Koha::Patron - Koha Patron Object class =cut +=head3 housebound_choosers + +Returns all Patrons which are Housebound choosers. + +=cut + +sub housebound_choosers { + my ( $self ) = @_; + my $cho = $self->_resultset->search + ->search_related('borrower_attributes', { + code => 'HSBND', + attribute => 'CHO', + })->search_related('borrowernumber'); + return Koha::Patrons->_new_from_dbic($cho); +} + +=head3 housebound_deliverers + +Returns all Patrons which are Housebound deliverers. + +=cut + +sub housebound_deliverers { + my ( $self ) = @_; + my $del = $self->_resultset->search + ->search_related('borrower_attributes', { + code => 'HSBND', + attribute => 'DEL', + })->search_related('borrowernumber'); + return Koha::Patrons->_new_from_dbic($del); +} + =head3 type =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..3219ade --- /dev/null +++ b/installer/data/mysql/atomicupdate/housebound_tables.sql @@ -0,0 +1,52 @@ +CREATE TABLE IF NOT EXISTS `housebound_profile` ( + `borrowernumber` int(11) NOT NULL, -- Number of the borrower associated with this profile. + `day` text NOT NULL, -- The preferred day of the week for delivery. + `frequency` text NOT NULL, -- The Authorised_Value definining the pattern for delivery. + `fav_itemtypes` text default NULL, -- Free text describing preferred itemtypes. + `fav_subjects` text default NULL, -- Free text describing preferred subjects. + `fav_authors` text default NULL, -- Free text describing preferred authors. + `referral` text default NULL, -- Free text indicating how the borrower was added to the service. + `notes` text default NULL, -- Free text for additional notes. + PRIMARY KEY (`borrowernumber`), + CONSTRAINT `housebound_profile_bnfk` + FOREIGN KEY (`borrowernumber`) + REFERENCES `borrowers` (`borrowernumber`) + ON UPDATE CASCADE ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +CREATE TABLE IF NOT EXISTS `housebound_visit` ( + `id` int(11) NOT NULL auto_increment, -- ID of the visit. + `borrowernumber` int(11) NOT NULL, -- Number of the borrower, & the profile, linked to this visit. + `appointment_date` date default NULL, -- Date of visit. + `day_segment` varchar(10), -- Rough time frame: 'morning', 'afternoon' 'evening' + `chooser_brwnumber` int(11) default NULL, -- Number of the borrower to choose items for delivery. + `deliverer_brwnumber` int(11) default NULL, -- Number of the borrower to deliver items. + PRIMARY KEY (`id`), + CONSTRAINT `houseboundvisit_bnfk` + FOREIGN KEY (`borrowernumber`) + REFERENCES `housebound_profile` (`borrowernumber`) + ON UPDATE CASCADE ON DELETE CASCADE, + CONSTRAINT `houseboundvisit_bnfk_1` + FOREIGN KEY (`chooser_brwnumber`) + REFERENCES `borrowers` (`borrowernumber`) + ON UPDATE CASCADE ON DELETE CASCADE, + CONSTRAINT `houseboundvisit_bnfk_2` + FOREIGN KEY (`deliverer_brwnumber`) + REFERENCES `borrowers` (`borrowernumber`) + ON UPDATE CASCADE ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +INSERT IGNORE INTO systempreferences + (variable,value,options,explanation,type) VALUES + ('HouseboundModule',0,'', + 'If ON, enable housebound module functionality.','YesNo'); + +INSERT IGNORE INTO authorised_values (category, authorised_value, lib) VALUES + ('HSBND_FREQ','EW','Every week'), + ('HSBND_ROLE','CHO','Chooser'), + ('HSBND_ROLE','DEL','Deliverer'); + +INSERT IGNORE INTO borrower_attribute_types + (code, description, repeatable, opac_display, staff_searchable, + authorised_value_category, display_checkout) values + ('HSBND', 'Housebound role', 1, 1, 1, 'HSBND_ROLE', 1); diff --git a/installer/data/mysql/en/mandatory/auth_values.sql b/installer/data/mysql/en/mandatory/auth_values.sql index d7fb280..511b096 100644 --- a/installer/data/mysql/en/mandatory/auth_values.sql +++ b/installer/data/mysql/en/mandatory/auth_values.sql @@ -1,2 +1,6 @@ INSERT INTO authorised_values (category,authorised_value,lib,lib_opac) VALUES ('YES_NO','0','No','No'); INSERT INTO authorised_values (category,authorised_value,lib,lib_opac) VALUES ('YES_NO','1','Yes','Yes'); +INSERT INTO authorised_values (category, authorised_value, lib) VALUES + ('HSBND_FREQ','EW','Every week'), + ('HSBND_ROLE','CHO','Chooser'), + ('HSBND_ROLE','DEL','Deliverer'); diff --git a/installer/data/mysql/en/mandatory/patron_attributes.sql b/installer/data/mysql/en/mandatory/patron_attributes.sql new file mode 100644 index 0000000..89845ad --- /dev/null +++ b/installer/data/mysql/en/mandatory/patron_attributes.sql @@ -0,0 +1,4 @@ +INSERT INTO borrower_attribute_types + (code, description, repeatable, opac_display, staff_searchable, + authorised_value_category, display_checkout) values + ('HSBND', 'Housebound role', 1, 1, 1, 'HSBND_ROLE', 1); diff --git a/installer/data/mysql/en/mandatory/patron_attributes.txt b/installer/data/mysql/en/mandatory/patron_attributes.txt new file mode 100644 index 0000000..c2d0d4f --- /dev/null +++ b/installer/data/mysql/en/mandatory/patron_attributes.txt @@ -0,0 +1,2 @@ +Default Koha system extended patron attributes: +* HSBND - Allow assignment of different housebound roles for volunteers diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index f00b63b..e0d176b 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -3810,6 +3810,54 @@ CREATE TABLE `hold_fill_targets` ( REFERENCES `branches` (`branchcode`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +-- +-- Table structure for table `housebound_profile` +-- + +DROP TABLE IF EXISTS `housebound_profile`; +CREATE TABLE `housebound_profile` ( + `borrowernumber` int(11) NOT NULL, -- Number of the borrower associated with this profile. + `day` text NOT NULL, -- The preferred day of the week for delivery. + `frequency` text NOT NULL, -- The Authorised_Value definining the pattern for delivery. + `fav_itemtypes` text default NULL, -- Free text describing preferred itemtypes. + `fav_subjects` text default NULL, -- Free text describing preferred subjects. + `fav_authors` text default NULL, -- Free text describing preferred authors. + `referral` text default NULL, -- Free text indicating how the borrower was added to the service. + `notes` text default NULL, -- Free text for additional notes. + PRIMARY KEY (`borrowernumber`), + CONSTRAINT `housebound_profile_bnfk` + FOREIGN KEY (`borrowernumber`) + REFERENCES `borrowers` (`borrowernumber`) + ON UPDATE CASCADE ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- +-- Table structure for table `housebound_visit` +-- + +DROP TABLE IF EXISTS `housebound_visit`; +CREATE TABLE `housebound_visit` ( + `id` int(11) NOT NULL auto_increment, -- ID of the visit. + `borrowernumber` int(11) NOT NULL, -- Number of the borrower, & the profile, linked to this visit. + `appointment_date` date default NULL, -- Date of visit. + `day_segment` varchar(10), -- Rough time frame: 'morning', 'afternoon' 'evening' + `chooser_brwnumber` int(11) default NULL, -- Number of the borrower to choose items for delivery. + `deliverer_brwnumber` int(11) default NULL, -- Number of the borrower to deliver items. + PRIMARY KEY (`id`), + CONSTRAINT `houseboundvisit_bnfk` + FOREIGN KEY (`borrowernumber`) + REFERENCES `housebound_profile` (`borrowernumber`) + ON UPDATE CASCADE ON DELETE CASCADE, + CONSTRAINT `houseboundvisit_bnfk_1` + FOREIGN KEY (`chooser_brwnumber`) + REFERENCES `borrowers` (`borrowernumber`) + ON UPDATE CASCADE ON DELETE CASCADE, + CONSTRAINT `houseboundvisit_bnfk_2` + FOREIGN KEY (`deliverer_brwnumber`) + REFERENCES `borrowers` (`borrowernumber`) + ON UPDATE CASCADE ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; diff --git a/installer/data/mysql/sysprefs.sql b/installer/data/mysql/sysprefs.sql index 5a90b7c..5473bc0 100644 --- a/installer/data/mysql/sysprefs.sql +++ b/installer/data/mysql/sysprefs.sql @@ -172,6 +172,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('HoldsQueueSkipClosed', '0', NULL, 'If enabled, any libraries that are closed when the holds queue is built will be ignored for the purpose of filling holds.', 'YesNo'), ('HoldsToPullStartDate','2',NULL,'Set the default start date for the Holds to pull list to this many days ago','Integer'), ('HomeOrHoldingBranch','holdingbranch','holdingbranch|homebranch','Used by Circulation to determine which branch of an item to check with independent branches on, and by search to determine which branch to choose for availability ','Choice'), +('HouseboundModule',0,'','If ON, enable housebound module functionality.','YesNo'), ('HTML5MediaEnabled','not','not|opac|staff|both','Show a tab with a HTML5 media player for files catalogued in field 856','Choice'), ('HTML5MediaExtensions','webm|ogg|ogv|oga|vtt','','Media file extensions','free'), ('HTML5MediaYouTube',0,'Embed|Don\'t embed','YouTube links as videos','YesNo'), 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 a90ad67..083a88c 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc @@ -105,5 +105,8 @@ [% IF CAN_user_borrowers && useDischarge %] [% IF dischargeview %]
  • [% ELSE %]
  • [% END %]Discharges
  • [% END %] + [% IF Koha.Preference('HouseboundModule') %] + [% IF houseboundview %]
  • [% ELSE %]
  • [% END %]Housebound
  • + [% END %] [% END %] 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 fc9706b..276ad50 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 @@ -769,3 +769,10 @@ Circulation: - "Patron categories allowed to checkout in a batch" - pref: BatchCheckoutsValidCategories - "(list of patron categories separated with a pipe '|')" + Housebound module: + - + - pref: HouseboundModule + choices: + yes: Enable + no: Disable + - "housebound module" 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..fd0c618 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/housebound.tt @@ -0,0 +1,434 @@ +[% USE Koha %] +[% USE KohaDates %] +[% USE AuthorisedValues %] +[% borrowernumber = patron.borrowernumber %] +[% branchname = branch.branchname %] +[% categoryname = category.description %] +[% categorycode = category.categorycode %] +[% category_type = category.category_type %] +[% firstname = patron.firstname %] +[% surname = patron.surname %] +[% othernames = patron.othernames %] +[% invert_name = 0 %] +[% INCLUDE 'doc-head-open.inc' %] +Koha › Housebound › Details for [% INCLUDE 'patron-title.inc' %] +[% INCLUDE 'doc-head-close.inc' %] +[% INCLUDE 'calendar.inc' %] + + + + +[% INCLUDE 'header.inc' %] +[% INCLUDE 'patron-search.inc' %] + + + +
    +
    +
    +
    + + [% UNLESS ( unknowuser ) %] + [% INCLUDE 'members-toolbar.inc' %] + [% END %] + +
    + + +

    Housebound details for [% patron.title %] [% patron.firstname %] [% patron.surname %] ([% patron.cardnumber %])

    +
    + + + [% IF ( method == 'update_or_create' ) %] +

    Manage housebound profile

    +
    + + [% IF ( housebound_profile ) %] + + [% ELSE %] + + [% END %] +
    + Housebound details +
      +
    1. + + +
    2. +
    3. + + +
    4. +
    5. + + [% IF ( housebound_profile ) %] + + [% ELSE %] + + [% END %] +
    6. +
    7. + + [% IF ( housebound_profile ) %] + + [% ELSE %] + + [% END %] +
    8. +
    9. + + [% IF ( housebound_profile ) %] + + [% ELSE %] + + [% END %] +
    10. +
    11. + + [% IF ( housebound_profile ) %] + + [% ELSE %] + + [% END %] +
    12. +
    13. + + [% IF ( housebound_profile ) %] + + [% ELSE %] + + [% END %] +
    14. +
    +
    +
    + + + Cancel + +
    +
    + + + [% ELSIF ( method == 'visit_update_or_create' ) %] +

    Manage housebound deliveries

    +
    + [% IF ( visit ) %] + + + [% ELSE %] + + [% END %] + +
    + Delivery details +
      +
    1. + + [% IF ( visit ) %] + + [% ELSE %] + + [% END %] +
    2. +
    3. + + +
    4. +
    5. + + +
    6. +
    7. + + +
    8. +
    +
    +
    + + + Cancel + +
    +
    + + + [% ELSIF ( housebound_profile ) %] +
    + +
    +
    +
      +
    1. + Delivery day: + [% hpd = housebound_profile.day %] + [% IF hpd == 'any' %] + Any + [% ELSIF hpd == 'monday' %] + Monday + [% ELSIF hpd == 'tuesday' %] + Tuesday + [% ELSIF hpd == 'wednesday' %] + Wednesday + [% ELSIF hpd == 'thursday' %] + Thursday + [% ELSIF hpd == 'friday' %] + Friday + [% ELSIF hpd == 'saturday' %] + Saturday + [% ELSIF hpd == 'sunday' %] + Sunday + [% END %] +
    2. +
    3. + Frequency: + [% AuthorisedValues.GetByCode( 'HSBND_FREQ', housebound_profile.frequency, 0 ) || housebound_profile.frequency %] +
    4. +
    5. + Material: + [% housebound_profile.fav_itemtypes %] +
    6. +
    7. + Subjects: + [% housebound_profile.fav_subjects %] +
    8. +
    9. + Authors: + [% housebound_profile.fav_authors %] +
    10. +
    11. + Referral: + [% housebound_profile.referral %] +
    12. +
    13. + Notes: + [% housebound_profile.notes %] +
    14. +
    +
    +
    +

    Deliveries

    +
    + +
    + [% housebound_visits = housebound_profile.housebound_visits %] + [% IF housebound_visits.size > 0 %] + + + + + [% FOREACH entry IN housebound_visits %] + + + + + + + + [% END %] +
    IDDateChooserDelivererActions
    [% entry.id %][% entry.appointment_date %] ([% entry.day_segment %]) + + [% INCLUDE 'patron-title.inc' borrowernumber = entry.chooser.borrowernumber category_type = entry.chooser.categorycode firstname = entry.chooser.firstname surname = entry.chooser.surname othernames = entry.chooser.othernames cardnumber = entry.chooser.cardnumber invert_name = 0 %] + + + + [% INCLUDE 'patron-title.inc' borrowernumber = entry.deliverer.borrowernumber category_type = entry.deliverer.categorycode firstname = entry.deliverer.firstname surname = entry.deliverer.surname othernames = entry.deliverer.othernames cardnumber = entry.deliverer.cardnumber invert_name = 0 %] + + + + Edit + + | + + Delete + +
    + [% END %] +
    + + [% 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..f5ced86 --- /dev/null +++ b/members/housebound.pl @@ -0,0 +1,150 @@ +#!/usr/bin/perl + +# Copyright 2016 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. + +=head1 housebound.pl + + Script to handle housebound management for patrons. This single script + handles display, creation, deletion and management of profiles and visits. + +=cut + +use Modern::Perl; +use CGI; +use C4::Auth; +use C4::Output; +use Koha::Libraries; +use Koha::Patrons; +use Koha::Patron::Categories; +use Koha::Patron::HouseboundProfile; +use Koha::Patron::HouseboundVisit; +use Koha::Patron::HouseboundVisits; + +my $input = CGI->new; + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { + template_name => 'members/housebound.tt', + query => $input, + type => 'intranet', + authnotrequired => 0, + flagsrequired => { borrowers => 1 }, + } +); + +my $patron = Koha::Patrons->new->find($input->param('borrowernumber')); +my $method = $input->param('method') // q{}; +my $visit_id = $input->param('visit_id') // q{}; +my $branch = Koha::Libraries->new->find($patron->branchcode); +my $category = Koha::Patron::Categories->new->find($patron->categorycode); +my $houseboundprofile = $patron->housebound_profile; + +my ( $houseboundvisits, $deliverers, $choosers ); +my ( $houseboundvisit, $deliverer, $chooser ); + +if ( $method eq 'updateconfirm' ) { + # We have received the input from the profile edit form. We must save the + # changes, and return to simple display. + $houseboundprofile->set({ + day => $input->param('day') // q{}, + frequency => $input->param('frequency') // q{}, + fav_itemtypes => $input->param('fav_itemtypes') // q{}, + fav_subjects => $input->param('fav_subjects') // q{}, + fav_authors => $input->param('fav_authors') // q{}, + referral => $input->param('referral') // q{}, + notes => $input->param('notes') // q{}, + }); + die("Unable to store edited profile") + unless ( $houseboundprofile->store ); + $method = undef; +} elsif ( $method eq 'createconfirm' ) { + # We have received the input necessary to create a new profile. We must + # save it, and return to simple display. + $houseboundprofile = Koha::Patron::HouseboundProfile->new({ + borrowernumber => $patron->borrowernumber, + day => $input->param('day') // q{}, + frequency => $input->param('frequency') // q{}, + fav_itemtypes => $input->param('fav_itemtypes') // q{}, + fav_subjects => $input->param('fav_subjects') // q{}, + fav_authors => $input->param('fav_authors') // q{}, + referral => $input->param('referral') // q{}, + notes => $input->param('notes') // q{}, + }); + die("Unable to store new profile") + unless ( $houseboundprofile->store ); + $method = undef; +} elsif ( $method eq 'visit_update_or_create' ) { + # We want to edit, edit a visit, so we must pass its details. + $deliverers = Koha::Patrons->new->housebound_deliverers; + $choosers = Koha::Patrons->new->housebound_choosers; + $houseboundvisit = Koha::Patron::HouseboundVisits->find($visit_id) + if ( $visit_id ); +} elsif ( $method eq 'visit_delete' ) { + # We want ot delete a specific visit. + my $visit = Koha::Patron::HouseboundVisits->find($visit_id); + die("Unable to delete visit") unless ( $visit->delete ); + $method = undef; +} elsif ( $method eq 'editvisitconfirm' ) { + # We have received input for editing a visit. We must store and return to + # simple display. + my $visit = Koha::Patron::HouseboundVisits->find($visit_id); + $visit->set({ + borrowernumber => $input->param('borrowernumber') // q{}, + appointment_date => $input->param('date') // q{}, + day_segment => $input->param('segment') // q{}, + chooser_brwnumber => $input->param('chooser') // q{}, + deliverer_brwnumber => $input->param('deliverer') // q{}, + }); + die("Unable to store edited visit") unless ( $visit->store ); + $method = undef; +} elsif ( $method eq 'addvisitconfirm' ) { + # We have received input for creating a visit. We must store and return + # to simple display. + my $visit = Koha::Patron::HouseboundVisit->new({ + borrowernumber => $input->param('borrowernumber') // q{}, + appointment_date => $input->param('date') // q{}, + day_segment => $input->param('segment') // q{}, + chooser_brwnumber => $input->param('chooser') // q{}, + deliverer_brwnumber => $input->param('deliverer') // q{}, + }); + die("Unable to store new visit") unless ( $visit->store ); + $method = undef; +} + +# We don't have any profile information, so we must display a creation form. +$method = 'update_or_create' if ( !$houseboundprofile ); + +$template->param( + patron => $patron, + housebound_profile => $houseboundprofile, + visit => $houseboundvisit, + branch => $branch, + category => $category, + method => $method, + choosers => $choosers, + deliverers => $deliverers, + houseboundview => 'on', +); + +output_html_with_http_headers $input, $cookie, $template->output; + +=head1 AUTHOR + +Alex Sassmannshausen + +=cut diff --git a/t/db_dependent/Patron/Housebound.t b/t/db_dependent/Patron/Housebound.t new file mode 100755 index 0000000..320dd61 --- /dev/null +++ b/t/db_dependent/Patron/Housebound.t @@ -0,0 +1,75 @@ +#!/usr/bin/perl +use Modern::Perl; + +use C4::Members; +use C4::Circulation; +use Koha::Database; +use Koha::Patrons; + +use Test::More tests => 6; + +use_ok('Koha::Patron'); + +use t::lib::TestBuilder; +use t::lib::Mocks; + +my $schema = Koha::Database->new->schema; +$schema->storage->txn_begin; + +my $builder = t::lib::TestBuilder->new; + +my $patron = $builder->build({ source => 'Borrower' }); +my $profile = $builder->build({ + source => 'HouseboundProfile', + value => { + borrowernumber => $patron->{borrowernumber}, + }, +}); + +# Test housebound_profile +is( + Koha::Patrons->find($patron->{borrowernumber}) + ->housebound_profile->frequency, + $profile->{frequency}, + "Fetch housebound_profile." +); + +# patron_choosers and patron_deliverers Tests + +# Current Patron Chooser / Deliverer count +my $orig_del_count = Koha::Patrons->housebound_deliverers->count; +my $orig_cho_count = Koha::Patrons->housebound_choosers->count; + +# We add one, just in case the above is 0, so we're guaranteed one of each. +my $patron_chooser = $builder->build({ source => 'Borrower' }); +$builder->build({ + source => 'BorrowerAttribute', + value => { + borrowernumber => $patron_chooser->{borrowernumber}, + code => 'HSBND', + attribute => 'CHO', + password => undef, + }, +}); + +my $patron_deliverer = $builder->build({ source => 'Borrower' }); +$builder->build({ + source => 'BorrowerAttribute', + value => { + borrowernumber => $patron_deliverer->{borrowernumber}, + code => 'HSBND', + attribute => 'DEL', + password => undef, + }, +}); + +# Test housebound_choosers +is(Koha::Patrons->housebound_choosers->count, $orig_cho_count + 1, "Correct count of choosers."); +is(Koha::Patrons->housebound_deliverers->count, $orig_del_count + 1, "Correct count of deliverers"); + +isa_ok(Koha::Patrons->housebound_choosers->next, "Koha::Patron"); +isa_ok(Koha::Patrons->housebound_deliverers->next, "Koha::Patron"); + +$schema->storage->txn_rollback; + +1; diff --git a/t/db_dependent/Patron/HouseboundProfiles.t b/t/db_dependent/Patron/HouseboundProfiles.t new file mode 100644 index 0000000..05d6392 --- /dev/null +++ b/t/db_dependent/Patron/HouseboundProfiles.t @@ -0,0 +1,75 @@ +#!/usr/bin/perl + +# 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, see . + +use Modern::Perl; + +use Test::More tests => 3; + +use Koha::Database; +use Koha::Patron::HouseboundProfiles; + +use t::lib::TestBuilder; + +my $schema = Koha::Database->new->schema; +$schema->storage->txn_begin; + +my $builder = t::lib::TestBuilder->new; + +# Profile Tests + +my $profile = $builder->build({ source => 'HouseboundProfile' }); + +is( + Koha::Patron::HouseboundProfiles + ->find($profile->{borrowernumber})->borrowernumber, + $profile->{borrowernumber}, + "Find created profile." +); + +my @profiles = Koha::Patron::HouseboundProfiles + ->search({ day => $profile->{day} }); +my $found_profile = shift @profiles; +is( + $found_profile->borrowernumber, + $profile->{borrowernumber}, + "Search for created profile." +); + +# ->housebound_profile Tests + +my $visit1 = $builder->build({ + source => 'HouseboundVisit', + value => { + borrowernumber => $profile->{borrowernumber}, + }, +}); +my $visit2 = $builder->build({ + source => 'HouseboundVisit', + value => { + borrowernumber => $profile->{borrowernumber}, + }, +}); + +is( + scalar @{$found_profile->housebound_visits}, + 2, + "Fetch housebound_visits." +); + +$schema->storage->txn_rollback; + +1; diff --git a/t/db_dependent/Patron/HouseboundVisits.t b/t/db_dependent/Patron/HouseboundVisits.t new file mode 100644 index 0000000..bec556c --- /dev/null +++ b/t/db_dependent/Patron/HouseboundVisits.t @@ -0,0 +1,92 @@ +#!/usr/bin/perl + +# 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, see . + +use Modern::Perl; + +use Test::More tests => 8; + +use Koha::Database; +use Koha::Patron::HouseboundVisits; +use Koha::Patron::HouseboundVisit; + +use t::lib::TestBuilder; + +my $schema = Koha::Database->new->schema; +$schema->storage->txn_begin; + +my $builder = t::lib::TestBuilder->new; + +########### Test HouseboundVisits + +my $visit = $builder->build({ source => 'HouseboundVisit' }); + +is( + Koha::Patron::HouseboundVisits + ->find($visit->{id})->id, + $visit->{id}, + "Find created visit." +); + +# Using our Prefetching search + +# Does it work implicitly? +my @visits = Koha::Patron::HouseboundVisits + ->special_search({ borrowernumber => $visit->{borrowernumber} }); +my $found_visit = shift @visits; +is( + $found_visit->borrowernumber, + $visit->{borrowernumber}, + "Search for created visit." +); + +# Does it work Explicitly? +@visits = Koha::Patron::HouseboundVisits + ->special_search({ 'me.borrowernumber' => $visit->{borrowernumber} }); +$found_visit = shift @visits; +is( + $found_visit->borrowernumber, + $visit->{borrowernumber}, + "Search for created visit." +); + +# Does it work without prefetcing? +@visits = Koha::Patron::HouseboundVisits + ->special_search({ borrowernumber => $visit->{borrowernumber} }, { prefetch => [] }); +$found_visit = shift @visits; +is( + $found_visit->borrowernumber, + $visit->{borrowernumber}, + "Search for created visit." +); + +########### Test HouseboundVisit + +my $result = Koha::Patron::HouseboundVisits->find($visit->{id}); + +is( $result->deliverer->borrowernumber, $visit->{deliverer_brwnumber} ); + +is( $result->chooser->borrowernumber, $visit->{chooser_brwnumber} ); + +TODO: { + local $TODO = "We want our results here to be Koha::Patron objects, but they by default return DBIC Schema objects. The currently accepted solution to this (use the _from_dbic method), is defined for Koha::Objects, but not for Koha::Object. We do not resolve this issue here"; + isa_ok( $result->deliverer, "Koha::Patron"); + isa_ok( $result->chooser, "Koha::Patron"); +} + +$schema->storage->txn_rollback; + +1; -- 2.8.1