summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorivan <ivan>2009-01-05 00:26:54 +0000
committerivan <ivan>2009-01-05 00:26:54 +0000
commit125fb1a284ae96b46fe433c418aafa87862c4382 (patch)
treecb9485c9cfd7e685bc63ea40fe214f80c18407b1
parentc23d6e1673dbec98fe9d778ee55962d2cbd145d5 (diff)
add rate copying, RT#4431
-rw-r--r--FS/FS/rate_prefix.pm23
-rw-r--r--httemplate/browse/rate.cgi7
-rw-r--r--httemplate/elements/checkboxes-table-name.html88
-rw-r--r--httemplate/elements/checkboxes.html103
-rw-r--r--httemplate/elements/select-rate.html9
-rw-r--r--httemplate/elements/tr-select-rate.html21
-rw-r--r--httemplate/misc/copy-rate_detail.html61
-rw-r--r--httemplate/misc/process/copy-rate_detail.html61
8 files changed, 294 insertions, 79 deletions
diff --git a/FS/FS/rate_prefix.pm b/FS/FS/rate_prefix.pm
index 42b004f5b..ce780fefe 100644
--- a/FS/FS/rate_prefix.pm
+++ b/FS/FS/rate_prefix.pm
@@ -2,7 +2,7 @@ package FS::rate_prefix;
use strict;
use vars qw( @ISA );
-use FS::Record qw( qsearch qsearchs );
+use FS::Record qw( qsearch qsearchs dbh );
use FS::rate_region;
@ISA = qw(FS::Record);
@@ -127,6 +127,27 @@ sub rate_region {
=back
+=head1 CLASS METHODS
+
+=over 4
+
+=item all_countrycodes
+
+Returns a list of all countrycodes listed in rate_prefix
+
+=cut
+
+sub all_countrycodes {
+ #my $class = shift;
+ my $sql =
+ "SELECT DISTINCT(countrycode) FROM rate_prefix ORDER BY countrycode";
+ my $sth = dbh->prepare($sql) or die dbh->errstr;
+ $sth->execute or die $sth->errstr;
+ map $_->[0], @{ $sth->fetchall_arrayref };
+}
+
+=back
+
=head1 BUGS
=head1 SEE ALSO
diff --git a/httemplate/browse/rate.cgi b/httemplate/browse/rate.cgi
index b20c45c0c..911b2fd28 100644
--- a/httemplate/browse/rate.cgi
+++ b/httemplate/browse/rate.cgi
@@ -17,12 +17,8 @@
%>
<%once>
-my $sth = dbh->prepare("SELECT DISTINCT(countrycode) FROM rate_prefix")
- or die dbh->errstr;
-$sth->execute or die $sth->errstr;
-my @all_countrycodes = map $_->[0], @{ $sth->fetchall_arrayref };
my $all_countrycodes = join("\n", map qq(<OPTION VALUE="$_">$_),
- @all_countrycodes
+ FS::rate_prefix->all_countrycodes
);
my $rates_sub = sub {
@@ -51,6 +47,7 @@ die "access denied"
my $html_init =
'Rate plans for VoIP and call billing.<BR><BR>'.
qq!<A HREF="${p}edit/rate.cgi"><I>Add a rate plan</I></A>!.
+ qq! | <A HREF="${p}misc/copy-rate_detail.html"><I>Copy rates between plans</I></A>!.
'<BR><BR>
<SCRIPT>
function rate_areyousure(href) {
diff --git a/httemplate/elements/checkboxes-table-name.html b/httemplate/elements/checkboxes-table-name.html
index b236787b6..31652f330 100644
--- a/httemplate/elements/checkboxes-table-name.html
+++ b/httemplate/elements/checkboxes-table-name.html
@@ -41,79 +41,12 @@ Example:
</%doc>
-<TABLE CELLSPACING=0 CELLPADDING=0>
-
-<TR>
- <TD COLSPAN=2 ALIGN="center"><FONT SIZE="-1">(
- <A HREF="javascript:setAll<%$prefix%>(true)">select all</A> |
- <A HREF="javascript:setAll<%$prefix%>(false)">unselect all</A> |
- <A HREF="javascript:toggleAll<%$prefix%>()">toggle all</A>
- )</FONT></TD>
-</TR>
-
-% my $num=0;
-% foreach my $item ( @{ $opt{'names_list'} } ) {
-%
-% my $name = ref($item) ? $item->[0] : $item;
-% ( my $display = $name ) =~ s/ /&nbsp;/g;
-% $display .= $item->[1]{note} if ref($item) && $item->[1]{note};
-% my $desc = ref($item) && $item->[1]{desc} ? $item->[1]{desc} : '';
-%
-% my $checked;
-% if ( $cgi->param('error') ) {
-%
-% $checked = $cgi->param($opt{'link_table'}. ".$name" )
-% ? 'CHECKED'
-% : '';
-%
-% } else {
-%
-% $checked =
-% qsearchs( $opt{'link_table'}, {
-% $source_pkey => $sourcenum,
-% $opt{'name_col'} => $name,
-% %$link_static,
-% } )
-% ? 'CHECKED'
-% : ''
-%
-% }
-
- <TR>
- <TD VALIGN="top">
- <INPUT TYPE="checkbox" NAME="<% $opt{'link_table'}. ".$name" %>" <% $checked %> ID="<%$prefix.$num++%>" VALUE="ON">
- </TD>
- <TD><% $display %>
-% if ( $desc ) {
- <BR><FONT SIZE="-2"><% $desc %></FONT>
-% }
- </TD>
- </TR>
-
-% }
-
-</TABLE>
-
-<SCRIPT TYPE="text/javascript">
-
- function setAll<%$prefix%>(setTo) {
-% for ( 0 .. ($num-1) ) {
- document.getElementById('<%$prefix.$_%>').checked = setTo;
-% }
- }
-
- function toggleAll<%$prefix%>(setTo) {
-% for ( 0 .. ($num-1) ) {
- var element = document.getElementById('<%$prefix.$_%>');
- if ( element.checked == true ) {
- element.checked = false;
- } else {
- element.checked = true;
- }
-% }
- }
-
-</SCRIPT>
+<% include('checkboxes.html',
+ 'names_list' => $opt{'names_list'},
+ 'checked_callback' => $checked_callback,
+ 'element_name_prefix' => $opt{'link_table'}. '.',
+ )
+%>
<%init>
@@ -145,4 +78,13 @@ $source_pkey = $opt{'num_col'} || $source_pkey;
my $link_static = $opt{'link_static'} || {};
+my $checked_callback = sub {
+ my( $cgi, $name ) = @_;
+ qsearchs( $opt{'link_table'}, {
+ $source_pkey => $sourcenum,
+ $opt{'name_col'} => $name,
+ %$link_static,
+ });
+};
+
</%init>
diff --git a/httemplate/elements/checkboxes.html b/httemplate/elements/checkboxes.html
new file mode 100644
index 000000000..126224538
--- /dev/null
+++ b/httemplate/elements/checkboxes.html
@@ -0,0 +1,103 @@
+<%doc>
+
+Example:
+
+ include( '/elements/checkboxes.html',
+
+ # required
+
+ #? 'name_callback' => sub { },
+
+ 'names_list' => [ 'value',
+ 'other value',
+ [ 'complex value' => { 'desc' => "Add'l description",
+ 'note' => '&nbsp;*',
+ }
+ ],
+ ],
+
+ 'element_name_prefix' => "$link_table.",
+
+ #recommended
+
+ 'checked_callback' => sub { my( $cgi, $name ) = @_; },
+
+ )
+
+</%doc>
+
+<TABLE CELLSPACING=0 CELLPADDING=0>
+
+<TR>
+ <TD COLSPAN=2 ALIGN="center"><FONT SIZE="-1">(
+ <A HREF="javascript:setAll<%$prefix%>(true)">select all</A> |
+ <A HREF="javascript:setAll<%$prefix%>(false)">unselect all</A> |
+ <A HREF="javascript:toggleAll<%$prefix%>()">toggle all</A>
+ )</FONT></TD>
+</TR>
+
+% my $num=0;
+% foreach my $item ( @{ $opt{'names_list'} } ) {
+%
+% my $name = ref($item) ? $item->[0] : $item;
+% ( my $display = $name ) =~ s/ /&nbsp;/g;
+% $display .= $item->[1]{note} if ref($item) && $item->[1]{note};
+% my $desc = ref($item) && $item->[1]{desc} ? $item->[1]{desc} : '';
+%
+% my $callback =
+% ( $cgi->param('error') ? 'error_' : '' ). 'checked_callback';
+% my $checked = &{ $opt{$callback} }( $cgi, $name ) ? 'CHECKED' : '';
+
+ <TR>
+ <TD VALIGN="top">
+ <INPUT TYPE="checkbox" NAME="<% $opt{'element_name_prefix'}. $name %>" <% $checked %> ID="<%$prefix.$num++%>" VALUE="ON">
+ </TD>
+ <TD><% $display %>
+% if ( $desc ) {
+ <BR><FONT SIZE="-2"><% $desc %></FONT>
+% }
+ </TD>
+ </TR>
+
+% }
+
+</TABLE>
+
+<SCRIPT TYPE="text/javascript">
+
+ function setAll<%$prefix%>(setTo) {
+% for ( 0 .. ($num-1) ) {
+ document.getElementById('<%$prefix.$_%>').checked = setTo;
+% }
+ }
+
+ function toggleAll<%$prefix%>(setTo) {
+% for ( 0 .. ($num-1) ) {
+ var element = document.getElementById('<%$prefix.$_%>');
+ if ( element.checked == true ) {
+ element.checked = false;
+ } else {
+ element.checked = true;
+ }
+% }
+ }
+
+</SCRIPT>
+
+<%init>
+
+my( %opt ) = @_;
+
+my @pset = ( 'a'..'z', 'A'..'Z', '0'..'9' );
+
+my $prefix = $opt{prefix}
+ || join('', map $pset[ int(rand $#pset) ], (0..20) );
+
+$opt{checked_callback} ||= sub {};
+
+$opt{'error_checked_callback'} ||= sub {
+ my( $cgi, $name ) = @_;
+ $cgi->param($opt{'element_name_prefix'}. $name );
+};
+
+</%init>
diff --git a/httemplate/elements/select-rate.html b/httemplate/elements/select-rate.html
new file mode 100644
index 000000000..83a7add06
--- /dev/null
+++ b/httemplate/elements/select-rate.html
@@ -0,0 +1,9 @@
+<% include( '/elements/select-table.html',
+ 'table' => 'rate',
+ 'name_col' => 'ratename',
+ 'empty_label' => 'Select rate plan',
+ #'hashref' => { 'disabled' => '' },
+ 'order_by' => ' ORDER BY ratenum', #ratename ?
+ @_,
+ )
+%>
diff --git a/httemplate/elements/tr-select-rate.html b/httemplate/elements/tr-select-rate.html
new file mode 100644
index 000000000..27f2645af
--- /dev/null
+++ b/httemplate/elements/tr-select-rate.html
@@ -0,0 +1,21 @@
+% unless ( $opt{'js_only'} ) {
+
+ <% include('tr-td-label.html', @_ ) %>
+
+ <TD <% $style %>>
+% }
+
+ <% include( '/elements/select-rate.html', %opt ) %>
+
+% unless ( $opt{'js_only'} ) {
+ </TD>
+ </TR>
+% }
+<%init>
+
+my( %opt ) = @_;
+
+my $style = $opt{'cell_style'} ? 'STYLE="'. $opt{'cell_style'}. '"' : '';
+
+</%init>
+
diff --git a/httemplate/misc/copy-rate_detail.html b/httemplate/misc/copy-rate_detail.html
new file mode 100644
index 000000000..3d328ce59
--- /dev/null
+++ b/httemplate/misc/copy-rate_detail.html
@@ -0,0 +1,61 @@
+<% include( '/elements/header.html', 'Copy rates between plans', menubar(
+ 'View all rate plans' => "${p}browse/rate.cgi",
+ ))
+%>
+
+<% include('/elements/error.html') %>
+
+<FORM ACTION="process/copy-rate_detail.html">
+
+<% ntable('#cccccc') %>
+
+ <% include( '/elements/tr-justtitle.html', 'value' => 'Copy rates' ) %>
+
+ <% include( '/elements/tr-select-rate.html',
+ 'label' => 'From rate plan',
+ 'element_name' => 'src_ratenum',
+ )
+ %>
+
+ <% include( '/elements/tr-select-rate.html',
+ 'label' => 'To rate plan',
+ 'element_name' => 'dst_ratenum',
+ )
+ %>
+
+ <TR>
+ <TD COLSPAN=2>Copy country codes</TD>
+ </TR>
+
+ <TR>
+ <TD COLSPAN=2>
+
+ <% include( '/elements/checkboxes.html',
+ 'names_list' => [ FS::rate_prefix->all_countrycodes ],
+ 'element_name_prefix' => 'countrycode',
+ )
+ %>
+ </TD>
+ </TR>
+
+ <TR>
+ <TD COLSPAN=2 ALIGN="center">
+ <INPUT TYPE="submit" VALUE="Copy rates">
+ </TD>
+ </TR>
+
+</TABLE>
+
+</FORM>
+
+<% include('/elements/footer.html') %>
+
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+#should have some javascript that enables submit button only when both src & dst
+#rates are chosen
+
+</%init>
diff --git a/httemplate/misc/process/copy-rate_detail.html b/httemplate/misc/process/copy-rate_detail.html
new file mode 100644
index 000000000..87a674566
--- /dev/null
+++ b/httemplate/misc/process/copy-rate_detail.html
@@ -0,0 +1,61 @@
+%# if ( $error ) {
+%# <% $cgi->redirect(popurl(2).'copy-rate_detail.html?'. $cgi->query_string ) %>
+%# } else {
+<% include('/elements/header.html', 'Rates copied',
+ menubar( 'View all rate plans' => popurl(3).'browse/rate.cgi' ),
+ ) %>
+%# }
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+$cgi->param('src_ratenum') =~ /^(\d+)$/ or die 'Illegal src_ratenum';
+my $src_ratenum = $1;
+
+$cgi->param('dst_ratenum') =~ /^(\d+)$/ or die 'Illegal src_ratenum';
+my $dst_ratenum = $1;
+
+my @countrycodes = map { /^countrycode(\d+)$/ or die; $1 }
+ grep { /^countrycode(\d+)$/ && $cgi->param($_) }
+ $cgi->param;
+
+foreach my $countrycode ( @countrycodes ) {
+
+ my @src_rate_detail = qsearch({
+ 'table' => 'rate_detail',
+ 'addl_from' => 'JOIN rate_region'.
+ ' ON ( rate_detail.dest_regionnum = rate_region.regionnum )',
+ 'hashref' => { 'ratenum' => $src_ratenum },
+ 'extra_sql' =>
+ "AND 0 < ( SELECT COUNT(*) FROM rate_prefix
+ WHERE rate_prefix.regionnum = rate_region.regionnum
+ AND countrycode = '$countrycode'
+ )
+ ",
+ });
+
+ foreach my $src_rate_detail ( @src_rate_detail ) {
+
+ my %hash = (
+ 'ratenum' => $dst_ratenum,
+ map { $_ => $src_rate_detail->get($_) }
+ qw( orig_regionnum dest_regionnum )
+ );
+
+ my $dst_rate_detail = qsearchs( 'rate_detail', \%hash)
+ || new FS::rate_detail \%hash;
+
+ $dst_rate_detail->$_( $src_rate_detail->get($_) )
+ foreach qw( min_included min_charge sec_granularity classnum );
+
+ my $method = $dst_rate_detail->ratedetailnum ? 'replace' : 'insert';
+
+ my $error = $dst_rate_detail->$method();
+
+ die $error if $error; # "shouldn't" happen
+
+ }
+}
+
+</%init>