diff options
Diffstat (limited to 'httemplate/misc')
119 files changed, 5782 insertions, 0 deletions
| diff --git a/httemplate/misc/areacodes.cgi b/httemplate/misc/areacodes.cgi new file mode 100644 index 000000000..69c9573c3 --- /dev/null +++ b/httemplate/misc/areacodes.cgi @@ -0,0 +1,24 @@ +%# [ <% join(', ', map { qq("$_") } @areacodes) %> ] +<% objToJson(\@areacodes) %> +<%init> + +my( $state, $svcpart ) = $cgi->param('arg'); + +my $part_svc = qsearchs('part_svc', { 'svcpart'=>$svcpart } ); +die "unknown svcpart $svcpart" unless $part_svc; + +my @exports = $part_svc->part_export_did; +if ( scalar(@exports) > 1 ) { +  die "more than one DID-providing export attached to svcpart $svcpart"; +} elsif ( ! @exports ) { +  die "no DID providing export attached to svcpart $svcpart"; +} +my $export = $exports[0]; + +my $something = $export->get_dids('state'=>$state); + +#warn Dumper($something); + +my @areacodes = @{ $something }; + +</%init> diff --git a/httemplate/misc/batch-cust_pay.html b/httemplate/misc/batch-cust_pay.html new file mode 100644 index 000000000..e10a5f658 --- /dev/null +++ b/httemplate/misc/batch-cust_pay.html @@ -0,0 +1,38 @@ +<% include('/elements/header.html', 'Quick payment entry') %> + +<% include('/elements/error.html') %> + +<FORM ACTION="process/batch-cust_pay.cgi" NAME="OneTrueForm" METHOD="POST" onsubmit="document.OneTrueForm.submit.disabled=true;"> + +<!-- <B>Batch</B> <INPUT TYPE="text" NAME="paybatch"><BR><BR> --> + +<% include( "/elements/customer-table.html", +              name_singular => 'payment', +              header  => [ '', 'Amount', 'Check #', '' ], +              fields  => [ sub {'$'}, 'paid', 'payinfo', 'error', ], +              types   => [ 'immutable', '', '', 'immutable', ], +              align   => [ 'c', 'r', 'r', 'l' ], +              sizes   => [ 0, 8, 10, 0, ], +              colors  => [ '', '', '', '#ff0000' ], +              param   => { () }, +              footer  => [ '$', '_TOTAL', '', '' ], +              footer_align => [ 'c', 'r', 'r', '' ], +          ) +%> + +<!-- <BR> +<INPUT TYPE="button" VALUE="TEST addrow" onclick="addRow()"> --> + +<BR> +<INPUT TYPE="submit" NAME="submit" VALUE="Post payment batch"> + +</FORM> + +<% include('/elements/footer.html') %> + +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Post payment batch'); + +</%init> diff --git a/httemplate/misc/bill.cgi b/httemplate/misc/bill.cgi new file mode 100755 index 000000000..3c3c48c54 --- /dev/null +++ b/httemplate/misc/bill.cgi @@ -0,0 +1,45 @@ +%if ( $error ) { +%  errorpage($error); +%} else { +<% $cgi->redirect(popurl(2). "view/cust_main.cgi?$custnum") %> +%} +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Bill customer now'); + +#untaint custnum +my($query) = $cgi->keywords; +$query =~ /^(\d*)$/; +my $custnum = $1; +my $cust_main = qsearchs('cust_main',{'custnum'=>$custnum}); +die "Can't find customer!\n" unless $cust_main; + +my $conf = new FS::Conf; + +my $error = $cust_main->bill( +#                          'time'=>$time +                         ); + +unless ( $error ) { +  $error = $cust_main->apply_payments_and_credits +           || $cust_main->collect( +                                  #'invoice-time'=>$time, +                                  #'batch_card'=> 'yes', +                                  #'batch_card'=> 'no', +                                  #'report_badcard'=> 'yes', +                                  #'retry_card' => 'yes', + +                                  'retry' => 'yes', +                                    +                                  #this is used only by cust_main::batch_card +                                  #need to pick & create an actual config +                                  #value if we're going to turn this on +                                  #("realtime-backend" doesn't exist, +                                  # "backend-realtime" is for something +                                  #  entirely different) +                                  #'realtime' => $conf->exists('realtime-backend'), +                                 ); +} + +</%init> diff --git a/httemplate/misc/bulk_change_pkg.cgi b/httemplate/misc/bulk_change_pkg.cgi new file mode 100755 index 000000000..4964e598f --- /dev/null +++ b/httemplate/misc/bulk_change_pkg.cgi @@ -0,0 +1,62 @@ +<% include('/elements/header-popup.html', "Change Packages") %> + +% if ( $cgi->param('error') ) { +  <FONT SIZE="+1" COLOR="#ff0000">Error: <% $cgi->param('error') %></FONT> +  <BR><BR> +% } + +<FORM ACTION="<% $p %>misc/process/bulk_change_pkg.cgi" METHOD=POST> + +%# some false laziness w/search/cust_pkg.cgi + +<INPUT TYPE="hidden" NAME="query" VALUE="<% $cgi->keywords |h %>"> +%  for my $param (qw(agentnum custnum 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") |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') %> + +  <TR> +    <TD>New package: </TD> +    <TD><% include('/elements/select-table.html', +                     'table'          => 'part_pkg', +                     'name_col'       => 'pkg', +                     'empty_label'    => 'Select package', +                     'label_callback' => sub { $_[0]->pkg_comment }, +                     'element_name'   => 'new_pkgpart', +                     'curr_value'     => ( $cgi->param('error') +                                           ? scalar($cgi->param('new_pkgpart')) +                                           : '' +                                         ), +                  ) +        %> +    </TD> +  </TR> + +</TABLE> + +<BR> +<INPUT TYPE="submit" VALUE="Change packages"> + +</FORM> +</BODY> +</HTML> + +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Bulk change customer packages'); + +</%init> diff --git a/httemplate/misc/cancel-unaudited.cgi b/httemplate/misc/cancel-unaudited.cgi new file mode 100755 index 000000000..4919c6632 --- /dev/null +++ b/httemplate/misc/cancel-unaudited.cgi @@ -0,0 +1,33 @@ +%if ( $error ) { +%  errorpage($error); +%} else { +<% $cgi->redirect(popurl(2)) %> +%} + +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Unprovision customer service') +      && $FS::CurrentUser::CurrentUser->access_right('View/link unlinked services'); + +#untaint svcnum +my($query) = $cgi->keywords; +$query =~ /^(\d+)$/; +my $svcnum = $1; + +#my $svc_acct = qsearchs('svc_acct',{'svcnum'=>$svcnum}); +#die "Unknown svcnum!" unless $svc_acct; + +my $cust_svc = qsearchs('cust_svc',{'svcnum'=>$svcnum}); +die "Unknown svcnum!" unless $cust_svc; +my $cust_pkg = $cust_svc->cust_pkg; +if ( $cust_pkg ) { +  errorpage( 'This account has already been audited.  Cancel the '. +           qq!<A HREF="${p}view/cust_main.cgi?!. $cust_pkg->custnum. +           '#cust_pkg'. $cust_pkg->pkgnum. '">'. +           'package</A> instead.'); +} + +my $error = $cust_svc->cancel; + +</%init> diff --git a/httemplate/misc/cancel_cust.html b/httemplate/misc/cancel_cust.html new file mode 100644 index 000000000..12c37ebe2 --- /dev/null +++ b/httemplate/misc/cancel_cust.html @@ -0,0 +1,63 @@ +<% include('/elements/header-popup.html', 'Cancel customer' ) %> + +<% include('/elements/error.html') %> + +<FORM NAME="cust_cancel_popup" ACTION="<% popurl(1) %>cust_main-cancel.cgi" METHOD=POST> +<INPUT TYPE="hidden" NAME="custnum" VALUE="<% $custnum %>"> + + + <P ALIGN="center"><B>Permanently delete all services and cancel this customer?</B> + + <% $ban %> +  +<BR><BR> + +<% ntable("#cccccc", 2) %> + +<% include('/elements/tr-select-reason.html', +             'field'          => 'reasonnum', +             'reason_class'   => 'C', +             'cgi'            => $cgi, +             'control_button' => "document.getElementById('confirm_cancel_cust_button')", +          ) +%> + +</TABLE> + +<BR> +<P ALIGN="CENTER"> +<INPUT TYPE="submit" NAME="submit" ID="confirm_cancel_cust_button" VALUE="Cancel customer" DISABLED>         <INPUT TYPE="BUTTON" VALUE="Don't cancel" onClick="parent.cClick();">  + +</FORM> +</BODY> +</HTML> + +<%init> + +$cgi->param('custnum') =~ /^(\d+)$/ or die 'illegal custnum'; +my $custnum = $1; + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" unless $curuser->access_right('Cancel customer'); + +my $cust_main = qsearchs( { +  'table'     => 'cust_main', +  'hashref'   => { 'custnum' => $custnum }, +  'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, +} ); +die "No customer # $custnum" unless $cust_main; + +my $ban = ''; +if ( $cust_main->payby =~ /^(CARD|DCRD|CHEK|DCHK)$/ ) { +  $ban = '<BR><P ALIGN="center">'. +         '<INPUT TYPE="checkbox" NAME="ban" VALUE="1"> Ban this customer\'s '; +  if ( $cust_main->payby =~ /^(CARD|DCRD)$/ ) { +    $ban .= 'credit card'; +  } elsif (  $cust_main->payby =~ /^(CHEK|DCHK)$/ ) { +    $ban .= 'ACH account'; +  } +} + +</%init> + diff --git a/httemplate/misc/cancel_pkg.html b/httemplate/misc/cancel_pkg.html new file mode 100755 index 000000000..607ce13c4 --- /dev/null +++ b/httemplate/misc/cancel_pkg.html @@ -0,0 +1,109 @@ +%# if ( $link eq 'popup' ) {  +  <% include('/elements/header-popup.html', $title ) %> +%# } else {  +%#  <%  include("/elements/header.html", $title, '') %> +%# }  + +<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> + +<% include('/elements/error.html') %> + +<FORM NAME="sc_popup" ACTION="<% popurl(1) %>process/cancel_pkg.html" METHOD=POST> +<INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $pkgnum %>"> +<INPUT TYPE="hidden" NAME="method" VALUE="<% $method %>"> + + +<BR><BR> +<% ucfirst($method) %> <% $part_pkg->pkg_comment %> +<% ntable("#cccccc", 2) %> + +% if ($method eq 'expire' || $method eq 'adjourn') { +<TR> +  <TD><% $submit =~ /^(\w*)\s/ %> package on </TD> +    <TD><INPUT TYPE="text" NAME="date" ID="expire_date" VALUE="<% $date |h %>"> +        <IMG SRC="<% $p %>images/calendar.png" ID="expire_button" STYLE="cursor:pointer" TITLE="Select date"> +        <BR><I>m/d/y</I> +    </TD> +</TR> +<SCRIPT TYPE="text/javascript"> +  Calendar.setup({ +    inputField: "expire_date", +    ifFormat:   "%m/%d/%Y", +    button:     "expire_button", +    align:      "BR" +  }); +</SCRIPT> +%} +% + +<% include('/elements/tr-select-reason.html', +             'field'          => 'reasonnum', +             'reason_class'   => $class, +             'curr_value'     => $reasonnum, +             'control_button' => "document.getElementById('confirm_cancel_pkg_button')", +          ) +%> + +</TABLE> + +<BR> +<INPUT TYPE="submit" NAME="submit" ID="confirm_cancel_pkg_button" VALUE="<% $submit %>" DISABLED> + +</FORM> +</BODY> +</HTML> + +<%init> + +my $date = time2str("%m/%d/%Y", time); + +my($pkgnum, $reasonnum); +if ( $cgi->param('error') ) { +  $pkgnum    = $cgi->param('pkgnum'); +  $reasonnum = $cgi->param('reasonnum'); +  $date      = $cgi->param('date'); +} elsif ( $cgi->param('pkgnum') =~ /^(\d+)$/ ) { +  $pkgnum    = $1; +  $reasonnum = ''; +} else { +  die "illegal query ". $cgi->keywords; +} + +$cgi->param('method') =~ /^(\w+)$/ or die 'illegal method'; +my $method = $1; + +my($class, $submit, $right); +if ($method eq 'cancel') { +  $class  = 'C'; +  $submit = 'Cancel Now'; +  $right  = 'Cancel customer package immediately'; +} elsif ($method eq 'expire') { +  $class  = 'C'; +  $submit = 'Cancel Later'; +  $right  = 'Cancel customer package later'; +} elsif ($method eq 'suspend') { +  $class  = 'S'; +  $submit = 'Suspend Now'; +  $right  = 'Suspend customer package'; +} elsif ($method eq 'adjourn') { +  $class  = 'S'; +  $submit = "Suspend Later"; +  $right  = 'Suspend customer package later'; +} else { +  die 'illegal query (unknown method param)'; +} + +my $curuser = $FS::CurrentUser::CurrentUser; +die "access denied" unless $curuser->access_right($right); + +my $title = ucfirst($method) . ' Package'; + +my $cust_pkg = qsearchs('cust_pkg', {'pkgnum' => $pkgnum}) +  or die "Unknown pkgnum: $pkgnum"; + +my $part_pkg = $cust_pkg->part_pkg; + +</%init> diff --git a/httemplate/misc/catchall.cgi b/httemplate/misc/catchall.cgi new file mode 100755 index 000000000..240f34d0e --- /dev/null +++ b/httemplate/misc/catchall.cgi @@ -0,0 +1,118 @@ +<% include('/elements/header.html', 'Domain Catchall Edit') %> + +<% include('/elements/error.html') %> + +<FORM ACTION="<%$p1%>process/catchall.cgi" METHOD=POST> + +<INPUT TYPE="hidden" NAME="svcnum" VALUE="<% $svcnum |h %>"> +Service #<FONT SIZE=+1><B><% $svcnum ? $svcnum : ' (NEW)' |h %></B></FONT> +<BR><BR> + +<INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $pkgnum |h %>"> + +<INPUT TYPE="hidden" NAME="svcpart" VALUE="<% $svcpart %>"> + +% my $domain   = $svc_domain->domain; +% my $catchall = $svc_domain->catchall; + +<INPUT TYPE="hidden" NAME="domain" VALUE="<% $domain |h %>"> + +Mail to <I>(anything)</I>@<B><% $domain |h %></B> forwards to <SELECT NAME="catchall" SIZE=1> +% foreach $_ (keys %email) { +    <OPTION<% $_ eq $catchall ? ' SELECTED' : '' %> VALUE="<% $_ %>"><% $email{$_} %> +% } +</SELECT> +<BR><BR> + +<INPUT TYPE="submit" VALUE="Submit"> + +</FORM> + +<% include('/elements/footer.html') %> + +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Edit domain catchall'); + +my $conf = new FS::Conf; + +my($svc_domain, $svcnum, $pkgnum, $svcpart, $part_svc); +if ( $cgi->param('error') ) { +  $svc_domain = new FS::svc_domain ( { +    map { $_, scalar($cgi->param($_)) } fields('svc_domain') +  } ); +  $svcnum = $svc_domain->svcnum; +  $pkgnum = $cgi->param('pkgnum'); +  $svcpart = $cgi->param('svcpart'); +  $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart}); +  die "No part_svc entry!" unless $part_svc; +} else { +  my($query) = $cgi->keywords; +  if ( $query =~ /^(\d+)$/ ) { #editing +    $svcnum=$1; +    $svc_domain=qsearchs('svc_domain',{'svcnum'=>$svcnum}) +      or die "Unknown (svc_domain) svcnum!"; + +    my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum}) +      or die "Unknown (cust_svc) svcnum!"; + +    $pkgnum=$cust_svc->pkgnum; +    $svcpart=$cust_svc->svcpart; +   +    $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart}); +    die "No part_svc entry!" unless $part_svc; + +  } else {  + +    die "Invalid (svc_domain) svcnum!"; + +  } +} + +my %email; +if ($pkgnum) { + +  #find all possible user svcnums (and emails) + +  #starting with that currently attached +  if ($svc_domain->catchall) { +    my($svc_acct)=qsearchs('svc_acct',{'svcnum'=>$svc_domain->catchall}); +    $email{$svc_domain->catchall} = $svc_acct->email; +  } + +  #and including the rest for this customer +  my($u_part_svc,@u_acct_svcparts); +  foreach $u_part_svc ( qsearch('part_svc',{'svcdb'=>'svc_acct'}) ) { +    push @u_acct_svcparts,$u_part_svc->getfield('svcpart'); +  } + +  my($cust_pkg)=qsearchs('cust_pkg',{'pkgnum'=>$pkgnum}); +  my($custnum)=$cust_pkg->getfield('custnum'); +  my($i_cust_pkg); +  foreach $i_cust_pkg ( qsearch('cust_pkg',{'custnum'=>$custnum}) ) { +    my($cust_pkgnum)=$i_cust_pkg->getfield('pkgnum'); +    my($acct_svcpart); +    foreach $acct_svcpart (@u_acct_svcparts) {   #now find the corresponding  +                                              #record(s) in cust_svc ( for this +                                              #pkgnum ! ) +      my($i_cust_svc); +      foreach $i_cust_svc ( qsearch('cust_svc',{'pkgnum'=>$cust_pkgnum,'svcpart'=>$acct_svcpart}) ) { +        my($svc_acct)=qsearchs('svc_acct',{'svcnum'=>$i_cust_svc->getfield('svcnum')}); +        $email{$svc_acct->getfield('svcnum')}=$svc_acct->email; +      }   +    } +  } + +} else { + +  my($svc_acct)=qsearchs('svc_acct',{'svcnum'=>$svc_domain->catchall}); +  $email{$svc_domain->catchall} = $svc_acct->email; +} + +# add an absence of a catchall +$email{''} = "(none)"; + +my $p1 = popurl(1); + +</%init> diff --git a/httemplate/misc/cdr-import.html b/httemplate/misc/cdr-import.html new file mode 100644 index 000000000..7af6c521f --- /dev/null +++ b/httemplate/misc/cdr-import.html @@ -0,0 +1,61 @@ +<% include("/elements/header.html",'Call Detail Record Import') %> +   +<% include( '/elements/form-file_upload.html', +              'name'      => 'CDRImportForm', +              'action'    => 'process/cdr-import.html', +              'num_files' => 1, +              'fields'    => [ 'format', 'cdrbatch', ], +              'message'   => 'CDR import successful', +              'url'       => $p."search/cdr.html?cdrbatch=$cdrbatch", +          ) +%> + +Import a file containing Call Detail Records (CDRs).<BR><BR> + +<INPUT TYPE="hidden" NAME="cdrbatch" VALUE="<% $cdrbatch %>"%> + +<% ntable('#cccccc', 2) %> + +  <TR> +    <TD>CDR Format</TD> +    <TD> +      <SELECT NAME="format"> +%       foreach my $format ( keys %formats ) { +         <OPTION VALUE="<% $format %>"><% $formats{$format} %></OPTION> +%       } +      </SELECT> +    </TD> +  </TR> + +  <% 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.InventoryItemImportForm.submit.disabled=true;" +      > +    </TD> +  </TR> + +</TABLE> + +</FORM> + +<% include('/elements/footer.html') %> + +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Import'); + +tie my %formats, 'Tie::IxHash', FS::cdr->import_formats; + +my $cdrbatch = time2str('webimport-%Y/%m/%d-%T'. "-$$-". rand() * 2**32, time); + +</%init> diff --git a/httemplate/misc/cdr.cgi b/httemplate/misc/cdr.cgi new file mode 100644 index 000000000..d2ee77364 --- /dev/null +++ b/httemplate/misc/cdr.cgi @@ -0,0 +1,48 @@ +%# <% $cgi->redirect(popurl(2). "search/cdr.html") %> +%# i should be a popup and reload my parent... until then, this will do +<% include('/elements/header.html','CDR update successful') %>  +<% include('/elements/footer.html') %>  +<%init>  +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Edit rating data'); + +$cgi->param('action') =~ /^(new|del|(reprocess|delete) selected)$/ +  or die "Illegal action"; +my $action = $1; + +my $cdr; +if ( $action eq 'new' || $action eq 'del' ) { +  $cgi->param('acctid') =~ /^(\d+)$/ or die "Illegal acctid"; +  my $acctid = $1; +  $cdr = qsearchs('cdr', { 'acctid' => $1 }) +    or die "unknown acctid $acctid"; +} + +if ( $action eq 'new' ) { +  my %hash = $cdr->hash; +  $hash{'freesidestatus'} = ''; +  my $new = new FS::cdr \%hash; +  my $error = $new->replace($cdr); +  die $error if $error; +} elsif ( $action eq 'del' ) { +  my $error = $cdr->delete; +  die $error if $error; +} elsif ( $action =~ /^(reprocess|delete) selected$/ ) { +  foreach my $acctid ( +    map { /^acctid(\d+)$/; $1; } grep /^acctid\d+$/, $cgi->param +  ) { +    my $cdr = qsearchs('cdr', { 'acctid' => $acctid }); +    if ( $action eq 'reprocess selected' && $cdr ) { #new +      my %hash = $cdr->hash; +      $hash{'freesidestatus'} = ''; +      my $new = new FS::cdr \%hash; +      my $error = $new->replace($cdr); +      die $error if $error; +    } elsif ( $action eq 'delete selected' && $cdr ) { #del +      my $error = $cdr->delete; +      die $error if $error; +    } +  } +} + +</%init> diff --git a/httemplate/misc/change_pkg.cgi b/httemplate/misc/change_pkg.cgi new file mode 100755 index 000000000..16b707121 --- /dev/null +++ b/httemplate/misc/change_pkg.cgi @@ -0,0 +1,68 @@ +<% include('/elements/header-popup.html', "Change Package") %> + +<% include('/elements/error.html') %> + +<FORM ACTION="<% $p %>edit/process/change-cust_pkg.html" METHOD=POST> +<INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $pkgnum %>"> + +<% ntable('#cccccc') %> + +  <TR> +    <TH ALIGN="right">Current package</TH> +    <TD COLSPAN=7> +      <% $curuser->option('show_pkgnum') ? $cust_pkg->pkgnum.': ' : '' %><B><% $part_pkg->pkg |h %></B> - <% $part_pkg->comment |h %> +    </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, +               'cust_main' => $cust_main, +            ) +  %> + +</TABLE> + +<BR> +<INPUT TYPE="submit" VALUE="Change package"> + +</FORM> +</BODY> +</HTML> + +<%init> + +my $conf = new FS::Conf; + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" +  unless $curuser->access_right('Change customer package'); + +my $pkgnum = scalar($cgi->param('pkgnum')); +$pkgnum =~ /^(\d+)$/ or die "illegal pkgnum $pkgnum"; +$pkgnum = $1; + +my $cust_pkg = +  qsearchs({ +    'table'     => 'cust_pkg', +    'addl_from' => 'LEFT JOIN cust_main USING ( custnum )', +    'hashref'   => { 'pkgnum' => $pkgnum }, +    'extra_sql' => ' AND '. $curuser->agentnums_sql, +  }) or die "unknown pkgnum $pkgnum"; + +my $cust_main = $cust_pkg->cust_main +  or die "can't get cust_main record for custnum ". $cust_pkg->custnum. +         " ( pkgnum ". cust_pkg->pkgnum. ")"; + +my $part_pkg = $cust_pkg->part_pkg; + +</%init> diff --git a/httemplate/misc/cities.cgi b/httemplate/misc/cities.cgi new file mode 100644 index 000000000..c92485ee4 --- /dev/null +++ b/httemplate/misc/cities.cgi @@ -0,0 +1,7 @@ +[ <% join(', ', map { qq("$_") } @cities) %> ] +<%init> + +my( $county, $state, $country ) = $cgi->param('arg'); +my @cities = cities($county, $state, $country); + +</%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/counties.cgi b/httemplate/misc/counties.cgi new file mode 100644 index 000000000..c022a27d9 --- /dev/null +++ b/httemplate/misc/counties.cgi @@ -0,0 +1,7 @@ +[ <% join(', ', map { qq("$_") } @counties) %> ] +<%init> + +my( $state, $country ) = $cgi->param('arg'); +my @counties = counties($state, $country); + +</%init> diff --git a/httemplate/misc/cust-part_pkg.cgi b/httemplate/misc/cust-part_pkg.cgi new file mode 100644 index 000000000..a249f033f --- /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_attachment.cgi b/httemplate/misc/cust_attachment.cgi new file mode 100644 index 000000000..d1ec777d8 --- /dev/null +++ b/httemplate/misc/cust_attachment.cgi @@ -0,0 +1,34 @@ +<% '',$cgi->redirect(popurl(2). "browse/cust_attachment.html?$browse_opts") %> +<%init> + +$cgi->param('action') =~ /^(Delete|Undelete|Purge) selected$/ +  or die "Illegal action"; +my $action = $1; + +my $browse_opts = join(';', map { $_.'='.$cgi->param($_) }  +    qw( orderby show_deleted ) +    ); + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right("$action attachment"); + +foreach my $attachnum ( +    map { /^attachnum(\d+)$/; $1; } grep /^attachnum\d+$/, $cgi->param +  ) { +  my $attach = qsearchs('cust_attachment', { 'attachnum' => $attachnum }); +  my $error; +  if ( $action eq 'Delete' and !$attach->disabled ) { +    $attach->disabled(time); +    $error = $attach->replace; +  } +  elsif ( $action eq 'Undelete' and $attach->disabled ) { +    $attach->disabled(''); +    $error = $attach->replace; +  } +  elsif ( $action eq 'Purge' and $attach->disabled ) { +    $error = $attach->delete; +  } +  die $error if $error; +} + +</%init> diff --git a/httemplate/misc/cust_main-cancel.cgi b/httemplate/misc/cust_main-cancel.cgi new file mode 100755 index 000000000..009a7d41b --- /dev/null +++ b/httemplate/misc/cust_main-cancel.cgi @@ -0,0 +1,57 @@ +<% header("Customer cancelled") %> +  <SCRIPT TYPE="text/javascript"> +    window.top.location.reload(); +  </SCRIPT> +  </BODY> +</HTML> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Cancel customer'); + +my $custnum; +my $ban = ''; +if ( $cgi->param('custnum') =~ /^(\d+)$/ ) { +  $custnum = $1; +  $ban = $cgi->param('ban'); +} else { +  my($query) = $cgi->keywords; +  $query =~ /^(\d+)$/ || die "Illegal custnum"; +  $custnum = $1; +} + +#false laziness w/process/cancel_pkg.html + +#untaint reasonnum +my $reasonnum = $cgi->param('reasonnum'); +$reasonnum =~ /^(-?\d+)$/ || die "Illegal reasonnum"; +$reasonnum = $1; + +if ($reasonnum == -1) { +  $reasonnum = { +    'typenum' => scalar( $cgi->param('newreasonnumT') ), +    'reason'  => scalar( $cgi->param('newreasonnum' ) ), +  }; +} + +#eslaf + +my $cust_main = qsearchs( { +  'table'     => 'cust_main', +  'hashref'   => { 'custnum' => $custnum }, +  'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, +} ); + +warn "cancelling $cust_main"; +my @errors = $cust_main->cancel( +  'ban'    => $ban, +  'reason' => $reasonnum, +); +my $error = join(' / ', @errors) if scalar(@errors); + +if ( $error ) { +  $cgi->param('error', $error); +  print $cgi->redirect(popurl(1). "cancel_cust.html?". $cgi->query_string ); +} + +</%init> diff --git a/httemplate/misc/cust_main-import.cgi b/httemplate/misc/cust_main-import.cgi new file mode 100644 index 000000000..9c1f98479 --- /dev/null +++ b/httemplate/misc/cust_main-import.cgi @@ -0,0 +1,148 @@ +<% include("/elements/header.html",'Batch Customer Import') %> + +Import a file containing customer records. +<BR><BR> + +<% include( '/elements/form-file_upload.html', +              'name'      => 'CustomerImportForm', +              'action'    => 'process/cust_main-import.cgi', +              'num_files' => 1, +              'fields'    => [ 'agentnum', 'custbatch', 'format' ], +              'message'   => 'Customer import successful', +              'url'       => $p."search/cust_main.html?custbatch=$custbatch", +          ) +%> + +<% &ntable("#cccccc", 2) %> + +  <% include( '/elements/tr-select-agent.html', +                 #'curr_value' => '', #$agentnum, +                 'label'       => "<B>Agent</B>", +                 'empty_label' => 'Select agent', +             ) +  %> + +  <INPUT TYPE="hidden" NAME="custbatch" VALUE="<% $custbatch %>"%> + +  <TR> +    <TH ALIGN="right">Format</TH> +    <TD> +      <SELECT NAME="format"> +        <!-- <OPTION VALUE="simple">Simple --> +        <OPTION VALUE="extended" SELECTED>Extended +        <OPTION VALUE="extended-plus_company">Extended plus company +        <OPTION VALUE="svc_external">External service +        <OPTION VALUE="svc_external_svc_phone">External service and phone service +      </SELECT> +    </TD> +  </TR> + +  <% include( '/elements/file-upload.html', +                'field' => 'file', +                'label' => 'Filename', +            ) +  %> + + +% #include('/elements/tr-select-part_referral.html') +% + + +<!-- +<TR> +  <TH>First package</TH> +  <TD> +    This needs to be agent-virtualized if it gets used! +    <SELECT NAME="pkgpart"><OPTION VALUE="">(none)</OPTION> +% foreach my $part_pkg ( qsearch('part_pkg',{'disabled'=>'' }) ) {  + +       <OPTION VALUE="<% $part_pkg->pkgpart %>"><% $part_pkg->pkg_comment %></OPTION> +% }  + +    </SELECT> +  </TD> +</TR> +--> + +  <TR> +    <TD COLSPAN=2 ALIGN="center" STYLE="padding-top:6px"> +      <INPUT TYPE    = "submit" +             ID      = "submit" +             VALUE   = "Import file" +             onClick = "document.CustomerImportForm.submit.disabled=true;" +      > +    </TD> +  </TR> + +</TABLE> + +</FORM> + +<BR> + +<!-- Simple file format is CSV, with the following field order: <i>cust_pkg.setup, dayphone, first, last, address1, address2, city, state, zip, comments</i> +<BR><BR> --> + +Uploaded files can be CSV (comma-separated value) files or Excel spreadsheets.  The file should have a .CSV or .XLS extension. +<BR><BR> + +<b>Extended</b> format has the following field order: <i>agent_custid, refnum<%$req%>, last<%$req%>, first<%$req%>, address1<%$req%>, address2, city<%$req%>, state<%$req%>, zip<%$req%>, country, daytime, night, ship_last, ship_first, ship_address1, ship_address2, ship_city, ship_state, ship_zip, ship_country, payinfo, paycvv, paydate, invoicing_list, pkgpart, username, _password</i> +<BR><BR> + +<b>Extended plus company</b> format has the following field order: <i>agent_custid, refnum<%$req%>, last<%$req%>, first<%$req%>, company, address1<%$req%>, address2, city<%$req%>, state<%$req%>, zip<%$req%>, country, daytime, night, ship_last, ship_first, ship_company, ship_address1, ship_address2, ship_city, ship_state, ship_zip, ship_country, payinfo, paycvv, paydate, invoicing_list, pkgpart, username, _password</i> +<BR><BR> + +<b>External service</b> format has the following field order: <i>agent_custid, refnum<%$req%>, last<%$req%>, first<%$req%>, company, address1<%$req%>, address2, city<%$req%>, state<%$req%>, zip<%$req%>, country, daytime, night, ship_last, ship_first, ship_company, ship_address1, ship_address2, ship_city, ship_state, ship_zip, ship_country, payinfo, paycvv, paydate, invoicing_list, pkgpart, next_bill_date, id, title</i> +<BR><BR> + +<b>External service and phone service</b> format has the following field order: <i>agent_custid, refnum<%$req%>, last<%$req%>, first<%$req%>, company, address1<%$req%>, address2, city<%$req%>, state<%$req%>, zip<%$req%>, country, daytime, night, ship_last, ship_first, ship_company, ship_address1, ship_address2, ship_city, ship_state, ship_zip, ship_country, payinfo, paycvv, paydate, invoicing_list, pkgpart, next_bill_date, id, title, countrycode, phonenum, sip_password, pin</i> +<BR><BR> + +<%$req%> Required fields +<BR><BR> + +Field information: + +<ul> + +  <li><i>agent_custid</i>: This is the reseller's idea of the customer number or identifier.  It may be left blank.  If specified, it must be unique per-agent. + +  <li><i>refnum</i>: Advertising source number - where a customer heard about your service.  Configuration -> Miscellaneous -> View/Edit advertising sources.  This field has special treatment upon import: If a string is passed instead +of an integer, the string is searched for and if necessary auto-created in the +advertising source table. + +  <li><i>payinfo</i>: Credit card number, or leave this, <i>paycvv</i> and <i>paydate</i> blank for email/paper invoicing. + +  <li><i>paycvv</i>: CVV2 number (three digits on the back of the credit card) + +  <li><i>paydate</i>: Credit card expiration date, MM/YYYY or MM/YY (M/YY and M/YYYY are also accepted). + +  <li><i>invoicing_list</i>: Email address for invoices, or POST for postal invoices. + +  <li><i>pkgpart</i>: Package definition.  Configuration -> Provisioning, services and packages -> View/Edit package definitions + +  <li><i>username</i> and <i>_password</i> are required if <i>pkgpart</i> is specified. (Extended and Extended plus company formats) + +  <li><i>id</i>: External service id, integer + +  <li><i>title</i>: External service identifier, text + +</ul> + +<BR> + +<% include('/elements/footer.html') %> + +<%once> + +my $req = qq!<font color="#ff0000">*</font>!; + +</%once> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Import'); + +my $custbatch = time2str('webimport-%Y/%m/%d-%T'. "-$$-". rand() * 2**32, time); + +</%init> diff --git a/httemplate/misc/cust_main-import_charges.cgi b/httemplate/misc/cust_main-import_charges.cgi new file mode 100644 index 000000000..3801929e8 --- /dev/null +++ b/httemplate/misc/cust_main-import_charges.cgi @@ -0,0 +1,22 @@ +<% include('/elements/header.html', 'Batch Customer Charge') %> + +<FORM ACTION="process/cust_main-import_charges.cgi" METHOD="post" ENCTYPE="multipart/form-data"> + +Import a CSV file containing customer charges.<BR><BR> +Default file format is CSV, with the following field order: <i>custnum, amount, description</i><BR><BR> +If <i>amount</i> is negative, a credit will be applied instead.<BR><BR> +<BR><BR> + +CSV Filename: <INPUT TYPE="file" NAME="csvfile"><BR><BR> +<INPUT TYPE="submit" VALUE="Import"> + +</FORM> + +<% include('/elements/footer.html') %> + +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Import'); + +</%init> diff --git a/httemplate/misc/cust_main_note-import.cgi b/httemplate/misc/cust_main_note-import.cgi new file mode 100644 index 000000000..b93c5c1cc --- /dev/null +++ b/httemplate/misc/cust_main_note-import.cgi @@ -0,0 +1,207 @@ +<% include("/elements/header.html", 'Batch Customer Note Import') %> +% + +<FORM ACTION="process/cust_main_note-import.cgi" METHOD="POST"> + + +<SCRIPT TYPE="text/javascript"> + +  function clearhint_custnum() { + +    if ( this.value == 'Not found' ) { +      this.value = ''; +      this.style.color = '#000000'; +    } + +  } + +  function search_custnum() { + +    this.style.color = '#000000' + +    var custnum_obj = this; +    var searchrow = this.getAttribute('rownum'); +    var custnum = this.value; +    var name_obj = document.getElementById('name'+searchrow); + +    if ( custnum == 'searching...' || custnum == 'Not found' ) +      return; + +    var customer_select = document.getElementById('cust_select'+searchrow); + +    if ( custnum == '' ) { +      customer_select.selectedIndex = 0; +      return; +    } + +    custnum_obj.value = 'searching...'; +    custnum_obj.disabled = true; +    custnum_obj.style.backgroundColor = '#dddddd'; + + +    //alert('search for custnum ' + custnum + ', row#' + searchrow ); + +    function search_custnum_update(name) { + +      var name = eval('(' + name + ')' ); + +      custnum_obj.disabled = false; +      custnum_obj.style.backgroundColor = '#ffffff'; + +      if ( name.length > 0 ) { +        //alert('custnum found: ' + name); +        opt(customer_select,custnum,name,'#000000'); +        customer_select.selectedIndex = customer_select.length - 1; +        custnum_obj.value = custnum; +        name_obj.value = name; +      } else { +        custnum_obj.value = 'Not found'; +        custnum_obj.style.color = '#ff0000'; +      } + +    } + +    custnum_search( custnum, search_custnum_update ); + +  } + +  function select_customer() { + +    var custnum = this.options[this.selectedIndex].value; +    var name = this.options[this.selectedIndex].text; + +    var searchrow = this.getAttribute('rownum'); +    var custnum_obj = document.getElementById('custnum'+searchrow); +    var name_obj = document.getElementById('name'+searchrow); + +    custnum_obj.value = custnum; +    custnum_obj.style.color = '#000000'; + +    name_obj.value = name; + +  } + +  function opt(what,value,text,color) { +    var optionName = new Option(text, value, false, false); +    optionName.style.color = color; +    var length = what.length; +    what.options[length] = optionName; +  } + +  function previewChanged(what) { +    var submit_obj = document.getElementById('importsubmit'); +    if (what.checked) { +      submit_obj.value = 'Preview note import'; +    }else{ +      submit_obj.value = 'Import notes'; +    } +  } + +</SCRIPT> + +<% include('/elements/xmlhttp.html', +              'url'  => $p. 'misc/xmlhttp-cust_main-search.cgi', +              'subs' => [qw( custnum_search )], +           ) +%> + +%  my $fh = $cgi->upload('csvfile'); +%  my $csv = new Text::CSV_XS; +%  my $skip_fuzzies = $cgi->param('fuzzies') ? 0 : 1; +% +%  if ( defined($fh) ) { +     <TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0> +     <TR> +       <TH>Cust #</TH> +       <TH>Customer</TH> +       <TH>Last</TH> +       <TH>First</TH> +       <TH>Note to be added</TH> +     </TR> +%    my $agentnum   => scalar($cgi->param('agentnum')), +%    my $line; +%    my $row = 0; +%    while ( defined($line=<$fh>) ) { +%      $line =~ s/(\S*)\s*$/$1/; +%      $line =~ s/^(.*)(#!).*/$1/; +% +%      $csv->parse($line) or die "can't parse line: " . $csv->error_input(); +%      my $custnum = 0; +%      my @values = $csv->fields(); +%      my $last  = shift @values; +%      if ($last =~ /^\s*(\d+)\s*$/ ) { +%        $custnum = $1; +%        $last = shift @values; +%      } +%      my $first = shift @values; +%      my $note  = join ' ', @values; +%      next unless ( $last || $first || $note ); +%      my @cust_main = (); +%      warn "searching for: $last, $first" if ($first || $last); +%      if ($custnum) { +%        @cust_main = qsearch('cust_main', { 'custnum' => $custnum }); +%      } else { +%        @cust_main = FS::cust_main::smart_search( +%                                          'search' => "$last, $first", +%                                          'no_fuzzy_on_exact' => $skip_fuzzies, +%                                                ) +%          if ($first || $last); +%      } +% +       <TR> +         <TD> +           <INPUT TYPE="text" NAME="custnum<% $row %>" ID="custnum<% $row %>" SIZE=8 MAXLENGTH=12 VALUE="<% $cust_main[0] ? $cust_main[0]->custnum : '' %>" rownum="<% $row %>"> +             <SCRIPT TYPE="text/javascript"> +               var custnum_input<% $row %> = document.getElementById("custnum<% $row %>"); +               custnum_input<% $row %>.onfocus = clearhint_custnum; +               custnum_input<% $row %>.onchange = search_custnum; +             </SCRIPT> +         </TD> +         <TD> +           <SELECT NAME="cust_select<% $row %>" ID="cust_select<% $row %>" rownum="<% $row %>"> +             <OPTION VALUE="">---</OPTION> +%      my $i=0; +%      foreach (@cust_main) { +             <OPTION <% $i ? '' : 'SELECTED' %> VALUE="<% $_->custnum %>"><% $_->name %></OPTION> +%        $i++; +%      } +           </SELECT> +             <SCRIPT TYPE="text/javascript"> +               var customer_select<% $row %> = document.getElementById("cust_select<% $row %>"); +               customer_select<% $row %>.onchange = select_customer; +             </SCRIPT> +           <INPUT TYPE="hidden" NAME="name<% $row %>" ID="name<% $row %>" VALUE="<% $i ? $cust_main[0]->name : '' %>"> +         </TD> +         <TD> +           <% $first %> +           <INPUT TYPE="hidden" NAME="first<% $row %>" VALUE="<% $first %>"> +         </TD> +         <TD> +           <% $last %> +           <INPUT TYPE="hidden" NAME="last<% $row %>" VALUE="<% $last %>"> +         </TD> +         <TD> +           <% $note %> +           <INPUT TYPE="hidden" NAME="note<% $row %>" VALUE="<% $note %>"> +         </TD> +       </TR> +%      $row++; +%    } +     </TABLE> +     <INPUT TYPE="submit" NAME="submit" ID="importsubmit" VALUE="Import notes"> +     <INPUT TYPE="checkbox" NAME="preview" onchange="previewChanged(this);"> +     Preview mode +%  } else { +     No file supplied +%  } + +</FORM> +</BODY> +</HTML> + +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Import'); + +</%init> diff --git a/httemplate/misc/cust_main_note-import.html b/httemplate/misc/cust_main_note-import.html new file mode 100644 index 000000000..d8fefa732 --- /dev/null +++ b/httemplate/misc/cust_main_note-import.html @@ -0,0 +1,39 @@ +<% include("/elements/header.html",'Batch Customer Note Import') %> + +<FORM ACTION="cust_main_note-import.cgi" METHOD="post" ENCTYPE="multipart/form-data"> + +Import a CSV file containing customer notes records. +<BR><BR> + +File format is CSV, with the following field order: <i>[custnum,] last, first, notefield1, notefield2, notefield3...</i> +<BR> +The optional custnum field is identified by being numeric. +Anything after the character sequence #! is ignored. +<BR><BR> + +<% &ntable("#cccccc") %> + +<TR> +  <TH ALIGN="right">CSV filename</TH> +  <TD><INPUT TYPE="file" NAME="csvfile"></TD> +</TR> +<TR> +  <TH ALIGN="right">Include additional possibilites when exact match is found</TH> +  <TD><INPUT TYPE="checkbox" NAME="fuzzies"></TD> +</TR> + +</TABLE> +<BR><BR> + +<INPUT TYPE="submit" VALUE="Load and match"> +</FORM> + +<% include('/elements/footer.html') %> + +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Import'); + +</%init> + diff --git a/httemplate/misc/cust_pay-import.cgi b/httemplate/misc/cust_pay-import.cgi new file mode 100644 index 000000000..849a25bea --- /dev/null +++ b/httemplate/misc/cust_pay-import.cgi @@ -0,0 +1,62 @@ +<% include("/elements/header.html",'Batch Payment Import') %> + +Import a CSV file containing customer payments. +<BR><BR> + +<FORM ACTION="process/cust_pay-import.cgi" METHOD="post" ENCTYPE="multipart/form-data"> + +<% &ntable("#cccccc", 2) %> + +<% include('/elements/tr-select-agent.html', +              #'curr_value' => '', #$agentnum, +              'label'       => "<B>Agent</B>", +              'empty_label' => 'Select agent', +           ) +%> + +<TR> +  <TH ALIGN="right">Format</TH> +  <TD> +    <SELECT NAME="format"> +      <OPTION VALUE="simple">Simple +<!--      <OPTION VALUE="extended" SELECTED>Extended --> +    </SELECT> +  </TD> +</TR> + +<TR> +  <TH ALIGN="right">CSV filename</TH> +  <TD><INPUT TYPE="file" NAME="csvfile"></TD> +</TR> + +<TR><TD COLSPAN=2 ALIGN="center" STYLE="padding-top:6px"><INPUT TYPE="submit" VALUE="Import CSV file"></TD></TR> + +</TABLE> + +</FORM> + +<BR> + +Simple file format is CSV, with the following field order: <i>custnum, agent_custid, amount, checknum</i> +<BR><BR> + +<!-- Extended file format is not yet defined</i> +<BR><BR> --> + +Field information: + +<ul> + +  <li><i>custnum</i>: This is the freeside customer number.  It may be left blank.  If specified, agent_custid must be blank. + +  <li><i>agent_custid</i>: This is the reseller's idea of the customer number or identifier.  It may be left blank.  If specified, custnum must be blank. + +  <li><i>amount</i>: A positive numeric value with at most two digits after the decimal point. + +  <li><i>checknum</i>: A sequences of digits.  May be left blank. + +</ul> + +<BR> + +<% include('/elements/footer.html') %> diff --git a/httemplate/misc/delay_susp_pkg.html b/httemplate/misc/delay_susp_pkg.html new file mode 100755 index 000000000..d4a6da18f --- /dev/null +++ b/httemplate/misc/delay_susp_pkg.html @@ -0,0 +1,70 @@ +%# if ( $link eq 'popup' ) {  +  <% include('/elements/header-popup.html', $title ) %> +%# } else {  +%#  <%  include("/elements/header.html", $title, '') %> +%# }  + +<% include('/elements/init_calendar.html') %> + +<% include('/elements/error.html') %> + +<FORM NAME="ds_popup" ACTION="<% popurl(1) %>process/delay_susp_pkg.html" METHOD=POST> +<INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $pkgnum %>"> + +<BR><BR> +<% "Delay automatic suspension of " .$part_pkg->pkg_comment %> +<% ntable("#cccccc", 2) %> + +<TR> +  <TD>Delay until</TD> +    <TD><INPUT TYPE="text" NAME="date" ID="dun_date" VALUE="<% $date |h %>"> +        <IMG SRC="<% $p %>images/calendar.png" ID="dun_button" STYLE="cursor:pointer" TITLE="Select date"> +        <BR><I>m/d/y</I> +    </TD> +</TR> +<SCRIPT TYPE="text/javascript"> +  Calendar.setup({ +    inputField: "dun_date", +    ifFormat:   "%m/%d/%Y", +    button:     "dun_button", +    align:      "BR" +  }); +</SCRIPT> + +</TABLE> + +<BR> +<INPUT TYPE="submit" NAME="submit" VALUE="<% $submit %>"> + +</FORM> +</BODY> +</HTML> + +<%init> + +my $date = time2str("%m/%d/%Y", time); + +my($pkgnum); +if ( $cgi->param('error') ) { +  $pkgnum    = $cgi->param('pkgnum'); +  $date      = $cgi->param('date'); +} elsif ( $cgi->param('pkgnum') =~ /^(\d+)$/ ) { +  $pkgnum    = $1; +} else { +  die "illegal query ". $cgi->keywords; +} + +my $submit = 'Delay Suspension'; +my $right  = 'Delay suspension events'; + +my $curuser = $FS::CurrentUser::CurrentUser; +die "access denied" unless $curuser->access_right($right); + +my $title = 'Delay Suspension of Package'; + +my $cust_pkg = qsearchs('cust_pkg', {'pkgnum' => $pkgnum}) +  or die "Unknown pkgnum: $pkgnum"; + +my $part_pkg = $cust_pkg->part_pkg; + +</%init> diff --git a/httemplate/misc/delete-agent_payment_gateway.cgi b/httemplate/misc/delete-agent_payment_gateway.cgi new file mode 100644 index 000000000..20a202e0e --- /dev/null +++ b/httemplate/misc/delete-agent_payment_gateway.cgi @@ -0,0 +1,15 @@ +% die "you don't have the 'Configuration' access right" +%   unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); +% +% my($query) = $cgi->keywords; +% $query  =~ /^(\d+)$/ || die "Illegal agentgatewaynum"; +% my $agentgatewaynum = $1; +% +% my $agent_payment_gateway = qsearchs('agent_payment_gateway', {  +%   'agentgatewaynum' => $agentgatewaynum, +% }); +% +% my $error = $agent_payment_gateway->delete; +% errorpage($error) if $error; +% +% print $cgi->redirect($p. "browse/agent.cgi"); diff --git a/httemplate/misc/delete-cust_bill.html b/httemplate/misc/delete-cust_bill.html new file mode 100644 index 000000000..3a642b0e9 --- /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-cust_credit.cgi b/httemplate/misc/delete-cust_credit.cgi new file mode 100755 index 000000000..03eb47299 --- /dev/null +++ b/httemplate/misc/delete-cust_credit.cgi @@ -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 credit'); + +#untaint crednum +my($query) = $cgi->keywords; +$query =~ /^(\d+)$/ || die "Illegal crednum"; +my $crednum = $1; + +my $cust_credit = qsearchs('cust_credit',{'crednum'=>$crednum}); +my $custnum = $cust_credit->custnum; + +my $error = $cust_credit->delete; + +</%init> diff --git a/httemplate/misc/delete-cust_pay.cgi b/httemplate/misc/delete-cust_pay.cgi new file mode 100755 index 000000000..38e7e4ba1 --- /dev/null +++ b/httemplate/misc/delete-cust_pay.cgi @@ -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 payment'); + +#untaint paynum +my($query) = $cgi->keywords; +$query =~ /^(\d+)$/ || die "Illegal paynum"; +my $paynum = $1; + +my $cust_pay = qsearchs('cust_pay',{'paynum'=>$paynum}); +my $custnum = $cust_pay->custnum; + +my $error = $cust_pay->delete; + +</%init> diff --git a/httemplate/misc/delete-cust_refund.cgi b/httemplate/misc/delete-cust_refund.cgi new file mode 100755 index 000000000..983a79da5 --- /dev/null +++ b/httemplate/misc/delete-cust_refund.cgi @@ -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 refund'); + +#untaint refundnum +my($query) = $cgi->keywords; +$query =~ /^(\d+)$/ || die "Illegal refundnum"; +my $refundnum = $1; + +my $cust_refund = qsearchs('cust_refund',{'refundnum'=>$refundnum}); +my $custnum = $cust_refund->custnum; + +my $error = $cust_refund->delete; + +</%init> diff --git a/httemplate/misc/delete-customer.cgi b/httemplate/misc/delete-customer.cgi new file mode 100755 index 000000000..203ed36a5 --- /dev/null +++ b/httemplate/misc/delete-customer.cgi @@ -0,0 +1,64 @@ +<% include('/elements/header.html', 'Delete customer') %> + +<% include('/elements/error.html') %> + +<FORM ACTION="<% popurl(1) %>process/delete-customer.cgi" METHOD=POST> +<INPUT TYPE="hidden" NAME="custnum" VALUE="<% $custnum |h %>"> + +%if ( qsearch('cust_pkg', { 'custnum' => $custnum, 'cancel' => '' } ) ) { +  Move uncancelled packages to customer number  +  <INPUT TYPE="text" NAME="new_custnum" VALUE="<% $new_custnum |h %>"><BR><BR> +%} + +This will <B>completely remove</B> all traces of this customer record.  This +is <B>not</B> what you want if this is a real customer who has simply +canceled service with you.  For that, cancel all of the customer's packages. +(you can optionally hide cancelled customers with the <A HREF="../config/config-view.cgi#hidecancelledcustomers">hidecancelledcustomers</A> configuration option) +<BR> +<BR>Are you <B>absolutely sure</B> you want to delete this customer? +<BR><INPUT TYPE="submit" VALUE="Yes"> +</FORM> + +<% include('/elements/footer.html') %> + +%#Deleting a customer you have financial records on (i.e. credits) is +%#typically considered fraudulant bookkeeping.  Remember, deleting    +%#customers should ONLY be used for completely bogus records.  You should +%#NOT delete real customers who simply discontinue service. +%# +%#For real customers who simply discontinue service, cancel all of the +%#customer's packages.  Customers with all cancelled packages are not   +%#billed.  There is no need to take further action to prevent billing on +%#customers with all cancelled packages. +%# +%#Also see the "hidecancelledcustomers" and "hidecancelledpackages" +%#configuration options, which will allow you to surpress the display of +%#cancelled customers and packages, respectively. + +<%init> + +my $conf = new FS::Conf; +die "Customer deletions not enabled in configuration" +  unless $conf->exists('deletecustomers'); + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Delete customer'); + +my($custnum, $new_custnum); +if ( $cgi->param('error') ) { +  $custnum = $cgi->param('custnum'); +  $new_custnum = $cgi->param('new_custnum'); +} else { +  my($query) = $cgi->keywords; +  $query =~ /^(\d+)$/ or die "Illegal query: $query"; +  $custnum = $1; +  $new_custnum = ''; +} +my $cust_main = qsearchs( { +  'table'     => 'cust_main', +  'hashref'   => { 'custnum' => $custnum }, +  'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, +} ) +  or die 'Unknown custnum'; + +</%init> diff --git a/httemplate/misc/delete-domain_record.cgi b/httemplate/misc/delete-domain_record.cgi new file mode 100755 index 000000000..08eedde5f --- /dev/null +++ b/httemplate/misc/delete-domain_record.cgi @@ -0,0 +1,20 @@ +% if ( $error ) { +%   errorpage($error); +% } else { +<% $cgi->redirect($p. "view/svc_domain.cgi?". $domain_record->svcnum) %> +% } +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Edit domain nameservice'); + +#untaint recnum +my($query) = $cgi->keywords; +$query =~ /^(\d+)$/ || die "Illegal recnum"; +my $recnum = $1; + +my $domain_record = qsearchs('domain_record',{'recnum'=>$recnum}); + +my $error = $domain_record->delete; + +</%init> diff --git a/httemplate/misc/delete-part_export.cgi b/httemplate/misc/delete-part_export.cgi new file mode 100755 index 000000000..52404e0c4 --- /dev/null +++ b/httemplate/misc/delete-part_export.cgi @@ -0,0 +1,20 @@ +% if ( $error ) { +%   errorpage($error); +% } else { +<% $cgi->redirect($p. "browse/part_export.cgi") %> +% } +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); + +#untaint exportnum +my($query) = $cgi->keywords; +$query =~ /^(\d+)$/ || die "Illegal exportnum"; +my $exportnum = $1; + +my $part_export = qsearchs('part_export',{'exportnum'=>$exportnum}); + +my $error = $part_export->delete; + +</%init> diff --git a/httemplate/misc/delete-phone_device.html b/httemplate/misc/delete-phone_device.html new file mode 100755 index 000000000..7220c41e3 --- /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/disable-payment_gateway.cgi b/httemplate/misc/disable-payment_gateway.cgi new file mode 100644 index 000000000..13e1f92bc --- /dev/null +++ b/httemplate/misc/disable-payment_gateway.cgi @@ -0,0 +1,25 @@ +%if ( $error ) { +%  errorpage($error); +%} else { +%#<% $cgi->redirect(popurl(2). "browse/payment_gateway.html?showdiabled=$showdisabled") %> +<% $cgi->redirect(popurl(2). "browse/payment_gateway.html") %> +%} +<%init> + +die "access deined" +  unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); + +#my $showdisabled = 0; +#$cgi->param('showdisabled') =~ /^(\d+)$/ and $showdisabled = $1; + +#$cgi->param('gatewaynum') =~ /^(\d+)$/ or die 'illegal gatewaynum'; +my($query) = $cgi->keywords; +$query =~ /^(\d+)$/ or die 'illegal gatewaynum'; +my $gatewaynum = $1; + +my $payment_gateway = +  qsearchs('payment_gateway', { 'gatewaynum' => $gatewaynum } ); + +my $error = $payment_gateway->disable; + +</%init> diff --git a/httemplate/misc/download-batch.cgi b/httemplate/misc/download-batch.cgi new file mode 100644 index 000000000..01bf5d25f --- /dev/null +++ b/httemplate/misc/download-batch.cgi @@ -0,0 +1,23 @@ +<% $pay_batch->export_batch($format) %> + +<%init> + +#http_header('Content-Type' => 'text/comma-separated-values' ); #IE chokes +http_header('Content-Type' => 'text/plain' ); # not necessarily correct... + +my $batchnum; +if ( $cgi->param('batchnum') =~ /^(\d+)$/ ) { +  $batchnum = $1; +} else { +  die "No batch number (bad URL) \n"; +} + +my $format; +if ( $cgi->param('format') =~ /^([\w\- ]+)$/ ) { +  $format = $1; +} + +my $pay_batch = qsearchs('pay_batch', { batchnum => $batchnum } ); +die "Batch not found: '$batchnum'" if !$pay_batch; + +</%init> diff --git a/httemplate/misc/dump.cgi b/httemplate/misc/dump.cgi new file mode 100644 index 000000000..3b60b20ef --- /dev/null +++ b/httemplate/misc/dump.cgi @@ -0,0 +1,20 @@ +%  die "access denied" +%    unless $FS::CurrentUser::CurrentUser->access_right('Export'); +% +%  if ( driver_name =~ /^Pg$/ ) { +%    my $dbname = (split(':', datasrc))[2]; +%    if ( $dbname =~ /[;=]/ ) { +%      my %elements = map { /^(\w+)=(.*)$/; $1=>$2 } split(';', $dbname); +%      $dbname = $elements{'dbname'}; +%    } +%    open(DUMP,"pg_dump $dbname |"); +%  } else { +%    errorpage("don't (yet) know how to dump ". driver_name. " databases"); +%  } +% +%  http_header('Content-Type' => 'text/plain' ); +% +%  while (<DUMP>) { +%    print $_; +%  } +%  close DUMP; diff --git a/httemplate/misc/email-customers.html b/httemplate/misc/email-customers.html new file mode 100644 index 000000000..4e4c15f2a --- /dev/null +++ b/httemplate/misc/email-customers.html @@ -0,0 +1,145 @@ +<% include('/elements/header.html', $title) %> + +<FORM NAME="OneTrueForm" ACTION="email-customers.html" METHOD="POST"> +% foreach my $key ( keys %search ) { +%   my @values = ref($search{$key}) ? @{$search{$key}} : ( $search{$key} ); +%   foreach my $value ( @values ) { +      <INPUT TYPE="hidden" NAME="<% $key %>" VALUE="<% $value %>"> +%   } +% } + +% if ( $cgi->param('magic') eq 'send' ) { + +    <FONT SIZE="+2">Sending notice</FONT> + +    <% include('/elements/progress-init.html', +                 'OneTrueForm', +                 [ keys(%search), qw( from subject html_body text_body ) ], +                 'process/email-customers.html', +                 { 'message' => "Notice sent" }, #would be nice to show #, but.. +              ) +    %> + +% } elsif ( $cgi->param('magic') eq 'preview' ) { + +    <FONT SIZE="+2">Preview notice</FONT> + +% } + +% if ( $cgi->param('magic') ) { + +    <TABLE BGCOLOR="#cccccc" CELLSPACING=0> + +      <% include('/elements/tr-fixed.html', +                   'field'      => 'from', +                   'label'      => 'From:', +                   'value' => scalar( $cgi->param('from') ), +                ) +      %> + +      <% include('/elements/tr-fixed.html', +                   'field'      => 'subject', +                   'label'      => 'Subject:', +                   'value' => scalar( $cgi->param('subject') ), +                ) +      %> + +      <INPUT TYPE="hidden" NAME="html_body" VALUE="<% $cgi->param('html_body') |h %>"> +      <TR> +        <TD ALIGN="right" VALIGN="top">Message (HTML display): </TD> +        <TD BGCOLOR="#e8e8e8" ALIGN="left"><% $cgi->param('html_body') %></TD> +      </TR> + +%     my $text_body = HTML::FormatText->new(leftmargin=>0)->format( +%                       HTML::TreeBuilder->new_from_content( +%                         $cgi->param('html_body') +%                       ) +%                     ); +      <INPUT TYPE="hidden" NAME="text_body" VALUE="<% $text_body |h %>"> +      <TR> +        <TD ALIGN="right" VALIGN="top">Message (Text display): </TD> +        <TD BGCOLOR="#e8e8e8" ALIGN="left"><PRE><% $text_body %></PRE></TD> +      </TR> + +    </TABLE> + +% if ( $cgi->param('magic') eq 'preview' ) { + +      <SCRIPT> +        function areyousure(href) { +          return confirm("Send this notice to <% $num_cust %> customers?"); +        } +      </SCRIPT> + +      <BR> +      <INPUT TYPE="hidden" NAME="magic" VALUE="send"> +      <INPUT TYPE="submit" VALUE="Send notice" onClick="return areyousure()"> +     +%   } + +% } else { + +  <TABLE BGCOLOR="#cccccc" CELLSPACING=0 WIDTH="100%"> + +    <% include('/elements/tr-input-text.html', +                 'field' => 'from', +                 'label' => 'From:', +              ) +    %> + +    <% include('/elements/tr-input-text.html', +                 'field' => 'subject', +                 'label' => 'Subject:', +              ) +    %> + +    <TR> +      <TD ALIGN="right" VALIGN="top">Message: </TD> +      <TD><% include('/elements/htmlarea.html', 'field'=>'html_body') %></TD> +    </TR> + +  </TABLE> + +%#Substitution vars: + +    <BR><BR> +    <INPUT TYPE="hidden" NAME="magic" VALUE="preview"> +    <INPUT TYPE="submit" VALUE="Preview notice"> + +% } + +</FORM> + +% if ( $cgi->param('magic') eq 'send' ) { +    <SCRIPT TYPE="text/javascript"> +      process(); +    </SCRIPT> +% } + +<% include('/elements/footer.html') %> + +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Bulk send customer notices'); + +my %search = $cgi->Vars; +delete $search{$_} for qw( magic from subject html_body text_body ); +$search{$_} = [ split(/\0/, $search{$_}) ] +  foreach grep { $_ eq 'payby' || $search{$_} =~ /\0/ } keys %search; + +my $title = 'Bulk send customer notices'; + +my $num_cust; +if ( $cgi->param('magic') eq 'preview' ) { +  my $sql_query = FS::cust_main->search(\%search); +  my $count_query = delete($sql_query->{'count_query'}); +  my $count_sth = dbh->prepare($count_query) +    or die "Error preparing $count_query: ". dbh->errstr; +  $count_sth->execute +    or die "Error executing $count_query: ". $count_sth->errstr; +  my $count_arrayref = $count_sth->fetchrow_arrayref; +  $num_cust = $count_arrayref->[0]; +} + +</%init> diff --git a/httemplate/misc/email-invoice.cgi b/httemplate/misc/email-invoice.cgi new file mode 100755 index 000000000..269722f67 --- /dev/null +++ b/httemplate/misc/email-invoice.cgi @@ -0,0 +1,19 @@ +<% $cgi->redirect("${p}view/cust_main.cgi?$custnum") %> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Resend invoices'); + +#untaint invnum +my($query) = $cgi->keywords; +$query =~ /^((.+)-)?(\d+)$/; +my $template = $2; +my $invnum = $3; +my $cust_bill = qsearchs('cust_bill',{'invnum'=>$invnum}); +die "Can't find invoice!\n" unless $cust_bill; + +$cust_bill->email($template);  + +my $custnum = $cust_bill->getfield('custnum'); + +</%init> diff --git a/httemplate/misc/email_events.cgi b/httemplate/misc/email_events.cgi new file mode 100644 index 000000000..e7a0e77f8 --- /dev/null +++ b/httemplate/misc/email_events.cgi @@ -0,0 +1,9 @@ +<% $server->process %> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Resend invoices'); + +my $server = new FS::UI::Web::JSRPC 'FS::cust_event::process_reemail', $cgi; + +</%init> diff --git a/httemplate/misc/email_invoice_events.cgi b/httemplate/misc/email_invoice_events.cgi new file mode 100644 index 000000000..d65fe172b --- /dev/null +++ b/httemplate/misc/email_invoice_events.cgi @@ -0,0 +1,9 @@ +<% $server->process %> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Resend invoices'); + +my $server = new FS::UI::Web::JSRPC 'FS::cust_bill_event::process_reemail', $cgi; + +</%init> diff --git a/httemplate/misc/email_invoices.cgi b/httemplate/misc/email_invoices.cgi new file mode 100644 index 000000000..78ca0f67d --- /dev/null +++ b/httemplate/misc/email_invoices.cgi @@ -0,0 +1,9 @@ +<% $server->process %> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Resend invoices'); + +my $server = new FS::UI::Web::JSRPC 'FS::cust_bill::process_reemail', $cgi; + +</%init> diff --git a/httemplate/misc/enable_or_disable_tax.html b/httemplate/misc/enable_or_disable_tax.html new file mode 100755 index 000000000..0efd07d19 --- /dev/null +++ b/httemplate/misc/enable_or_disable_tax.html @@ -0,0 +1,37 @@ +<% include('/elements/header-popup.html', ucfirst($action). ' Tax Rates') %> +<% include('/elements/error.html') %> + +<FORM ACTION="<% popurl(1) %>process/enable_or_disable_tax.html" METHOD=POST> +<INPUT TYPE="hidden" NAME="action" VALUE="<% $action %>"> +<INPUT TYPE="hidden" NAME="data_vendor" VALUE="<% $cgi->param('data_vendor') %>"> +<INPUT TYPE="hidden" NAME="geocode" VALUE="<% $cgi->param('geocode') %>"> +<INPUT TYPE="hidden" NAME="taxclassnum" VALUE="<% $cgi->param('taxclassnum') %>"> +<INPUT TYPE="hidden" NAME="tax_type" VALUE="<% $cgi->param('tax_type') %>"> +<INPUT TYPE="hidden" NAME="tax_cat" VALUE="<% $cgi->param('tax_cat') %>"> +<INPUT TYPE="hidden" NAME="showdisabled" VALUE="<% $cgi->param('showdisabled') |h %>"> + +This will <B><% $action %></B> <% $count %> tax +<% $count == 1 ? 'rate' : 'rates' %>.  Are you <B>certain</B> you want to do +this? +<BR><BR><INPUT TYPE="submit" VALUE="Yes"> +</FORM> + +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); + +my $action = ''; +if ( $cgi->param('action') =~ /^(\w+)$/ ) { +  $action = $1; +} + +my ($query, $count_query) = FS::tax_rate::browse_queries(scalar($cgi->Vars)); + +my $count_sth = dbh->prepare($count_query) +  or die "Error preparing $count_query: ". dbh->errstr; +$count_sth->execute +  or die "Error executing $count_query: ". $count_sth->errstr; +my $count = $count_sth->fetchrow_arrayref->[0]; + +</%init> diff --git a/httemplate/misc/exchanges.cgi b/httemplate/misc/exchanges.cgi new file mode 100644 index 000000000..f5860cff2 --- /dev/null +++ b/httemplate/misc/exchanges.cgi @@ -0,0 +1,24 @@ +%# [ <% join(', ', map { qq("$_") } @exchanges) %> ] +<% objToJson(\@exchanges) %> +<%init> + +my( $areacode, $svcpart ) = $cgi->param('arg'); + +my $part_svc = qsearchs('part_svc', { 'svcpart'=>$svcpart } ); +die "unknown svcpart $svcpart" unless $part_svc; + +my @exports = $part_svc->part_export_did; +if ( scalar(@exports) > 1 ) { +  die "more than one DID-providing export attached to svcpart $svcpart"; +} elsif ( ! @exports ) { +  die "no DID providing export attached to svcpart $svcpart"; +} +my $export = $exports[0]; + +my $something = $export->get_dids('areacode'=>$areacode); + +#warn Dumper($something); + +my @exchanges = @{ $something }; + +</%init> diff --git a/httemplate/misc/fax-invoice.cgi b/httemplate/misc/fax-invoice.cgi new file mode 100755 index 000000000..2591fceb8 --- /dev/null +++ b/httemplate/misc/fax-invoice.cgi @@ -0,0 +1,19 @@ +<% $cgi->redirect("${p}view/cust_main.cgi?$custnum") %> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Resend invoices'); + +#untaint invnum +my($query) = $cgi->keywords; +$query =~ /^((.+)-)?(\d+)$/; +my $template = $2; +my $invnum = $3; +my $cust_bill = qsearchs('cust_bill',{'invnum'=>$invnum}); +die "Can't find invoice!\n" unless $cust_bill; + +$cust_bill->fax_invoice($template); + +my $custnum = $cust_bill->getfield('custnum'); + +</%init> diff --git a/httemplate/misc/fax_events.cgi b/httemplate/misc/fax_events.cgi new file mode 100644 index 000000000..39cba0707 --- /dev/null +++ b/httemplate/misc/fax_events.cgi @@ -0,0 +1,9 @@ +<% $server->process %> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Resend invoices'); + +my $server = new FS::UI::Web::JSRPC 'FS::cust_event::process_refax', $cgi; + +</%init> diff --git a/httemplate/misc/fax_invoice_events.cgi b/httemplate/misc/fax_invoice_events.cgi new file mode 100644 index 000000000..05420eeca --- /dev/null +++ b/httemplate/misc/fax_invoice_events.cgi @@ -0,0 +1,9 @@ +<% $server->process %> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Resend invoices'); + +my $server = new FS::UI::Web::JSRPC 'FS::cust_bill_event::process_refax', $cgi; + +</%init> diff --git a/httemplate/misc/fax_invoices.cgi b/httemplate/misc/fax_invoices.cgi new file mode 100644 index 000000000..a843523db --- /dev/null +++ b/httemplate/misc/fax_invoices.cgi @@ -0,0 +1,9 @@ +<% $server->process %> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Resend invoices'); + +my $server = new FS::UI::Web::JSRPC 'FS::cust_bill::process_refax', $cgi; + +</%init> diff --git a/httemplate/misc/file-upload.html b/httemplate/misc/file-upload.html new file mode 100644 index 000000000..469274c69 --- /dev/null +++ b/httemplate/misc/file-upload.html @@ -0,0 +1,53 @@ +<% include('/elements/header-minimal.html', 'File Upload') %> +% if ($error) { +Error: <% $error %> +% }else{ +File Upload Successful <% join(',', @filenames) %>; +% } +<% include('/elements/footer.html') %> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Import'); #? + +my @filenames = (); +my $error = '';     # could be extended to the access control + +$cgi->param('upload_fields') =~ /^([,\w]+)$/ +  or $error = "invalid upload_fields"; +my $fields = $1; + +my $dir = $FS::UID::cache_dir. "/cache.". $FS::UID::datasrc; + +foreach my $field (split /,/, $fields) { +  next if $error; + +  my $fh = $cgi->upload($field) +    or $error = "No valid file was provided."; + +  my $suffix = ''; +  if ( $cgi->param($field) =~ /(\.\w+)$/i ) { +    $suffix = lc($1); +  } + +  my $sh = new File::Temp( TEMPLATE => 'upload.XXXXXXXX', +                           SUFFIX   => $suffix, +                           DIR      => $dir, +                           UNLINK   => 0, +                         ) +    or $error ||= "can't open temporary file to store upload: $!\n"; + +  unless ($error) { +    while(<$fh>) { +      print $sh $_; +    } +    $sh->filename =~ m!.*/([.\w]+)$!; +    push @filenames,  "$field:$1"; +    close $sh +  } + +} + +$error = "No files" unless scalar(@filenames); + +</%init> diff --git a/httemplate/misc/ftp_invoices.cgi b/httemplate/misc/ftp_invoices.cgi new file mode 100644 index 000000000..9a072b99f --- /dev/null +++ b/httemplate/misc/ftp_invoices.cgi @@ -0,0 +1,9 @@ +<% $server->process %> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Resend invoices'); + +my $server = new FS::UI::Web::JSRPC 'FS::cust_bill::process_reftp', $cgi; + +</%init> diff --git a/httemplate/misc/inventory_item-import.html b/httemplate/misc/inventory_item-import.html new file mode 100644 index 000000000..c7edac609 --- /dev/null +++ b/httemplate/misc/inventory_item-import.html @@ -0,0 +1,68 @@ +<% include("/elements/header.html", PL($inventory_class->classname)) %> + +Import a file containing <% PL($inventory_class->classname) %>, one per line. +<BR><BR> + +<% include( '/elements/form-file_upload.html', +              'name'      => 'InventoryItemImportForm', +              'action'    => 'process/inventory_item-import.html', +              'num_files' => 1, +              #'fields'    => [ 'format', 'itembatch', 'classnum', ], +              'fields'    => [ 'format', 'classnum', ], +              'message'   => 'Inventory import successful', +              #XXX redirect via $itembatch?  or just back to class browse? +              #'url'       => $p."search/phone_avail.html?availbatch=$availbatch", +              'url'       => $p."search/inventory_item.html?classnum=$classnum;avail=1", +          ) +%> + +<% &ntable("#cccccc", 2) %> + +  <INPUT TYPE="hidden" NAME="format" VALUE="default"> + +  <INPUT TYPE="hidden" NAME="classnum" VALUE="<% $classnum %>"> + +%#  <INPUT TYPE="hidden" NAME="itembatch" VALUE="<% $itembatch %>"> + +  <% 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.InventoryItemImportForm.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'); + +$cgi->param('classnum') =~ /^(\d+)$/ or errorpage("illegal classnum"); +my $classnum = $1; +my $inventory_class = qsearchs('inventory_class', { 'classnum' => $classnum } ); + +#my $conf = new FS::Conf; +#my $itembatch = +#  time2str('webimport-%Y/%m/%d-%T'. "-$$-". rand() * 2**32, time); + +</%init> diff --git a/httemplate/misc/link.cgi b/httemplate/misc/link.cgi new file mode 100755 index 000000000..f37f769bc --- /dev/null +++ b/httemplate/misc/link.cgi @@ -0,0 +1,85 @@ +<% include("/elements/header.html","Link to existing $svc") %> + +<FORM ACTION="<% popurl(1) %>process/link.cgi" METHOD=POST> +% if ( $link_field ) {  + +  <INPUT TYPE="hidden" NAME="svcnum" VALUE=""> +  <INPUT TYPE="hidden" NAME="link_field" VALUE="<% $link_field %>"> +  <% $link_field %> of existing service: <INPUT TYPE="text" NAME="link_value"> +  <BR> +% if ( $link_field2 ) {  + +    <INPUT TYPE="hidden" NAME="link_field2" VALUE="<% $link_field2->{field} %>"> +    <% $link_field2->{'label'} %> of existing service:  +% if ( $link_field2->{'type'} eq 'select' ) {  +% if ( $link_field2->{'select_table'} ) {  + +        <SELECT NAME="link_value2"> +        <OPTION> </OPTION> +% foreach my $r ( qsearch( $link_field2->{'select_table'}, {})) {  +% my $key = $link_field2->{'select_key'};  +% my $label = $link_field2->{'select_label'};  + +          <OPTION VALUE="<% $r->$key() %>"><% $r->$label() %></OPTION> +% }  + +        </SELECT> +% } else {  + +        Don't know how to process secondary link field for <% $svcdb %> +        (type=>select but no select_table) +% }  +% } else {  + +      Don't know how to process secondary link field for <% $svcdb %> +        (unknown type <% $link_field2->{'type'} %>) +% }  + +    <BR> +% }  +% } else {  + +  Service # of existing service: <INPUT TYPE="text" NAME="svcnum" VALUE=""> +% }  + + +<INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $pkgnum %>"> +<INPUT TYPE="hidden" NAME="svcpart" VALUE="<% $svcpart %>"> +<BR><INPUT TYPE="submit" VALUE="Link"> +</FORM> + +<% include('/elements/footer.html') %> + +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('View/link unlinked services'); + +my %link_field = ( +  'svc_acct'    => 'username', +  'svc_domain'  => 'domain', +  'svc_phone'   => 'phonenum', +); + +my %link_field2 = ( +  'svc_acct'    => { label => 'Domain', +                     field => 'domsvc', +                     type  => 'select', +                     select_table => 'svc_domain', +                     select_key   => 'svcnum', +                     select_label => 'domain' +                   }, +); + +$cgi->param('pkgnum') =~ /^(\d+)$/ or die 'unparsable pkgnum'; +my $pkgnum = $1; +$cgi->param('svcpart') =~ /^(\d+)$/ or die 'unparsable svcpart'; +my $svcpart = $1; + +my $part_svc = qsearchs('part_svc',{'svcpart'=>$svcpart}); +my $svc = $part_svc->getfield('svc'); +my $svcdb = $part_svc->getfield('svcdb'); +my $link_field = $link_field{$svcdb}; +my $link_field2 = $link_field2{$svcdb}; + +</%init> diff --git a/httemplate/misc/location.cgi b/httemplate/misc/location.cgi new file mode 100644 index 000000000..419c59f2e --- /dev/null +++ b/httemplate/misc/location.cgi @@ -0,0 +1,19 @@ +<% objToJson(\%hash) %> +<%init> + +my $locationnum = $cgi->param('arg'); + +my $cust_location = qsearchs({ +  'select'    => 'cust_location.*', +  'table'     => 'cust_location', +  'hashref'   => { 'locationnum' => $locationnum }, +  'addl_from' => 'LEFT JOIN cust_main USING ( custnum )', +  'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, +}); + +my %hash = (); +%hash = map { $_ => $cust_location->$_() } +            qw( address1 address2 city county state zip country ) +  if $cust_location; + +</%init> diff --git a/httemplate/misc/meta-import.cgi b/httemplate/misc/meta-import.cgi new file mode 100644 index 000000000..8c158bd14 --- /dev/null +++ b/httemplate/misc/meta-import.cgi @@ -0,0 +1,79 @@ +<% include('/elements/header.html', 'Import') %> + +<FORM ACTION="process/meta-import.cgi" METHOD="post" ENCTYPE="multipart/form-data"> +Import data from a DBI data source<BR><BR> +% +%  #false laziness with edit/cust_main.cgi +%  my @agents = qsearch( 'agent', {} ); +%  die "No agents created!" unless @agents; +%  my $agentnum = $agents[0]->agentnum; #default to first +% +%  if ( scalar(@agents) == 1 ) { +% + +    <INPUT TYPE="hidden" NAME="agentnum" VALUE="<% $agentnum %>"> +% } else {  + +    <BR><BR>Agent <SELECT NAME="agentnum" SIZE="1"> +% foreach my $agent (sort { $a->agent cmp $b->agent } @agents) {  + +    <OPTION VALUE="<% $agent->agentnum %>" <% " SELECTED"x($agent->agentnum==$agentnum) %>><% $agent->agent %></OPTION> +% }  + +    </SELECT><BR><BR> +% }  +% +%  my @referrals = qsearch('part_referral',{}); +%  die "No advertising sources created!" unless @referrals; +%  my $refnum = $referrals[0]->refnum; #default to first +% +%  if ( scalar(@referrals) == 1 ) { +% + +    <INPUT TYPE="hidden" NAME="refnum" VALUE="<% $refnum %>"> +% } else {  + +    <BR><BR>Advertising source <SELECT NAME="refnum" SIZE="1"> +% foreach my $referral ( sort { $a->referral <=> $b->referral } @referrals) {  + +    <OPTION VALUE="<% $referral->refnum %>" <% " SELECTED"x($referral->refnum==$refnum) %>><% $referral->refnum %>: <% $referral->referral %></OPTION> +% }  + +    </SELECT><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_comment %></OPTION> +% }  + +</SELECT><BR><BR> + +  <table> +    <tr> +      <td align="right">DBI data source: </td> +      <td><INPUT TYPE="text" NAME="data_source"></td> +    </tr> +    <tr> +      <td align="right">DBI username: </td> +      <td><INPUT TYPE="text" NAME="username"></td> +    </tr> +    <tr> +      <td align="right">DBI password: </td> +      <td><INPUT TYPE="text" NAME="password"></td> +    </tr> +  </table> +  <INPUT TYPE="submit" VALUE="Import"> + +  </FORM> + +<% include('/elements/footer.html') %> + +<%init> + +#there's no ACL for this...  haven't used in ages +die 'meta-import not enabled; remove this if you want to use it'; + +</%init> diff --git a/httemplate/misc/order_pkg.html b/httemplate/misc/order_pkg.html new file mode 100644 index 000000000..a7571ca58 --- /dev/null +++ b/httemplate/misc/order_pkg.html @@ -0,0 +1,108 @@ +<% 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 () { +    if ( document.OrderPkgForm.pkgpart.selectedIndex > 0 ) { +      document.OrderPkgForm.submit.disabled = false; +    } else { +      document.OrderPkgForm.submit.disabled = true; +    } +  } + +</SCRIPT> + +<% include('/elements/error.html') %> + +<FORM NAME="OrderPkgForm" ACTION="<% $p %>edit/process/quick-cust_pkg.cgi" METHOD="POST"> + +<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">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, +               'disable_empty' => 1, +               'multiple'      => $conf->exists('pkg_referral-multiple'), +               'colspan'       => 7, +            ) +  %> +% } + +<% include('/elements/tr-select-cust_location.html', +             'cgi'       => $cgi, +             'cust_main' => $cust_main, +          ) +%> + +</TABLE> + +<BR> +<INPUT NAME="submit" TYPE="submit" VALUE="Order Package" <% $pkgpart ? '' : 'DISABLED' %>> + +</FORM> +</BODY> +</HTML> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Order customer package'); + +my $conf = new FS::Conf; + +$cgi->param('custnum') =~ /^(\d+)$/ or die "no custnum"; +my $custnum = $1; +my $cust_main = qsearchs({ +  'table'     => 'cust_main', +  'hashref'   => { 'custnum' => $custnum }, +  'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, +}); + +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 000000000..7bd640459 --- /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 000000000..060256154 --- /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 new file mode 100644 index 000000000..813b560bd --- /dev/null +++ b/httemplate/misc/payment.cgi @@ -0,0 +1,335 @@ +<% include( '/elements/header.html', "Process $type{$payby} payment" ) %> +<% include( '/elements/small_custview.html', $cust_main, '', '', popurl(2) . "view/cust_main.cgi" ) %> +<FORM NAME="OneTrueForm" ACTION="process/payment.cgi" METHOD="POST" onSubmit="document.OneTrueForm.process.disabled=true"> +<INPUT TYPE="hidden" NAME="custnum"   VALUE="<% $custnum %>"> +<INPUT TYPE="hidden" NAME="payby"     VALUE="<% $payby %>"> +<INPUT TYPE="hidden" NAME="payunique" VALUE="<% $payunique %>"> +<INPUT TYPE="hidden" NAME="balance"   VALUE="<% $balance %>"> + +<% include('/elements/init_overlib.html') %> + +% #include( '/elements/table.html', '#cccccc' )  + +<% ntable('#cccccc') %> +  <TR> +    <TH ALIGN="right">Payment amount</TH> +    <TD COLSPAN=7> +      <TABLE><TR><TD BGCOLOR="#ffffff"> +        <% $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'); +%   if ( $cust_main->payby =~ /^(CARD|DCRD)$/ ) { +%     $payinfo = $cust_main->paymask; +%     $paycvv = $cust_main->paycvv; +%     ( $month, $year ) = $cust_main->paydate_monthyear; +%     $payname = $cust_main->payname if $cust_main->payname; +%   } + +    <TR> +      <TH ALIGN="right">Card number</TH> +      <TD COLSPAN=7> +        <TABLE> +          <TR> +            <TD> +              <INPUT TYPE="text" NAME="payinfo" SIZE=20 MAXLENGTH=19 VALUE="<%$payinfo%>"> </TD> +            <TH>Exp.</TH> +            <TD> +              <SELECT NAME="month"> +% for ( ( map "0$_", 1 .. 9 ), 10 .. 12 ) {  + +                  <OPTION<% $_ == $month ? ' SELECTED' : '' %>><% $_ %> +% }  + +              </SELECT> +            </TD> +            <TD> / </TD> +            <TD> +              <SELECT NAME="year"> +% my @a = localtime; for ( $a[5]+1900 .. $a[5]+1915 ) {  + +                  <OPTION<% $_ == $year ? ' SELECTED' : '' %>><% $_ %> +% }  + +              </SELECT> +            </TD> +          </TR> +        </TABLE> +      </TD> +    </TR> +    <TR> +      <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> +      <TH ALIGN="right">Exact name on card</TH> +      <TD><INPUT TYPE="text" SIZE=32 MAXLENGTH=80 NAME="payname" VALUE="<%$payname%>"></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, +%       $stateid, $stateid_state ) +%     = ( '', '', '', '', '', '', '', '' ); +%   if ( $cust_main->payby =~ /^(CHEK|DCHK)$/ ) { +%     $cust_main->paymask =~ /^([\dx]+)\@([\dx]+)$/i +%       or die "unparsable payinfo ". $cust_main->payinfo; +%     ($payinfo1, $payinfo2) = ($1, $2); +%     $payname = $cust_main->payname; +%     $ss = $cust_main->ss; +%     $paytype = $cust_main->getfield('paytype'); +%     $paystate = $cust_main->getfield('paystate'); +%     $stateid = $cust_main->getfield('stateid'); +%     $stateid_state = $cust_main->getfield('stateid_state'); +%   } + +    <INPUT TYPE="hidden" NAME="month" VALUE="12"> +    <INPUT TYPE="hidden" NAME="year" VALUE="2037"> +    <TR> +      <TD ALIGN="right">Account number</TD> +      <TD><INPUT TYPE="text" SIZE=10 NAME="payinfo1" VALUE="<%$payinfo1%>"></TD> +      <TD ALIGN="right">Type</TD> +      <TD><SELECT NAME="paytype"><% join('', map { qq!<OPTION VALUE="$_" !.($paytype eq $_ ? 'SELECTED' : '').">$_</OPTION>" } @FS::cust_main::paytypes) %></SELECT></TD> +    </TR> +    <TR> +      <TD ALIGN="right">ABA/Routing number</TD> +      <TD> +        <INPUT TYPE="text" SIZE=10 MAXLENGTH=9 NAME="payinfo2" VALUE="<%$payinfo2%>"> +        (<A HREF="javascript:void(0);" onClick="overlib( OLiframeContent('../docs/ach.html', 380, 240, 'ach_popup' ), CAPTION, 'ACH Help', STICKY, AUTOSTATUSCAP, CLOSECLICK, DRAGGABLE ); return false;">help</A>) +      </TD> +    </TR> +    <TR> +      <TD ALIGN="right">Bank name</TD> +      <TD><INPUT TYPE="text" NAME="payname" VALUE="<%$payname%>"></TD> +    </TR> + +%   if ( $conf->exists('show_bankstate') ) { +      <TR> +        <TD ALIGN="right">Bank state</TD> +        <TD><% include('/elements/select-state.html', +                         'disable_empty' => 0, +                         'empty_label'   => '(choose)', +                         'state'         => $paystate, +                         'country'       => $cust_main->country, +                         'prefix'        => 'pay', +                      ) +            %> +        </TD> +      </TR> +%   } else { +      <INPUT TYPE="hidden" NAME="paystate" VALUE="<% $paystate %>"> +%   } + +%   if ( $conf->exists('show_ss') ) { +      <TR> +        <TD ALIGN="right"> +          Account holder<BR> +          Social security or tax ID # +        </TD> +        <TD><INPUT TYPE="text" NAME="ss" VALUE="<% $ss %>"></TD> +      </TR> +%   } else { +      <INPUT TYPE="hidden" NAME="ss" VALUE="<% $ss %>"></TD> +%   } + +%   if ( $conf->exists('show_stateid') ) { +      <TR> +        <TD ALIGN="right"> +          Account holder<BR> +          Driver’s license or state ID # +        </TD> +        <TD><INPUT TYPE="text" NAME="stateid" VALUE="<% $stateid %>"></TD> +        <TD ALIGN="right">State</TD> +        <TD><% include('/elements/select-state.html', +                         'disable_empty' => 0, +                         'empty_label'   => '(choose)', +                         'state'         => $stateid_state, +                         'country'       => $cust_main->country, +                         'prefix'        => 'stateid_', +                      ) +            %> +        </TD> +      </TR> +%   } else { +      <INPUT TYPE="hidden" NAME="stateid" VALUE="<% $stateid %>"> +      <INPUT TYPE="hidden" NAME="stateid_state" VALUE="<% $stateid_state %>"> +%   } + +% } #end CARD/CHEK-specific section + + +<TR> +  <TD COLSPAN=2> +    <INPUT TYPE="checkbox" CHECKED NAME="save" VALUE="1"> +    Remember this information +  </TD> +</TR> + +% if ( $conf->exists("batch-enable") +%      || grep $payby eq $_, $conf->config('batch-enable_payby') +%    ) { +% +%     if ( grep $payby eq $_, $conf->config('realtime-disable_payby') ) { + +          <INPUT TYPE="hidden" NAME="batch" VALUE="1"> + +%     } else { + +          <TR> +            <TD COLSPAN=2> +              <INPUT TYPE="checkbox" NAME="batch" VALUE="1"> +              Add to current batch +            </TD> +          </TR> + +%     } +% } + +<TR> +  <TD COLSPAN=2> +    <INPUT TYPE="checkbox"<% ( ( $payby eq 'CARD' && $cust_main->payby ne 'DCRD' ) || ( $payby eq 'CHEK' && $cust_main->payby eq 'CHEK' ) ) ? ' CHECKED' : '' %> NAME="auto" VALUE="1" onClick="if (this.checked) { document.OneTrueForm.save.checked=true; }"> +    Charge future payments to this <% $type{$payby} %> automatically +  </TD> +</TR> + +</TABLE> + +<BR> +<INPUT TYPE="submit" NAME="process" VALUE="Process payment"> +</FORM> + +<% include('/elements/footer.html') %> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Process payment'); + +my %type = ( 'CARD' => 'credit card', +             'CHEK' => 'electronic check (ACH)', +           ); + +$cgi->param('payby') =~ /^(CARD|CHEK)$/ +  or die "unknown payby ". $cgi->param('payby'); +my $payby = $1; + +$cgi->param('custnum') =~ /^(\d+)$/ +  or die "illegal custnum ". $cgi->param('custnum'); +my $custnum = $1; + +my $cust_main = qsearchs( 'cust_main', { 'custnum'=>$custnum } ); +die "unknown custnum $custnum" unless $cust_main; + +my $balance = $cust_main->balance; + +my $payinfo = ''; + +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/phone_avail-import.html b/httemplate/misc/phone_avail-import.html new file mode 100644 index 000000000..1f4d8caae --- /dev/null +++ b/httemplate/misc/phone_avail-import.html @@ -0,0 +1,88 @@ +<% include('/elements/header.html', 'Phone number (DID) import') %> + +Import a file containing phone numbers (DIDs). +<BR><BR> + +<% include( '/elements/form-file_upload.html', +              'name'      => 'PhonenumImportForm', +              'action'    => 'process/phone_avail-import.html', +              'num_files' => 1, +              'fields'    => [ 'format', 'availbatch', 'exportnum', 'countrycode' ], +              'message'   => 'DID import successful', +              'url'       => $p."search/phone_avail.html?availbatch=$availbatch", +          ) +%> + +<% &ntable("#cccccc", 2) %> + +  <INPUT TYPE="hidden" NAME="format" VALUE="default"> + +  <INPUT TYPE="hidden" NAME="availbatch" VALUE="<% $availbatch %>"> + +  <% include( '/elements/tr-select-table.html', +                'table'       => 'part_export', +                'name_col'    => 'machine', +                'label'       => 'Export', +                'empty_label' => 'Select export', +                'hashref'     => { 'exporttype' => 'internal_diddb', }, +                #'label_callback' =>  +            ) +  %> + +  <TR> +    <TH ALIGN="right">Country code</TH> +    <TD> +      <INPUT TYPE  = "text" +             NAME  = "countrycode" +             VALUE = "<% $conf->config('default_phone_countrycode') || 1 %>" +      > +    </TD> +  </TR> + +  <% 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.PhonenumImportForm.submit.disabled=true;" +      > +    </TD> +  </TR> + +</TABLE> + +</FORM> + +<BR> + +Uploaded files can be CSV (comma-separated value) files or Excel spreadsheets.  The file should have a .CSV or .XLS extension. +<BR><BR> + +<b>Default</b> format has the following field order: <i>state, number<i></i> +<BR><BR> + +Field information: +<ul> +  <li><i>state</i>: Two-letter state code, i.e. "CA" +  <li><i>number</i>: Phone number +</ul> + +<% include('/elements/footer.html') %> + +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Import'); + +my $conf = new FS::Conf; + +my $availbatch = +  time2str('webimport-%Y/%m/%d-%T'. "-$$-". rand() * 2**32, time); + +</%init> diff --git a/httemplate/misc/phonenums.cgi b/httemplate/misc/phonenums.cgi new file mode 100644 index 000000000..2ed0f617d --- /dev/null +++ b/httemplate/misc/phonenums.cgi @@ -0,0 +1,29 @@ +%# [ <% join(', ', map { qq("$_") } @exchanges) %> ] +<% objToJson(\@exchanges) %> +<%init> + +my( $exchangestring, $svcpart ) = $cgi->param('arg'); + +$exchangestring =~ /\((\d{3})-(\d{3})-XXXX\)\s*$/i +  or die "unparsable exchange: $exchangestring"; +my( $areacode, $exchange ) = ( $1, $2 ); +my $part_svc = qsearchs('part_svc', { 'svcpart'=>$svcpart } ); +die "unknown svcpart $svcpart" unless $part_svc; + +my @exports = $part_svc->part_export_did; +if ( scalar(@exports) > 1 ) { +  die "more than one DID-providing export attached to svcpart $svcpart"; +} elsif ( ! @exports ) { +  die "no DID providing export attached to svcpart $svcpart"; +} +my $export = $exports[0]; + +my $something = $export->get_dids('areacode'=>$areacode, +                                  'exchange'=>$exchange, +                                 ); + +#warn Dumper($something); + +my @exchanges = @{ $something }; + +</%init> diff --git a/httemplate/misc/ping.html b/httemplate/misc/ping.html new file mode 100644 index 000000000..4f0360e8b --- /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/print-invoice.cgi b/httemplate/misc/print-invoice.cgi new file mode 100755 index 000000000..aeef68795 --- /dev/null +++ b/httemplate/misc/print-invoice.cgi @@ -0,0 +1,19 @@ +<% $cgi->redirect("${p}view/cust_main.cgi?$custnum") %> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Resend invoices'); + +#untaint invnum +my($query) = $cgi->keywords; +$query =~ /^((.+)-)?(\d+)$/; +my $template = $2; +my $invnum = $3; +my $cust_bill = qsearchs('cust_bill',{'invnum'=>$invnum}); +die "Can't find invoice!\n" unless $cust_bill; + +$cust_bill->print($template); + +my $custnum = $cust_bill->getfield('custnum'); + +</%init> diff --git a/httemplate/misc/print_events.cgi b/httemplate/misc/print_events.cgi new file mode 100644 index 000000000..8d83d3de1 --- /dev/null +++ b/httemplate/misc/print_events.cgi @@ -0,0 +1,9 @@ +<% $server->process %> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Resend invoices'); + +my $server = new FS::UI::Web::JSRPC 'FS::cust_event::process_reprint', $cgi;  + +</%init> diff --git a/httemplate/misc/print_invoice_events.cgi b/httemplate/misc/print_invoice_events.cgi new file mode 100644 index 000000000..c974d5f4e --- /dev/null +++ b/httemplate/misc/print_invoice_events.cgi @@ -0,0 +1,9 @@ +<% $server->process %> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Resend invoices'); + +my $server = new FS::UI::Web::JSRPC 'FS::cust_bill_event::process_reprint', $cgi;  + +</%init> diff --git a/httemplate/misc/print_invoices.cgi b/httemplate/misc/print_invoices.cgi new file mode 100644 index 000000000..f859f6db8 --- /dev/null +++ b/httemplate/misc/print_invoices.cgi @@ -0,0 +1,9 @@ +<% $server->process %> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Resend invoices'); + +my $server = new FS::UI::Web::JSRPC 'FS::cust_bill::process_reprint', $cgi; + +</%init> diff --git a/httemplate/misc/process/batch-cust_pay.cgi b/httemplate/misc/process/batch-cust_pay.cgi new file mode 100644 index 000000000..058a2251a --- /dev/null +++ b/httemplate/misc/process/batch-cust_pay.cgi @@ -0,0 +1,47 @@ +%  die "access denied" +%    unless $FS::CurrentUser::CurrentUser->access_right('Post payment batch'); +% +%  my $param = $cgi->Vars; +% +%  #my $paybatch = $param->{'paybatch'}; +%  my $paybatch = time2str('webbatch-%Y/%m/%d-%T'. "-$$-". rand() * 2**32, time); +% +%  my @cust_pay = (); +%  #my $row = 0; +%  #while ( exists($param->{"custnum$row"}) ) { +%  for ( my $row = 0; exists($param->{"custnum$row"}); $row++ ) { +%    push @cust_pay, new FS::cust_pay { +%                                       'custnum'  => $param->{"custnum$row"}, +%                                       'paid'     => $param->{"paid$row"}, +%                                       'payby'    => 'BILL', +%                                       'payinfo'  => $param->{"payinfo$row"}, +%                                       'paybatch' => $paybatch, +%                                     } +%      if    $param->{"custnum$row"} +%         || $param->{"paid$row"} +%         || $param->{"payinfo$row"}; +%    #$row++; +%  } +% +%  my @errors = FS::cust_pay->batch_insert(@cust_pay); +%  my $num_errors = scalar(grep $_, @errors); +% +%  if ( $num_errors ) { +% +%    $cgi->param('error', "$num_errors error". ($num_errors>1 ? 's' : ''). +%                         ' - Batch not processed, correct and resubmit' +%               ); +% +%    my $erow=0; +%    $cgi->param('error'. $erow++, shift @errors) while @errors; +% +%     +<% $cgi->redirect($p.'batch-cust_pay.html?'. $cgi->query_string) + +  %> +% } else { +% +%     +<% $cgi->redirect(popurl(3). "search/cust_pay.cgi?magic=paybatch;paybatch=$paybatch") %> +% }  + diff --git a/httemplate/misc/process/bulk_change_pkg.cgi b/httemplate/misc/process/bulk_change_pkg.cgi new file mode 100755 index 000000000..e22dafef0 --- /dev/null +++ b/httemplate/misc/process/bulk_change_pkg.cgi @@ -0,0 +1,56 @@ +% if ($error) { +<% $cgi->redirect(popurl(2)."/bulk_change_pkg.cgi?".$cgi->query_string ) %> +% } +<% include('/elements/header-popup.html', "Packages Changed") %> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Bulk change customer packages'); + +my %search_hash = (); + +$search_hash{'query'} = $cgi->param('query'); + +for my $param (qw(agentnum magic status classnum pkgpart)) { +  $search_hash{$param} = $cgi->param($param) +    if $cgi->param($param); +} + +### +# parse dates +### + +#false laziness w/report_cust_pkg.html +my %disable = ( +  'all'             => {}, +  'one-time charge' => { 'last_bill'=>1, 'bill'=>1, 'adjourn'=>1, 'susp'=>1, 'expire'=>1, 'cancel'=>1, }, +  'active'          => { 'susp'=>1, 'cancel'=>1 }, +  'suspended'       => { 'cancel' => 1 }, +  'cancelled'       => {}, +  ''                => {}, +); + +foreach my $field (qw( setup last_bill bill adjourn susp expire cancel )) { + +  my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi, $field); + +  next if $beginning == 0 && $ending == 4294967295 +       or $disable{$cgi->param('status')}->{$field}; + +  $search_hash{$field} = [ $beginning, $ending ]; + +} + +my $sql_query = FS::cust_pkg->search(\%search_hash); +$sql_query->{'select'} = 'cust_pkg.pkgnum'; + +my $error = FS::cust_pkg::bulk_change( [ $cgi->param('new_pkgpart') ], +                                       [ map { $_->pkgnum } qsearch($sql_query) ], +                                     ); + +$cgi->param("error", substr($error, 0, 512)); # arbitrary length believed +                                              # suited for all supported +                                              # browsers + + +</%init> diff --git a/httemplate/misc/process/cancel_pkg.html b/httemplate/misc/process/cancel_pkg.html new file mode 100755 index 000000000..669af9c87 --- /dev/null +++ b/httemplate/misc/process/cancel_pkg.html @@ -0,0 +1,72 @@ +<% header("Package $past{$method}") %> +  <SCRIPT TYPE="text/javascript"> +    window.top.location.reload(); +  </SCRIPT> +  </BODY> +</HTML> +<%once> + +my %past = ( 'cancel'  => 'cancelled', +             'expire'  => 'expired', +             'suspend' => 'suspended', +             'adjourn' => 'adjourned', +           ); + +#i'm sure this is false laziness with somewhere, at least w/misc/cancel_pkg.html +my %right = ( 'cancel'  => 'Cancel customer package immediately', +              'expire'  => 'Cancel customer package later', +              'suspend' => 'Suspend customer package', +              'adjourn' => 'Suspend customer package later', +            ); + +</%once> +<%init> + +#untaint method +my $method = $cgi->param('method'); +$method =~ /^(cancel|expire|suspend|adjourn)$/ or die "Illegal method"; +$method = $1; + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right($right{$method}); + +#untaint pkgnum +my $pkgnum = $cgi->param('pkgnum'); +$pkgnum =~ /^(\d+)$/ or die "Illegal pkgnum"; +$pkgnum = $1; + +#untaint reasonnum +my $reasonnum = $cgi->param('reasonnum'); +$reasonnum =~ /^(-?\d+)$/ or die "Illegal reasonnum"; +$reasonnum = $1; + +my $date = time; +if ($method eq 'expire' || $method eq 'adjourn'){ +  #untaint date +  $date = $cgi->param('date'); +  str2time($cgi->param('date')) =~ /^(\d+)$/ or die "Illegal date"; +  $date = $1; +  $method = ($method eq 'expire') ? 'cancel' : 'suspend'; +} + +my $cust_pkg = qsearchs( 'cust_pkg', {'pkgnum'=>$pkgnum} ); + +#my $otaker = $FS::CurrentUser::CurrentUser->name; +#$otaker = $FS::CurrentUser::CurrentUser->username +#  if ($otaker eq "User, Legacy"); + +if ($reasonnum == -1) { +  $reasonnum = { +    'typenum' => scalar( $cgi->param('newreasonnumT') ), +    'reason'  => scalar( $cgi->param('newreasonnum' ) ), +  }; +} + +my $error = $cust_pkg->$method( 'reason' => $reasonnum, 'date' => $date ); + +if ($error) { +  $cgi->param('error', $error); +  print $cgi->redirect(popurl(2). "cancel_pkg.html?". $cgi->query_string ); +} + +</%init> diff --git a/httemplate/misc/process/catchall.cgi b/httemplate/misc/process/catchall.cgi new file mode 100755 index 000000000..0dda2eada --- /dev/null +++ b/httemplate/misc/process/catchall.cgi @@ -0,0 +1,35 @@ +%if ($error) { +%  $cgi->param('error', $error); +<% $cgi->redirect(popurl(2). "catchall.cgi?". $cgi->query_string ) %> +%} else { +<% $cgi->redirect(popurl(3). "view/svc_domain.cgi?$svcnum") %> +%} +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Edit domain catchall'); + +$FS::svc_domain::whois_hack=1; + +$cgi->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!"; +my $svcnum =$1; + +my $old = qsearchs('svc_domain',{'svcnum'=>$svcnum}) if $svcnum; + +my $new = new FS::svc_domain ( { +  map { +    ($_, scalar($cgi->param($_))); +  } ( fields('svc_domain'), qw( pkgnum svcpart ) ) +} ); + +$new->setfield('action' => 'M'); + +my $error; +if ( $svcnum ) { +  $error = $new->replace($old); +} else { +  $error = $new->insert; +  $svcnum = $new->getfield('svcnum'); +}  + +</%init> diff --git a/httemplate/misc/process/cdr-import.html b/httemplate/misc/process/cdr-import.html new file mode 100644 index 000000000..edc441e35 --- /dev/null +++ b/httemplate/misc/process/cdr-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::cdr::process_batch_import', $cgi; + +</%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> diff --git a/httemplate/misc/process/cust_main-import.cgi b/httemplate/misc/process/cust_main-import.cgi new file mode 100644 index 000000000..2b705a6fc --- /dev/null +++ b/httemplate/misc/process/cust_main-import.cgi @@ -0,0 +1,10 @@ +<% $server->process %> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Import'); + +my $server = +  new FS::UI::Web::JSRPC 'FS::cust_main::Import::process_batch_import', $cgi; + +</%init> diff --git a/httemplate/misc/process/cust_main-import_charges.cgi b/httemplate/misc/process/cust_main-import_charges.cgi new file mode 100644 index 000000000..3ca68944a --- /dev/null +++ b/httemplate/misc/process/cust_main-import_charges.cgi @@ -0,0 +1,23 @@ +% if ( $error ) { +%   errorpage($error); +%  } else { +     <% include('/elements/header.html','Import successful') %>  +     <% include('/elements/footer.html') %>  +%  } +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Import'); + +my $fh = $cgi->upload('csvfile'); +#warn $cgi; +#warn $fh; + +my $error = defined($fh) +  ? FS::cust_main::batch_charge( { +      filehandle => $fh, +      'fields'    => [qw( custnum amount pkg )], +    } ) +  : 'No file'; + +</%init> diff --git a/httemplate/misc/process/cust_main_note-import.cgi b/httemplate/misc/process/cust_main_note-import.cgi new file mode 100644 index 000000000..6aa8b1d37 --- /dev/null +++ b/httemplate/misc/process/cust_main_note-import.cgi @@ -0,0 +1,82 @@ +<% include("/elements/header.html", "Batch Customer Note Import $op") %> + +The following items <% $op eq 'Preview' ? 'would not be' : 'were not' %> imported.  (See below for imported items) +<PRE> +%  foreach my $row (@uninserted) { +%    $csv->combine( (map{ $row->{$_} } qw(last first note) ), +%                   $row->{error} ? ('#!', $row->{error}) : (), +%                 ); +<% $csv->string %> +%  } +</PRE> + +The following items <% $op eq 'Preview' ? 'would be' : 'were' %> imported.  (See above for unimported items) + +<PRE> +%  foreach my $row (@inserted) { +%    $csv->combine( (map{ $row->{$_} } qw(custnum last first note) ), +%                   ('#!', $row->{name}), +%                 ); +<% $csv->string %> +%  } +</PRE> +   +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Import'); + +my $date = time; +my $otaker = $FS::CurrentUser::CurrentUser->username; +my $csv = new Text::CSV_XS; + +my $param = $cgi->Vars; + +my $op = $param->{preview} ? "Preview" : "Results"; + +my @inserted = (); +my @uninserted = (); +for ( my $row = 0; exists($param->{"custnum$row"}); $row++ ) { +  if ( $param->{"custnum$row"} ) { +#    my $cust_main_note = new FS::cust_main_note { +#                                          'custnum'  => $param->{"custnum$row"}, +#                                          '_date'    => $date, +#                                          'otaker'   => $otaker, +#                                          'comments' => $param->{"note$row"}, +#                                                }; +#    my $error = ''; +#    $error = $cust_main_note->insert unless ($op eq "Preview"); +    my $cust_main = qsearchs('cust_main', +                             { 'custnum' => $param->{"custnum$row"} } +                            ); +    my $error; +    if ($cust_main) { +      $cust_main->comments +        ? $cust_main->comments($cust_main->comments. " ". $param->{"note$row"}) +        : $cust_main->comments($param->{"note$row"}); +      $error = $cust_main->replace; +    }else{ +      $error = "Can't find customer " . $param->{"custnum$row"}; +    } +    my $result = { 'custnum' => $param->{"custnum$row"}, +                   'last'    => $param->{"last$row"}, +                   'first'   => $param->{"first$row"}, +                   'note'    => $param->{"note$row"}, +                   'name'    => $param->{"name$row"}, +                   'error'   => $error, +                 }; +    if ($error) { +      push @uninserted, $result; +    }else{ +      push @inserted, $result; +    } +  }else{ +    push @uninserted, { 'custnum' => '', +                        'last'    => $param->{"last$row"}, +                        'first'   => $param->{"first$row"}, +                        'note'    => $param->{"note$row"}, +                        'error'   => '', +                      }; +  } +} +</%init> diff --git a/httemplate/misc/process/cust_pay-import.cgi b/httemplate/misc/process/cust_pay-import.cgi new file mode 100644 index 000000000..d4ff226ec --- /dev/null +++ b/httemplate/misc/process/cust_pay-import.cgi @@ -0,0 +1,21 @@ +<% $cgi->redirect(popurl(3). "search/cust_pay.cgi?magic=paybatch;paybatch=$paybatch") %>  +<%init> + +my $fh = $cgi->upload('csvfile'); + +# webbatch?  I suppose +my $paybatch = time2str('webbatch-%Y/%m/%d-%T'. "-$$-". rand() * 2**32, time); + +my $error = defined($fh) +  ? FS::cust_pay::batch_import( { +      'filehandle' => $fh, +      'agentnum'   => scalar($cgi->param('agentnum')), +      'format'     => scalar($cgi->param('format')), +      'paybatch'   => $paybatch, +    } ) +  : 'No file'; + +errorpage($error) +  if ( $error ); + +</%init> diff --git a/httemplate/misc/process/delay_susp_pkg.html b/httemplate/misc/process/delay_susp_pkg.html new file mode 100755 index 000000000..c7cc7de7c --- /dev/null +++ b/httemplate/misc/process/delay_susp_pkg.html @@ -0,0 +1,41 @@ +<% header("Package suspension delayed") %> +  <SCRIPT TYPE="text/javascript"> +    window.top.location.reload(); +  </SCRIPT> +  </BODY> +</HTML> +<%once> + +my $right = 'Delay suspension events'; + +</%once> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right($right); + +my ($pkgnum, $date, $cust_pkg, $cust_main, $error); + +#untaint pkgnum +$cgi->param('pkgnum') =~ /^(\d+)$/ or die "Illegal pkgnum"; +$pkgnum = $1; + +#untaint date +str2time($cgi->param('date')) =~ /^(\d+)$/ or die "Illegal date"; +my $date = $1; + +$cust_pkg = qsearchs( 'cust_pkg', {'pkgnum'=>$pkgnum} ); +if ($cust_pkg) { +  $cust_main = $cust_pkg->cust_main; +  $cust_main->dundate( $date ); +  $error = $cust_main->replace; +} else { +  $error = "Invalid pkgnum"; +} + +if ($error) { +  $cgi->param('error', $error); +  print $cgi->redirect(popurl(2). "cancel_pkg.html?". $cgi->query_string ); +} + +</%init> diff --git a/httemplate/misc/process/delete-customer.cgi b/httemplate/misc/process/delete-customer.cgi new file mode 100755 index 000000000..d509a5e0e --- /dev/null +++ b/httemplate/misc/process/delete-customer.cgi @@ -0,0 +1,33 @@ +%if ( $error ) { +%  $cgi->param('error', $error); +<% $cgi->redirect(popurl(2). "delete-customer.cgi?". $cgi->query_string ) %> +%} elsif ( $new_custnum ) { +<% $cgi->redirect(popurl(3). "view/cust_main.cgi?$new_custnum") %> +%} else { +<% $cgi->redirect(popurl(3)) %> +%} +<%init> + +my $conf = new FS::Conf; +die "Customer deletions not enabled in configuration" +  unless $conf->exists('deletecustomers'); + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Delete customer'); + +$cgi->param('custnum') =~ /^(\d+)$/; +my $custnum = $1; +my $new_custnum; +if ( $cgi->param('new_custnum') ) { +  $cgi->param('new_custnum') =~ /^(\d+)$/ +    or die "Illegal new customer number: ". $cgi->param('new_custnum'); +  $new_custnum = $1; +} else { +  $new_custnum = ''; +} +my $cust_main = qsearchs( 'cust_main', { 'custnum' => $custnum } ) +  or die "Customer not found: $custnum"; + +my $error = $cust_main->delete($new_custnum); + +</%init> diff --git a/httemplate/misc/process/email-customers.html b/httemplate/misc/process/email-customers.html new file mode 100644 index 000000000..c54bc6dca --- /dev/null +++ b/httemplate/misc/process/email-customers.html @@ -0,0 +1,9 @@ +<% $server->process %> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Bulk send customer notices'); + +my $server = new FS::UI::Web::JSRPC 'FS::cust_main::process_email_search_result', $cgi;  + +</%init> diff --git a/httemplate/misc/process/enable_or_disable_tax.html b/httemplate/misc/process/enable_or_disable_tax.html new file mode 100755 index 000000000..9b7324b0d --- /dev/null +++ b/httemplate/misc/process/enable_or_disable_tax.html @@ -0,0 +1,41 @@ +%if ($error) { +<% $cgi->redirect(popurl(2).'enable_or_disable_tax.html?'.$cgi->query_string) %> +%}else{ +  <% include('/elements/header-popup.html', $title) %> + +  <SCRIPT TYPE="text/javascript"> +    window.top.location.reload(); +  </SCRIPT> + +  </BODY> +  </HTML> +%} +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); + +my $action = ''; +if ( $cgi->param('action') =~ /^(\w+)$/ ) { +  $action = $1; +} + +my ($query, $count_query) = FS::tax_rate::browse_queries(scalar($cgi->Vars)); +my @tax_rate = qsearch( $query ); + +#transaction? +my $error; +$error = "Invalid action" unless ($action =~ /enable|disable/); + +foreach my $tax_rate (@tax_rate) { +  $action eq 'enable' ? $tax_rate->disabled('') : $tax_rate->disabled('Y'); +  # $tax_rate->manual('Y'); +  $error ||= $tax_rate->replace; +  last if $error; +} +$cgi->param('error', $error) if $error; + +my $title = scalar(@tax_rate) == 1 ? 'Tax rate ' : 'Tax rates '; +$title .= lc($action). 'd'; + +</%init> diff --git a/httemplate/misc/process/inventory_item-import.html b/httemplate/misc/process/inventory_item-import.html new file mode 100644 index 000000000..377943fb1 --- /dev/null +++ b/httemplate/misc/process/inventory_item-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::inventory_item::process_batch_import', $cgi; + +</%init> diff --git a/httemplate/misc/process/link.cgi b/httemplate/misc/process/link.cgi new file mode 100755 index 000000000..77546f3f7 --- /dev/null +++ b/httemplate/misc/process/link.cgi @@ -0,0 +1,78 @@ +%unless ($error) { +%  #no errors, so let's view this customer. +%  my $custnum = $new->cust_pkg->custnum; +%  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 $curuser->access_right('View/link unlinked services'); + +my $DEBUG = 0; + +$cgi->param('pkgnum') =~ /^(\d+)$/; +my $pkgnum = $1; +$cgi->param('svcpart') =~ /^(\d+)$/; +my $svcpart = $1; +$cgi->param('svcnum') =~ /^(\d*)$/; +my $svcnum = $1; + +unless ( $svcnum ) { +  my $part_svc = qsearchs('part_svc',{'svcpart'=>$svcpart}); +  my $svcdb = $part_svc->getfield('svcdb'); +  $cgi->param('link_field') =~ /^(\w+)$/; +  my $link_field = $1; +  my %search = ( $link_field => $cgi->param('link_value') ); +  if ( $cgi->param('link_field2') =~ /^(\w+)$/ ) { +    $search{$1} = $cgi->param('link_value2'); +  } + +  my @svc_x = ( sort { ($a->cust_svc->pkgnum > 0) <=> ($b->cust_svc->pkgnum > 0) +                       or ($b->cust_svc->svcpart == $svcpart) +                            <=> ($a->cust_svc->svcpart == $svcpart) +                     } +                     qsearch( $svcdb, \%search ) +              ); + +  if ( $DEBUG ) { +    warn scalar(@svc_x). " candidate accounts found for linking ". +         "(svcpart $svcpart):\n"; +    foreach my $svc_x ( @svc_x ) { +      warn "  ". $svc_x->email. +           " (svcnum ". $svc_x->svcnum. ",". +           " pkgnum ".  $svc_x->cust_svc->pkgnum. ",". +           " svcpart ". $svc_x->cust_svc->svcpart. ")\n"; +    } +  } + +  my $svc_x = $svc_x[0]; + +  errorpage("$link_field not found!") unless $svc_x; + +  $svcnum = $svc_x->svcnum; + +} + +my $old = qsearchs('cust_svc',{'svcnum'=>$svcnum}); +die "svcnum not found!" unless $old; +my $conf = new FS::Conf; +my($error, $new); +if ( $old->pkgnum && ! $conf->exists('legacy_link-steal') ) { +  $error = "svcnum $svcnum already linked to package ". $old->pkgnum; +} else { +  $new = new FS::cust_svc { $old->hash }; +  $new->pkgnum($pkgnum); +  $new->svcpart($svcpart); + +  $error = $new->replace($old); +} + +</%init> diff --git a/httemplate/misc/process/meta-import.cgi b/httemplate/misc/process/meta-import.cgi new file mode 100644 index 000000000..68ae49c60 --- /dev/null +++ b/httemplate/misc/process/meta-import.cgi @@ -0,0 +1,190 @@ +<% include("/elements/header.html",'Map tables') %> + +<SCRIPT> +var gSafeOnload = new Array(); +var gSafeOnsubmit = new Array(); +window.onload = SafeOnload; +function SafeAddOnLoad(f) { +  gSafeOnload[gSafeOnload.length] = f; +} +function SafeOnload() { +  for (var i=0;i<gSafeOnload.length;i++) +    gSafeOnload[i](); +} +function SafeAddOnSubmit(f) { +  gSafeOnsubmit[gSafeOnsubmit.length] = f; +} +function SafeOnsubmit() { +  for (var i=0;i<gSafeOnsubmit.length;i++) +    gSafeOnsubmit[i](); +} +</SCRIPT> + +<FORM NAME="OneTrueForm" METHOD="POST" ACTION="meta-import.cgi"> +% +%  #use DBIx::DBSchema; +%  my $schema = new_native DBIx::DBSchema +%                 map { $cgi->param($_) } qw( data_source username password ); +%  foreach my $field (qw( data_source username password )) {  + +    <INPUT TYPE="hidden" NAME=<% $field %> VALUE="<% $cgi->param($field) %>"> +% } +% +%  my %schema; +%  use Tie::DxHash; +%  tie %schema, 'Tie::DxHash'; +%  if ( $cgi->param('schema') ) { +%    my $schema_string = $cgi->param('schema'); +%     + <INPUT TYPE="hidden" NAME="schema" VALUE="<%$schema_string%>">  +% +%    %schema = map { /^\s*(\w+)\s*=>\s*(\w+)\s*$/ +%                      or die "guru meditation #420: $_"; +%                    ( $1 => $2 ); +%                  } +%              split( /\n/, $schema_string ); +%  } +% +%  #first page +%  unless ( $cgi->param('magic') ) {  + + +    <INPUT TYPE="hidden" NAME="magic" VALUE="process"> +    <% hashmaker('schema', [ $schema->tables ], +                            [ grep !/^h_/, dbdef->tables ],  ) %> +    <br><INPUT TYPE="submit" VALUE="done"> +% +% +%  #second page +%  } elsif ( $cgi->param('magic') eq 'process' ) {  + + +    <INPUT TYPE="hidden" NAME="magic" VALUE="process2"> +% +% +%    my %unique; +%    foreach my $table ( keys %schema ) { +% +%      my @from_columns = $schema->table($table)->columns; +%      my @fs_columns = dbdef->table($schema{$table})->columns; +% +%       + +      <% hashmaker( $table.'__'.$unique{$table}++, +                     \@from_columns => \@fs_columns, +                     $table         =>  $schema{$table}, ) %> +      <br><hr><br> +% +% +%    } +% +%     + +    <br><INPUT TYPE="submit" VALUE="done"> +% +% +%  #third (results) +%  } elsif ( $cgi->param('magic') eq 'process2' ) { +% +%    print "<pre>\n"; +% +%    my %unique; +%    foreach my $table ( keys %schema ) { +%      ( my $spaces = $table ) =~ s/./ /g; +%      print "'$table' => { 'table' => '$schema{$table}',\n". +%            #(length($table) x ' '). "         'map'   => {\n"; +%            "$spaces        'map'   => {\n"; +%      my %map = map { /^\s*(\w+)\s*=>\s*(\w+)\s*$/ +%                         or die "guru meditation #420: $_"; +%                       ( $1 => $2 ); +%                     } +%                 split( /\n/, $cgi->param($table.'__'.$unique{$table}++) ); +%      foreach ( keys %map ) { +%        print "$spaces                     '$_' => '$map{$_}',\n"; +%      } +%      print "$spaces                   },\n"; +%      print "$spaces      },\n"; +% +%    } +%    print "\n</pre>"; +% +%  } else { +%    warn "unrecognized magic: ". $cgi->param('magic'); +%  } +% +%   + +</FORM> +</BODY> +</HTML> +% +%  #hashmaker widget +%  sub hashmaker { +%    my($name, $from, $to, $labelfrom, $labelto) = @_; +%    my $fromsize = scalar(@$from); +%    my $tosize = scalar(@$to); +%    "<TABLE><TR><TH>$labelfrom</TH><TH>$labelto</TH></TR><TR><TD>". +%        qq!<SELECT NAME="${name}_from" SIZE=$fromsize>\n!. +%        join("\n", map { qq!<OPTION VALUE="$_">$_</OPTION>! } sort { $a cmp $b } @$from ). +%        "</SELECT>\n<BR>". +%      qq!<INPUT TYPE="button" VALUE="refill" onClick="repack_${name}_from()">!. +%      '</TD><TD>'. +%        qq!<SELECT NAME="${name}_to" SIZE=$tosize>\n!. +%        join("\n", map { qq!<OPTION VALUE="$_">$_</OPTION>! } sort { $a cmp $b } @$to ). +%        "</SELECT>\n<BR>". +%      qq!<INPUT TYPE="button" VALUE="refill" onClick="repack_${name}_to()">!. +%      '</TD></TR>'. +%      '<TR><TD COLSPAN=2>'. +%        qq!<INPUT TYPE="button" VALUE="map" onClick="toke_$name(this.form)">!. +%      '</TD></TR><TR><TD COLSPAN=2>'. +%      qq!<TEXTAREA NAME="$name" COLS=80 ROWS=8></TEXTAREA>!. +%      '</TD></TR></TABLE>'. +%      "<script> +%            function toke_$name() { +%              fromObject = document.OneTrueForm.${name}_from; +%              for (var i=fromObject.options.length-1;i>-1;i--) { +%                if (fromObject.options[i].selected) +%                  fromname = deleteOption_$name(fromObject,i); +%              } +%              toObject = document.OneTrueForm.${name}_to; +%              for (var i=toObject.options.length-1;i>-1;i--) { +%                if (toObject.options[i].selected) +%                  toname = deleteOption_$name(toObject,i); +%              } +%              document.OneTrueForm.$name.value = document.OneTrueForm.$name.value + fromname + ' => ' + toname + '\\n'; +%            } +%            function deleteOption_$name(object,index) { +%              value = object.options[index].value; +%              object.options[index] = null; +%              return value; +%            } +%            function repack_${name}_from() { +%              var object = document.OneTrueForm.${name}_from; +%              object.options.length = 0; +%              ". join("\n",  +%                   map { "addOption_$name(object, '$_');\n" } +%                       ( sort { $a cmp $b } @$from )           ). " +%            } +%            function repack_${name}_to() { +%              var object = document.OneTrueForm.${name}_to; +%              object.options.length = 0; +%              ". join("\n",  +%                   map { "addOption_$name(object, '$_');\n" } +%                       ( sort { $a cmp $b } @$to )           ). " +%            } +%            function addOption_$name(object,value) { +%              var length = object.length; +%              object.options[length] = new Option(value, value, false, false); +%            } +%      </script>". +%      ''; +%  } +% +% +<%init> + +#there's no ACL for this...  haven't used in ages +#make XSS-safe if this is used for more than just admins to import data.... +die 'meta-import not enabled; remove this if you want to use it'; + +</%init> diff --git a/httemplate/misc/process/part_device-import.html b/httemplate/misc/process/part_device-import.html new file mode 100644 index 000000000..eac111a40 --- /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 new file mode 100644 index 000000000..1e9501df8 --- /dev/null +++ b/httemplate/misc/process/payment.cgi @@ -0,0 +1,204 @@ +% if ( $cgi->param('batch') ) { + +  <% include( '/elements/header.html', ucfirst($type{$payby}). ' processing successful', +                 include('/elements/menubar.html'), + +            ) +  %> + +  <% include( '/elements/small_custview.html', $cust_main, '', '', popurl(3). "view/cust_main.cgi" ) %> + +  <% include('/elements/footer.html') %> + +% } else { +<% $cgi->redirect(popurl(3). "view/cust_pay.html?paynum=$paynum" ) %> +% } +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Process payment'); + +#some false laziness w/MyAccount::process_payment + +$cgi->param('custnum') =~ /^(\d+)$/ +  or die "illegal custnum ". $cgi->param('custnum'); +my $custnum = $1; + +my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ); +die "unknown custnum $custnum" unless $cust_main; + +$cgi->param('amount') =~ /^\s*(\d*(\.\d\d)?)\s*$/ +  or errorpage("illegal amount ". $cgi->param('amount')); +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; + +$cgi->param('month') =~ /^(\d+)$/ +  or errorpage("illegal month ". $cgi->param('month')); +my $month = $1; + +$cgi->param('payby') =~ /^(CARD|CHEK)$/ +  or errorpage("illegal payby ". $cgi->param('payby')); +my $payby = $1; +my %payby2fields = ( +  'CARD' => [ qw( address1 address2 city county state zip country ) ], +  'CHEK' => [ qw( ss paytype paystate stateid stateid_state ) ], +); +my %type = ( 'CARD' => 'credit card', +             'CHEK' => 'electronic check (ACH)', +           ); + +$cgi->param('payname') =~ /^([\w \,\.\-\']+)$/ +  or errorpage(gettext('illegal_name'). " payname: ". $cgi->param('payname')); +my $payname = $1; + +$cgi->param('payunique') =~ /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=]*)$/ +  or errorpage(gettext('illegal_text'). " payunique: ". $cgi->param('payunique')); +my $payunique = $1; + +$cgi->param('balance') =~ /^\s*(\-?\s*\d*(\.\d\d)?)\s*$/ +  or errorpage("illegal balance"); +my $balance = $1; + +my $payinfo; +my $paycvv = ''; +if ( $payby eq 'CHEK' ) { + +  if ($cgi->param('payinfo1') =~ /xx/i || $cgi->param('payinfo2') =~ /xx/i ) { +    $payinfo = $cust_main->payinfo; +  } else { +    $cgi->param('payinfo1') =~ /^(\d+)$/ +      or errorpage("illegal account number ". $cgi->param('payinfo1')); +    my $payinfo1 = $1; +    $cgi->param('payinfo2') =~ /^(\d+)$/ +      or errorpage("illegal ABA/routing number ". $cgi->param('payinfo2')); +    my $payinfo2 = $1; +    $payinfo = $payinfo1. '@'. $payinfo2; +  } + +} elsif ( $payby eq 'CARD' ) { + +  $payinfo = $cgi->param('payinfo'); +  if ($payinfo eq $cust_main->paymask) { +    $payinfo = $cust_main->payinfo; +  } +  $payinfo =~ s/\D//g; +  $payinfo =~ /^(\d{13,16})$/ +    or errorpage(gettext('invalid_card')); # . ": ". $self->payinfo; +  $payinfo = $1; +  validate($payinfo) +    or errorpage(gettext('invalid_card')); # . ": ". $self->payinfo; +  errorpage(gettext('unknown_card_type')) +    if cardtype($payinfo) eq "Unknown"; + +  if ( defined $cust_main->dbdef_table->column('paycvv') ) { +    if ( length($cgi->param('paycvv') ) ) { +      if ( cardtype($payinfo) eq 'American Express card' ) { +        $cgi->param('paycvv') =~ /^(\d{4})$/ +          or errorpage("CVV2 (CID) for American Express cards is four digits."); +        $paycvv = $1; +      } else { +        $cgi->param('paycvv') =~ /^(\d{3})$/ +          or errorpage("CVV2 (CVC2/CID) is three digits."); +        $paycvv = $1; +      } +    } +  } + +} else { +  die "unknown payby $payby"; +} + +my $error = ''; +my $paynum = ''; +if ( $cgi->param('batch') ) { + +  $error = $cust_main->batch_card( +                                   'payby'    => $payby, +                                   'amount'   => $amount, +                                   'payinfo'  => $payinfo, +                                   'paydate'  => "$year-$month-01", +                                   'payname'  => $payname, +                                   map { $_ => $cgi->param($_) }  +                                     @{$payby2fields{$payby}} +                                 ); +  errorpage($error) if $error; + +} else { + +  $error = $cust_main->realtime_bop( $FS::payby::payby2bop{$payby}, $amount, +    'quiet'      => 1, +    'manual'     => 1, +    'balance'    => $balance, +    'payinfo'    => $payinfo, +    'paydate'    => "$year-$month-01", +    'payname'    => $payname, +    'payunique'  => $payunique, +    'paycvv'     => $paycvv, +    'paynum_ref' => \$paynum, +    map { $_ => $cgi->param($_) } @{$payby2fields{$payby}} +  ); +  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; + +} + +if ( $cgi->param('save') ) { +  my $new = new FS::cust_main { $cust_main->hash }; +  if ( $payby eq 'CARD' ) {  +    $new->set( 'payby' => ( $cgi->param('auto') ? 'CARD' : 'DCRD' ) ); +  } elsif ( $payby eq 'CHEK' ) { +    $new->set( 'payby' => ( $cgi->param('auto') ? 'CHEK' : 'DCHK' ) ); +  } else { +    die "unknown payby $payby"; +  } +  $new->set( 'payinfo' => $payinfo ); +  $new->set( 'paydate' => "$year-$month-01" ); +  $new->set( 'payname' => $payname ); + +  #false laziness w/FS:;cust_main::realtime_bop - check both to make sure +  # working correctly +  my $conf = new FS::Conf; +  if ( $payby eq 'CARD' && +       grep { $_ eq cardtype($payinfo) } $conf->config('cvv-save') ) { +    $new->set( 'paycvv' => $paycvv ); +  } else { +    $new->set( 'paycvv' => ''); +  } + +  $new->set( $_ => $cgi->param($_) ) foreach @{$payby2fields{$payby}}; + +  my $error = $new->replace($cust_main); +  errorpage("payment processed successfully, but error saving info: $error") +    if $error; +  $cust_main = $new; +} + +#success! + +</%init> diff --git a/httemplate/misc/process/phone_avail-import.html b/httemplate/misc/process/phone_avail-import.html new file mode 100644 index 000000000..f1a2f2493 --- /dev/null +++ b/httemplate/misc/process/phone_avail-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::phone_avail::process_batch_import', $cgi; + +</%init> diff --git a/httemplate/misc/process/rate_edit_excel.html b/httemplate/misc/process/rate_edit_excel.html new file mode 100644 index 000000000..acd5f4995 --- /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 new file mode 100755 index 000000000..5f68bf151 --- /dev/null +++ b/httemplate/misc/process/recharge_svc.html @@ -0,0 +1,91 @@ +%if ($error) { +%  $cgi->param('error', $error); +<% $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; + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Recharge customer service'); + +#untaint svcnum +my $svcnum = $cgi->param('svcnum'); +$svcnum =~ /^(\d+)$/ || die "Illegal svcnum"; +$svcnum = $1; + +#untaint prepaid +my $prepaid = $cgi->param('prepaid'); +$prepaid =~ /^(\w*)$/; +$prepaid = $1; + +#untaint payby +my $payby = $cgi->param('payby'); +$payby =~ /^([A-Z]*)$/; +$payby = $1; + +my $error = ''; +my $svc_acct = qsearchs( 'svc_acct', {'svcnum'=>$svcnum} ); +$error = "Can't recharge service $svcnum. " unless $svc_acct; + +my $cust_main = $svc_acct->cust_svc->cust_pkg->cust_main; + +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/recharge_svc.new b/httemplate/misc/process/recharge_svc.new new file mode 100755 index 000000000..bc916e5da --- /dev/null +++ b/httemplate/misc/process/recharge_svc.new @@ -0,0 +1,85 @@ +% +% +%#untaint svcnum +%my $svcnum = $cgi->param('svcnum'); +%$svcnum =~ /^(\d+)$/ || die "Illegal svcnum"; +%$svcnum = $1; +% +%#untaint prepaid +%my $prepaid = $cgi->param('prepaid'); +%$prepaid =~ /^(\w*)$/; +%$prepaid = $1; + +%#untaint payby +%my $payby = $cgi->param('payby'); +%$payby =~ /^([A-Z]*)$/; +%$payby = $1; +% +%my $error = ''; +%my $svc_acct = qsearchs( 'svc_acct', {'svcnum'=>$svcnum} ); +%$error = "Can't recharge service $svcnum. " unless $svc_acct; +% +%my $cust_main = $svc_acct->cust_svc->cust_pkg->cust_main; +% +%my $oldAutoCommit = $FS::UID::AutoCommit; +%local $FS::UID::AutoCommit = 0; +%my $dbh = dbh; +% +% +%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($_, 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); +% +%    $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; +% +<% header("Package recharged") %> +  <SCRIPT TYPE="text/javascript"> +    window.top.location.reload(); +  </SCRIPT> +  </BODY></HTML> +<%init> +my $conf = new FS::Conf; +</%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 000000000..553c7551a --- /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 000000000..1a9b62628 --- /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 new file mode 100644 index 000000000..f800dbd5b --- /dev/null +++ b/httemplate/misc/process/tax-import.cgi @@ -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::tax_rate::process_batch_import', $cgi;  + +</%init> diff --git a/httemplate/misc/process/tax-upgrade.cgi b/httemplate/misc/process/tax-upgrade.cgi new file mode 100644 index 000000000..8782282bd --- /dev/null +++ b/httemplate/misc/process/tax-upgrade.cgi @@ -0,0 +1,147 @@ +% if ( $error ) { +%   warn $error; +%   errorpage($error); +%  } else { +    <% include('/elements/header.html','Import successful') %>  +    <% include('/elements/footer.html') %>  +%  } +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Import'); + +my $cfh = $cgi->upload('codefile'); +my $zfh = $cgi->upload('plus4file'); +my $tfh = $cgi->upload('txmatrix'); +my $dfh = $cgi->upload('detail'); +#warn $cgi; +#warn $fh; + +my $oldAutoCommit = $FS::UID::AutoCommit; +local $FS::UID::AutoCommit = 0; +my $dbh = dbh; + +my $error = ''; + +my ($cifh, $cdfh, $zifh, $zdfh, $tifh, $tdfh); + +if (defined($cfh)) { +  $cifh = new File::Temp( TEMPLATE => 'code.insert.XXXXXXXX', +                          DIR      => $FS::UID::conf_dir. "/cache.". $FS::UID::datasrc, +                        ) or die "can't open temp file: $!\n"; + +  $cdfh = new File::Temp( TEMPLATE => 'code.insert.XXXXXXXX', +                          DIR      => $FS::UID::conf_dir. "/cache.". $FS::UID::datasrc, +                        ) or die "can't open temp file: $!\n"; + +  while(<$cfh>) { +    my $fh = ''; +    $fh = $cifh if $_ =~ /"I"\s*$/; +    $fh = $cdfh if $_ =~ /"D"\s*$/; +    die "bad input line: $_" unless $fh; +    print $fh $_; +  } +  seek $cifh, 0, 0; +  seek $cdfh, 0, 0; + +}else{ +  $error = 'No code file'; +} + +$error ||= FS::tax_class::batch_import( { +             filehandle => $cifh, +             'format'   => scalar($cgi->param('format')), +           } ); + +close $cifh if $cifh; + +if (defined($zfh)) { +  $zifh = new File::Temp( TEMPLATE => 'plus4.insert.XXXXXXXX', +                          DIR      => $FS::UID::conf_dir. "/cache.". $FS::UID::datasrc, +                        ) or die "can't open temp file: $!\n"; + +  $zdfh = new File::Temp( TEMPLATE => 'plus4.insert.XXXXXXXX', +                          DIR      => $FS::UID::conf_dir. "/cache.". $FS::UID::datasrc, +                        ) or die "can't open temp file: $!\n"; + +  while(<$zfh>) { +    my $fh = ''; +    $fh = $zifh if $_ =~ /"I"\s*$/; +    $fh = $zdfh if $_ =~ /"D"\s*$/; +    die "bad input line: $_" unless $fh; +    print $fh $_; +  } +  seek $zifh, 0, 0; +  seek $zdfh, 0, 0; + +}else{ +  $error = 'No plus4 file'; +} + +$error ||= FS::cust_tax_location::batch_import( { +             filehandle => $zifh, +             'format'   => scalar($cgi->param('format')), +           } ); +close $zifh if $zifh; + +if (defined($tfh)) { +  $tifh = new File::Temp( TEMPLATE => 'txmatrix.insert.XXXXXXXX', +                          DIR      => $FS::UID::conf_dir. "/cache.". $FS::UID::datasrc, +                        ) or die "can't open temp file: $!\n"; + +  $tdfh = new File::Temp( TEMPLATE => 'txmatrix.insert.XXXXXXXX', +                          DIR      => $FS::UID::conf_dir. "/cache.". $FS::UID::datasrc, +                        ) or die "can't open temp file: $!\n"; + +  while(<$tfh>) { +    my $fh = ''; +    $fh = $tifh if $_ =~ /"I"\s*$/; +    $fh = $tdfh if $_ =~ /"D"\s*$/; +    die "bad input line: $_" unless $fh; +    print $fh $_; +  } +  seek $tifh, 0, 0; +  seek $tdfh, 0, 0; + +}else{ +  $error = 'No tax matrix file'; +} + +$error ||= FS::part_pkg_taxrate::batch_import( { +             filehandle => $tifh, +             'format'   => scalar($cgi->param('format')), +           } ); +close $tifh if $tifh; + +$error ||= defined($dfh) +  ? FS::tax_rate::batch_update( { +      filehandle => $dfh, +      'format'   => scalar($cgi->param('format')), +    } ) +  : 'No tax detail file'; + +$error ||= FS::part_pkg_taxrate::batch_import( { +             filehandle => $tdfh, +             'format'   => scalar($cgi->param('format')), +           } ); +close $tdfh if $tdfh; + +$error ||= FS::cust_tax_location::batch_import( { +             filehandle => $zdfh, +             'format'   => scalar($cgi->param('format')), +           } ); +close $zdfh if $zdfh; + +$error ||= FS::tax_class::batch_import( { +             filehandle => $cdfh, +             'format'   => scalar($cgi->param('format')), +           } ); +close $cdfh if $cdfh; + +if ($error) { +  $dbh->rollback or die $dbh->errstr if $oldAutoCommit; +}else{ +  $dbh->commit or die $dbh->errstr if $oldAutoCommit; +} + +</%init> diff --git a/httemplate/misc/process/timeworked.html b/httemplate/misc/process/timeworked.html new file mode 100644 index 000000000..200a7511d --- /dev/null +++ b/httemplate/misc/process/timeworked.html @@ -0,0 +1,59 @@ +% if ($error) { +<% $cgi->redirect(popurl(2). "timeworked.html?". $cgi->query_string) %> +% } else { +<% $cgi->redirect(popurl(3). "search/timeworked.html?begin=$begin;end=$end") %> +% } +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Time queue'); + +my($begin, $end) = FS::UI::Web::parse_beginning_ending($cgi); + +my @acct_rt_transaction; +foreach my $transaction ( +  map { /^transactionid(\d+)$/; $1; } grep /^transactionid\d+$/, $cgi->param +) { +  my $s = "multiplier${transaction}_"; +  my %multipliers = map { /^$s(\d+)$/; $1 => $cgi->param("$s$1"); } +                      grep /^$s\d+$/, $cgi->param; +  my $msum = 0; +  foreach(values %multipliers) {$msum += $_}; + +  my $seconds = $cgi->param("seconds$transaction"); +  my %seconds =  +       map { $_ => sprintf("%.0f", $seconds * $multipliers{$_} / $msum) }  +         (keys %multipliers); +  my $sum = 0; +  my $count = 0; +  foreach (values %seconds) { +    $sum += $_; +    $count++; +  } + +  #fudge in some time if we're close +  if (abs($seconds-$sum) <= $count) { +    my $adjustment = $seconds-$sum; +    foreach (keys %seconds) {       # explicitly choose one? +      $seconds{$_} += $adjustment; +      last; +    } +  } else { +    die "unexpectedly cannot apportion time"; +  } + +  foreach my $customer ( grep {$seconds{$_}} keys %seconds ) { +    push @acct_rt_transaction, new FS::acct_rt_transaction { +      'custnum'        => $customer, +      'transaction_id' => $transaction, +      'seconds'        => $seconds{$customer}, +      'support'        => int( $seconds{$customer} * $msum ), +    }; +  } + +} + +my $error = FS::acct_rt_transaction->batch_insert(@acct_rt_transaction); +$cgi->param('error', $error) if $error; + +</%init> diff --git a/httemplate/misc/queue.cgi b/httemplate/misc/queue.cgi new file mode 100644 index 000000000..5dee29b88 --- /dev/null +++ b/httemplate/misc/queue.cgi @@ -0,0 +1,49 @@ +<% $cgi->redirect(popurl(2). "search/queue.html") %> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Job queue'); + +$cgi->param('action') =~ /^(new|del|(retry|remove) selected)$/ +  or die "Illegal action"; +my $action = $1; + +my $job; +if ( $action eq 'new' || $action eq 'del' ) { +  $cgi->param('jobnum') =~ /^(\d+)$/ or die "Illegal jobnum"; +  my $jobnum = $1; +  $job = qsearchs('queue', { 'jobnum' => $1 }) +    or die "unknown jobnum $jobnum - ". +           "it probably completed normally or was removed by another user"; +} + +if ( $action eq 'new' ) { +  my %hash = $job->hash; +  $hash{'status'} = 'new'; +  $hash{'statustext'} = ''; +  my $new = new FS::queue \%hash; +  my $error = $new->replace($job); +  die $error if $error; +} elsif ( $action eq 'del' ) { +  my $error = $job->delete; +  die $error if $error; +} elsif ( $action =~ /^(retry|remove) selected$/ ) { +  foreach my $jobnum ( +    map { /^jobnum(\d+)$/; $1; } grep /^jobnum\d+$/, $cgi->param +  ) { +    my $job = qsearchs('queue', { 'jobnum' => $jobnum }); +    if ( $action eq 'retry selected' && $job ) { #new +      my %hash = $job->hash; +      $hash{'status'} = 'new'; +      $hash{'statustext'} = ''; +      my $new = new FS::queue \%hash; +      my $error = $new->replace($job); +      die $error if $error; +    } elsif ( $action eq 'remove selected' && $job ) { #del +      my $error = $job->delete; +      die $error if $error; +    } +  } +} + +</%init> diff --git a/httemplate/misc/rate_edit_excel.html b/httemplate/misc/rate_edit_excel.html new file mode 100644 index 000000000..e73133c05 --- /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> +          - To add rates, add four columns like an existing rate, with headers starting with "NEW: Rate Name" or "Rate Name".<BR> +         - <FONT SIZE="-2"><I>For rate addition, protection can be turned off in Excel via the Tools->Protection->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/recharge_svc.html b/httemplate/misc/recharge_svc.html new file mode 100755 index 000000000..d8a8faad4 --- /dev/null +++ b/httemplate/misc/recharge_svc.html @@ -0,0 +1,105 @@ +<% include('/elements/header-popup.html', 'Recharge Service' ) %> + +<% include('/elements/error.html') %> + +<FORM NAME="recharge_popup" ACTION="<% popurl(1) %>process/recharge_svc.html" METHOD=POST> +<INPUT TYPE="hidden" NAME="svcnum" VALUE="<% $svcnum %>"> + +<BR><BR> +<% "Recharge $svcnum: $label  -  $value" %> +<% ntable("#cccccc", 2) %> + +<SCRIPT> +  function toggle_prep(what) { +    if (what.value == "PREP"){ +      what.form.prepaid.disabled = false; +    }else{ +      what.form.prepaid.disabled = true; +    } +  } +</SCRIPT> +<TR> +  <TD><INPUT TYPE="radio" NAME="payby" onchange="toggle_prep(this)" VALUE="PREP" <% $payby eq "PREP" ? 'checked' : '' %> <% $recharge_label ? '' : 'disabled' %>></TD> +  <TD>Prepaid Card</TD> +% if ($recharge_label) { +  <TD><INPUT TYPE="radio" NAME="payby" onchange="toggle_prep(this)" VALUE="<% $cust_svc->cust_pkg->cust_main->payby %>" <% $payby eq "PREP" ? '' : 'checked' %>></TD> +  <TD><% $recharge_label %></TD> +% } +</TR> +<TR> +  <TD>Enter prepaid card: </TD> +  <TD><INPUT TYPE="text" NAME="prepaid" VALUE="<% $prepaid |h %>" <% $payby eq "PREP" ? '' : 'disabled' %>></TD> +</TR> + +</TABLE> + +<BR> +<INPUT TYPE="submit" NAME="submit" VALUE="Recharge"> + +</FORM> + +<% include('/elements/footer.html') %> + +<%once> + +my $conf = new FS::Conf; +my $money_char = $conf->config('money_char') || '$'; + +</%once> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Recharge customer service'); + +my($svcnum, $prepaid, $payby);  +if ( $cgi->param('error') ) { +  $svcnum        = $cgi->param('svcnum'); +  $prepaid       = $cgi->param('prepaid'); +  $payby         = $cgi->param('payby'); +} elsif ( $cgi->param('svcnum') =~ /^(\d+)$/ ) { +  $svcnum  = $1; +  $prepaid = ''; +} else { +  die "illegal query ". $cgi->keywords; +} + +my $title = 'Recharge Service'; + +my $cust_svc = qsearchs('cust_svc', {'svcnum' => $svcnum}); +die "No such service: $svcnum" unless $cust_svc; + +my($label, $value) = $cust_svc->label; + +$payby = $cust_svc->cust_pkg->cust_main->payby unless $payby; +my $part_pkg = $cust_svc->cust_pkg->part_pkg; +my $amount = $part_pkg->option('recharge_amount', 1) || 0; + +my $recharge_label = "Charge $money_char$amount for "; + +$recharge_label .= $part_pkg->option('recharge_seconds', 1) . 's ' +  if $part_pkg->option('recharge_seconds', 1); + + +$recharge_label .= FS::UI::bytecount::display_bytecount( +                     $part_pkg->option('recharge_upbytes', 1) ) +                . ' up ' +  if $part_pkg->option('recharge_upbytes', 1); + + +$recharge_label .= FS::UI::bytecount::display_bytecount( +                     $part_pkg->option('recharge_downbytes', 1) ) +                . ' down ' +  if $part_pkg->option('recharge_downbytes', 1); + + +$recharge_label .= FS::UI::bytecount::display_bytecount( +                     $part_pkg->option('recharge_totalbytes', 1) ) +                . ' total ' +  if $part_pkg->option('recharge_totalbytes', 1); + + +$recharge_label = '' +  unless ($recharge_label ne "Charge $money_char$amount for "); + +</%init> + diff --git a/httemplate/misc/send-invoice.cgi b/httemplate/misc/send-invoice.cgi new file mode 100644 index 000000000..32dfe276d --- /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 000000000..e363fbd09 --- /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/spool_invoices.cgi b/httemplate/misc/spool_invoices.cgi new file mode 100644 index 000000000..bfe24e6ea --- /dev/null +++ b/httemplate/misc/spool_invoices.cgi @@ -0,0 +1,9 @@ +<% $server->process %> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Resend invoices'); + +my $server = new FS::UI::Web::JSRPC 'FS::cust_bill::process_respool', $cgi; + +</%init> diff --git a/httemplate/misc/states.cgi b/httemplate/misc/states.cgi new file mode 100644 index 000000000..02b7be4af --- /dev/null +++ b/httemplate/misc/states.cgi @@ -0,0 +1,7 @@ +[ <% join(', ', map { qq("$_") } @output) %> ] +<%init> + +my $country = $cgi->param('arg'); +my @output = states_hash($country); + +</%init> diff --git a/httemplate/misc/svc_acct-domains.cgi b/httemplate/misc/svc_acct-domains.cgi new file mode 100644 index 000000000..573457483 --- /dev/null +++ b/httemplate/misc/svc_acct-domains.cgi @@ -0,0 +1,31 @@ +[ <% join(', ', map { qq("$_->[0]", "$_->[1]") } @svc_domain) %> ] +<%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 $part_svc_column = $part_svc->part_svc_column('domsvc') if $part_svc; + +my @output = split /,/, $part_svc_column->columnvalue if $part_svc_column; +my $columnflag = $part_svc_column->columnflag if $part_svc_column; +my @svc_domain = (); +my %seen = (); + +foreach (@output) { +  my $svc_domain = qsearchs('svc_domain', { 'svcnum' => $_ }) +    or warn "unknown svc_domain.svcnum $_ for part_svc_column domsvc; ". +       "svcpart = " . $part_svc->svcpart; +  push @svc_domain, [ $_ => $svc_domain->domain ]; +  $seen{$_}++; +} +if ($conf->exists('svc_acct-alldomains') +     && ( $columnflag eq 'D' || $columnflag eq '' ) +   ) { +  foreach (grep { $_->svcnum ne $output[0] } qsearch('svc_domain', {}) ){ +    push @svc_domain, [ $_->svcnum => $_->domain ]; +  } +} + +</%init> diff --git a/httemplate/misc/tax-fetch_and_import.cgi b/httemplate/misc/tax-fetch_and_import.cgi new file mode 100644 index 000000000..33a6c9b01 --- /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 000000000..3290a3c44 --- /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 new file mode 100644 index 000000000..5116e5404 --- /dev/null +++ b/httemplate/misc/tax-import.cgi @@ -0,0 +1,67 @@ +<% include("/elements/header.html",'Batch Tax Rate Import') %> + +Import a CSV file set containing tax rate records. +<BR><BR> + +<% include( '/elements/form-file_upload.html', +              'name'      => 'TaxRateUpload', +              'action'    => 'process/tax-import.cgi',  +              'num_files' => 6, +              'fields'    => [ 'format', ], +              'message'   => 'Tax rates imported', +          ) +%> + +<% &ntable("#cccccc", 2) %> + +  <TR> +    <TH ALIGN="right">Format</TH> +    <TD> +      <SELECT NAME="format"> +        <OPTION VALUE="cch-update" SELECTED>CCH update (CSV) +        <OPTION VALUE="cch">CCH initial import (CSV) +        <OPTION VALUE="cch-fixed-update">CCH update (fixed length) +        <OPTION VALUE="cch-fixed">CCH initial import (fixed length) +      </SELECT> +    </TD> +  </TR> + +  <% include( '/elements/file-upload.html', +                'field'    => [ 'geofile', +                                'codefile', +                                'plus4file', +                                'zipfile', +                                'txmatrix', +                                'detail', +                              ], +                'label'    => [ 'geocode filename', +                                'code filename', +                                'plus4 filename', +                                'zip filename', +                                'txmatrix filename', +                                'detail filename', +                              ], +                'debug'    => 0, +            ) +  %> + +  <TR> +    <TD COLSPAN=2 ALIGN="center" STYLE="padding-top:6px"> +      <INPUT TYPE    = "submit" +             VALUE   = "Import CSV files" +             onClick = "document.TaxRateUpload.submit.disabled=true;" +      > +    </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/timeworked.html b/httemplate/misc/timeworked.html new file mode 100755 index 000000000..46063e829 --- /dev/null +++ b/httemplate/misc/timeworked.html @@ -0,0 +1,138 @@ +<% include('/elements/header.html', $title, '' ) %> + +<% include('/elements/error.html') %> + +<FORM NAME="timeworked_form" ACTION="<% popurl(1) %>process/timeworked.html" METHOD=POST> + +<TABLE CELLSPACING="2" CELLPADDING="2" RULES="groups" FRAME="hsides"> + +  <THEAD> +    <TR> +      <TH>Trans</TH> +      <TH COLSPAN="2">Ticket</TH> +      <TH>Time</TH> +      <TH COLSPAN="2">Customer</TH> +      <TH>Multiplier</TH> +    </TR> + +    <TR> +      <TH>#</TH> +      <TH>#</TH> +      <TH>Subject</TH> +      <TH>hours</TH> +      <TH>#</TH> +      <TH>Name</TH> +      <TH></TH> +    </TR> +  </THEAD> + +  <TBODY> + +%   foreach my $tr_id ( keys %ticketmap ) { +%     my (@customers) = @{$customers{$ticketmap{$tr_id}}}; +%     next unless @customers; +%     my $default_multiplier = sprintf("%.2f", 1/@customers); +%     my ($custnum, $name) = split(':', pop @customers, 2); +%     my $link = $p. 'rt/Ticket/Display.html?id='. $ticketmap{$tr_id}. +%                    '#txn-'. $tr_id; + +      <TR> +        <TD><a href="<% $link %>"><% $tr_id %></a></TD> +        <TD><a href="<% $link %>"><% $ticketmap{$tr_id} %></a></TD> +        <TD><a href="<% $link %>"><% $ticket{$ticketmap{$tr_id}} |h %></a></TD> + +%       my $seconds = 0; +%       if ( $cgi->param("seconds$tr_id") =~ /^(\d+)$/ ) { +%         $seconds = $1; +%       } + +        <TD><% sprintf("%0.2f", $seconds/3600) %></TD> +        <TD ALIGN="right"><% $custnum %></TD> +        <TD ALIGN="right"><% $name %></TD> +        <TD> +          <INPUT TYPE="hidden" NAME="transactionid<%$tr_id%>" VALUE="1" > +          <INPUT TYPE="hidden" NAME="seconds<%$tr_id%>" VALUE="<% $seconds %>" > + +%         my $multiplier = $default_multiplier; +%         my $mult_paramname = "multiplier${tr_id}_$custnum"; +%         if ( $cgi->param($mult_paramname) =~ /^\s*([\d\.]+)\s*$/ ) { +%           $multiplier = $1; +%         } + +          <INPUT TYPE="text" NAME="<% $mult_paramname %>" SIZE="5" VALUE="<% $multiplier %>" > +        </TD> +      </TR> + +%     foreach ( @customers ) { +%       ($custnum, $name) = split(':', $_, 2); + +        <TR> +          <TD ALIGN="right" COLSPAN="5" ><% $custnum %></TD> +          <TD ALIGN="right"><% $name %></TD> +          <TD> + +%           $multiplier = $default_multiplier; +%           $mult_paramname = "multiplier${tr_id}_$custnum"; +%           if ( $cgi->param($mult_paramname) =~ /^\s*([\d\.]+)\s*$/ ) { +%             $multiplier = $1; +%           } + +            <INPUT TYPE="text" NAME="<% $mult_paramname %>" SIZE="5" VALUE="<% $multiplier %>" > + +          </TD> + +        </TR> + +%     } +%   } + +  </TBODY> + +</TABLE> + +<BR> + +<INPUT TYPE="hidden" NAME="begin" VALUE="<% $cgi->param('begin') |h %>"> +<INPUT TYPE="hidden" NAME="end"   VALUE="<% $cgi->param('end')   |h %>"> + +<INPUT TYPE="submit" NAME="submit" VALUE="<% $title %>"> +</FORM> + +<% include('/elements/footer.html') %> + +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Time queue'); + +my(%ticketmap, %ticket, %customers);  +my $title = 'Assign Time Worked'; +tie %ticketmap, 'Tie::IxHash'; + +RT::Init(); + +my $CurrentUser = RT::CurrentUser->new(); +$CurrentUser->LoadByName($FS::CurrentUser::CurrentUser->username); + +foreach my $id ( map { /^transactionid(\d+)$/; $1; } +                     grep /^transactionid\d+$/, $cgi->param) { +  my $transaction = new RT::Transaction($CurrentUser);  +  $transaction->Load($id); +  $ticketmap{$id} = $transaction->ObjectId; +  unless(exists($ticket{$ticketmap{$id}})) { +    my $ticket = new RT::Ticket($CurrentUser); +    $ticket->Load($ticketmap{$id}); +    $ticket{$ticketmap{$id}} = $ticket->Subject; +    $customers{$ticketmap{$id}} = +                            [ map  { $_->Resolver->AsString } +                              grep { $_->Resolver->{'fstable'} eq 'cust_main' } +                              grep { $_->Scheme eq 'freeside' }  +                              map  { $_->TargetURI }  +                                @{ $ticket->_Links('Base')->ItemsArrayRef }  +                            ]; +                             +  } +} + +</%init> + diff --git a/httemplate/misc/unadjourn_pkg.cgi b/httemplate/misc/unadjourn_pkg.cgi new file mode 100755 index 000000000..356b49cb3 --- /dev/null +++ b/httemplate/misc/unadjourn_pkg.cgi @@ -0,0 +1,17 @@ +%if ( $error ) { +%  errorpage($error); +%} else { +<% $cgi->redirect(popurl(2). "view/cust_main.cgi?".$cust_pkg->getfield('custnum')) %> +%} +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Suspend customer package later'); + +my ($pkgnum) = $cgi->keywords; +my $cust_pkg = qsearchs( 'cust_pkg', { 'pkgnum' => $pkgnum } ); +my $error = "No package $pkgnum" unless $cust_pkg; + +$error ||= $cust_pkg->unadjourn; + +</%init> diff --git a/httemplate/misc/unapply-cust_credit.cgi b/httemplate/misc/unapply-cust_credit.cgi new file mode 100755 index 000000000..ed739ac1b --- /dev/null +++ b/httemplate/misc/unapply-cust_credit.cgi @@ -0,0 +1,20 @@ +<% $cgi->redirect($p. "view/cust_main.cgi?". $custnum) %> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Unapply credit'); + +#untaint crednum +my($query) = $cgi->keywords; +$query =~ /^(\d+)$/ || die "Illegal crednum"; +my $crednum = $1; + +my $cust_credit = qsearchs('cust_credit', { 'crednum' => $crednum } ); +my $custnum = $cust_credit->custnum; + +foreach my $cust_credit_bill ( $cust_credit->cust_credit_bill ) { +  my $error = $cust_credit_bill->delete; +  errorpage($error) if $error; +} + +</%init> diff --git a/httemplate/misc/unapply-cust_pay.cgi b/httemplate/misc/unapply-cust_pay.cgi new file mode 100755 index 000000000..8cdac180b --- /dev/null +++ b/httemplate/misc/unapply-cust_pay.cgi @@ -0,0 +1,20 @@ +<% $cgi->redirect($p. "view/cust_main.cgi?". $custnum) %> +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Unapply payment'); + +#untaint paynum +my($query) = $cgi->keywords; +$query =~ /^(\d+)$/ || die "Illegal paynum"; +my $paynum = $1; + +my $cust_pay = qsearchs('cust_pay', { 'paynum' => $paynum } ); +my $custnum = $cust_pay->custnum; + +foreach my $cust_bill_pay ( $cust_pay->cust_bill_pay ) { +  my $error = $cust_bill_pay->delete; +  errorpage($error) if $error; +} + +</%init> diff --git a/httemplate/misc/unexpire_pkg.cgi b/httemplate/misc/unexpire_pkg.cgi new file mode 100755 index 000000000..445025524 --- /dev/null +++ b/httemplate/misc/unexpire_pkg.cgi @@ -0,0 +1,17 @@ +%if ( $error ) { +%  errorpage($error); +%} else { +<% $cgi->redirect(popurl(2). "view/cust_main.cgi?".$cust_pkg->getfield('custnum')) %> +%} +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Cancel customer package later'); + +my ($pkgnum) = $cgi->keywords; +my $cust_pkg = qsearchs( 'cust_pkg', { 'pkgnum' => $pkgnum } ); +my $error = "No package $pkgnum" unless $cust_pkg; + +$error ||= $cust_pkg->unexpire; + +</%init> diff --git a/httemplate/misc/unprovision.cgi b/httemplate/misc/unprovision.cgi new file mode 100755 index 000000000..4ab15fdc0 --- /dev/null +++ b/httemplate/misc/unprovision.cgi @@ -0,0 +1,26 @@ +%if ( $error ) { +%  errorpage($error); +%} else { +<% $cgi->redirect(popurl(2)."view/cust_main.cgi?$custnum") %> +%} +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Unprovision customer service'); + +#untaint svcnum +my($query) = $cgi->keywords; +$query =~ /^(\d+)$/; +my $svcnum = $1; + +#my $svc_acct = qsearchs('svc_acct',{'svcnum'=>$svcnum}); +#die "Unknown svcnum!" unless $svc_acct; + +my $cust_svc = qsearchs('cust_svc',{'svcnum'=>$svcnum}); +die "Unknown svcnum!" unless $cust_svc; + +my $custnum = $cust_svc->cust_pkg->custnum; + +my $error = $cust_svc->cancel; + +</%init> diff --git a/httemplate/misc/unsusp_pkg.cgi b/httemplate/misc/unsusp_pkg.cgi new file mode 100755 index 000000000..b350693dd --- /dev/null +++ b/httemplate/misc/unsusp_pkg.cgi @@ -0,0 +1,20 @@ +%if ( $error ) { +%  errorpage($error); +%} else { +<% $cgi->redirect(popurl(2). "view/cust_main.cgi?".$cust_pkg->getfield('custnum')) %> +%} +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Unsuspend customer package'); + +#untaint pkgnum +my ($query) = $cgi->keywords; +$query =~ /^(\d+)$/ || die "Illegal pkgnum"; +my $pkgnum = $1; + +my $cust_pkg = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum}); + +my $error = $cust_pkg->unsuspend; + +</%init> diff --git a/httemplate/misc/unvoid-cust_pay_void.cgi b/httemplate/misc/unvoid-cust_pay_void.cgi new file mode 100755 index 000000000..91fe1c223 --- /dev/null +++ b/httemplate/misc/unvoid-cust_pay_void.cgi @@ -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('Unvoid'); + +#untaint paynum +my($query) = $cgi->keywords; +$query =~ /^(\d+)$/ || die "Illegal paynum"; +my $paynum = $1; + +my $cust_pay_void = qsearchs('cust_pay_void', { 'paynum' => $paynum } ); +my $custnum = $cust_pay_void->custnum; + +my $error = $cust_pay_void->unvoid; + +</%init> diff --git a/httemplate/misc/upload-batch.cgi b/httemplate/misc/upload-batch.cgi new file mode 100644 index 000000000..d1a84fd02 --- /dev/null +++ b/httemplate/misc/upload-batch.cgi @@ -0,0 +1,36 @@ +% if ( $error ) { +%   errorpage($error); +% } else { +    <% include('/elements/header.html','Batch results upload successful') %>  +    <% include('/elements/footer.html') %>  +% } +<%init> + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Process batches'); + +my $error; + +my $fh = $cgi->upload('batch_results'); +$error = 'No file uploaded' unless defined($fh); + +unless ( $error ) { + +  $cgi->param('batchnum') =~ /^(\d+)$/; +  my $batchnum = $1; + +  my $pay_batch = qsearchs( 'pay_batch', { 'batchnum' => $batchnum } ); +  if ( ! $pay_batch ) { +    $error = "batchnum $batchnum not found"; +  } elsif ( $pay_batch->status ne 'I' ) { +    $error = "batch $batchnum is not in transit"; +  } else { +    $error = $pay_batch->import_results( +                                         'filehandle' => $fh, +                                         'format'     => $cgi->param('format'), +                                       ); +  } + +} + +</%init> diff --git a/httemplate/misc/void-cust_pay.cgi b/httemplate/misc/void-cust_pay.cgi new file mode 100755 index 000000000..7b484e93e --- /dev/null +++ b/httemplate/misc/void-cust_pay.cgi @@ -0,0 +1,26 @@ +%if ( $error ) { +%  errorpage($error); +%} else { +<% $cgi->redirect($p. "view/cust_main.cgi?". $custnum) %> +%} +<%init> + +#untaint paynum +my($query) = $cgi->keywords; +$query =~ /^(\d+)$/ || die "Illegal paynum"; +my $paynum = $1; + +my $cust_pay = qsearchs('cust_pay',{'paynum'=>$paynum}); + +my $right = 'Regular void'; +$right = 'Credit card void' if $cust_pay->payby eq 'CARD'; +$right = 'Echeck void'      if $cust_pay->payby eq 'CHEK'; + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right($right); + +my $custnum = $cust_pay->custnum; + +my $error = $cust_pay->void; + +</%init> diff --git a/httemplate/misc/whois.cgi b/httemplate/misc/whois.cgi new file mode 100644 index 000000000..533b2d7a8 --- /dev/null +++ b/httemplate/misc/whois.cgi @@ -0,0 +1,33 @@ +<% include("/elements/header.html","Whois $domain", menubar( +  ( $custnum +    ? ( "View this customer (#$display_custnum)" => "${p}view/cust_main.cgi?$custnum", +      ) +    : () +  ), +  "View this domain (#$svcnum)" => "${p}view/svc_domain.cgi?$svcnum", +)) %> + +<PRE><% $whois %></PRE> + +<% include('/elements/footer.html') %> + +<%init> + +my $svcnum = $cgi->param('svcnum'); +my $custnum = $cgi->param('custnum'); +my $domain = $cgi->param('domain'); + +my $display_custnum; +if ( $custnum ) { +  my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ); +  $display_custnum = $cust_main->display_custnum; +} + +my $whois = eval { whois($domain) }; +  if ( $@ ) { +    ( $whois = $@ ) =~ s/ at \/.*Net\/Whois\/Raw\.pm line \d+.*$//s; +  } else { +    $whois =~ s/^\n+//; +  } + +</%init> diff --git a/httemplate/misc/xmlhttp-calculate_taxes.html b/httemplate/misc/xmlhttp-calculate_taxes.html new file mode 100644 index 000000000..774b89381 --- /dev/null +++ b/httemplate/misc/xmlhttp-calculate_taxes.html @@ -0,0 +1,105 @@ +<% objToJson($return) %> +<%init> + +my $DEBUG = 0; + +my $conf = new FS::Conf; + +my $sub = $cgi->param('sub'); + +my $return = {}; + +if ( $sub eq 'calculate_taxes' ) { + +  { +    my %arg = $cgi->param('arg'); +    $return = \%arg; +    warn join('', map "$_: $arg{$_}\n", keys %arg ) +      if $DEBUG; + +    my $cust_credit = qsearchs( 'cust_credit', { 'crednum' => $arg{crednum} } ); +    unless ($cust_credit) { +      $return->{error} = "No such credit: $arg{crednum}"; +      last; +    } +   +    my %cust_bill_pkg = (); +    my @items = split(',', $arg{items}); +    while ( @items ) { +      my ($billpkgnum, $s_or_r, $amount ) = splice(@items, 0, 3); +      unless ( defined($amount) ) { +        $return->{error} = "Bad items argument list"; +        last; +      } +      unless ( $cust_bill_pkg{$billpkgnum} ) { +        my $cust_bill_pkg = +          qsearchs( 'cust_bill_pkg', { 'billpkgnum' => $billpkgnum } ); +        unless ($cust_bill_pkg) { +          $return->{error} = "No such line item: $billpkgnum"; +          last; +        } +        next unless $cust_bill_pkg->pkgnum > 0; #hmmm @ one shot (-1) +        unless ($cust_bill_pkg->cust_pkg->custnum == $cust_credit->custnum) { +          $return->{error} = "Credit/line item customer mismatch"; +          last; +        } +        $cust_bill_pkg{$billpkgnum} = $cust_bill_pkg; +        $cust_bill_pkg->setup(0); +        $cust_bill_pkg->recur(0); +      } + +      last if $return->{error}; + +      my $cust_bill_pkg = $cust_bill_pkg{$billpkgnum}; +      $s_or_r = $s_or_r eq 'setup' ? 'setup' : 'recur'; +      my $value = sprintf('%.2f', $cust_bill_pkg->$s_or_r + $amount); +      $cust_bill_pkg->$s_or_r($value); +    } + +    last if $return->{error}; + +    my $cust_main = $cust_credit->cust_main; + +    my $taxlisthash = {}; +    foreach my $cust_bill_pkg (values %cust_bill_pkg) { +      my $part_pkg = $cust_bill_pkg->part_pkg; +      $cust_main->_handle_taxes( $part_pkg, +                                 $taxlisthash, +                                 $cust_bill_pkg, +                                 $cust_bill_pkg->cust_pkg, +                                 $cust_bill_pkg->cust_bill->_date, +                                 $cust_bill_pkg->cust_pkg->pkgpart, +                               ); +    } +    my $listref_or_error =  +      $cust_main->calculate_taxes( [ values %cust_bill_pkg ], $taxlisthash, [ values %cust_bill_pkg ]->[0]->cust_bill->_date ); + +    unless ( ref( $listref_or_error ) ) { +      $return->{error} = "No such credit: $arg{crednum}"; +      last; +    } + +    my @taxlines = (); +    $return->{taxlines} = \@taxlines; +    foreach my $taxline ( @$listref_or_error ) { +      my $amount = $taxline->setup; +      my $desc = $taxline->desc; +      foreach my $location ( @{$taxline->cust_bill_pkg_tax_location}, @{$taxline->cust_bill_pkg_tax_rate_location} ) { +        my $taxlocnum = $location->locationnum || ''; +        my $taxratelocnum = $location->taxratelocationnum || ''; +        push @taxlines, +          [ $location->desc, $taxline->setup, $taxlocnum, $taxratelocnum ]; +        $amount -= $location->amount; +      } +      if ($amount > 0) { +        push @taxlines, +          [ $taxline->itemdesc. ' (default)', sprintf('%.2f', $amount), '', '' ]; +      } +    } + +    $return->{taxlines} = \@taxlines; + +  } +} + +</%init> diff --git a/httemplate/misc/xmlhttp-cust_main-address_standardize.html b/httemplate/misc/xmlhttp-cust_main-address_standardize.html new file mode 100644 index 000000000..3b9e142f5 --- /dev/null +++ b/httemplate/misc/xmlhttp-cust_main-address_standardize.html @@ -0,0 +1,92 @@ +<% objToJson($return) %> +<%init> + +my $DEBUG = 0; + +my $conf = new FS::Conf; + +my $sub = $cgi->param('sub'); + +my $return = {}; + +if ( $sub eq 'address_standardize' ) { + +  my %arg = $cgi->param('arg'); +  $return = \%arg; +  warn join('', map "$_: $arg{$_}\n", keys %arg ) +    if $DEBUG; + +  my $userid   = $conf->config('usps_webtools-userid'); +  my $password = $conf->config('usps_webtools-password'); + +  if ( length($userid) && length($password) ) { + +    my $verifier = Business::US::USPS::WebTools::AddressStandardization->new( { +      UserID   => $userid,   #$ENV{USPS_WEBTOOLS_USERID}, +      Password => $password, #$ENV{USPS_WEBTOOLS_PASSWORD}, +      #Testing  => 1, +    } ); + +    foreach my $pre ( '', 'ship_' ) { + +      my($zip5, $zip4) = split('-',$arg{$pre.'zip'}); + +      my %usps_args = ( +        FirmName => $arg{$pre.'company'}, +        Address2 => $arg{$pre.'address1'}, +        Address1 => $arg{$pre.'address2'}, +        City     => $arg{$pre.'city'},   +        State    => $arg{$pre.'state'}, +        Zip5     => $zip5, +        Zip4     => $zip4, +      ); +      warn join('', map "$_: $usps_args{$_}\n", keys %usps_args ) +        if $DEBUG; + +      my $hash = $verifier->verify_address( %usps_args ); + +      warn $verifier->response +        if $DEBUG; + +      unless ( $verifier->is_error ) { + +        my $zip = $hash->{Zip5}; +        $zip .= '-'. $hash->{Zip4} if $hash->{Zip4} =~ /\d/; + +        $return = { +          %$return, +          "new_$pre".'company'  => $hash->{FirmName}, +          "new_$pre".'address1' => $hash->{Address2}, +          "new_$pre".'address2' => $hash->{Address1}, +          "new_$pre".'city'     => $hash->{City}, +          "new_$pre".'state'    => $hash->{State}, +          "new_$pre".'zip'      => $zip, +        }; + +        my @fields = (qw( company address1 address2 city state zip )); #hmm + +        my $changed = +          scalar( grep { $return->{$pre.$_} ne $return->{"new_$pre$_"} } +                       @fields +                ) +            ? 1 : 0; + +        $return->{$pre.'address_standardized'} = $changed; + +      } else { + +        $return->{$pre.'error'} = "USPS WebTools error: ". +                                  $verifier->{error}{description}; + + +      } + +    } + +  } + +  $return; + +} + +</%init> diff --git a/httemplate/misc/xmlhttp-cust_main-censustract.html b/httemplate/misc/xmlhttp-cust_main-censustract.html new file mode 100644 index 000000000..9d588d712 --- /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-cust_main-search.cgi b/httemplate/misc/xmlhttp-cust_main-search.cgi new file mode 100644 index 000000000..26e68b5d8 --- /dev/null +++ b/httemplate/misc/xmlhttp-cust_main-search.cgi @@ -0,0 +1,36 @@ +% if ( $sub eq 'custnum_search' ) { +%  +%   my $custnum = $cgi->param('arg'); +%   my $cust_main = ''; +%   if ( $custnum <= 2147483647 ) { +%     $cust_main = qsearchs({ +%       'table'   => 'cust_main', +%       'hashref' => { 'custnum' => $custnum }, +%       'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, +%     }); +%   } +%   if ( ! $cust_main ) { +%     $cust_main = qsearchs({ +%       'table'   => 'cust_main', +%       'hashref' => { 'agent_custid' => $custnum }, +%       'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, +%     }); +%   } +%      +"<% $cust_main ? $cust_main->name : '' %>" +% +% } elsif ( $sub eq 'smart_search' ) { +% +%   my $string = $cgi->param('arg'); +%   my @cust_main = smart_search( 'search' => $string ); +%   my $return = [ map [ $_->custnum, $_->name ], @cust_main ]; +%      +<% objToJson($return) %> +% }  +<%init> + +my $conf = new FS::Conf; + +my $sub = $cgi->param('sub'); + +</%init> diff --git a/httemplate/misc/xmlhttp-ping.html b/httemplate/misc/xmlhttp-ping.html new file mode 100644 index 000000000..e99303207 --- /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> diff --git a/httemplate/misc/xmlrpc.cgi b/httemplate/misc/xmlrpc.cgi new file mode 100644 index 000000000..1d0383f2a --- /dev/null +++ b/httemplate/misc/xmlrpc.cgi @@ -0,0 +1,18 @@ +% +% +%  my $request_xml = $cgi->param('POSTDATA'); +% +%  #$r->log_error($request_xml); +% +%  my $fsxmlrpc = new FS::XMLRPC; +%  my ($error, $response_xml) = $fsxmlrpc->serve($request_xml); +%   +%  #$r->log_error($error) if $error; +% +%  http_header('Content-Type' => 'text/xml', +%              'Content-Length' => length($response_xml)); +% +%  print $response_xml; +% +% + | 
