input and output on data volume fields specified with k,m,g,or t
authorjeff <jeff>
Thu, 12 Apr 2007 03:16:43 +0000 (03:16 +0000)
committerjeff <jeff>
Thu, 12 Apr 2007 03:16:43 +0000 (03:16 +0000)
15 files changed:
FS/FS/Conf.pm
FS/FS/UI/Web.pm
FS/FS/part_pkg.pm
FS/FS/part_pkg/flat.pm
FS/FS/part_svc.pm
FS/FS/svc_acct.pm
FS/bin/freeside-queued
httemplate/browse/part_pkg.cgi
httemplate/browse/part_svc.cgi
httemplate/edit/part_pkg.cgi
httemplate/edit/part_svc.cgi
httemplate/edit/process/part_pkg.cgi
httemplate/edit/process/svc_acct.cgi
httemplate/edit/svc_acct.cgi
httemplate/view/svc_acct.cgi

index 374b583..8bff460 100644 (file)
@@ -1755,6 +1755,20 @@ httemplate/docs/config.html
     'type' => 'checkbox',
   },
 
+  {
+    'key'         => 'datavolume-forcemegabytes',
+    'section'     => 'UI',
+    'description' => 'All data volumes are expressed in megabytes',
+    'type'        => 'checkbox',
+  },
+
+  {
+    'key'         => 'datavolume-significantdigits',
+    'section'     => 'UI',
+    'description' => 'number of significant digits to use to represent data volumes',
+    'type'        => 'text',
+  },
+
 );
 
 1;
index 9ddcf14..a05a667 100644 (file)
@@ -4,6 +4,7 @@ use strict;
 use vars qw($DEBUG $me);
 use FS::Conf;
 use FS::Record qw(dbdef);
+use Number::Format;
 
 #use vars qw(@ISA);
 #use FS::UI
@@ -186,6 +187,31 @@ sub bytecount_unexact {
   return(sprintf("%.2f Gbytes", $bc/1000000000));
 }
 
+sub parse_bytecount {
+  my $bc = shift;
+  return $bc if (($bc =~ tr/.//) > 1);
+  $bc =~ /^\s*([\d.]*)\s*([kKmMgGtT]?)[bB]?\s*$/ or return $bc;
+  my $base = $1;
+  return $bc unless length $base;
+  my $exponent = index ' kmgt', lc($2);
+  return $bc if ($exponent < 0 && $2);
+  $exponent = 0 if ($exponent < 0);
+  return $base * 1024 ** $exponent;
+}
+
+sub display_bytecount {
+  my $bc = shift;
+  return $bc unless ($bc =~ /^(\d+)$/);
+  my $conf = new FS::Conf;
+  my $f = new Number::Format;
+  my $precision = $conf->exists('datavolume-significantdigits')
+                ? $conf->config('datavolume-significantdigits')
+                : 3;
+  my $unit = $conf->exists('datavolume-forcemegabytes') ? 'M' : 'A';
+
+  return $f->format_bytes($bc, precision => $precision, unit => $unit);
+}
+
 ###
 # cust_main report subroutines
 ###
index 03222fa..3110c1c 100644 (file)
@@ -817,6 +817,39 @@ sub plan_info {
   \%plans;
 }
 
+=item format OPTION DATA
+
+Returns data formatted according to the function 'format' described
+in the plan info.  Returns DATA if no such function exists.
+
+=cut
+
+sub format {
+  my ($self, $option, $data) = (shift, shift, shift);
+  if (exists($plans{$self->plan}->{fields}->{$option}{format})) {
+    &{$plans{$self->plan}->{fields}->{$option}{format}}($data);
+  }else{
+    $data;
+  }
+}
+
+=item prase OPTION DATA
+
+Returns data parsed according to the function 'parse' described
+in the plan info.  Returns DATA if no such function exists.
+
+=cut
+
+sub parse {
+  my ($self, $option, $data) = (shift, shift, shift);
+  if (exists($plans{$self->plan}->{fields}->{$option}{parse})) {
+    &{$plans{$self->plan}->{fields}->{$option}{parse}}($data);
+  }else{
+    $data;
+  }
+}
+
+
 =back
 
 =head1 NEW PLAN CLASSES
index 94b7d99..c0fbb5a 100644 (file)
@@ -28,27 +28,43 @@ use FS::part_pkg;
                        },
     'upbytes'       => { 'name' => 'Upload limit for this package',
                          'default' => '',
+                         'format' => \&FS::UI::Web::display_bytecount,
+                         'parse' => \&FS::UI::Web::parse_bytecount,
                        },
     'downbytes'     => { 'name' => 'Download limit for this package',
                          'default' => '',
+                         'format' => \&FS::UI::Web::display_bytecount,
+                         'parse' => \&FS::UI::Web::parse_bytecount,
                        },
     'totalbytes'    => { 'name' => 'Transfer limit for this package',
                          'default' => '',
+                         'format' => \&FS::UI::Web::display_bytecount,
+                         'parse' => \&FS::UI::Web::parse_bytecount,
                        },
     'recharge_amount'       => { 'name' => 'Cost of recharge for this package',
                          'default' => '',
+                         'format' => \&FS::UI::Web::display_bytecount,
+                         'parse' => \&FS::UI::Web::parse_bytecount,
                        },
     'recharge_seconds'      => { 'name' => 'Recharge time for this package',
                          'default' => '',
+                         'format' => \&FS::UI::Web::display_bytecount,
+                         'parse' => \&FS::UI::Web::parse_bytecount,
                        },
     'recharge_upbytes'      => { 'name' => 'Recharge upload for this package',
                          'default' => '',
+                         'format' => \&FS::UI::Web::display_bytecount,
+                         'parse' => \&FS::UI::Web::parse_bytecount,
                        },
     'recharge_downbytes'    => { 'name' => 'Recharge download for this package',
                          'default' => '',
+                         'format' => \&FS::UI::Web::display_bytecount,
+                         'parse' => \&FS::UI::Web::parse_bytecount,
                        },
     'recharge_totalbytes'   => { 'name' => 'Recharge transfer for this package',
                          'default' => '',
+                         'format' => \&FS::UI::Web::display_bytecount,
+                         'parse' => \&FS::UI::Web::parse_bytecount,
                        },
   },
   'fieldorder' => [ 'setup_fee', 'recur_fee', 'unused_credit', 
index 5b4e54c..4fae457 100644 (file)
@@ -145,9 +145,11 @@ sub insert {
     my $flag = $self->getfield($svcdb.'__'.$field.'_flag');
     #if ( uc($flag) =~ /^([DFMAX])$/ ) {
     if ( uc($flag) =~ /^([A-Z])$/ ) { #part_svc_column will test it
+      my $parser = FS::part_svc->svc_table_fields($svcdb)->{$field}->{parse}
+                   || sub { shift };
       $part_svc_column->setfield('columnflag', $1);
       $part_svc_column->setfield('columnvalue',
-        $self->getfield($svcdb.'__'.$field)
+        &$parser($self->getfield($svcdb.'__'.$field))
       );
       if ( $previous ) {
         $error = $part_svc_column->replace($previous);
@@ -264,9 +266,11 @@ sub replace {
       my $flag = $new->getfield($svcdb.'__'.$field.'_flag');
       #if ( uc($flag) =~ /^([DFMAX])$/ ) {
       if ( uc($flag) =~ /^([A-Z])$/ ) { #part_svc_column will test it
+        my $parser = FS::part_svc->svc_table_fields($svcdb)->{$field}->{parse}
+                     || sub { shift };
         $part_svc_column->setfield('columnflag', $1);
         $part_svc_column->setfield('columnvalue',
-          $new->getfield($svcdb.'__'.$field)
+          &$parser($new->getfield($svcdb.'__'.$field))
         );
         if ( $previous ) {
           $error = $part_svc_column->replace($previous);
index 1ef2119..be5a6d3 100644 (file)
@@ -273,6 +273,53 @@ sub table_info {
                          disable_inventory => 1,
                          disable_select => 1,
                        },
+        'upbytes'   => { label => 'Upload',
+                         type  => 'text',
+                         disable_inventory => 1,
+                         disable_select => 1,
+                         'format' => \&FS::UI::Web::display_bytecount,
+                         'parse' => \&FS::UI::Web::parse_bytecount,
+                       },
+        'downbytes' => { label => 'Download',
+                         type  => 'text',
+                         disable_inventory => 1,
+                         disable_select => 1,
+                         'format' => \&FS::UI::Web::display_bytecount,
+                         'parse' => \&FS::UI::Web::parse_bytecount,
+                       },
+        'totalbytes'=> { label => 'Total up and download',
+                         type  => 'text',
+                         disable_inventory => 1,
+                         disable_select => 1,
+                         'format' => \&FS::UI::Web::display_bytecount,
+                         'parse' => \&FS::UI::Web::parse_bytecount,
+                       },
+        'seconds_threshold'   => { label => 'Seconds',
+                                   type  => 'text',
+                                   disable_inventory => 1,
+                                   disable_select => 1,
+                                 },
+        'upbytes_threshold'   => { label => 'Upload',
+                                   type  => 'text',
+                                   disable_inventory => 1,
+                                   disable_select => 1,
+                                   'format' => \&FS::UI::Web::display_bytecount,
+                                   'parse' => \&FS::UI::Web::parse_bytecount,
+                                 },
+        'downbytes_threshold' => { label => 'Download',
+                                   type  => 'text',
+                                   disable_inventory => 1,
+                                   disable_select => 1,
+                                   'format' => \&FS::UI::Web::display_bytecount,
+                                   'parse' => \&FS::UI::Web::parse_bytecount,
+                                 },
+        'totalbytes_threshold'=> { label => 'Total up and download',
+                                   type  => 'text',
+                                   disable_inventory => 1,
+                                   disable_select => 1,
+                                   'format' => \&FS::UI::Web::display_bytecount,
+                                   'parse' => \&FS::UI::Web::parse_bytecount,
+                                 },
     },
   };
 }
index 93d735d..b3128f0 100644 (file)
@@ -9,6 +9,7 @@ use FS::Daemon qw(daemonize1 drop_root logfile daemonize2 sigint sigterm);
 use FS::Record qw(qsearch qsearchs);
 use FS::queue;
 use FS::queue_depend;
+use FS::UI::Web;
 
 # no autoloading for non-FS classes...
 use Net::SSH 0.07;
index 6b62ec6..5acf17e 100755 (executable)
@@ -189,7 +189,7 @@ push @fields, sub { shift->plan || '(legacy)' },
                                 { 'data'  => $1,
                                   'align' => 'right',
                                 },
-                                { 'data'  => $2,
+                                { 'data'  => $part_pkg->format($1,$2),
                                   'align' => 'left',
                                 },
                               ];
index 3694955..92c0840 100755 (executable)
@@ -135,6 +135,9 @@ function part_export_areyousure(href) {
 %   
 %     my($n1)='';
 %     foreach my $field ( @fields ) {
+%       my $formatter =
+%            FS::part_svc->svc_table_fields($svcdb)->{$field}->{format}
+%            || sub { shift };
 %       my $flag = $part_svc->part_svc_column($field)->columnflag;
 %
 
@@ -143,7 +146,7 @@ function part_export_areyousure(href) {
      <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $flag{$flag} %></TD>
 
      <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
-% my $value = $part_svc->part_svc_column($field)->columnvalue;
+% my $value = &$formatter($part_svc->part_svc_column($field)->columnvalue);
 %          if ( $flag =~ /^[MA]$/ ) { 
 %            $inventory_class{$value}
 %              ||= qsearchs('inventory_class', { 'classnum' => $value } );
index ce3e854..bdd3f30 100755 (executable)
@@ -323,10 +323,12 @@ Reseller information
 %
 %      $html .= '<TR><TD ALIGN="right">'. $href->{$field}{'name'}. '</TD><TD>';
 %
+%      my $format = sub { shift };
+%      $format = $href->{$field}{'format'} if exists($href->{$field}{'format'});
 %      if ( ! exists($href->{$field}{'type'}) ) {
 %        $html .= qq!<INPUT TYPE="text" NAME="$field" VALUE="!.
 %                 ( exists($plandata{$field})
-%                     ? $plandata{$field}
+%                     ? &$format($plandata{$field})
 %                     : $href->{$field}{'default'} ).
 %                 qq!">!;
 %      } elsif ( $href->{$field}{'type'} eq 'checkbox' ) {
index 6ba9240..9432839 100755 (executable)
@@ -166,12 +166,13 @@ that field.
 %
 %      foreach my $field (@fields) {
 %
-%        my $part_svc_column = $part_svc->part_svc_column($field);
-%        my $value = $part_svc_column->columnvalue;
-%        my $flag = $part_svc_column->columnflag;
 %        #my $def = $defs{$layer}{$field};
 %        my $def = FS::part_svc->svc_table_fields($layer)->{$field};
 %        my $label = $def->{'def_label'} || $def->{'label'};
+%        my $formatter = $def->{'format'} || sub { shift };
+%        my $part_svc_column = $part_svc->part_svc_column($field);
+%        my $value = &$formatter($part_svc_column->columnvalue);
+%        my $flag = $part_svc_column->columnflag;
 %
 %        if ( $bgcolor eq $bgcolor1 ) {
 %          $bgcolor = $bgcolor2;
index 1158222..5fc59c1 100755 (executable)
@@ -6,11 +6,17 @@
 %
 %my $old = qsearchs('part_pkg',{'pkgpart'=>$pkgpart}) if $pkgpart;
 %
+%tie my %plans, 'Tie::IxHash', %{ FS::part_pkg::plan_info() };
+%my $href = $plans{$cgi->param('plan')}->{'fields'};
+%
 %#fixup plandata
 %my $plandata = $cgi->param('plandata');
 %my @plandata = split(',', $plandata);
 %$cgi->param('plandata', 
-%  join('', map { "$_=". join(', ', $cgi->param($_)). "\n" } @plandata )
+%  join('', map { my $parser = sub { shift };
+%                 $parser = $href->{$_}{parse} if exists($href->{$_}{parse});
+%                 "$_=". join(', ', &$parser($cgi->param($_))). "\n"
+%               } @plandata )
 %);
 %
 %foreach (qw( setuptax recurtax disabled )) {
index 30552c8..65ac5c1 100755 (executable)
 %#unmunge usergroup
 %$cgi->param('usergroup', [ $cgi->param('radius_usergroup') ] );
 %
+%#unmunge bytecounts
+%foreach (map { $_,$_."_threshold" } qw( upbytes downbytes totalbytes )) {
+%  $cgi->param($_, FS::UI::Web::parse_bytecount($cgi->param($_)) );
+%}
+%
 %my %hash = $svcnum ? $old->hash : ();
 %map {
 %    $hash{$_} = scalar($cgi->param($_));
index 01f665a..e0610b2 100755 (executable)
@@ -386,27 +386,27 @@ Service # <% $svcnum ? "<B>$svcnum</B>" : " (NEW)" %><BR>
   </TR>
 % } 
 %
-% if ( $curuser->access_right('Edit usage') ) { 
-%   my %label = ( seconds => 'Seconds',
-%                 upbytes => 'Upload bytes',
-%                 downbytes => 'Download bytes',
-%                 totalbytes => 'Total bytes',
-%               );
-%   foreach my $uf (keys %label) {
-%     my $tf = $uf . "_threshold";
-%     if ( $svc_acct->$tf ne '' ) { 
-
+% my %label = ( seconds => 'Time',
+%               upbytes => 'Upload bytes',
+%               downbytes => 'Download bytes',
+%               totalbytes => 'Total bytes',
+%             );
+% foreach my $uf (keys %label) {
+%   my $tf = $uf . "_threshold";
+%   if ( $curuser->access_right('Edit usage') ) { 
   <TR>
     <TD ALIGN="right"><% $label{$uf} %> remaining</TD>
-    <TD><INPUT TYPE="text" NAME="<% $uf %>" VALUE="<% $svc_acct->$uf %>"></TD>
+    <TD><INPUT TYPE="text" NAME="<% $uf %>" VALUE="<% $svc_acct->$uf %>">(blank disables)</TD>
   </TR>
   <TR>
     <TD ALIGN="right"><% $label{$uf} %> threshold</TD>
-    <TD><INPUT TYPE="text" NAME="<% $tf %>" VALUE="<% $svc_acct->$tf %>">(blank or zero disables <% lc($label{$uf}) %> remaining)</TD>
+    <TD><INPUT TYPE="text" NAME="<% $tf %>" VALUE="<% $svc_acct->$tf %>">(blank disables)</TD>
   </TR>
-%     } 
+%   }else{
+      <INPUT TYPE="hidden" NAME="<% $uf %>" VALUE="<% $svc_acct->$uf %>">
+      <INPUT TYPE="hidden" NAME="<% $tf %>" VALUE="<% $svc_acct->$tf %>">
 %   } 
-% } 
+% }
 %
 %foreach my $r ( grep { /^r(adius|[cr])_/ } fields('svc_acct') ) {
 %  $r =~ /^^r(adius|[cr])_(.+)$/ or next; #?
index 8647868..2ad9b8e 100755 (executable)
@@ -245,17 +245,19 @@ Service #<B><% $svcnum %></B>
     </TD>
   </TR>
 % } 
-% my %ulabel = ( seconds    => 'Seconds',
+% my %ulabel = ( seconds    => 'Time',
 %                upbytes    => 'Upload bytes',
 %                downbytes  => 'Download bytes',
 %                totalbytes => 'Total bytes',
 %              );
 % foreach my $uf ( keys %ulabel ) {
 %   my $tf = $uf . "_threshold";
-%   if ( $svc_acct->$tf ne '' ) {
+%   if ( $svc_acct->$uf ne '' ) {
+%   my $v = $uf eq 'seconds' ? duration_exact($svc_acct->$uf)
+%                            : FS::UI::Web::display_bytecount($svc_acct->$uf);
     <TR>
       <TD ALIGN="right"><% $ulabel{$uf} %> remaining</TD>
-      <TD BGCOLOR="#ffffff"><% $svc_acct->$uf %></TD>
+      <TD BGCOLOR="#ffffff"><% $v %></TD>
     </TR>
 
 %   }
@@ -286,13 +288,6 @@ Service #<B><% $svcnum %></B>
   <TD ALIGN="right">RADIUS groups</TD>
   <TD BGCOLOR="#ffffff"><% join('<BR>', $svc_acct->radius_groups) %></TD>
 </TR>
-% if ( $svc_acct->seconds =~ /^\d+$/ ) { 
-
-  <TR>
-    <TD ALIGN="right">Prepaid time</TD>
-    <TD BGCOLOR="#ffffff"><% duration_exact($svc_acct->seconds) %></TD>
-  </TR>
-% } 
 %
 %# Can this be abstracted further?  Maybe a library function like
 %# widget('HTML', 'view', $svc_acct) ?  It would definitely make UI