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

(-)a/installer/data/mysql/sysprefs.sql (+1 lines)
Lines 17-22 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
17
('AllFinesNeedOverride','1','0','If on, staff will be asked to override every fine, even if it is below noissuescharge.','YesNo'),
17
('AllFinesNeedOverride','1','0','If on, staff will be asked to override every fine, even if it is below noissuescharge.','YesNo'),
18
('AllowAllMessageDeletion','0','','Allow any Library to delete any message','YesNo'),
18
('AllowAllMessageDeletion','0','','Allow any Library to delete any message','YesNo'),
19
('AllowFineOverride','0','0','If on, staff will be able to issue books to patrons with fines greater than noissuescharge.','YesNo'),
19
('AllowFineOverride','0','0','If on, staff will be able to issue books to patrons with fines greater than noissuescharge.','YesNo'),
20
('AllowGDPRPatronExport','1','','If set all data for a patron can be exported from the staff interface.','YesNo'),
20
('AllowHoldDateInFuture','0','','If set a date field is displayed on the Hold screen of the Staff Interface, allowing the hold date to be set in the future.','YesNo'),
21
('AllowHoldDateInFuture','0','','If set a date field is displayed on the Hold screen of the Staff Interface, allowing the hold date to be set in the future.','YesNo'),
21
('AllowHoldItemTypeSelection','0','','If enabled, patrons and staff will be able to select the itemtype when placing a hold','YesNo'),
22
('AllowHoldItemTypeSelection','0','','If enabled, patrons and staff will be able to select the itemtype when placing a hold','YesNo'),
22
('AllowHoldPolicyOverride','0',NULL,'Allow staff to override hold policies when placing holds','YesNo'),
23
('AllowHoldPolicyOverride','0',NULL,'Allow staff to override hold policies when placing holds','YesNo'),
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/members-toolbar.inc (+3 lines)
Lines 89-94 Link Here
89
                        <li><a id="exportcheckins" href="#">Export today's checked in barcodes</a></li>
89
                        <li><a id="exportcheckins" href="#">Export today's checked in barcodes</a></li>
90
                    [% END %]
90
                    [% END %]
91
                [% END %]
91
                [% END %]
92
                [% IF Koha.Preference('AllowGDPRPatronExport') %]
93
                    <li><a id="exportgdprdata" href="#">Export patron's GDPR data</a></li>
94
                [% END %]
92
            </ul>
95
            </ul>
93
    </div>
96
    </div>
94
</div>
97
</div>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref (+6 lines)
Lines 1-6 Link Here
1
Patrons:
1
Patrons:
2
    General:
2
    General:
3
     -
3
     -
4
         - pref: AllowGDPRPatronExport
5
           choices:
6
               yes: "Allow export"
7
               no: "Don't allow export"
8
         - of patron data for GDPR compliance.
9
     -
4
         - pref: AutoEmailOpacUser
10
         - pref: AutoEmailOpacUser
5
           choices:
11
           choices:
6
               yes: Send
12
               yes: Send
(-)a/koha-tmpl/intranet-tmpl/prog/js/members-menu.js (+8 lines)
Lines 55-60 $(document).ready(function(){ Link Here
55
        $(".btn-group").removeClass("open");
55
        $(".btn-group").removeClass("open");
56
        return false;
56
        return false;
57
    });
57
    });
58
    $("#exportgdprdata").click(function(){
59
        export_gdpr_data();
60
        $(".btn-group").removeClass("open");
61
        return false;
62
    });
58
    $("#printsummary").click(function(){
63
    $("#printsummary").click(function(){
59
        printx_window("page");
64
        printx_window("page");
60
        $(".btn-group").removeClass("open");
65
        $(".btn-group").removeClass("open");
Lines 108-113 function confirm_reregistration() { Link Here
108
function export_barcodes() {
113
function export_barcodes() {
109
    window.open('/cgi-bin/koha/members/readingrec.pl?borrowernumber=' + borrowernumber + '&amp;op=export_barcodes');
114
    window.open('/cgi-bin/koha/members/readingrec.pl?borrowernumber=' + borrowernumber + '&amp;op=export_barcodes');
110
}
115
}
116
function export_gdpr_data() {
117
    window.open('/cgi-bin/koha/members/readingrec.pl?borrowernumber=' + borrowernumber + '&amp;op=export_gdprdata');
118
}
111
var slip_re = /slip/;
119
var slip_re = /slip/;
112
function printx_window(print_type) {
120
function printx_window(print_type) {
113
    var handler = print_type.match(slip_re) ? "printslip" : "summary-print";
121
    var handler = print_type.match(slip_re) ? "printslip" : "summary-print";
(-)a/members/readingrec.pl (-2 / +251 lines)
Lines 30-38 use C4::Members; Link Here
30
use List::MoreUtils qw/any uniq/;
30
use List::MoreUtils qw/any uniq/;
31
use Koha::DateUtils;
31
use Koha::DateUtils;
32
use C4::Members::Attributes qw(GetBorrowerAttributes);
32
use C4::Members::Attributes qw(GetBorrowerAttributes);
33
use JSON;
34
use Data::Dumper;
33
35
34
use Koha::Patrons;
36
use Koha::Patrons;
35
use Koha::Patron::Categories;
37
use Koha::Patron::Categories;
38
use Koha::Account::Lines;
36
39
37
my $input = CGI->new;
40
my $input = CGI->new;
38
41
Lines 54-60 if ($input->param('borrowernumber')) { Link Here
54
    my $borrowernumber = $input->param('borrowernumber');
57
    my $borrowernumber = $input->param('borrowernumber');
55
    $patron = Koha::Patrons->find( $borrowernumber );
58
    $patron = Koha::Patrons->find( $borrowernumber );
56
}
59
}
57
58
my $logged_in_user = Koha::Patrons->find( $loggedinuser ) or die "Not logged in";
60
my $logged_in_user = Koha::Patrons->find( $loggedinuser ) or die "Not logged in";
59
output_and_exit_if_error( $input, $cookie, $template, { module => 'members', logged_in_user => $logged_in_user, current_patron => $patron } );
61
output_and_exit_if_error( $input, $cookie, $template, { module => 'members', logged_in_user => $logged_in_user, current_patron => $patron } );
60
62
Lines 92-97 if ( $op eq 'export_barcodes' ) { Link Here
92
    }
94
    }
93
}
95
}
94
96
97
if($op eq 'export_gdprdata') {
98
    my $exportedData = {
99
	'patron' => {
100
	    'title' => $patron->title,
101
	    'surname' => $patron->surname,
102
	    'firstname' => $patron->firstname,
103
	    'othernames' => $patron->othernames,
104
	    'initials' => $patron->initials,
105
	    'streetnumber' => $patron->streetnumber,
106
	    'streettype' => $patron->streettype,
107
	    'address' => $patron->address,
108
	    'address2' => $patron->address2,
109
	    'city' => $patron->city,
110
	    'state' => $patron->state,
111
	    'zipcode' => $patron->zipcode,
112
	    'country' => $patron->country,
113
	    'category_type' => $patron->category->category_type,
114
	    'email' => $patron->email,
115
	    'phone' => $patron->phone,
116
	    'mobile' => $patron->mobile,
117
	    'fax' => $patron->fax,
118
	    'emailpro' => $patron->emailpro,
119
	    'phonepro' => $patron->phonepro,
120
	    'B_streetnumber' => $patron->B_streetnumber,
121
	    'B_streettype' => $patron->B_streettype,
122
	    'B_address' => $patron->B_address,
123
	    'B_address2' => $patron->B_address2,
124
	    'B_city' => $patron->B_city,
125
	    'B_state' => $patron->B_state,
126
	    'B_zipcode' => $patron->B_zipcode,
127
	    'B_country' => $patron->B_country,
128
	    'B_email' => $patron->B_email,
129
	    'B_phone' => $patron->B_phone,
130
	    'dateoffbirth' => $patron->dateofbirth,
131
	    'categorycode' => $patron->categorycode,
132
	    'dateenrolled' => $patron->dateenrolled,
133
	    'dateexpiry' => $patron->dateexpiry,
134
	    'date_renewed' => $patron->date_renewed,
135
	    'gonenoaddress' => $patron->gonenoaddress,
136
	    'lost' => $patron->lost,
137
	    'debarred' => $patron->debarred,
138
	    'debarredcomment' => $patron->debarredcomment,
139
	    'contactname' => $patron->contactname,
140
	    'contactfirstname' => $patron->contactfirstname,
141
	    'contacttitle' => $patron->contacttitle,
142
	    'borrowernotes' => $patron->borrowernotes,
143
	    'sex' => $patron->sex,
144
	    'userid' => $patron->userid,
145
	    'opacnote' => $patron->opacnote,
146
	    'contactnote' => $patron->contactnote,
147
	    'altcontactfirstname' => $patron->altcontactfirstname,
148
	    'altcontactsurname' => $patron->altcontactsurname,
149
	    'altcontactaddress1' => $patron->altcontactaddress1,
150
	    'altcontactaddress2' => $patron->altcontactaddress2,
151
	    'altcontactaddress3' => $patron->altcontactaddress3,
152
	    'altcontactstate' => $patron->altcontactstate,
153
	    'altcontactzipcode' => $patron->altcontactzipcode,
154
	    'altcontactcountry' => $patron->altcontactcountry,
155
	    'altcontactphone' => $patron->altcontactphone,
156
	    'smsalertnumber' => $patron->smsalertnumber,
157
	    'updated_on' => $patron->updated_on,
158
	    'lastseen' => $patron->lastseen,
159
	    'lang' => $patron->lang,
160
	    'login_attempts' => $patron->login_attempts,
161
	    'account_locked' => $patron->account_locked,
162
	    'age' => $patron->get_age,
163
	    'has_overdues' => $patron->has_overdues,
164
	    'borrowernumber' => $patron->borrowernumber,
165
	    'cardnumber' => $patron->cardnumber,
166
	    'branchcode' => $patron->branchcode,
167
	    },
168
    };
169
170
    my $guarantor = $patron->guarantor();
171
    if($guarantor) {
172
	$exportedData->{'patron'}->{'guarantor'} =
173
	    $guarantor->{'borrowernumber'};
174
    }
175
    my @guarantees = $patron->guarantees();
176
    if(@guarantees) {
177
	foreach my $bod (@guarantees) {
178
	    push @{$exportedData->{'patron'}->{'guarantees'}}, $bod->borrowernumber;
179
	}
180
    }
181
182
    my $image = $patron->image;
183
    if($image) {
184
	$exportedData->{'image'} = {
185
	    'mimetype' => $image->mimetype,
186
	    'imagefile' => $image->imagefile,
187
	};
188
    }
189
190
    my $holds = $patron->holds;
191
    if($holds) {
192
	while(my $hold = $holds->next()) {
193
	    push @{$exportedData->{'holds'}}, {
194
		'reserve_id' => $hold->reserve_id,
195
		'reservedate' => $hold->reservedate,
196
		'biblionumber' => $hold->biblionumber,
197
		'branchcode' => $hold->branchcode,
198
		'nofificationdate' => $hold->notificationdate,
199
		'reminderdate' => $hold->reminderdate,
200
		'cancellationdate' => $hold->cancellationdate,
201
		'reservenotes' => $hold->reservenotes,
202
		'priority' => $hold->priority,
203
		'found' => $hold->found,
204
		'timestamp' => $hold->timestamp,
205
		'itemnumber' => $hold->itemnumber,
206
		'waitingdate' => $hold->waitingdate,
207
		'expirationdate' => $hold->expirationdate,
208
		'lowestPriority' => $hold->lowestPriority,
209
		'suspend' => $hold->suspend,
210
		'suspend_until' => $hold->suspend_until,
211
		'itemtype' => $hold->itemtype,
212
	    }
213
	}
214
    }
215
216
    my $oldHolds = $patron->old_holds;
217
    if($oldHolds) {
218
	while(my $hold = $oldHolds->next()) {
219
	    push @{$exportedData->{'holds'}}, {
220
		'reserve_id' => $hold->reserve_id,
221
		'reservedate' => $hold->reservedate,
222
		'biblionumber' => $hold->biblionumber,
223
		'branchcode' => $hold->branchcode,
224
		'nofificationdate' => $hold->notificationdate,
225
		'reminderdate' => $hold->reminderdate,
226
		'cancellationdate' => $hold->cancellationdate,
227
		'reservenotes' => $hold->reservenotes,
228
		'priority' => $hold->priority,
229
		'found' => $hold->found,
230
		'timestamp' => $hold->timestamp,
231
		'itemnumber' => $hold->itemnumber,
232
		'waitingdate' => $hold->waitingdate,
233
		'expirationdate' => $hold->expirationdate,
234
		'lowestPriority' => $hold->lowestPriority,
235
		'suspend' => $hold->suspend,
236
		'suspend_until' => $hold->suspend_until,
237
		'itemtype' => $hold->itemtype,
238
	    }
239
	}
240
    }
241
242
    my $checkouts = $patron->checkouts;
243
    if($checkouts) {
244
	while(my $checkout = $checkouts->next()) {
245
	    push @{$exportedData->{'checkouts'}}, {
246
		'issue_id' => $checkout->issue_id,
247
		'itemnumber' => $checkout->itemnumber,
248
		'date_due' => $checkout->date_due,
249
		'branchcode' => $checkout->branchcode,
250
		'returndate' => $checkout->returndate,
251
		'lastreneweddate' => $checkout->lastreneweddate,
252
		'renewals' =>$checkout->renewals,
253
		'auto_renew' => $checkout->auto_renew,
254
		'auto_renew_error' => $checkout->auto_renew_error,
255
		'timestamp' => $checkout->timestamp,
256
		'issuedate' => $checkout->issuedate,
257
		'onsite_checkout' => $checkout->onsite_checkout,
258
		'note' => $checkout->note,
259
		'notedate' => $checkout->notedate,
260
	    }
261
	}
262
    }
263
264
    my $oldCheckouts = $patron->old_checkouts;
265
    if($oldCheckouts) {
266
	while(my $checkout = $oldCheckouts->next()) {
267
	    push @{$exportedData->{'checkouts'}}, {
268
		'issue_id' => $checkout->issue_id,
269
		'itemnumber' => $checkout->itemnumber,
270
		'date_due' => $checkout->date_due,
271
		'branchcode' => $checkout->branchcode,
272
		'returndate' => $checkout->returndate,
273
		'lastreneweddate' => $checkout->lastreneweddate,
274
		'renewals' =>$checkout->renewals,
275
		'auto_renew' => $checkout->auto_renew,
276
		'auto_renew_error' => $checkout->auto_renew_error,
277
		'timestamp' => $checkout->timestamp,
278
		'issuedate' => $checkout->issuedate,
279
		'onsite_checkout' => $checkout->onsite_checkout,
280
		'note' => $checkout->note,
281
		'notedate' => $checkout->notedate,
282
	    }
283
	}
284
    }
285
286
    my $clubs = $patron->get_club_enrollments;
287
    if($clubs) {
288
	while(my $club = $clubs->next()) {
289
	    push @{$exportedData->{'clubs'}}, {
290
		id => $club->id,
291
		date_enrolled => $club->date_enrolled,
292
		date_canceled => $club->date_canceled,
293
		date_created => $club->date_created,
294
		date_updated => $club->date_updated,
295
		branchcode => $club->branchcode,
296
	    }
297
	}
298
    }
299
300
    my $account = $patron->account;
301
    if($account) {
302
	$exportedData->{'account'} = {
303
	    'balance' => $account->balance,
304
	    'non_issues_charges' => $account->non_issues_charges,
305
	};
306
	my $acclines = Koha::Account::Lines->search(
307
	    {
308
		borrowernumber => $patron->borrowernumber,
309
	    },
310
	    {
311
		order_by => 'accountno'
312
	    }
313
	    );
314
	while(my $thisLine = $acclines->next()) {
315
	    push @{$exportedData->{'account'}->{'accountLines'}}, {
316
		'accountlines_id' => $thisLine->accountlines_id,
317
		'payment_type' => $thisLine->payment_type,
318
		'amountoutstanding' => $thisLine->amountoutstanding,
319
		'accounttype' => $thisLine->accounttype,
320
		'timestamp' => $thisLine->timestamp,
321
		'issue_id' => $thisLine->issue_id,
322
		'description' => $thisLine->description,
323
		'lastincrement' => $thisLine->lastincrement,
324
		'date' => $thisLine->date,
325
		'amount' => $thisLine->amount,
326
		'manager_id' => $thisLine->manager_id,
327
		'note' => $thisLine->note,
328
	    }
329
	}
330
    }
331
332
    # Generate the JSON file and spit it out
333
    my $today = output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 });
334
    my $borrowercardnumber = $patron->cardnumber;
335
    print $input->header(
336
	-type        => 'application/json',
337
	-charset     => 'utf-8',
338
	-attachment  => "$today-$borrowercardnumber-GDPR-Export.json"
339
	);
340
    my $json = new JSON;
341
    print $json->pretty->encode($exportedData);
342
    exit;
343
}
344
95
if (! $limit){
345
if (! $limit){
96
	$limit = 'full';
346
	$limit = 'full';
97
}
347
}
98
- 

Return to bug 20028