View | Details | Raw Unified | Return to bug 5742
Collapse All | Expand All

(-)a/C4/Members.pm (-67 / +84 lines)
Lines 42-127 use Koha::DateUtils; Link Here
42
our ($VERSION,@ISA,@EXPORT,@EXPORT_OK,$debug);
42
our ($VERSION,@ISA,@EXPORT,@EXPORT_OK,$debug);
43
43
44
BEGIN {
44
BEGIN {
45
	$VERSION = 3.02;
45
    $VERSION = 3.02;
46
	$debug = $ENV{DEBUG} || 0;
46
    $debug = $ENV{DEBUG} || 0;
47
	require Exporter;
47
    require Exporter;
48
	@ISA = qw(Exporter);
48
    @ISA = qw(Exporter);
49
	#Get data
49
    #Get data
50
	push @EXPORT, qw(
50
    push @EXPORT, qw(
51
		&Search
51
        &Search
52
		&GetMemberDetails
52
        &GetMemberDetails
53
        &GetMemberRelatives
53
        &GetMemberRelatives
54
		&GetMember
54
        &GetMember
55
55
56
		&GetGuarantees 
56
        &GetGuarantees
57
57
58
		&GetMemberIssuesAndFines
58
        &GetMemberIssuesAndFines
59
		&GetPendingIssues
59
        &GetPendingIssues
60
		&GetAllIssues
60
        &GetAllIssues
61
61
62
		&get_institutions 
62
        &get_institutions
63
		&getzipnamecity 
63
        &getzipnamecity
64
		&getidcity
64
        &getidcity
65
65
66
                &GetFirstValidEmailAddress
66
        &GetFirstValidEmailAddress
67
67
68
		&GetAge 
68
        &GetAge
69
		&GetCities 
69
        &GetCities
70
		&GetRoadTypes 
70
        &GetRoadTypes
71
		&GetRoadTypeDetails 
71
        &GetRoadTypeDetails
72
		&GetSortDetails
72
        &GetSortDetails
73
		&GetTitles
73
        &GetTitles
74
74
75
    &GetPatronImage
75
        &GetPatronImage
76
    &PutPatronImage
76
        &PutPatronImage
77
    &RmPatronImage
77
        &RmPatronImage
78
78
79
                &GetHideLostItemsPreference
79
        &GetHideLostItemsPreference
80
80
81
		&IsMemberBlocked
81
        &IsMemberBlocked
82
		&GetMemberAccountRecords
82
        &GetMemberAccountRecords
83
		&GetBorNotifyAcctRecord
83
        &GetBorNotifyAcctRecord
84
84
85
		&GetborCatFromCatType 
85
        &GetborCatFromCatType
86
		&GetBorrowercategory
86
        &GetBorrowercategory
87
    &GetBorrowercategoryList
87
        GetBorrowerCategorycode
88
        &GetBorrowercategoryList
88
89
89
		&GetBorrowersWhoHaveNotBorrowedSince
90
        &GetBorrowersWhoHaveNotBorrowedSince
90
		&GetBorrowersWhoHaveNeverBorrowed
91
        &GetBorrowersWhoHaveNeverBorrowed
91
		&GetBorrowersWithIssuesHistoryOlderThan
92
        &GetBorrowersWithIssuesHistoryOlderThan
92
93
93
		&GetExpiryDate
94
        &GetExpiryDate
94
95
95
		&AddMessage
96
        &AddMessage
96
		&DeleteMessage
97
        &DeleteMessage
97
		&GetMessages
98
        &GetMessages
98
		&GetMessagesCount
99
        &GetMessagesCount
99
100
100
        &IssueSlip
101
        &IssueSlip
101
		GetBorrowersWithEmail
102
        GetBorrowersWithEmail
102
	);
103
    );
103
104
104
	#Modify data
105
    #Modify data
105
	push @EXPORT, qw(
106
    push @EXPORT, qw(
106
		&ModMember
107
        &ModMember
107
		&changepassword
108
        &changepassword
108
         &ModPrivacy
109
         &ModPrivacy
109
	);
110
    );
110
111
111
	#Delete data
112
    #Delete data
112
	push @EXPORT, qw(
113
    push @EXPORT, qw(
113
		&DelMember
114
        &DelMember
114
	);
115
    );
115
116
116
	#Insert data
117
    #Insert data
117
	push @EXPORT, qw(
118
    push @EXPORT, qw(
118
		&AddMember
119
        &AddMember
119
		&add_member_orgs
120
        &add_member_orgs
120
		&MoveMemberToDeleted
121
        &MoveMemberToDeleted
121
		&ExtendMemberSubscriptionTo
122
        &ExtendMemberSubscriptionTo
122
	);
123
    );
123
124
124
	#Check data
125
    #Check data
125
    push @EXPORT, qw(
126
    push @EXPORT, qw(
126
        &checkuniquemember
127
        &checkuniquemember
127
        &checkuserpassword
128
        &checkuserpassword
Lines 1409-1418 sub GetborCatFromCatType { Link Here
1409
Given the borrower's category code, the function returns the corresponding
1410
Given the borrower's category code, the function returns the corresponding
1410
data hashref for a comprehensive information display.
1411
data hashref for a comprehensive information display.
1411
1412
1412
  $arrayref_hashref = &GetBorrowercategory;
1413
1414
If no category code provided, the function returns all the categories.
1415
1416
=cut
1413
=cut
1417
1414
1418
sub GetBorrowercategory {
1415
sub GetBorrowercategory {
Lines 1433-1438 sub GetBorrowercategory { Link Here
1433
    return;  
1430
    return;  
1434
}    # sub getborrowercategory
1431
}    # sub getborrowercategory
1435
1432
1433
1434
=head2 GetBorrowerCategorycode
1435
1436
    $categorycode = &GetBorrowerCategoryCode( $borrowernumber );
1437
1438
Given the borrowernumber, the function returns the corresponding categorycode
1439
=cut
1440
1441
sub GetBorrowerCategorycode {
1442
    my ( $borrowernumber ) = @_;
1443
    my $dbh = C4::Context->dbh;
1444
    my $sth = $dbh->prepare( qq{
1445
        SELECT categorycode
1446
        FROM borrowers
1447
        WHERE borrowernumber = ?
1448
    } );
1449
    $sth->execute( $borrowernumber );
1450
    return $sth->fetchrow;
1451
}
1452
1436
=head2 GetBorrowercategoryList
1453
=head2 GetBorrowercategoryList
1437
1454
1438
  $arrayref_hashref = &GetBorrowercategoryList;
1455
  $arrayref_hashref = &GetBorrowercategoryList;
(-)a/C4/Members/Attributes.pm (-5 / +51 lines)
Lines 32-39 BEGIN { Link Here
32
    $VERSION = 3.01;
32
    $VERSION = 3.01;
33
    @ISA = qw(Exporter);
33
    @ISA = qw(Exporter);
34
    @EXPORT_OK = qw(GetBorrowerAttributes GetBorrowerAttributeValue CheckUniqueness SetBorrowerAttributes
34
    @EXPORT_OK = qw(GetBorrowerAttributes GetBorrowerAttributeValue CheckUniqueness SetBorrowerAttributes
35
                    DeleteBorrowerAttribute UpdateBorrowerAttribute
35
                    extended_attributes_code_value_arrayref extended_attributes_merge
36
                    extended_attributes_code_value_arrayref extended_attributes_merge
36
					SearchIdMatchingAttribute);
37
                    SearchIdMatchingAttribute);
37
    %EXPORT_TAGS = ( all => \@EXPORT_OK );
38
    %EXPORT_TAGS = ( all => \@EXPORT_OK );
38
}
39
}
39
40
Lines 76-93 sub GetBorrowerAttributes { Link Here
76
                 FROM borrower_attributes
77
                 FROM borrower_attributes
77
                 JOIN borrower_attribute_types USING (code)
78
                 JOIN borrower_attribute_types USING (code)
78
                 LEFT JOIN authorised_values ON (category = authorised_value_category AND attribute = authorised_value)
79
                 LEFT JOIN authorised_values ON (category = authorised_value_category AND attribute = authorised_value)
79
                 WHERE borrowernumber = ?";
80
                 WHERE 1";
81
    $query .= "\nAND borrowernumber = ?" if $borrowernumber;
80
    $query .= "\nAND opac_display = 1" if $opac_only;
82
    $query .= "\nAND opac_display = 1" if $opac_only;
81
    $query .= "\nORDER BY code, attribute";
83
    $query .= "\nORDER BY code, attribute";
82
    my $sth = $dbh->prepare_cached($query);
84
    my $sth = $dbh->prepare_cached($query);
83
    $sth->execute($borrowernumber);
85
    $sth->execute($borrowernumber ? $borrowernumber : ());
84
    my @results = ();
86
    my @results = ();
85
    while (my $row = $sth->fetchrow_hashref()) {
87
    while (my $row = $sth->fetchrow_hashref()) {
86
        push @results, {
88
        push @results, {
87
            code              => $row->{'code'},
89
            code              => $row->{'code'},
88
            description       => $row->{'description'},
90
            description       => $row->{'description'},
89
            value             => $row->{'attribute'},  
91
            value             => $row->{'attribute'},
90
            value_description => $row->{'lib'},  
92
            value_description => $row->{'lib'},
91
            password          => $row->{'password'},
93
            password          => $row->{'password'},
92
            display_checkout  => $row->{'display_checkout'},
94
            display_checkout  => $row->{'display_checkout'},
93
            category_code     => $row->{'category_code'},
95
            category_code     => $row->{'category_code'},
Lines 233-238 sub SetBorrowerAttributes { Link Here
233
    return 1; # borower attributes successfully set
235
    return 1; # borower attributes successfully set
234
}
236
}
235
237
238
=head2 DeleteBorrowerAttribute
239
240
  DeleteBorrowerAttribute($borrowernumber, $attribute);
241
242
Delete a borrower attribute for the patron identified by C<$borrowernumber> and the attribute code of C<$attribute>
243
244
=cut
245
sub DeleteBorrowerAttribute {
246
    my ( $borrowernumber, $attribute ) = @_;
247
248
    my $dbh = C4::Context->dbh;
249
    my $sth = $dbh->prepare(qq{
250
        DELETE FROM borrower_attributes
251
            WHERE borrowernumber = ?
252
            AND code = ?
253
    } );
254
    $sth->execute( $borrowernumber, $attribute->{code} );
255
}
256
257
=head2 UpdateBorrowerAttribute
258
259
  UpdateBorrowerAttribute($borrowernumber, $attribute );
260
261
Update a borrower attribute C<$attribute> for the patron identified by C<$borrowernumber>,
262
263
=cut
264
sub UpdateBorrowerAttribute {
265
    my ( $borrowernumber, $attribute ) = @_;
266
267
    DeleteBorrowerAttribute $borrowernumber, $attribute;
268
269
    my $dbh = C4::Context->dbh;
270
    my $query = "INSERT INTO borrower_attributes SET attribute = ?, code = ?, borrowernumber = ?";
271
    my @params = ( $attribute->{attribute}, $attribute->{code}, $borrowernumber );
272
    if ( defined $attribute->{password} ) {
273
        $query .= ", password = ?";
274
        push @params, $attribute->{password};
275
    }
276
    my $sth = $dbh->prepare( $query );
277
278
    $sth->execute( @params );
279
}
280
281
236
=head2 extended_attributes_code_value_arrayref 
282
=head2 extended_attributes_code_value_arrayref 
237
283
238
   my $patron_attributes = "homeroom:1150605,grade:01,extradata:foobar";
284
   my $patron_attributes = "homeroom:1150605,grade:01,extradata:foobar";
(-)a/installer/data/mysql/de-DE/mandatory/userpermissions.sql (+1 lines)
Lines 28-33 INSERT INTO permissions (module_bit, code, description) VALUES Link Here
28
   (13, 'manage_staged_marc', 'MARC-Importe verwalten, auch Übernahme in Katalog und Import rückgängig machen'),
28
   (13, 'manage_staged_marc', 'MARC-Importe verwalten, auch Übernahme in Katalog und Import rückgängig machen'),
29
   (13, 'export_catalog', 'Titel- und Exemplardaten exportieren'),
29
   (13, 'export_catalog', 'Titel- und Exemplardaten exportieren'),
30
   (13, 'import_patrons', 'Benutzerdaten importieren'),
30
   (13, 'import_patrons', 'Benutzerdaten importieren'),
31
   (13, 'edit_patrons', 'Perform batch modification of patrons'),
31
   (13, 'delete_anonymize_patrons', 'Inaktive Benutzer löschen und Ausleihhistorie anonymisieren (Benutzerausleihhistorie löschen)'),
32
   (13, 'delete_anonymize_patrons', 'Inaktive Benutzer löschen und Ausleihhistorie anonymisieren (Benutzerausleihhistorie löschen)'),
32
   (13, 'batch_upload_patron_images', 'Benutzerfotos einzeln oder im Stapel hochladen'),
33
   (13, 'batch_upload_patron_images', 'Benutzerfotos einzeln oder im Stapel hochladen'),
33
   (13, 'schedule_tasks', 'Aufgabenplaner verwenden'),
34
   (13, 'schedule_tasks', 'Aufgabenplaner verwenden'),
(-)a/installer/data/mysql/en/mandatory/userpermissions.sql (+1 lines)
Lines 28-33 INSERT INTO permissions (module_bit, code, description) VALUES Link Here
28
   (13, 'manage_staged_marc', 'Managed staged MARC records, including completing and reversing imports'),
28
   (13, 'manage_staged_marc', 'Managed staged MARC records, including completing and reversing imports'),
29
   (13, 'export_catalog', 'Export bibliographic and holdings data'),
29
   (13, 'export_catalog', 'Export bibliographic and holdings data'),
30
   (13, 'import_patrons', 'Import patron data'),
30
   (13, 'import_patrons', 'Import patron data'),
31
   (13, 'edit_patrons', 'Perform batch modification of patrons'),
31
   (13, 'delete_anonymize_patrons', 'Delete old borrowers and anonymize circulation history (deletes borrower reading history)'),
32
   (13, 'delete_anonymize_patrons', 'Delete old borrowers and anonymize circulation history (deletes borrower reading history)'),
32
   (13, 'batch_upload_patron_images', 'Upload patron images in batch or one at a time'),
33
   (13, 'batch_upload_patron_images', 'Upload patron images in batch or one at a time'),
33
   (13, 'schedule_tasks', 'Schedule tasks to run'),
34
   (13, 'schedule_tasks', 'Schedule tasks to run'),
(-)a/installer/data/mysql/es-ES/mandatory/userpermissions.sql (+1 lines)
Lines 28-33 INSERT INTO permissions (module_bit, code, description) VALUES Link Here
28
   (13, 'manage_staged_marc', 'Managed staged MARC records, including completing and reversing imports'),
28
   (13, 'manage_staged_marc', 'Managed staged MARC records, including completing and reversing imports'),
29
   (13, 'export_catalog', 'Export bibliographic and holdings data'),
29
   (13, 'export_catalog', 'Export bibliographic and holdings data'),
30
   (13, 'import_patrons', 'Import patron data'),
30
   (13, 'import_patrons', 'Import patron data'),
31
   (13, 'edit_patrons', 'Perform batch modification of patrons'),
31
   (13, 'delete_anonymize_patrons', 'Delete old borrowers and anonymize circulation history (deletes borrower reading history)'),
32
   (13, 'delete_anonymize_patrons', 'Delete old borrowers and anonymize circulation history (deletes borrower reading history)'),
32
   (13, 'batch_upload_patron_images', 'Upload patron images in batch or one at a time'),
33
   (13, 'batch_upload_patron_images', 'Upload patron images in batch or one at a time'),
33
   (13, 'schedule_tasks', 'Schedule tasks to run'),
34
   (13, 'schedule_tasks', 'Schedule tasks to run'),
(-)a/installer/data/mysql/fr-FR/1-Obligatoire/userpermissions.sql (+1 lines)
Lines 18-23 INSERT INTO permissions (module_bit, code, description) VALUES Link Here
18
   (13, 'manage_staged_marc', 'Gérer les notices du réservoir, les charger ou annuler leur chargement'),
18
   (13, 'manage_staged_marc', 'Gérer les notices du réservoir, les charger ou annuler leur chargement'),
19
   (13, 'export_catalog', 'Exporter des notices bibliographiques et leurs exemplaires'),
19
   (13, 'export_catalog', 'Exporter des notices bibliographiques et leurs exemplaires'),
20
   (13, 'import_patrons', 'Importer des données d''adhérents'),
20
   (13, 'import_patrons', 'Importer des données d''adhérents'),
21
   (13, 'edit_patrons', 'Modification par lot des lecteurs'),
21
   (13, 'delete_anonymize_patrons', 'Supprimer les anciens adhérents et anonymiser l''historique des prêts (supprime l''historique des prêts des lecteurs'),
22
   (13, 'delete_anonymize_patrons', 'Supprimer les anciens adhérents et anonymiser l''historique des prêts (supprime l''historique des prêts des lecteurs'),
22
   (13, 'batch_upload_patron_images', 'Charger sur le serveur les images des adhérents par lot ou un par un'),
23
   (13, 'batch_upload_patron_images', 'Charger sur le serveur les images des adhérents par lot ou un par un'),
23
   (13, 'schedule_tasks', 'Planifier les tâches à exécuter'),
24
   (13, 'schedule_tasks', 'Planifier les tâches à exécuter'),
(-)a/installer/data/mysql/it-IT/necessari/userpermissions.sql (+1 lines)
Lines 30-35 INSERT INTO permissions (module_bit, code, description) VALUES Link Here
30
   (13, 'manage_staged_marc', 'Gestisci i record MARC in lavorazione, inclusi il completare e il cancellare gli import'),
30
   (13, 'manage_staged_marc', 'Gestisci i record MARC in lavorazione, inclusi il completare e il cancellare gli import'),
31
   (13, 'export_catalog', 'Esporta i dati bibliografici e di copia'),
31
   (13, 'export_catalog', 'Esporta i dati bibliografici e di copia'),
32
   (13, 'import_patrons', 'Importa i dati utente'),
32
   (13, 'import_patrons', 'Importa i dati utente'),
33
   (13, 'edit_patrons', 'Perform batch modification of patrons'),
33
   (13, 'delete_anonymize_patrons', 'Cancella i vecchi prestiti e rendi anonimo lo storico della circolazione (canella in lettura lo storico utenti prestito)'),
34
   (13, 'delete_anonymize_patrons', 'Cancella i vecchi prestiti e rendi anonimo lo storico della circolazione (canella in lettura lo storico utenti prestito)'),
34
   (13, 'batch_upload_patron_images', 'Aggiorna le foto utente in modalità batch o al momento'),
35
   (13, 'batch_upload_patron_images', 'Aggiorna le foto utente in modalità batch o al momento'),
35
   (13, 'schedule_tasks', 'Schedula i task da far andare'),
36
   (13, 'schedule_tasks', 'Schedula i task da far andare'),
(-)a/installer/data/mysql/nb-NO/1-Obligatorisk/userpermissions.sql (+1 lines)
Lines 49-54 INSERT INTO permissions (module_bit, code, description) VALUES Link Here
49
   (13, 'manage_staged_marc', 'Behandle lagrede MARC-poster, inkludert ferdigstilling og reversering av importer'),
49
   (13, 'manage_staged_marc', 'Behandle lagrede MARC-poster, inkludert ferdigstilling og reversering av importer'),
50
   (13, 'export_catalog', 'Eksportere bibliografiske data og beholdningsdata'),
50
   (13, 'export_catalog', 'Eksportere bibliografiske data og beholdningsdata'),
51
   (13, 'import_patrons', 'Importere låneropplysninger'),
51
   (13, 'import_patrons', 'Importere låneropplysninger'),
52
   (13, 'edit_patrons', 'Perform batch modification of patrons'),
52
   (13, 'delete_anonymize_patrons', 'Slette utgåtte lånere og anonymisere lånehistorikk'),
53
   (13, 'delete_anonymize_patrons', 'Slette utgåtte lånere og anonymisere lånehistorikk'),
53
   (13, 'batch_upload_patron_images', 'Laste opp bilder av lånere enkeltvis eller en masse'),
54
   (13, 'batch_upload_patron_images', 'Laste opp bilder av lånere enkeltvis eller en masse'),
54
   (13, 'schedule_tasks', 'Planlegge oppgaver som skal kjøres'),
55
   (13, 'schedule_tasks', 'Planlegge oppgaver som skal kjøres'),
(-)a/installer/data/mysql/pl-PL/mandatory/userpermissions.sql (+1 lines)
Lines 28-33 INSERT INTO permissions (module_bit, code, description) VALUES Link Here
28
   (13, 'manage_staged_marc', 'Managed staged MARC records, including completing and reversing imports'),
28
   (13, 'manage_staged_marc', 'Managed staged MARC records, including completing and reversing imports'),
29
   (13, 'export_catalog', 'Export bibliographic and holdings data'),
29
   (13, 'export_catalog', 'Export bibliographic and holdings data'),
30
   (13, 'import_patrons', 'Import patron data'),
30
   (13, 'import_patrons', 'Import patron data'),
31
   (13, 'edit_patrons', 'Perform batch modification of patrons'),
31
   (13, 'delete_anonymize_patrons', 'Delete old borrowers and anonymize circulation history (deletes borrower reading history)'),
32
   (13, 'delete_anonymize_patrons', 'Delete old borrowers and anonymize circulation history (deletes borrower reading history)'),
32
   (13, 'batch_upload_patron_images', 'Upload patron images in batch or one at a time'),
33
   (13, 'batch_upload_patron_images', 'Upload patron images in batch or one at a time'),
33
   (13, 'schedule_tasks', 'Schedule tasks to run'),
34
   (13, 'schedule_tasks', 'Schedule tasks to run'),
(-)a/installer/data/mysql/updatedatabase.pl (+10 lines)
Lines 5086-5091 if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) { Link Here
5086
    SetVersion($DBversion);
5086
    SetVersion($DBversion);
5087
}
5087
}
5088
5088
5089
5090
5091
5092
$DBversion = "3.07.00.XXX";
5093
if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) {
5094
    $dbh->do("INSERT IGNORE INTO `permissions` (`module_bit`, `code`, `description`) VALUES('13', 'edit_patrons', 'Perform batch modifivation of patrons')");
5095
    print "Upgrade to $DBversion done (Adds permissions flag for access to the patron modifications tool)\n";
5096
    SetVersion($DBversion);
5097
}
5098
5089
=head1 FUNCTIONS
5099
=head1 FUNCTIONS
5090
5100
5091
=head2 DropAllForeignKeys($table)
5101
=head2 DropAllForeignKeys($table)
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/modborrowers.tt (+310 lines)
Line 0 Link Here
1
[% USE KohaDates %]
2
[% INCLUDE 'doc-head-open.inc'%]
3
<title>Koha &rsaquo; Tools &rsaquo; [% IF ( del ) %]Batch item deletion[% ELSE %]Batch item modification[% END %] </title>
4
[% INCLUDE 'doc-head-close.inc' %]
5
[% INCLUDE 'calendar.inc' %]
6
<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.tablesorter.min.js"></script>
7
<script type="text/JavaScript" language="JavaScript">
8
//<![CDATA[
9
        var patron_attributes_lib = new Array();
10
        var patron_attributes_values = new Array();
11
        $(document).ready(function() {
12
            $("#borrowerst").tablesorter();
13
14
            $("#selectallbutton").click(function() {
15
                $("#borrowerst").find("input:checkbox").each(function() {
16
                    $(this).attr("checked", true);
17
                });
18
                return false;
19
            });
20
            $("#clearallbutton").click(function() {
21
                $("#borrowerst").find("input:checkbox").each(function() {
22
                    $(this).attr("checked", false);
23
                });
24
                return false;
25
            });
26
27
            var values = new Array();
28
            var lib = new Array();
29
            [% FOREACH pav IN patron_attributes_values %]
30
                values = new Array();
31
                lib = new Array();
32
                [% FOREACH option IN pav.options %]
33
                    values.push("[% option.lib %]");
34
                    lib.push("[% option.authorised_value %]");
35
                [% END %]
36
                patron_attributes_lib["[% pav.attribute_code %]"] = values;
37
                patron_attributes_values["[% pav.attribute_code %]"] = lib;
38
            [% END %]
39
40
            $('select[name="patron_attributes"]').change(function() {
41
                updateAttrValues(this);
42
            } );
43
44
            $('select[name="patron_attributes"]').change();
45
46
        } );
47
48
        function updateAttrValues (select_attr) {
49
            var attr_code = $(select_attr).val();
50
            var type = $(select_attr).find("option:selected").attr('data-type');
51
            var category = $(select_attr).find("option:selected").attr('data-category');
52
            var span = $(select_attr).parent().parent().find('span.patron_attributes_value');
53
            var information_category_node = $(select_attr).parent().parent().find('span.information_category');
54
            information_category_node.html("");
55
            if ( category.length > 0 ) {
56
                information_category_node.html('This attribute will be only applied to the borrower\'s category "' + category + '"');
57
            }
58
            if ( type == 'select' ) {
59
                var options = '<option value = ""></option>';
60
                for ( var i = 0 ; i < patron_attributes_values[attr_code].length ; i++ ) {
61
                    options += '<option value="'+patron_attributes_values[attr_code][i]+'">'+patron_attributes_lib[attr_code][i]+'</option>';
62
                }
63
                span.html('<select name="patron_attributes_value">' + options + '</select>');
64
            } else {
65
                span.html('<input type="text" name="patron_attributes_value"/>')
66
            }
67
        }
68
69
        function add_attributes() {
70
            var li_node = $("li.attributes:last");
71
            var li_clone = $(li_node).clone();
72
            if ( $(li_clone).find("a.delete").length == 0 ) {
73
                $(li_clone).append('[<a href="#" title="Delete" class="delete" onclick="del_attributes(this);return false;">X</a>]');
74
            }
75
            $(li_clone).find('select[name="patron_attributes"]').change(function() {
76
                updateAttrValues(this);
77
            } );
78
79
            $(li_clone).find('select[name="patron_attributes"]').change();
80
81
            $("#fields_list>ol").append(li_clone);
82
            update_attr_values();
83
        }
84
85
        function del_attributes(a_node) {
86
            $(a_node).parent('li').remove();
87
            update_attr_values();
88
        }
89
90
        function update_attr_values() {
91
            $("li.attributes").each(function(i) {
92
                $(this).find("input:checkbox").val("attr"+i+"_value");
93
            });
94
        }
95
        function clearDate(nodeid) {
96
            $("#"+nodeid).val("");
97
        }
98
99
//]]>
100
</script>
101
</head>
102
<body>
103
[% INCLUDE 'header.inc' %]
104
[% INCLUDE 'cat-search.inc' %]
105
106
<div id="breadcrumbs">
107
    <a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo;
108
    <a href="/cgi-bin/koha/tools/tools-home.pl">Tools</a> &rsaquo;
109
    <a href="/cgi-bin/koha/tools/modborrowers.pl">Patrons modification</a>
110
</div>
111
112
<div id="doc3" class="yui-t2">
113
    <div id="bd">
114
        <div id="yui-main">
115
            <div class="yui-b">
116
                [% IF ( op == 'show_form' ) %]
117
                <h1>Batch patrons modification</h1>
118
                <form method="post" enctype="multipart/form-data" action="/cgi-bin/koha/tools/modborrowers.pl">
119
                    <fieldset class="rows">
120
                    <legend>Use a file</legend>
121
                    <label for="uploadfile">File: </label> <input type="file" id="uploadfile" name="uploadfile" />
122
                    </fieldset>
123
                    <fieldset class="rows">
124
                        <legend>Or list cardnumbers one by one</legend>
125
                        <ol>
126
                            <li>
127
                              <label for="cardnumberlist">Carnumber list (one cardnumber per line): </label>
128
                              <textarea rows="10" cols="30" id="cardnumberlist" name="cardnumberlist">[% cardnumberlist %]</textarea>
129
                            </li>
130
                        </ol>
131
                    </fieldset>
132
                    <input type="hidden" name="op" value="show" />
133
                    <fieldset class="action">
134
                        <input type="submit" value="Continue" class="button" />
135
                        <a class="cancel" href="/cgi-bin/koha/tools/tools-home.pl">Cancel</a>
136
                    </fieldset>
137
                </form>
138
                [% END %]
139
140
                [% IF ( op == 'show' or op == 'show_results' ) %]
141
                    [% IF ( op == 'show' ) %]
142
                        <h1>Batch patrons modification</h1>
143
                    [% ELSE %]
144
                        <h1>Batch patrons results</h1>
145
                    [% END %]
146
                    [% IF ( notfoundcardnumbers ) %]
147
                        <div class="dialog alert"><p>Warning, the following cardnumbers were not found:</p></div>
148
                        <table style="margin:auto;">
149
                            <thead>
150
                                <tr><th>Cardnumbers not found</th></tr>
151
                            </thead>
152
                            <tbody>
153
                                [% FOREACH notfoundcardnumber IN notfoundcardnumbers %]
154
                                    <tr><td>[% notfoundcardnumber.cardnumber %]</td></tr>
155
                                [% END %]
156
                            </tbody>
157
                        </table>
158
                    [% END %]
159
160
                    [% IF ( op == 'show_results' ) %]
161
                        [% IF ( errors ) %]
162
                            Errors occured :
163
                            <ul class="warnings">
164
                            [% FOREACH error IN errors %]
165
                                [% IF ( error.error == 'can_not_update' ) %]
166
                                    <li>Can not update borrower with borrowernumber [% error.borrowernumber %]</li>
167
                                [% ELSE %]
168
                                    <li>[% error.error %]</li>
169
                                [% END %]
170
                            [% END %]
171
                            </ul>
172
                        [% END %]
173
                        <br/>
174
                    [% END %]
175
176
                    [% IF ( op == 'show' ) %]
177
                    <form name="f" action="modborrowers.pl" method="post">
178
                        <input type="hidden" name="op" value="do" />
179
                        [% IF ( borrowers ) %]
180
                            <div id="toolbar"><a id="selectallbutton" href="#">Select All</a> | <a id="clearallbutton" href="#">Clear All</a></div>
181
                        [% END %]
182
                    [% END %]
183
                            <div id="cataloguing_additem_itemlist">
184
                                <div style="overflow:auto">
185
                                    <table id="borrowerst">
186
                                        <thead>
187
                                            <tr>
188
                                                [% IF ( op == 'show' ) %]
189
                                                    <th>&nbsp;</th>
190
                                                [% END %]
191
                                                <th>Surname</th>
192
                                                <th>Firstname</th>
193
                                                <th>Branchname</th>
194
                                                <th>Categorycode</th>
195
                                                <th>Cardnumber</th>
196
                                                <th>dateenrolled</th>
197
                                                <th>dateexpiry</th>
198
                                                <th>debarred</th>
199
                                                [% FOREACH attrh IN attributes_header %]
200
                                                    <th>[% attrh.attribute %]</th>
201
                                                [% END %]
202
                                            </tr>
203
                                        </thead>
204
                                        <tbody>
205
                                            [% FOREACH borrower IN borrowers %]
206
                                                <tr>
207
                                                    [% IF ( op == 'show' ) %]
208
                                                        <td><input type="checkbox" name="borrowernumber" value="[% borrower.borrowernumber %]" checked="checked" /></td>
209
                                                    [% END %]
210
                                                    <td>[% borrower.surname %]</td>
211
                                                    <td>[% borrower.firstname %]</td>
212
                                                    <td>[% borrower.branchname %]</td>
213
                                                    <td>[% borrower.categorycode %]</td>
214
                                                    <td>[% borrower.cardnumber %]</td>
215
                                                    <td>[% borrower.dateenrolled | $KohaDates %]</td>
216
                                                    <td>[% borrower.dateexpiry | $KohaDates %]</td>
217
                                                    <td>[% borrower.debarred | $KohaDates %]</td>
218
                                                    [% FOREACH pa IN borrower.patron_attributes %]
219
                                                        [% IF ( pa.code ) %]
220
                                                            <td>[% pa.code %]=[% pa.value %]</td>
221
                                                        [% ELSE %]
222
                                                            <td></td>
223
                                                        [% END %]
224
                                                    [% END %]
225
                                                </tr>
226
                                            [% END %]
227
                                        </tbody>
228
                                    </table>
229
                                </div>
230
                            </div>
231
232
                            [% IF ( op == 'show' ) %]
233
                            <div id="cataloguing_additem_newitem">
234
                                <h2>Edit Patrons</h2>
235
                                <div class="hint">Checking the box right next the label will disable the entry and delete the values of that field on all selected patrons</div>
236
                                <fieldset class="rows" id="fields_list">
237
                                    <ol>
238
                                        [% FOREACH field IN fields %]
239
                                        <li>
240
                                            <label style="width:20em;">[% field.lib %]</label>
241
                                            <input type="checkbox" title="check to delete this field" name="disable_input" value="[% field.name %]"/>
242
                                            [% IF ( field.type == 'text' ) %]
243
                                                <input type="text" name="[% field.name %]" value="" />
244
                                            [% END %]
245
                                            [% IF ( field.type == 'select' ) %]
246
                                                [% IF field.option.size %]
247
                                                    <select name="[% field.name %]" >
248
                                                        [% FOREACH opt IN field.option %]
249
                                                            <option value="[% opt.value %]">[% opt.lib %]</option>
250
                                                        [% END %]
251
                                                    </select>
252
                                                [% ELSE %]
253
                                                    There is no value defined for [% field.name %]
254
                                                [% END %]
255
                                            [% END %]
256
                                            [% IF ( field.type == 'date' ) %]
257
                                                <img src="[% themelang %]/lib/calendar/cal.gif" style="cursor: pointer;" alt="Show Calendar" title="Show Calendar" id="[% field.name %]button"/>
258
                                                <input type="text" name="[% field.name %]" id="[% field.name %]" value="" size="10" maxlength="10" readonly />
259
                                                <a href="#" onclick="clearDate('[% field.name %]');return false;">X</a>
260
                                                <script type="text/javascript">
261
                                                 //<![CDATA[ 
262
                                                Calendar.setup({
263
                                                    inputField      : "[% field.name %]", 
264
                                                    button          : "[% field.name %]button",
265
                                                    ifFormat        : "[% DHTMLcalendar_dateformat %]",
266
                                                    onClose: function() { $("#[% field.name %]").change(); this.hide();}
267
                                                });
268
                                                //]]>
269
                                                </script>
270
                                            [% END %]
271
                                        </li>
272
                                        [% END %]
273
                                        <li class="attributes">
274
                                            <label style="width:20em;">Attribute
275
                                                <select name="patron_attributes">
276
                                                    [% FOREACH pac IN patron_attributes_codes %]
277
                                                        <option value="[% pac.attribute_code %]" data-type="[% pac.type %]" data-category="[% pac.category_lib %]">[% pac.attribute_lib %]</option>
278
                                                    [% END %]
279
                                                </select>
280
                                            </label>
281
                                            <input type="checkbox" title="check to delete this field" name="disable_input" value="attr0_value" />
282
                                            <span class="patron_attributes_value"></span>
283
                                            <a href="#" title="Add an attribute" onclick="add_attributes(); return false;">+</a>
284
                                            <span class="information_category"></span>
285
                                        </li>
286
                                    </ol>
287
                                </fieldset>
288
                                <fieldset class="action">
289
                                    <input type="submit" name="mainformsubmit" value="Save" />
290
                                    <a href="/cgi-bin/koha/tools/modborrowers.pl" class="cancel">Cancel</a>
291
                                </fieldset>
292
                            </div>
293
                        </form>
294
                        [% END %]
295
                [% END %]
296
                [% IF ( op == 'show_results' ) %]
297
                    <br/>
298
                    <a href="/cgi-bin/koha/tools/modborrowers.pl" title="new Batch patrons modification">new Batch patrons modification</a>
299
                [% END %]
300
            </div>
301
            </div>
302
            <div class="yui-b">
303
                [% INCLUDE 'tools-menu.inc' %]
304
            </div>
305
        </div>
306
    </div>
307
</div>
308
</body>
309
</html>
310
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt (+5 lines)
Lines 45-50 Link Here
45
    <dd>Delete old borrowers and anonymize circulation history (deletes borrower reading history)</dd>
45
    <dd>Delete old borrowers and anonymize circulation history (deletes borrower reading history)</dd>
46
    [% END %]
46
    [% END %]
47
47
48
    [% IF ( CAN_user_tools_edit_patrons ) %]
49
    <dt><a href="/cgi-bin/koha/tools/modborrowers.pl">Patrons (Modification)</a></dt>
50
    <dd>Modify patrons</dd>
51
    [% END %]
52
48
    [% IF ( CAN_user_tools_moderate_tags ) %]
53
    [% IF ( CAN_user_tools_moderate_tags ) %]
49
    <dt><a href="/cgi-bin/koha/tags/review.pl">Tags</a> [% IF ( pendingtags ) %]<span class="holdcount"><a href="/cgi-bin/koha/tags/review.pl">[% pendingtags %]</a></span>[% END %]</dt>
54
    <dt><a href="/cgi-bin/koha/tags/review.pl">Tags</a> [% IF ( pendingtags ) %]<span class="holdcount"><a href="/cgi-bin/koha/tags/review.pl">[% pendingtags %]</a></span>[% END %]</dt>
50
	<dd>Moderate patron tags</dd>
55
	<dd>Moderate patron tags</dd>
(-)a/tools/modborrowers.pl (-1 / +322 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
3
# Copyright 2012 BibLibre
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
use CGI;
22
use C4::Auth;
23
use C4::Branch;
24
use C4::Koha;
25
use C4::Members;
26
use C4::Members::Attributes qw(GetBorrowerAttributes UpdateBorrowerAttribute DeleteBorrowerAttribute);
27
use C4::Members::AttributeTypes qw/GetAttributeTypes_hashref/;
28
use C4::Output;
29
use List::MoreUtils qw /any uniq/;
30
31
my $input = new CGI;
32
my $op = $input->param('op') || 'show_form';
33
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
34
    {   template_name   => "tools/modborrowers.tmpl",
35
        query           => $input,
36
        type            => "intranet",
37
        authnotrequired => 0,
38
        flagsrequired   => { tools => "edit_patrons" },
39
    }
40
);
41
42
my %cookies   = parse CGI::Cookie($cookie);
43
my $sessionID = $cookies{'CGISESSID'}->value;
44
my $dbh       = C4::Context->dbh;
45
46
47
48
if ( $op eq 'show' ) {
49
    my $filefh      = $input->upload('uploadfile');
50
    my $filecontent = $input->param('filecontent');
51
    my @borrowers;
52
    my @cardnumbers;
53
    my @notfoundcardnumbers;
54
55
    my @contentlist;
56
    if ($filefh) {
57
        while ( my $content = <$filefh> ) {
58
            $content =~ s/[\r\n]*$//g;
59
            push @cardnumbers, $content if $content;
60
        }
61
    } else {
62
        if ( my $list = $input->param('cardnumberlist') ) {
63
            push @cardnumbers, split( /\s\n/, $list );
64
        }
65
    }
66
67
    my $max_nb_attr = 0;
68
    for my $cardnumber ( @cardnumbers ) {
69
        my $borrower = GetBorrowerInfos( cardnumber => $cardnumber );
70
        if ( $borrower ) {
71
            $max_nb_attr = scalar( @{ $borrower->{patron_attributes} } )
72
                if scalar( @{ $borrower->{patron_attributes} } ) > $max_nb_attr;
73
            push @borrowers, $borrower;
74
        } else {
75
            push @notfoundcardnumbers, $cardnumber;
76
        }
77
    }
78
79
    # Just for a correct display
80
    for my $borrower ( @borrowers ) {
81
        my $length = scalar( @{ $borrower->{patron_attributes} } );
82
        push @{ $borrower->{patron_attributes} }, {} for ( $length .. $max_nb_attr - 1);
83
    }
84
85
    my @patron_attributes_values;
86
    my @patron_attributes_codes;
87
    my $patron_attribute_types = C4::Members::AttributeTypes::GetAttributeTypes_hashref('all');
88
    my $patron_categories = C4::Members::GetBorrowercategoryList;
89
    for ( values $patron_attribute_types ) {
90
        my $attr_type = C4::Members::AttributeTypes->fetch( $_->{code} );
91
        my $options = $attr_type->authorised_value_category
92
            ? GetAuthorisedValues( $attr_type->authorised_value_category )
93
            : undef;
94
        push @patron_attributes_values,
95
            {
96
                attribute_code => $_->{code},
97
                options        => $options,
98
            };
99
100
        my $category_code = $_->{category_code};
101
        my ( $category_lib ) = map {
102
            ( defined $category_code and $_->{categorycode} eq $category_code ) ? $_->{description} : ()
103
        } @$patron_categories;
104
        push @patron_attributes_codes,
105
            {
106
                attribute_code => $_->{code},
107
                attribute_lib  => $_->{description},
108
                category_lib   => $category_lib,
109
                type           => $attr_type->authorised_value_category ? 'select' : 'text',
110
            };
111
    }
112
113
    my @attributes_header = ();
114
    for ( 1 .. scalar( $max_nb_attr ) ) {
115
        push @attributes_header, { attribute => "Attributes $_" };
116
    }
117
    $template->param( borrowers => \@borrowers );
118
    $template->param( attributes_header => \@attributes_header );
119
    @notfoundcardnumbers = map { { cardnumber => $_ } } @notfoundcardnumbers;
120
    $template->param( notfoundcardnumbers => \@notfoundcardnumbers )
121
        if @notfoundcardnumbers;
122
123
    my $branches = GetBranchesLoop;
124
    my @branches_option;
125
    push @branches_option, { value => $_->{value}, lib => $_->{branchname} } for @$branches;
126
    unshift @branches_option, { value => "", lib => "" };
127
    my $categories = GetBorrowercategoryList;
128
    my @categories_option;
129
    push @categories_option, { value => $_->{categorycode}, lib => $_->{description} } for @$categories;
130
    unshift @categories_option, { value => "", lib => "" };
131
    my $bsort1 = GetAuthorisedValues("Bsort1");
132
    my @sort1_option;
133
    push @sort1_option, { value => $_->{authorised_value}, lib => $_->{lib} } for @$bsort1;
134
    unshift @sort1_option, { value => "", lib => "" }
135
        if @sort1_option;
136
    my $bsort2 = GetAuthorisedValues("Bsort2");
137
    my @sort2_option;
138
    push @sort2_option, { value => $_->{authorised_value}, lib => $_->{lib} } for @$bsort2;
139
    unshift @sort2_option, { value => "", lib => "" }
140
        if @sort2_option;
141
    my @fields = (
142
        {
143
            name => "surname",
144
            lib  => "Surname",
145
            type => "text",
146
        }
147
        ,
148
        {
149
            name => "firstname",
150
            lib  => "Firstname",
151
            type => "text",
152
        }
153
        ,
154
        {
155
            name => "branchcode",
156
            lib  => "Branchname",
157
            type => "select",
158
            option => \@branches_option,
159
        }
160
        ,
161
        {
162
            name => "categorycode",
163
            lib  => "Category",
164
            type => "select",
165
            option => \@categories_option,
166
        }
167
        ,
168
        {
169
            name => "sort1",
170
            lib  => "Sort 1",
171
            type => "select",
172
            option => \@sort1_option,
173
        }
174
        ,
175
        {
176
            name => "sort2",
177
            lib  => "Sort 2",
178
            type => "select",
179
            option => \@sort2_option,
180
        }
181
        ,
182
        {
183
            name => "dateenrolled",
184
            lib  => "Date enrolled",
185
            type => "date",
186
        }
187
        ,
188
        {
189
            name => "dateexpiry",
190
            lib  => "Date expiry",
191
            type => "date",
192
        }
193
        ,
194
        {
195
            name => "debarred",
196
            lib  => "Debarred",
197
            type => "date",
198
        }
199
        ,
200
        {
201
            name => "debarredcomment",
202
            lib  => "Debarred comment",
203
            type => "text",
204
        }
205
        ,
206
        {
207
            name => "borrowernotes",
208
            lib  => "Borrower Notes",
209
            type => "text",
210
        }
211
    );
212
213
    $template->param('patron_attributes_codes', \@patron_attributes_codes);
214
    $template->param('patron_attributes_values', \@patron_attributes_values);
215
216
    $template->param( fields => \@fields );
217
    $template->param( DHTMLcalendar_dateformat => C4::Dates->DHTMLcalendar() );
218
}
219
220
if ( $op eq 'do' ) {
221
222
    my @disabled = $input->param('disable_input');
223
    my $infos;
224
    for my $field ( qw/surname firstname branchcode categorycode sort1 sort2 dateenrolled dateexpiry debarred debarredcomment borrowernotes/ ) {
225
        my $value = $input->param($field);
226
        $infos->{$field} = $value if $value;
227
        $infos->{$field} = "" if grep { /^$field$/ } @disabled;
228
    }
229
230
    my @attributes = $input->param('patron_attributes');
231
    my @attr_values = $input->param('patron_attributes_value');
232
233
    my @errors;
234
    my @borrowernumbers = $input->param('borrowernumber');
235
    for my $borrowernumber ( @borrowernumbers ) {
236
        if ( defined $infos ) {
237
            $infos->{borrowernumber} = $borrowernumber;
238
            my $success = ModMember(%$infos);
239
            push @errors, { error => "can_not_update", borrowernumber => $infos->{borrowernumber} } if not $success;
240
        }
241
242
        my $borrower_categorycode = GetBorrowerCategorycode $borrowernumber;
243
        my $i=0;
244
        for ( @attributes ) {
245
            my $attribute;
246
            $attribute->{code} = $_;
247
            $attribute->{attribute} = $attr_values[$i];
248
            my $attr_type = C4::Members::AttributeTypes->fetch( $_ );
249
            ++$i and next if $attr_type->{category_code} and $attr_type->{category_code} ne $borrower_categorycode;
250
            my $valuename = "attr" . $i . "_value";
251
            if ( grep { /^$valuename$/ } @disabled ) {
252
                eval {
253
                    DeleteBorrowerAttribute $borrowernumber, $attribute;
254
                };
255
                push @errors, { error => $@ } if $@;
256
            } else {
257
                ++$i and next if not $attribute->{attribute};
258
                eval {
259
                    UpdateBorrowerAttribute $borrowernumber, $attribute;
260
                };
261
                push @errors, { error => $@ } if $@;
262
            }
263
            $i++;
264
        }
265
    }
266
    $op = "show_results";
267
268
    my @borrowers;
269
    my $max_nb_attr = 0;
270
    for my $borrowernumber ( @borrowernumbers ) {
271
        my $borrower = GetBorrowerInfos( borrowernumber => $borrowernumber );
272
        if ( $borrower ) {
273
            $max_nb_attr = scalar( @{ $borrower->{patron_attributes} } )
274
                if scalar( @{ $borrower->{patron_attributes} } ) > $max_nb_attr;
275
            push @borrowers, $borrower;
276
        }
277
    }
278
    my @patron_attributes_option;
279
    for my $borrower ( @borrowers ) {
280
        push @patron_attributes_option, { value => "$_->{code}", lib => $_->{code} } for @{ $borrower->{patron_attributes} };
281
        my $length = scalar( @{ $borrower->{patron_attributes} } );
282
        push @{ $borrower->{patron_attributes} }, {} for ( $length .. $max_nb_attr - 1);
283
    }
284
285
    my @attributes_header = ();
286
    for ( 1 .. scalar( $max_nb_attr ) ) {
287
        push @attributes_header, { attribute => "Attributes $_" };
288
    }
289
290
    $template->param( borrowers => \@borrowers );
291
    $template->param( attributes_header => \@attributes_header );
292
293
    $template->param( borrowers => \@borrowers );
294
    $template->param( errors => \@errors );
295
}
296
297
$template->param(
298
    op => $op,
299
);
300
output_html_with_http_headers $input, $cookie, $template->output;
301
exit;
302
303
sub GetBorrowerInfos {
304
    my ( %info ) = @_;
305
    my $borrower = GetMember( %info );
306
    if ( $borrower ) {
307
        $borrower->{branchname} = GetBranchName( $borrower->{branchcode} );
308
        for ( qw(dateenrolled dateexpiry debarred) ) {
309
            my $userdate = $borrower->{$_};
310
            unless ($userdate && $userdate ne "0000-00-00" and $userdate ne "9999-12-31") {
311
                $borrower->{$_} = '';
312
                next;
313
            }
314
            $borrower->{$_} = $userdate || '';
315
        }
316
        $borrower->{category_description} = GetBorrowercategory( $borrower->{categorycode} )->{description};
317
        my $attr_loop = C4::Members::Attributes::GetBorrowerAttributes( $borrower->{borrowernumber} );
318
        $borrower->{patron_attributes} = $attr_loop;
319
    }
320
    return $borrower;
321
}
322

Return to bug 5742