X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=FS%2FFS%2Fpart_export.pm;h=1a8f43de10097174ba511ece6f4ad7bdc0b0e488;hp=28cb1419da2f50fe9e909950ae7c3fff0ca5af33;hb=bb7e827141c9ed68f30765c9ca2ddcd1d760ad2d;hpb=ded0ab5cac02f099b387de360fb6dd6bd8cbb6b4 diff --git a/FS/FS/part_export.pm b/FS/FS/part_export.pm index 28cb1419d..1a8f43de1 100644 --- a/FS/FS/part_export.pm +++ b/FS/FS/part_export.pm @@ -1,16 +1,16 @@ package FS::part_export; +use base qw( FS::option_Common FS::m2m_Common ); use strict; use vars qw( @ISA @EXPORT_OK $DEBUG %exports ); use Exporter; use Tie::IxHash; -use base qw( FS::option_Common FS::m2m_Common ); use FS::Record qw( qsearch qsearchs dbh ); use FS::part_svc; use FS::part_export_option; use FS::part_export_machine; use FS::svc_export_machine; -use FS::export_svc; +use FS::export_cust_svc; #for export modules, though they should probably just use it themselves use FS::queue; @@ -59,6 +59,12 @@ fields are currently supported: =item nodomain - blank or "Y" : usernames are exported to this service with no domain +=item default_machine - For exports that require a machine to be selected for +each service (see L), the one to use as the default. + +=item no_suspend - Don't export service suspensions. In the future there may +be "no_*" options for the other service actions. + =back =head1 METHODS @@ -157,11 +163,26 @@ sub delete { local $FS::UID::AutoCommit = 0; my $dbh = dbh; + # delete associated export_cust_svc + foreach my $export_cust_svc ( + qsearch('export_cust_svc',{ 'exportnum' => $self->exportnum }) + ) { + my $error = $export_cust_svc->delete; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + # clean up export_nas records my $error = $self->process_m2m( 'link_table' => 'export_nas', 'target_table' => 'nas', 'params' => [], + ) || $self->process_m2m( + 'link_table' => 'export_svc', + 'target_table' => 'part_svc', + 'params' => [], ) || $self->SUPER::delete; if ( $error ) { $dbh->rollback if $oldAutoCommit; @@ -334,6 +355,7 @@ sub check { || $self->ut_textn('exportname') || $self->ut_domainn('machine') || $self->ut_alpha('exporttype') + || $self->ut_flag('no_suspend') ; if ( $self->machine eq '_SVC_MACHINE' ) { @@ -449,24 +471,10 @@ sub part_export_machine { Returns a list of associated FS::export_svc records. -=cut - -sub export_svc { - my $self = shift; - qsearch('export_svc', { 'exportnum' => $self->exportnum } ); -} - =item export_device Returns a list of associated FS::export_device records. -=cut - -sub export_device { - my $self = shift; - qsearch('export_device', { 'exportnum' => $self->exportnum } ); -} - =item part_export_option Returns all options as FS::part_export_option objects (see @@ -546,15 +554,19 @@ sub default_export_machine { die "no default export hostname for export ".$self->exportnum; } -#these should probably all go away, just let the subclasses define em - =item export_insert SVC_OBJECT =cut +# Do not overload! Overload _export_insert instead + sub export_insert { my $self = shift; #$self->rebless; + if ( $FS::svc_Common::noexport_hack ) { + carp "export_insert() suppressed by noexport_hack" if $DEBUG; + return; + } $self->_export_insert(@_); } @@ -571,9 +583,15 @@ sub export_insert { =cut +# Do not overload! Overload _export_replace instead + sub export_replace { my $self = shift; #$self->rebless; + if ( $FS::svc_Common::noexport_hack ) { + carp "export_replace() suppressed by noexport_hack" if $DEBUG; + return; + } $self->_export_replace(@_); } @@ -581,9 +599,15 @@ sub export_replace { =cut +# Do not overload! Overload _export_delete instead + sub export_delete { my $self = shift; #$self->rebless; + if ( $FS::svc_Common::noexport_hack ) { + carp "export_delete() suppressed by noexport_hack" if $DEBUG; + return; + } $self->_export_delete(@_); } @@ -591,9 +615,15 @@ sub export_delete { =cut +# Do not overload! Overload _export_suspend instead + sub export_suspend { my $self = shift; #$self->rebless; + if ( $FS::svc_Common::noexport_hack ) { + carp "export_suspend() suppressed by noexport_hack" if $DEBUG; + return; + } $self->_export_suspend(@_); } @@ -601,9 +631,15 @@ sub export_suspend { =cut +# Do not overload! Overload _export_unsuspend instead + sub export_unsuspend { my $self = shift; #$self->rebless; + if ( $FS::svc_Common::noexport_hack ) { + carp "export_unsuspend() suppressed by noexport_hack" if $DEBUG; + return; + } $self->_export_unsuspend(@_); } @@ -641,6 +677,81 @@ sub _export_unsuspend { $self->_export_replace( $svc_x, $old ); } +=item get_remoteid SVC + +Returns the remote id for this export for the given service. + +=cut + +sub get_remoteid { + my ($self, $svc_x) = @_; + + my $export_cust_svc = qsearchs('export_cust_svc',{ + 'exportnum' => $self->exportnum, + 'svcnum' => $svc_x->svcnum + }); + + return $export_cust_svc ? $export_cust_svc->remoteid : ''; +} + +=item set_remoteid SVC VALUE + +Sets the remote id for this export for the given service. +See L. + +If value is true, inserts or updates export_cust_svc record. +If value is false, deletes any existing record. + +Returns error message, blank on success. + +=cut + +sub set_remoteid { + my ($self, $svc_x, $value) = @_; + + my $export_cust_svc = qsearchs('export_cust_svc',{ + 'exportnum' => $self->exportnum, + 'svcnum' => $svc_x->svcnum + }); + + 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 = ''; + if ($value) { + if ($export_cust_svc) { + $export_cust_svc->set('remoteid',$value); + $error = $export_cust_svc->replace; + } else { + $export_cust_svc = new FS::export_cust_svc { + 'exportnum' => $self->exportnum, + 'svcnum' => $svc_x->svcnum, + 'remoteid' => $value + }; + $error = $export_cust_svc->insert; + } + } else { + if ($export_cust_svc) { + $error = $export_cust_svc->delete; + } #otherwise, it already doesn't exist + } + + if ($oldAutoCommit) { + $dbh->rollback if $error; + $dbh->commit unless $error; + } + + return $error; +} + =item export_links SVC_OBJECT ARRAYREF Adds a list of web elements to ARRAYREF specific to this export and SVC_OBJECT. @@ -694,7 +805,41 @@ sub info { }; } +=item get_dids SELECTION + +Does several things, which is unfortunate. DID phone numbers are organized +in a sort-of hierarchy: state, areacode, exchange, number. Or, for some +vendors: state, region, number. But not always that, either. + +SELECTION is one or more field/value pairs specifying parts of the hierarchy +that have already been selected. C will then return an arrayref of +the possible values for the next selection level. Note that these are not +actual DIDs except at the lowest level. + +Generally, 'state' alone will return an array of area codes or region names +in the state. + +'state' and 'areacode' together will return an array of either: +- exchange strings of the form "New York (212-555-XXXX)" +- ratecenter names of the form "New York, NY" + +These strings are sent back to the UI and offered as options so that the user +can choose the local calling area they like. + +'areacode' and 'exchange', or 'state' and 'ratecenter', or 'region' by itself +will return an array of actual DID numbers. + +Passing 'tollfree' with a true value will override the whole hierarchy and +return an array of tollfree numbers. + +C methods should report errors via die(). + +=cut + +# no stub; can('get_dids') should return false by default + #default fallbacks... FS::part_export::DID_Common ? +sub can_get_dids { 0; } sub get_dids_can_tollfree { 0; } sub get_dids_can_manual { 0; } sub get_dids_can_edit { 0; } #don't use without can_manual, otherwise the @@ -702,6 +847,79 @@ sub get_dids_can_edit { 0; } #don't use without can_manual, otherwise the # inventory each edit sub get_dids_npa_select { 1; } +# get_dids_npa_select: if true, then prompt to select state, then area code, +# then city/exchange, then phone number. +# if false, then prompt to select state (actually province), then "region", +# then phone number. +# +# get_dids_can_manual: if true, then there will be a radio button to enter +# a phone number manually. +# +# get_dids_can_tollfree: if true, then the user will be prompted to choose +# both a regular and a toll-free number. The export can have a +# 'restrict_selection' option to enable only one or the other of those. See +# part_export/vitelity.pm for an example. +# +# get_dids_can_edit: if true, then the user can use the selector again to +# change the phone number for a service. if false, then they can't (have to +# reprovision completely). + +=item svc_role SVC + +Returns the role that SVC occupies with respect to this export, if any. +This is part of the part_svc's export configuration. + +=cut + +sub svc_role { + my $self = shift; + my $svc_x = shift; + my $cust_svc = $svc_x->cust_svc or return ''; + my $export_svc = qsearchs('export_svc', { exportnum => $self->exportnum, + svcpart => $cust_svc->svcpart }) + or return ''; + $export_svc->role; +} + +=item svc_with_role { SVC | PKGNUM }, ROLE + +Given a svc_* object SVC or pkgnum PKG, and a role name ROLE, finds the +service(s) in the same package that are linked to this export with ROLE. + +=cut + +sub svc_with_role { + my $self = shift; + my $svc_or_pkgnum = shift; + my $role = shift; + my $pkgnum; + if ( ref $svc_or_pkgnum ) { + $pkgnum = $svc_or_pkgnum->cust_svc->pkgnum or return ''; + } else { + $pkgnum = $svc_or_pkgnum; + } + my $role_info = $self->info->{roles}->{$role} + or die "role '$role' does not exist for export '".$self->exporttype."'\n"; + my $svcdb = $role_info->{svcdb}; + + my @svcs = qsearch({ + 'table' => $svcdb, + 'addl_from' => ' JOIN cust_svc USING (svcnum)' . + ' JOIN export_svc USING (svcpart)', + 'extra_sql' => " WHERE cust_svc.pkgnum = $pkgnum" . + " AND export_svc.exportnum = ".$self->exportnum . + " AND export_svc.role = '$role'", + }); + if ( $role_info->{multiple} ) { + return @svcs; + } else { + if ( @svcs > 1 ) { + warn "multiple $role services in pkgnum $pkgnum; returning the first one.\n"; + } + return $svcs[0]; + } +} + =back =head1 SUBROUTINES