Lines 881-952
sub changepassword {
Link Here
|
881 |
|
881 |
|
882 |
=head2 fixup_cardnumber |
882 |
=head2 fixup_cardnumber |
883 |
|
883 |
|
884 |
Warning: The caller is responsible for locking the members table in write |
884 |
Previously, there was a gap in time between the insertion of the |
885 |
mode, to avoid database corruption. |
885 |
card number into borrowers and the generation. This gap meant that |
|
|
886 |
the same card number could be calculated by two different processes |
887 |
resulting in two different members being added with the same card |
888 |
number. |
886 |
|
889 |
|
887 |
=cut |
890 |
By serializing the cardnumber requests, at worst we may skip a |
|
|
891 |
cardnumber, rather than duplicate one. No locking required, |
892 |
because the INSERT into cardnumber_sequence is atomic! |
888 |
|
893 |
|
889 |
use vars qw( @weightings ); |
894 |
The reason no duplicates happen is because the sequence of |
890 |
my @weightings = ( 8, 4, 6, 3, 5, 2, 1 ); |
895 |
cardnumbers is calculated from the previous one, and recalculating |
|
|
896 |
would generate exactly the same value. So even if two processes |
897 |
are calculating the same cardnumber for a given UID record, it |
898 |
will result in the same value. |
899 |
|
900 |
=cut |
891 |
|
901 |
|
892 |
sub fixup_cardnumber { |
902 |
sub fixup_cardnumber { |
893 |
my ($cardnumber) = @_; |
903 |
my ($cardnumber) = @_; |
894 |
my $autonumber_members = C4::Context->boolean_preference('autoMemberNum') || 0; |
904 |
my @weightings = ( 8, 4, 6, 3, 5, 2, 1 ); |
|
|
905 |
my ( |
906 |
$autonumber_members, |
907 |
$checkdigit, |
908 |
$dbh, |
909 |
$sth, |
910 |
$my_UID, |
911 |
$current_UID, |
912 |
$previous_UID, |
913 |
$previous_cardnumber, |
914 |
$current_cardnumber, |
915 |
$sum, |
916 |
$i, |
917 |
$temp1, |
918 |
$temp2, |
919 |
$rem, |
920 |
$new_cardnumber, |
921 |
); |
895 |
|
922 |
|
896 |
# Find out whether member numbers should be generated |
923 |
# Find out whether member numbers should be generated |
897 |
# automatically. Should be either "1" or something else. |
924 |
# automatically. Should be either "1" or something else. |
898 |
# Defaults to "0", which is interpreted as "no". |
925 |
# Defaults to "0", which is interpreted as "no". |
|
|
926 |
$autonumber_members = C4::Context->boolean_preference('autoMemberNum') || 0; |
899 |
|
927 |
|
900 |
# if ($cardnumber !~ /\S/ && $autonumber_members) { |
928 |
# if we don't auto-generate, then there is nothing to fixup. |
|
|
929 |
# So return what was passed. |
901 |
($autonumber_members) or return $cardnumber; |
930 |
($autonumber_members) or return $cardnumber; |
902 |
my $checkdigit = C4::Context->preference('checkdigit'); |
|
|
903 |
my $dbh = C4::Context->dbh; |
904 |
if ( $checkdigit and $checkdigit eq 'katipo' ) { |
905 |
|
906 |
# if checkdigit is selected, calculate katipo-style cardnumber. |
907 |
# otherwise, just use the max() |
908 |
# purpose: generate checksum'd member numbers. |
909 |
# We'll assume we just got the max value of digits 2-8 of member #'s |
910 |
# from the database and our job is to increment that by one, |
911 |
# determine the 1st and 9th digits and return the full string. |
912 |
my $sth = $dbh->prepare( |
913 |
"select max(substring(borrowers.cardnumber,2,7)) as new_num from borrowers" |
914 |
); |
915 |
$sth->execute; |
916 |
my $data = $sth->fetchrow_hashref; |
917 |
$cardnumber = $data->{new_num}; |
918 |
if ( !$cardnumber ) { # If DB has no values, |
919 |
$cardnumber = 1000000; # start at 1000000 |
920 |
} else { |
921 |
$cardnumber += 1; |
922 |
} |
923 |
|
924 |
my $sum = 0; |
925 |
for ( my $i = 0 ; $i < 8 ; $i += 1 ) { |
926 |
# read weightings, left to right, 1 char at a time |
927 |
my $temp1 = $weightings[$i]; |
928 |
|
931 |
|
929 |
# sequence left to right, 1 char at a time |
932 |
# determine which kind of auto-generate we are doing |
930 |
my $temp2 = substr( $cardnumber, $i, 1 ); |
933 |
$checkdigit = C4::Context->preference('checkdigit'); |
931 |
|
934 |
|
932 |
# mult each char 1-7 by its corresponding weighting |
935 |
# grab a database handle. |
933 |
$sum += $temp1 * $temp2; |
936 |
$dbh = C4::Context->dbh; |
|
|
937 |
|
938 |
# first we need to show our intent to generate a cardnumber. |
939 |
$sth = $dbh->prepare(" |
940 |
INSERT INTO cardnumber_sequence |
941 |
(cardnumber,checkdigit) VALUES |
942 |
('',?); |
943 |
"); |
944 |
$sth->execute($checkdigit); |
945 |
$my_UID = $dbh->last_insert_id(undef,undef,'cardnumber_sequence','UID'); |
946 |
|
947 |
# next we need to find the first ungenerated cardnumber. |
948 |
# if we don't find any, another process filled them for us! |
949 |
# if we find some, then we need to start generating. |
950 |
$sth = $dbh->prepare(" |
951 |
SELECT MIN(UID) AS UID FROM cardnumber_sequence |
952 |
WHERE cardnumber='' AND checkdigit=?; |
953 |
"); |
954 |
$sth->execute($checkdigit); |
955 |
$current_UID = $sth->fetchrow(); |
956 |
|
957 |
# if there is a current_UID, we need to calculate |
958 |
while ($current_UID) { |
959 |
|
960 |
# so find the previous UID |
961 |
$sth = $dbh->prepare(" |
962 |
SELECT MAX(UID) AS UID FROM cardnumber_sequence |
963 |
WHERE UID < ? AND checkdigit=?; |
964 |
"); |
965 |
$sth->execute($current_UID,$checkdigit); |
966 |
$previous_UID = $sth->fetchrow(); |
967 |
|
968 |
# grab the previous cardnumber |
969 |
$sth = $dbh->prepare(" |
970 |
SELECT cardnumber FROM cardnumber_sequence |
971 |
WHERE UID = ?; |
972 |
"); |
973 |
$sth->execute($previous_UID); |
974 |
$previous_cardnumber = $sth->fetchrow(); |
975 |
|
976 |
# now calculate the current cardnumber. |
977 |
if ($checkdigit && $checkdigit eq 'katipo') { |
978 |
$current_cardnumber = substr($previous_cardnumber,1,7); |
979 |
$current_cardnumber = $current_cardnumber+1; |
980 |
$sum = 0; |
981 |
foreach $i (1..7) { |
982 |
# read weightings, left to right, 1 char at a time |
983 |
$temp1 = $weightings[$i-1]; |
984 |
|
985 |
# sequence left to right, 1 char at a time |
986 |
$temp2 = substr( $current_cardnumber, $i-1, 1 ); |
987 |
|
988 |
# mult each char 1-7 by its corresponding weighting |
989 |
$sum += $temp1 * $temp2; |
990 |
} |
991 |
$rem = ( $sum % 11 ); |
992 |
$rem = 'X' if $rem == 10; |
993 |
$current_cardnumber = "V$current_cardnumber$rem"; |
994 |
} |
995 |
else { |
996 |
$current_cardnumber = $previous_cardnumber+1; |
934 |
} |
997 |
} |
935 |
|
998 |
|
936 |
my $rem = ( $sum % 11 ); |
999 |
# update the current_UID record with the generated cardnumber. |
937 |
$rem = 'X' if $rem == 10; |
1000 |
$sth = $dbh->prepare(" |
938 |
|
1001 |
UPDATE cardnumber_sequence SET cardnumber=? WHERE UID=?; |
939 |
return "V$cardnumber$rem"; |
1002 |
"); |
940 |
} else { |
1003 |
$sth->execute($current_cardnumber,$current_UID); |
941 |
|
1004 |
|
942 |
my $sth = $dbh->prepare( |
1005 |
# we need to find the next ungenerated cardnumber. |
943 |
'SELECT MAX( CAST( cardnumber AS SIGNED ) ) FROM borrowers WHERE cardnumber REGEXP "^-?[0-9]+$"' |
1006 |
# if we don't find any, we are done generating everything. |
944 |
); |
1007 |
$sth = $dbh->prepare(" |
945 |
$sth->execute; |
1008 |
SELECT MIN(UID) AS UID FROM cardnumber_sequence |
946 |
my ($result) = $sth->fetchrow; |
1009 |
WHERE cardnumber='' and checkdigit=?; |
947 |
return $result + 1; |
1010 |
"); |
948 |
} |
1011 |
$sth->execute($checkdigit); |
949 |
return $cardnumber; # just here as a fallback/reminder |
1012 |
$current_UID = $sth->fetchrow(); |
|
|
1013 |
|
1014 |
} |
1015 |
|
1016 |
# need already know our UID ($my_UID) |
1017 |
# let's grab the cardnumber. |
1018 |
$sth = $dbh->prepare(" |
1019 |
SELECT cardnumber FROM cardnumber_sequence |
1020 |
WHERE UID=?; |
1021 |
"); |
1022 |
$sth->execute($my_UID); |
1023 |
$new_cardnumber = $sth->fetchrow(); |
1024 |
|
1025 |
return $new_cardnumber; |
950 |
} |
1026 |
} |
951 |
|
1027 |
|
952 |
=head2 GetGuarantees |
1028 |
=head2 GetGuarantees |