X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=FS%2FFS%2Fexport_svc.pm;h=4579e6d4a535a8f2b1d21b61e89d412c7ba784a5;hp=da9ac698ae0eadd0672d662d4ccc1186282cc9a0;hb=57bb423fe457ba4e13726877f53bcdf944f828f8;hpb=c0567c688084e89fcd11bf82348b6c418f1254ac diff --git a/FS/FS/export_svc.pm b/FS/FS/export_svc.pm index da9ac698a..4579e6d4a 100644 --- a/FS/FS/export_svc.pm +++ b/FS/FS/export_svc.pm @@ -1,12 +1,9 @@ package FS::export_svc; +use base qw(FS::Record); use strict; -use vars qw( @ISA ); -use FS::Record qw( qsearch qsearchs ); -use FS::part_export; -use FS::part_svc; - -@ISA = qw(FS::Record); +use FS::Record qw( dbh qsearch ); #qsearchs ); +use FS::svc_export_machine; =head1 NAME @@ -41,6 +38,8 @@ The following fields are currently supported: =item svcpart - service definition (see L) +=item role - export role (see export parameters) + =back =head1 METHODS @@ -60,14 +59,203 @@ points to. You can ask the object for a copy with the I method. sub table { 'export_svc'; } -=item insert +=item insert [ JOB, OFFSET, MULTIPLIER ] Adds this record to the database. If there is an error, returns the error, otherwise returns false. +TODOC: JOB, OFFSET, MULTIPLIER + =cut -# the insert method can be inherited from FS::Record +sub insert { + my $self = shift; + my( $job, $offset, $mult ) = ( '', 0, 100); + $job = shift if @_; + $offset = shift if @_; + $mult = shift if @_; + + local $SIG{HUP} = 'IGNORE'; + local $SIG{INT} = 'IGNORE'; + local $SIG{QUIT} = 'IGNORE'; + local $SIG{TERM} = 'IGNORE'; + local $SIG{TSTP} = 'IGNORE'; + local $SIG{PIPE} = 'IGNORE'; + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + my $error = $self->check; + return $error if $error; + + #check for duplicates! + my @checks = (); + my $svcdb = $self->part_svc->svcdb; + if ( $svcdb eq 'svc_acct' ) { + + if ( $self->part_export->nodomain =~ /^Y/i ) { + push @checks, { + label => 'usernames', + method => 'username', + sortby => sub { $a cmp $b }, + }; + } else { + push @checks, { + label => 'username@domain', + method => 'email', + sortby => sub { + my($auser, $adomain) = split('@', $a); + my($buser, $bdomain) = split('@', $b); + $adomain cmp $bdomain || $auser cmp $buser; + }, + }; + } + + unless ( $self->part_svc->part_svc_column('uid')->columnflag eq 'F' ) { + push @checks, { + label => 'uids', + method => 'uid', + sortby => sub { $a <=> $b }, + }; + } + + } elsif ( $svcdb eq 'svc_domain' ) { + push @checks, { + label => 'domains', + method => 'domain', + sortby => sub { $a cmp $b }, + }; + } else { + warn "WARNING: No duplicate checking done on merge of $svcdb exports"; + } + + if ( @checks ) { + + my $done = 0; + my $percheck = $mult / scalar(@checks); + + foreach my $check ( @checks ) { + + if ( $job ) { + $error = $job->update_statustext(int( $offset + ($done+.33) *$percheck )); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + + my @current_svc = $self->part_export->svc_x; + #warn "current: ". scalar(@current_svc). " $current_svc[0]\n"; + + if ( $job ) { + $error = $job->update_statustext(int( $offset + ($done+.67) *$percheck )); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + + my @new_svc = $self->part_svc->svc_x; + #warn "new: ". scalar(@new_svc). " $new_svc[0]\n"; + + if ( $job ) { + $error = $job->update_statustext(int( $offset + ($done+1) *$percheck )); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + + my $method = $check->{'method'}; + my %cur_svc = map { $_->$method() => $_ } @current_svc; + my @dup_svc = grep { $cur_svc{$_->$method()} } @new_svc; + #my @diff_customer = grep { + # $_->cust_pkg->custnum != $cur_svc{$_->$method()}->cust_pkg->custnum + # } @dup_svc; + + + + if ( @dup_svc ) { #aye, that's the rub + #error out for now, eventually accept different options of adjustments + # to make to allow us to continue forward + $dbh->rollback if $oldAutoCommit; + + my @diff_customer_svc = grep { + my $cust_pkg = $_->cust_svc->cust_pkg; + my $custnum = $cust_pkg ? $cust_pkg->custnum : 0; + my $other_cust_pkg = $cur_svc{$_->$method()}->cust_svc->cust_pkg; + my $other_custnum = $other_cust_pkg ? $other_cust_pkg->custnum : 0; + $custnum != $other_custnum; + } @dup_svc; + + my $label = $check->{'label'}; + my $sortby = $check->{'sortby'}; + return "Can't export ". + $self->part_svc->svcpart.':'.$self->part_svc->svc. " service to ". + $self->part_export->exportnum.':'.$self->part_export->exporttype. + ' on '. $self->part_export->machine. + ' : '. scalar(@dup_svc). " duplicate $label". + ' ('. scalar(@diff_customer_svc). " from different customers)". + ": ". join(', ', sort $sortby map { $_->$method() } @dup_svc ) + #": ". join(', ', sort $sortby map { $_->$method() } @diff_customer_svc ) + ; + } + + $done++; + } + + } #end of duplicate check, whew + + $error = $self->SUPER::insert; + + my $part_export = $self->part_export; + if ( !$error and $part_export->default_machine ) { + foreach my $cust_svc ( $self->part_svc->cust_svc ) { + my $svc_export_machine = FS::svc_export_machine->new({ + 'exportnum' => $self->exportnum, + 'svcnum' => $cust_svc->svcnum, + 'machinenum' => $part_export->default_machine, + }); + $error ||= $svc_export_machine->insert; + } + } + + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + +# if ( $self->part_svc->svcdb eq 'svc_acct' ) { +# +# if ( $self->part_export->nodomain =~ /^Y/i ) { +# +# select username from svc_acct where svcpart = $svcpart +# group by username having count(*) > 1; +# +# } else { +# +# select username, domain +# from svc_acct +# join svc_domain on ( svc_acct.domsvc = svc_domain.svcnum ) +# group by username, domain having count(*) > 1; +# +# } +# +# } elsif ( $self->part_svc->svcdb eq 'svc_domain' ) { +# +# #similar but easier domain checking one +# +# } #etc.? +# +# my @services = +# map { $_->part_svc } +# grep { $_->svcpart != $self->svcpart } +# $self->part_export->export_svc; + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + ''; #no error +} =item delete @@ -75,7 +263,23 @@ Delete this record from the database. =cut -# the delete method can be inherited from FS::Record +sub delete { + my $self = shift; + my $dbh = dbh; + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + + my $error = $self->SUPER::delete; + foreach ($self->svc_export_machine) { + $error ||= $_->delete; + } + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + $dbh->commit or die $dbh->errstr if $oldAutoCommit; +} + =item replace OLD_RECORD @@ -105,7 +309,50 @@ sub check { || $self->ut_foreign_key('exportnum', 'part_export', 'exportnum') || $self->ut_number('svcpart') || $self->ut_foreign_key('svcpart', 'part_svc', 'svcpart') + || $self->ut_alphan('role') + || $self->SUPER::check ; + + my $part_export = $self->part_export; + if ( exists $part_export->info->{roles} ) { + my $role = $self->get('role'); + if ( ! $role ) { + return 'must select an export role' + } + if ( ! exists($part_export->info->{roles}->{$role}) ) { + return "invalid role for export '".$part_export->exporttype."'"; + } + } else { + $self->set('role', ''); + } + + ''; +} + +=item part_export + +Returns the FS::part_export object (see L). + +=item part_svc + +Returns the FS::part_svc object (see L). + +=item svc_export_machine + +Returns all export hostname records (L) for this +combination of svcpart and exportnum. + +=cut + +sub svc_export_machine { + my $self = shift; + qsearch({ + 'table' => 'svc_export_machine', + 'select' => 'svc_export_machine.*', + 'addl_from' => 'JOIN cust_svc USING (svcnum)', + 'hashref' => { 'exportnum' => $self->exportnum }, + 'extra_sql' => ' AND cust_svc.svcpart = '.$self->svcpart, + }); } =back