summaryrefslogtreecommitdiff
path: root/httemplate/misc
diff options
context:
space:
mode:
Diffstat (limited to 'httemplate/misc')
-rwxr-xr-xhttemplate/misc/bulk_change_pkg.cgi25
-rwxr-xr-xhttemplate/misc/cancel_pkg.html2
-rwxr-xr-xhttemplate/misc/change_pkg.cgi22
-rw-r--r--httemplate/misc/cust-part_pkg.cgi29
-rw-r--r--httemplate/misc/cust_main-import.cgi2
-rwxr-xr-xhttemplate/misc/delay_susp_pkg.html2
-rw-r--r--httemplate/misc/delete-cust_bill.html21
-rwxr-xr-xhttemplate/misc/delete-phone_device.html23
-rw-r--r--httemplate/misc/download-batch.cgi200
-rw-r--r--httemplate/misc/email-customers.html2
-rwxr-xr-xhttemplate/misc/link.cgi1
-rw-r--r--httemplate/misc/meta-import.cgi2
-rw-r--r--httemplate/misc/order_pkg.html49
-rw-r--r--httemplate/misc/part_device-import.html53
-rw-r--r--httemplate/misc/part_svc-columns.cgi13
-rw-r--r--httemplate/misc/payment.cgi152
-rw-r--r--httemplate/misc/ping.html102
-rwxr-xr-xhttemplate/misc/process/link.cgi10
-rw-r--r--httemplate/misc/process/part_device-import.html9
-rw-r--r--httemplate/misc/process/payment.cgi23
-rw-r--r--httemplate/misc/process/rate_edit_excel.html10
-rwxr-xr-xhttemplate/misc/process/recharge_svc.html103
-rw-r--r--httemplate/misc/process/tax-fetch_and_import.cgi9
-rw-r--r--httemplate/misc/process/tax-fetch_and_replace.cgi9
-rw-r--r--httemplate/misc/process/tax-import.cgi2
-rw-r--r--httemplate/misc/rate_edit_excel.html61
-rw-r--r--httemplate/misc/send-invoice.cgi30
-rwxr-xr-xhttemplate/misc/send-statement.cgi28
-rw-r--r--httemplate/misc/states.cgi12
-rw-r--r--httemplate/misc/tax-fetch_and_import.cgi48
-rw-r--r--httemplate/misc/tax-fetch_and_replace.cgi48
-rw-r--r--httemplate/misc/tax-import.cgi8
-rw-r--r--httemplate/misc/xmlhttp-cust_main-address_standardize.html5
-rw-r--r--httemplate/misc/xmlhttp-cust_main-censustract.html105
-rw-r--r--httemplate/misc/xmlhttp-ping.html20
35 files changed, 891 insertions, 349 deletions
diff --git a/httemplate/misc/bulk_change_pkg.cgi b/httemplate/misc/bulk_change_pkg.cgi
index 9334985..7f47a84 100755
--- a/httemplate/misc/bulk_change_pkg.cgi
+++ b/httemplate/misc/bulk_change_pkg.cgi
@@ -7,17 +7,23 @@
<FORM ACTION="<% $p %>misc/process/bulk_change_pkg.cgi" METHOD=POST>
-<INPUT TYPE="hidden" NAME="query" VALUE="<% $cgi->keywords %>">
-% for my $param (qw(agentnum magic status classnum pkgpart)) {
-<INPUT TYPE="hidden" NAME="<% $param %>" VALUE="<% $cgi->param($param) %>">
+%# some false laziness w/search/cust_pkg.cgi
+
+<INPUT TYPE="hidden" NAME="query" VALUE="<% $cgi->keywords |h %>">
+% for my $param (qw(agentnum magic status classnum custom censustract)) {
+<INPUT TYPE="hidden" NAME="<% $param %>" VALUE="<% $cgi->param($param) |h %>">
% }
%
+% foreach my $pkgpart ($cgi->param('pkgpart')) {
+<INPUT TYPE="hidden" NAME="pkgpart" VALUE="<% $pkgpart |h %>">
+% }
+%
% foreach my $field (qw( setup last_bill bill adjourn susp expire cancel )) {
%
- <INPUT TYPE="hidden" NAME="<% $field %>begin" VALUE="<% $cgi->param("${field}.begin") %>">
- <INPUT TYPE="hidden" NAME="<% $field %>beginning" VALUE="<% $cgi->param("${field}beginning") %>">
- <INPUT TYPE="hidden" NAME="<% $field %>end" VALUE="<% $cgi->param("${field}.end") %>">
- <INPUT TYPE="hidden" NAME="<% $field %>ending" VALUE="<% $cgi->param("${field}.ending") %>">
+ <INPUT TYPE="hidden" NAME="<% $field %>begin" VALUE="<% $cgi->param("${field}.begin") |h %>">
+ <INPUT TYPE="hidden" NAME="<% $field %>beginning" VALUE="<% $cgi->param("${field}beginning") |h %>">
+ <INPUT TYPE="hidden" NAME="<% $field %>end" VALUE="<% $cgi->param("${field}.end") |h %>">
+ <INPUT TYPE="hidden" NAME="<% $field %>ending" VALUE="<% $cgi->param("${field}.ending") |h %>">
% }
<% ntable('#cccccc') %>
@@ -28,10 +34,7 @@
'table' => 'part_pkg',
'name_col' => 'pkg',
'empty_label' => 'Select package',
- 'label_callback' => sub { $_[0]->pkgpart. ': '.
- $_[0]->pkg. ' - '.
- $_[0]->comment;
- },
+ 'label_callback' => sub { $_[0]->pkg_comment },
'element_name' => 'new_pkgpart',
'curr_value' => ( $cgi->param('error')
? scalar($cgi->param('new_pkgpart'))
diff --git a/httemplate/misc/cancel_pkg.html b/httemplate/misc/cancel_pkg.html
index e0e5fd1..607ce13 100755
--- a/httemplate/misc/cancel_pkg.html
+++ b/httemplate/misc/cancel_pkg.html
@@ -17,7 +17,7 @@
<BR><BR>
-<% ucfirst($method) . " $pkgnum: " .$part_pkg->pkg. ' - ' .$part_pkg->comment %>
+<% ucfirst($method) %> <% $part_pkg->pkg_comment %>
<% ntable("#cccccc", 2) %>
% if ($method eq 'expire' || $method eq 'adjourn') {
diff --git a/httemplate/misc/change_pkg.cgi b/httemplate/misc/change_pkg.cgi
index c4dfca2..16b7071 100755
--- a/httemplate/misc/change_pkg.cgi
+++ b/httemplate/misc/change_pkg.cgi
@@ -13,19 +13,15 @@
<% $curuser->option('show_pkgnum') ? $cust_pkg->pkgnum.': ' : '' %><B><% $part_pkg->pkg |h %></B> - <% $part_pkg->comment |h %>
</TD>
</TR>
-
- <TR>
- <TH ALIGN="right">New package</TH>
- <TD COLSPAN=7>
- <% include('/elements/select-cust-part_pkg.html',
- 'cust_main' => $cust_main,
- 'element_name' => 'pkgpart',
- #'extra_sql' => ' AND pkgpart != '. $cust_pkg->pkgpart,
- 'curr_value' => scalar($cgi->param('pkgpart')),
- )
- %>
- </TD>
- </TR>
+
+ <% include('/elements/tr-select-cust-part_pkg.html',
+ 'pre_label' => 'New',
+ 'curr_value' => scalar($cgi->param('pkgpart')),
+ 'classnum' => $part_pkg->classnum,
+ 'cust_main' => $cust_main,
+ #'extra_sql' => ' AND pkgpart != '. $cust_pkg->pkgpart,
+ )
+ %>
<% include('/elements/tr-select-cust_location.html',
'cgi' => $cgi,
diff --git a/httemplate/misc/cust-part_pkg.cgi b/httemplate/misc/cust-part_pkg.cgi
new file mode 100644
index 0000000..a249f03
--- /dev/null
+++ b/httemplate/misc/cust-part_pkg.cgi
@@ -0,0 +1,29 @@
+<% objToJson( \@return ) %>
+<%init>
+
+my( $custnum, $classnum ) = $cgi->param('arg');
+
+#XXX i guess i should be agent-virtualized. cause "packages a customer can
+#order" is such a huge deal
+my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } );
+
+my %hash = ( 'disabled' => '' );
+if ( $classnum > 0 ) {
+ $hash{'classnum'} = $classnum;
+} elsif ( $classnum eq '' || $classnum == 0 ) {
+ $hash{'classnum'} = '';
+} #else -1, all classes, so don't set classnum
+
+my @part_pkg = qsearch({
+ 'table' => 'part_pkg',
+ 'hashref' => \%hash,
+ 'extra_sql' =>
+ ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql( 'null'=>1 ).
+ ' AND '. FS::part_pkg->agent_pkgs_sql( $cust_main->agent ),
+});
+
+my @return = map { $_->pkgpart => $_->pkg_comment }
+ sort { $a->pkg_comment cmp $b->pkg_comment }
+ @part_pkg;
+
+</%init>
diff --git a/httemplate/misc/cust_main-import.cgi b/httemplate/misc/cust_main-import.cgi
index b822c5d..9c1f984 100644
--- a/httemplate/misc/cust_main-import.cgi
+++ b/httemplate/misc/cust_main-import.cgi
@@ -56,7 +56,7 @@ Import a file containing customer records.
<SELECT NAME="pkgpart"><OPTION VALUE="">(none)</OPTION>
% foreach my $part_pkg ( qsearch('part_pkg',{'disabled'=>'' }) ) {
- <OPTION VALUE="<% $part_pkg->pkgpart %>"><% $part_pkg->pkg. ' - '. $part_pkg->comment %></OPTION>
+ <OPTION VALUE="<% $part_pkg->pkgpart %>"><% $part_pkg->pkg_comment %></OPTION>
% }
</SELECT>
diff --git a/httemplate/misc/delay_susp_pkg.html b/httemplate/misc/delay_susp_pkg.html
index 1158a35..d4a6da1 100755
--- a/httemplate/misc/delay_susp_pkg.html
+++ b/httemplate/misc/delay_susp_pkg.html
@@ -12,7 +12,7 @@
<INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $pkgnum %>">
<BR><BR>
-<% "Delay automatic suspension of $pkgnum: " .$part_pkg->pkg. ' - ' .$part_pkg->comment %>
+<% "Delay automatic suspension of " .$part_pkg->pkg_comment %>
<% ntable("#cccccc", 2) %>
<TR>
diff --git a/httemplate/misc/delete-cust_bill.html b/httemplate/misc/delete-cust_bill.html
new file mode 100644
index 0000000..3a642b0
--- /dev/null
+++ b/httemplate/misc/delete-cust_bill.html
@@ -0,0 +1,21 @@
+% if ( $error ) {
+% errorpage($error);
+% } else {
+<% $cgi->redirect($p. "view/cust_main.cgi?". $custnum) %>
+% }
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Delete invoices');
+
+#untaint invnum
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/ || die "Illegal crednum";
+my $invnum = $1;
+
+my $cust_bill = qsearchs('cust_bill',{'invnum'=>$invnum});
+my $custnum = $cust_bill->custnum;
+
+my $error = $cust_bill->delete;
+
+</%init>
diff --git a/httemplate/misc/delete-phone_device.html b/httemplate/misc/delete-phone_device.html
new file mode 100755
index 0000000..7220c41
--- /dev/null
+++ b/httemplate/misc/delete-phone_device.html
@@ -0,0 +1,23 @@
+% if ( $error ) {
+% errorpage($error);
+% } else {
+<% $cgi->redirect($p. "view/svc_phone.cgi?". $svcnum) %>
+% }
+<%init>
+
+# :/ needs agent-virt so you can't futz with arbitrary devices
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific?
+
+#untaint devicenum
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/ || die "Illegal devicenum";
+my $devicenum = $1;
+
+my $phone_device = qsearchs('phone_device', { 'devicenum' => $devicenum } );
+my $svcnum = $phone_device->svcnum;
+
+my $error = $phone_device->delete;
+
+</%init>
diff --git a/httemplate/misc/download-batch.cgi b/httemplate/misc/download-batch.cgi
index 57905da..01bf5d2 100644
--- a/httemplate/misc/download-batch.cgi
+++ b/httemplate/misc/download-batch.cgi
@@ -1,146 +1,9 @@
-%if ($format eq "BoM") {
-%
-% my($origid,$datacenter,$typecode,$shortname,$longname,$mybank,$myacct) =
-% $conf->config("batchconfig-$format");
-%
-<% sprintf( "A%10s%04u%06u%05u%54s\n",$origid,$pay_batch->batchnum,$jdate,$datacenter,"").
- sprintf( "XD%03u%06u%-15s%-30s%09u%-12s \n",$typecode,$jdate,$shortname,$longname,$mybank,$myacct )
- %>
-%
-%}elsif ($format eq "PAP"){
-%
-% my($origid,$datacenter,$typecode,$shortname,$longname,$mybank,$myacct) =
-% $conf->config("batchconfig-$format");
-%
-<% sprintf( "H%10sD%3s%06u%-15s%09u%-12s%04u%19s\n",$origid,$typecode,$cdate,$shortname,$mybank,$myacct,$pay_batch->batchnum,"") %>
-%
-%
-%}elsif ($format eq "csv-td_canada_trust-merchant_pc_batch"){
-%# 1;
-%}elsif ($format eq "csv-chase_canada-E-xactBatch"){
-%
-% my($origid) = $conf->config("batchconfig-$format");
-<% sprintf( '$$E-xactBatchFileV1.0$$%s:%03u$$%s',$sdate,$pay_batch->batchnum, $origid)
- %>
-%
-%}elsif ($format eq "ach-spiritone"){
-%# 1;
-%}else{
-% die "Unknown format for batch in batchconfig. \n";
-%}
-%
-%
-%for my $cust_pay_batch ( sort { $a->paybatchnum <=> $b->paybatchnum }
-% qsearch('cust_pay_batch',
-% {'batchnum'=>$pay_batch->batchnum} )
-%) {
-%
-% $cust_pay_batch->exp =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/;
-% my( $mon, $y ) = ( $2, $1 );
-% if ( $conf->exists('batch-increment_expiration') ) {
-% my( $curmon, $curyear ) = (localtime(time))[4,5];
-% $curmon++; $curyear-=100;
-% $y++ while $y < $curyear || ( $y == $curyear && $mon < $curmon );
-% }
-% $mon = "0$mon" if $mon =~ /^\d$/;
-% $y = "0$y" if $y =~ /^\d$/;
-% my $exp = "$mon$y";
-%
-% if ( $first_download ) {
-% my $balance = $cust_pay_batch->cust_main->balance;
-% if ( $balance <= 0 ) {
-% my $error = $cust_pay_batch->delete;
-% if ( $error ) {
-% $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
-% die $error;
-% }
-% next;
-% } elsif ( $balance < $cust_pay_batch->amount ) {
-% $cust_pay_batch->amount($balance);
-% my $error = $cust_pay_batch->replace;
-% if ( $error ) {
-% $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
-% die $error;
-% }
-% #} elsif ( $balance > $cust_pay_batch->amount ) {
-% }
-% }
-%
-% $batchcount++;
-% $batchtotal += $cust_pay_batch->amount;
-%
-% if ($format eq "BoM") {
-%
-% my( $account, $aba ) = split( '@', $cust_pay_batch->payinfo );
-%
-<% sprintf( "D%010.0f%09u%-12s%-29s%-19s\n",$cust_pay_batch->amount*100,$aba,$account,$cust_pay_batch->payname,$cust_pay_batch->paybatchnum) %>
-%
-%
-% } elsif ($format eq "PAP"){
-%
-% my( $account, $aba ) = split( '@', $cust_pay_batch->payinfo );
-%
-<% sprintf( "D%-23s%06u%-19s%09u%-12s%010.0f\n",$cust_pay_batch->payname,$cdate,$cust_pay_batch->paybatchnum,$aba,$account,$cust_pay_batch->amount*100) %>
-%
-%
-% } elsif ($format eq "csv-td_canada_trust-merchant_pc_batch") {
-%
-%
-,,,,<% $cust_pay_batch->payinfo %>,<% $exp %>,<% $cust_pay_batch->amount %>,<% $cust_pay_batch->paybatchnum %>
-%
-%
-% } elsif ($format eq "csv-chase_canada-E-xactBatch"){
-%
-% my $payname=$cust_pay_batch->payname; $payname =~ tr/",/ /; #payinfo too? :P
-<% $cust_pay_batch->paybatchnum %>,<% $cust_pay_batch->custnum %>,<% $cust_pay_batch->invnum %>,"<% $payname %>",00,<% $cust_pay_batch->payinfo %>,<% $cust_pay_batch->amount %>,<% $exp %>,,
-%
-%
-% }elsif ($format eq "ach-spiritone"){
-%
-% my( $account, $aba ) = split( '@', $cust_pay_batch->payinfo );
-% my $payname=$cust_pay_batch->first. " ". $cust_pay_batch->last;
-% $payname =~ tr/",/ /; #payinfo too?
-% my $batchline = qq!"$payname","!.$cust_pay_batch->paybatchnum.
-% qq!","$aba","$account","27","!.$cust_pay_batch->amount.
-% qq!","27","0.00"!;
-% push @batchlines, $batchline;
-<% $batchline %>
-%
-% } else {
-% die "I'm already dead, but you did not know that.\n";
-% }
-%
-%}
-%
-%if ($format eq "BoM") {
-%
-%
-<% sprintf( "YD%08u%014.0f%56s\n",$batchcount,$batchtotal*100,"" ).
- sprintf( "Z%014u%05u%014u%05u%41s\n",$batchtotal*100,$batchcount,"0","0","" ) %>
-%
-%
-%} elsif ($format eq "PAP"){
-%
-%
-<% sprintf( "T%08u%014.0f%57s\n",$batchcount,$batchtotal*100,"" ) %>
-%
-%
-%} elsif ($format eq "csv-td_canada_trust-merchant_pc_batch"){
-% #1;
-%} elsif ($format eq "csv-chase_canada-E-xactBatch"){
-% #1;
-%} elsif ($format eq "ach-spiritone"){
-% #1;
-%} else {
-% die "I'm already dead (again), but you did not know that.\n";
-%}
-%
-<%init>
+<% $pay_batch->export_batch($format) %>
-my $conf=new FS::Conf;
+<%init>
#http_header('Content-Type' => 'text/comma-separated-values' ); #IE chokes
-http_header('Content-Type' => 'text/plain' );
+http_header('Content-Type' => 'text/plain' ); # not necessarily correct...
my $batchnum;
if ( $cgi->param('batchnum') =~ /^(\d+)$/ ) {
@@ -152,62 +15,9 @@ if ( $cgi->param('batchnum') =~ /^(\d+)$/ ) {
my $format;
if ( $cgi->param('format') =~ /^([\w\- ]+)$/ ) {
$format = $1;
-} else {
- $format = $conf->config('batch-default_format');
-}
-
-my $autopost;
-if ( $format eq 'ach-spiritone' ) {
- $autopost = 1;
-}else{
- $autopost = 0;
-}
-
-my $oldAutoCommit = $FS::UID::AutoCommit;
-local $FS::UID::AutoCommit = 0;
-my $dbh = dbh;
-
-my $pay_batch = qsearchs('pay_batch', {'batchnum'=>$batchnum, 'status'=>'O'} );
-my $first_download = 1;
-unless ($pay_batch) {
- $pay_batch = qsearchs('pay_batch', {'batchnum'=>$batchnum, 'status'=>'I'} )
- if $FS::CurrentUser::CurrentUser->access_right('Reprocess batches');
- $first_download = 0;
}
-die "No pending batch. \n" unless $pay_batch;
-my $error = $pay_batch->set_status('I');
-die "error updating batch status: $error\n" if $error;
+my $pay_batch = qsearchs('pay_batch', { batchnum => $batchnum } );
+die "Batch not found: '$batchnum'" if !$pay_batch;
-my $batchtotal=0;
-my $batchcount=0;
-
-my (@date)=localtime($pay_batch->download);
-my $jdate = sprintf("%03d", $date[5] % 100).sprintf("%03d", $date[7] + 1);
-my $cdate = sprintf("%02d", $date[3]).sprintf("%02d", $date[4] + 1).
- sprintf("%02d", $date[5] % 100);
-my $sdate = sprintf("%02d", $date[5] % 100).'/'.sprintf("%02d", $date[4] + 1).
- '/'.sprintf("%02d", $date[3]);
-
-my @batchlines = ();
</%init>
-<%cleanup>
-if ($autopost) {
- my $dir = $FS::UID::conf_dir. "/cache.". $FS::UID::datasrc;
- my $fh = new File::Temp(
- TEMPLATE => 'paybatch.'. $batchnum .'.XXXXXXXX',
- DIR => $dir,
- ) or die "can't open temp file: $!\n";
-
- print $fh map{ "$_\n" } @batchlines;
- seek $fh, 0, 0;
-
- $error = $pay_batch->import_results( 'filehandle' => $fh,
- 'format' => $format,
- );
- die $error if $error;
-}
-
-$dbh->commit or die $dbh->errstr if $oldAutoCommit;
-
-</%cleanup>
diff --git a/httemplate/misc/email-customers.html b/httemplate/misc/email-customers.html
index 0d3d622..f644db9 100644
--- a/httemplate/misc/email-customers.html
+++ b/httemplate/misc/email-customers.html
@@ -126,7 +126,7 @@ die "access denied"
my %search = $cgi->Vars;
delete $search{$_} for qw( magic from subject html_body text_body );
$search{$_} = [ split(/\0/, $search{$_}) ]
- foreach grep $search{$_} =~ /\0/, keys %search;
+ foreach grep { $_ eq 'payby' || $search{$_} =~ /\0/ } keys %search;
my $title = 'Bulk send customer notices';
diff --git a/httemplate/misc/link.cgi b/httemplate/misc/link.cgi
index 748eaa1..f37f769 100755
--- a/httemplate/misc/link.cgi
+++ b/httemplate/misc/link.cgi
@@ -58,6 +58,7 @@ die "access denied"
my %link_field = (
'svc_acct' => 'username',
'svc_domain' => 'domain',
+ 'svc_phone' => 'phonenum',
);
my %link_field2 = (
diff --git a/httemplate/misc/meta-import.cgi b/httemplate/misc/meta-import.cgi
index 5b3470c..8c158bd 100644
--- a/httemplate/misc/meta-import.cgi
+++ b/httemplate/misc/meta-import.cgi
@@ -46,7 +46,7 @@ Import data from a DBI data source<BR><BR>
First package: <SELECT NAME="pkgpart"><OPTION VALUE="">(none)</OPTION>
% foreach my $part_pkg ( qsearch('part_pkg',{'disabled'=>'' }) ) {
- <OPTION VALUE="<% $part_pkg->pkgpart %>"><% $part_pkg->pkg. ' - '. $part_pkg->comment %></OPTION>
+ <OPTION VALUE="<% $part_pkg->pkgpart %>"><% $part_pkg->pkg_comment %></OPTION>
% }
</SELECT><BR><BR>
diff --git a/httemplate/misc/order_pkg.html b/httemplate/misc/order_pkg.html
index 2c83351..a7571ca 100644
--- a/httemplate/misc/order_pkg.html
+++ b/httemplate/misc/order_pkg.html
@@ -1,5 +1,10 @@
<% include('/elements/header-popup.html', 'Order new package' ) %>
+<LINK REL="stylesheet" TYPE="text/css" HREF="../elements/calendar-win2k-2.css" TITLE="win2k-2">
+<SCRIPT TYPE="text/javascript" SRC="../elements/calendar_stripped.js"></SCRIPT>
+<SCRIPT TYPE="text/javascript" SRC="../elements/calendar-en.js"></SCRIPT>
+<SCRIPT TYPE="text/javascript" SRC="../elements/calendar-setup.js"></SCRIPT>
+
<SCRIPT TYPE="text/javascript">
function enable_order_pkg () {
@@ -19,18 +24,42 @@
<INPUT TYPE="hidden" NAME="custnum" VALUE="<% $cust_main->custnum %>">
<% ntable("#cccccc", 2) %>
+<% include('/elements/tr-select-cust-part_pkg.html',
+ 'curr_value' => $pkgpart,
+ 'classnum' => -1,
+ 'cust_main' => $cust_main,
+ 'onchange' => 'enable_order_pkg',
+ )
+%>
+
+%# false laziness w/edit/quick-charge.html
<TR>
- <TH ALIGN="right">Package</TH>
- <TD COLSPAN=7>
- <% include('/elements/select-cust-part_pkg.html',
- 'curr_value' => $pkgpart,
- 'cust_main' => $cust_main,
- 'onchange' => 'enable_order_pkg',
- )
- %>
+ <TH ALIGN="right">Start date </TD>
+ <TD COLSPAN=6>
+ <INPUT TYPE = "text"
+ NAME = "start_date"
+ SIZE = 32
+ ID = "start_date_text"
+ VALUE = "<% $start_date %>"
+ >
+ <IMG SRC = "../images/calendar.png"
+ ID = "start_date_button"
+ STYLE = "cursor: pointer"
+ TITLE = "Select date"
+ >
+ <FONT SIZE=-1>(leave blank to start immediately)</FONT>
</TD>
</TR>
+<SCRIPT TYPE="text/javascript">
+ Calendar.setup({
+ inputField: "start_date_text",
+ ifFormat: "%m/%d/%Y",
+ button: "start_date_button",
+ align: "BR"
+ });
+</SCRIPT>
+
% if ( $conf->exists('pkg_referral') ) {
<% include('/elements/tr-select-part_referral.html',
'curr_value' => scalar( $cgi->param('refnum') ), #get rid of empty_label first# || $cust_main->refnum,
@@ -72,4 +101,8 @@ my $cust_main = qsearchs({
my $pkgpart = scalar($cgi->param('pkgpart'));
+my $format = "%m/%d/%Y %T %z (%Z)"; #false laziness w/REAL_cust_pkg.cgi?
+my $start_date = $cust_main->next_bill_date;
+$start_date = $start_date ? time2str($format, $start_date) : '';
+
</%init>
diff --git a/httemplate/misc/part_device-import.html b/httemplate/misc/part_device-import.html
new file mode 100644
index 0000000..7bd6404
--- /dev/null
+++ b/httemplate/misc/part_device-import.html
@@ -0,0 +1,53 @@
+<% include("/elements/header.html", 'Import device types') %>
+
+Import a file containing phone device types, one per line.
+<BR><BR>
+
+<% include( '/elements/form-file_upload.html',
+ 'name' => 'PartDeviceImportForm',
+ 'action' => 'process/part_device-import.html',
+ 'num_files' => 1,
+ 'fields' => [ 'format', ],
+ 'message' => 'Device type import successful',
+ 'url' => $p.'browse/part_device.html',
+ )
+%>
+
+<% &ntable("#cccccc", 2) %>
+
+ <INPUT TYPE="hidden" NAME="format" VALUE="default">
+
+ <% include( '/elements/file-upload.html',
+ 'field' => 'file',
+ 'label' => 'Filename',
+ )
+ %>
+
+ <TR>
+ <TD COLSPAN=2 ALIGN="center" STYLE="padding-top:6px">
+ <INPUT TYPE = "submit"
+ ID = "submit"
+ VALUE = "Import file"
+ onClick = "document.PartDeviceImportForm.submit.disabled=true;"
+ >
+ </TD>
+ </TR>
+
+</TABLE>
+
+</FORM>
+
+<BR>
+
+Upload file can be a text file or Excel spreadsheet. If an Excel spreadsheet,
+ should have an .XLS extension.
+<BR><BR>
+
+<% include('/elements/footer.html') %>
+
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Import');
+
+</%init>
diff --git a/httemplate/misc/part_svc-columns.cgi b/httemplate/misc/part_svc-columns.cgi
new file mode 100644
index 0000000..0602561
--- /dev/null
+++ b/httemplate/misc/part_svc-columns.cgi
@@ -0,0 +1,13 @@
+<% objToJson(\@output) %>
+<%init>
+
+my $conf = new FS::Conf;
+
+my $pkgpart_svcpart = $cgi->param('arg');
+$pkgpart_svcpart =~ /^\d+_(\d+)$/;
+my $part_svc = qsearchs('part_svc', { 'svcpart' => $1 }) if $1;
+
+my @output = map { ( $_->columnname, $_->columnflag, $_->columnvalue ) }
+ $part_svc->all_part_svc_column;
+
+</%init>
diff --git a/httemplate/misc/payment.cgi b/httemplate/misc/payment.cgi
index 0047004..813b560 100644
--- a/httemplate/misc/payment.cgi
+++ b/httemplate/misc/payment.cgi
@@ -12,23 +12,66 @@
<% ntable('#cccccc') %>
<TR>
- <TD ALIGN="right">Payment amount</TD>
- <TD>
+ <TH ALIGN="right">Payment amount</TH>
+ <TD COLSPAN=7>
<TABLE><TR><TD BGCOLOR="#ffffff">
- $<INPUT TYPE="text" NAME="amount" SIZE=8 VALUE="<% $balance > 0 ? sprintf("%.2f", $balance) : '' %>">
+ <% $money_char %><INPUT NAME = "amount"
+ TYPE = "text"
+ VALUE = "<% $amount %>"
+ SIZE = 8
+ STYLE = "text-align:right;"
+% if ( $fee ) {
+ onChange = "amount_changed(this)"
+ onKeyDown = "amount_changed(this)"
+ onKeyUp = "amount_changed(this)"
+ onKeyPress = "amount_changed(this)"
+% }
+ >
+ </TD><TD BGCOLOR="#cccccc">
+% if ( $fee ) {
+ <INPUT TYPE="hidden" NAME="fee_pkgpart" VALUE="<% $fee_pkg->pkgpart %>">
+ <INPUT TYPE="hidden" NAME="fee" VALUE="<% $fee_display eq 'add' ? $fee : '' %>">
+ <B><FONT SIZE='+1'><% $fee_op %></FONT>
+ <% $money_char . $fee %>
+ </B>
+ <% $fee_pkg->pkg |h %>
+ <B><FONT SIZE='+1'>=</FONT></B>
+ </TD><TD ID="ajax_total_cell" BGCOLOR="#dddddd" STYLE="border:1px solid blue">
+ <FONT SIZE="+1"><% length($amount) ? $money_char. sprintf('%.2f', ($fee_display eq 'add') ? $amount + $fee : $amount - $fee ) : '' %> <% $fee_display eq 'add' ? 'TOTAL' : 'AVAILABLE' %></FONT>
+
+% }
</TD></TR></TABLE>
</TD>
</TR>
+% if ( $fee ) {
+
+ <SCRIPT TYPE="text/javascript">
+
+ function amount_changed(what) {
+
+
+ var total = '';
+ if ( what.value.length ) {
+ total = parseFloat(what.value) <% $fee_op %> <% $fee %>;
+ /* total = Math.round(total*100)/100; */
+ total = '<% $money_char %>' + total.toFixed(2);
+ }
+
+ var total_cell = document.getElementById('ajax_total_cell');
+ total_cell.innerHTML = '<FONT SIZE="+1">' + total + ' <% $fee_display eq 'add' ? 'TOTAL' : 'AVAILABLE' %></FONT>';
+
+ }
+
+ </SCRIPT>
+
+% }
+
+
% if ( $payby eq 'CARD' ) {
%
% my( $payinfo, $paycvv, $month, $year ) = ( '', '', '', '' );
% my $payname = $cust_main->first. ' '. $cust_main->getfield('last');
-% my $address1 = $cust_main->address1;
-% my $address2 = $cust_main->address2;
-% my $city = $cust_main->city;
-% my $state = $cust_main->state;
-% my $zip = $cust_main->zip;
% if ( $cust_main->payby =~ /^(CARD|DCRD)$/ ) {
% $payinfo = $cust_main->paymask;
% $paycvv = $cust_main->paycvv;
@@ -37,13 +80,13 @@
% }
<TR>
- <TD ALIGN="right">Card&nbsp;number</TD>
- <TD>
+ <TH ALIGN="right">Card&nbsp;number</TH>
+ <TD COLSPAN=7>
<TABLE>
<TR>
<TD>
<INPUT TYPE="text" NAME="payinfo" SIZE=20 MAXLENGTH=19 VALUE="<%$payinfo%>"> </TD>
- <TD>Exp.</TD>
+ <TH>Exp.</TH>
<TD>
<SELECT NAME="month">
% for ( ( map "0$_", 1 .. 9 ), 10 .. 12 ) {
@@ -68,51 +111,23 @@
</TD>
</TR>
<TR>
- <TD ALIGN="right">CVV2</TD>
+ <TH ALIGN="right">CVV2</TH>
<TD><INPUT TYPE="text" NAME="paycvv" VALUE="<% $paycvv %>" SIZE=4 MAXLENGTH=4>
(<A HREF="javascript:void(0);" onClick="overlib( OLiframeContent('../docs/cvv2.html', 480, 352, 'cvv2_popup' ), CAPTION, 'CVV2 Help', STICKY, AUTOSTATUSCAP, CLOSECLICK, DRAGGABLE ); return false;">help</A>)
</TD>
</TR>
<TR>
- <TD ALIGN="right">Exact&nbsp;name&nbsp;on&nbsp;card</TD>
+ <TH ALIGN="right">Exact&nbsp;name&nbsp;on&nbsp;card</TH>
<TD><INPUT TYPE="text" SIZE=32 MAXLENGTH=80 NAME="payname" VALUE="<%$payname%>"></TD>
- </TR><TR>
- <TD ALIGN="right">Card&nbsp;billing&nbsp;address</TD>
- <TD>
- <INPUT TYPE="text" SIZE=40 MAXLENGTH=80 NAME="address1" VALUE="<%$address1%>">
- </TD>
- </TR><TR>
- <TD ALIGN="right">Address&nbsp;line&nbsp;2</TD>
- <TD>
- <INPUT TYPE="text" SIZE=40 MAXLENGTH=80 NAME="address2" VALUE="<%$address2%>">
- </TD>
- </TR><TR>
- <TD ALIGN="right">City</TD>
- <TD>
- <TABLE>
- <TR>
- <TD>
- <INPUT TYPE="text" NAME="city" SIZE="12" MAXLENGTH=80 VALUE="<%$city%>">
- </TD>
- <TD>State</TD>
- <TD>
- <SELECT NAME="state">
-% for ( @states ) {
-
- <OPTION<% $_ eq $state ? ' SELECTED' : '' %>><% $_ %>
-% }
-
- </SELECT>
- </TD>
- <TD>Zip</TD>
- <TD>
- <INPUT TYPE="text" NAME="zip" SIZE=11 MAXLENGTH=10 VALUE="<%$zip%>">
- </TD>
- </TR>
- </TABLE>
- </TD>
</TR>
+ <% include( '/elements/location.html',
+ 'object' => $cust_main, #XXX errors???
+ 'no_asterisks' => 1,
+ 'address1_label' => 'Card billing address',
+ )
+ %>
+
% } elsif ( $payby eq 'CHEK' ) {
%
% my( $payinfo1, $payinfo2, $payname, $ss, $paytype, $paystate,
@@ -270,16 +285,51 @@ my $balance = $cust_main->balance;
my $payinfo = '';
-#false laziness w/selfservice make_payment.html shortcut for one-country
my $conf = new FS::Conf;
+
+my $money_char = $conf->config('money_char') || '$';
+
+#false laziness w/selfservice make_payment.html shortcut for one-country
my %states = map { $_->state => 1 }
qsearch('cust_main_county', {
'country' => $conf->config('countrydefault') || 'US'
} );
my @states = sort { $a cmp $b } keys %states;
+my $fee = '';
+my $fee_pkg = '';
+my $fee_display = '';
+my $fee_op = '';
+my $num_payments = scalar($cust_main->cust_pay);
+#handle old cust_main.pm (remove...)
+$num_payments = scalar( @{ [ $cust_main->cust_pay ] } )
+ unless defined $num_payments;
+if ( $conf->config('manual_process-pkgpart')
+ and ! $conf->exists('manual_process-skip_first') || $num_payments
+ )
+{
+
+ $fee_display = $conf->config('manual_process-display') || 'add';
+ $fee_op = $fee_display eq 'add' ? '+' : '-';
+
+ $fee_pkg =
+ qsearchs('part_pkg', { pkgpart=>$conf->config('manual_process-pkgpart') } );
+
+ #well ->unit_setup or ->calc_setup both call for a $cust_pkg
+ # (though ->unit_setup doesn't use it...)
+ $fee = $fee_pkg->option('setup_fee')
+ if $fee_pkg; #in case.. better than dying with a perl traceback
+
+}
+
+my $amount = '';
+if ( $balance > 0 ) {
+ $amount = $balance;
+ $amount += $fee
+ if $fee && $fee_display eq 'subtract';
+ $amount = sprintf("%.2f", $amount);
+}
+
my $payunique = "webui-payment-". time. "-$$-". rand() * 2**32;
</%init>
-
-
diff --git a/httemplate/misc/ping.html b/httemplate/misc/ping.html
new file mode 100644
index 0000000..4f0360e
--- /dev/null
+++ b/httemplate/misc/ping.html
@@ -0,0 +1,102 @@
+<% include('/elements/header-popup.html', "Ping $ip" ) %>
+
+<% include('/elements/xmlhttp.html',
+ 'url' => $p. 'misc/xmlhttp-ping.html',
+ 'subs' => [ 'ping' ],
+ )
+%>
+
+%# <img src="<%$p%>images/bullet_red.png" border=0>
+
+
+<%ntable("#cccccc", 2)%>
+
+<TR>
+ <TD>Status</TD>
+ <TD BGCOLOR="#ffffff" ID="ping_status">Checking...</TD>
+</TR>
+<TR>
+ <TD>Packet loss</TD>
+ <TD BGCOLOR="#ffffff" ID="ping_packetloss"></TD>
+</TR>
+<TR>
+ <TD>Latency</TD>
+ <TD BGCOLOR="#ffffff" ID="ping_latency"></TD>
+</TR>
+<TR>
+ <TD>Packets</TD>
+ <TD BGCOLOR="#ffffff" ID="ping_packets"></TD>
+</TR>
+
+</TABLE>
+
+<BR>
+<CENTER>
+<INPUT TYPE="button" VALUE="Close" onClick="parent.nd(1);">
+</CENTER>
+
+<SCRIPT TYPE="text/javascript">
+
+ var fails = 0;
+ var pongs = 0;
+ var totaltime = 0;
+ var avg = 0;
+
+ function ping_update ( updatetext ) {
+ var pingArray = eval('(' + updatetext + ')');
+ var status = pingArray[0];
+ var rtt = pingArray[1];
+
+ if ( status == 0 ) {
+ fails++;
+ } else if ( status == 1 ) {
+ pongs++;
+ totaltime = totaltime + rtt;
+ avg = totaltime / pongs;
+ }
+
+ var loss = 100 * fails / ( fails + pongs );
+
+ var statusCell = document.getElementById('ping_status');
+ var packetlossCell = document.getElementById('ping_packetloss');
+ var latencyCell = document.getElementById('ping_latency');
+ var packetsCell = document.getElementById('ping_packets');
+
+ var status = '';
+ // red conditions
+ if ( loss == 100 ) {
+ status = '<FONT COLOR="#ff0000">Unreachable</FONT>';
+ } else
+ // yellow conditions
+ if ( loss > 50 ) {
+ status = '<FONT COLOR="#ff9900">High packet loss</FONT>';
+ } else
+ if ( avg > 1 ) {
+ status = '<FONT COLOR="#ff9900">High latency</FONT>';
+ } else {
+ status = '<FONT COLOR="#00cc00">Up</FONT>';
+ }
+
+ statusCell.innerHTML = '<B>' + status + '</B>';
+ packetlossCell.innerHTML = '<B>' + Math.round(loss) + '%</B>';
+ if ( avg > 0 ) {
+ latencyCell.innerHTML = '<B>' + Math.round( avg*1000 ) + 'ms</B>';
+ }
+ var packets = fails + pongs;
+ packetsCell.innerHTML = '<B>' + packets + '</B>';
+
+ setTimeout( "ping('<%$ip%>', ping_update)", 1000 );
+
+ }
+
+ ping( '<%$ip%>', ping_update );
+
+</SCRIPT>
+
+<%init>
+
+my($query) = $cgi->keywords;
+$query =~ /^([\d\.]+)$/ or die 'Illegal IP';
+my $ip = $1;
+
+</%init>
diff --git a/httemplate/misc/process/link.cgi b/httemplate/misc/process/link.cgi
index df15dca..77546f3 100755
--- a/httemplate/misc/process/link.cgi
+++ b/httemplate/misc/process/link.cgi
@@ -1,14 +1,20 @@
%unless ($error) {
% #no errors, so let's view this customer.
% my $custnum = $new->cust_pkg->custnum;
-<% $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum#cust_pkg$pkgnum" ) %>
+% my $show = $curuser->default_customer_view =~ /^(jumbo|packages)$/
+% ? ''
+% : ';show=packages';
+% my $frag = "cust_pkg$pkgnum"; #hack for IE ignoring real #fragment
+<% $cgi->redirect(popurl(3). "view/cust_main.cgi?custnum=$custnum$show;fragment=$frag#$frag" ) %>
%} else {
% errorpage($error);
%}
<%init>
+my $curuser = $FS::CurrentUser::CurrentUser;
+
die "access denied"
- unless $FS::CurrentUser::CurrentUser->access_right('View/link unlinked services');
+ unless $curuser->access_right('View/link unlinked services');
my $DEBUG = 0;
diff --git a/httemplate/misc/process/part_device-import.html b/httemplate/misc/process/part_device-import.html
new file mode 100644
index 0000000..eac111a
--- /dev/null
+++ b/httemplate/misc/process/part_device-import.html
@@ -0,0 +1,9 @@
+<% $server->process %>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Import');
+
+my $server = new FS::UI::Web::JSRPC 'FS::part_device::process_batch_import', $cgi;
+
+</%init>
diff --git a/httemplate/misc/process/payment.cgi b/httemplate/misc/process/payment.cgi
index 2baca1e..1e9501d 100644
--- a/httemplate/misc/process/payment.cgi
+++ b/httemplate/misc/process/payment.cgi
@@ -32,6 +32,11 @@ $cgi->param('amount') =~ /^\s*(\d*(\.\d\d)?)\s*$/
my $amount = $1;
errorpage("amount <= 0") unless $amount > 0;
+if ( $cgi->param('fee') =~ /^\s*(\d*(\.\d\d)?)\s*$/ ) {
+ my $fee = $1;
+ $amount = sprintf('%.2f', $amount + $fee);
+}
+
$cgi->param('year') =~ /^(\d+)$/
or errorpage("illegal year ". $cgi->param('year'));
my $year = $1;
@@ -44,7 +49,7 @@ $cgi->param('payby') =~ /^(CARD|CHEK)$/
or errorpage("illegal payby ". $cgi->param('payby'));
my $payby = $1;
my %payby2fields = (
- 'CARD' => [ qw( address1 address2 city state zip ) ],
+ 'CARD' => [ qw( address1 address2 city county state zip country ) ],
'CHEK' => [ qw( ss paytype paystate stateid stateid_state ) ],
);
my %type = ( 'CARD' => 'credit card',
@@ -143,6 +148,22 @@ if ( $cgi->param('batch') ) {
);
errorpage($error) if $error;
+ #no error, so order the fee package if applicable...
+ if ( $cgi->param('fee_pkgpart') =~ /^(\d+)$/ ) {
+
+ my $cust_pkg = new FS::cust_pkg { 'pkgpart' => $1 };
+
+ my $error = $cust_main->order_pkg( 'cust_pkg' => $cust_pkg );
+ errorpage("payment processed successfully, but error ordering fee: $error")
+ if $error;
+
+ #and generate an invoice for it now too
+ $error = $cust_main->bill( 'pkg_list' => [ $cust_pkg ] );
+ errorpage("payment processed and fee ordered sucessfully, but error billing fee: $error")
+ if $error;
+
+ }
+
$cust_main->apply_payments;
}
diff --git a/httemplate/misc/process/rate_edit_excel.html b/httemplate/misc/process/rate_edit_excel.html
new file mode 100644
index 0000000..acd5f49
--- /dev/null
+++ b/httemplate/misc/process/rate_edit_excel.html
@@ -0,0 +1,10 @@
+<% $server->process %>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+my $server = new FS::UI::Web::JSRPC 'FS::rate_detail::process_edit_import', $cgi;
+
+</%init>
+
diff --git a/httemplate/misc/process/recharge_svc.html b/httemplate/misc/process/recharge_svc.html
index 147b953..5f68bf1 100755
--- a/httemplate/misc/process/recharge_svc.html
+++ b/httemplate/misc/process/recharge_svc.html
@@ -1,62 +1,13 @@
-%unless ($error) {
-%
-% my ($amount, $seconds, $up, $down, $total) = (0, 0, 0, 0, 0);
-% #should probably use payby.pm but whatever
-% if ($payby eq 'PREP') {
-% $error = $cust_main->get_prepay($prepaid, \$amount, \$seconds, \$up, \$down, \$total)
-% || $svc_acct->increment_seconds($seconds)
-% || $svc_acct->increment_upbytes($up)
-% || $svc_acct->increment_downbytes($down)
-% || $svc_acct->increment_totalbytes($total)
-% || $cust_main->insert_cust_pay_prepay( $amount, $prepaid );
-% } elsif ( $payby =~ /^(CARD|DCRD|CHEK|DCHK|LECB|BILL|COMP)$/ ) {
-% my $part_pkg = $svc_acct->cust_svc->cust_pkg->part_pkg;
-% $amount = $part_pkg->option('recharge_amount', 1);
-% my %rhash = map { $_ =~ /^recharge_(.*)$/; $1, $part_pkg->option($_) }
-% grep { $part_pkg->option($_, 1) }
-% qw ( recharge_seconds recharge_upbytes recharge_downbytes
-% recharge_totalbytes );
-%
-% my $description = "Recharge";
-% $description .= " $rhash{seconds}s" if $rhash{seconds};
-% $description .= " $rhash{upbytes} up" if $rhash{upbytes};
-% $description .= " $rhash{downbytes} down" if $rhash{downbytes};
-% $description .= " $rhash{totalbytes} total" if $rhash{totalbytes};
-%
-% $error = $cust_main->charge($amount, "Recharge " . $svc_acct->label,
-% $description, $part_pkg->taxclass);
-%
-% if ($part_pkg->option('recharge_reset', 1)) {
-% $error ||= $svc_acct->set_usage(\%rhash);
-% }else{
-% $error ||= $svc_acct->recharge(\%rhash);
-% }
-%
-% my $old_balance = $cust_main->balance;
-% $error ||= $cust_main->bill;
-% $error ||= $cust_main->apply_payments_and_credits;
-% my $bill_error = $cust_main->collect('realtime' => 1) unless $error;
-% $error ||= "Failed to collect - $bill_error"
-% if $cust_main->balance > $old_balance && $cust_main->balance > 0
-% && $payby ne 'BILL';
-%
-% } else {
-% $error = "fatal error - unknown payby: $payby";
-% }
-%}
-%
%if ($error) {
% $cgi->param('error', $error);
-% $dbh->rollback if $oldAutoCommit;
-% print $cgi->redirect(popurl(2). "recharge_svc.html?". $cgi->query_string );
-%}
-%$dbh->commit or die $dbh->errstr if $oldAutoCommit;
-%
+<% $cgi->redirect(popurl(2). "recharge_svc.html?". $cgi->query_string ) %>
+%} else {
<% header("Package recharged") %>
<SCRIPT TYPE="text/javascript">
window.top.location.reload();
</SCRIPT>
</BODY></HTML>
+%}
<%init>
my $conf = new FS::Conf;
@@ -89,4 +40,52 @@ my $oldAutoCommit = $FS::UID::AutoCommit;
local $FS::UID::AutoCommit = 0;
my $dbh = dbh;
+unless ($error) {
+
+ #should probably use payby.pm but whatever
+ if ($payby eq 'PREP') {
+ $error = $cust_main->recharge_prepay( $prepaid );
+ } elsif ( $payby =~ /^(CARD|DCRD|CHEK|DCHK|LECB|BILL|COMP)$/ ) {
+ my $part_pkg = $svc_acct->cust_svc->cust_pkg->part_pkg;
+ my $amount = $part_pkg->option('recharge_amount', 1);
+ my %rhash = map { $_ =~ /^recharge_(.*)$/; $1, $part_pkg->option($_) }
+ grep { $part_pkg->option($_, 1) }
+ qw ( recharge_seconds recharge_upbytes recharge_downbytes
+ recharge_totalbytes );
+
+ my $description = "Recharge";
+ $description .= " $rhash{seconds}s" if $rhash{seconds};
+ $description .= " $rhash{upbytes} up" if $rhash{upbytes};
+ $description .= " $rhash{downbytes} down" if $rhash{downbytes};
+ $description .= " $rhash{totalbytes} total" if $rhash{totalbytes};
+
+ $error = $cust_main->charge($amount, "Recharge " . $svc_acct->label,
+ $description, $part_pkg->taxclass);
+
+ if ($part_pkg->option('recharge_reset', 1)) {
+ $error ||= $svc_acct->set_usage(\%rhash, 'null' => 1);
+ }else{
+ $error ||= $svc_acct->recharge(\%rhash);
+ }
+
+ my $old_balance = $cust_main->balance;
+ $error ||= $cust_main->bill;
+ $error ||= $cust_main->apply_payments_and_credits;
+ my $bill_error = $cust_main->collect('realtime' => 1) unless $error;
+ $error ||= "Failed to collect - $bill_error"
+ if $cust_main->balance > $old_balance && $cust_main->balance > 0
+ && $payby ne 'BILL';
+
+ } else {
+ $error = "fatal error - unknown payby: $payby";
+ }
+
+}
+
+if ($error) {
+ $dbh->rollback if $oldAutoCommit;
+} else {
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+}
+
</%init>
diff --git a/httemplate/misc/process/tax-fetch_and_import.cgi b/httemplate/misc/process/tax-fetch_and_import.cgi
new file mode 100644
index 0000000..553c755
--- /dev/null
+++ b/httemplate/misc/process/tax-fetch_and_import.cgi
@@ -0,0 +1,9 @@
+<% $server->process %>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+my $server = new FS::UI::Web::JSRPC 'FS::tax_rate::process_download_and_update', $cgi;
+
+</%init>
diff --git a/httemplate/misc/process/tax-fetch_and_replace.cgi b/httemplate/misc/process/tax-fetch_and_replace.cgi
new file mode 100644
index 0000000..1a9b626
--- /dev/null
+++ b/httemplate/misc/process/tax-fetch_and_replace.cgi
@@ -0,0 +1,9 @@
+<% $server->process %>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+my $server = new FS::UI::Web::JSRPC 'FS::tax_rate::process_download_and_reload', $cgi;
+
+</%init>
diff --git a/httemplate/misc/process/tax-import.cgi b/httemplate/misc/process/tax-import.cgi
index 016d4b6..f800dbd 100644
--- a/httemplate/misc/process/tax-import.cgi
+++ b/httemplate/misc/process/tax-import.cgi
@@ -2,7 +2,7 @@
<%init>
die "access denied"
- unless $FS::CurrentUser::CurrentUser->access_right('Resend invoices');
+ unless $FS::CurrentUser::CurrentUser->access_right('Import');
my $server = new FS::UI::Web::JSRPC 'FS::tax_rate::process_batch_import', $cgi;
diff --git a/httemplate/misc/rate_edit_excel.html b/httemplate/misc/rate_edit_excel.html
new file mode 100644
index 0000000..e73133c
--- /dev/null
+++ b/httemplate/misc/rate_edit_excel.html
@@ -0,0 +1,61 @@
+<% include('/elements/header.html', 'Edit rates with Excel' ) %>
+
+<% include( '/elements/form-file_upload.html',
+ 'name' => 'RateImportForm',
+ 'action' => 'process/rate_edit_excel.html',
+ 'num_files' => 1,
+ 'fields' => [ 'format' ],
+ 'message' => 'Rate edit successful',
+ 'url' => $p."browse/rate_region.html",
+ )
+%>
+
+<% &ntable("#cccccc", 2) %>
+
+ <TR>
+ <TH ALIGN="left">1. Download current rates:</TH>
+ <TD>
+ <A HREF="<%$p%>/browse/rate_region.html?show_rates=1;_type=regions.xls">Download rate spreadsheet</A>
+ </TD>
+ </TR>
+
+ <TR>
+ <TH ALIGN="left" COLSPAN=2>2. Edit rates with Excel (or other .XLS-compatible application)</TH>
+ </TR>
+
+ <TR>
+ <TD ALIGN="left" COLSPAN=2>
+ &nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;To add rates, add four columns like an existing rate, with headers starting with "NEW: Rate Name" or "Rate Name".<BR>
+ &nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;<FONT SIZE="-2"><I>For rate addition, protection can be turned off in Excel via the Tools-&gt;Protection-&gt;Unprotect Sheet menu command. Note that only new rates can be added; modified grayed out cells will not be imported.</I></FONT>
+ </TD>
+ </TR>
+
+ <% include( '/elements/file-upload.html',
+ 'field' => 'file',
+ 'label' => '3. Upload edited rate file: ',
+ 'label_align' => 'left',
+ )
+ %>
+
+ <INPUT TYPE="hidden" NAME="format" VALUE="default">
+
+ <TR>
+ <TD COLSPAN=2 ALIGN="center" STYLE="padding-top:6px">
+ <INPUT TYPE = "submit"
+ ID = "submit"
+ VALUE = "Upload"
+ onClick = "document.RateImportForm.submit.disabled=true;"
+ >
+ </TD>
+ </TR>
+
+
+</TABLE>
+
+<% include('/elements/footer.html') %>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+</%init>
diff --git a/httemplate/misc/send-invoice.cgi b/httemplate/misc/send-invoice.cgi
new file mode 100644
index 0000000..32dfe27
--- /dev/null
+++ b/httemplate/misc/send-invoice.cgi
@@ -0,0 +1,30 @@
+<% $cgi->redirect("${p}view/cust_main.cgi?$custnum") %>
+<%once>
+
+my %method = ( map { $_=>1 } qw( email print fax_invoice ) );
+
+</%once>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Resend invoices');
+
+my $invnum = $cgi->param('invnum');
+my $template = $cgi->param('template');
+my $notice_name = $cgi->param('notice_name') if $cgi->param('notice_name');
+my $method = $cgi->param('method');
+
+$method .= '_invoice' if $method eq 'fax'; #!
+
+die "unknown method $method" unless $method{$method};
+
+my $cust_bill = qsearchs('cust_bill',{'invnum'=>$invnum});
+die "Can't find invoice!\n" unless $cust_bill;
+
+$cust_bill->$method({ 'template' => $template,
+ 'notice_name' => $notice_name,
+ });
+
+my $custnum = $cust_bill->getfield('custnum');
+
+</%init>
diff --git a/httemplate/misc/send-statement.cgi b/httemplate/misc/send-statement.cgi
new file mode 100755
index 0000000..e363fbd
--- /dev/null
+++ b/httemplate/misc/send-statement.cgi
@@ -0,0 +1,28 @@
+<% $cgi->redirect("${p}view/cust_main.cgi?$custnum") %>
+<%once>
+
+my %method = map { $_=>1 } qw( email print fax_invoice );
+
+</%once>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Resend invoices');
+
+my $statementnum = $cgi->param('statementnum');
+my $template = $cgi->param('template') || 'statement'; #XXX configure... via event?? eh..
+my $notice_name = $cgi->param('notice_name') if $cgi->param('notice_name');
+my $method = $cgi->param('method');
+
+$method .= '_invoice' if $method eq 'fax'; #!
+
+die "unknown method $method" unless $method{$method};
+
+my $cust_statement = qsearchs('cust_statement',{'statementnum'=>$statementnum});
+die "Can't find statement!\n" unless $cust_statement;
+
+$cust_statement->$method({ 'template' => $template });
+
+my $custnum = $cust_statement->getfield('custnum');
+
+</%init>
diff --git a/httemplate/misc/states.cgi b/httemplate/misc/states.cgi
index cf2b46e..02b7be4 100644
--- a/httemplate/misc/states.cgi
+++ b/httemplate/misc/states.cgi
@@ -1,7 +1,7 @@
-%
-%
-% my $country = $cgi->param('arg');
-% my @output = states_hash($country);
-%
-%
[ <% join(', ', map { qq("$_") } @output) %> ]
+<%init>
+
+my $country = $cgi->param('arg');
+my @output = states_hash($country);
+
+</%init>
diff --git a/httemplate/misc/tax-fetch_and_import.cgi b/httemplate/misc/tax-fetch_and_import.cgi
new file mode 100644
index 0000000..33a6c9b
--- /dev/null
+++ b/httemplate/misc/tax-fetch_and_import.cgi
@@ -0,0 +1,48 @@
+<% include("/elements/header.html",'Tax Rate Download and Import') %>
+
+Import a tax data update.
+<BR><BR>
+
+<% include( '/elements/progress-init.html', 'TaxRateImport',[ 'format', ],
+ 'process/tax-fetch_and_import.cgi', { 'message' => 'Tax rates imported' },
+ )
+%>
+
+<FORM NAME="TaxRateImport" ACTION="javascript:void()" METHOD="POST">
+<% &ntable("#cccccc", 2) %>
+
+ <TR>
+ <TH ALIGN="right">Format</TH>
+ <TD>
+ <SELECT NAME="format">
+ <OPTION VALUE="cch">CCH import
+ </SELECT>
+ </TD>
+ </TR>
+ <TR>
+ <TH ALIGN="right">Update Password</TH>
+ <TD>
+ <INPUT TYPE="text" NAME="password">
+ </TD>
+ </TR>
+
+ <TR>
+ <TD COLSPAN=2 ALIGN="center" STYLE="padding-top:6px">
+ <INPUT TYPE = "submit"
+ VALUE = "Download and Import"
+ onClick = "document.TaxRateImport.submit.disabled=true; process();"
+ >
+ </TD>
+ </TR>
+
+</TABLE>
+
+</FORM>
+
+<% include('/elements/footer.html') %>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Import');
+
+</%init>
diff --git a/httemplate/misc/tax-fetch_and_replace.cgi b/httemplate/misc/tax-fetch_and_replace.cgi
new file mode 100644
index 0000000..3290a3c
--- /dev/null
+++ b/httemplate/misc/tax-fetch_and_replace.cgi
@@ -0,0 +1,48 @@
+<% include("/elements/header.html",'Tax Rate Download and Import') %>
+
+Replace tax data.
+<BR><BR>
+
+<% include( '/elements/progress-init.html', 'TaxRateImport',[ 'format', ],
+ 'process/tax-fetch_and_replace.cgi', { 'message' => 'Tax rates replaced' },
+ )
+%>
+
+<FORM NAME="TaxRateImport" ACTION="javascript:void()" METHOD="POST">
+<% &ntable("#cccccc", 2) %>
+
+ <TR>
+ <TH ALIGN="right">Format</TH>
+ <TD>
+ <SELECT NAME="format">
+ <OPTION VALUE="cch">CCH import
+ </SELECT>
+ </TD>
+ </TR>
+ <TR>
+ <TH ALIGN="right">Update Password</TH>
+ <TD>
+ <INPUT TYPE="text" NAME="password">
+ </TD>
+ </TR>
+
+ <TR>
+ <TD COLSPAN=2 ALIGN="center" STYLE="padding-top:6px">
+ <INPUT TYPE = "submit"
+ VALUE = "Download and Import"
+ onClick = "document.TaxRateImport.submit.disabled=true; process();"
+ >
+ </TD>
+ </TR>
+
+</TABLE>
+
+</FORM>
+
+<% include('/elements/footer.html') %>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Import');
+
+</%init>
diff --git a/httemplate/misc/tax-import.cgi b/httemplate/misc/tax-import.cgi
index a695e97..5116e54 100644
--- a/httemplate/misc/tax-import.cgi
+++ b/httemplate/misc/tax-import.cgi
@@ -6,7 +6,7 @@ Import a CSV file set containing tax rate records.
<% include( '/elements/form-file_upload.html',
'name' => 'TaxRateUpload',
'action' => 'process/tax-import.cgi',
- 'num_files' => 5,
+ 'num_files' => 6,
'fields' => [ 'format', ],
'message' => 'Tax rates imported',
)
@@ -27,13 +27,15 @@ Import a CSV file set containing tax rate records.
</TR>
<% include( '/elements/file-upload.html',
- 'field' => [ 'codefile',
+ 'field' => [ 'geofile',
+ 'codefile',
'plus4file',
'zipfile',
'txmatrix',
'detail',
],
- 'label' => [ 'code filename',
+ 'label' => [ 'geocode filename',
+ 'code filename',
'plus4 filename',
'zip filename',
'txmatrix filename',
diff --git a/httemplate/misc/xmlhttp-cust_main-address_standardize.html b/httemplate/misc/xmlhttp-cust_main-address_standardize.html
index 72fa4a4..3b9e142 100644
--- a/httemplate/misc/xmlhttp-cust_main-address_standardize.html
+++ b/httemplate/misc/xmlhttp-cust_main-address_standardize.html
@@ -50,6 +50,9 @@ if ( $sub eq 'address_standardize' ) {
unless ( $verifier->is_error ) {
+ my $zip = $hash->{Zip5};
+ $zip .= '-'. $hash->{Zip4} if $hash->{Zip4} =~ /\d/;
+
$return = {
%$return,
"new_$pre".'company' => $hash->{FirmName},
@@ -57,7 +60,7 @@ if ( $sub eq 'address_standardize' ) {
"new_$pre".'address2' => $hash->{Address1},
"new_$pre".'city' => $hash->{City},
"new_$pre".'state' => $hash->{State},
- "new_$pre".'zip' => $hash->{Zip5}. '-'. $hash->{Zip4},
+ "new_$pre".'zip' => $zip,
};
my @fields = (qw( company address1 address2 city state zip )); #hmm
diff --git a/httemplate/misc/xmlhttp-cust_main-censustract.html b/httemplate/misc/xmlhttp-cust_main-censustract.html
new file mode 100644
index 0000000..9d588d7
--- /dev/null
+++ b/httemplate/misc/xmlhttp-cust_main-censustract.html
@@ -0,0 +1,105 @@
+<% objToJson($return) %>
+<%init>
+
+my $DEBUG = 0;
+
+my $url='http://www.ffiec.gov/Geocode/default.aspx';
+
+my $sub = $cgi->param('sub');
+
+my $return = {};
+my $error = '';
+
+use LWP::UserAgent;
+use HTTP::Request;
+use HTTP::Request::Common qw( GET POST );
+use HTML::TokeParser;
+
+if ( $sub eq 'censustract' ) {
+
+ my %arg = $cgi->param('arg');
+ warn join('', map "$_: $arg{$_}\n", keys %arg )
+ if $DEBUG;
+
+ my $ua = new LWP::UserAgent;
+ my $res = $ua->request( GET( $url ) );
+
+ warn $res->as_string
+ if $DEBUG > 1;
+
+ unless ($res->code eq '200') {
+
+ $error = $res->message;
+
+ } else {
+
+ my $content = $res->content;
+ my $p = new HTML::TokeParser \$content;
+ my $viewstate;
+ while (my $token = $p->get_tag('input') ) {
+ next unless $token->[1]->{name} eq '__VIEWSTATE';
+ $viewstate = $token->[1]->{value};
+ last;
+ }
+
+ unless ($viewstate) {
+
+ $error = "no __VIEWSTATE found";
+
+ } else {
+
+ my($zip5, $zip4) = split('-',$arg{zip});
+
+ my @ffiec_args = (
+ __VIEWSTATE => $viewstate,
+ ddlbYear => $arg{year},
+ txtAddress => $arg{address},
+ txtCity => $arg{city},
+ ddlbState => $arg{state},
+ txtZipCode => $zip5,
+ btnSearch => 'Search',
+ );
+ warn join("\n", @ffiec_args )
+ if $DEBUG;
+
+ $res = $ua->request( POST( $url, \@ffiec_args ) );
+ warn $res->as_string
+ if $DEBUG > 1;
+
+ unless ($res->code eq '200') {
+
+ $error = $res->message;
+
+ } else {
+
+ my @id = qw( MSACode StateCode CountyCode TractCode );
+ $content = $res->content;
+ $p = new HTML::TokeParser \$content;
+ my $prefix = 'UcGeoResult11_lb';
+ my $compare =
+ sub { my $t=shift; scalar( grep { lc($t) eq lc("$prefix$_")} @id ) };
+
+ while (my $token = $p->get_tag('span') ) {
+ next unless ( $token->[1]->{id} && &$compare( $token->[1]->{id} ) );
+ $token->[1]->{id} =~ /^$prefix(\w+)$/;
+ $return->{lc($1)} = $p->get_trimmed_text("/span");
+ }
+
+ $error = "No census tract found" unless $return->{tractcode};
+ $return->{tractcode} .= ' '
+ unless $error || $JSON::VERSION >= 2; #broken JSON 1 workaround
+
+ } #unless ($res->code eq '200')
+
+ } #unless ($viewstate)
+
+ } #unless ($res->code eq '200')
+
+ $error = "FFIEC Geocoding error: $error" if $error;
+ $return->{'error'} = $error;
+
+ $return;
+
+}
+
+</%init>
diff --git a/httemplate/misc/xmlhttp-ping.html b/httemplate/misc/xmlhttp-ping.html
new file mode 100644
index 0000000..e993032
--- /dev/null
+++ b/httemplate/misc/xmlhttp-ping.html
@@ -0,0 +1,20 @@
+<% objToJson($return) %>
+<%init>
+
+my $conf = new FS::Conf;
+
+my $sub = $cgi->param('sub');
+
+die "$sub not supported" unless $sub eq 'ping';
+
+my $ip = $cgi->param('arg');
+
+my $ping = new Net::Ping('external', 5);
+$ping->hires(1);
+#my $a=time; warn "pinging\n";
+my ($ret, $duration, $ip2) = $ping->ping($ip);
+#warn "done pinging (". int(time-$a). "s)\n";
+
+my $return = [ $ret, $duration ];
+
+</%init>