X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fcust_svc.pm;h=a1df059c55e82b1b4dc00bdcf914d6d4decd0fcc;hb=b03bd63dcee4fce35d86e906b0379acdb6c76c27;hp=4c38aae245fda2813b0f19d0965fc77699ff0961;hpb=acc311a412cd8660572eb6de6712a1e0b2768ec1;p=freeside.git diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm index 4c38aae24..a1df059c5 100644 --- a/FS/FS/cust_svc.pm +++ b/FS/FS/cust_svc.pm @@ -6,7 +6,7 @@ use Carp; #use Scalar::Util qw( blessed ); use List::Util qw( max ); use FS::Conf; -use FS::Record qw( qsearch qsearchs dbh str2time_sql ); +use FS::Record qw( qsearch qsearchs dbh str2time_sql str2time_sql_closing ); use FS::cust_pkg; use FS::part_pkg; use FS::part_svc; @@ -102,6 +102,37 @@ sub table { 'cust_svc'; } Adds this service to the database. If there is an error, returns the error, otherwise returns false. +=cut + +sub insert { + my $self = shift; + + 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->SUPER::insert; + + #check if this releases a hold (see FS::pkg_svc provision_hold) + $error ||= $self->_provision_hold; + + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error if $error + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + ''; #no error + +} + =item delete Deletes this service from the database. If there is an error, returns the @@ -335,15 +366,37 @@ sub replace { #trigger a relocate export on location changes if ( $new->cust_pkg->locationnum != $old->cust_pkg->locationnum ) { - $error ||= $new->svc_x->export('relocate', - $new->cust_pkg->cust_location, - $old->cust_pkg->cust_location, + my $svc_x = $new->svc_x; + if ( $svc_x->locationnum ) { + if ( $svc_x->locationnum == $old->cust_pkg->locationnum ) { + # in this case, set the service location to be the same as the new + # package location + $svc_x->set('locationnum', $new->cust_pkg->locationnum); + # and replace it, which triggers a relocate export so we don't + # need to + $error ||= $svc_x->replace; + } else { + # the service already has a different location from its package + # so don't change it + } + } else { + # the service doesn't have a locationnum (either isn't of a type + # that has the locationnum field, or the locationnum is null and + # defaults to cust_pkg->locationnum) + # so just trigger the export here + $error ||= $new->svc_x->export('relocate', + $new->cust_pkg->cust_location, + $old->cust_pkg->cust_location, ); - } + } # if ($svc_x->locationnum) + } # if this is a location change + + #check if this releases a hold (see FS::pkg_svc provision_hold) + $error ||= $new->_provision_hold; if ( $error ) { $dbh->rollback if $oldAutoCommit; - return $error if $error; + return $error if $error } $dbh->commit or die $dbh->errstr if $oldAutoCommit; @@ -656,6 +709,7 @@ sub seconds_since_sqlradacct { #select a unix time conversion function based on database type my $str2time = str2time_sql( $dbh->{Driver}->{Name} ); + my $closing = str2time_sql_closing( $dbh->{Driver}->{Name} ); my $username = $part_export->export_username($svc_x); @@ -675,9 +729,9 @@ sub seconds_since_sqlradacct { FROM radacct WHERE UserName = ? $realm - AND $str2time AcctStartTime) >= ? - AND $str2time AcctStopTime ) < ? - AND $str2time AcctStopTime ) > 0 + AND $str2time AcctStartTime $closing >= ? + AND $str2time AcctStopTime $closing < ? + AND $str2time AcctStopTime $closing > 0 AND AcctStopTime IS NOT NULL" ) or die $dbh->errstr; $sth->execute($username, ($realm ? $realmparam : ()), $start, $end) @@ -688,14 +742,14 @@ sub seconds_since_sqlradacct { if $DEBUG; # count session start->range end - $query = "SELECT SUM( ? - $str2time AcctStartTime ) ) + $query = "SELECT SUM( ? - $str2time AcctStartTime $closing ) FROM radacct WHERE UserName = ? $realm - AND $str2time AcctStartTime ) >= ? - AND $str2time AcctStartTime ) < ? - AND ( ? - $str2time AcctStartTime ) ) < 86400 - AND ( $str2time AcctStopTime ) = 0 + AND $str2time AcctStartTime $closing >= ? + AND $str2time AcctStartTime $closing < ? + AND ( ? - $str2time AcctStartTime $closing ) < 86400 + AND ( $str2time AcctStopTime $closing = 0 OR AcctStopTime IS NULL )"; $sth = $dbh->prepare($query) or die $dbh->errstr; $sth->execute( $end, @@ -711,14 +765,14 @@ sub seconds_since_sqlradacct { if $DEBUG; #count range start->session end - $sth = $dbh->prepare("SELECT SUM( $str2time AcctStopTime ) - ? ) + $sth = $dbh->prepare("SELECT SUM( $str2time AcctStopTime $closing - ? ) FROM radacct WHERE UserName = ? $realm - AND $str2time AcctStartTime ) < ? - AND $str2time AcctStopTime ) >= ? - AND $str2time AcctStopTime ) < ? - AND $str2time AcctStopTime ) > 0 + AND $str2time AcctStartTime $closing < ? + AND $str2time AcctStopTime $closing >= ? + AND $str2time AcctStopTime $closing < ? + AND $str2time AcctStopTime $closing > 0 AND AcctStopTime IS NOT NULL" ) or die $dbh->errstr; $sth->execute( $start, @@ -739,8 +793,8 @@ sub seconds_since_sqlradacct { FROM radacct WHERE UserName = ? $realm - AND $str2time AcctStartTime ) < ? - AND ( $str2time AcctStopTime ) >= ? + AND $str2time AcctStartTime $closing < ? + AND ( $str2time AcctStopTime $closing >= ? )" # OR AcctStopTime = 0 # OR AcctStopTime IS NULL )" @@ -801,6 +855,7 @@ sub attribute_since_sqlradacct { #select a unix time conversion function based on database type my $str2time = str2time_sql( $dbh->{Driver}->{Name} ); + my $closing = str2time_sql_closing( $dbh->{Driver}->{Name} ); my $username = $part_export->export_username($svc_x); @@ -818,8 +873,8 @@ sub attribute_since_sqlradacct { FROM radacct WHERE UserName = ? $realm - AND $str2time AcctStopTime ) >= ? - AND $str2time AcctStopTime ) < ? + AND $str2time AcctStopTime $closing >= ? + AND $str2time AcctStopTime $closing < ? AND AcctStopTime IS NOT NULL" ) or die $dbh->errstr; $sth->execute($username, ($realm ? $realmparam : ()), $start, $end) @@ -837,6 +892,78 @@ sub attribute_since_sqlradacct { } +#note: implementation here, POD in FS::svc_acct +# false laziness w/above +sub attribute_last_sqlradacct { + my($self, $attrib) = @_; + + my $mes = "$me attribute_last_sqlradacct:"; + + my $svc_x = $self->svc_x; + + my @part_export = $self->part_svc->part_export_usage; + die "no accounting-capable exports are enabled for ". $self->part_svc->svc. + " service definition" + unless @part_export; + #or return undef; + + my $value = ''; + my $AcctStartTime = 0; + + foreach my $part_export ( @part_export ) { + + next if $part_export->option('ignore_accounting'); + + warn "$mes connecting to sqlradius database\n" + if $DEBUG; + + my $dbh = DBI->connect( map { $part_export->option($_) } + qw(datasrc username password) ) + or die "can't connect to sqlradius database: ". $DBI::errstr; + + warn "$mes connected to sqlradius database\n" + if $DEBUG; + + #select a unix time conversion function based on database type + my $str2time = str2time_sql( $dbh->{Driver}->{Name} ); + my $closing = str2time_sql_closing( $dbh->{Driver}->{Name} ); + + my $username = $part_export->export_username($svc_x); + + warn "$mes finding most-recent $attrib\n" + if $DEBUG; + + my $realm = ''; + my $realmparam = ''; + if ($part_export->option('process_single_realm')) { + $realm = 'AND Realm = ?'; + $realmparam = $part_export->option('realm'); + } + + my $sth = $dbh->prepare("SELECT $attrib, $str2time AcctStartTime $closing + FROM radacct + WHERE UserName = ? + $realm + ORDER BY AcctStartTime DESC LIMIT 1 + ") or die $dbh->errstr; + $sth->execute($username, ($realm ? $realmparam : ()) ) + or die $sth->errstr; + + my $row = $sth->fetchrow_arrayref; + if ( defined($row->[0]) && $row->[1] > $AcctStartTime ) { + $value = $row->[0]; + $AcctStartTime = $row->[1]; + } + + warn "$mes done\n" + if $DEBUG; + + } + + $value; + +} + =item get_session_history TIMESTAMP_START TIMESTAMP_END See L. Equivalent to @@ -980,6 +1107,35 @@ sub smart_search_param { ); } +# If the associated cust_pkg is 'on hold' +# and the associated pkg_svc has the provision_hold flag +# and there are no more available_part_svcs on the cust_pkg similarly flagged, +# then removes hold from pkg +# returns $error or '' on success, +# does not indicate if pkg status was changed +sub _provision_hold { + my $self = shift; + + # check status of cust_pkg + my $cust_pkg = $self->cust_pkg; + return '' unless $cust_pkg->status eq 'on hold'; + + # check flag on this svc + # small false laziness with $self->pkg_svc + # to avoid looking up cust_pkg twice + my $pkg_svc = qsearchs( 'pkg_svc', { + 'svcpart' => $self->svcpart, + 'pkgpart' => $cust_pkg->pkgpart, + }); + return '' unless $pkg_svc->provision_hold; + + # check for any others available with that flag + return '' if $cust_pkg->available_part_svc( 'provision_hold' => 1 ); + + # conditions met, remove hold + return $cust_pkg->unsuspend; +} + sub _upgrade_data { my $class = shift;