Bug 10403: (follow-up) fix test to use vendor created earlier during test
[koha.git] / tools / import_borrowers.pl
index 0385275..5f65c97 100755 (executable)
@@ -1,6 +1,7 @@
 #!/usr/bin/perl
 
-# Copyright 2007 Liblime Ltd
+# Copyright 2007 Liblime
+# Parts copyright 2010 BibLibre
 #
 # This file is part of Koha.
 #
 # 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., 59 Temple Place,
-# Suite 330, Boston, MA  02111-1307 USA
+# 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.
 
 # Script to take some borrowers data in a known format and load it into Koha
 #
 # File format
 #
 # cardnumber,surname,firstname,title,othernames,initials,streetnumber,streettype,
-# address line , address line 2, city, zipcode, email, phone, mobile, fax, work email, work phone,
+# address line , address line 2, city, zipcode, contry, email, phone, mobile, fax, work email, work phone,
 # alternate streetnumber, alternate streettype, alternate address line 1, alternate city,
-# alternate zipcode, alternate email, alternate phone, date of birth, branchcode,
+# alternate zipcode, alternate country, alternate email, alternate phone, date of birth, branchcode,
 # categorycode, enrollment date, expiry date, noaddress, lost, debarred, contact surname,
 # contact firstname, contact title, borrower notes, contact relationship, ethnicity, ethnicity notes
 # gender, username, opac note, contact note, password, sort one, sort two
@@ -42,7 +43,7 @@ use C4::Dates qw(format_date_in_iso);
 use C4::Context;
 use C4::Branch qw(GetBranchName);
 use C4::Members;
-use C4::Members::Attributes;
+use C4::Members::Attributes qw(:all);
 use C4::Members::AttributeTypes;
 use C4::Members::Messaging;
 
@@ -57,15 +58,15 @@ use CGI;
 my (@errors, @feedback);
 my $extended = C4::Context->preference('ExtendedPatronAttributes');
 my $set_messaging_prefs = C4::Context->preference('EnhancedMessagingPreferences');
-my @columnkeys = C4::Members->columns;
+my @columnkeys = C4::Members::columns();
 if ($extended) {
     push @columnkeys, 'patron_attributes';
 }
-my $columnkeystpl = [ map { {'key' => $_} }  grep {$_ ne 'borrowernumber' && $_ ne 'cardnumber'} @columnkeys ];  # ref. to array of hashrefs.
+my $columnkeystpl = [ map { {'key' => $_} }  grep {$_ ne 'borrowernumber' } @columnkeys ];  # ref. to array of hashrefs.
 
 my $input = CGI->new();
-my $csv   = Text::CSV->new({binary => 1});  # binary needed for non-ASCII Unicode
-# push @feedback, {feedback=>1, name=>'backend', value=>$csv->backend, backend=>$csv->backend};
+our $csv  = Text::CSV->new({binary => 1});  # binary needed for non-ASCII Unicode
+#push @feedback, {feedback=>1, name=>'backend', value=>$csv->backend, backend=>$csv->backend}; #XXX
 
 my ( $template, $loggedinuser, $cookie ) = get_template_and_user({
         template_name   => "tools/import_borrowers.tmpl",
@@ -125,6 +126,7 @@ if ( $uploadborrowers && length($uploadborrowers) > 0 ) {
         $csvkeycol{$keycol} = $col++;
     }
     #warn($borrowerline);
+    my $ext_preserve = $input->param('ext_preserve') || 0;
     if ($extended) {
         $matchpoint_attr_type = C4::Members::AttributeTypes->fetch($matchpoint);
     }
@@ -146,7 +148,7 @@ if ( $uploadborrowers && length($uploadborrowers) > 0 ) {
         } elsif (@columns == @columnkeys) {
             @borrower{@columnkeys} = @columns;
             # MJR: try to fill blanks gracefully by using default values
-            foreach my $key (@criticals) {
+            foreach my $key (@columnkeys) {
                 if ($borrower{$key} !~ /\S/) {
                     $borrower{$key} = $defaults{$key};
                 }
@@ -189,14 +191,13 @@ if ( $uploadborrowers && length($uploadborrowers) > 0 ) {
             # The first 25 errors are enough.  Keeping track of 30,000+ would destroy performance.
             next LINE;
         }
-        my @attrs;
         if ($extended) {
             my $attr_str = $borrower{patron_attributes};
-            delete $borrower{patron_attributes};
-            my $ok = $csv->parse($attr_str);
-            my @list = $csv->fields();
-            # FIXME error handling
-            $patron_attributes = [ map { map { my @arr = split /:/, $_, 2; { code => $arr[0], value => $arr[1] } } $_ } @list ];
+            $attr_str =~ s/\xe2\x80\x9c/"/g; # fixup double quotes in case we are passed smart quotes
+            $attr_str =~ s/\xe2\x80\x9d/"/g;
+            push @feedback, {feedback=>1, name=>'attribute string', value=>$attr_str, filename=>$uploadborrowers};
+            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)) {
@@ -215,7 +216,7 @@ if ( $uploadborrowers && length($uploadborrowers) > 0 ) {
         my $borrowernumber;
         my $member;
         if ( ($matchpoint eq 'cardnumber') && ($borrower{'cardnumber'}) ) {
-            $member = GetMember( $borrower{'cardnumber'}, 'cardnumber' );
+            $member = GetMember( 'cardnumber' => $borrower{'cardnumber'} );
             if ($member) {
                 $borrowernumber = $member->{'borrowernumber'};
             }
@@ -239,20 +240,30 @@ if ( $uploadborrowers && length($uploadborrowers) > 0 ) {
                 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}) ;
+            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.
+
+                # The password is always encrypted, skip it!
+                next if $col eq 'password';
+
+                unless(exists($csvkeycol{$col}) || $defaults{$col}) {
+                    $borrower{$col} = $member->{$col} if($member->{$col}) ;
+                }
             }
-        }
             unless (ModMember(%borrower)) {
                 $invalid++;
+                # untill we have better error trapping, we have no way of knowing why ModMember errored out...
+                push @errors, {unknown_error => 1};
                 $template->param('lastinvalid'=>$borrower{'surname'}.' / '.$borrowernumber);
                 next LINE;
             }
             if ($extended) {
-                C4::Members::Attributes::SetBorrowerAttributes($borrower{'borrowernumber'}, $patron_attributes);
+                if ($ext_preserve) {
+                    my $old_attributes = GetBorrowerAttributes($borrowernumber);
+                    $patron_attributes = extended_attributes_merge($old_attributes, $patron_attributes);  #TODO: expose repeatable options in template
+                }
+                push @errors, {unknown_error => 1} unless SetBorrowerAttributes($borrower{'borrowernumber'}, $patron_attributes);
             }
             $overwritten++;
             $template->param('lastoverwritten'=>$borrower{'surname'}.' / '.$borrowernumber);
@@ -264,7 +275,7 @@ if ( $uploadborrowers && length($uploadborrowers) > 0 ) {
             }
             if ($borrowernumber = AddMember(%borrower)) {
                 if ($extended) {
-                    C4::Members::Attributes::SetBorrowerAttributes($borrowernumber, $patron_attributes);
+                    SetBorrowerAttributes($borrowernumber, $patron_attributes);
                 }
                 if ($set_messaging_prefs) {
                     C4::Members::Messaging::SetMessagingPreferencesFromDefaults({ borrowernumber => $borrowernumber,
@@ -273,7 +284,8 @@ if ( $uploadborrowers && length($uploadborrowers) > 0 ) {
                 $imported++;
                 $template->param('lastimported'=>$borrower{'surname'}.' / '.$borrowernumber);
             } else {
-                $invalid++;            # was just "$invalid", I assume incrementing was the point --atz
+                $invalid++;
+                push @errors, {unknown_error => 1};
                 $template->param('lastinvalid'=>$borrower{'surname'}.' / AddMember');
             }
         }
@@ -292,7 +304,7 @@ if ( $uploadborrowers && length($uploadborrowers) > 0 ) {
 } else {
     if ($extended) {
         my @matchpoints = ();
-        my @attr_types = C4::Members::AttributeTypes::GetAttributeTypes();
+        my @attr_types = C4::Members::AttributeTypes::GetAttributeTypes(undef, 1);
         foreach my $type (@attr_types) {
             my $attr_type = C4::Members::AttributeTypes->fetch($type->{code});
             if ($attr_type->unique_id()) {