export negative byte values to chillispot attributes as 0, RT#5815
[freeside.git] / FS / FS / svc_acct.pm
index 1a42e65..ac97864 100644 (file)
@@ -15,6 +15,7 @@ use vars qw( @ISA $DEBUG $me $conf $skip_fuzzyfiles
              $dirhash
              @saltset @pw_set );
 use Scalar::Util qw( blessed );
+use Math::BigInt;
 use Carp;
 use Fcntl qw(:flock);
 use Date::Format;
@@ -539,12 +540,13 @@ sub insert {
       my %values = $part_pkg->usage_valuehash;
       my $multiplier = $conf->exists('svc_acct-usage_threshold') 
                          ? 1 - $conf->config('svc_acct-usage_threshold')/100
-                         : 0.20;
+                         : 0.20; #doesn't matter
 
       foreach ( keys %values ) {
         next if $self->getfield($_);
         $self->setfield( $_, $values{$_} );
-        $self->setfield( $_. '_threshold', int( $values{$_} * $multiplier ) );
+        $self->setfield( $_. '_threshold', int( $values{$_} * $multiplier ) )
+          if $conf->exists('svc_acct-usage_threshold');
       }
 
     }
@@ -1439,6 +1441,29 @@ sub radius_reply {
     $reply{'Session-Timeout'} = $self->seconds;
   }
 
+  if ( $conf->exists('radius-chillispot-max') ) {
+    #http://dev.coova.org/svn/coova-chilli/doc/dictionary.chillispot
+
+    #hmm.  just because sqlradius.pm says so?
+    my %whatis = (
+      'input'  => 'up',
+      'output' => 'down',
+      'total'  => 'total',
+    );
+
+    foreach my $what (qw( input output total )) {
+      my $is = $whatis{$what}.'bytes';
+      if ( $self->$is() =~ /\d/ ) {
+        my $big = new Math::BigInt $self->$is();
+        $big = new Math::BigInto '0' if $big->is_neg();
+        my $att = "Chillispot-Max-\u$what";
+        $reply{"$att-Octets"}    = $big->copy->band(0xffffffff)->bstr;
+        $reply{"$att-Gigawords"} = $big->copy->brsft(32)->bstr;
+      }
+    }
+
+  }
+
   %reply;
 }
 
@@ -1472,11 +1497,15 @@ sub radius_check {
   $check{$pw_attrib} = $password;
 
   my $cust_svc = $self->cust_svc;
-  die "FATAL: no cust_svc record for svc_acct.svcnum ". $self->svcnum. "\n"
-    unless $cust_svc;
-  my $cust_pkg = $cust_svc->cust_pkg;
-  if ( $cust_pkg && $cust_pkg->part_pkg->is_prepaid && $cust_pkg->bill ) {
-    $check{'Expiration'} = time2str('%B %e %Y %T', $cust_pkg->bill ); #http://lists.cistron.nl/pipermail/freeradius-users/2005-January/040184.html
+  if ( $cust_svc ) {
+    my $cust_pkg = $cust_svc->cust_pkg;
+    if ( $cust_pkg && $cust_pkg->part_pkg->is_prepaid && $cust_pkg->bill ) {
+      $check{'Expiration'} = time2str('%B %e %Y %T', $cust_pkg->bill ); #http://lists.cistron.nl/pipermail/freeradius-users/2005-January/040184.html
+    }
+  } else {
+    warn "WARNING: no cust_svc record for svc_acct.svcnum ". $self->svcnum.
+         "; can't set Expiration\n"
+      unless $cust_svc;
   }
 
   %check;
@@ -1771,6 +1800,38 @@ sub _op_usage {
   die "Can't update $column for svcnum". $self->svcnum
     if $rv == 0;
 
+  #$self->snapshot; #not necessary, we retain the old values
+  #create an object with the updated usage values
+  my $new = qsearchs('svc_acct', { 'svcnum' => $self->svcnum });
+  #call exports
+  my $error = $new->replace($self);
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return "Error replacing: $error";
+  }
+
+  #overlimit_action eq 'cancel' handling
+  my $cust_pkg = $self->cust_svc->cust_pkg;
+  if ( $cust_pkg
+       && $cust_pkg->part_pkg->option('overlimit_action', 1) eq 'cancel' 
+       && $op eq '-' && &{$op2condition{$op}}($self, $column, $amount)
+     )
+  {
+
+    my $error = $cust_pkg->cancel; #XXX should have a reason
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return "Error cancelling: $error";
+    }
+
+    #nothing else is relevant if we're cancelling, so commit & return success
+    warn "$me update successful; committing\n"
+      if $DEBUG;
+    $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+    return '';
+
+  }
+
   my $action = $op2action{$op};
 
   if ( &{$op2condition{$op}}($self, $column, $amount) &&
@@ -1902,6 +1963,16 @@ sub set_usage {
       if $rv == 0;
   }
 
+  #$self->snapshot; #not necessary, we retain the old values
+  #create an object with the updated usage values
+  my $new = qsearchs('svc_acct', { 'svcnum' => $self->svcnum });
+  #call exports
+  my $error = $new->replace($self);
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return "Error replacing: $error";
+  }
+
   if ( $reset ) {
     my $error;
 
@@ -2683,6 +2754,8 @@ probably live somewhere else...
 insertion of RADIUS group stuff in insert could be done with child_objects now
 (would probably clean up export of them too)
 
+_op_usage and set_usage bypass the history... maybe they shouldn't
+
 =head1 SEE ALSO
 
 L<FS::svc_Common>, edit/part_svc.cgi from an installed web interface,