8 use FS::Record qw(qsearch qsearchs);
14 use FS::part_referral;
16 use FS::UID qw(adminsuidsetup);
22 my $s_dbname = 'DBI:Pg:dbname=optigoldimport';
23 my $s_dbuser = 'freeside';
25 my $extension = '.htm';
27 #my $d_dbuser = 'freeside';
28 my $d_dbuser = 'enet';
29 #my $d_dbuser = 'ivan';
30 #my $d_dbuser = 'freesideimport';
32 my $radius_file = 'radius.csv';
33 my $email_file = 'email.csv';
37 my $legacy_domain_svcnum = 1;
38 my $legacy_ppp_svcpart = 2;
39 my $legacy_email_svcpart = 3;
40 #my $legacy_broadband_svcpart = 4;
41 #my $legacy_broadband_svcpart = 14;
42 #my $previous_credit_reasonnum = 1;
43 my $previous_credit_reasonnum = 1220;
46 my $state = ''; #statemachine-ish
63 $s_dbh = DBI->connect($s_dbname, $s_dbuser, $s_dbpass,
66 'ShowErrorStatement' => 1
70 foreach ( qw ( billcycle cust email product ) ) {
73 print "parsing $sourcefile\n";
75 die "bad file name" unless $sourcefile =~ /^\w+$/;
81 if ( $c_sth = $s_dbh->prepare("SELECT COUNT(*) FROM $sourcefile") ) {
82 if ( $c_sth->execute ) {
83 if ( $c_sth->fetchrow_arrayref->[0] ) {
84 warn "already have data in $sourcefile table; skipping";
90 my $tp = new HTML::TableParser( \@args, { Decode => 1, Trim => 1, Chomp => 1 });
91 $tp->parse_file($sourcefile.$extension) or die "failed";
92 $s_dbh->commit or die $s_dbh->errstr;
98 warn "start\n" if $DEBUG;
100 die "unexpected state change" unless $state eq '';
101 die "unexpected table" unless $table_id eq '1';
106 warn "end\n" if $DEBUG;
107 my ($tbl_id, $line, $udata) = @_;
108 die "unexpected state change in header" unless $state eq 'rows';
109 die "unexpected table" unless $tbl_id eq '1';
114 warn "header\n" if $DEBUG;
115 my ($tbl_id, $line, $cols, $udata) = @_;
116 die "unexpected state change in header" unless $state eq 'table';
117 die "unexpected table" unless $tbl_id eq '1';
120 die "invalid column ". join (', ', grep { !/^[ \w\r]+$/ } @$cols)
121 if scalar(grep { !/^[ \w\r]+$/ } @$cols);
123 my $sql = "CREATE TABLE $sourcefile ( ".
124 join(', ', map { s/[ \r]/_/g; "$_ varchar NULL" } @$cols). " )";
125 $s_dbh->do($sql) or die "create table failed: ". $s_dbh->errstr;
126 $columncount = scalar( @$cols );
130 warn "row\n" if $DEBUG;
131 my ($tbl_id, $line, $cols, $udata) = @_;
132 die "unexpected state change in row" unless $state eq 'rows';
133 die "unexpected table" unless $tbl_id eq '1';
135 die "invalid number of columns: ". join(', ', @$cols)
136 unless (scalar(@$cols) == $columncount);
138 my $sql = "INSERT INTO $sourcefile VALUES(".
139 join(', ', map { $s_dbh->quote($_) } @$cols). ")";
140 $s_dbh->do($sql) or die "insert failed: ". $s_dbh->errstr;
142 warn "row $rowcount\n" unless ($rowcount % 1000);
145 ## now svc_acct from CSV files
147 $FS::cust_main::import=1;
148 $FS::cust_pkg::disable_agentcheck = 1;
149 $FS::cust_svc::ignore_quantity = 1;
151 my (%master_map) = ();
152 my (%referrals) = ();
158 my (%cust_pkg_map) = ();
159 my (%object_map) = ();
160 my (%package_cache) = ();
163 my $d_dbh = adminsuidsetup $d_dbuser;
164 local $FS::UID::AutoCommit = 0;
166 my @import = ( { 'file' => $radius_file,
168 'fields' => [ qw( garbage1 username garbage2 garbage3 _password ) ],
172 foreach qw (garbage1 garbage2 garbage3);
173 $hash->{'svcpart'} = $legacy_ppp_svcpart;
174 $hash->{'domsvc'} = $legacy_domain_svcnum;
177 'mapkey' => 'legacy_ppp',
178 'skey' => 'username',
180 { 'file' => $email_file,
182 'fields' => [ qw( username null finger _password status garbage ) ],
186 if $object_map{'legacy_ppp'}{$hash->{'username'}};
188 foreach qw (null status garbage);
189 $hash->{'svcpart'} = $legacy_email_svcpart;
190 $hash->{'domsvc'} = $legacy_domain_svcnum;
193 'mapkey' => 'legacy_email',
194 'skey' => 'username',
199 my $href = shift @import;
200 my $file = $href->{'file'} or die "No file specified";
201 my (@fields) = @{$href->{'fields'}};
202 my ($sep_char) = $href->{'sep_char'} || ';';
203 my ($fixup) = $href->{'fixup'};
204 my ($mapkey) = $href->{'mapkey'};
205 my ($skey) = $href->{'skey'};
208 my $csv = new Text::CSV_XS({'sep_char' => $sep_char});
209 open(FH, $file) or die "cannot open $file: $!";
212 while ( defined($line=<FH>) ) {
215 $line &= "\177" x length($line); # i hope this isn't really necessary
217 or die "cannot parse: " . $csv->error_input();
219 my @values = $csv->fields();
221 foreach my $field (@fields) {
222 $hash{$field} = shift @values;
226 warn "skipping malformed line: $line\n";
230 my $skip = &{$fixup}(\%hash)
234 my $svc_acct = new FS::svc_acct { %hash };
235 my $error = $svc_acct->insert;
241 if ($skey && $mapkey) {
242 my $key = (ref($skey) eq 'CODE') ? &{$skey}($svc_acct) : $hash{$skey};
243 $object_map{$mapkey}{$key} = $svc_acct->svcnum;
249 print "Imported $count service records\n";
256 my ( $href ) = ( shift );
257 $href->{'one_time_list'}
259 # : int(eval "$href->{'months_credit'} + 0");
260 : int(eval "$href->{'month_credit'} + 0");
264 my ( $field, $hash ) = ( shift, shift );
265 $field = 'bill_'. $field
266 if $hash->{'billing_use'} eq 'Billing Address';
271 my ( $field, $hash ) = ( shift, shift );
272 $field = 'bill_'. $field
273 if $hash->{'billing_use'} eq 'Billing Address';
274 my $ac = ( $hash->{$field. '_area_code'}
275 && $hash->{$field. '_area_code'} =~ /^\d{3}$/ )
276 ? $hash->{$field. '_area_code'}. '-'
279 ( $hash->{$field} && $hash->{$field} =~ /^\d{3}-\d{4}$/)
280 ? $ac. $hash->{$field}
285 my ( $field, $hash ) = ( shift, shift );
286 $hash->{'billing_use'} eq 'Billing Address' ? $hash->{$field} : '';
290 my ( $field, $hash ) = ( shift, shift );
291 $hash->{'billing_use'} eq 'Billing Address' && $hash->{$field} =~ /^\d{3}-\d{4}$/
292 ? ( $hash->{$field. '_area_code'} =~ /^\d{3}$/
293 ? $hash->{$field. '_area_code'}. '-'
299 my %payby_map = ( '' => 'BILL',
301 'Credit Card' => 'CARD',
302 'Bank Debit' => 'CHEK',
303 'Virtual Check' => 'CHEK',
306 $payby_map{ shift->{billing_type} };
311 my $payby = payby($hash);
314 $hash->{'credit_card_number_1'}.
315 $hash->{'credit_card_number_2'}.
316 $hash->{'credit_card_number_3'}.
317 $hash->{'credit_card_number_4'};
319 $hash->{'bank_account_number'}.
321 $hash->{'bank_transit_number'};
322 if ($payby eq 'CARD') {
324 }elsif ($payby eq 'CHEK') {
326 }elsif ($payby eq 'BILL') {
327 $info = $hash->{'blanket_purchase_order_number'};
328 $bank =~ s/[^\d\@]//g;
330 if ( $bank =~ /^\d+\@\d{9}/) {
334 if ( $cc =~ /^\d{13,16}/ ) {
339 die "unexpected payby";
345 my ($object, $field) = (shift, shift);
346 my $value = $object->getfield($field);
347 $value =~ s/[^\w \,\.\-\']/ /g;
348 $object->setfield($field, $value);
352 my ($object, $field) = (shift, shift);
353 my $value = $object->getfield($field);
354 $value =~ s/[^\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=\[\]]/ /g;
355 $object->setfield($field, $value);
359 my ($object, $field) = (shift, shift);
360 my $value = $object->getfield($field);
361 $value = 'TX' if $value eq 'TTX';
362 $object->setfield($field, $value);
366 my ($object, $field) = (shift, shift);
367 my $value = $object->getfield($field);
368 $value =~ s/[^-\d]//g;
369 $object->setfield($field, $value);
373 #part_pkg => { 'stable' => 'product',
374 part_pkg => { 'stable' => 'billcycle',
376 { 'pkg' => sub { my $href = shift;
377 $href->{'description'}
378 ? $href->{'description'}
379 : $href->{'product_id'};
381 'comment' => 'product_id',
382 'freq' => sub { pkg_freq(shift) },
383 'recur' => sub { my $href = shift;
384 my $price = ( pkg_freq($href)
385 ? $href->{'unit_price'}
388 $price =~ s/[^\d.]//g;
389 $price = 0 unless $price;
390 sprintf("%.2f", $price);
392 'setuptax' => sub { my $href = shift;
393 $href->{'taxable'} ? '' : 'Y';
395 'recurtax' => sub { my $href = shift;
396 $href->{'taxable'} ? '' : 'Y';
398 'plan' => sub { 'flat' },
399 'disabled' => sub { 'Y' },
400 'pkg_svc' => sub { my $href = shift;
402 if (pkg_freq($href)){
403 $result->{$legacy_ppp_svcpart} = 1;
404 $result->{$legacy_email_svcpart} =
405 $href->{emails_allowed}
406 if $href->{emails_allowed};
409 'primary_svc'=> sub { pkg_freq(shift)
410 ? $legacy_ppp_svcpart
415 'fixup' => sub { my $part_pkg = shift;
417 unless ($part_pkg->pkg =~ /^\s*(\S[\S ]*?)\s*$/) {
418 warn "no pkg: ". $part_pkg->pkg. " for ". $row->{product_id};
422 unless ($part_pkg->comment =~ /^\s*(\S[\S ]*?)\s*$/) {
423 warn "no comment: ". $part_pkg->comment. " for ". $row->{product_id};
427 return 1 if exists($package_cache{$1});
428 $package_cache{$1} = $part_pkg;
431 'wrapup' => sub { foreach (keys %package_cache) {
432 my $part_pkg = $package_cache{$_};
434 { map { my $v = $part_pkg->$_;
441 $part_pkg->insert(options=>$options);
442 die "Error inserting package: $error"
444 $count++ unless $error;
448 part_referral => { 'stable' => 'cust',
450 { 'agentnum' => sub { $agentnum },
451 'referral' => sub { my $r = shift->{'referred_from'};
455 'fixup' => sub { 1 },
456 'wrapup' => sub { foreach (keys %referrals) {
458 new FS::part_referral( {
459 'agentnum' => $agentnum,
460 'referral' => $referrals{$_},
462 my $error = $part_referral->insert;
463 die "Error inserting referral: $error"
465 $count++ unless $error;
466 $referrals{$_} = $part_referral->refnum;
470 #svc_acct => { 'stable' => 'cust',
472 # { 'username' => 'login',
473 # '_password' => 'password',
474 # 'svcpart' => sub{ $legacy_ppp_svcpart },
475 # 'domsvc' => sub{ $legacy_domain_svcnum },
476 # 'status' => 'status',
478 # 'fixup' => sub { my $svc_acct = shift;
480 # my $id = $row->{'master_account'}
481 # ? 'slave:'. $row->{'customer_id'}
483 # my $status = $svc_acct->status;
484 # if ( $status ne 'Current'
485 # && $status ne 'On Hold' )
488 # str2time($row->{termination_date});
489 # warn "not creating (cancelled) svc_acct for " .
490 # $svc_acct->username. "\n";
493 # $susp{$id} = str2time($row->{hold_date})
494 # if $status eq 'On Hold';
495 # $adjo{$id} = str2time($row->{hold_date})
496 # if ( $status eq 'Current' &&
497 # $row->{hold_date} );
499 # str2time($row->{expiration_date});
502 # 'skey' => sub { my $svc_acct = shift;
504 # my $id = $row->{'master_account'}
505 # ? 'slave:'. $row->{'customer_id'}
509 cust_main => { 'stable' => 'cust',
511 { 'agentnum' => sub { $agentnum },
512 'agent_custid' => sub { my $id = shift->{'customer_number'};
513 if (exists($custid{$id})) {
515 $id. chr(64 + $custid{$id});
521 'last' => sub { b_or('last_name', shift) || ' ' },
522 'first' => sub { b_or('first_name', shift) || ' ' },
523 'stateid' => 'drivers_license_number',
524 'signupdate' => sub { str2time(shift->{'creation_date'}) },
525 'company' => sub { b_or('company_name', shift) },
526 'address1' => sub { b_or('address', shift) || ' ' },
527 'city' => sub { b_or('city', shift) || 'Paris' },
528 'state' => sub { uc(b_or('state', shift)) || 'TX' },
529 'zip' => sub { b_or('zip_code', shift) || '75460' },
530 'country' => sub { 'US' },
531 'daytime' => sub { p_or('phone', shift) },
532 'night' => sub { p_or('phone_alternate_1', shift) },
533 'fax' => sub { p_or('fax', shift) },
534 'ship_last' => sub { or_b('last_name', shift) },
535 'ship_first' => sub { or_b('first_name', shift) },
536 'ship_company' => sub { or_b('company_name', shift) },
537 'ship_address1'=> sub { or_b('address', shift) },
538 'ship_city' => sub { or_b('city', shift) },
539 'ship_state' => sub { uc(or_b('state', shift)) },
540 'ship_zip' => sub { or_b('zip_code', shift) },
541 'ship_daytime' => sub { or_p('phone', shift) },
542 'ship_fax' => sub { or_p('fax', shift) },
543 'tax' => sub { shift->{taxable} eq '' ? 'Y' : '' },
544 'refnum' => sub { $referrals{shift->{'referred_from'}}
548 'fixup' => sub { my $cust_main = shift;
551 my ($master_account, $customer_id, $login) =
553 $row->{'master_account'} =~ /^\s*(\S[\S ]*?)\s*$/
554 && ($master_account = $1);
555 $row->{'customer_id'} =~ /^\s*(\S[\S ]*?)\s*$/
556 && ($customer_id = $1);
557 $row->{'login'} =~ /^\s*(\S[\S ]*?)\s*$/
560 my $id = $master_account
561 ? 'slave:'. $customer_id
563 my $status = $row->{status};
566 if ( $status ne 'Current'
567 && $status ne 'On Hold' )
571 str2time($row->{termination_date});
573 $susp{$login} = str2time($row->{hold_date})
574 if ($status eq 'On Hold' && !$cancelled);
575 $adjo{$login} = str2time($row->{hold_date})
576 if ( $status eq 'Current' && !$cancelled &&
579 str2time($row->{expiration_date})
583 $object_map{legacy_ppp}{$row->{'login'} };
584 unless( $cancelled || $svcnum ) {
585 warn "can't find svc_acct for legacy ppp ".
586 $row->{'login'}, "\n";
589 $object_map{svc_acct}{$id} = $svcnum
592 $master_map{$login} = $row->{master_account}
593 if $row->{master_account};
594 return 1 if $row->{master_account};
595 $cust_main->ship_country('US')
596 if $cust_main->has_ship_address;
597 ut_name_fixup($cust_main, 'first');
598 ut_name_fixup($cust_main, 'company');
599 ut_name_fixup($cust_main, 'last');
601 my ($info, $payby) = payinfo($row);
602 $cust_main->payby($payby);
603 $cust_main->payinfo($info);
606 $row->{'credit_card_cvv_number'}
608 if ($payby eq 'CARD' or $payby eq 'DCRD');
610 $cust_main->paydate('20'.
611 $row->{'credit_card_exp_date_2'}. '-'.
613 $row->{'credit_card_exp_date_1'},
619 if ($payby eq 'CARD' or $payby eq 'DCRD');
622 $payname = $row->{'credit_card_name'}
623 if ($payby eq 'CARD' or $payby eq 'DCRD');
624 $payname = $row->{'bank_name'}
625 if ($payby eq 'CHEK' or $payby eq 'DCHK');
626 $cust_main->payname($payname);
629 $row->{'bank_account_to_debit'}
631 $row->{bank_account_to_debit}
634 if ($payby eq 'CHEK' or $payby eq 'DCHK');
636 $cust_main->payby('BILL')
637 if ($cust_main->payby eq 'CHEK' &&
638 $cust_main->payinfo !~ /^\d+\@\d{9}$/);
639 $cust_main->payby('BILL')
640 if ($cust_main->payby eq 'CARD' &&
641 $cust_main->payinfo =~ /^\s*$/);
642 $cust_main->paydate('2037-12-01')
643 if ($cust_main->payby eq 'BILL');
644 ut_text_fixup($cust_main, 'address1');
645 ut_state_fixup($cust_main, 'state');
646 ut_zip_fixup($cust_main, 'zip');
651 'skey' => sub { my $object = shift;
653 my $balance = sprintf("%.2f",
654 $href->{balance_due});
656 my $cust_credit = new FS::cust_credit({
657 'custnum' => $object->custnum,
658 'amount' => sprintf("%.2f", -$balance),
659 'reasonnum' => $previous_credit_reasonnum,
661 my $error = $cust_credit->insert;
662 warn "Error inserting credit for ",
663 $href->{'login'}, " : $error\n"
666 }elsif($balance > 0) {
667 my $error = $object->charge(
668 $balance, "Prior balance",
670 warn "Error inserting balance charge for ",
671 $href->{'login'}, " : $error\n"
678 #cust_main => { 'stable' => 'cust',
680 # { 'referred_by' => sub { my $href = shift;
681 # my $u = shift->{'login'};
682 # my $cn = $href->{'customer_number'};
684 # my $c = qsearch( 'cust_main',
685 # { 'custnum' => $cn }
686 # ) or die "can't fine customer $cn";
688 # my $s = qsearch( 'svc_acct',
689 # { 'username' => $u }
692 # my $n = $s->cust_svc
697 # $c->referral_custnum($n);
698 # my $error = $c->replace;
699 # die "error setting referral: $error"
704 # 'fixup' => sub { 1 },
706 cust_pkg => { 'stable' => 'billcycle',
708 { 'custnum' => sub { my $l = shift->{cbilling_cycle_login};
709 $l =~ /^\s*(\S[\S ]*?)\s*$/ && ($l = $1);
710 my $r = $object_map{'cust_main'}{$l};
712 my $m = $master_map{$l};
713 $r = $object_map{'cust_main'}{$m}
718 'pkgpart' => sub { my $p = shift->{product_id};
719 $p =~ /^\s*(\S[\S ]*?)\s*$/ && ($p = $1);
721 ? $package_cache{$p}->pkgpart
724 'setup' => sub { str2time(shift->{creation_date}) },
725 'bill' => sub { my $href = shift;
726 #my $id = $href->{'slave_account_id'}
727 # ? 'slave:'. $href->{'slave_account_id'}
728 # : $href->{'cbilling_cycle_login'};
730 $bill{$href->{cbilling_cycle_login}};
732 'susp' => sub { my $href = shift;
733 #my $id = $href->{'slave_account_id'}
734 # ? 'slave:'. $href->{'slave_account_id'}
735 # : $href->{'cbilling_cycle_login'};
737 $susp{$href->{cbilling_cycle_login}};
739 'adjo' => sub { my $href = shift;
740 #my $id = $href->{'slave_account_id'}
741 # ? 'slave:'. $href->{'slave_account_id'}
742 # : $href->{'cbilling_cycle_login'};
744 $adjo{$href->{cbilling_cycle_login}};
746 'cancel' => sub { my $href = shift;
747 #my $id = $href->{'slave_account_id'}
748 # ? 'slave:'. $href->{'slave_account_id'}
749 # : $href->{'cbilling_cycle_login'};
751 $cancel{$href->{cbilling_cycle_login}};
754 'fixup' => sub { my ($object, $row) = (shift,shift);
755 unless ($object->custnum) {
756 warn "can't find customer for ".
757 $row->{cbilling_cycle_login}. "\n";
760 unless ($object->pkgpart) {
761 warn "can't find package for ".
762 $row->{product_id}. "\n";
767 'skey' => sub { my $object = shift;
769 if ($href->{'slave_account_id'} =~ /^\s*(\S[\S ]*?)\s*$/) {
772 my $id = $href->{'billing_cycle_item_id'};
773 $cust_pkg_map{$id} = $object->pkgnum;
774 $href->{'cbilling_cycle_login'};
777 'wrapup' => sub { for my $id (keys %{$object_map{'cust_pkg'}}){
779 qsearchs( 'cust_svc', { 'svcnum' =>
780 $object_map{'svc_acct'}{$id} }
783 warn "can't find legacy ppp $id\n";
787 pkgnum($object_map{'cust_pkg'}{$id});
788 my $error = $cust_svc->replace;
789 warn "error linking legacy ppp $id: $error\n"
794 svc_acct => { 'stable' => 'email',
796 { 'username' => 'email_name',
797 '_password' => 'password',
798 'svcpart' => sub{ $legacy_email_svcpart },
799 'domsvc' => sub{ $legacy_domain_svcnum },
801 # 'fixup' => sub { my ($object, $row) = (shift,shift);
802 # my ($sd,$sm,$sy) = split '/',
803 # $row->{shut_off_date}
804 # if $row->{shut_off_date};
805 # if ($sd && $sm && $sy) {
806 # my ($cd, $cm, $cy) = (localtime)[3,4,5];
807 # $cy += 1900; $cm++;
808 # return 1 if $sy < $cy;
809 # return 1 if ($sy == $cy && $sm < $cm);
810 # return 1 if ($sy == $cy && $sm == $cm && $sd <= $cd);
812 # return 1 if $object_map{'cust_main'}{$object->username};
815 'fixup' => sub { my ($object, $row) = (shift,shift);
816 my ($sd,$sm,$sy) = split '/',
817 $row->{shut_off_date}
818 if $row->{shut_off_date};
819 if ($sd && $sm && $sy) {
820 my ($cd, $cm, $cy) = (localtime)[3,4,5];
822 return 1 if $sy < $cy;
823 return 1 if ($sy == $cy && $sm < $cm);
824 return 1 if ($sy == $cy && $sm == $cm && $sd <= $cd);
826 return 1 if $object_map{'cust_main'}{$object->username};
829 $object_map{legacy_email}{$row->{'email_name'} };
831 warn "can't find svc_acct for legacy email ".
832 $row->{'email_name'}, "\n";
836 $object_map{svc_acct}{'email:'.$row->{'email_customer_id'}} = $svcnum;
839 # 'skey' => sub { my $object = shift;
841 # 'email:'. $href->{'email_customer_id'};
843 'wrapup' => sub { for my $id (keys %{$object_map{'cust_pkg'}}){
844 next unless $id =~ /^email:(\d+)/;
847 qsearchs( 'cust_svc', { 'svcnum' =>
848 $object_map{'svc_acct'}{$id} }
851 warn "can't find legacy email $id\n";
856 pkgnum($cust_pkg_map{$custid});
857 my $error = $cust_svc->replace;
858 warn "error linking legacy email $id: $error\n"
865 #my $s_dbh = DBI->connect($s_datasrc, $s_dbuser, $s_dbpass) or die $DBI::errstr;
868 my ($table, $href) = (shift @tables, shift @tables);
869 my $stable = $href->{'stable'} or die "No source table"; # good enough for now
870 my (%mapping) = %{$href->{'mapping'}};
871 my ($fixup) = $href->{'fixup'};
872 my ($wrapup) = $href->{'wrapup'};
873 my ($id) = $href->{'id'};
874 my ($skey) = $href->{'skey'};
876 #$d_dbh->do("delete from $table");
878 my $s_sth = $s_dbh->prepare("select count(*) from $stable");
879 $s_sth->execute or die $s_sth->errstr;
880 my $rowcount = $s_sth->fetchrow_arrayref->[0];
882 $s_sth = $s_dbh->prepare("select * from $stable");
883 $s_sth->execute or die $s_sth->errstr;
887 while ( $row = $s_sth->fetchrow_hashref ) {
888 my $class = "FS::$table";
890 warn sprintf("%.2f", 100*$count/$rowcount). "% of $table processed\n"
891 unless( !$count || $count % 100 );
893 my $object = new $class ( {
894 map { $_ => ( ref($mapping{$_}) eq 'CODE'
895 ? &{$mapping{$_}}($row)
896 : $row->{$mapping{$_}}
901 my $skip = &{$fixup}($object, $row)
905 my $error = $object->insert;
907 warn "Error inserting $table ".
908 join(", ", map{"$_ => ". $object->get($_)} fields $object).
913 my $key = (ref($skey) eq 'CODE') ? &{$skey}($object, $row)
915 $object_map{$table}{$key} = $object->get($object->primary_key)
924 print "$count/$rowcount of $table SUCCESSFULLY processed\n";
931 $d_dbh->commit or die $d_dbh->errstr;