+ }
+ #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;
+ }
+ if ($extended) {
+ my $attr_str = $borrower{patron_attributes};
+ $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)) {
+ 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};
+ }
+ }
+ $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;
+ }