diff options
Diffstat (limited to 'FS')
-rw-r--r-- | FS/FS/ClientAPI/MyAccount.pm | 30 | ||||
-rw-r--r-- | FS/FS/ClientAPI_XMLRPC.pm | 1 | ||||
-rw-r--r-- | FS/FS/Misc/Savepoint.pm | 2 | ||||
-rw-r--r-- | FS/FS/UID.pm | 12 | ||||
-rw-r--r-- | FS/FS/access_user.pm | 98 | ||||
-rw-r--r-- | FS/FS/contact.pm | 13 | ||||
-rw-r--r-- | FS/FS/cust_bill.pm | 6 | ||||
-rw-r--r-- | FS/FS/cust_main.pm | 34 | ||||
-rw-r--r-- | FS/FS/cust_main/Billing.pm | 17 | ||||
-rw-r--r-- | FS/FS/cust_main/Billing_Realtime.pm | 31 | ||||
-rw-r--r-- | FS/FS/cust_payby.pm | 74 | ||||
-rw-r--r-- | FS/FS/part_export/nena2.pm | 8 | ||||
-rw-r--r-- | FS/FS/part_export/saisei.pm | 60 |
13 files changed, 355 insertions, 31 deletions
diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index 263b3116b..57d42982d 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -184,6 +184,29 @@ sub skin_info { } +sub get_mac_address { + my $p = shift; + +## access radius exports acct tables to get mac + my @part_export = (); + @part_export = ( + qsearch( 'part_export', { 'exporttype' => 'sqlradius' } ), + qsearch( 'part_export', { 'exporttype' => 'sqlradius_withdomain' } ), + qsearch( 'part_export', { 'exporttype' => 'broadband_sqlradius' } ), + ); + + my @sessions; + foreach my $part_export (@part_export) { + push @sessions, ( @{ $part_export->usage_sessions( { + 'ip' => $p->{'ip'}, + } ) } ); + } + + my $mac = $sessions[0]->{'callingstationid'}; + + return { 'mac_address' => $mac, }; +} + sub login_info { my $p = shift; @@ -239,8 +262,11 @@ sub login { } elsif ( $p->{'domain'} eq 'ip_mac' ) { - my $svc_broadband = qsearchs( 'svc_broadband', { 'mac_addr' => $p->{'username'} } ); - return { error => 'IP address not found' } + my $mac_address = $p->{'username'}; + $mac_address =~ s/\://g; + + my $svc_broadband = qsearchs( 'svc_broadband', { 'mac_addr' => $mac_address } ); + return { error => 'MAC address not found '.$p->{'username'} } unless $svc_broadband; $svc_x = $svc_broadband; diff --git a/FS/FS/ClientAPI_XMLRPC.pm b/FS/FS/ClientAPI_XMLRPC.pm index dcf34fdaa..db0537c02 100644 --- a/FS/FS/ClientAPI_XMLRPC.pm +++ b/FS/FS/ClientAPI_XMLRPC.pm @@ -227,6 +227,7 @@ sub ss2clientapi { 'quotation_add_pkg' => 'MyAccount/quotation/quotation_add_pkg', 'quotation_remove_pkg' => 'MyAccount/quotation/quotation_remove_pkg', 'quotation_order' => 'MyAccount/quotation/quotation_order', + 'get_mac_address' => 'MyAccount/get_mac_address', 'freesideinc_service' => 'Freeside/freesideinc_service', }; diff --git a/FS/FS/Misc/Savepoint.pm b/FS/FS/Misc/Savepoint.pm index b15b36ded..f8e2c5ff5 100644 --- a/FS/FS/Misc/Savepoint.pm +++ b/FS/FS/Misc/Savepoint.pm @@ -55,7 +55,7 @@ Savepoints cannot work while AutoCommit is enabled. Savepoint labels must be valid sql identifiers. If your choice of label would not make a valid column name, it probably will not make a valid label. -Savepint labels must be unique within the transaction. +Savepoint labels must be unique within the transaction. =cut diff --git a/FS/FS/UID.pm b/FS/FS/UID.pm index 50a917895..693e5d952 100644 --- a/FS/FS/UID.pm +++ b/FS/FS/UID.pm @@ -5,7 +5,7 @@ use strict; use vars qw( @EXPORT_OK $DEBUG $me $cgi $freeside_uid $conf_dir $cache_dir $secrets $datasrc $db_user $db_pass $schema $dbh $driver_name - $AutoCommit %callback @callback $callback_hack + $AutoCommit $ForceObeyAutoCommit %callback @callback $callback_hack ); use subs qw( getsecrets ); use Carp qw( carp croak cluck confess ); @@ -26,7 +26,17 @@ $freeside_uid = scalar(getpwnam('freeside')); $conf_dir = "%%%FREESIDE_CONF%%%"; $cache_dir = "%%%FREESIDE_CACHE%%%"; +# Code wanting to issue a COMMIT statement to the database is expected to +# obey the convention of checking this flag first. Setting $AutoCommit = 0 +# should (usually) suppress COMMIT statements. $AutoCommit = 1; #ours, not DBI + +# Not all methods obey $AutoCommit, by design choice. Setting +# $ForceObeyAutoCommit = 1 will override that design choice for: +# &FS::cust_main::Billing::collect +# &FS::cust_main::Billing::do_cust_event +$ForceObeyAutoCommit = 0; + $callback_hack = 0; =head1 NAME diff --git a/FS/FS/access_user.pm b/FS/FS/access_user.pm index a9fdf5b1e..f23aa77f9 100644 --- a/FS/FS/access_user.pm +++ b/FS/FS/access_user.pm @@ -12,6 +12,7 @@ use FS::Record qw( qsearch qsearchs dbh ); use FS::agent; use FS::cust_main; use FS::sales; +use Carp qw( croak ); $DEBUG = 0; $me = '[FS::access_user]'; @@ -814,6 +815,103 @@ sub set_page_pref { return $error; } +=item get_pref NAME + +Fetch the prefvalue column from L<FS::access_user_pref> for prefname NAME + +Returns undef when no value has been saved, or when record has expired + +=cut + +sub get_pref { + my ( $self, $prefname ) = @_; + croak 'prefname parameter requrired' unless $prefname; + + my $pref_row = $self->get_pref_row( $prefname ) + or return undef; + + return undef + if $pref_row->expiration + && $pref_row->expiration < time(); + + $pref_row->prefvalue; +} + +=item get_pref_row NAME + +Fetch the row object from L<FS::access_user_pref> for prefname NAME + +returns undef when no row has been created + +=cut + +sub get_pref_row { + my ( $self, $prefname ) = @_; + croak 'prefname parameter required' unless $prefname; + + qsearchs( + access_user_pref => { + usernum => $self->usernum, + prefname => $prefname, + } + ); +} + +=item set_pref NAME, VALUE, [EXPIRATION_EPOCH] + +Add or update user preference in L<FS::access_user_pref> table + +Passing an undefined VALUE will delete the user preference + +Returns VALUE + +=cut + +sub set_pref { + my $self = shift; + my ( $prefname, $prefvalue, $expiration ) = @_; + + return $self->delete_pref( $prefname ) + unless defined $prefvalue; + + if ( my $pref_row = $self->get_pref_row( $prefname )) { + return $prefvalue + if $pref_row->prefvalue eq $prefvalue; + + $pref_row->prefvalue( $prefvalue ); + $pref_row->expiration( $expiration || ''); + + if ( my $error = $pref_row->replace ) { croak $error } + + return $prefvalue; + } + + my $pref_row = FS::access_user_pref->new({ + usernum => $self->usernum, + prefname => $prefname, + prefvalue => $prefvalue, + expiration => $expiration, + }); + if ( my $error = $pref_row->insert ) { croak $error } + + $prefvalue; +} + +=item delete_pref NAME + +Delete user preference from L<FS::access_user_pref> table + +=cut + +sub delete_pref { + my ( $self, $prefname ) = @_; + + my $pref_row = $self->get_pref_row( $prefname ) + or return; + + if ( my $error = $pref_row->delete ) { croak $error } +} + =back =head1 BUGS diff --git a/FS/FS/contact.pm b/FS/FS/contact.pm index fa047f59d..81dfdbc01 100644 --- a/FS/FS/contact.pm +++ b/FS/FS/contact.pm @@ -199,8 +199,6 @@ sub insert { } - $error ||= $self->insert_password_history; - if ( $error ) { $dbh->rollback if $oldAutoCommit; return $error; @@ -302,6 +300,15 @@ sub insert { } } + if ( $self->get('password') ) { + my $error = $self->is_password_allowed($self->get('password')) + || $self->change_password($self->get('password')); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; @@ -811,7 +818,7 @@ sub authenticate_password { $hash eq $check_hash; - } else { + } else { return 0 if $self->_password eq ''; diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 47f71c458..7158cb285 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -41,6 +41,7 @@ use FS::cust_bill_void; use FS::reason; use FS::reason_type; use FS::L10N; +use FS::Misc::Savepoint; $DEBUG = 0; $me = '[FS::cust_bill]'; @@ -974,6 +975,9 @@ sub apply_payments_and_credits { local $FS::UID::AutoCommit = 0; my $dbh = dbh; + my $savepoint_label = 'cust_bill__apply_payments_and_credits'; + savepoint_create( $savepoint_label ); + $self->select_for_update; #mutex my @payments = grep { $_->unapplied > 0 } @@ -1062,6 +1066,7 @@ sub apply_payments_and_credits { my $error = $app->insert(%options); if ( $error ) { + savepoint_rollback_and_release( $savepoint_label ); $dbh->rollback if $oldAutoCommit; return "Error inserting ". $app->table. " record: $error"; } @@ -1069,6 +1074,7 @@ sub apply_payments_and_credits { } + savepoint_release( $savepoint_label ); $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; #no error diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index ea524dae4..2e8fe8159 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -79,6 +79,7 @@ use FS::sales; use FS::cust_payby; use FS::contact; use FS::reason; +use FS::Misc::Savepoint; # 1 is mostly method/subroutine entry and options # 2 traces progress of some operations @@ -2212,11 +2213,15 @@ sub cancel_pkgs { my( $self, %opt ) = @_; # we're going to cancel services, which is not reversible + # unless exports are suppressed die "cancel_pkgs cannot be run inside a transaction" - if $FS::UID::AutoCommit == 0; + if !$FS::UID::AutoCommit && !$FS::svc_Common::noexport_hack; + my $oldAutoCommit = $FS::UID::AutoCommit; local $FS::UID::AutoCommit = 0; + savepoint_create('cancel_pkgs'); + return ( 'access denied' ) unless $FS::CurrentUser::CurrentUser->access_right('Cancel customer'); @@ -2233,7 +2238,8 @@ sub cancel_pkgs { my $ban = new FS::banned_pay $cust_payby->_new_banned_pay_hashref; my $error = $ban->insert; if ($error) { - dbh->rollback; + savepoint_rollback_and_release('cancel_pkgs'); + dbh->rollback if $oldAutoCommit; return ( $error ); } @@ -2253,11 +2259,13 @@ sub cancel_pkgs { 'time' => $cancel_time ); if ($error) { warn "Error billing during cancel, custnum ". $self->custnum. ": $error"; - dbh->rollback; + savepoint_rollback_and_release('cancel_pkgs'); + dbh->rollback if $oldAutoCommit; return ( "Error billing during cancellation: $error" ); } } - dbh->commit; + savepoint_release('cancel_pkgs'); + dbh->commit if $oldAutoCommit; my @errors; # try to cancel each service, the same way we would for individual packages, @@ -2271,17 +2279,22 @@ sub cancel_pkgs { warn "$me removing ".scalar(@sorted_cust_svc)." service(s) for customer ". $self->custnum."\n" if $DEBUG; + my $i = 0; foreach my $cust_svc (@sorted_cust_svc) { + my $savepoint = 'cancel_pkgs_'.$i++; + savepoint_create( $savepoint ); my $part_svc = $cust_svc->part_svc; next if ( defined($part_svc) and $part_svc->preserve ); # immediate cancel, no date option # transactionize individually my $error = try { $cust_svc->cancel } catch { $_ }; if ( $error ) { - dbh->rollback; + savepoint_rollback_and_release( $savepoint ); + dbh->rollback if $oldAutoCommit; push @errors, $error; } else { - dbh->commit; + savepoint_release( $savepoint ); + dbh->commit if $oldAutoCommit; } } if (@errors) { @@ -2297,8 +2310,11 @@ sub cancel_pkgs { @cprs = @{ delete $opt{'cust_pkg_reason'} }; } my $null_reason; + $i = 0; foreach (@pkgs) { my %lopt = %opt; + my $savepoint = 'cancel_pkgs_'.$i++; + savepoint_create( $savepoint ); if (@cprs) { my $cpr = shift @cprs; if ( $cpr ) { @@ -2319,10 +2335,12 @@ sub cancel_pkgs { } my $error = $_->cancel(%lopt); if ( $error ) { - dbh->rollback; + savepoint_rollback_and_release( $savepoint ); + dbh->rollback if $oldAutoCommit; push @errors, 'pkgnum '.$_->pkgnum.': '.$error; } else { - dbh->commit; + savepoint_release( $savepoint ); + dbh->commit if $oldAutoCommit; } } diff --git a/FS/FS/cust_main/Billing.pm b/FS/FS/cust_main/Billing.pm index 71d5c9b81..1be7d39f9 100644 --- a/FS/FS/cust_main/Billing.pm +++ b/FS/FS/cust_main/Billing.pm @@ -26,6 +26,7 @@ use FS::pkg_category; use FS::FeeOrigin_Mixin; use FS::Log; use FS::TaxEngine; +use FS::Misc::Savepoint; # 1 is mostly method/subroutine entry and options # 2 traces progress of some operations @@ -1753,7 +1754,10 @@ sub collect { $dbh->commit or die $dbh->errstr if $oldAutoCommit; #never want to roll back an event just because it returned an error - local $FS::UID::AutoCommit = 1; #$oldAutoCommit; + # unless $FS::UID::ForceObeyAutoCommit is set + local $FS::UID::AutoCommit = 1 + unless !$oldAutoCommit + && $FS::UID::ForceObeyAutoCommit; $self->do_cust_event( 'debug' => ( $options{'debug'} || 0 ), @@ -1961,9 +1965,13 @@ sub do_cust_event { } $dbh->commit or die $dbh->errstr if $oldAutoCommit; + #never want to roll back an event just because it or a different one # returned an error - local $FS::UID::AutoCommit = 1; #$oldAutoCommit; + # unless $FS::UID::ForceObeyAutoCommit is set + local $FS::UID::AutoCommit = 1 + unless !$oldAutoCommit + && $FS::UID::ForceObeyAutoCommit; foreach my $cust_event ( @$due_cust_event ) { @@ -2288,16 +2296,21 @@ sub apply_payments_and_credits { local $FS::UID::AutoCommit = 0; my $dbh = dbh; + my $savepoint_label = 'Billing__apply_payments_and_credits'; + savepoint_create( $savepoint_label ); + $self->select_for_update; #mutex foreach my $cust_bill ( $self->open_cust_bill ) { my $error = $cust_bill->apply_payments_and_credits(%options); if ( $error ) { + savepoint_rollback_and_release( $savepoint_label ); $dbh->rollback if $oldAutoCommit; return "Error applying: $error"; } } + savepoint_release( $savepoint_label ); $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; #no error diff --git a/FS/FS/cust_main/Billing_Realtime.pm b/FS/FS/cust_main/Billing_Realtime.pm index d286f635e..714a2e687 100644 --- a/FS/FS/cust_main/Billing_Realtime.pm +++ b/FS/FS/cust_main/Billing_Realtime.pm @@ -16,6 +16,7 @@ use FS::cust_bill_pay; use FS::cust_refund; use FS::banned_pay; use FS::payment_gateway; +use FS::Misc::Savepoint; $realtime_bop_decline_quiet = 0; @@ -27,6 +28,7 @@ $me = '[FS::cust_main::Billing_Realtime]'; our $BOP_TESTING = 0; our $BOP_TESTING_SUCCESS = 1; +our $BOP_TESTING_TIMESTAMP = ''; install_callback FS::UID sub { $conf = new FS::Conf; @@ -405,7 +407,7 @@ sub realtime_bop { confess "Can't call realtime_bop within another transaction ". '($FS::UID::AutoCommit is false)' - unless $FS::UID::AutoCommit; + unless $FS::UID::AutoCommit || $BOP_TESTING; local($DEBUG) = $FS::cust_main::DEBUG if $FS::cust_main::DEBUG > $DEBUG; @@ -682,7 +684,7 @@ sub realtime_bop { my $cust_pay_pending = new FS::cust_pay_pending { 'custnum' => $self->custnum, 'paid' => $options{amount}, - '_date' => '', + '_date' => $BOP_TESTING ? $BOP_TESTING_TIMESTAMP : '', 'payby' => $bop_method2payby{$options{method}}, 'payinfo' => $options{payinfo}, 'paymask' => $options{paymask}, @@ -757,7 +759,7 @@ sub realtime_bop { return { reference => $cust_pay_pending->paypendingnum, map { $_ => $transaction->$_ } qw ( popup_url collectitems ) }; - } elsif ( $transaction->is_success() && $action2 ) { + } elsif ( !$BOP_TESTING && $transaction->is_success() && $action2 ) { $cust_pay_pending->status('authorized'); my $cpp_authorized_err = $cust_pay_pending->replace; @@ -946,7 +948,7 @@ sub _realtime_bop_result { 'custnum' => $self->custnum, 'invnum' => $options{'invnum'}, 'paid' => $cust_pay_pending->paid, - '_date' => '', + '_date' => $BOP_TESTING ? $BOP_TESTING_TIMESTAMP : '', 'payby' => $cust_pay_pending->payby, 'payinfo' => $options{'payinfo'}, 'paymask' => $options{'paymask'} || $cust_pay_pending->paymask, @@ -967,12 +969,16 @@ sub _realtime_bop_result { local $FS::UID::AutoCommit = 0; my $dbh = dbh; + my $savepoint_label = '_realtime_bop_result'; + savepoint_create( $savepoint_label ); + #start a transaction, insert the cust_pay and set cust_pay_pending.status to done in a single transction my $error = $cust_pay->insert($options{'manual'} ? ( 'manual' => 1 ) : () ); if ( $error ) { - $dbh->rollback or die $dbh->errstr if $oldAutoCommit; + savepoint_rollback( $savepoint_label ); + $cust_pay->invnum(''); #try again with no specific invnum $cust_pay->paynum(''); my $error2 = $cust_pay->insert( $options{'manual'} ? @@ -981,7 +987,8 @@ sub _realtime_bop_result { if ( $error2 ) { # gah. but at least we have a record of the state we had to abort in # from cust_pay_pending now. - $dbh->rollback or die $dbh->errstr if $oldAutoCommit; + savepoint_rollback_and_release( $savepoint_label ); + my $e = "WARNING: $options{method} captured but payment not recorded -". " error inserting payment (". $payment_gateway->gateway_module. "): $error2". @@ -996,9 +1003,10 @@ sub _realtime_bop_result { my $jobnum = $cust_pay_pending->jobnum; if ( $jobnum ) { my $placeholder = qsearchs( 'queue', { 'jobnum' => $jobnum } ); - + unless ( $placeholder ) { - $dbh->rollback or die $dbh->errstr if $oldAutoCommit; + savepoint_rollback_and_release( $savepoint_label ); + my $e = "WARNING: $options{method} captured but job $jobnum not ". "found for paypendingnum ". $cust_pay_pending->paypendingnum. "\n"; warn $e; @@ -1008,7 +1016,8 @@ sub _realtime_bop_result { $error = $placeholder->delete; if ( $error ) { - $dbh->rollback or die $dbh->errstr if $oldAutoCommit; + savepoint_rollback_and_release( $savepoint_label ); + my $e = "WARNING: $options{method} captured but could not delete ". "job $jobnum for paypendingnum ". $cust_pay_pending->paypendingnum. ": $error\n"; @@ -1030,8 +1039,8 @@ sub _realtime_bop_result { my $cpp_done_err = $cust_pay_pending->replace; if ( $cpp_done_err ) { + savepoint_rollback_and_release( $savepoint_label ); - $dbh->rollback or die $dbh->errstr if $oldAutoCommit; my $e = "WARNING: $options{method} captured but payment not recorded - ". "error updating status for paypendingnum ". $cust_pay_pending->paypendingnum. ": $cpp_done_err \n"; @@ -1039,7 +1048,7 @@ sub _realtime_bop_result { return $e; } else { - + savepoint_release( $savepoint_label ); $dbh->commit or die $dbh->errstr if $oldAutoCommit; if ( $options{'apply'} ) { diff --git a/FS/FS/cust_payby.pm b/FS/FS/cust_payby.pm index c497059fa..9d8be120a 100644 --- a/FS/FS/cust_payby.pm +++ b/FS/FS/cust_payby.pm @@ -1,5 +1,6 @@ package FS::cust_payby; use base qw( FS::payinfo_Mixin FS::cust_main_Mixin FS::Record ); +use feature 'state'; use strict; use Scalar::Util qw( blessed ); @@ -914,8 +915,81 @@ sub search_sql { =back +=item has_autobill_cards + +Returns the number of unexpired cards configured for autobill + +=cut + +sub has_autobill_cards { + scalar FS::Record::qsearch({ + table => 'cust_payby', + addl_from => 'JOIN cust_main USING (custnum)', + order_by => 'LIMIT 1', + hashref => { + paydate => { op => '>', value => DateTime->now->ymd }, + weight => { op => '>', value => 0 }, + }, + extra_sql => + "AND payby IN ('CARD', 'DCRD') ". + 'AND '. + $FS::CurrentUser::CurrentUser->agentnums_sql( table => 'cust_main' ), + }); +} + +=item has_autobill_checks + +Returns the number of check accounts configured for autobill + +=cut + +sub has_autobill_checks { + scalar FS::Record::qsearch({ + table => 'cust_payby', + addl_from => 'JOIN cust_main USING (custnum)', + order_by => 'LIMIT 1', + hashref => { + weight => { op => '>', value => 0 }, + }, + extra_sql => + "AND payby IN ('CHEK','DCHEK','DCHK') ". + 'AND '. + $FS::CurrentUser::CurrentUser->agentnums_sql( table => 'cust_main' ), + }); +} + +=item future_autobill_report_title + +Determine if the future_autobill report should be available. +If so, return a dynamic title for it + =cut +sub future_autobill_report_title { + # Perhaps this function belongs somewhere else + state $title; + return $title if defined $title; + + # Report incompatible with tax engines + return $title = '' if FS::TaxEngine->new->info->{batch}; + + my $has_cards = has_autobill_cards(); + my $has_checks = has_autobill_checks(); + my $_title = 'Future %s transactions'; + + if ( $has_cards && $has_checks ) { + $title = sprintf $_title, 'credit card and electronic check'; + } elsif ( $has_cards ) { + $title = sprintf $_title, 'credit card'; + } elsif ( $has_checks ) { + $title = sprintf $_title, 'electronic check'; + } else { + $title = ''; + } + + $title; +} + sub _upgrade_data { my $class = shift; diff --git a/FS/FS/part_export/nena2.pm b/FS/FS/part_export/nena2.pm index f6a730ebc..cc4069c72 100644 --- a/FS/FS/part_export/nena2.pm +++ b/FS/FS/part_export/nena2.pm @@ -10,6 +10,7 @@ use Date::Format qw(time2str); use Parse::FixedLength; use File::Temp qw(tempfile); use vars qw(%info %options $initial_load_hack $DEBUG); +use Carp qw( carp ); my %upload_targets; @@ -396,6 +397,13 @@ sub process { my $self = shift; my $batch = shift; local $DEBUG = $self->option('debug'); + + if ( $FS::svc_Common::noexport_hack ) { + carp 'FS::part_export::nena2::process() suppressed by noexport_hack' + if $DEBUG; + return; + } + local $FS::UID::AutoCommit = 0; my $error; diff --git a/FS/FS/part_export/saisei.pm b/FS/FS/part_export/saisei.pm index 1b7295d04..6db43c11d 100644 --- a/FS/FS/part_export/saisei.pm +++ b/FS/FS/part_export/saisei.pm @@ -201,12 +201,28 @@ sub _export_insert { my $accesspoint = process_sector($self, $sector_opt); return $self->api_error if $self->{'__saisei_error'}; +## get custnum and pkgpart from cust_pkg for virtual access point + my $cust_pkg = FS::Record::qsearchs({ + 'table' => 'cust_pkg', + 'hashref' => { 'pkgnum' => $svc_broadband->{Hash}->{pkgnum}, }, + }); + my $virtual_ap_name = $cust_pkg->{Hash}->{custnum}.'_'.$cust_pkg->{Hash}->{pkgpart}.'_'.$svc_broadband->{Hash}->{speed_down}.'_'.$svc_broadband->{Hash}->{speed_up}; + + my $virtual_ap_opt = { + 'virtual_name' => $virtual_ap_name, + 'sector_name' => $sector_name, + 'virtual_uprate_limit' => $svc_broadband->{Hash}->{speed_up}, + 'virtual_downrate_limit' => $svc_broadband->{Hash}->{speed_down}, + }; + my $virtual_ap = process_virtual_ap($self, $virtual_ap_opt); + return $self->api_error if $self->{'__saisei_error'}; + ## tie host to user add sector name as access point. $self->api_add_host_to_user( $user->{collection}->[0]->{name}, $rateplan->{collection}->[0]->{name}, $svc_broadband->{Hash}->{ip_addr}, - $accesspoint->{collection}->[0]->{name}, + $virtual_ap->{collection}->[0]->{name}, ) unless $self->{'__saisei_error'}; } @@ -216,8 +232,8 @@ sub _export_insert { sub _export_replace { my ($self, $svc_broadband) = @_; - $self->_export_insert($svc_broadband); - return ''; + my $error = $self->_export_insert($svc_broadband); + return $error; } sub _export_delete { @@ -817,6 +833,44 @@ sub process_sector { return $accesspoint; } +sub process_virtual_ap { + my ($self, $opt) = @_; + + my $existing_virtual_ap; + my $virtual_name = $opt->{virtual_name}; + + #check if sector has been set up as an access point. + $existing_virtual_ap = $self->api_get_accesspoint($virtual_name); + + # modify the existing virtual accesspoint if changing it. this should never happen + $self->api_modify_existing_accesspoint ( + $virtual_name, + $opt->{sector_name}, + $opt->{virtual_uprate_limit}, + $opt->{virtual_downrate_limit}, + ) if $existing_virtual_ap && $opt->{modify_existing}; + + #if virtual ap does not exist as an access point create it. + $self->api_create_accesspoint( + $virtual_name, + $opt->{virtual_uprate_limit}, + $opt->{virtual_downrate_limit}, + ) unless $existing_virtual_ap; + +my $update_sector; +if ($existing_virtual_ap && ($existing_virtual_ap->{collection}->[0]->{uplink}->{link}->{name} ne $opt->{sector_name})) { + $update_sector = 1; +} + + # Attach newly created virtual ap to tower sector ap or if sector has changed. + $self->api_modify_accesspoint($virtual_name, $opt->{sector_name}) unless ($self->{'__saisei_error'} || ($existing_virtual_ap && !$update_sector)); + + # set access point to existing one or newly created one. + my $accesspoint = $existing_virtual_ap ? $existing_virtual_ap : $self->api_get_accesspoint($virtual_name); + + return $accesspoint; +} + sub export_provisioned_services { my $job = shift; my $param = shift; |