adding basic program to convert from Apollo LDF to staging tables
[migration-tools.git] / apollo / apollo_exporter.pl
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5
6 use Data::Dumper;
7 use Getopt::Long;
8 use XML::LibXML;
9 use Switch;
10 use open ':encoding(utf8)';
11
12 select(STDERR);
13 $| = 1;
14 select(STDOUT); 
15 $| = 1;
16
17 my $mig_schema;
18 my $ldif_xml;
19
20 my $ret = GetOptions(
21     'ldif_xml:s'     => \$ldif_xml
22 );
23 if (!defined $ldif_xml) {$ldif_xml = 'export.xml'};
24
25 print "Parsing LDIF ... ";
26 my $parser = XML::LibXML->new();
27 my $dom = $parser->parse_file($ldif_xml);
28 print "done.\n\n";
29
30 user_defined_values($dom,'user_defined_values.tsv');
31 asset_copy_locations($dom,'asset_copy_location_legacy.tsv');
32 actor_usr_groups($dom,'actor_usr_legacy_groups.tsv');
33 actor_usr($dom,'actor_usr_legacy.tsv','actor_usr_address_legacy.tsv','actor_usr_phones.tsv','actor_usr_note_legacy.tsv','money_billing_legacy.tsv');
34 biblio_record_entry($dom,'biblio_record_entry_legacy.tsv');
35 action_uses($dom,'action_in_house_use_legacy.tsv','in-library'); 
36 action_uses($dom,'action_circulation_legacy.tsv','circulation');
37 action_uses($dom,'action_transit_copy_legacy.tsv','transit');
38 action_uses($dom,'action_hold_request_shelf.tsv','reserve');
39 action_hold_request($dom,'action_hold_request_legacy.tsv');
40 asset_copy($dom,'asset_copy_legacy.tsv');
41 asset_copy_note($dom,'asset_copy_note_legacy.tsv');
42
43 print "Staging tables conversion completed.\n\n";
44
45 #################################################################
46 sub user_defined_values {
47     my $dom = shift;
48     my $outfile = shift;
49
50     print "Parsing for user defined values... ";
51     my @user_defined; 
52     foreach my $def ($dom->findnodes('//userdef')) {
53         push @user_defined, {
54             id          => $def->findvalue('./@id'),
55             record_type => $def->findvalue('./@record'),
56             name        => $def->findvalue('./@name'),
57             type        => $def->findvalue('./@type')
58         };  
59     }
60    
61     my $num_rows = @user_defined;
62         
63     open my $out_fh, ">:utf8", $outfile or die "can not open $outfile file for writing.\n";
64
65     print "writing $outfile ... ";
66
67     print $out_fh "id\trecord_type\tname\ttype\n";
68
69     foreach my $built_hash( @user_defined ) { 
70         print $out_fh "$built_hash->{id}\t";
71         print $out_fh "$built_hash->{record_type}\t";
72         print $out_fh "$built_hash->{name}\t";
73         print $out_fh "$built_hash->{type}\n";
74     }   
75
76     close $out_fh;
77     print "$num_rows rows written plus headers.\n";
78 }
79
80 sub asset_copy_note {
81     my $dom = shift;
82     my $outfile = shift;
83
84     print "Parsing for holdings values... ";
85     my @holdings;
86     foreach my $copy ($dom->findnodes('//holding')) {
87         if (length($copy->findvalue('./@deleted')) > 1) { next; }
88         foreach my $note ($copy->findnodes('.//holdingNote')) {
89             push @holdings, {
90                 copy_id => $copy->findvalue('./@id'),
91                 active  => $note->findvalue('./@active'),
92                 note    => $note->findvalue('./@note')
93             };
94         }
95     }
96
97     my $num_rows = @holdings;
98
99     open my $out_fh, ">:utf8", $outfile or die "can not open $outfile file for writing.\n";
100     print "writing $outfile ... ";
101     print $out_fh "copy_id\tactive\tnote\n";
102     foreach my $built_hash( @holdings ) {
103         print $out_fh "$built_hash->{copy_id}\t";
104         print $out_fh "$built_hash->{active}\t";
105         print $out_fh "$built_hash->{note}\n";
106     }
107
108     close $out_fh;
109     print "$num_rows rows written plus headers.\n";
110 }
111
112 sub asset_copy {
113     my $dom = shift;
114     my $outfile = shift;
115
116     print "Parsing for holdings values... ";
117     my @holdings;
118     foreach my $copy ($dom->findnodes('//holding')) {
119         if (length($copy->findvalue('./@deleted')) > 1) { next; }
120         my $memberships;
121         foreach my $mship ($copy->findnodes('./membership')) {
122             if (defined $memberships) { $memberships = $memberships . '|' . $mship->to_literal; }
123                 else { $memberships = $mship->to_literal; }
124         }
125         push @holdings, {
126             id           => $copy->findvalue('./@id'),
127             memberships  => $memberships,
128             location     => $copy->findvalue('./@location'),
129             deleted_type => $copy->findvalue('./@deletedType'),
130             status       => $copy->findvalue('./@status'),
131             deleted      => $copy->findvalue('./@deleted'),
132             barcode      => $copy->findvalue('./@barcode'),
133             biblio       => $copy->findvalue('./@biblio'),
134             usage_count  => $copy->findvalue('./@usageCount'),
135             price_cents  => $copy->findvalue('./@priceCents'),
136             call         => $copy->findvalue('./@call'),
137             edited       => $copy->findvalue('./@edited')
138         }; 
139     }
140   
141     my $num_rows = @holdings;
142
143     open my $out_fh, ">:utf8", $outfile or die "can not open $outfile file for writing.\n";
144     print "writing $outfile ... ";
145     print $out_fh "id\tmemberships\tlocation\tdeleted_type\tstatus\tdeleted\tbarcode\tbiblio\tusage_count\tprice_cents\tcall\tedited\n";
146     foreach my $built_hash( @holdings ) {
147         print $out_fh "$built_hash->{id}\t";
148         print $out_fh "$built_hash->{memberships}\t";
149         print $out_fh "$built_hash->{location}\t";
150         print $out_fh "$built_hash->{deleted_type}\t";
151         print $out_fh "$built_hash->{status}\t";
152         print $out_fh "$built_hash->{deleted}\t";
153         print $out_fh "$built_hash->{barcode}\t";
154         print $out_fh "$built_hash->{biblio}\t";
155         print $out_fh "$built_hash->{usage_count}\t";
156         print $out_fh "$built_hash->{price_cents}\t";
157         print $out_fh "$built_hash->{call}\t";
158         print $out_fh "$built_hash->{edited}\n";
159     }  
160
161     close $out_fh;
162     print "$num_rows rows written plus headers.\n";
163 }
164
165 sub action_hold_request {
166     my $dom = shift;
167     my $out_file = shift;
168
169     print "Parsing users data for hold requests ... ";
170     my @holds;
171     foreach my $patron ($dom->findnodes('///patron')) {
172         foreach my $request ($patron->findnodes('.//reserve')) {
173             if (length($request->findvalue('./@resolved')) > 1) { next; }
174             push @holds, {   #patron id, reserve id should be redundant but leaving in for error checking
175                 id => $request->findvalue('./@id'),
176                 patron_barcode => $patron->findvalue('./@barcode'),
177                 patron_id => $patron->findvalue('./@id'),
178                 biblio => $request->findvalue('./@biblio'),
179                 status => $request->findvalue('./@status'),
180                 resolved => $request->findvalue('./@resolved'),
181                 placed => $request->findvalue('./@placed'),
182             };
183         }
184     }
185
186     my $num_rows = @holds;
187     open my $out_fh, ">:utf8", $out_file or die "can not open $out_file file for writing.\n";
188     print "writing $out_file ... \n";
189     print $out_fh "id\tpatron_barcode\tpatron_id\tbiblio\tstatus\tresolved\tplaced\n";
190     foreach my $built_hash( @holds ) {
191         print $out_fh "$built_hash->{id}\t";
192         print $out_fh "$built_hash->{patron_barcode}\t";
193         print $out_fh "$built_hash->{patron_id}\t";
194         print $out_fh "$built_hash->{biblio}\t";
195         print $out_fh "$built_hash->{status}\t";
196         print $out_fh "$built_hash->{resolved}\t";
197         print $out_fh "$built_hash->{placed}\n";
198     }
199     close $out_fh;
200     print "$num_rows rows written plus headers to $out_file.\n";
201 }
202
203 sub asset_copy_locations {
204     my $dom = shift;
205     my $outfile = shift;
206
207     print "Parsing for copy locations... ";
208     my @copy_locations;  
209     foreach my $membershiplist ($dom->findnodes('///holdingMembershipList')) {
210         my $membershiplist_id = $membershiplist->findvalue('./@id'); 
211         my $membershiplist_name = $membershiplist->findvalue('./@name');
212         foreach my $membership ($membershiplist->findnodes('./holdingMembership')) {
213             push @copy_locations, {
214                 membership_list_id   => $membershiplist_id,
215                 membership_list_name => $membershiplist_name,
216                 membership_number    => $membership->findvalue('./@number'),
217                 membership_name      => $membership->findvalue('./@name'),
218                 membership_id        => $membership->findvalue('./@id')
219             };
220         }
221     } 
222
223     my $num_rows = @copy_locations;
224     
225     open my $out_fh, ">:utf8", $outfile or die "can not open $outfile file for writing.\n";
226
227     print "writing $outfile ... ";
228
229     #print headers
230     print $out_fh "membership_list_id\tmembership_list_name\tmembership_id\tmembership_number\tmembership_name\n";
231
232     foreach my $built_hash( @copy_locations ) {
233         print $out_fh "$built_hash->{membership_list_id}\t";
234         print $out_fh "$built_hash->{membership_list_name}\t";
235         print $out_fh "$built_hash->{membership_number}\t";
236         print $out_fh "$built_hash->{membership_name}\t";
237         print $out_fh "$built_hash->{membership_id}\n";
238     }
239
240     close $out_fh;
241     print "$num_rows rows written plus headers.\n";
242 }
243
244
245 sub action_uses {
246     my $dom = shift;
247     my $outfile = shift;
248     my $table_type = shift;
249
250     switch ($table_type) {
251         case 'transit'      {print "Parsing for copy transits ... ";}
252         case 'in-library'   {print "Parsing for in house uses ... ";}
253         case 'circulation'  {print "Parsing for circulations ... ";}
254     }
255
256     my @checkouts;  #not exporting the memberships since we have the patron id to link
257     foreach my $circ ($dom->findnodes('//checkout')) {
258         my $renewals = 0;
259         if ($table_type eq 'circulation') {
260             if ($circ->findvalue('./@type') ne 'normal') { next; }
261             if (length($circ->findvalue('./@due')) < 1) { next; } #bunch of records with no due dates, cause not clear
262             if (length($circ->findvalue('./@returned')) > 0) { next; }
263         }
264         if ($table_type eq 'transit') {
265             if ($circ->findvalue('./@type') ne 'transt') { next; }
266             if (length($circ->findvalue('./@returned')) > 0) { next; }
267         }
268         if ($table_type eq 'in-library') {
269             if ($circ->findvalue('./@type') ne 'in-library') { next; }
270         }
271         if ($table_type eq 'reserve') {
272             if ($circ->findvalue('./@type') ne 'reserve') { next; } 
273             if ($circ->findvalue('./@status') ne 'out') { next; }
274         }
275
276         foreach ($circ->findnodes('./renewal')) { 
277             $renewals++;  #normally don't move move over previous circs in renewal sequence so just counting them
278         }
279         push @checkouts, {
280             id                  => $circ->findvalue('./@id'),
281             patron              => $circ->findvalue('./@patron'),
282             out                 => $circ->findvalue('./@out'),
283             due                 => $circ->findvalue('./@due'),
284             status              => $circ->findvalue('./@status'),
285             holding             => $circ->findvalue('./@holding'),
286             returned            => $circ->findvalue('./@returned'),
287             type                => $circ->findvalue('./@type'),
288             out_location        => $circ->findvalue('./@outLocation'),
289             returned_location   => $circ->findvalue('./@returnedLocation'),
290             reserve_id          => $circ->findvalue('./@reserveId'),
291             self_check          => $circ->findvalue('./@selfCheck'),
292             renewals            => $renewals
293         };  
294     }   
295
296     my $num_rows = @checkouts;
297             
298     open my $out_fh, ">:utf8", $outfile or die "can not open $outfile file for writing.\n";
299
300     print "writing $outfile ... ";
301     
302     print $out_fh "id\tpatron\tout\tdue\tstatus\tholding\treturned\ttype\tout_location\treturned_location\treserve_id\tself_check\trenewals\n";
303
304     foreach my $built_hash( @checkouts ) { 
305         print $out_fh "$built_hash->{id}\t";
306         print $out_fh "$built_hash->{patron}\t";
307         print $out_fh "$built_hash->{out}\t";
308         print $out_fh "$built_hash->{due}\t";
309         print $out_fh "$built_hash->{status}\t";
310         print $out_fh "$built_hash->{holding}\t";
311         print $out_fh "$built_hash->{returned}\t";
312         print $out_fh "$built_hash->{type}\t";
313         print $out_fh "$built_hash->{out_location}\t";
314         print $out_fh "$built_hash->{returned_location}\t";
315         print $out_fh "$built_hash->{reserve_id}\t";
316         print $out_fh "$built_hash->{self_check}\t";
317         print $out_fh "$built_hash->{renewals}\n";
318     }   
319     close $out_fh;
320     print "$num_rows rows written plus headers.\n";
321
322 }
323
324 sub actor_usr_groups {
325     my $dom = shift;
326     my $outfile = shift;
327
328     print "Parsing for user groups... ";
329     my @user_groups;  
330     foreach my $membershiplist ($dom->findnodes('///patronMembershipList')) {
331
332         my $membershiplist_id = $membershiplist->findvalue('./@id'); 
333         my $membershiplist_name = $membershiplist->findvalue('./@name');
334         foreach my $membership ($membershiplist->findnodes('./patronMembership')) {
335             push @user_groups, {
336                 membership_list_id   => $membershiplist_id,
337                 membership_list_name => $membershiplist_name,
338                 membership_length_months    => $membership->findvalue('./@membershipLengthMonths'),
339                 membership_name      => $membership->findvalue('./@name'),
340                 membership_id        => $membership->findvalue('./@id'),
341                 membership_number    => $membership->findvalue('./@number')
342             };  
343         }   
344     }   
345
346     my $num_rows = @user_groups;
347         
348     open my $out_fh, ">:utf8", $outfile or die "can not open $outfile file for writing.\n";
349
350     print "writing $outfile ... ";
351
352     print $out_fh "membership_list_id\tmembership_list_name\tmembership_id\tmembership_number\tmembership_name\tmembership_length_months\n";
353
354     foreach my $built_hash( @user_groups ) { 
355         print $out_fh "$built_hash->{membership_list_id}\t";
356         print $out_fh "$built_hash->{membership_list_name}\t";
357         print $out_fh "$built_hash->{membership_number}\t";
358         print $out_fh "$built_hash->{membership_name}\t";
359         print $out_fh "$built_hash->{membership_id}\t";
360         print $out_fh "$built_hash->{membership_length_months}\n";
361     }
362
363     close $out_fh;
364     print "$num_rows rows written plus headers.\n";
365 }
366
367 sub actor_usr {
368     my $dom = shift;
369     my $out_user_file = shift;
370     my $out_address_file = shift;
371     my $out_phone_file = shift;
372     my $out_note_file = shift;
373     my $out_fine_file = shift;
374
375     my @users; 
376     my @user_addresses;
377     my @user_phones;
378     my @user_notes;
379     my @patron_fines;
380
381     print "Parsing users for addresses, patrons, fines, notes, etc... \n";
382     foreach my $patron ($dom->findnodes('///patron')) {
383         my $first_names;
384         my $middle_names;
385         my $preferred_names;
386         my $birthdates;
387         foreach my $f_name ($patron->findnodes('.//firstName')) {
388             if (defined $first_names) { $first_names = $first_names . '|' . $f_name->findvalue('./@name'); }
389                 else { $first_names = $f_name->findvalue('./@name'); }
390             if (defined $birthdates) { $birthdates = $birthdates . '|' . $f_name->findvalue('./@birthdate'); }
391                 else { $birthdates = $f_name->findvalue('./@birthdate'); }
392             if (defined $middle_names) { $middle_names = $middle_names . '|' . $f_name->findvalue('./@middleName'); }
393                 else { $middle_names = $f_name->findvalue('./@middleName'); }
394             if (defined $preferred_names) { $preferred_names = $preferred_names . '|' . $f_name->findvalue('./@preferredName'); }
395                 else { $preferred_names = $f_name->findvalue('./@preferredName'); }
396         }       
397         my $memberships;
398         foreach my $mship ($patron->findnodes('.//membership')) {
399             if (defined $memberships) { $memberships = $memberships . '|' . $mship->to_literal; }
400                 else { $memberships = $mship->to_literal; }
401         }
402         my $emails;  
403         foreach my $email ($patron->findnodes('.//email')) {
404             if (defined $emails) { $emails = $emails . ',' . $email->findvalue('./@address'); }
405                 else { $emails = $email->findvalue('./@address'); }
406         }  
407         #lazy code, do programatically later
408         my $u3710;
409         my $u3714;
410         foreach my $ud ($patron->findnodes('./userdefVal')) {
411             if ($ud->findvalue('./@uID') eq 'u3710') { $u3710 = $ud->findvalue('./@value')};
412             if ($ud->findvalue('./@uID') eq 'u3714') { $u3714 = $ud->findvalue('./@value')};
413         } 
414         push @users, {
415             patron_barcode => $patron->findvalue('./@barcode'),
416             created => $patron->findvalue('./@created'),
417             usage_count => $patron->findvalue('./@usageCount'),
418             family_id => $patron->findvalue('./@familyID'),
419             expiration => $patron->findvalue('./@expiration'),
420             patron_id => $patron->findvalue('./@id'),
421             last_name => $patron->findvalue('./@lastName'),
422             edited => $patron->findvalue('./@edited'),
423             emails => $emails,
424             first_names => $first_names,
425             middle_names => $middle_names,
426             preferred_names => $preferred_names,
427             birthdates => $birthdates,
428             memberships => $memberships,
429             reserve_contact => $patron->findvalue('./reserveContactDefault/@contact'),
430             reserve_contact_sms => $patron->findvalue('./reserveContactDefault/@sms'),
431             overdue_contact => $patron->findvalue('./overdueContact/@contact'),
432             overdue_contact_sms => $patron->findvalue('./overdueContact/@sms'),
433             due_warning_contact => $patron->findvalue('./dueWarningContact/@contact'),
434             due_warning_contact_sms => $patron->findvalue('./dueWarningContact/@sms'),
435             internet => $u3714,
436             birthdate => $u3710
437         };
438         
439         my $lines;
440         foreach my $address ($patron->findnodes('.//address')) {
441             foreach my $add_line ($address->findnodes('./line')) {
442                 if (defined $lines) { $lines = $lines . '|' . $add_line->to_literal; }
443                     else { $lines = $add_line->to_literal; }
444                 }
445             push @user_addresses, {
446                 patron_barcode => $patron->findvalue('./@barcode'),
447                 patron_id => $patron->findvalue('./@id'),
448                 lines => $lines,
449                 locality => $address->findvalue('./@locality'),
450                 country_division => $address->findvalue('./@countryDivision'),
451                 country => $address->findvalue('./@country'),
452                 postal_code => $address->findvalue('./@postalCode'),
453                 mailing => $address->findvalue('./@mailing')
454             };
455         }
456
457         foreach my $phone ($patron->findnodes('.//phone')) {
458             push @user_phones, {
459                 patron_barcode => $patron->findvalue('./@barcode'),
460                 patron_id => $patron->findvalue('./@id'),
461                 number => $phone->findvalue('./@number'),
462                 area_code => $phone->findvalue('./@areaCode'),
463                 type => $phone->findvalue('./@type'),  #should be home/work/mobile/other/none
464                 phone_id => $phone->findvalue('./@id'),
465                 country_code => $phone->findvalue('./@countryCode')
466             };
467         }
468
469         foreach my $note ($patron->findnodes('.//patronNote')) {
470             my $message = $note->findvalue('./@message');
471             $message =~ s/\\$//;
472             push @user_notes, {
473                 patron_barcode => $patron->findvalue('./@barcode'),
474                 patron_id => $patron->findvalue('./@id'),
475                 active => $note->findvalue('./@active'),
476                 signature => $note->findvalue('./@signature'),
477                 urgent => $note->findvalue('./@urgent'),
478                 sensitive => $note->findvalue('./@sensitive'),
479                 date_added => $note->findvalue('./dateAdded'),
480                 date_cleared => $note->findvalue('./dateCleared'),
481                 last_updated => $note->findvalue('./dateUpdated'),
482                 message => $message
483             };  
484         }   
485         
486         foreach my $fine ($patron->findnodes('.//fine')) {
487             push @patron_fines, {
488                 patron_barcode => $patron->findvalue('./@barcode'),
489                 patron_id => $patron->findvalue('./@id'),
490                 fine_id => $fine->findvalue('./@id'), 
491                 checkout => $fine->findvalue('./@checkout'),
492                 amount_paid_cents => $fine->findvalue('./@amountPaidCents'),
493                 status => $fine->findvalue('./@status'),
494                 updated => $fine->findvalue('./@updated'),
495                 amountCents=> $fine->findvalue('./@amountCents')
496             };
497         }
498
499     }
500
501     my $num_user_rows = @users;
502     open my $out_user_fh, ">:utf8", $out_user_file or die "can not open $out_user_file file for writing.\n";
503     print "writing $out_user_file ... \n";
504     print $out_user_fh "patron_id\tpatron_barcode\tcreated\tusage_count\tfamily_id\texpiration\tedited\tlast_name\tfirst_name\tmiddle_name\tpreferred_name\tbirthdates\temails\tmemberships\treserve_contact\treserve_contact_sms\toverdue_contact\toverdue_contact_sms\tdue_warning_contact\tdue_warning_sms\tbirthdate\tinternet\n";
505     foreach my $built_user_hash( @users ) {
506         print $out_user_fh "$built_user_hash->{patron_id}\t";
507         print $out_user_fh "$built_user_hash->{patron_barcode}\t";
508         print $out_user_fh "$built_user_hash->{created}\t";
509         print $out_user_fh "$built_user_hash->{usage_count}\t";
510         print $out_user_fh "$built_user_hash->{family_id}\t";
511         print $out_user_fh "$built_user_hash->{expiration}\t";
512         print $out_user_fh "$built_user_hash->{edited}\t";
513         print $out_user_fh "$built_user_hash->{last_name}\t";
514         print $out_user_fh "$built_user_hash->{first_names}\t"; #plural names indicate arrays seperated by pipe
515         print $out_user_fh "$built_user_hash->{middle_names}\t";
516         print $out_user_fh "$built_user_hash->{preferred_names}\t";
517         print $out_user_fh "$built_user_hash->{birthdates}\t";
518         print $out_user_fh "$built_user_hash->{emails}\t";
519         print $out_user_fh "$built_user_hash->{memberships}\t";
520         print $out_user_fh "$built_user_hash->{reserve_contact}\t";
521         print $out_user_fh "$built_user_hash->{reserve_contact_sms}\t";
522         print $out_user_fh "$built_user_hash->{overdue_contact}\t";
523         print $out_user_fh "$built_user_hash->{overdue_contact_sms}\t";
524         print $out_user_fh "$built_user_hash->{due_warning_contact}\t";
525         print $out_user_fh "$built_user_hash->{due_warning_contact_sms}\t";
526         print $out_user_fh "$built_user_hash->{birthdate}\t";
527         print $out_user_fh "$built_user_hash->{internet}\n";
528     } 
529     close $out_user_fh;
530     print "$num_user_rows rows written plus headers to $out_user_file.\n";
531
532     my $num_address_rows = @user_addresses;
533     open my $out_address_fh, ">:utf8", $out_address_file or die "can not open $out_address_file file for writing.\n";
534     print "writing $out_address_file ... \n";
535     print $out_address_fh "patron_id\tpatron_barcode\tlines\tlocality\tcountry_division\tcountry\tpostal_code\tmailing\n";
536     foreach my $built_address_hash( @user_addresses ) { 
537         print $out_address_fh "$built_address_hash->{patron_id}\t";
538         print $out_address_fh "$built_address_hash->{patron_barcode}\t";
539         print $out_address_fh "$built_address_hash->{lines}\t";
540         print $out_address_fh "$built_address_hash->{locality}\t";
541         print $out_address_fh "$built_address_hash->{country_division}\t";
542         print $out_address_fh "$built_address_hash->{country}\t";
543         print $out_address_fh "$built_address_hash->{postal_code}\t";
544         print $out_address_fh "$built_address_hash->{mailing}\n";
545     }   
546     close $out_address_fh;
547     print "$num_address_rows rows written plus headers to $out_address_file.\n";
548
549     my $num_phone_rows = @user_phones;
550     open my $out_phone_fh, ">:utf8", $out_phone_file or die "can not open $out_phone_file file for writing.\n";
551     print "writing $out_phone_file ... \n";
552     print $out_phone_fh "patron_id\tpatron_barcode\tphone_id\tnumber\tarea_code\ttype\tcountry_code\n";
553     foreach my $built_phone_hash( @user_phones ) {
554         print $out_phone_fh "$built_phone_hash->{patron_id}\t";
555         print $out_phone_fh "$built_phone_hash->{patron_barcode}\t";
556         print $out_phone_fh "$built_phone_hash->{phone_id}\t";
557         print $out_phone_fh "$built_phone_hash->{number}\t";
558         print $out_phone_fh "$built_phone_hash->{area_code}\t";
559         print $out_phone_fh "$built_phone_hash->{type}\t";
560         print $out_phone_fh "$built_phone_hash->{country_code}\n";
561     }
562     close $out_phone_fh;
563     print "$num_phone_rows rows written plus headers to $out_phone_file.\n";
564
565     my $num_note_rows = @user_notes;
566     open my $out_note_fh, ">:utf8", $out_note_file or die "can not open $out_note_file file for writing.\n";
567     print "writing $out_note_file ... \n";
568     print $out_note_fh "patron_id\tpatron_barcode\tactive\tsignature\turgent\tsensitive\tdate_added\tdate_cleared\tlast_updated\tmessage\n";
569     foreach my $built_note_hash( @user_notes ) {
570         print $out_note_fh "$built_note_hash->{patron_id}\t";
571         print $out_note_fh "$built_note_hash->{patron_barcode}\t";
572         print $out_note_fh "$built_note_hash->{active}\t";
573         print $out_note_fh "$built_note_hash->{signature}\t";
574         print $out_note_fh "$built_note_hash->{urgent}\t";
575         print $out_note_fh "$built_note_hash->{sensitive}\t";
576         print $out_note_fh "$built_note_hash->{date_added}\t";
577         print $out_note_fh "$built_note_hash->{date_cleared}\t";
578         print $out_note_fh "$built_note_hash->{last_updated}\t";
579         print $out_note_fh "$built_note_hash->{message}\n";
580     }
581     close $out_note_fh;
582     print "$num_note_rows rows written plus headers to $out_note_file.\n";
583
584     my $num_fine_rows = @patron_fines;
585     open my $out_fine_fh, ">:utf8", $out_fine_file or die "can not open $out_fine_file file for writing.\n";
586     print "writing $out_fine_file ... \n";
587     print $out_fine_fh "patron_id\tpatron_barcode\tfine_id\tcheckout\tamount_paid_cents\tstatus\tupdated\tamountCents\n";
588     foreach my $built_fine_hash( @patron_fines ) {
589         print $out_fine_fh "$built_fine_hash->{patron_id}\t";
590         print $out_fine_fh "$built_fine_hash->{patron_barcode}\t";
591         print $out_fine_fh "$built_fine_hash->{fine_id}\t";
592         print $out_fine_fh "$built_fine_hash->{checkout}\t";
593         print $out_fine_fh "$built_fine_hash->{amount_paid_cents}\t";
594         print $out_fine_fh "$built_fine_hash->{status}\t";
595         print $out_fine_fh "$built_fine_hash->{updated}\t";
596         print $out_fine_fh "$built_fine_hash->{amountCents}\n";
597     }
598     close $out_fine_fh;
599     print "$num_fine_rows rows written plus headers to $out_fine_file.\n";
600 }
601
602 sub biblio_record_entry {
603     my $dom = shift;
604     my $outfile = shift;
605
606     open my $out_fh, ">:utf8", $outfile or die "can not open $outfile file for writing.\n";
607     my $num_rows = 0;
608     print "Parsing for bib records...\n";
609     print $out_fh "id\tusage_count\tstatus\tadded\tedited\tmarc\n"; 
610     foreach my $bib ($dom->findnodes('///biblio')) {
611         my $id = $bib->findvalue('./@id');
612         my $usageCount = $bib->findvalue('./@usageCount');
613         my $status = $bib->findvalue('./@status');
614         my $added = $bib->findvalue('./@added');
615         my $edited = $bib->findvalue('./@edited');
616         my $marc = $bib->toString;
617         $marc =~ s/<marc:/</g;
618         $marc =~ s/<\/marc:/<\//g;
619         $marc =~ s/<bib.+?>//g;
620         $marc =~ s/<\/bib.+?>//g;
621         $marc =~ s/\R//g;
622         $marc =~ s/\s+</</g;
623         $marc =~ s/>\s+/>/g;
624         print $out_fh "$id\t";
625         print $out_fh "$usageCount\t";
626         print $out_fh "$status\t";
627         print $out_fh "$added\t";
628         print $out_fh "$edited\t";
629         print $out_fh "$marc\n"; 
630         $num_rows++;
631     }
632     close $out_fh;
633     print "$num_rows rows written plus headers.\n";
634 }
635
636 sub abort {
637     my $msg = shift;
638     print STDERR "$0: $msg", "\n";
639     print_usage();
640     exit 1;
641 }
642
643    
644 sub print_usage {
645     print <<_USAGE_;
646
647 LDIF Exporter loads an ldif xml file version 032 into staging tables 
648 to load into Evergreen.  This implementation assumes that the user 
649 is using a distinct Postgres schema to stage tables from.  The Exporter
650 creates linked tables in the schema to production tables that inherit 
651 sequences and then child tables with data to manipulate.  
652
653 For example: patron data will be loaded in m_foo.actor_usr which inherits
654 from actor.usr and a m_foo.actor_usr_legacy is created.  The table is 
655 prepopulated with likely data but legacy value is suppplied in the legacy 
656 table in l_ so it can be non-destrutively manipulated.
657
658 LDIF Exporter requires the following parameter:   
659
660   --mig_schema - the staging schema of the migration
661
662 Optionally you may also provide a file with --ldif_xml 
663
664 If --ldif_xml is not used then it will assume there is an export.xml file and
665 fail if not found.
666
667
668
669 _USAGE_
670 }
671