cdr rating by day and time, part 2, RT#4763
authormark <mark>
Thu, 22 Jul 2010 00:11:56 +0000 (00:11 +0000)
committermark <mark>
Thu, 22 Jul 2010 00:11:56 +0000 (00:11 +0000)
FS/FS/rate_time_interval.pm
httemplate/browse/rate_detail.html
httemplate/edit/process/rate_region.cgi
httemplate/edit/process/rate_time.cgi
httemplate/edit/rate.cgi
httemplate/edit/rate_region.cgi
httemplate/edit/rate_time.cgi
httemplate/elements/auto-table.html
httemplate/elements/menu.html

index 37bc83b..1a82edb 100644 (file)
@@ -3,6 +3,7 @@ package FS::rate_time_interval;
 use strict;
 use base qw( FS::Record );
 use FS::Record qw( qsearch qsearchs );
+use List::Util 'first';
 
 =head1 NAME
 
@@ -96,7 +97,7 @@ returns the error, otherwise returns false.
 
 =item check
 
-Checks all fields to make sure this is a valid example.  If there is
+Checks all fields to make sure this is a valid interval.  If there is
 an error, returns the error, otherwise returns false.  Called by the insert
 and replace methods.
 
@@ -112,6 +113,21 @@ sub check {
     || $self->ut_number('ratetimenum')
   ;
   return $error if $error;
+  # Disallow backward intervals. As a special case, an etime of 0 
+  # should roll to the last second of the week.
+  $self->etime(7*24*60*60) if $self->etime == 0;
+  return "end of interval is before start" if ($self->etime < $self->stime);
+
+  # Detect overlap between intervals within the same rate_time.
+  # Since intervals are added one at a time, we only need to look 
+  # for an existing interval that contains one of the endpoints of
+  # this one or that is completely inside this one.
+  my $overlap = $self->rate_time->contains($self->stime + 1) ||
+                $self->rate_time->contains($self->etime - 1) ||
+                first { $self->stime <= $_->stime && $self->etime >= $_->etime }
+                    ( $self->rate_time->intervals );
+  return "interval overlap: (".join('-',$self->description).') with ('.
+      join('-',$overlap->description).')' if $overlap;
 
   $self->SUPER::check;
 }
@@ -130,7 +146,8 @@ sub rate_time {
 =item description
 
 Returns two strings containing stime and etime, formatted 
-"Day HH:MM:SS AM/PM".  Example: "Mon 5:00 AM".
+"Day HH:MM AM/PM".  Example: "Mon 5:00 AM".  Seconds are 
+not displayed, so be careful.
 
 =cut
 
@@ -139,11 +156,10 @@ my @days = qw(Sun Mon Tue Wed Thu Fri Sat);
 sub description {
   my $self = shift;
   return map { 
-            sprintf('%s %02d:%02d:%02d %s',
+            sprintf('%s %02d:%02d %s',
             $days[int($_/86400) % 7],
             int($_/3600) % 12,
             int($_/60) % 60,
-            $_ % 60,
             (($_/3600) % 24 < 12) ? 'AM' : 'PM' )
        } ( $self->stime, $self->etime );
 }
index faaec2c..aef5505 100644 (file)
@@ -1,58 +1,14 @@
 <% include('/elements/init_overlib.html') %>
 <% include('/elements/header.html',$title) %>
 <% include('/elements/menubar.html',@menubar) %>
-<BR><BR>
-<% include('/elements/table-grid.html') %>
-<TR>
-% my $col = 0;
-% foreach (@header) {
-%   my $hlink = $hlinks[$col];
-  <TH CLASS   = "grid",
-      BGCOLOR = "#cccccc">
-  <% $hlink ? qq!<A HREF="$hlink">$_</A>! : $_ %>
-  </TH>
-%   $col++;
-% } #foreach @header
-</TR><TR>
-% my $row = 0;
-% foreach my $region (@rate_region) {
-%   $col = 0;
-%   foreach ($region->regionname, $region->prefixes_short) {
-  <TD>
-    <A HREF="<% $p.'edit/rate_region.cgi?'.$region->regionnum %>"><% $_ %></A>
-  </TD>
-%   }
-%   foreach my $rate_time (@rate_time, '') {
-  <TD>
-%     my $detail = $details[$row][$col];
-%     if($detail) {
-      <TABLE CLASS="inv" STYLE="border:none">
-      <TR><TD><% edit_link($detail) %><% $money_char.$detail->min_charge %>
-              <% $detail->sec_granularity ? ' / minute':' / call' %>
-      <% $edit_hint %></A>
-      </TD></TR>
-      <% granularity_detail($detail) %>
-      <% min_included_detail($detail) %>
-      <% conn_charge_detail($detail) %>
-      <TR><TD><% $rate_time ? delete_link($detail) : '' %></TD></TR>
-    </TABLE>
-%     }
-%     else { #!$detail
-    <% add_link($ratenum, $region, $rate_time) %>
-%     }
-%     $col++;
-  </TD>
-%   } # foreach @rate_time
-</TR>
-%   $row++;
-% }# foreach @rate_region
+<% include('/edit/elements/rate_detail.html',
+    'ratenum' => $ratenum,
+    'countrycode' => $countrycode,
+) %>
 <% include('/elements/footer.html') %>
 
 <%once>
 
-tie my %granularity, 'Tie::IxHash', FS::rate_detail::granularities();
-tie my %conn_secs,   'Tie::IxHash', FS::rate_detail::conn_secs();
-
 my $conf = new FS::Conf;
 my $money_char = $conf->config('money_char') || '$';
 
@@ -61,88 +17,6 @@ my @menubar = ( 'Rate plans' => $p.'browse/rate.cgi',
                 'Time Periods' => $p.'browse/rate_time.html',
                 );
 
-sub small {
-  '<FONT SIZE="-1">'.shift.'</FONT>'
-}
-my $edit_hint = small('(edit)');
-
-sub edit_link {
-  my $rate_detail = shift;
-  my $ratedetailnum = $rate_detail->ratedetailnum;
-  '<A HREF="javascript:void(0);" onclick="'.
-  include( '/elements/popup_link_onclick.html',
-             'action'      => "${p}edit/rate_detail.html?$ratedetailnum",
-             'actionlabel' => 'Edit rate',
-             'height'      => 420,
-             #default# 'width'       => 540,
-             #default# 'color'       => '#333399',
-         ) . '">'
-}
-
-sub add_link {
-  my ($ratenum, $region, $rate_time) = @_;
-  '<A HREF="javascript:void(0);" onclick="'.
-  include( '/elements/popup_link_onclick.html',
-             'action'      => "${p}edit/rate_detail.html?ratenum=$ratenum".
-                               ';dest_regionnum='.$region->regionnum.
-                               ($rate_time ? 
-                                 ';ratetimenum='.$rate_time->ratetimenum :
-                                 ''),
-             'actionlabel' => 'Add rate',
-             'height'      => 420,
-             ).'">'.small('(add)').'</A>'
-}
-
-sub delete_link {
-  my $rate_detail = shift;
-  my $ratedetailnum = $rate_detail->ratedetailnum;
-  my $onclick = include( '/elements/popup_link_onclick.html',
-             'action'      => "${p}misc/delete-rate_detail.html?$ratedetailnum",
-             'actionlabel' => 'Delete rate',
-             'width'       => 510,
-             'height'      => 315,
-             'frame'       => 'top',
-             );
-  $onclick = "if(confirm('Delete this rate?')) { $onclick }";
-  qq!<A HREF="javascript:void(0);" onclick="$onclick">!.small('(delete)').'</A>'
-}
-
-sub granularity_detail {
-  my $rate_detail = shift;
-  if($rate_detail->sec_granularity != 60 && $rate_detail->sec_granularity > 0) {
-    '<TR><TD>'.
-    small('in '.$granularity{$rate_detail->sec_granularity}.' increments').
-    '</TD></TR>';
-  }
-  else { '' }
-}
-
-sub min_included_detail {
-  my $rate_detail = shift;
-  if($rate_detail->min_included) {
-    '<TR><TD>'.
-    small( $rate_detail->min_included . 
-            ($rate_detail->sec_granularity ? 
-             ' minutes included' : 
-             ' calls included') ).
-    '</TD></TR>'
-  }
-  else { '' }
-}
-
-sub conn_charge_detail {
-  my $rate_detail = shift;
-  if($rate_detail->conn_charge > 0) {
-  #return '' unless $rate_detail->conn_charge > 0 || $rate_detail->conn_sec;
-    '<TR><TD>'.
-    small( $money_char. $rate_detail->conn_charge.
-      ' for '.$conn_secs{$rate_detail->conn_sec}
-    ).
-    '</TD></TR>'
-  }
-  else { '' }
-}
-
 </%once>
 <%init>
 
@@ -157,35 +31,10 @@ my $ratename = $rate->ratename;
 my $title = "$ratename rates";
 
 my $where;
+my $countrycode = '';
 if ( $cgi->param('countrycode') =~ /^(\d+)$/ ) { 
-  my $countrycode = $1;
-  $where = "WHERE 0 < ( SELECT COUNT(*) FROM rate_prefix
-                        WHERE rate_prefix.regionnum = rate_region.regionnum
-                          AND countrycode = '$countrycode'
-                    )
-               ";
+  $countrycode = $1;
   $title .= " for +$countrycode";
 }
 
-my @rate_region = qsearch({ table     => 'rate_region',
-                            hashref   => {},
-                            extra_sql => $where,
-                          });
-
-my @rate_time = qsearch('rate_time', {});
-my @header = ('Region', 'Prefix(es)',
-  map( { $_->ratetimename } @rate_time ),
-  '(default)');
-my @hlinks = map {''} @header;
-
-my @rtns = ( map( { $_->ratetimenum } @rate_time ), '' );
-my @details;
-foreach my $region (@rate_region) {
-   push @details, [ map { qsearchs('rate_detail', 
-                                    { 'ratenum'        => $ratenum,
-                                      'dest_regionnum' => $region->regionnum,
-                                      'ratetimenum'    => $_ } ) or ''
-                        } @rtns ];
-}
-
 </%init>
index 8036f73..d342e60 100755 (executable)
@@ -1,6 +1,8 @@
 %if ( $error ) {
 %  $cgi->param('error', $error);
 <% $cgi->redirect(popurl(2). "rate_region.cgi?". $cgi->query_string ) %>
+%} elsif ( $action eq 'Add' ) {
+<% $cgi->redirect(popurl(2). "rate_region.cgi?$regionnum") %>
 %} else { 
 <% $cgi->redirect(popurl(3). "browse/rate_region.html") %>
 %}
@@ -11,6 +13,7 @@ die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
 
 my $regionnum = $cgi->param('regionnum');
+my $action = $regionnum ? 'Edit' : 'Add';
 
 my $old = qsearchs('rate_region', { 'regionnum' => $regionnum } ) if $regionnum;
 
@@ -33,24 +36,12 @@ my @rate_prefix = map {
                           'npa'         => $_,
                         }
                       } @npa;
-
-my @dest_detail = map {
-  my $ratenum = $_->ratenum;
-  new FS::rate_detail {
-    'ratenum'  => $ratenum,
-    map { $_ => $cgi->param("$_$ratenum") }
-        qw( min_included conn_charge conn_sec min_charge sec_granularity classnum )
-  };
-} qsearch('rate', {} );
-
-
+# we no longer process dest_detail records here
 my $error;
 if ( $regionnum ) {
-  $error = $new->replace($old, 'rate_prefix' => \@rate_prefix,
-                               'dest_detail' => \@dest_detail, );
+  $error = $new->replace($old, 'rate_prefix' => \@rate_prefix );
 } else {
-  $error = $new->insert( 'rate_prefix' => \@rate_prefix,
-                         'dest_detail' => \@dest_detail, );
+  $error = $new->insert( 'rate_prefix' => \@rate_prefix );
   $regionnum = $new->getfield('regionnum');
 }
 
index 48ed273..4fa78ce 100644 (file)
@@ -44,12 +44,13 @@ else { #!$ratetimenum, adding new
   $ratetimenum = $rate_time->ratetimenum;
 }
 
+my @new_ints;
 if(!$delete and !$error) {
-  foreach my $i (map { /stime(\d+)/ } keys(%vars)) {
-    my $stime = str2wtime($vars{"stime$i"});
-    my $etime = str2wtime($vars{"etime$i"});
-    next if !defined($stime) or !defined($etime);
-    #warn "$i: $stime-$etime";
+  foreach my $i (map { /^sd(\d+)$/ } keys(%vars)) {
+    my $stime = l2wtime(@vars{"sd$i", "sh$i", "sm$i", "sa$i"});
+    my $etime = l2wtime(@vars{"ed$i", "eh$i", "em$i", "ea$i"});
+    #warn "$i: $stime - $etime";
+    next if !defined($stime) or !defined($etime) or $etime == $stime;
     # try to avoid needlessly wiping and replacing intervals every 
     # time this is edited.
     if( %old_ints ) {
@@ -63,12 +64,9 @@ if(!$delete and !$error) {
         next; #$i
       }
     }
-    my $new_int = FS::rate_time_interval->new({ ratetimenum => $ratetimenum,
-                                                stime       => $stime,
-                                                etime       => $etime, } );
-    $error = $new_int->insert;
-    #warn "inserting $stime-$etime\n";
-    last if $error;
+    push @new_ints, FS::rate_time_interval->new({ ratetimenum => $ratetimenum,
+                                                  stime       => $stime,
+                                                  etime       => $etime, } );
   }
 }
 if(!$error) {
@@ -78,17 +76,19 @@ if(!$error) {
     last if $error;
   }
 }
+if(!$error) {
+  # do this last to avoid overlap errors with deleted intervals
+  foreach (@new_ints) {
+    $error = $_->insert;
+    #warn "inserting $stime-$etime\n";
+    last if $error;
+  }
+}
 
-sub str2wtime {
-  my %days;
-  @days{qw(Sun Mon Tue Wed Thu Fri Sat)} = (0..6);
-  my $str = shift;
-  my ($d, $h, $m, $s, $ampm) = 
-    ($str =~ /^(\w{3}) (\d{2}):(\d{2}):(\d{2}) (\w{2})$/);
-  return () if !$d;
-  $h += 24*$days{$d} + ($ampm eq 'PM' ? 12 : 0);
+sub l2wtime {
+  my ($d, $h, $m, $a) = @_;
+  $h += 24*$d + 12*$a;
   $m += 60*$h;
-  $s += 60*$m;
-  return $s;
+  return 60*$m
 }
 </%init>
index 75c7143..13717dc 100644 (file)
@@ -22,9 +22,15 @@ Rate plan
 <INPUT NAME="submit" TYPE="button" VALUE="<% 
   $rate->ratenum ? "Apply changes" : "Add rate plan"
 %>" onClick="document.OneTrueForm.submit.disabled=true; process();">
-
 </FORM>
 
+% if($rate->ratenum) {
+<BR><BR><FONT SIZE="+2">Rates in this plan</FONT>
+<% include('/edit/elements/rate_detail.html',
+            'ratenum' => $rate->ratenum
+) %>
+% }
+
 <% include('/elements/footer.html') %>
 
 <%init>
index f77c0db..cae3003 100644 (file)
 
 </TABLE>
 
-%# rate plan info
-
-<BR>
-
-<% include('/elements/table-grid.html') %>
-%   my $bgcolor1 = '#eeeeee';
-%   my $bgcolor2 = '#ffffff';
-%   my $bgcolor = '';
-
-  <TR>
-    <TH CLASS="grid" BGCOLOR="#cccccc">
-      Rate plan
-    </TH>
-    <TH CLASS="grid" BGCOLOR="#cccccc">
-      <FONT SIZE=-1>Included<BR>minutes/calls</FONT>
-    </TH>
-    <TH CLASS="grid" BGCOLOR="#cccccc">
-      <FONT SIZE=-1>Connection<BR>charge</FONT>
-    </TH>
-    <TH CLASS="grid" BGCOLOR="#cccccc">
-      <FONT SIZE=-1>Connection<BR>charge for</FONT>
-    </TH>
-    <TH CLASS="grid" BGCOLOR="#cccccc">
-      <FONT SIZE=-1>Charge per<BR>minute/call</FONT>
-    </TH>
-    <TH CLASS="grid" BGCOLOR="#cccccc">
-      <FONT SIZE=-1>Granularity</FONT>
-    </TH>
-    <TH CLASS="grid" BGCOLOR="#cccccc">
-      <FONT SIZE=-1>Usage class</FONT>
-    </TH>
-  </TR>
-
-% foreach my $rate ( qsearch('rate', {}) ) {
-%
-%  my $n = $rate->ratenum;
-%  my $rate_detail = $rate->dest_detail($rate_region)
-%                    || new FS::rate_region { 'min_included'    => 0,
-%                                             'min_charge'      => 0,
-%                                             'sec_granularity' => '60'
-%                                           };
-%
-% if ( $bgcolor eq $bgcolor1 ) {
-%   $bgcolor = $bgcolor2;
-% } else {
-%   $bgcolor = $bgcolor1;
-% }
-
-  <TR>
-
-    <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
-      <A HREF="<%$p%>edit/rate.cgi?<% $rate->ratenum %>"><% $rate->ratename %></A>
-    </TD>
-
-    <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
-      <INPUT TYPE="text" SIZE=9 NAME="min_included<%$n%>" VALUE="<% $cgi->param("min_included$n") || $rate_detail->min_included |h %>">
-    </TD>
-
-    <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
-      <%$money_char%><INPUT TYPE="text" SIZE=9 NAME="conn_charge<%$n%>" VALUE="<% $cgi->param("conn_charge$n") || $rate_detail->conn_charge |h %>">
-    </TD>
-
-    <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
-      <SELECT NAME="conn_sec<%$n%>">
-%       foreach my $conn_sec ( keys %conn_secs ) {
-%         my $curr_value = $cgi->param("conn_sec$n") || $rate_detail->conn_sec;
-%         my $selected = ($conn_sec==$curr_value) ? ' SELECTED' : '';
-          <OPTION VALUE="<% $conn_sec %>" <%$selected%>><% $conn_secs{$conn_sec} %></OPTION>
-%       }
-    </TD>
-
-    <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
-      <%$money_char%><INPUT TYPE="text" SIZE=6 NAME="min_charge<%$n%>" VALUE="<% $cgi->param("min_charge$n") || $rate_detail->min_charge |h %>">
-    </TD>
-
-    <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
-      <SELECT NAME="sec_granularity<%$n%>">
-%       foreach my $granularity ( keys %granularity ) { 
-          <OPTION VALUE="<%$granularity%>"<% $granularity == ( $cgi->param("sec_granularity$n") || $rate_detail->sec_granularity ) ? ' SELECTED' : '' %>><%$granularity{$granularity}%>
-%       } 
-      </SELECT>
-    </TD>
-
-    <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
-      <% include( '/elements/select-table.html',
-                  'element_name' => "classnum$n",
-                  'table'        => 'usage_class',
-                  'name_col'     => 'classname',
-                  'empty_label'  => '(default)',
-                  'hashref'      => { disabled => '' },
-                  'curr_value'   => ( $cgi->param("classnum$n") ||
-                                      $rate_detail->classnum ),
-                )
-      %>
-    </TD>
-
-  </TR>
-
-% } 
-
-</TABLE>
-
-
 <BR><BR>
 <INPUT TYPE="submit" VALUE="<% $rate_region->regionnum ? "Apply changes" : "Add region" %>">
-
 </FORM>
+%# rate plan info, if the region has been created yet
+
+% if($rate_region->regionnum) {
+<BR>
+<BR>
+<FONT SIZE="+2">Rates in this region</FONT>
+<% include('/edit/elements/rate_detail.html',
+            'regionnum' => $rate_region->regionnum,
+) %>
+% }
 
 <% include('/elements/footer.html') %>
 <%once>
index 230aef8..eca8fbb 100644 (file)
@@ -1,9 +1,10 @@
-<% include("/elements/header.html","$action Time Period", menubar(
+<% include("/elements/header.html", { title => "$action Time Period" }) %>
+<% include("/elements/menubar.html",
       'Rate plans' => "${p}browse/rate.cgi",
-    ) )
-%>
-
+    ) %>
+<BR>
 <% include('/elements/error.html') %>
+<BR>
 
 <FORM METHOD="POST" ACTION="<% "${p}edit/process/rate_time.cgi" %>">
 <INPUT TYPE="hidden" NAME="ratetimenum" VALUE="<% $ratetimenum %>">
   </TR>
 </TABLE>
 <% include('/elements/auto-table.html', 
-                      header => [ 'Start', 'End' ],
-                      fields => [ 'stime', 'etime' ],
-                      size   => [ 18, 18 ],
-                      maxl   => [ 15, 15 ],
-                      align  => [ 'right', 'right' ],
-                      data   => \@data,
+                      'header' => [ '', 'Start','','', '','End','','' ],
+                      'fields' => [ qw(sd sh sm sa ed eh em ea) ],
+                      'select' => [ ($day, $hour, $min, $ampm) x 2 ],
+                      'data'   => \@data,
    ) %>
 <INPUT TYPE="submit" VALUE="<% $rate_time ? 'Apply changes' : 'Add period'%>">
 </FORM>
 <% include('/elements/footer.html') %>
 
 <%init>
-my $ratetimenum = ($cgi->keywords)[0] || '';
+my $ratetimenum = ($cgi->keywords)[0] || $cgi->param('ratetimenum') || '';
 my $action = 'Add';
 my $rate_time;
 my @data = ();
+my $day = [ 0 => 'Sun',
+            1 => 'Mon',
+            2 => 'Tue',
+            3 => 'Wed',
+            4 => 'Thu',
+            5 => 'Fri',
+            6 => 'Sat', ];
+my $hour = [ map( {$_, sprintf('%02d',$_) } 0..11 )];
+my $min  = [ map( {$_, sprintf('%02d',$_) } 0,30  )];
+my $ampm = [ 0 => 'AM', 1 => 'PM' ];
 
 if($ratetimenum) {
   $action = 'Edit';
   $rate_time = qsearchs('rate_time', {ratetimenum => $ratetimenum})
     or die "ratetimenum $ratetimenum not found";
-  @data = $rate_time->description;
+  if($cgi->param('error')) {
+    my %vars = $cgi->Vars;
+    foreach my $i (sort {$a <=> $b } map { /^sd(\d+)$/ } keys(%vars)) {
+      push @data, [ @vars{"sd$i", "sh$i", "sm$i", "sa$i",
+                          "ed$i", "eh$i", "em$i", "ea$i"} ];
+    }
+  }
+  else {
+    foreach my $interval ($rate_time->intervals) {
+      push @data, [ map { int($_/86400) % 7,
+                          int($_/3600) % 12,
+                          int($_/60) % 60,
+                          int($_/43200) % 2, } 
+                    ( $interval->stime, $interval->etime ) 
+      ];
+    }
+  }
 }
 
 </%init>
index 89d6eac..9c7dfd0 100644 (file)
@@ -28,6 +28,12 @@ Example:
               'records'       => [ qsearch('item', { } ) ],
               # or any other array of FS::Record objects
 
+              'select'        => [ '',
+                                   [ 1 => 'option 1',
+                                     2 => 'option 2', ...
+                                   ], # options for second field
+                                   '' ],
+
               'prefix'        => 'mytable_',
 ) %>
 
@@ -47,6 +53,17 @@ Values will be passed through as "mytable_id1", etc.
 %   for ( $col = 0; $col < scalar @fields; $col++ ) {
 %     my $id = $prefix . $fields[$col] . $row;
     <TD>
+%     my @o = @{ $select[$col] };
+%     if( @o ) {
+      <SELECT NAME="<% $id %>" ID="<% $id %>">
+%       while(@o) {
+%         my $val = shift @o;
+        <OPTION VALUE=<% $val %><% 
+$val eq $data[$row][$col] ? ' SELECTED' : ''%>><% shift @o %></OPTION>
+%       }
+      </SELECT>
+%     }
+%     else {
       <INPUT TYPE      = "text"
              NAME      = "<% $id %>"
              ID        = "<% $id %>"
@@ -54,63 +71,58 @@ Values will be passed through as "mytable_id1", etc.
              MAXLENGTH = <% $maxl[$col] %>
              STYLE     = "text-align:<% $align[$col] %>"
              VALUE     = "<% $data[$row][$col] %>"
-             onchange  = "possiblyAddRow();"
+%       if( $opt{'autoadd'} ) {
+             onchange  = "possiblyAddRow(this);"
+%       }
       >
     </TD>
+%     }
 %   }
     <TD>
       <IMG SRC     = "<% "${p}images/cross.png" %>" 
            ALT     = "X" 
-           onclick = "deleteThisRow(this);"
+           onclick = "deleteRow(this);"
            >
     </TD>
   </TR>
 % }
 </TABLE>
+% if( !$opt{'autoadd'} ) {
+<INPUT TYPE="button" VALUE="Add" onclick="<% $prefix %>addRow();"><BR>
+% }
 
 <SCRIPT TYPE="text/javascript">
   var <% $prefix %>rownum = <% $row %>;
   var <% $prefix %>table = document.getElementById('<% $prefix %>AutoTable');
+  // last row is initially blank, clone it and remove it
+  var <% $prefix %>_blank = 
+    <% $prefix %>table.rows[<% $prefix %>table.rows.length-1].cloneNode(true);
+% if( !$opt{'autoadd'} ) {
+  <% $prefix %>table.deleteRow(<% $prefix %>table.rows.length-1);
+% }
+  
+    
 
   function rownum_of(obj) {
     return (obj.parentNode.parentNode.sectionRowIndex);
   }
 
-  function possiblyAddRow() {
-    if ( <% $prefix %>rownum == rownum_of(this) ) {
+  function <% $prefix %>possiblyAddRow(obj) {
+    if ( <% $prefix %>rownum == rownum_of(obj) ) {
       <% $prefix %>addRow();
     }
   }
 
   function <% $prefix %>addRow() {
-    var row = <% $prefix %>table.insertRow(<% $prefix %>rownum + 1);
-%   my $col = 0;
-%   for( $col = 0; $col < scalar @fields; $col++ ) {
-%     my $field = $prefix.$fields[$col];
-    var <% $field %>_cell = document.createElement('TD');
-      var <% $field %>_input = document.createElement('INPUT');
-      <% $field %>_input.setAttribute('name', '<% $field %>'+<% $prefix %>rownum);
-      <% $field %>_input.setAttribute('id',   '<% $field %>'+<% $prefix %>rownum);
-      <% $field %>_input.setAttribute('type', 'text');
-      <% $field %>_input.setAttribute('size', <% $size[$col] %>);
-      <% $field %>_input.setAttribute('maxlength', <% $maxl[$col] %>);
-      <% $field %>_input.style.textAlign = '<% $align[$col] %>';
-      <% $field %>_input.onchange = possiblyAddRow;
-      <% $field %>_cell.appendChild(<% $field %>_input);
-    row.appendChild(<% $field %>_cell);
-%   }
-    var delcell = document.createElement('TD');
-      var delinput = document.createElement('IMG');
-      delinput.setAttribute('src', '<% "${p}images/cross.png" %>');
-      delinput.setAttribute('alt', 'X');
-      delinput.setAttribute('onclick', 'deleteThisRow(this);');
-      delcell.appendChild(delinput);
-    row.appendChild(delcell);
-
+    var row = <% $prefix %>table.insertRow(-1);
+    var cells = <% $prefix %>_blank.cells;
+    for (i=0; i<cells.length; i++) {
+      row.appendChild(cells[i].cloneNode(true));
+    }
     <% $prefix %>rownum++;
   }
 
-  function deleteThisRow(obj) {
+  function deleteRow(obj) {
     if(<% $prefix %>rownum == rownum_of(obj))  {
       <% $prefix %>addRow();
     }
@@ -119,7 +131,6 @@ Values will be passed through as "mytable_id1", etc.
     return(false);
   }
 
-  <% $prefix %>addRow();
 </SCRIPT>
 
 <%init>
@@ -137,10 +148,14 @@ elsif($opt{'records'}) {
   }
 }
 # else @data = ();
+push @data, [ map {''} @fields ]; # make a blank row
 
 my $prefix = $opt{'prefix'};
 my @size = $opt{'size'} ? @{ $opt{'size'} } : (map {16} @fields);
 my @maxl = $opt{'maxl'} ? @{ $opt{'maxl'} } : @size;
 my @align = $opt{'align'} ? @{ $opt{'align'} } : (map {'right'} @fields);
-
+my @select = @{ $opt{'select'} || [] };
+foreach (0..scalar(@fields)-1) {
+  $select[$_] ||= [];
+}
 </%init>
index 1eaefe2..da2dcaa 100644 (file)
@@ -421,6 +421,7 @@ tie my %config_billing_rates, 'Tie::IxHash',
   'Rate plans' => [ $fsurl.'browse/rate.cgi', 'Manage rate plans' ],
   'Regions and prefixes' => [ $fsurl.'browse/rate_region.html', 'Manage regions and prefixes' ],
   'Usage classes'  => [ $fsurl.'browse/usage_class.html', 'Usage classes define groups of usage for taxation.' ],
+  'Time periods' => [ $fsurl.'browse/rate_time.html', 'Time periods define days and hours for rate plans' ],
   'Edit rates with Excel' => [ $fsurl.'misc/rate_edit_excel.html', 'Download and edit rates with Excel, then upload changes.' ], #"Edit with Excel" ?
 ;