Bug 5670: Housebound Readers Module
authorA. Sassmannshausen <alex.sassmannshausen@ptfs-europe.com>
Fri, 4 Apr 2014 09:55:07 +0000 (09:55 +0000)
committerKyle M Hall <kyle@bywatersolutions.com>
Fri, 21 Oct 2016 18:17:57 +0000 (18:17 +0000)
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 <chrisc@catalyst.net.nz>
Signed-off-by: Claire Gravely <claire_gravely@hotmail.com>
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 <claire_gravely@hotmail.com>
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 <claire_gravely@hotmail.com>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
19 files changed:
Koha/Patron.pm
Koha/Patron/HouseboundProfile.pm [new file with mode: 0644]
Koha/Patron/HouseboundProfiles.pm [new file with mode: 0644]
Koha/Patron/HouseboundVisit.pm [new file with mode: 0644]
Koha/Patron/HouseboundVisits.pm [new file with mode: 0644]
Koha/Patrons.pm
installer/data/mysql/atomicupdate/housebound_tables.sql [new file with mode: 0644]
installer/data/mysql/en/mandatory/auth_values.sql
installer/data/mysql/en/mandatory/patron_attributes.sql [new file with mode: 0644]
installer/data/mysql/en/mandatory/patron_attributes.txt [new file with mode: 0644]
installer/data/mysql/kohastructure.sql
installer/data/mysql/sysprefs.sql
koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc
koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref
koha-tmpl/intranet-tmpl/prog/en/modules/members/housebound.tt [new file with mode: 0644]
members/housebound.pl [new file with mode: 0755]
t/db_dependent/Patron/Housebound.t [new file with mode: 0755]
t/db_dependent/Patron/HouseboundProfiles.t [new file with mode: 0644]
t/db_dependent/Patron/HouseboundVisits.t [new file with mode: 0644]

index 84c49c7..9436bf2 100644 (file)
@@ -30,6 +30,7 @@ use Koha::Holds;
 use Koha::Issues;
 use Koha::OldIssues;
 use Koha::Patron::Categories;
+use Koha::Patron::HouseboundProfiles;
 use Koha::Patron::Images;
 use Koha::Patrons;
 use Koha::Virtualshelves;
@@ -123,6 +124,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 (file)
index 0000000..5ce87f8
--- /dev/null
@@ -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 <alex.sassmannshausen@ptfs-europe.com>
+
+=cut
diff --git a/Koha/Patron/HouseboundProfiles.pm b/Koha/Patron/HouseboundProfiles.pm
new file mode 100644 (file)
index 0000000..65cc771
--- /dev/null
@@ -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 <alex.sassmannshausen@ptfs-europe.com>
+
+=cut
diff --git a/Koha/Patron/HouseboundVisit.pm b/Koha/Patron/HouseboundVisit.pm
new file mode 100644 (file)
index 0000000..a7dc0c6
--- /dev/null
@@ -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 <alex.sassmannshausen@ptfs-europe.com>
+
+=cut
diff --git a/Koha/Patron/HouseboundVisits.pm b/Koha/Patron/HouseboundVisits.pm
new file mode 100644 (file)
index 0000000..5a31f60
--- /dev/null
@@ -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 <alex.sassmannshausen@ptfs-europe.com>
+
+=cut
index e001b84..384a25c 100644 (file)
@@ -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 (file)
index 0000000..3219ade
--- /dev/null
@@ -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);
index d7fb280..511b096 100644 (file)
@@ -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 (file)
index 0000000..89845ad
--- /dev/null
@@ -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 (file)
index 0000000..c2d0d4f
--- /dev/null
@@ -0,0 +1,2 @@
+Default Koha system extended patron attributes:
+* HSBND - Allow assignment of different housebound roles for volunteers
index 0343b5b..4b362f0 100644 (file)
@@ -3808,6 +3808,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 */;
index 3caac49..e1d190d 100644 (file)
@@ -173,6 +173,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'),
index a90ad67..083a88c 100644 (file)
     [% IF CAN_user_borrowers && useDischarge %]
         [% IF dischargeview %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/discharge.pl?borrowernumber=[% borrowernumber %]">Discharges</a></li>
     [% END %]
+    [% IF Koha.Preference('HouseboundModule') %]
+        [% IF houseboundview %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/housebound.pl?borrowernumber=[% borrowernumber %]">Housebound</a></li>
+    [% END %]
 </ul></div>
 [% END %]
index 1f6edef..81c0876 100644 (file)
@@ -775,3 +775,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 (file)
index 0000000..fd0c618
--- /dev/null
@@ -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' %]
+<title>Koha &rsaquo; Housebound &rsaquo; Details for [% INCLUDE 'patron-title.inc' %]</title>
+[% INCLUDE 'doc-head-close.inc' %]
+[% INCLUDE 'calendar.inc' %]
+<script type="text/javascript">
+//<![CDATA[
+$(document).ready(function() {
+  $("#date").datepicker({ minDate: 0, dateFormat: "yy-mm-dd" });
+});
+//]]>
+</script>
+
+</head>
+<body>
+[% INCLUDE 'header.inc' %]
+[% INCLUDE 'patron-search.inc' %]
+
+<div id="breadcrumbs">
+         <a href="/cgi-bin/koha/mainpage.pl">Home</a>
+&rsaquo; <a href="/cgi-bin/koha/members/members-home.pl">Patrons</a>
+&rsaquo; Details for [% INCLUDE 'patron-title.inc' %]
+</div>
+
+<div id="doc3" class="yui-t2">
+  <div id="bd">
+    <div id="yui-main">
+      <div class="yui-b">
+
+        [% UNLESS ( unknowuser ) %]
+        [% INCLUDE 'members-toolbar.inc' %]
+        [% END %]
+
+        <div class="yui-g">
+
+          <!-- Title -->
+          <h3>Housebound details for [% patron.title %] [% patron.firstname %] [% patron.surname %] ([% patron.cardnumber %])</h3>
+          <div class="yui-u first">
+
+            <!-- Create or edit housebound_profile -->
+            [% IF ( method == 'update_or_create' ) %]
+              <h4>Manage housebound profile</h4>
+              <form id="editform" method="post" name="editform"
+                    action="/cgi-bin/koha/members/housebound.pl">
+                <input type="hidden" name="borrowernumber" value="[% borrowernumber %]" />
+                [% IF ( housebound_profile ) %]
+                  <input type="hidden" name="method" value="updateconfirm" />
+                [% ELSE %]
+                  <input type="hidden" name="method" value="createconfirm" />
+                [% END %]
+                <fieldset id="houseboundentry" class="rows">
+                  <legend>Housebound details</legend>
+                  <ol>
+                    <li>
+                      <label for="day">Delivery day:</label>
+                      <select id="day" name="day" required="required">
+                        <option value="">Select a day</option>
+                        [% IF ( housebound_profile ) %]
+                          [% IF ( housebound_profile.day == 'any' ) %]
+                            <option value="any" selected='selected'>Any</option>
+                          [% ELSE %]
+                            <option value="any">Any</option>
+                          [% END %]
+                          [% IF ( housebound_profile.day == 'monday' ) %]
+                            <option value="monday" selected='selected'>Monday</option>
+                          [% ELSE %]
+                            <option value="monday">Monday</option>
+                          [% END %]
+                          [% IF ( housebound_profile.day == 'tuesday' ) %]
+                            <option value="tuesday" selected='selected'>Tuesday</option>
+                          [% ELSE %]
+                            <option value="tuesday">Tuesday</option>
+                          [% END %]
+                          [% IF ( housebound_profile.day == 'wednesday' ) %]
+                            <option value="wednesday" selected='selected'>Wednesday</option>
+                          [% ELSE %]
+                            <option value="wednesday">Wednesday</option>
+                          [% END %]
+                          [% IF ( housebound_profile.day == 'thursday' ) %]
+                            <option value="thursday" selected='selected'>Thursday</option>
+                          [% ELSE %]
+                            <option value="thursday">Thursday</option>
+                          [% END %]
+                          [% IF ( housebound_profile.day == 'friday' ) %]
+                            <option value="friday" selected='selected'>Friday</option>
+                          [% ELSE %]
+                            <option value="friday">Friday</option>
+                          [% END %]
+                          [% IF ( housebound_profile.day == 'saturday' ) %]
+                            <option value="saturday" selected='selected'>Saturday</option>
+                          [% ELSE %]
+                            <option value="saturday">Saturday</option>
+                          [% END %]
+                          [% IF ( housebound_profile.day == 'sunday' ) %]
+                            <option value="sunday" selected='selected'>Sunday</option>
+                          [% ELSE %]
+                            <option value="sunday">Sunday</option>
+                          [% END %]
+                        [% ELSE %]
+                          <option value="any">Any</option>
+                          <option value="monday">Monday</option>
+                          <option value="tuesday">Tuesday</option>
+                          <option value="wednesday">Wednesday</option>
+                          <option value="thursday">Thursday</option>
+                          <option value="friday">Friday</option>
+                          <option value="saturday">Saturday</option>
+                          <option value="sunday">Sunday</option>
+                        [% END %]
+                      </select>
+                    </li>
+                    <li>
+                      <label for="frequency">Frequency:</label>
+                      <select id="frequency" name="frequency" required="required">
+                        <option value="">Select a frequency</option>
+                        [% FOREACH frequency IN AuthorisedValues.GetAuthValueDropbox('HSBND_FREQ') %]
+                          [% IF housebound_profile.frequency == frequency.value %]
+                            <option value="[% frequency.value %]" selected="selected">[% frequency.label %]</option>
+                          [% ELSE %]
+                            <option value="[% frequency.value %]">[% frequency.label %]</option>
+                          [% END %]
+                        [% END %]
+                      </select>
+                    </li>
+                    <li>
+                      <label for="fav_itemtypes">Preferred materials:</label>
+                      [% IF ( housebound_profile ) %]
+                        <input id="fav_itemtypes" type="text" size="50" name="fav_itemtypes"
+                               value="[% housebound_profile.fav_itemtypes %]">
+                      [% ELSE %]
+                        <input id="fav_itemtypes" type="text" value="" size="50" name="fav_itemtypes">
+                      [% END %]
+                    </li>
+                    <li>
+                      <label for="fav_subjects">Subjects:</label>
+                      [% IF ( housebound_profile ) %]
+                        <input id="fav_subjects" type="text" size="50" name="fav_subjects"
+                               value="[% housebound_profile.fav_subjects %]">
+                      [% ELSE %]
+                        <input id="fav_subjects" type="text" value="" size="50" name="fav_subjects">
+                      [% END %]
+                    </li>
+                    <li>
+                      <label for="fav_authors">Authors:</label>
+                      [% IF ( housebound_profile ) %]
+                        <input id="fav_authors" type="text" size="50" name="fav_authors"
+                               value="[% housebound_profile.fav_authors %]">
+                      [% ELSE %]
+                        <input id="fav_authors" type="text" value="" size="50" name="fav_authors">
+                      [% END %]
+                    </li>
+                    <li>
+                      <label for="referral">Referral:</label>
+                      [% IF ( housebound_profile ) %]
+                        <input id="referral" type="text" size="50" name="referral"
+                               value="[% housebound_profile.referral %]">
+                      [% ELSE %]
+                        <input id="referral" type="text" value="" size="50" name="referral">
+                      [% END %]
+                    </li>
+                    <li>
+                      <label for="notes">Notes:</label>
+                      [% IF ( housebound_profile ) %]
+                        <input id="notes" type="text" size="50" name="notes"
+                               value="[% housebound_profile.notes %]">
+                      [% ELSE %]
+                        <input id="notes" type="text" value="" size="50" name="notes">
+                      [% END %]
+                    </li>
+                  </ol>
+                </fieldset>
+                <fieldset class="action">
+                  <input type="submit" value="Save changes" name="save"
+                         onclick="console.log('Must validate form');" />
+                  <a class="cancel"
+                     href="/cgi-bin/koha/members/housebound.pl?borrowernumber=[% borrowernumber %]">
+                    Cancel
+                  </a>
+                </fieldset>
+              </form>
+
+            <!-- Create or edit housebound_visit -->
+            [% ELSIF ( method == 'visit_update_or_create' ) %]
+              <h4>Manage housebound deliveries</h4>
+              <form name="form" id="instance_form" method="post"
+                    action="/cgi-bin/koha/members/housebound.pl">
+                [% IF ( visit ) %]
+                  <input type="hidden" name="method" value="editvisitconfirm" />
+                  <input type="hidden" name="visit_id" value="[% visit.id %]" />
+                [% ELSE %]
+                  <input type="hidden" name="method" value="addvisitconfirm" />
+                [% END %]
+                <input type="hidden" name="borrowernumber" value="[% borrowernumber %]" />
+                <fieldset class="rows" id="instance">
+                  <legend>Delivery details</legend>
+                  <ol>
+                    <li>
+                      <label for="date">Date: </label>
+                      [% IF ( visit ) %]
+                        <input type="text" id="date" name="date" size="20"
+                               value="[% visit.appointment_date %]"
+                               required="required"/>
+                      [% ELSE %]
+                        <input type="text" id="date" name="date" size="20"
+                               value="" required="required"/>
+                      [% END %]
+                    </li>
+                    <li>
+                      <label for="segment">Time:</label>
+                      <select id="segment" name="segment" required="required">
+                        <option value="">Select a time</option>
+                        [% IF ( visit ) %]
+                          [% IF ( visit.day_segment == 'morning' ) %]
+                            <option value="morning" selected="selected">
+                              Morning
+                            </option>
+                          [% ELSE %]
+                            <option value="morning">Morning</option>
+                          [% END %]
+                          [% IF ( visit.day_segment == 'afternoon' ) %]
+                            <option value="afternoon" selected="selected">
+                              Afternoon
+                            </option>
+                          [% ELSE %]
+                            <option value="afternoon">Afternoon</option>
+                          [% END %]
+                          [% IF ( visit.day_segment == 'evening' ) %]
+                            <option value="evening" selected="selected">
+                              Evening
+                            </option>
+                          [% ELSE %]
+                            <option value="evening">Evening</option>
+                          [% END %]
+                        [% ELSE %]
+                          <option value="morning">Morning</option>
+                          <option value="afternoon">Afternoon</option>
+                          <option value="evening">Evening</option>
+                        [% END %]
+                      </select>
+                    </li>
+                    <li>
+                      <label for="chooser">Chooser:</label>
+                      <select id="chooser" name="chooser" required="required">
+                        <option value="">Select a chooser</option>
+                        [% IF ( visit ) %]
+                          [% FOREACH chooser IN choosers %]
+                            [% IF ( visit.chooser_brwnumber == chooser.borrowernumber ) %]
+                              <option value="[% chooser.borrowernumber %]" selected="selected">
+                                [% INCLUDE 'patron-title.inc' borrowernumber = chooser.borrowernumber category_type = chooser.categorycode firstname = chooser.firstname surname = chooser.surname othernames = chooser.othernames cardnumber = chooser.cardnumber invert_name = 0 %]
+                              </option>
+                            [% ELSE %]
+                              <option value="[% chooser.borrowernumber %]">
+                                [% INCLUDE 'patron-title.inc' borrowernumber = chooser.borrowernumber category_type = chooser.categorycode firstname = chooser.firstname surname = chooser.surname othernames = chooser.othernames cardnumber = chooser.cardnumber invert_name = 0 %]
+                              </option>
+                            [% END %]
+                          [% END %]
+                        [% ELSE %]
+                          [% FOREACH chooser IN choosers %]
+                            <option value="[% chooser.borrowernumber %]">
+                              [% INCLUDE 'patron-title.inc' borrowernumber = chooser.borrowernumber category_type = chooser.categorycode firstname = chooser.firstname surname = chooser.surname othernames = chooser.othernames cardnumber = chooser.cardnumber invert_name = 0 %]
+                            </option>
+                          [% END %]
+                        [% END %]
+                      </select>
+                    </li>
+                    <li>
+                      <label for="deliverer">Deliverer:</label>
+                      <select id="deliverer" name="deliverer" required="required">
+                        <option value="">Select a deliverer</option>
+                        [% IF ( visit ) %]
+                          [% FOREACH deliverer IN deliverers %]
+                            [% IF ( visit.deliverer_brwnumber == deliverer.borrowernumber ) %]
+                              <option value="[% deliverer.borrowernumber %]" selected="selected">
+                                [% INCLUDE 'patron-title.inc' borrowernumber = deliverer.borrowernumber category_type = deliverer.categorycode firstname = deliverer.firstname surname = deliverer.surname othernames = deliverer.othernames cardnumber = deliverer.cardnumber invert_name = 0 %]
+                              </option>
+                            [% ELSE %]
+                              <option value="[% deliverer.borrowernumber %]">
+                                [% INCLUDE 'patron-title.inc' borrowernumber = deliverer.borrowernumber category_type = deliverer.categorycode firstname = deliverer.firstname surname = deliverer.surname othernames = deliverer.othernames cardnumber = deliverer.cardnumber invert_name = 0 %]
+                              </option>
+                            [% END %]
+                          [% END %]
+                        [% ELSE %]
+                          [% FOREACH deliverer IN deliverers %]
+                            <option value="[% deliverer.borrowernumber %]">
+                              [% INCLUDE 'patron-title.inc' borrowernumber = deliverer.borrowernumber category_type = deliverer.categorycode firstname = deliverer.firstname surname = deliverer.surname othernames = deliverer.othernames cardnumber = deliverer.cardnumber invert_name = 0 %]
+                            </option>
+                          [% END %]
+                        [% END %]
+                      </select>
+                    </li>
+                  </ol>
+                </fieldset>
+                <fieldset class="action">
+                  <input type="submit" value="Save" name="save"
+                         onclick="console.log('Must validate form');" />
+                  <a class="cancel"
+                     href="/cgi-bin/koha/members/housebound.pl?borrowernumber=[% borrowernumber %]">
+                    Cancel
+                  </a>
+                </fieldset>
+              </form>
+
+            <!-- Display a housebound_profile -->
+            [% ELSIF ( housebound_profile ) %]
+              <div>
+                <ul class="toolbar">
+                  <li>
+                    <span class="yui-button yui-link-button first-child">
+                      <a href="/cgi-bin/koha/members/housebound.pl?borrowernumber=[% borrowernumber %]&method=update_or_create">
+                        Edit
+                      </a>
+                    </span>
+                  </li>
+                </ul>
+              </div>
+              <div class="rows">
+                <ol>
+                  <li>
+                    <span class="label">Delivery day:</span>
+                    [% 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 %]
+                  </li>
+                  <li>
+                    <span class="label">Frequency:</span>
+                    [% AuthorisedValues.GetByCode( 'HSBND_FREQ', housebound_profile.frequency, 0 ) || housebound_profile.frequency %]
+                  </li>
+                  <li>
+                    <span class="label">Material:</span>
+                    [% housebound_profile.fav_itemtypes %]
+                  </li>
+                  <li>
+                    <span class="label">Subjects:</span>
+                    [% housebound_profile.fav_subjects %]
+                  </li>
+                  <li>
+                    <span class="label">Authors:</span>
+                    [% housebound_profile.fav_authors %]
+                  </li>
+                  <li>
+                    <span class="label">Referral:</span>
+                    [% housebound_profile.referral %]
+                  </li>
+                  <li>
+                    <span class="label">Notes:</span>
+                    [% housebound_profile.notes %]
+                  </li>
+                </ol>
+              </div>
+              <div>
+                <h4>Deliveries</h4>
+                <div>
+                  <ul class="toolbar">
+                    <li>
+                      <span class="yui-button yui-link-button first-child">
+                        <a href="/cgi-bin/koha/members/housebound.pl?method=visit_update_or_create&borrowernumber=[% borrowernumber %]">
+                          Add a new delivery
+                        </a>
+                      </span>
+                    </li>
+                  </ul>
+                </div>
+                [% housebound_visits = housebound_profile.housebound_visits %]
+                [% IF  housebound_visits.size > 0 %]
+                <table border="0" width="100%" cellpadding="3" cellspacing="0">
+                  <tr>
+                    <th>ID</th><th>Date</th><th>Chooser</th><th>Deliverer</th><th>Actions</th>
+                  </tr>
+                    [% FOREACH entry IN housebound_visits %]
+                    <tr>
+                      <td>[% entry.id %]</td>
+                      <td>[% entry.appointment_date %] ([% entry.day_segment %])</td>
+                      <td>
+                        <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% entry.chooser.borrowernumber %]">
+                          [% 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 %]
+                        </a>
+                      </td>
+                      <td>
+                        <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% entry.deliverer.borrowernumber %]">
+                          [% 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 %]
+                        </a>
+                      </td>
+                      <td align="center">
+                        <a href="/cgi-bin/koha/members/housebound.pl?method=visit_update_or_create&visit_id=[% entry.id %]&borrowernumber=[% borrowernumber %]">
+                          Edit
+                        </a>
+                        |
+                        <a href="/cgi-bin/koha/members/housebound.pl?method=visit_delete&visit_id=[% entry.id %]&borrowernumber=[% borrowernumber %]">
+                          Delete
+                        </a>
+                      </td>
+                    </tr>
+                    [% END %]
+                </table>
+                [% END %]
+              </div>
+
+            [% END %]
+
+          </div>  <!-- End yui-u first -->
+        </div>    <!-- End yui-g -->
+      </div>
+    </div
+  </div>
+  <div class="yui-b">
+    [% INCLUDE 'circ-menu.inc' %]
+  </div>
+</div>
+[% INCLUDE 'intranet-bottom.inc' %]
diff --git a/members/housebound.pl b/members/housebound.pl
new file mode 100755 (executable)
index 0000000..f5ced86
--- /dev/null
@@ -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 <alex.sassmannshausen@ptfs-europe.com>
+
+=cut
diff --git a/t/db_dependent/Patron/Housebound.t b/t/db_dependent/Patron/Housebound.t
new file mode 100755 (executable)
index 0000000..320dd61
--- /dev/null
@@ -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 (file)
index 0000000..05d6392
--- /dev/null
@@ -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 <http://www.gnu.org/licenses>.
+
+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 (file)
index 0000000..bec556c
--- /dev/null
@@ -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 <http://www.gnu.org/licenses>.
+
+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;