[Koha-patches] [PATCH] Bug 4102: import_borrowers.pl fails silently

Chris Nighswonger cnighswonger at foundations.edu
Thu Feb 18 22:01:24 CET 2010


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
+
+ at 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) {
-            @borrower{@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) {
+                @borrower{@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




More information about the Koha-patches mailing list