summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FS/FS/cust_pkg.pm41
-rw-r--r--FS/FS/cust_svc.pm87
-rw-r--r--FS/FS/svc_acct.pm27
-rwxr-xr-xhttemplate/edit/part_pkg.cgi31
4 files changed, 181 insertions, 5 deletions
diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm
index 0c71435e1..b16d08137 100644
--- a/FS/FS/cust_pkg.pm
+++ b/FS/FS/cust_pkg.pm
@@ -475,7 +475,7 @@ sub cust_main {
=item seconds_since TIMESTAMP
Returns the number of seconds all accounts (see L<FS::svc_acct>) in this
-package have been online since TIMESTAMP.
+package have been online since TIMESTAMP, according to the session monitor.
TIMESTAMP is specified as a UNIX timestamp; see L<perlfunc/"time">. Also see
L<Time::Local> and L<Date::Parse> for conversion functions.
@@ -496,6 +496,43 @@ sub seconds_since {
}
+=item seconds_since_sqlradacct TIMESTAMP_START TIMESTAMP_END DATASRC DB_USERNAME DB_PASSWORD
+
+Returns the numbers of seconds all accounts (see L<FS::svc_acct>) in this
+package have been online between TIMESTAMP_START (inclusive) and TIMESTAMP_END
+(exclusive), according to an external SQL radacct table, such as those
+generated by ICRADIUS or FreeRADIUS. Sessions which started in the specified
+range but are still open are counted from session start to the end of the
+range. Also, sessions which end in the range but started earlier are counted
+from the start of the range to session end. Finally, sessions which start
+before the range but end after (or are still open) are counted for the entire
+range.
+
+TIMESTAMP_START and TIMESTAMP_END are specified as UNIX timestamps; see
+L<perlfunc/"time">. Also see L<Time::Local> and L<Date::Parse> for conversion
+functions.
+
+
+=cut
+
+sub seconds_since_sqlradacct {
+ my($self, $start, $end, $datasrc, $db_user, $db_pass) = @_;
+
+ my $dbh = DBI->connect($datasrc, $db_user, $db_pass)
+ or die "can't connect to $datasrc: ". $DBI::errstr;
+
+ my $seconds = 0;
+
+ foreach my $cust_svc (
+ grep { $_->part_svc->svcdb eq 'svc_acct' } $self->cust_svc
+ ) {
+ $seconds += $cust_svc->seconds_since_sqlradacct($start, $end, $dbh);
+ }
+
+ $seconds;
+
+}
+
=back
=head1 SUBROUTINES
@@ -678,7 +715,7 @@ sub order {
=head1 VERSION
-$Id: cust_pkg.pm,v 1.24 2002-09-17 09:19:06 ivan Exp $
+$Id: cust_pkg.pm,v 1.25 2002-10-12 13:26:45 ivan Exp $
=head1 BUGS
diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm
index 9d510b38a..4fc663450 100644
--- a/FS/FS/cust_svc.pm
+++ b/FS/FS/cust_svc.pm
@@ -336,11 +336,93 @@ sub seconds_since {
$sth->fetchrow_arrayref->[0];
}
+=item seconds_since_sqlradacct TIMESTAMP_START TIMESTAMP_END ( DBI_DATABASE_HANDLE | DATASRC DB_USERNAME DB_PASSWORD )
+
+See L<FS::svc_acct/seconds_since_sqlradacct>. Equivalent to
+$cust_svc->svc_x->seconds_since, but more efficient. Meaningless for records
+where B<svcdb> is not "svc_acct".
+
+NOTE: specifying a DATASRC/USERNAME/PASSWORD instead of a DBI database handle
+is not yet implemented.
+
+=cut
+
+#note: implementation here, POD in FS::svc_acct
+sub seconds_since_sqlradacct {
+ my($self, $start, $end, $dbh) = @_;
+
+ my $username = $self->svc_x->username;
+
+ #select a unix time conversion function based on database type
+ my $str2time;
+ if ( $dbh->{Driver}->{Name} eq 'mysql' ) {
+ $str2time = 'UNIX_TIMESTAMP(';
+ } elsif ( $dbh->{Driver}->{Name} eq 'Pg' ) {
+ $str2time = 'EXTRACT( EPOCH FROM ';
+ } else {
+ warn "warning: unknown database type ". $dbh->{Driver}->{Name}.
+ "; guessing how to convert to UNIX timestamps";
+ $str2time = 'extract(epoch from ';
+ }
+
+ #find sessions completely within the given range
+ my $sth = $dbh->prepare("SELECT SUM(acctsessiontime)
+ FROM radacct
+ WHERE UserName = ?
+ AND $str2time AcctStartTime) >= ?
+ AND $str2time AcctStopTime ) < ?
+ AND AcctStopTime =! 0
+ AND AcctStopTime IS NOT NULL"
+ ) or die $dbh->errstr;
+ $sth->execute($username, $start, $end) or die $sth->errstr;
+ my $regular = $sth->fetchrow_arrayref->[0];
+
+ #find open sessions which start in the range, count session start->range end
+ $sth = $dbh->prepare("SELECT SUM( ? - $str2time AcctStartTime ) )
+ FROM radacct
+ WHERE UserName = ?
+ AND AcctStartTime >= ?
+ AND ( AcctStopTime = 0
+ OR AcctStopTime IS NULL )"
+ ) or die $dbh->errstr;
+ $sth->execute($end, $username, $start) or die $sth->errstr;
+ my $start_during = $sth->fetchrow_arrayref->[0];
+
+ #find closed sessions which start before the range but stop during,
+ #count range start->session end
+ $sth = $dbh->prepare("SELECT SUM( $str2time AcctStopTime ) - ? )
+ FROM radacct
+ WHERE UserName = ?
+ AND AcctStartTime < ?
+ AND AcctStopTime >= ?
+ AND AcctStopTime < ?
+ AND AcctStopTime != 0
+ AND AcctStopTime IS NOT NULL"
+ ) or die $dbh->errstr;
+ $sth->execute($start, $username, $start, $start, $end ) or die $sth->errstr;
+ my $end_during = $sth->fetchrow_arrayref->[0];
+
+ #find closed or open sessions which start before the range but stop
+ # after, or are still open, count range start->range end
+ $sth = $dbh->prepare("SELECT COUNT(*)
+ FROM radacct
+ WHERE UserName = ?
+ AND AcctStartTime < ?
+ AND ( AcctStopTime >= ?
+ OR AcctStopTime = 0
+ OR AcctStopTime IS NULL )"
+ ) or die $dbh->errstr;
+ $sth->execute($username, $start, $end ) or die $sth->errstr;
+ my $entire_range = ($end-$start) * $sth->fetchrow_arrayref->[0];
+
+ $regular + $end_during + $start_during + $entire_range;
+}
+
=back
=head1 VERSION
-$Id: cust_svc.pm,v 1.17 2002-09-18 22:39:01 ivan Exp $
+$Id: cust_svc.pm,v 1.18 2002-10-12 13:26:45 ivan Exp $
=head1 BUGS
@@ -352,6 +434,9 @@ pkg_svc records are not checked in general (here).
Deleting this record doesn't check or delete the svc_* record associated
with this record.
+In seconds_since_sqlradacct, specifying a DATASRC/USERNAME/PASSWORD instead of
+a DBI database handle is not yet implemented.
+
=head1 SEE ALSO
L<FS::Record>, L<FS::cust_pkg>, L<FS::part_svc>, L<FS::pkg_svc>,
diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm
index b5ade6fac..3afee7f64 100644
--- a/FS/FS/svc_acct.pm
+++ b/FS/FS/svc_acct.pm
@@ -921,8 +921,8 @@ sub email {
=item seconds_since TIMESTAMP
-Returns the number of seconds this account has been online since TIMESTAMP.
-See L<FS::session>
+Returns the number of seconds this account has been online since TIMESTAMP,
+according to the session monitor (see L<FS::Session>).
TIMESTAMP is specified as a UNIX timestamp; see L<perlfunc/"time">. Also see
L<Time::Local> and L<Date::Parse> for conversion functions.
@@ -935,6 +935,29 @@ sub seconds_since {
$self->cust_svc->seconds_since(@_);
}
+=item seconds_since_sqlradacct TIMESTAMP_START TIMESTAMP_END DATASRC DB_USERNAME DB_PASSWORD
+
+Returns the numbers of seconds this account has been online between
+TIMESTAMP_START (inclusive) and TIMESTAMP_END (exclusive), according to an
+external SQL radacct table, such as those generated by ICRADIUS or FreeRADIUS.
+Sessions which started in the specified range but are still open are counted
+from session start to the end of the range. Also, sessions which end in the
+range but started earlier are counted from the start of the range to session
+end. Finally, sessions which start before the range but end after (or are
+still open) are counted for the entire range.
+
+TIMESTAMP_START and TIMESTAMP_END are specified as UNIX timestamps; see
+L<perlfunc/"time">. Also see L<Time::Local> and L<Date::Parse> for conversion
+functions.
+
+=cut
+
+#note: POD here, implementation in FS::cust_svc
+sub seconds_since_sqlradacct {
+ my $self = shift;
+ $self->cust_svc->seconds_since_sqlradacct(@_);
+}
+
=item radius_groups
Returns all RADIUS groups for this account (see L<FS::radius_usergroup>).
diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi
index 38d7358a5..ddd86765a 100755
--- a/httemplate/edit/part_pkg.cgi
+++ b/httemplate/edit/part_pkg.cgi
@@ -355,6 +355,37 @@ tie my %plans, 'Tie::IxHash',
},
+ 'sqlradacct_hour' => {
+ 'name' => 'Base charge plus charge per-hour from an external SQL radacct table',
+ 'fields' => {
+ 'setup_fee' => { 'name' => 'Setup fee for this package',
+ 'default' => 0,
+ },
+ 'recur_flat' => { 'name' => 'Base monthly charge for this package',
+ 'default' => 0,
+ },
+ 'sql_datasrc' => { 'name' => 'DBI data source',
+ 'default' => 'DBI:mysql:host=radius.server.name;dbname=radius',
+ },
+ 'sql_username' => { 'name' => 'Database username',
+ 'default' => 'radius',
+ },
+ 'sql_password' => { 'name' => 'Database password',
+ 'default' => '',
+ },
+ 'recur_included_hours' => { 'name' => 'Hours included',
+ 'default' => 0,
+ },
+ 'recur_hourly_charge' => { 'name' => 'Additional charge per hour',
+ 'default' => 0,
+ },
+ },
+ 'fieldorder' => [ 'setup_fee', 'recur_flat', 'recur_included_hours', 'recur_hourly_charge' ],
+ 'setup' => 'what.setup_fee.value',
+ 'recur' => '\'my ($sec,$min,$hour,$mday,$mon,$year) = (localtime($sdate))[0,1,2,3,4,5]; $mon+=$part_pkg->freq; until ($mon<12) { $mon-=12; $year++ }; $edate = timelocal($sec,$min,$hour,$mday,$mon,$year); my $hours = $cust_pkg->seconds_since_sqlradacct($sdate, $edate, \' + what.sql_datasrc + \', \' + what.sql_username + \', \' + what.sql_password + \' ) / 3600 - \' + what.recur_included_hours.value + \'; $hours = 0 if $hours < 0; \' + what.recur_flat.value + \' + \' + what.recur_hourly_charge.value + \' * $hours;\'',
+ },
+
+
;
my %plandata = map { /^(\w+)=(.*)$/; ( $1 => $2 ); }