This patch adds code to validate column names in the CSV
header row against the current columns in the borrowers
table as well as additional valid columns.

It also adds error trapping to prevent import of files with
fatal errors such as unparsable header rows and invalid
column names.
---
 C4/Members.pm                                      |   22 ++
 .../prog/en/includes/error-messages.inc            |   17 +
 .../prog/en/modules/tools/import_borrowers.tmpl    |    4 +-
 tools/import_borrowers.pl                          |  335 +++++++++++---------
 4 files changed, 229 insertions(+), 149 deletions(-)

diff --git a/C4/Members.pm b/C4/Members.pm
index 98adc27..f492336 100644
--- a/C4/Members.pm
+++ b/C4/Members.pm
@@ -2189,6 +2189,28 @@ sub DeleteMessage {
 
 }
 
+=head2 get_borrower_table_fields
+
+=over 4
+
+...@field_list = get_borrower_table_fields();
+
+=back
+
+=cut
+
+sub get_borrower_table_fields {
+        my $dbh = C4::Context->dbh;
+        my $query = "DESCRIBE borrowers";
+        my $sth = $dbh->prepare($query);
+        $sth->execute();
+        my $columns = [];
+        while (my $row = $sth->fetchrow_hashref) {
+                push @$columns, $row;
+            }
+            return $columns;
+        }
+
 END { }    # module clean-up code here (global destructor)
 
 1;
diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/error-messages.inc 
b/koha-tmpl/intranet-tmpl/prog/en/includes/error-messages.inc
index 7eb0fe8..1dcbc6c 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/includes/error-messages.inc
+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/error-messages.inc
@@ -71,22 +71,26 @@ window.onload=function(){
 <div id='mypopup' name='mypopup' style='position: absolute; width: 400px; 
height: 131px; display: none; background: #FFC 
url(/intranet-tmpl/prog/img/alert-bg.gif) repeat-x left 0; border: 1px solid 
#bcbcbc; right: 0px; top: 500px'>
     <span id="message" style="position: absolute; top: 5px; left: 5px;">
     <strong style="color: #900;">WARNING:</strong>
+        <!-- NOTE: 100 Errors apply to creator database operations. -->
         <!-- TMPL_IF NAME="101" -->
         The database returned an error while <!-- TMPL_IF NAME="card_element" 
-->saving <!-- TMPL_VAR NAME="card_element" --> <!-- TMPL_VAR NAME="element_id" 
--><!-- TMPL_ELSE -->attempting a save operation<!-- /TMPL_IF -->. Please have 
your system administrator check the error log for details.
         <!-- TMPL_ELSIF NAME="102" -->
         The database returned an error while <!-- TMPL_IF NAME="card_element" 
-->deleteing <!-- TMPL_VAR NAME="card_element" --> <!-- TMPL_VAR 
NAME="element_id" --><!-- TMPL_ELSIF NAME=image_ids --><!-- TMPL_VAR 
NAME="image_ids" --><!-- TMPL_ELSE -->attempting a delete operation<!-- 
/TMPL_IF -->. Please have your system administrator check the error log for 
details.
+        <!-- NOTE: 200 Errors apply to creator manage scripts. -->
         <!-- TMPL_ELSIF NAME="201" -->
         An unsupported operation was attempted<!-- TMPL_IF NAME="element_id" 
--> on <!-- TMPL_VAR NAME="card_element" --> <!-- TMPL_VAR NAME="element_id" 
--><!-- /TMPL_IF -->. Please have your system administrator check the error log 
for details.
         <!-- TMPL_ELSIF NAME="202" -->
         An error has occurred. Please ask your system administrator to check 
the error log for more details.
         <!-- TMPL_ELSIF NAME="203" -->
         A non-existent or invalid branch code was supplied. Please <a 
href="/cgi-bin/koha/circ/selectbranchprinter.pl">verify</a> that you have a 
branch selected.
+        <!-- NOTE: 300 Errors apply to image upload scripts. -->
         <!-- TMPL_ELSIF NAME="301" -->
         An error has occurred while attempting to upload the image file. 
Please ask you system administrator to check the error log for more details.
         <!-- TMPL_ELSIF NAME="302" -->
         Image exceeds 500KB. Please resize and import again.
         <!-- TMPL_ELSIF NAME="303" -->
         The database image quota currently only allows a maximum of <!-- 
TMPL_VAR NAME="image_limit" --> images to be stored at any one time. Please 
delete one or more images to free up quota space.
+        <!-- NOTE: 400 Errors apply to creator batch scripts. -->
         <!-- TMPL_ELSIF NAME="401" -->
         An error has occurred and the item(s) was not added to batch <!-- 
TMPL_VAR NAME="batch_id" -->. Please have your system administrator check the 
error log for details.
         <!-- TMPL_ELSIF NAME="402" -->
@@ -97,6 +101,19 @@ window.onload=function(){
         An error has occurred and batch <!-- TMPL_VAR NAME="batch_id" --> was 
not deleted.  Please have your system administrator check the error log for 
details.
         <!-- TMPL_ELSIF NAME="405" -->
         An error has occurred and batch <!-- TMPL_VAR NAME="batch_id" --> not 
fully de-duplicated.
+        <!-- NOTE: 500 Errors apply to the import_borrowers.pl script. -->
+        <!-- TMPL_ELSIF NAME="501" -->
+        The uploaded CSV file contains the following invalid column name(s):
+            <div style="margin: 3px;">
+            <ul>
+            <!-- TMPL_LOOP NAME="errors" -->
+                <li><b><!-- TMPL_VAR NAME="column" --></b></li>
+            <!-- /TMPL_LOOP -->
+            </ul>
+            </div>
+        Please correct and re-import.
+        <!-- TMPL_ELSIF NAME="502" -->
+        Header row could not be parsed. Please correct and re-import.
         <!-- TMPL_ELSE -->
         <!-- /TMPL_IF -->
     </span>
diff --git 
a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/import_borrowers.tmpl 
b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/import_borrowers.tmpl
index e71fc5f..0e0e97b 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/import_borrowers.tmpl
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/import_borrowers.tmpl
@@ -17,6 +17,7 @@
  <div id="bd">
   <div id="yui-main">
    <div class="yui-b">
+    <!-- TMPL_INCLUDE NAME="error-messages.inc" -->
     <div class="yui-g">
      <div class="yui-u first">
 <h1>Import Patrons</h1>
@@ -53,7 +54,6 @@
     <h5>Error analysis:</h5>
     <ul>
     <!-- TMPL_LOOP NAME="ERRORS" -->
-        <!-- TMPL_IF NAME="badheader" --><li>Header row could not be 
parsed</li><!-- /TMPL_IF -->
         <!-- TMPL_LOOP NAME="missing_criticals" -->
         <li class="line_error">
             Line <span class="linenumber"><!-- TMPL_VAR NAME="line" --></span>
@@ -147,7 +147,7 @@
     <!-- TMPL_LOOP name="columnkeys" -->'<!-- TMPL_VAR name="key" -->', <!-- 
/TMPL_LOOP -->
 </li></ul></li>
 <!-- TMPL_IF NAME="ExtendedPatronAttributes" -->
-<li>If loading patron attributes, the 'patron_attributes' field should contain 
a comma-separated list of attribute types 
+<li>If loading patron attributes, the 'patron_attributes' field should contain 
a comma-separated list of attribute types
 and values.  The attribute type code and a ':' should precede each value. For 
example: &quot;INSTID:12345,LANG:fr&quot;.  This
 means that if an input record has more than one attribute, the 
'patron_attributes' field must be wrapped in double quotation marks.
 </li>
diff --git a/tools/import_borrowers.pl b/tools/import_borrowers.pl
index 1baf079..f0fd9aa 100755
--- a/tools/import_borrowers.pl
+++ b/tools/import_borrowers.pl
@@ -46,6 +46,7 @@ use C4::Members::Attributes qw(:all);
 use C4::Members::AttributeTypes;
 use C4::Members::Messaging;
 
+use autouse 'Data::Dumper' => qw(Dumper);
 use Text::CSV;
 # Text::CSV::Unicode, even in binary mode, fails to parse lines with these 
diacriticals:
 # ė
@@ -55,6 +56,8 @@ use CGI;
 # use encoding 'utf8';    # don't do this
 
 my (@errors, @feedback);
+my $errstr= 0;
+my $invalid_columns = [];
 my $extended = C4::Context->preference('ExtendedPatronAttributes');
 my $set_messaging_prefs = 
C4::Context->preference('EnhancedMessagingPreferences');
 my @columnkeys = C4::Members->columns;
@@ -109,13 +112,23 @@ if ( $uploadborrowers && length($uploadborrowers) > 0 ) {
     my $alreadyindb = 0;
     my $overwritten = 0;
     my $invalid     = 0;
-    my $matchpoint_attr_type; 
+    my $matchpoint_attr_type;
     my %defaults = $input->Vars;
 
     # use header line to construct key to column map
     my $borrowerline = <$handle>;
     my $status = $csv->parse($borrowerline);
-    ($status) or push @errors, {badheader=>1,line=>$., lineraw=>$borrowerline};
+    if (!$status) {
+        push @errors, {badheader => 1};
+        $errstr = 502;
+        $template->param(
+                        error           => ($errstr ? 1 : 0),
+                        $errstr         => 1,
+                        errors          => \...@errors,
+        );
+        output_html_with_http_headers $input, $cookie, $template->output;
+        exit; # fatal so bail here
+    }
     my @csvcolumns = $csv->fields();
     my %csvkeycol;
     my $col = 0;
@@ -124,173 +137,195 @@ if ( $uploadborrowers && length($uploadborrowers) > 0 ) 
{
        $keycol =~ s/ +//g;
         $csvkeycol{$keycol} = $col++;
     }
-    #warn($borrowerline);
-    my $ext_preserve = $input->param('ext_preserve') || 0;
-    if ($extended) {
-        $matchpoint_attr_type = 
C4::Members::AttributeTypes->fetch($matchpoint);
-    }
-
-    push @feedback, {feedback=>1, name=>'headerrow', value=>join(', ', 
@csvcolumns)};
-    my $today_iso = C4::Dates->new()->output('iso');
-    my @criticals = qw(surname branchcode categorycode);    # there probably 
should be others
-    my @bad_dates;  # I've had a few.
-    my $date_re = C4::Dates->new->regexp('syspref');
-    my  $iso_re = C4::Dates->new->regexp('iso');
-    LINE: while ( my $borrowerline = <$handle> ) {
-        my %borrower;
-        my @missing_criticals;
-        my $patron_attributes;
-        my $status  = $csv->parse($borrowerline);
-        my @columns = $csv->fields();
-        if (! $status) {
-            push @missing_criticals, {badparse=>1, line=>$., 
lineraw=>$borrowerline};
-        } elsif (@columns == @columnkeys) {
-            @borrow...@columnkeys} = @columns;
-            # MJR: try to fill blanks gracefully by using default values
-            foreach my $key (@criticals) {
-                if ($borrower{$key} !~ /\S/) {
-                    $borrower{$key} = $defaults{$key};
-                }
-            } 
-        } else {
-            # MJR: try to recover gracefully by using default values
-            foreach my $key (@columnkeys) {
-               if (defined($csvkeycol{$key}) and $columns[$csvkeycol{$key}] =~ 
/\S/) { 
-                   $borrower{$key} = $columns[$csvkeycol{$key}];
-               } elsif ( $defaults{$key} ) {
-                   $borrower{$key} = $defaults{$key};
-               } elsif ( scalar grep {$key eq $_} @criticals ) {
-                   # a critical field is undefined
-                   push @missing_criticals, {key=>$key, line=>$., 
lineraw=>$borrowerline};
-               } else {
-                       $borrower{$key} = '';
-               }
-            }
-        }
-        #warn join(':',%borrower);
-        if ($borrower{categorycode}) {
-            push @missing_criticals, {key=>'categorycode', line=>$. , 
lineraw=>$borrowerline, value=>$borrower{categorycode}, category_map=>1}
-                unless GetBorrowercategory($borrower{categorycode});
-        } else {
-            push @missing_criticals, {key=>'categorycode', line=>$. , 
lineraw=>$borrowerline};
-        }
-        if ($borrower{branchcode}) {
-            push @missing_criticals, {key=>'branchcode', line=>$. , 
lineraw=>$borrowerline, value=>$borrower{branchcode}, branch_map=>1}
-                unless GetBranchName($borrower{branchcode});
-        } else {
-            push @missing_criticals, {key=>'branchcode', line=>$. , 
lineraw=>$borrowerline};
-        }
-        if (@missing_criticals) {
-            foreach (@missing_criticals) {
-                $_->{borrowernumber} = $borrower{borrowernumber} || 'UNDEF';
-                $_->{surname}        = $borrower{surname} || 'UNDEF';
-            }
-            $invalid++;
-            (25 > scalar @errors) and push @errors, 
{missing_criticals=>\...@missing_criticals};
-            # The first 25 errors are enough.  Keeping track of 30,000+ would 
destroy performance.
-            next LINE;
+#   verify submitted columns against actual borrowers table columns and 
additional valid columns
+    my $valid_columns = get_borrower_table_fields;
+    push @$valid_columns, {Field => 'patron_attributes'}; # add valid columns 
not in borrowers table here
+    my $valid = 0;
+    foreach (keys %csvkeycol) {
+        foreach my $column (@$valid_columns) {
+            $valid = 1 if $column->{'Field'} eq $_;
         }
+        push @errors, {column => $_} if !$valid;
+        $valid = 0;
+    }
+    if (@errors) {
+        $errstr = 501;
+        $template->param(
+                        error           => ($errstr ? 1 : 0),
+                        $errstr         => 1,
+                        errors          => \...@errors,
+        );
+        output_html_with_http_headers $input, $cookie, $template->output;
+        exit; # fatal so bail here
+    }
+    unless ($errstr) {
+        my $ext_preserve = $input->param('ext_preserve') || 0;
         if ($extended) {
-            my $attr_str = $borrower{patron_attributes};
-            delete $borrower{patron_attributes};    # not really a field in 
borrowers, so we don't want to pass it to ModMember.
-            $patron_attributes = 
extended_attributes_code_value_arrayref($attr_str); 
+            $matchpoint_attr_type = 
C4::Members::AttributeTypes->fetch($matchpoint);
         }
-       # Popular spreadsheet applications make it difficult to force date 
outputs to be zero-padded, but we require it.
-        foreach (qw(dateofbirth dateenrolled dateexpiry)) {
-            my $tempdate = $borrower{$_} or next;
-            if ($tempdate =~ /$date_re/) {
-                $borrower{$_} = format_date_in_iso($tempdate);
-            } elsif ($tempdate =~ /$iso_re/) {
-                $borrower{$_} = $tempdate;
+
+        push @feedback, {feedback=>1, name=>'headerrow', value=>join(', ', 
@csvcolumns)};
+        my $today_iso = C4::Dates->new()->output('iso');
+        my @criticals = qw(surname branchcode categorycode);    # there 
probably should be others
+        my @bad_dates;  # I've had a few.
+        my $date_re = C4::Dates->new->regexp('syspref');
+        my  $iso_re = C4::Dates->new->regexp('iso');
+        LINE: while ( my $borrowerline = <$handle> ) {
+            my %borrower;
+            my @missing_criticals;
+            my $patron_attributes;
+            my $status  = $csv->parse($borrowerline);
+            my @columns = $csv->fields();
+            if (! $status) {
+                push @missing_criticals, {badparse=>1, line=>$., 
lineraw=>$borrowerline};
+            } elsif (@columns == @columnkeys) {
+                @borrow...@columnkeys} = @columns;
+                # MJR: try to fill blanks gracefully by using default values
+                foreach my $key (@criticals) {
+                    if ($borrower{$key} !~ /\S/) {
+                        $borrower{$key} = $defaults{$key};
+                    }
+                }
             } else {
-                $borrower{$_} = '';
-                push @missing_criticals, {key=>$_, line=>$. , 
lineraw=>$borrowerline, bad_date=>1};
-            }
-        }
-       $borrower{dateenrolled} = $today_iso unless $borrower{dateenrolled};
-       $borrower{dateexpiry} = 
GetExpiryDate($borrower{categorycode},$borrower{dateenrolled}) unless 
$borrower{dateexpiry}; 
-        my $borrowernumber;
-        my $member;
-        if ( ($matchpoint eq 'cardnumber') && ($borrower{'cardnumber'}) ) {
-            $member = GetMember( 'cardnumber' => $borrower{'cardnumber'} );
-            if ($member) {
-                $borrowernumber = $member->{'borrowernumber'};
-            }
-        } elsif ($extended) {
-            if (defined($matchpoint_attr_type)) {
-                foreach my $attr (@$patron_attributes) {
-                    if ($attr->{code} eq $matchpoint and $attr->{value} ne '') 
{
-                        my @borrowernumbers = 
$matchpoint_attr_type->get_patrons($attr->{value});
-                        $borrowernumber = $borrowernumbers[0] if 
scalar(@borrowernumbers) == 1;
-                        last;
+                # MJR: try to recover gracefully by using default values
+                foreach my $key (@columnkeys) {
+                    if (defined($csvkeycol{$key}) and 
$columns[$csvkeycol{$key}] =~ /\S/) {
+                        $borrower{$key} = $columns[$csvkeycol{$key}];
+                    } elsif ( $defaults{$key} ) {
+                        $borrower{$key} = $defaults{$key};
+                    } elsif ( scalar grep {$key eq $_} @criticals ) {
+                        # a critical field is undefined
+                        push @missing_criticals, {key=>$key, line=>$., 
lineraw=>$borrowerline};
+                    } else {
+                        $borrower{$key} = '';
                     }
                 }
             }
-        }
-            
-        if ($borrowernumber) {
-            # borrower exists
-            unless ($overwrite_cardnumber) {
-                $alreadyindb++;
-                $template->param('lastalreadyindb'=>$borrower{'surname'}.' / 
'.$borrowernumber);
-                next LINE;
+            #warn join(':',%borrower);
+            if ($borrower{categorycode}) {
+                push @missing_criticals, {key=>'categorycode', line=>$. , 
lineraw=>$borrowerline, value=>$borrower{categorycode}, category_map=>1}
+                    unless GetBorrowercategory($borrower{categorycode});
+            } else {
+                push @missing_criticals, {key=>'categorycode', line=>$. , 
lineraw=>$borrowerline};
             }
-            $borrower{'borrowernumber'} = $borrowernumber;
-            for my $col (keys %borrower) {
-                # use values from extant patron unless our csv file includes 
this column or we provided a default.
-                # FIXME : You cannot update a field with a  perl-evaluated 
false value using the defaults.
-                unless(exists($csvkeycol{$col}) || $defaults{$col}) {
-                    $borrower{$col} = $member->{$col} if($member->{$col}) ;
-                }
+            if ($borrower{branchcode}) {
+                push @missing_criticals, {key=>'branchcode', line=>$. , 
lineraw=>$borrowerline, value=>$borrower{branchcode}, branch_map=>1}
+                    unless GetBranchName($borrower{branchcode});
+            } else {
+                push @missing_criticals, {key=>'branchcode', line=>$. , 
lineraw=>$borrowerline};
             }
-            unless (ModMember(%borrower)) {
+            if (@missing_criticals) {
+                foreach (@missing_criticals) {
+                    $_->{borrowernumber} = $borrower{borrowernumber} || 
'UNDEF';
+                    $_->{surname}        = $borrower{surname} || 'UNDEF';
+                }
                 $invalid++;
-                $template->param('lastinvalid'=>$borrower{'surname'}.' / 
'.$borrowernumber);
+                (25 > scalar @errors) and push @errors, 
{missing_criticals=>\...@missing_criticals};
+                # The first 25 errors are enough.  Keeping track of 30,000+ 
would destroy performance.
                 next LINE;
             }
             if ($extended) {
-                if ($ext_preserve) {
-                    my $old_attributes = 
GetBorrowerAttributes($borrowernumber);
-                    $patron_attributes = 
extended_attributes_merge($old_attributes, $patron_attributes);  #TODO: expose 
repeatable options in template
+                my $attr_str = $borrower{patron_attributes};
+                delete $borrower{patron_attributes};    # not really a field 
in borrowers, so we don't want to pass it to ModMember.
+                $patron_attributes = 
extended_attributes_code_value_arrayref($attr_str);
+            }
+        # Popular spreadsheet applications make it difficult to force date 
outputs to be zero-padded, but we require it.
+            foreach (qw(dateofbirth dateenrolled dateexpiry)) {
+                my $tempdate = $borrower{$_} or next;
+                if ($tempdate =~ /$date_re/) {
+                    $borrower{$_} = format_date_in_iso($tempdate);
+                } elsif ($tempdate =~ /$iso_re/) {
+                    $borrower{$_} = $tempdate;
+                } else {
+                    $borrower{$_} = '';
+                    push @missing_criticals, {key=>$_, line=>$. , 
lineraw=>$borrowerline, bad_date=>1};
                 }
-                SetBorrowerAttributes($borrower{'borrowernumber'}, 
$patron_attributes);
             }
-            $overwritten++;
-            $template->param('lastoverwritten'=>$borrower{'surname'}.' / 
'.$borrowernumber);
-        } else {
-            # FIXME: fixup_cardnumber says to lock table, but the web 
interface doesn't so this doesn't either.
-            # At least this is closer to AddMember than in 
members/memberentry.pl
-            if (!$borrower{'cardnumber'}) {
-                $borrower{'cardnumber'} = fixup_cardnumber(undef);
+        $borrower{dateenrolled} = $today_iso unless $borrower{dateenrolled};
+        $borrower{dateexpiry} = 
GetExpiryDate($borrower{categorycode},$borrower{dateenrolled}) unless 
$borrower{dateexpiry};
+            my $borrowernumber;
+            my $member;
+            if ( ($matchpoint eq 'cardnumber') && ($borrower{'cardnumber'}) ) {
+                $member = GetMember( 'cardnumber' => $borrower{'cardnumber'} );
+                if ($member) {
+                    $borrowernumber = $member->{'borrowernumber'};
+                }
+            } elsif ($extended) {
+                if (defined($matchpoint_attr_type)) {
+                    foreach my $attr (@$patron_attributes) {
+                        if ($attr->{code} eq $matchpoint and $attr->{value} ne 
'') {
+                            my @borrowernumbers = 
$matchpoint_attr_type->get_patrons($attr->{value});
+                            $borrowernumber = $borrowernumbers[0] if 
scalar(@borrowernumbers) == 1;
+                            last;
+                        }
+                    }
+                }
             }
-            if ($borrowernumber = AddMember(%borrower)) {
-                if ($extended) {
-                    SetBorrowerAttributes($borrowernumber, $patron_attributes);
+
+            if ($borrowernumber) {
+                # borrower exists
+                unless ($overwrite_cardnumber) {
+                    $alreadyindb++;
+                    $template->param('lastalreadyindb'=>$borrower{'surname'}.' 
/ '.$borrowernumber);
+                    next LINE;
+                }
+                $borrower{'borrowernumber'} = $borrowernumber;
+                for my $col (keys %borrower) {
+                    # use values from extant patron unless our csv file 
includes this column or we provided a default.
+                    # FIXME : You cannot update a field with a  perl-evaluated 
false value using the defaults.
+                    unless(exists($csvkeycol{$col}) || $defaults{$col}) {
+                        $borrower{$col} = $member->{$col} if($member->{$col}) ;
+                    }
+                }
+                unless (ModMember(%borrower)) {
+                    $invalid++;
+                    $template->param('lastinvalid'=>$borrower{'surname'}.' / 
'.$borrowernumber);
+                    next LINE;
                 }
-                if ($set_messaging_prefs) {
-                    
C4::Members::Messaging::SetMessagingPreferencesFromDefaults({ borrowernumber => 
$borrowernumber,
-                                                                               
   categorycode => $borrower{categorycode} });
+                if ($extended) {
+                    if ($ext_preserve) {
+                        my $old_attributes = 
GetBorrowerAttributes($borrowernumber);
+                        $patron_attributes = 
extended_attributes_merge($old_attributes, $patron_attributes);  #TODO: expose 
repeatable options in template
+                    }
+                    SetBorrowerAttributes($borrower{'borrowernumber'}, 
$patron_attributes);
                 }
-                $imported++;
-                $template->param('lastimported'=>$borrower{'surname'}.' / 
'.$borrowernumber);
+                $overwritten++;
+                $template->param('lastoverwritten'=>$borrower{'surname'}.' / 
'.$borrowernumber);
             } else {
-                $invalid++;
-                $template->param('lastinvalid'=>$borrower{'surname'}.' / 
AddMember');
+                # FIXME: fixup_cardnumber says to lock table, but the web 
interface doesn't so this doesn't either.
+                # At least this is closer to AddMember than in 
members/memberentry.pl
+                if (!$borrower{'cardnumber'}) {
+                    $borrower{'cardnumber'} = fixup_cardnumber(undef);
+                }
+                if ($borrowernumber = AddMember(%borrower)) {
+                    if ($extended) {
+                        SetBorrowerAttributes($borrowernumber, 
$patron_attributes);
+                    }
+                    if ($set_messaging_prefs) {
+                        
C4::Members::Messaging::SetMessagingPreferencesFromDefaults({ borrowernumber => 
$borrowernumber,
+                                                                               
       categorycode => $borrower{categorycode} });
+                    }
+                    $imported++;
+                    $template->param('lastimported'=>$borrower{'surname'}.' / 
'.$borrowernumber);
+                } else {
+                    $invalid++;
+                    $template->param('lastinvalid'=>$borrower{'surname'}.' / 
AddMember');
+                }
             }
         }
+        (@errors  ) and $template->param(  ERRORS=>\...@errors  );
+        (@feedback) and $template->param(FEEDBACK=>\...@feedback);
+        $template->param(
+            'uploadborrowers' => 1,
+            'imported'        => $imported,
+            'overwritten'     => $overwritten,
+            'alreadyindb'     => $alreadyindb,
+            'invalid'         => $invalid,
+            'total'           => $imported + $alreadyindb + $invalid + 
$overwritten,
+        );
     }
-    (@errors  ) and $template->param(  ERRORS=>\...@errors  );
-    (@feedback) and $template->param(FEEDBACK=>\...@feedback);
-    $template->param(
-        'uploadborrowers' => 1,
-        'imported'        => $imported,
-        'overwritten'     => $overwritten,
-        'alreadyindb'     => $alreadyindb,
-        'invalid'         => $invalid,
-        'total'           => $imported + $alreadyindb + $invalid + 
$overwritten,
-    );
-
-} else {
+}
+else {
     if ($extended) {
         my @matchpoints = ();
         my @attr_types = C4::Members::AttributeTypes::GetAttributeTypes();
@@ -304,5 +339,11 @@ if ( $uploadborrowers && length($uploadborrowers) > 0 ) {
     }
 }
 
+$template->param(
+                error           => ($errstr ? 1 : 0),
+                $errstr         => 1,
+                invalid_columns => $invalid_columns,
+);
+
 output_html_with_http_headers $input, $cookie, $template->output;
 
-- 
1.6.0.4

_______________________________________________
Koha-patches mailing list
[email protected]
http://lists.koha.org/mailman/listinfo/koha-patches

Reply via email to