[Koha-patches] [PATCH] patron attributes - staff search and display

Galen Charlton galen.charlton at liblime.com
Sat May 10 01:08:22 CEST 2008


If ExtendedPatronAttributes is ON, patron attributes
can be displayed and edited by staff members.

The patron attributes are displayed and edited
in a new section (step 4) of the patron details page.  Each
attribute is identified by its type (including type code
and type description) and value (included value description
if the attribute is controlled by an authorised value category).

Note: if, for a repeatable attribute type, the staff member
enters multiple copies of that type with the same value, duplicates
are removed when the patron record is saved.  Also, if the type
is repeatable, a JavaScript link allows the staff member to
create new attributes of that type.
---
 .../prog/en/modules/members/memberentrygen.tmpl    |   87 ++++++++++++++++
 .../prog/en/modules/members/moremember.tmpl        |   25 +++++-
 members/memberentry.pl                             |  107 +++++++++++++++++++-
 members/moremember.pl                              |    6 +
 4 files changed, 221 insertions(+), 4 deletions(-)

diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tmpl b/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tmpl
index 79327e5..ab93c57 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tmpl
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tmpl
@@ -22,6 +22,32 @@ patron <!-- TMPL_VAR NAME="surname" -->, <!-- TMPL_VAR name="firstname" --><!--
 		        document.form.city.value=RegExp.$2;					
 		});
 	 });
+
+    function clear_entry(node) {
+        var original = node.parentNode.parentNode;
+        $("input", original).attr('value', '');
+        $("select", original).attr('value', '');
+    }
+
+    function clone_entry(node) {
+        var original = node.parentNode.parentNode;
+        var clone = original.cloneNode(true);
+        var newId = 50 + parseInt(Math.random() * 100000);
+        $("input", clone).attr('id', function() {
+            return this.id.replace(/patron_attr_\d+/, 'patron_attr_' + newId);
+        });
+        $("input", clone).attr('name', function() {
+            return this.name.replace(/patron_attr_\d+/, 'patron_attr_' + newId);
+        });
+        $("select", clone).attr('id', function() {
+            return this.id.replace(/patron_attr_\d+/, 'patron_attr_' + newId);
+        });
+        $("select", clone).attr('name', function() {
+            return this.name.replace(/patron_attr_\d+/, 'patron_attr_' + newId);
+        });
+        original.parentNode.insertBefore(clone, original.nextSibling);
+    }
+
 //]]>
 </script>
 </head>
@@ -106,6 +132,10 @@ patron </strong><!-- /TMPL_IF --></div>
 			<!-- TMPL_IF NAME="ERROR_dateexpiry" -->
 				<li id="ERROR_dateexpiry">Date of expiration is invalid.</li>
 			<!-- /TMPL_IF -->
+            <!-- TMPL_IF NAME="ERROR_extended_unique_id_failed" -->
+                <li id="ERROR_extended_unique_id_failed">The attribute value 
+                    <!-- TMPL_VAR NAME="ERROR_extended_unique_id_failed" --> is already is use by another patron record.</li>
+			<!-- /TMPL_IF -->
 			</ul>
 		</div>
 	<!-- /TMPL_IF -->
@@ -793,6 +823,63 @@ patron </strong><!-- /TMPL_IF --></div>
 			</fieldset>
 		<!-- /TMPL_UNLESS -->	
 <!-- /TMPL_IF -->
+
+<!-- TMPL_IF NAME="step_4" --><!-- TMPL_IF NAME="ExtendedPatronAttributes" -->
+  <fieldset class="rows" id="memberentry_patron_attributes">
+    <input type="hidden" name="setting_extended_patron_attributes" value="1">
+    <legend>Additional attributes and identifiers</legend>
+    <!-- TMPL_IF NAME="no_patron_attribute_types" -->
+    No patron attribute types defined.
+    <!-- TMPL_ELSE -->
+    <table>
+        <tr>
+            <th>Type</th>
+            <th colspan="2">Value</th>
+        </tr>
+        <!-- TMPL_LOOP NAME='patron_attributes' -->
+        <tr>
+            <td><!-- TMPL_VAR NAME="code" --> (<!-- TMPL_VAR NAME="description" -->)
+            </td>
+            <td>
+                <input type="hidden" id="<!-- TMPL_VAR NAME="form_id" -->_code" name="<!-- TMPL_VAR NAME="form_id" -->_code"
+                       value="<!-- TMPL_VAR NAME="code" -->" />
+                <!-- TMPL_IF NAME="use_dropdown" -->
+                    <select id="<!-- TMPL_VAR NAME="form_id" -->" name="<!-- TMPL_VAR NAME="form_id" -->">
+                        <option value="" />
+                        <!-- TMPL_LOOP NAME="auth_val_loop" -->
+                            <!-- TMPL_IF NAME="selected" -->
+                                <option value="<!-- TMPL_VAR NAME="authorised_value" -->" selected="selected">
+                                    <!-- TMPL_VAR NAME="lib" -->
+                                </option>
+                            <!-- TMPL_ELSE -->
+                                <option value="<!-- TMPL_VAR NAME="authorised_value" -->" >
+                                    <!-- TMPL_VAR NAME="lib" -->
+                                </option>
+                            <!-- /TMPL_IF -->
+                        <!-- /TMPL_LOOP -->
+                    </select>
+                <!-- TMPL_ELSE -->
+                    <input type="text" maxlength="30" value="<!-- TMPL_VAR NAME="value" -->"
+                           id="<!-- TMPL_VAR NAME="form_id" -->" name="<!-- TMPL_VAR NAME="form_id" -->" />
+                <!-- /TMPL_IF -->
+                <!-- TMPL_IF NAME="password_allowed" -->
+                    (Password: <input type="password" maxlength="30" value="<!-- TMPL_VAR NAME="password" -->"
+                           id="<!-- TMPL_VAR NAME="form_id" -->_password" name="<!-- TMPL_VAR NAME="form_id" -->_password" />)
+                <!-- /TMPL_IF -->
+            </td>
+            <td>
+                <a href="#" onclick="clear_entry(this); return false;">Clear</a>
+                <!-- TMPL_IF NAME="repeatable" -->
+                <a href="#" onclick="clone_entry(this); return false;">New</a>
+                <!-- /TMPL_IF -->
+            </td>
+        </tr>
+        <!-- /TMPL_LOOP -->
+    </table>
+    <!-- /TMPL_IF -->
+  </fieldset>
+<!-- /TMPL_IF--><!-- /TMPL_IF -->
+
     <fieldset class="action">
         <input type="submit" name="save" onclick="return check_form_borrowers();" value="Save" />
       <!-- TMPL_IF NAME="opadd" -->
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tmpl b/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tmpl
index e284f65..c3baf79 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tmpl
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tmpl
@@ -227,6 +227,29 @@ if (nodename =="barcodes[]"){
 
 <!-- End Upload Patron Image Section -->
 
+<!-- TMPL_IF NAME="ExtendedPatronAttributes" -->
+<div id="patron-extended-attributes" style="padding-top: 1em;">
+<h3>Additional attributes and identifiers</h3>
+<table>
+    <tr>
+        <th>Type</th>
+        <th>Value</th>
+    </tr>
+    <!-- TMPL_LOOP NAME="patron_attributes" -->
+    <tr>
+        <td><!-- TMPL_VAR NAME="code" --> (<!-- TMPL_VAR NAME="description" -->)</td>
+        <td><!-- TMPL_VAR NAME="value" -->
+            <!-- TMPL_IF NAME="value_description" -->
+                (<!-- TMPL_VAR NAME="value_description" -->)
+            <!-- /TMPL_IF -->
+        </td>
+    </tr>
+    <!-- /TMPL_LOOP -->
+</table>
+</div>
+<div class="action"><a href="memberentry.pl?op=modify&amp;borrowernumber=<!-- TMPL_VAR NAME="borrowernumber" -->&amp;step=4">Edit</a></div>
+<!-- /TMPL_IF -->
+
 </div>
  <div class="yui-u"> 
  <div id="patron-library-details">
@@ -292,7 +315,7 @@ if (nodename =="barcodes[]"){
     <li><span class="label">Phone: </span><!-- TMPL_VAR NAME="altcontactphone" --></li></ol></div>
 </div>
 <div class="action"><a href="memberentry.pl?op=modify&amp;borrowernumber=<!-- TMPL_VAR NAME="borrowernumber" -->&amp;step=2">Edit</a></div>
- 
+
 </div>
 </div>
 
diff --git a/members/memberentry.pl b/members/memberentry.pl
index 5cc8c00..4ca7034 100755
--- a/members/memberentry.pl
+++ b/members/memberentry.pl
@@ -29,6 +29,8 @@ use C4::Auth;
 use C4::Context;
 use C4::Output;
 use C4::Members;
+use C4::Members::Attributes;
+use C4::Members::AttributeTypes;
 use C4::Koha;
 use C4::Dates qw/format_date format_date_in_iso/;
 use C4::Input;
@@ -180,6 +182,7 @@ if ( (defined $newdata{'userid'}) && ($newdata{'userid'} eq '')){
   
 $debug and warn join "\t", map {"$_: $newdata{$_}"} qw(dateofbirth dateenrolled dateexpiry);
 my $loginexist=0;
+my $extended_patron_attributes = ();
 if ($op eq 'save' || $op eq 'insert'){
   if (checkcardnumber($newdata{cardnumber},$newdata{borrowernumber})){ 
     push @errors, 'ERROR_cardnumber';
@@ -207,6 +210,16 @@ if ($op eq 'save' || $op eq 'insert'){
     push @errors, "ERROR_login_exist";
     $loginexist=1; 
   }
+
+  if (C4::Context->preference('ExtendedPatronAttributes')) {
+    $extended_patron_attributes = parse_extended_patron_attributes($input);
+    foreach my $attr (@$extended_patron_attributes) {
+        unless (C4::Members::Attributes::CheckUniqueness($attr->{code}, $attr->{value}, $borrowernumber)) {
+            push @errors, "ERROR_extended_unique_id_failed";
+            $template->param(ERROR_extended_unique_id_failed => "$attr->{code}/$attr->{value}");
+        }
+    }
+  }
 }
 
 if ($op eq 'modify' || $op eq 'insert'){
@@ -229,12 +242,18 @@ if ((!$nok) and ($op eq 'insert' or $op eq 'save')){
 			my @orgs=split(/\|/,$data{'organisations'});
 			add_member_orgs($borrowernumber,\@orgs);
 		}
+        if (C4::Context->preference('ExtendedPatronAttributes') and $input->param('setting_extended_patron_attributes')) {
+            C4::Members::Attributes::SetBorrowerAttributes($borrowernumber, $extended_patron_attributes);
+        }
 	} elsif ($op eq 'save'){ 
 		if ($NoUpdateLogin) {
 			delete $newdata{'password'};
 			delete $newdata{'userid'};
 		}
 		&ModMember(%newdata);    
+        if (C4::Context->preference('ExtendedPatronAttributes') and $input->param('setting_extended_patron_attributes')) {
+            C4::Members::Attributes::SetBorrowerAttributes($borrowernumber, $extended_patron_attributes);
+        }
 	}
 	print scalar ($destination eq "circ") ? 
 		$input->redirect("/cgi-bin/koha/circ/circulation.pl?borrowernumber=$borrowernumber") :
@@ -253,7 +272,7 @@ if ($nok){
   %data=%newdata; 
   $template->param( updtype => ($op eq 'add' ?'I':'M'));	# used to check for $op eq "insert"... but we just changed $op!
   unless ($step){  
-    $template->param( step_1 => 1,step_2 => 1,step_3 => 1);
+    $template->param( step_1 => 1,step_2 => 1,step_3 => 1, step_4 => 1);
   }  
 } 
 if (C4::Context->preference("IndependantBranches")) {
@@ -268,12 +287,12 @@ if (C4::Context->preference("IndependantBranches")) {
 if ($op eq 'add'){
 	my $arg2 = $newdata{'dateenrolled'} || C4::Dates->today('iso');
 	$data{'dateexpiry'} = GetExpiryDate($newdata{'categorycode'},$arg2);
-	$template->param( updtype => 'I',step_1=>1,step_2=>1,step_3=>1);
+	$template->param( updtype => 'I',step_1=>1,step_2=>1,step_3=>1, step_4 => 1);
 	
 } 
 if ($op eq "modify")  {
   $template->param( updtype => 'M',modify => 1 );
-  $template->param( step_1=>1,step_2=>1,step_3=>1) unless $step;
+  $template->param( step_1=>1,step_2=>1,step_3=>1, step_4 => 1) unless $step;
 }
 # my $cardnumber=$data{'cardnumber'};
 $data{'cardnumber'}=fixup_cardnumber($data{'cardnumber'}) if $op eq 'add';
@@ -482,6 +501,11 @@ foreach (qw(dateenrolled dateexpiry dateofbirth)) {
 	$template->param( $_ => $data{$_});
 }
 
+if (C4::Context->preference('ExtendedPatronAttributes')) {
+    $template->param(ExtendedPatronAttributes => 1);
+    patron_attributes_form($template, $borrowernumber);
+}
+
 $template->param( "showguarantor"  => ($category_type=~/A|I|S|X/) ? 0 : 1); # associate with step to know where you are
 $debug and warn "memberentry step: $step";
 $template->param(%data);
@@ -522,6 +546,83 @@ $template->param(
   
 output_html_with_http_headers $input, $cookie, $template->output;
 
+sub  parse_extended_patron_attributes {
+    my ($input) = @_;
+    my @patron_attr = grep { /^patron_attr_\d+$/ } $input->param();
+
+    my @attr = ();
+    my %dups = ();
+    foreach my $key (@patron_attr) {
+        my $value = $input->param($key);
+        next unless defined($value) and $value ne '';
+        my $password = $input->param("${key}_password");
+        my $code = $input->param("${key}_code");
+        next if exists $dups{$code}->{$value};
+        $dups{$code}->{$value} = 1;
+        push @attr, { code => $code, value => $value, password => $password };
+    }
+    return \@attr;
+}
+
+sub patron_attributes_form {
+    my $template = shift;
+    my $borrowernumber = shift;
+
+    my @types = C4::Members::AttributeTypes::GetAttributeTypes();
+    if (scalar(@types) == 0) {
+        $template->param(no_patron_attribute_types => 1);
+        return;
+    }
+    my $attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber);
+
+    # map patron's attributes into a more convenient structure
+    my %attr_hash = ();
+    foreach my $attr (@$attributes) {
+        push @{ $attr_hash{$attr->{code}} }, $attr;
+    }
+
+    my @attribute_loop = ();
+    my $i = 0;
+    foreach my $type_code (map { $_->{code} } @types) {
+        my $attr_type = C4::Members::AttributeTypes->fetch($type_code);
+        my $entry = {
+            code              => $attr_type->code(),
+            description       => $attr_type->description(),
+            repeatable        => $attr_type->repeatable(),
+            password_allowed  => $attr_type->password_allowed(),
+            category          => $attr_type->authorised_value_category(),
+            password          => '',
+        };
+        if (exists $attr_hash{$attr_type->code()}) {
+            foreach my $attr (@{ $attr_hash{$attr_type->code()} }) {
+                my $newentry = { map { $_ => $entry->{$_} } %$entry };
+                $newentry->{value} = $attr->{value};
+                $newentry->{password} = $attr->{password};
+                $newentry->{use_dropdown} = 0;
+                if ($attr_type->authorised_value_category()) {
+                    $newentry->{use_dropdown} = 1;
+                    $newentry->{auth_val_loop} = GetAuthorisedValues($attr_type->authorised_value_category(), $attr->{value});
+                }
+                $i++;
+                $newentry->{form_id} = "patron_attr_$i";
+                #use Data::Dumper; die Dumper($entry) if  $entry->{use_dropdown};
+                push @attribute_loop, $newentry;
+            }
+        } else {
+            $i++;
+            my $newentry = { map { $_ => $entry->{$_} } %$entry };
+            if ($attr_type->authorised_value_category()) {
+                $newentry->{use_dropdown} = 1;
+                $newentry->{auth_val_loop} = GetAuthorisedValues($attr_type->authorised_value_category());
+            }
+            $newentry->{form_id} = "patron_attr_$i";
+            push @attribute_loop, $newentry;
+        }
+    }
+    $template->param(patron_attributes => \@attribute_loop);
+
+}
+
 # Local Variables:
 # tab-width: 8
 # End:
diff --git a/members/moremember.pl b/members/moremember.pl
index 22a56ef..1b66b44 100755
--- a/members/moremember.pl
+++ b/members/moremember.pl
@@ -37,6 +37,7 @@ use C4::Context;
 use C4::Auth;
 use C4::Output;
 use C4::Members;
+use C4::Members::Attributes;
 use C4::Dates;
 use C4::Reserves;
 use C4::Circulation;
@@ -335,6 +336,11 @@ my $branch=C4::Context->userenv->{'branch'};
 
 $template->param($data);
 
+if (C4::Context->preference('ExtendedPatronAttributes')) {
+    $template->param(ExtendedPatronAttributes => 1);
+    $template->param(patron_attributes => C4::Members::Attributes::GetBorrowerAttributes($borrowernumber));
+}
+
 $template->param(
 	detailview => 1,
   DHTMLcalendar_dateformat=>C4::Dates->DHTMLcalendar(), 
-- 
1.5.5.rc0.16.g02b00




More information about the Koha-patches mailing list