summaryrefslogtreecommitdiff
path: root/httemplate/search
diff options
context:
space:
mode:
Diffstat (limited to 'httemplate/search')
-rw-r--r--httemplate/search/cdr.html41
-rwxr-xr-xhttemplate/search/cust_bill.cgi165
-rwxr-xr-xhttemplate/search/cust_bill.html335
-rw-r--r--httemplate/search/cust_bill_event.cgi184
-rwxr-xr-xhttemplate/search/cust_bill_event.html32
-rw-r--r--httemplate/search/cust_bill_pkg.cgi157
-rwxr-xr-xhttemplate/search/cust_credit.html143
-rwxr-xr-xhttemplate/search/cust_main-otaker.cgi57
-rwxr-xr-xhttemplate/search/cust_main-payinfo.html20
-rwxr-xr-xhttemplate/search/cust_main-quickpay.html44
-rw-r--r--httemplate/search/cust_main-zip.html99
-rwxr-xr-xhttemplate/search/cust_main.cgi1401
-rwxr-xr-xhttemplate/search/cust_main.html5
-rwxr-xr-xhttemplate/search/cust_pay.cgi336
-rwxr-xr-xhttemplate/search/cust_pay.html18
-rwxr-xr-xhttemplate/search/cust_pay_batch.cgi190
-rwxr-xr-xhttemplate/search/cust_pkg.cgi405
-rwxr-xr-xhttemplate/search/cust_pkg_report.cgi23
-rw-r--r--httemplate/search/cust_svc.html138
-rw-r--r--httemplate/search/cust_tax_exempt_pkg.cgi182
-rw-r--r--httemplate/search/elements/search.html994
-rw-r--r--httemplate/search/inventory_item.html125
-rwxr-xr-xhttemplate/search/pay_batch.cgi130
-rw-r--r--httemplate/search/pay_batch.html33
-rw-r--r--httemplate/search/prepay_credit.html53
-rw-r--r--httemplate/search/queue.html139
-rw-r--r--httemplate/search/reg_code.html24
-rw-r--r--httemplate/search/report_cdr.html17
-rw-r--r--httemplate/search/report_cust_bill.html60
-rw-r--r--httemplate/search/report_cust_credit.html89
-rw-r--r--httemplate/search/report_cust_main-zip.html52
-rw-r--r--httemplate/search/report_cust_pay.html116
-rw-r--r--httemplate/search/report_cust_pay_batch.html43
-rwxr-xr-xhttemplate/search/report_cust_pkg.html144
-rw-r--r--httemplate/search/report_prepaid_income.cgi131
-rw-r--r--httemplate/search/report_prepaid_income.html32
-rwxr-xr-xhttemplate/search/report_receivables.cgi331
-rwxr-xr-xhttemplate/search/report_receivables.html26
-rwxr-xr-xhttemplate/search/report_tax.cgi571
-rwxr-xr-xhttemplate/search/report_tax.html62
-rw-r--r--httemplate/search/sql.html8
-rw-r--r--httemplate/search/sqlradius.cgi553
-rw-r--r--httemplate/search/sqlradius.html79
-rwxr-xr-xhttemplate/search/svc_acct.cgi138
-rwxr-xr-xhttemplate/search/svc_acct.html19
-rwxr-xr-xhttemplate/search/svc_broadband.cgi209
-rwxr-xr-xhttemplate/search/svc_domain.cgi125
-rwxr-xr-xhttemplate/search/svc_domain.html19
-rwxr-xr-xhttemplate/search/svc_external.cgi240
-rwxr-xr-xhttemplate/search/svc_forward.cgi119
-rw-r--r--httemplate/search/svc_phone.cgi115
-rwxr-xr-xhttemplate/search/svc_www.cgi122
52 files changed, 5525 insertions, 3368 deletions
diff --git a/httemplate/search/cdr.html b/httemplate/search/cdr.html
new file mode 100644
index 000000000..54c804c1a
--- /dev/null
+++ b/httemplate/search/cdr.html
@@ -0,0 +1,41 @@
+<% include( 'elements/search.html',
+ 'title' => $title,
+ 'name' => 'call detail records',
+ 'query' => { 'table' => 'cdr',
+ 'hashref' => $hashref
+ },
+ 'count_query' => $count_query,
+ 'header' => [ fields('cdr') ], #XXX fill in some nice names
+ 'fields' => [ fields('cdr') ], #XXX fill in some pretty-print
+ # processing, etc.
+ )
+%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('List rating data');
+
+my $title = 'Call Detail Records';
+my $hashref = {};
+my $count_query = 'SELECT COUNT(*) FROM cdr';
+
+#process params for CDR search, populate $hashref...
+# and fixup $count_query
+
+if ( $cgi->param('freesidestatus') eq 'NULL' ) {
+
+ my $title = "Unprocessed $title";
+ $hashref->{'freesidestatus'} = ''; # Record.pm will take care of it
+ #$count_query .= " AND ( freesidestatus IS NULL OR freesidestatus = '' )";
+ $count_query .= " WHERE ( freesidestatus IS NULL OR freesidestatus = '' )";
+
+} elsif ( $cgi->param('freesidestatus') =~ /^([\w ]+)$/ ) {
+
+ my $title = "Processed $title";
+ $hashref->{'freesidestatus'} = $1;
+ #$count_query .= " AND freesidestatus = '$1'";
+ $count_query .= " WHERE freesidestatus = '$1'";
+
+}
+
+</%init>
diff --git a/httemplate/search/cust_bill.cgi b/httemplate/search/cust_bill.cgi
deleted file mode 100755
index 5b0538ca3..000000000
--- a/httemplate/search/cust_bill.cgi
+++ /dev/null
@@ -1,165 +0,0 @@
-<%
-
-my $conf = new FS::Conf;
-my $maxrecords = $conf->config('maxsearchrecordsperpage');
-
-my $orderby = ''; #removeme
-
-my $limit = '';
-$limit .= "LIMIT $maxrecords" if $maxrecords;
-
-my $offset = $cgi->param('offset') || 0;
-$limit .= " OFFSET $offset" if $offset;
-
-my($total, $tot_amount, $tot_balance);
-
-my(@cust_bill);
-if ( $cgi->keywords ) {
- my($query) = $cgi->keywords;
- my $owed = "charged - ( select coalesce(sum(amount),0) from cust_bill_pay
- where cust_bill_pay.invnum = cust_bill.invnum )
- - ( select coalesce(sum(amount),0) from cust_credit_bill
- where cust_credit_bill.invnum = cust_bill.invnum )";
- my @where;
- if ( $query =~ /^(OPEN(\d*)_)?(invnum|date|custnum)$/ ) {
- my($open, $days, $field) = ($1, $2, $3);
- $field = "_date" if $field eq 'date';
- $orderby = "ORDER BY cust_bill.$field";
- push @where, "0 != $owed" if $open;
- push @where, "cust_bill._date < ". (time-86400*$days) if $days;
- } else {
- die "unknown query string $query";
- }
-
- my $extra_sql = scalar(@where) ? 'WHERE '. join(' AND ', @where) : '';
-
- my $statement = "SELECT COUNT(*), sum(charged), sum($owed)
- FROM cust_bill $extra_sql";
- my $sth = dbh->prepare($statement) or die dbh->errstr. " doing $statement";
- $sth->execute or die "Error executing \"$statement\": ". $sth->errstr;
-
- ( $total, $tot_amount, $tot_balance ) = @{$sth->fetchrow_arrayref};
-
- @cust_bill = qsearch(
- 'cust_bill',
- {},
- "cust_bill.*, $owed as owed",
- "$extra_sql $orderby $limit"
- );
-} else {
- $cgi->param('invnum') =~ /^\s*(FS-)?(\d+)\s*$/;
- my $invnum = $2;
- @cust_bill = qsearchs('cust_bill', { 'invnum' => $invnum } );
- $total = scalar(@cust_bill);
-}
-
-#if ( scalar(@cust_bill) == 1 ) {
-if ( $total == 1 ) {
- my $invnum = $cust_bill[0]->invnum;
- print $cgi->redirect(popurl(2). "view/cust_bill.cgi?$invnum"); #redirect
-} elsif ( scalar(@cust_bill) == 0 ) {
-%>
-<!-- mason kludge -->
-<%
- eidiot("Invoice not found.");
-} else {
-%>
-<!-- mason kludge -->
-<%
-
- #begin pager
- my $pager = '';
- if ( $total != scalar(@cust_bill) && $maxrecords ) {
- unless ( $offset == 0 ) {
- $cgi->param('offset', $offset - $maxrecords);
- $pager .= '<A HREF="'. $cgi->self_url.
- '"><B><FONT SIZE="+1">Previous</FONT></B></A> ';
- }
- my $poff;
- my $page;
- for ( $poff = 0; $poff < $total; $poff += $maxrecords ) {
- $page++;
- if ( $offset == $poff ) {
- $pager .= qq!<FONT SIZE="+2">$page</FONT> !;
- } else {
- $cgi->param('offset', $poff);
- $pager .= qq!<A HREF="!. $cgi->self_url. qq!">$page</A> !;
- }
- }
- unless ( $offset + $maxrecords > $total ) {
- $cgi->param('offset', $offset + $maxrecords);
- $pager .= '<A HREF="'. $cgi->self_url.
- '"><B><FONT SIZE="+1">Next</FONT></B></A> ';
- }
- }
- #end pager
-
- print header("Invoice Search Results", menubar(
- 'Main Menu', popurl(2)
- )).
- "$total matching invoices found<BR>".
- "\$$tot_balance total balance<BR>".
- "\$$tot_amount total amount<BR>".
- "<BR>$pager". table(). <<END;
- <TR>
- <TH></TH>
- <TH>Balance</TH>
- <TH>Amount</TH>
- <TH>Date</TH>
- <TH>Contact name</TH>
- <TH>Company</TH>
- </TR>
-END
-
- foreach my $cust_bill ( @cust_bill ) {
- my($invnum, $owed, $charged, $date ) = (
- $cust_bill->invnum,
- sprintf("%.2f", $cust_bill->getfield('owed')),
- sprintf("%.2f", $cust_bill->charged),
- $cust_bill->_date,
- );
- my $pdate = time2str("%b %d %Y", $date);
-
- my $rowspan = 1;
-
- my $view = popurl(2). "view/cust_bill.cgi?$invnum";
- print <<END;
- <TR>
- <TD ROWSPAN=$rowspan><A HREF="$view">$invnum</A></TD>
- <TD ROWSPAN=$rowspan ALIGN="right"><A HREF="$view">\$$owed</A></TD>
- <TD ROWSPAN=$rowspan ALIGN="right"><A HREF="$view">\$$charged</A></TD>
- <TD ROWSPAN=$rowspan><A HREF="$view">$pdate</A></TD>
-END
- my $custnum = $cust_bill->custnum;
- my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } );
- if ( $cust_main ) {
- my $cview = popurl(2). "view/cust_main.cgi?". $cust_main->custnum;
- my ( $name, $company ) = (
- $cust_main->last. ', '. $cust_main->first,
- $cust_main->company,
- );
- print <<END;
- <TD ROWSPAN=$rowspan><A HREF="$cview">$name</A></TD>
- <TD ROWSPAN=$rowspan><A HREF="$cview">$company</A></TD>
-END
- } else {
- print <<END
- <TD ROWSPAN=$rowspan COLSPAN=2>WARNING: couldn't find cust_main.custnum $custnum (cust_bill.invnum $invnum)</TD>
-END
- }
-
- print "</TR>";
- }
- $tot_balance = sprintf("%.2f", $tot_balance);
- $tot_amount = sprintf("%.2f", $tot_amount);
- print "</TABLE>$pager<BR>". table(). <<END;
- <TR><TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD><TH>Total<BR>Balance</TH><TH>Total<BR>Amount</TH></TR>
- <TR><TD></TD><TD ALIGN="right">\$$tot_balance</TD><TD ALIGN="right">\$$tot_amount</TD></TD></TR>
- </TABLE>
- </BODY>
-</HTML>
-END
-
-}
-
-%>
diff --git a/httemplate/search/cust_bill.html b/httemplate/search/cust_bill.html
index 2108653a8..b65608eab 100755
--- a/httemplate/search/cust_bill.html
+++ b/httemplate/search/cust_bill.html
@@ -1,150 +1,4 @@
-<%
- my( $count_query, $sql_query );
- my( $count_addl ) = ( '' );
- my( $distinct ) = ( '' );
- my($begin, $end) = ( '', '' );
- my($agentnum) = ( '' );
- my($open, $days) = ( '', '' );
- if ( $cgi->param('invnum') =~ /^\s*(FS-)?(\d+)\s*$/ ) {
- $count_query = "SELECT COUNT(*) FROM cust_bill WHERE invnum = $2";
- $sql_query = {
- 'table' => 'cust_bill',
- 'hashref' => { 'invnum' => $2 },
- #'select' => '*',
- };
- } else {
- #if ( $cgi->param('begin') || $cgi->param('end')
- # || $cgi->param('beginning') || $cgi->param('ending')
- # || $cgi->keywords
- # )
- #{
-
- #some false laziness w/cust_bill::re_X
- my @where;
- my $orderby = 'ORDER BY cust_bill._date';
-
- if ( $cgi->param('beginning')
- && $cgi->param('beginning') =~ /^([ 0-9\-\/]{0,10})$/ ) {
- $begin = str2time($1);
- push @where, "cust_bill._date >= $begin";
- }
- if ( $cgi->param('ending')
- && $cgi->param('ending') =~ /^([ 0-9\-\/]{0,10})$/ ) {
- $end = str2time($1) + 86399;
- push @where, "cust_bill._date < $end";
- }
-
- if ( $cgi->param('begin') =~ /^(\d+)$/ ) {
- $begin = $1;
- push @where, "cust_bill._date >= $begin";
- }
- if ( $cgi->param('end') =~ /^(\d+)$/ ) {
- $end = $1;
- push @where, "cust_bill._date < $end";
- }
-
- if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) {
- $agentnum = $1;
- push @where, "cust_main.agentnum = $agentnum";
- }
-
- my $owed =
- "charged - ( SELECT COALESCE(SUM(amount),0) FROM cust_bill_pay
- WHERE cust_bill_pay.invnum = cust_bill.invnum )
- - ( SELECT COALESCE(SUM(amount),0) FROM cust_credit_bill
- WHERE cust_credit_bill.invnum = cust_bill.invnum )";
-
- if ( $cgi->param('open') ) {
- push @where, "0 != $owed";
- $open = 1;
- }
-
- my($query) = $cgi->keywords;
- if ( $query =~ /^(OPEN(\d*)_)?(invnum|date|custnum)$/ ) {
- ($open, $days, my $field) = ($1, $2, $3);
- $field = "_date" if $field eq 'date';
- $orderby = "ORDER BY cust_bill.$field";
- push @where, "0 != $owed" if $open;
- push @where, "cust_bill._date < ". (time-86400*$days) if $days;
- }
-
- my $extra_sql = scalar(@where) ? 'WHERE '. join(' AND ', @where) : '';
-
- my $addl_from = 'left join cust_main using ( custnum )';
-
- if ( $cgi->param('newest_percust') ) {
- $distinct = 'DISTINCT ON ( cust_bill.custnum )';
- $orderby = 'ORDER BY cust_bill.custnum ASC, cust_bill._date DESC';
- #$count_query = "SELECT 'N/A', 'N/A', 'N/A'"; #XXXXXXX fix
- $count_query = "SELECT COUNT(DISTINCT cust_bill.custnum), 'N/A', 'N/A'";
- }
-
- unless ( $count_query ) {
- $count_query = "SELECT COUNT(*), sum(charged), sum($owed)";
- $count_addl = [ '$%.2f total invoiced',
- '$%.2f total outstanding balance',
- ];
- }
- $count_query .= " FROM cust_bill $addl_from $extra_sql";
-
- $sql_query = {
- 'table' => 'cust_bill',
- 'addl_from' => $addl_from,
- 'hashref' => {},
- 'select' => "$distinct ". join(', ',
- 'cust_bill.*',
- #( map "cust_main.$_", qw(custnum last first company) ),
- 'cust_main.custnum as cust_main_custnum',
- FS::UI::Web::cust_sql_fields(),
- "$owed as owed",
- ),
- 'extra_sql' => "$extra_sql $orderby"
- };
-
- }
-
- my $link = [ "${p}view/cust_bill.cgi?", 'invnum', ];
- my $clink = sub {
- my $cust_bill = shift;
- $cust_bill->cust_main_custnum
- ? [ "${p}view/cust_main.cgi?", 'custnum' ]
- : '';
- };
-
- my $conf = new FS::Conf;
- my $money_char = $conf->config('money_char') || '$';
-
- my $html_init = join("\n", map {
- ( my $action = $_ ) =~ s/_$//;
- include('/elements/progress-init.html',
- $_.'form',
- [ 'begin', 'end', 'agentnum', 'open', 'days', 'newest_percust' ],
- "../misc/${_}invoices.cgi",
- { 'message' => "Invoices re-${action}ed" }, #would be nice to show the number of them, but...
- $_, #key
- ),
- qq!<FORM NAME="${_}form">!,
- qq!<INPUT TYPE="hidden" NAME="begin" VALUE="$begin">!,
- qq!<INPUT TYPE="hidden" NAME="end" VALUE="$end">!,
- qq!<INPUT TYPE="hidden" NAME="agentnum" VALUE="$agentnum">!,
- qq!<INPUT TYPE="hidden" NAME="open" VALUE="$open">!,
- qq!<INPUT TYPE="hidden" NAME="days" VALUE="$days">!,
- qq!</FORM>!
- } qw( print_ email_ fax_ ) );
-
- my $menubar = [
- 'Main menu' => $p,
- 'Print these invoices' =>
- "javascript:print_process()",
- 'Email these invoices' =>
- "javascript:email_process()",
- ];
-
- push @$menubar, 'Fax these invoices' =>
- "javascript:fax_process()"
- if $conf->exists('hylafax');
-
-%><%= include( 'elements/search.html',
+<% include( 'elements/search.html',
'title' => 'Invoice Search Results',
'html_init' => $html_init,
'menubar' => $menubar,
@@ -166,14 +20,197 @@
sub { time2str('%b %d %Y', shift->_date ) },
\&FS::UI::Web::cust_fields,
],
- 'align' => 'rrrrll',
+ 'align' => 'rrrr'.FS::UI::Web::cust_aligns(),
'links' => [
$link,
$link,
$link,
$link,
- ( map { $clink } FS::UI::Web::cust_header() ),
+ ( map { $_ ne 'Cust. Status' ? $clink : '' }
+ FS::UI::Web::cust_header()
+ ),
],
+ 'color' => [
+ '',
+ '',
+ '',
+ '',
+ FS::UI::Web::cust_colors(),
+ ],
+ 'style' => [
+ '',
+ '',
+ '',
+ '',
+ FS::UI::Web::cust_styles(),
+ ],
+
)
%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('List invoices');
+
+my $join_cust_main = 'LEFT JOIN cust_main USING ( custnum )';
+#here is the agent virtualization
+my $agentnums_sql = $FS::CurrentUser::CurrentUser->agentnums_sql;
+
+my( $count_query, $sql_query );
+my( $count_addl ) = ( '' );
+my( $distinct ) = ( '' );
+my($begin, $end) = ( '', '' );
+my($agentnum) = ( '' );
+my($open, $days) = ( '', '' );
+if ( $cgi->param('invnum') =~ /^\s*(FS-)?(\d+)\s*$/ ) {
+ $count_query =
+ "SELECT COUNT(*) FROM cust_bill $join_cust_main".
+ " WHERE invnum = $2 AND $agentnums_sql"; #agent virtualization
+ $sql_query = {
+ 'table' => 'cust_bill',
+ 'addl_from' => $join_cust_main,
+ 'hashref' => { 'invnum' => $2 },
+ #'select' => '*',
+ 'extra_sql' => " AND $agentnums_sql", #agent virtualization
+ };
+} else {
+#if ( $cgi->param('begin') || $cgi->param('end')
+# || $cgi->param('beginning') || $cgi->param('ending')
+# || $cgi->keywords
+# )
+#{
+
+ #some false laziness w/cust_bill::re_X
+ my @where;
+ my $orderby = 'ORDER BY cust_bill._date';
+
+ if ( $cgi->param('beginning')
+ && $cgi->param('beginning') =~ /^([ 0-9\-\/]{0,10})$/ ) {
+ $begin = str2time($1);
+ push @where, "cust_bill._date >= $begin";
+ }
+ if ( $cgi->param('ending')
+ && $cgi->param('ending') =~ /^([ 0-9\-\/]{0,10})$/ ) {
+ $end = str2time($1) + 86399;
+ push @where, "cust_bill._date < $end";
+ }
+
+ if ( $cgi->param('begin') =~ /^(\d+)$/ ) {
+ $begin = $1;
+ push @where, "cust_bill._date >= $begin";
+ }
+ if ( $cgi->param('end') =~ /^(\d+)$/ ) {
+ $end = $1;
+ push @where, "cust_bill._date < $end";
+ }
+
+ if ( $cgi->param('invnum_min') =~ /^\s*(\d+)\s*$/ ) {
+ push @where, "cust_bill.invnum >= $1";
+ }
+ if ( $cgi->param('invnum_max') =~ /^\s*(\d+)\s*$/ ) {
+ push @where, "cust_bill.invnum <= $1";
+ }
+
+ if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) {
+ $agentnum = $1;
+ push @where, "cust_main.agentnum = $agentnum";
+ }
+
+ my $owed =
+ "charged - ( SELECT COALESCE(SUM(amount),0) FROM cust_bill_pay
+ WHERE cust_bill_pay.invnum = cust_bill.invnum )
+ - ( SELECT COALESCE(SUM(amount),0) FROM cust_credit_bill
+ WHERE cust_credit_bill.invnum = cust_bill.invnum )";
+
+ if ( $cgi->param('open') ) {
+ push @where, "0 != $owed";
+ $open = 1;
+ }
+
+ my($query) = $cgi->keywords;
+ if ( $query =~ /^(OPEN(\d*)_)?(invnum|date|custnum)$/ ) {
+ ($open, $days, my $field) = ($1, $2, $3);
+ $field = "_date" if $field eq 'date';
+ $orderby = "ORDER BY cust_bill.$field";
+ push @where, "0 != $owed" if $open;
+ push @where, "cust_bill._date < ". (time-86400*$days) if $days;
+ }
+
+ #here is the agent virtualization
+ push @where, $agentnums_sql;
+ my $extra_sql = scalar(@where) ? 'WHERE '. join(' AND ', @where) : '';
+
+ if ( $cgi->param('newest_percust') ) {
+ $distinct = 'DISTINCT ON ( cust_bill.custnum )';
+ $orderby = 'ORDER BY cust_bill.custnum ASC, cust_bill._date DESC';
+ #$count_query = "SELECT 'N/A', 'N/A', 'N/A'"; #XXXXXXX fix
+ $count_query = "SELECT COUNT(DISTINCT cust_bill.custnum), 'N/A', 'N/A'";
+ }
+
+ unless ( $count_query ) {
+ $count_query = "SELECT COUNT(*), sum(charged), sum($owed)";
+ $count_addl = [ '$%.2f total invoiced',
+ '$%.2f total outstanding balance',
+ ];
+ }
+ $count_query .= " FROM cust_bill $join_cust_main $extra_sql";
+
+ $sql_query = {
+ 'table' => 'cust_bill',
+ 'addl_from' => $join_cust_main,
+ 'hashref' => {},
+ 'select' => "$distinct ". join(', ',
+ 'cust_bill.*',
+ #( map "cust_main.$_", qw(custnum last first company) ),
+ 'cust_main.custnum as cust_main_custnum',
+ FS::UI::Web::cust_sql_fields(),
+ "$owed as owed",
+ ),
+ 'extra_sql' => "$extra_sql $orderby"
+ };
+
+}
+
+my $link = [ "${p}view/cust_bill.cgi?", 'invnum', ];
+my $clink = sub {
+ my $cust_bill = shift;
+ $cust_bill->cust_main_custnum
+ ? [ "${p}view/cust_main.cgi?", 'custnum' ]
+ : '';
+};
+
+my $conf = new FS::Conf;
+my $money_char = $conf->config('money_char') || '$';
+
+my $html_init = join("\n", map {
+ ( my $action = $_ ) =~ s/_$//;
+ include('/elements/progress-init.html',
+ $_.'form',
+ [ 'begin', 'end', 'agentnum', 'open', 'days', 'newest_percust' ],
+ "../misc/${_}invoices.cgi",
+ { 'message' => "Invoices re-${action}ed" }, #would be nice to show the number of them, but...
+ $_, #key
+ ),
+ qq!<FORM NAME="${_}form">!,
+ qq!<INPUT TYPE="hidden" NAME="begin" VALUE="$begin">!,
+ qq!<INPUT TYPE="hidden" NAME="end" VALUE="$end">!,
+ qq!<INPUT TYPE="hidden" NAME="agentnum" VALUE="$agentnum">!,
+ qq!<INPUT TYPE="hidden" NAME="open" VALUE="$open">!,
+ qq!<INPUT TYPE="hidden" NAME="days" VALUE="$days">!,
+ qq!</FORM>!
+} qw( print_ email_ fax_ ) );
+
+my $menubar = [
+ 'Main menu' => $p,
+ 'Print these invoices' =>
+ "javascript:print_process()",
+ 'Email these invoices' =>
+ "javascript:email_process()",
+ ];
+
+push @$menubar, 'Fax these invoices' =>
+ "javascript:fax_process()"
+ if $conf->exists('hylafax');
+
+</%init>
diff --git a/httemplate/search/cust_bill_event.cgi b/httemplate/search/cust_bill_event.cgi
index d82a83368..ada7e4362 100644
--- a/httemplate/search/cust_bill_event.cgi
+++ b/httemplate/search/cust_bill_event.cgi
@@ -1,52 +1,123 @@
-<%
+<% include( 'elements/search.html',
+ 'title' => $title,
+ 'html_init' => $html_init,
+ 'menubar' => $menubar,
+ 'name' => 'billing events',
+ 'query' => $sql_query,
+ 'count_query' => $count_sql,
+ 'header' => [ 'Event',
+ 'Date',
+ 'Status',
+ #'Inv #', 'Inv Date', 'Cust #',
+ 'Invoice',
+ FS::UI::Web::cust_header(),
+ ],
+ 'fields' => [
+ 'event',
+ sub { time2str("%b %d %Y %T", $_[0]->_date) },
+ sub {
+ #my $cust_bill_event = shift;
+ my $status = $_[0]->status;
+ $status .= ': '.$_[0]->statustext
+ if $_[0]->statustext;
+ $status;
+ },
+ sub {
+ #my $cust_bill_event = shift;
+ 'Invoice #'. $_[0]->invnum.
+ ' ('.
+ time2str("%D", $_[0]->cust_bill_date).
+ ')';
+ },
+ \&FS::UI::Web::cust_fields,
+ ],
+ 'align' => 'lrlr'.FS::UI::Web::cust_aligns(),
+ 'links' => [
+ '',
+ '',
+ '',
+ sub {
+ my $part_bill_event = shift;
+ my $template = $part_bill_event->templatename;
+ $template .= '-' if $template;
+ [ "${p}view/cust_bill.cgi?$template", 'invnum'];
+ },
+ ( map { $_ ne 'Cust. Status' ? $link_cust : '' }
+ FS::UI::Web::cust_header()
+ ),
+ ],
+ 'color' => [
+ '',
+ '',
+ '',
+ '',
+ FS::UI::Web::cust_colors(),
+ ],
+ 'style' => [
+ '',
+ '',
+ '',
+ '',
+ FS::UI::Web::cust_styles(),
+ ],
+ )
+%>
+<%init>
-my $title = $cgi->param('failed') ? 'Failed invoice events' : 'Invoice events';
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Billing event reports');
-my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi);
+my $title = $cgi->param('failed')
+ ? 'Failed invoice events'
+ : 'Invoice events';
+
+my @search = ();
-##tie my %hash, 'Tie::DxHash',
-#my %hash = (
-# _date => { op=> '>=', value=>$beginning },
-## i wish...
-## _date => { op=> '<=', value=>$ending },
-#);
-#$hash{'statustext'} = { op=> '!=', value=>'' }
-# if $cgi->param('failed');
+if ( $cgi->param('agentnum') && $cgi->param('agentnum') =~ /^(\d+)$/ ) {
+ push @search, "agentnum = $1";
+ #my $agent = qsearchs('agent', { 'agentnum' => $1 } );
+ #die "unknown agentnum $1" unless $agent;
+}
-my $where = " WHERE cust_bill_event._date >= $beginning".
- " AND cust_bill_event._date <= $ending";
+my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi);
+push @search, "cust_bill_event._date >= $beginning",
+ "cust_bill_event._date <= $ending";
if ( $cgi->param('failed') ) {
- $where .= " AND statustext != '' ".
- " AND statustext IS NOT NULL ".
- " AND statustext != 'N/A' "
+ push @search, "statustext != ''",
+ "statustext IS NOT NULL",
+ "statustext != 'N/A'";
}
if ( $cgi->param('part_bill_event.payby') =~ /^(\w+)$/ ) {
- $where .= " AND part_bill_event.payby = '$1' ";
+ push @search, "part_bill_event.payby = '$1'";
}
+#here is the agent virtualization
+push @search, $FS::CurrentUser::CurrentUser->agentnums_sql;
+
+my $where = 'WHERE '. join(' AND ', @search );
+
+my $join = 'LEFT JOIN part_bill_event USING ( eventpart ) '.
+ 'LEFT JOIN cust_bill USING ( invnum ) '.
+ 'LEFT JOIN cust_main USING ( custnum ) ';
+
my $sql_query = {
'table' => 'cust_bill_event',
- #'hashref' => \%hash,
- 'hashref' => {},
'select' => join(', ',
- 'cust_bill_event.*',
- 'part_bill_event.event',
- 'cust_bill.custnum',
- 'cust_bill._date AS cust_bill_date',
- 'cust_main.custnum AS cust_main_custnum',
- FS::UI::Web::cust_sql_fields(),
- ),
+ 'cust_bill_event.*',
+ 'part_bill_event.event',
+ 'cust_bill.custnum',
+ 'cust_bill._date AS cust_bill_date',
+ 'cust_main.custnum AS cust_main_custnum',
+ FS::UI::Web::cust_sql_fields(),
+ ),
+ 'hashref' => {},
'extra_sql' => "$where ORDER BY _date ASC",
- 'addl_from' => 'LEFT JOIN part_bill_event USING ( eventpart ) '.
- 'LEFT JOIN cust_bill USING ( invnum ) '.
- 'LEFT JOIN cust_main USING ( custnum ) ',
+ 'addl_from' => $join,
};
-my $count_sql = "SELECT COUNT(*) FROM cust_bill_event ".
- "LEFT JOIN part_bill_event USING ( eventpart ) ".
- $where;
+my $count_sql = "SELECT COUNT(*) FROM cust_bill_event $join $where";
my $conf = new FS::Conf;
@@ -70,7 +141,6 @@ my $html_init = join("\n", map {
} qw( print_ email_ fax_ ) );
my $menubar = [
- 'Main menu' => $p,
'Re-print these events' =>
"javascript:print_process()",
'Re-email these events' =>
@@ -88,50 +158,4 @@ my $link_cust = sub {
: '';
};
-%><%= include( 'elements/search.html',
- 'title' => $title,
- 'html_init' => $html_init,
- 'menubar' => $menubar,
- 'name' => 'billing events',
- 'query' => $sql_query,
- 'count_query' => $count_sql,
- 'header' => [ 'Event',
- 'Date',
- 'Status',
- #'Inv #', 'Inv Date', 'Cust #',
- 'Invoice',
- FS::UI::Web::cust_header(),
- ],
- 'fields' => [
- 'event',
- sub { time2str("%b %d %Y %T", $_[0]->_date) },
- sub {
- #my $cust_bill_event = shift;
- my $status = $_[0]->status;
- $status .= ': '.$_[0]->statustext
- if $_[0]->statustext;
- $status;
- },
- sub {
- #my $cust_bill_event = shift;
- 'Invoice #'. $_[0]->invnum.
- ' ('.
- time2str("%D", $_[0]->cust_bill_date).
- ')';
- },
- \&FS::UI::Web::cust_fields,
- ],
- 'links' => [
- '',
- '',
- '',
- sub {
- my $part_bill_event = shift;
- my $template = $part_bill_event->templatename;
- $template .= '-' if $template;
- [ "${p}view/cust_bill.cgi?$template", 'invnum'];
- },
- ( map { $link_cust } FS::UI::Web::cust_header() ),
- ],
- )
-%>
+</%init>
diff --git a/httemplate/search/cust_bill_event.html b/httemplate/search/cust_bill_event.html
index 197f28028..334bda3d3 100755
--- a/httemplate/search/cust_bill_event.html
+++ b/httemplate/search/cust_bill_event.html
@@ -1,16 +1,15 @@
-<%= include(
+<% include(
'/elements/header.html',
( $cgi->param('failed') ? 'Failed invoice events' : 'Invoice events' ),
- include('/elements/menubar.html',
- 'Main menu' => $p, # popurl(2),
- ),
-
- )
+ )
%>
<FORM ACTION="cust_bill_event.cgi" METHOD="GET">
- <INPUT TYPE="hidden" NAME="failed" VALUE="<%= $cgi->param('failed') %>">
+ <INPUT TYPE="hidden" NAME="failed" VALUE="<% $cgi->param('failed') %>">
<TABLE>
+
+ <% include( '/elements/tr-select-agent.html' ) %>
+
<!--<TR>
<TD ALIGN="right">Customer type</TD>
<TD><SELECT MULTIPLE NAME="perhaps_payby">
@@ -23,15 +22,16 @@
</TD>
</TR>
-->
- <%= include( '/elements/tr-input-beginning_ending.html' ) %>
+ <% include( '/elements/tr-input-beginning_ending.html' ) %>
<!--
<TR>
<TD ALIGN="right">Events: </TD>
<TD>
<SELECT NAME="eventpart">
- <OPTION SELECTED VALUE=""><%= $cgi->param('failed') ? '(all failed events)' : '(all events)' %>
- <% foreach my $part_bill_event ( qsearch( 'part_bill_event', {} ) ) { %>
- <% } %>
+ <OPTION SELECTED VALUE=""><% $cgi->param('failed') ? '(all failed events)' : '(all events)' %>
+% #foreach my $part_bill_event ( qsearch( 'part_bill_event', {} ) ) {
+% #}
+
</SELECT>
</TD>
</TR>
@@ -54,5 +54,11 @@
</TABLE>
<BR><INPUT TYPE="submit" VALUE="Get Report">
</FORM>
- </BODY>
-</HTML>
+
+<% include('/elements/footer.html') %>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Billing event reports');
+
+</%init>
diff --git a/httemplate/search/cust_bill_pkg.cgi b/httemplate/search/cust_bill_pkg.cgi
index 082ccc893..17b4bc240 100644
--- a/httemplate/search/cust_bill_pkg.cgi
+++ b/httemplate/search/cust_bill_pkg.cgi
@@ -1,10 +1,74 @@
-<%
+<% include( 'elements/search.html',
+ 'title' => 'Line items',
+ 'name' => 'line items',
+ 'query' => $query,
+ 'count_query' => $count_query,
+ 'count_addl' => [ $money_char. '%.2f total', ],
+ 'header' => [
+ '#',
+ 'Description',
+ 'Setup charge',
+ 'Recurring charge',
+ 'Invoice',
+ 'Date',
+ FS::UI::Web::cust_header(),
+ ],
+ 'fields' => [
+ 'billpkgnum',
+ sub { $_[0]->pkgnum > 0
+ ? $_[0]->get('pkg')
+ : $_[0]->get('itemdesc')
+ },
+ #strikethrough or "N/A ($amount)" or something these when
+ # they're not applicable to pkg_tax search
+ sub { sprintf($money_char.'%.2f', shift->setup ) },
+ sub { sprintf($money_char.'%.2f', shift->recur ) },
+ 'invnum',
+ sub { time2str('%b %d %Y', shift->_date ) },
+ \&FS::UI::Web::cust_fields,
+ ],
+ 'links' => [
+ '',
+ '',
+ '',
+ '',
+ $ilink,
+ $ilink,
+ ( map { $_ ne 'Cust. Status' ? $clink : '' }
+ FS::UI::Web::cust_header()
+ ),
+ ],
+ 'align' => 'rlrrrc'.FS::UI::Web::cust_aligns(),
+ 'color' => [
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ FS::UI::Web::cust_colors(),
+ ],
+ 'style' => [
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ FS::UI::Web::cust_styles(),
+ ],
+ )
+%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi);
my $join_cust = "
JOIN cust_bill USING ( invnum )
- JOIN cust_main USING ( custnum )
+ LEFT JOIN cust_main USING ( custnum )
";
my $join_pkg = "
@@ -12,10 +76,22 @@ my $join_pkg = "
LEFT JOIN part_pkg USING ( pkgpart )
";
-my $where = "
- WHERE _date >= $beginning AND _date <= $ending
- AND payby != 'COMP'
-";
+my $where = " WHERE _date >= $beginning AND _date <= $ending ";
+
+$where .= " AND payby != 'COMP' "
+ unless $cgi->param('include_comp_cust');
+
+if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) {
+ $where .= " AND agentnum = $1 ";
+}
+
+if ( $cgi->param('classnum') =~ /^(\d+)$/ ) {
+ if ( $1 == 0 ) {
+ $where .= " AND classnum IS NULL ";
+ } else {
+ $where .= " AND classnum = $1 ";
+ }
+}
if ( $cgi->param('out') ) {
@@ -62,19 +138,27 @@ my $count_query;
if ( $cgi->param('pkg_tax') ) {
$count_query =
- "SELECT COUNT(*), SUM( ( CASE WHEN part_pkg.setuptax = 'Y'
- THEN cust_bill_pkg.setup
- ELSE 0 )
- +
- ( CASE WHEN part_pkg.recurtax = 'Y'
- THEN cust_bill_pkg.recur
- ELSE 0 )
- )";
+ "SELECT COUNT(*), SUM(
+ ( CASE WHEN part_pkg.setuptax = 'Y'
+ THEN cust_bill_pkg.setup
+ ELSE 0
+ END
+ )
+ +
+ ( CASE WHEN part_pkg.recurtax = 'Y'
+ THEN cust_bill_pkg.recur
+ ELSE 0
+ END
+ )
+ )
+ ";
$where .= " AND (
( part_pkg.setuptax = 'Y' AND cust_bill_pkg.setup > 0 )
OR ( part_pkg.recurtax = 'Y' AND cust_bill_pkg.recur > 0 )
- )";
+ )
+ AND ( tax != 'Y' OR tax IS NULL )
+ ";
} else {
@@ -104,45 +188,4 @@ my $clink = [ "${p}view/cust_main.cgi?", 'custnum' ];
my $conf = new FS::Conf;
my $money_char = $conf->config('money_char') || '$';
-%><%= include( 'elements/search.html',
- 'title' => 'Line items',
- 'name' => 'line items',
- 'query' => $query,
- 'count_query' => $count_query,
- 'count_addl' => [ $money_char. '%.2f total', ],
- 'header' => [
- '#',
- 'Description',
- 'Setup charge',
- 'Recurring charge',
- 'Invoice',
- 'Date',
- FS::UI::Web::cust_header(),
- ],
- 'fields' => [
- 'billpkgnum',
- sub { $_[0]->pkgnum > 0
- ? $_[0]->get('pkg')
- : $_[0]->get('itemdesc')
- },
- #strikethrough or "N/A ($amount)" or something these when
- # they're not applicable to pkg_tax search
- sub { sprintf($money_char.'%.2f', shift->setup ) },
- sub { sprintf($money_char.'%.2f', shift->recur ) },
- 'invnum',
- sub { time2str('%b %d %Y', shift->_date ) },
- \&FS::UI::Web::cust_fields,
- ],
- 'links' => [
- '',
- '',
- '',
- '',
- $ilink,
- $ilink,
- ( map { $clink } FS::UI::Web::cust_header() ),
- ],
- 'align' => 'rlrrrc',
- )
-%>
-
+</%init>
diff --git a/httemplate/search/cust_credit.html b/httemplate/search/cust_credit.html
index 279d682cd..e4975c8de 100755
--- a/httemplate/search/cust_credit.html
+++ b/httemplate/search/cust_credit.html
@@ -1,69 +1,4 @@
-<%
- my $title = 'Credit Search Results';
- #my( $count_query, $sql_query );
-
- my @search = ();
-
- if ( $cgi->param('otaker') && $cgi->param('otaker') =~ /^([\w\.\-]+)$/ ) {
- push @search, "cust_credit.otaker = '$1'";
- }
-
- if ( $cgi->param('agentnum') && $cgi->param('agentnum') =~ /^(\d+)$/ ) {
- push @search, "agentnum = $1";
- my $agent = qsearchs('agent', { 'agentnum' => $1 } );
- die "unknown agentnum $1" unless $agent;
- $title = $agent->agent. " $title";
- }
-
- #false laziness with cust_pkg.cgi and cust_pay.cgi
- if ( $cgi->param('beginning')
- && $cgi->param('beginning') =~ /^([ 0-9\-\/]{1,10})$/ ) {
- my $beginning = str2time($1);
- push @search, "_date >= $beginning ";
- }
- if ( $cgi->param('ending')
- && $cgi->param('ending') =~ /^([ 0-9\-\/]{1,10})$/ ) {
- my $ending = str2time($1) + 86399;
- push @search, " _date <= $ending ";
- }
-
- if ( $cgi->param('begin')
- && $cgi->param('begin') =~ /^(\d+)$/ ) {
- push @search, "_date >= $1 ";
- }
- if ( $cgi->param('end')
- && $cgi->param('end') =~ /^(\d+)$/ ) {
- push @search, " _date < $1 ";
- }
-
- my $where = scalar(@search)
- ? 'WHERE '. join(' AND ', @search)
- : '';
-
- my $count_query = 'SELECT COUNT(*), SUM(amount) '.
- 'FROM cust_credit LEFT JOIN cust_main USING ( custnum ) '.
- $where;
-
- my $sql_query = {
- 'table' => 'cust_credit',
- 'select' => join(', ',
- 'cust_credit.*',
- 'cust_main.custnum as cust_main_custnum',
- FS::UI::Web::cust_sql_fields(),
- ),
- 'hashref' => {},
- 'extra_sql' => $where,
- 'addl_from' => 'LEFT JOIN cust_main USING ( custnum )',
- };
-
- my $clink = sub {
- my $cust_bill = shift;
- $cust_bill->cust_main_custnum
- ? [ "${p}view/cust_main.cgi?", 'custnum' ]
- : '';
- };
-
-%><%= include( 'elements/search.html',
+<% include( 'elements/search.html',
'title' => $title,
'name' => 'credits',
'query' => $sql_query,
@@ -85,13 +20,85 @@
'reason',
],
#'align' => 'rrrllll',
- 'align' => 'rr',
+ 'align' => 'rr'.FS::UI::Web::cust_aligns().'ll',
'links' => [
'',
'',
- ( map { $clink } FS::UI::Web::cust_header() ),
+ ( map { $_ ne 'Cust. Status' ? $clink : '' }
+ FS::UI::Web::cust_header()
+ ),
'',
'',
],
+ 'color' => [
+ '',
+ '',
+ FS::UI::Web::cust_colors(),
+ '',
+ '',
+ ],
+ 'style' => [
+ '',
+ '',
+ FS::UI::Web::cust_styles(),
+ '',
+ '',
+ ],
)
%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
+
+my $title = 'Credit Search Results';
+#my( $count_query, $sql_query );
+
+my @search = ();
+
+if ( $cgi->param('otaker') && $cgi->param('otaker') =~ /^([\w\.\-]+)$/ ) {
+ push @search, "cust_credit.otaker = '$1'";
+}
+
+if ( $cgi->param('agentnum') && $cgi->param('agentnum') =~ /^(\d+)$/ ) {
+ push @search, "agentnum = $1";
+ my $agent = qsearchs('agent', { 'agentnum' => $1 } );
+ die "unknown agentnum $1" unless $agent;
+ $title = $agent->agent. " $title";
+}
+
+my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi);
+push @search, "_date >= $beginning ",
+ "_date <= $ending";
+
+push @search, FS::UI::Web::parse_lt_gt($cgi, 'amount' );
+
+#here is the agent virtualization
+push @search, $FS::CurrentUser::CurrentUser->agentnums_sql;
+
+my $where = 'WHERE '. join(' AND ', @search);
+
+my $count_query = 'SELECT COUNT(*), SUM(amount) '.
+ 'FROM cust_credit LEFT JOIN cust_main USING ( custnum ) '.
+ $where;
+
+my $sql_query = {
+ 'table' => 'cust_credit',
+ 'select' => join(', ',
+ 'cust_credit.*',
+ 'cust_main.custnum as cust_main_custnum',
+ FS::UI::Web::cust_sql_fields(),
+ ),
+ 'hashref' => {},
+ 'extra_sql' => $where,
+ 'addl_from' => 'LEFT JOIN cust_main USING ( custnum )',
+};
+
+ my $clink = sub {
+ my $cust_bill = shift;
+ $cust_bill->cust_main_custnum
+ ? [ "${p}view/cust_main.cgi?", 'custnum' ]
+ : '';
+ };
+
+</%init>
diff --git a/httemplate/search/cust_main-otaker.cgi b/httemplate/search/cust_main-otaker.cgi
index 03c2619af..0c252e44b 100755
--- a/httemplate/search/cust_main-otaker.cgi
+++ b/httemplate/search/cust_main-otaker.cgi
@@ -1,28 +1,31 @@
-<HTML>
- <HEAD>
- <TITLE>Customer Search</TITLE>
- </HEAD>
- <BODY BGCOLOR="#e8e8e8">
- <FONT SIZE=7>
- Customer Search
- </FONT>
- <BR>
- <FORM ACTION="cust_main.cgi" METHOD="GET">
- Search for <B>Order taker</B>:
- <INPUT TYPE="hidden" NAME="otaker_on" VALUE="TRUE">
- <% my $sth = dbh->prepare("SELECT DISTINCT otaker FROM cust_main")
- or die dbh->errstr;
- $sth->execute() or die $sth->errstr;
-# my @otakers = map { $_->[0] } @{$sth->selectall_arrayref};
- %>
- <SELECT NAME="otaker">
- <% my $otaker; while ( $otaker = $sth->fetchrow_arrayref ) { %>
- <OPTION><%= $otaker->[0] %></OTAKER>
- <% } %>
- </SELECT>
- <P><INPUT TYPE="submit" VALUE="Search">
-
- </FORM>
- </BODY>
-</HTML>
+<% include('/elements/header.html', 'Customer Search' ) %>
+<FORM ACTION="cust_main.cgi" METHOD="GET">
+
+Search for <B>Order taker</B>:
+ <INPUT TYPE="hidden" NAME="otaker_on" VALUE="TRUE">
+% my $sth = dbh->prepare("SELECT DISTINCT otaker FROM cust_main")
+% or die dbh->errstr;
+% $sth->execute() or die $sth->errstr;
+% #my @otakers = map { $_->[0] } @{$sth->fetchall_arrayref};
+%
+
+<SELECT NAME="otaker">
+% my $otaker; while ( $otaker = $sth->fetchrow_arrayref ) {
+
+ <OPTION><% $otaker->[0] %>
+% }
+
+</SELECT>
+
+<P><INPUT TYPE="submit" VALUE="Search">
+
+</FORM>
+
+<% include('/elements/footer.html') %>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+</%init>
diff --git a/httemplate/search/cust_main-payinfo.html b/httemplate/search/cust_main-payinfo.html
deleted file mode 100755
index b82b610d8..000000000
--- a/httemplate/search/cust_main-payinfo.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<HTML>
- <HEAD>
- <TITLE>Customer Search</TITLE>
- </HEAD>
- <BODY BGCOLOR="#e8e8e8">
- <FONT SIZE=7>
- Customer Search
- </FONT>
- <BR>
- <FORM ACTION="cust_main.cgi" METHOD="GET">
- Search for <B>Credit card #</B>:
- <INPUT TYPE="hidden" NAME="card_on" VALUE="TRUE">
- <INPUT TYPE="text" NAME="card">
-
- <P><INPUT TYPE="submit" VALUE="Search">
-
- </FORM>
- </BODY>
-</HTML>
-
diff --git a/httemplate/search/cust_main-quickpay.html b/httemplate/search/cust_main-quickpay.html
deleted file mode 100755
index 154a64199..000000000
--- a/httemplate/search/cust_main-quickpay.html
+++ /dev/null
@@ -1,44 +0,0 @@
-<HTML>
- <HEAD>
- <TITLE>Quick payment entry</TITLE>
- </HEAD>
- <BODY BGCOLOR="#e8e8e8">
- <FONT SIZE=7>
- Quick payment entry
- </FONT>
- <BR><BR>
- <A HREF="../">Main Menu</A><BR><BR>
- <FORM ACTION="cust_main.cgi" METHOD="GET">
- <INPUT TYPE="hidden" NAME="quickpay" VALUE="yes">
- <INPUT TYPE="checkbox" NAME="last_on" CHECKED> Search for <B>last name</B>:
- <INPUT TYPE="text" NAME="last_text">
- using search method: <SELECT NAME="last_type">
- <OPTION SELECTED>All
- <OPTION>Fuzzy
- <OPTION>Substring
- <OPTION>Exact
- </SELECT>
-
- <P><INPUT TYPE="checkbox" NAME="company_on" CHECKED> Search for <B>company</B>:
- <INPUT TYPE="text" NAME="company_text">
- using search method: <SELECT NAME="company_type">
- <OPTION SELECTED>All
- <OPTION>Fuzzy
- <OPTION>Substring
- <OPTION>Exact
- </SELECT>
-
- <P><INPUT TYPE="submit" VALUE="Search">
-
- </FORM>
-
- <HR>Explanation of search methods:
- <UL>
- <LI><B>All</B> - Try all search methods.
- <LI><B>Fuzzy</B> - Searches for matches that are close to your text.
- <LI><B>Substring</B> - Searches for matches that contain your text.
- <LI><B>Exact</B> - Finds exact matches only, but much faster than the other search methods.
- </UL>
- </BODY>
-</HTML>
-
diff --git a/httemplate/search/cust_main-zip.html b/httemplate/search/cust_main-zip.html
new file mode 100644
index 000000000..56df924bc
--- /dev/null
+++ b/httemplate/search/cust_main-zip.html
@@ -0,0 +1,99 @@
+<% include( 'elements/search.html',
+ 'title' => 'Zip code Search Results',
+ 'name' => 'zip codes',
+ 'query' => $sql_query,
+ 'count_query' => $count_sql,
+ 'header' => [ 'Zip code', 'Customers', ],
+ #'fields' => [ 'zip', 'num_cust', ],
+ 'links' => [ '', sub { 'somewhere'; } ],
+ )
+%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('List zip codes');
+
+# XXX link to customers
+
+my @where = ();
+
+# select status
+
+if ( $cgi->param('status') =~ /^(prospect|uncancel|active|susp|cancel)$/ ) {
+ my $method = $1.'_sql';
+ push @where, FS::cust_main->$method();
+}
+
+# select agent
+# XXX this needs to be virtualized by agent too (like lots of stuff)
+
+my $agentnum = '';
+if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) {
+ $agentnum = $1;
+ push @where, "cust_main.agentnum = $agentnum";
+}
+my $where = scalar(@where) ? 'WHERE '. join(' AND ', @where) : '';
+
+# bill zip vs ship zip
+
+sub fieldorempty {
+ my $field = shift;
+ "CASE WHEN $field IS NULL THEN '' ELSE $field END";
+}
+
+sub strip_plus4 {
+ my $field = shift;
+ "CASE WHEN $field is NULL
+ THEN ''
+ ELSE CASE WHEN $field LIKE '_____-____'
+ THEN SUBSTRING($field FROM 1 FOR 5)
+ ELSE $field
+ END
+ END";
+}
+
+my( $zip, $czip);
+if ( $cgi->param('column') eq 'ship_zip' ) {
+
+ my $casewhen_noship =
+ "CASE WHEN ( ship_last IS NULL OR ship_last = '' ) THEN ";
+
+ $czip = "$casewhen_noship zip ELSE ship_zip END";
+
+ if ( $cgi->param('ignore_plus4') ) {
+ $zip = $casewhen_noship. strip_plus4('zip').
+ " ELSE ". strip_plus4('ship_zip'). ' END';
+
+ } else {
+ $zip = $casewhen_noship. fieldorempty('zip').
+ " ELSE ". fieldorempty('ship_zip'). ' END';
+ }
+
+} else {
+
+ $czip = 'zip';
+
+ if ( $cgi->param('ignore_plus4') ) {
+ $zip = strip_plus4('zip');
+ } else {
+ $zip = fieldorempty('zip');
+ }
+
+}
+
+# construct the queries and send 'em off
+
+my $sql_query =
+ "SELECT $zip AS zipcode,
+ COUNT(*) AS num_cust
+ FROM cust_main
+ $where
+ GROUP BY zipcode
+ ORDER BY num_cust DESC
+ ";
+
+my $count_sql = "select count(distinct $czip) from cust_main $where";
+
+# XXX should link...
+
+</%init>
diff --git a/httemplate/search/cust_main.cgi b/httemplate/search/cust_main.cgi
index 665f5637d..e87fe36d7 100755
--- a/httemplate/search/cust_main.cgi
+++ b/httemplate/search/cust_main.cgi
@@ -1,685 +1,728 @@
-<%
+%die "access denied"
+% unless $FS::CurrentUser::CurrentUser->access_right('List customers');
+%
+%my $conf = new FS::Conf;
+%my $maxrecords = $conf->config('maxsearchrecordsperpage');
+%
+%#my $cache;
+%
+%#my $monsterjoin = <<END;
+%#cust_main left outer join (
+%# ( cust_pkg left outer join part_pkg using(pkgpart)
+%# ) left outer join (
+%# (
+%# (
+%# ( cust_svc left outer join part_svc using (svcpart)
+%# ) left outer join svc_acct using (svcnum)
+%# ) left outer join svc_domain using(svcnum)
+%# ) left outer join svc_forward using(svcnum)
+%# ) using (pkgnum)
+%#) using (custnum)
+%#END
+%
+%#my $monsterjoin = <<END;
+%#cust_main left outer join (
+%# ( cust_pkg left outer join part_pkg using(pkgpart)
+%# ) left outer join (
+%# (
+%# (
+%# ( cust_svc left outer join part_svc using (svcpart)
+%# ) left outer join (
+%# svc_acct left outer join (
+%# select svcnum, domain, catchall from svc_domain
+%# ) as svc_acct_domsvc (
+%# svc_acct_svcnum, svc_acct_domain, svc_acct_catchall
+%# ) on svc_acct.domsvc = svc_acct_domsvc.svc_acct_svcnum
+%# ) using (svcnum)
+%# ) left outer join svc_domain using(svcnum)
+%# ) left outer join svc_forward using(svcnum)
+%# ) using (pkgnum)
+%#) using (custnum)
+%#END
+%
+%my $limit = '';
+%$limit .= "LIMIT $maxrecords" if $maxrecords;
+%
+%my $offset = $cgi->param('offset') || 0;
+%$limit .= " OFFSET $offset" if $offset;
+%
+%my $total = 0;
+%
+%my(@cust_main, $sortby, $orderby);
+%my @select = ();
+%my @addl_headers = ();
+%my @addl_cols = ();
+%if ( $cgi->param('browse')
+% || $cgi->param('otaker_on')
+% || $cgi->param('agentnum_on')
+%) {
+%
+% my %search = ();
+%
+% if ( $cgi->param('browse') ) {
+% my $query = $cgi->param('browse');
+% if ( $query eq 'custnum' ) {
+% $sortby=\*custnum_sort;
+% $orderby = "ORDER BY custnum";
+% } elsif ( $query eq 'last' ) {
+% $sortby=\*last_sort;
+% $orderby = "ORDER BY LOWER(last || ' ' || first)";
+% } elsif ( $query eq 'company' ) {
+% $sortby=\*company_sort;
+% $orderby = "ORDER BY LOWER(company || ' ' || last || ' ' || first )";
+% } elsif ( $query eq 'tickets' ) {
+% $sortby = \*tickets_sort;
+% $orderby = "ORDER BY tickets DESC";
+% push @select, FS::TicketSystem->sql_num_customer_tickets. " as tickets";
+% push @addl_headers, 'Tickets';
+% push @addl_cols, 'tickets';
+% } else {
+% die "unknown browse field $query";
+% }
+% } else {
+% $sortby = \*last_sort; #??
+% $orderby = "ORDER BY LOWER(last || ' ' || first)"; #??
+% }
+%
+% if ( $cgi->param('otaker_on') ) {
+% die "access denied"
+% unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+% $cgi->param('otaker') =~ /^(\w{1,32})$/ or eidiot "Illegal otaker\n";
+% $search{otaker} = $1;
+% } elsif ( $cgi->param('agentnum_on') ) {
+% $cgi->param('agentnum') =~ /^(\d+)$/ or eidiot "Illegal agentnum\n";
+% $search{agentnum} = $1;
+%# } else {
+%# die "unknown query...";
+% }
+%
+% my @qual = ();
+%
+% my $ncancelled = '';
+%
+% if ( $cgi->param('showcancelledcustomers') eq '0' #see if it was set by me
+% || ( $conf->exists('hidecancelledcustomers')
+% && ! $cgi->param('showcancelledcustomers') )
+% ) {
+% #grep { $_->ncancelled_pkgs || ! $_->all_pkgs }
+% push @qual, FS::cust_main->uncancel_sql;
+%
+% }
+%
+% push @qual, FS::cust_main->cancel_sql if $cgi->param('cancelled');
+% push @qual, FS::cust_main->prospect_sql if $cgi->param('prospect');
+% push @qual, FS::cust_main->active_sql if $cgi->param('active');
+% push @qual, FS::cust_main->inactive_sql if $cgi->param('inactive');
+% push @qual, FS::cust_main->susp_sql if $cgi->param('suspended');
+%
+% #EWWWWWW
+% my $qual = join(' AND ',
+% map { "$_ = ". dbh->quote($search{$_}) } keys %search );
+%
+% my $addl_qual = join(' AND ', @qual);
+%
+% #here is the agent virtualization
+% $addl_qual .= ( $addl_qual ? ' AND ' : '' ).
+% $FS::CurrentUser::CurrentUser->agentnums_sql;
+%
+% if ( $addl_qual ) {
+% $qual .= ' AND ' if $qual;
+% $qual .= $addl_qual;
+% }
+%
+% $qual = " WHERE $qual" if $qual;
+% my $statement = "SELECT COUNT(*) FROM cust_main $qual";
+% my $sth = dbh->prepare($statement) or die dbh->errstr." preparing $statement";
+% $sth->execute or die "Error executing \"$statement\": ". $sth->errstr;
+%
+% $total = $sth->fetchrow_arrayref->[0];
+%
+% if ( $addl_qual ) {
+% if ( %search ) {
+% $addl_qual = " AND $addl_qual";
+% } else {
+% $addl_qual = " WHERE $addl_qual";
+% }
+% }
+%
+% my $select;
+% if ( @select ) {
+% $select = 'cust_main.*, '. join (', ', @select);
+% } else {
+% $select = '*';
+% }
+%
+% @cust_main = qsearch('cust_main', \%search, $select,
+% "$addl_qual $orderby $limit" );
+%
+%# foreach my $cust_main ( @just_cust_main ) {
+%#
+%# my @one_cust_main;
+%# $FS::Record::DEBUG=1;
+%# ( $cache, @one_cust_main ) = jsearch(
+%# "$monsterjoin",
+%# { 'custnum' => $cust_main->custnum },
+%# '',
+%# '',
+%# 'cust_main',
+%# 'custnum',
+%# );
+%# push @cust_main, @one_cust_main;
+%# }
+%
+%} else {
+% @cust_main=();
+% $sortby = \*last_sort;
+%
+% push @cust_main, @{&custnumsearch}
+% if $cgi->param('custnum_on') && $cgi->param('custnum_text');
+% push @cust_main, @{&cardsearch}
+% if $cgi->param('card_on') && $cgi->param('card');
+% push @cust_main, @{&lastsearch}
+% if $cgi->param('last_on') && $cgi->param('last_text');
+% push @cust_main, @{&companysearch}
+% if $cgi->param('company_on') && $cgi->param('company_text');
+% push @cust_main, @{&address2search}
+% if $cgi->param('address2_on') && $cgi->param('address2_text');
+% push @cust_main, @{&phonesearch}
+% if $cgi->param('phone_on') && $cgi->param('phone_text');
+% push @cust_main, @{&referralsearch}
+% if $cgi->param('referral_custnum');
+%
+% if ( $cgi->param('company_on') && $cgi->param('company_text') ) {
+% $sortby = \*company_sort;
+% push @cust_main, @{&companysearch};
+% }
+%
+% if ( $cgi->param('search_cust') ) {
+% $sortby = \*company_sort;
+% $orderby = "ORDER BY LOWER(company || ' ' || last || ' ' || first )";
+% push @cust_main, smart_search( 'search' => $cgi->param('search_cust') );
+% }
+%
+% @cust_main = grep { $_->ncancelled_pkgs || ! $_->all_pkgs } @cust_main
+% if ! $cgi->param('cancelled')
+% && (
+% $cgi->param('showcancelledcustomers') eq '0' #see if it was set by me
+% || ( $conf->exists('hidecancelledcustomers')
+% && ! $cgi->param('showcancelledcustomers') )
+% );
+%
+% my %saw = ();
+% @cust_main = grep { !$saw{$_->custnum}++ } @cust_main;
+%}
+%
+%my %all_pkgs;
+%if ( $conf->exists('hidecancelledpackages' ) ) {
+% %all_pkgs = map { $_->custnum => [ $_->ncancelled_pkgs ] } @cust_main;
+%} else {
+% %all_pkgs = map { $_->custnum => [ $_->all_pkgs ] } @cust_main;
+%}
+%#%all_pkgs = ();
+%
+%if ( scalar(@cust_main) == 1 && ! $cgi->param('referral_custnum') ) {
+% if ( $cgi->param('quickpay') eq 'yes' ) {
+% print $cgi->redirect(popurl(2). "edit/cust_pay.cgi?quickpay=yes;custnum=". $cust_main[0]->custnum);
+% } else {
+% print $cgi->redirect(popurl(2). "view/cust_main.cgi?". $cust_main[0]->custnum);
+% }
+% #exit;
+%} elsif ( scalar(@cust_main) == 0 ) {
+%
-my $conf = new FS::Conf;
-my $maxrecords = $conf->config('maxsearchrecordsperpage');
-
-#my $cache;
-
-#my $monsterjoin = <<END;
-#cust_main left outer join (
-# ( cust_pkg left outer join part_pkg using(pkgpart)
-# ) left outer join (
-# (
-# (
-# ( cust_svc left outer join part_svc using (svcpart)
-# ) left outer join svc_acct using (svcnum)
-# ) left outer join svc_domain using(svcnum)
-# ) left outer join svc_forward using(svcnum)
-# ) using (pkgnum)
-#) using (custnum)
-#END
-
-#my $monsterjoin = <<END;
-#cust_main left outer join (
-# ( cust_pkg left outer join part_pkg using(pkgpart)
-# ) left outer join (
-# (
-# (
-# ( cust_svc left outer join part_svc using (svcpart)
-# ) left outer join (
-# svc_acct left outer join (
-# select svcnum, domain, catchall from svc_domain
-# ) as svc_acct_domsvc (
-# svc_acct_svcnum, svc_acct_domain, svc_acct_catchall
-# ) on svc_acct.domsvc = svc_acct_domsvc.svc_acct_svcnum
-# ) using (svcnum)
-# ) left outer join svc_domain using(svcnum)
-# ) left outer join svc_forward using(svcnum)
-# ) using (pkgnum)
-#) using (custnum)
-#END
-
-my $limit = '';
-$limit .= "LIMIT $maxrecords" if $maxrecords;
-
-my $offset = $cgi->param('offset') || 0;
-$limit .= " OFFSET $offset" if $offset;
-
-my $total = 0;
-
-my(@cust_main, $sortby, $orderby);
-my @select = ();
-my @addl_headers = ();
-my @addl_cols = ();
-if ( $cgi->param('browse')
- || $cgi->param('otaker_on')
- || $cgi->param('agentnum_on')
-) {
-
- my %search = ();
-
- if ( $cgi->param('browse') ) {
- my $query = $cgi->param('browse');
- if ( $query eq 'custnum' ) {
- $sortby=\*custnum_sort;
- $orderby = "ORDER BY custnum";
- } elsif ( $query eq 'last' ) {
- $sortby=\*last_sort;
- $orderby = "ORDER BY LOWER(last || ' ' || first)";
- } elsif ( $query eq 'company' ) {
- $sortby=\*company_sort;
- $orderby = "ORDER BY LOWER(company || ' ' || last || ' ' || first )";
- } elsif ( $query eq 'tickets' ) {
- $sortby = \*tickets_sort;
- $orderby = "ORDER BY tickets DESC";
- push @select, FS::TicketSystem->sql_num_customer_tickets. " as tickets";
- push @addl_headers, 'Tickets';
- push @addl_cols, 'tickets';
- } else {
- die "unknown browse field $query";
- }
- } else {
- $sortby = \*last_sort; #??
- $orderby = "ORDER BY LOWER(last || ' ' || first)"; #??
- }
-
- if ( $cgi->param('otaker_on') ) {
- $cgi->param('otaker') =~ /^(\w{1,32})$/ or eidiot "Illegal otaker\n";
- $search{otaker} = $1;
- } elsif ( $cgi->param('agentnum_on') ) {
- $cgi->param('agentnum') =~ /^(\d+)$/ or eidiot "Illegal agentnum\n";
- $search{agentnum} = $1;
-# } else {
-# die "unknown query...";
- }
-
- my @qual = ();
-
- my $ncancelled = '';
-
- if ( $cgi->param('showcancelledcustomers') eq '0' #see if it was set by me
- || ( $conf->exists('hidecancelledcustomers')
- && ! $cgi->param('showcancelledcustomers') )
- ) {
- #grep { $_->ncancelled_pkgs || ! $_->all_pkgs }
- push @qual, "
- ( 0 < ( SELECT COUNT(*) FROM cust_pkg
- WHERE cust_pkg.custnum = cust_main.custnum
- AND ( cust_pkg.cancel IS NULL
- OR cust_pkg.cancel = 0
- )
- )
- OR 0 = ( SELECT COUNT(*) FROM cust_pkg
- WHERE cust_pkg.custnum = cust_main.custnum
- )
- )
- ";
- }
-
- push @qual, FS::cust_main->cancel_sql if $cgi->param('cancelled');
- push @qual, FS::cust_main->prospect_sql if $cgi->param('prospect');
- push @qual, FS::cust_main->active_sql if $cgi->param('active');
- push @qual, FS::cust_main->susp_sql if $cgi->param('suspended');
-
- #EWWWWWW
- my $qual = join(' AND ',
- map { "$_ = ". dbh->quote($search{$_}) } keys %search );
-
- my $addl_qual = join(' AND ', @qual);
-
- if ( $addl_qual ) {
- $qual .= ' AND ' if $qual;
- $qual .= $addl_qual;
- }
-
- $qual = " WHERE $qual" if $qual;
- my $statement = "SELECT COUNT(*) FROM cust_main $qual";
- my $sth = dbh->prepare($statement) or die dbh->errstr." preparing $statement";
- $sth->execute or die "Error executing \"$statement\": ". $sth->errstr;
-
- $total = $sth->fetchrow_arrayref->[0];
-
- if ( $addl_qual ) {
- if ( %search ) {
- $addl_qual = " AND $addl_qual";
- } else {
- $addl_qual = " WHERE $addl_qual";
- }
- }
-
- my $select;
- if ( @select ) {
- $select = 'cust_main.*, '. join (', ', @select);
- } else {
- $select = '*';
- }
-
- @cust_main = qsearch('cust_main', \%search, $select,
- "$addl_qual $orderby $limit" );
-
-# foreach my $cust_main ( @just_cust_main ) {
-#
-# my @one_cust_main;
-# $FS::Record::DEBUG=1;
-# ( $cache, @one_cust_main ) = jsearch(
-# "$monsterjoin",
-# { 'custnum' => $cust_main->custnum },
-# '',
-# '',
-# 'cust_main',
-# 'custnum',
-# );
-# push @cust_main, @one_cust_main;
-# }
-
-} else {
- @cust_main=();
- $sortby = \*last_sort;
-
- push @cust_main, @{&custnumsearch}
- if $cgi->param('custnum_on') && $cgi->param('custnum_text');
- push @cust_main, @{&cardsearch}
- if $cgi->param('card_on') && $cgi->param('card');
- push @cust_main, @{&lastsearch}
- if $cgi->param('last_on') && $cgi->param('last_text');
- push @cust_main, @{&companysearch}
- if $cgi->param('company_on') && $cgi->param('company_text');
- push @cust_main, @{&address2search}
- if $cgi->param('address2_on') && $cgi->param('address2_text');
- push @cust_main, @{&phonesearch}
- if $cgi->param('phone_on') && $cgi->param('phone_text');
- push @cust_main, @{&referralsearch}
- if $cgi->param('referral_custnum');
-
- if ( $cgi->param('company_on') && $cgi->param('company_text') ) {
- $sortby = \*company_sort;
- push @cust_main, @{&companysearch};
- }
-
- @cust_main = grep { $_->ncancelled_pkgs || ! $_->all_pkgs } @cust_main
- if ! $cgi->param('cancelled')
- && (
- $cgi->param('showcancelledcustomers') eq '0' #see if it was set by me
- || ( $conf->exists('hidecancelledcustomers')
- && ! $cgi->param('showcancelledcustomers') )
- );
-
- my %saw = ();
- @cust_main = grep { !$saw{$_->custnum}++ } @cust_main;
-}
-
-my %all_pkgs;
-if ( $conf->exists('hidecancelledpackages' ) ) {
- %all_pkgs = map { $_->custnum => [ $_->ncancelled_pkgs ] } @cust_main;
-} else {
- %all_pkgs = map { $_->custnum => [ $_->all_pkgs ] } @cust_main;
-}
-#%all_pkgs = ();
-
-if ( scalar(@cust_main) == 1 && ! $cgi->param('referral_custnum') ) {
- if ( $cgi->param('quickpay') eq 'yes' ) {
- print $cgi->redirect(popurl(2). "edit/cust_pay.cgi?quickpay=yes;custnum=". $cust_main[0]->custnum);
- } else {
- print $cgi->redirect(popurl(2). "view/cust_main.cgi?". $cust_main[0]->custnum);
- }
- #exit;
-} elsif ( scalar(@cust_main) == 0 ) {
-%>
-<!-- mason kludge -->
-<%
- eidiot "No matching customers found!\n";
-} else {
-%>
<!-- mason kludge -->
-<%
-
- $total ||= scalar(@cust_main);
- print header("Customer Search Results",menubar(
- 'Main Menu', popurl(2)
- )), "$total matching customers found ";
-
- #begin pager
- my $pager = '';
- if ( $total != scalar(@cust_main) && $maxrecords ) {
- unless ( $offset == 0 ) {
- $cgi->param('offset', $offset - $maxrecords);
- $pager .= '<A HREF="'. $cgi->self_url.
- '"><B><FONT SIZE="+1">Previous</FONT></B></A> ';
- }
- my $poff;
- my $page;
- for ( $poff = 0; $poff < $total; $poff += $maxrecords ) {
- $page++;
- if ( $offset == $poff ) {
- $pager .= qq!<FONT SIZE="+2">$page</FONT> !;
- } else {
- $cgi->param('offset', $poff);
- $pager .= qq!<A HREF="!. $cgi->self_url. qq!">$page</A> !;
- }
- }
- unless ( $offset + $maxrecords > $total ) {
- $cgi->param('offset', $offset + $maxrecords);
- $pager .= '<A HREF="'. $cgi->self_url.
- '"><B><FONT SIZE="+1">Next</FONT></B></A> ';
- }
- }
- #end pager
-
- unless ( $cgi->param('cancelled') ) {
- if ( $cgi->param('showcancelledcustomers') eq '0' #see if it was set by me
- || ( $conf->exists('hidecancelledcustomers')
- && ! $cgi->param('showcancelledcustomers')
- )
- ) {
- $cgi->param('showcancelledcustomers', 1);
- $cgi->param('offset', 0);
- print qq!( <a href="!. $cgi->self_url. qq!">show!;
- } else {
- $cgi->param('showcancelledcustomers', 0);
- $cgi->param('offset', 0);
- print qq!( <a href="!. $cgi->self_url. qq!">hide!;
- }
- print ' cancelled customers</a> )';
- }
-
- if ( $cgi->param('referral_custnum') ) {
- $cgi->param('referral_custnum') =~ /^(\d+)$/
- or eidiot "Illegal referral_custnum\n";
- my $referral_custnum = $1;
- my $cust_main = qsearchs('cust_main', { custnum => $referral_custnum } );
- print '<FORM METHOD="GET">'.
- qq!<INPUT TYPE="hidden" NAME="referral_custnum" VALUE="$referral_custnum">!.
- 'referrals of <A HREF="'. popurl(2).
- "view/cust_main.cgi?$referral_custnum\">$referral_custnum: ".
- ( $cust_main->company
- || $cust_main->last. ', '. $cust_main->first ).
- '</A>';
- print "\n",<<END;
- <SCRIPT>
- function changed(what) {
- what.form.submit();
- }
- </SCRIPT>
-END
- print ' <SELECT NAME="referral_depth" SIZE="1" onChange="changed(this)">';
- my $max = 8; #config file
- $cgi->param('referral_depth') =~ /^(\d*)$/
- or eidiot "Illegal referral_depth";
- my $referral_depth = $1;
-
- foreach my $depth ( 1 .. $max ) {
- print '<OPTION',
- ' SELECTED'x($depth == $referral_depth),
- ">$depth";
- }
- print "</SELECT> levels deep".
- '<NOSCRIPT> <INPUT TYPE="submit" VALUE="change"></NOSCRIPT>'.
- '</FORM>';
- }
-
- my @custom_priorities = ();
- if ( $conf->config('ticket_system-custom_priority_field')
- && @{[ $conf->config('ticket_system-custom_priority_field-values') ]} ) {
- @custom_priorities =
- $conf->config('ticket_system-custom_priority_field-values');
- }
-
- print "<BR><BR>". $pager. &table(). <<END;
- <TR>
- <TH></TH>
- <TH>(bill) name</TH>
- <TH>company</TH>
-END
+%
+% eidiot "No matching customers found!\n";
+%} else {
+%
+
+<% include('/elements/header.html', "Customer Search Results", '' ) %>
+% $total ||= scalar(@cust_main);
+
+
+ <% $total %> matching customers found
+
+% my $pager = include( '/elements/pager.html',
+% 'offset' => $offset,
+% 'num_rows' => scalar(@cust_main),
+% 'total' => $total,
+% 'maxrecords' => $maxrecords,
+% );
+%
+% unless ( $cgi->param('cancelled') ) {
+% if ( $cgi->param('showcancelledcustomers') eq '0' #see if it was set by me
+% || ( $conf->exists('hidecancelledcustomers')
+% && ! $cgi->param('showcancelledcustomers')
+% )
+% ) {
+% $cgi->param('showcancelledcustomers', 1);
+% $cgi->param('offset', 0);
+% print qq!( <a href="!. $cgi->self_url. qq!">show!;
+% } else {
+% $cgi->param('showcancelledcustomers', 0);
+% $cgi->param('offset', 0);
+% print qq!( <a href="!. $cgi->self_url. qq!">hide!;
+% }
+% print ' cancelled customers</a> )';
+% }
+%
+% if ( $cgi->param('referral_custnum') ) {
+% $cgi->param('referral_custnum') =~ /^(\d+)$/
+% or eidiot "Illegal referral_custnum\n";
+% my $referral_custnum = $1;
+% my $cust_main = qsearchs('cust_main', { custnum => $referral_custnum } );
+% print '<FORM METHOD="GET">'.
+% qq!<INPUT TYPE="hidden" NAME="referral_custnum" VALUE="$referral_custnum">!.
+% 'referrals of <A HREF="'. popurl(2).
+% "view/cust_main.cgi?$referral_custnum\">$referral_custnum: ".
+% ( $cust_main->company
+% || $cust_main->last. ', '. $cust_main->first ).
+% '</A>';
+% print "\n",<<END;
+% <SCRIPT>
+% function changed(what) {
+% what.form.submit();
+% }
+% </SCRIPT>
+%END
+% print ' <SELECT NAME="referral_depth" SIZE="1" onChange="changed(this)">';
+% my $max = 8; #config file
+% $cgi->param('referral_depth') =~ /^(\d*)$/
+% or eidiot "Illegal referral_depth";
+% my $referral_depth = $1;
+%
+% foreach my $depth ( 1 .. $max ) {
+% print '<OPTION',
+% ' SELECTED'x($depth == $referral_depth),
+% ">$depth";
+% }
+% print "</SELECT> levels deep".
+% '<NOSCRIPT> <INPUT TYPE="submit" VALUE="change"></NOSCRIPT>'.
+% '</FORM>';
+% }
+%
+% my @custom_priorities = ();
+% if ( $conf->config('ticket_system-custom_priority_field')
+% && @{[ $conf->config('ticket_system-custom_priority_field-values') ]} ) {
+% @custom_priorities =
+% $conf->config('ticket_system-custom_priority_field-values');
+% }
+%
+% print "<BR><BR>". $pager. include('/elements/table-grid.html'). <<END;
+% <TR>
+% <TH CLASS="grid" BGCOLOR="#cccccc">#</TH>
+% <TH CLASS="grid" BGCOLOR="#cccccc">Status</TH>
+% <TH CLASS="grid" BGCOLOR="#cccccc">(bill) name</TH>
+% <TH CLASS="grid" BGCOLOR="#cccccc">company</TH>
+%END
+%
+%if ( defined dbdef->table('cust_main')->column('ship_last') ) {
+% print <<END;
+% <TH CLASS="grid" BGCOLOR="#cccccc">(service) name</TH>
+% <TH CLASS="grid" BGCOLOR="#cccccc">company</TH>
+%END
+%}
+%
+%foreach my $addl_header ( @addl_headers ) {
+% print '<TH CLASS="grid" BGCOLOR="#cccccc">'. "$addl_header</TH>";
+%}
+%
+%print <<END;
+% <TH CLASS="grid" BGCOLOR="#cccccc">Packages</TH>
+% <TH CLASS="grid" BGCOLOR="#cccccc" COLSPAN=2>Services</TH>
+% </TR>
+%END
+%
+% my $bgcolor1 = '#eeeeee';
+% my $bgcolor2 = '#ffffff';
+% my $bgcolor;
+%
+% my(%saw,$cust_main);
+% foreach $cust_main (
+% sort $sortby grep(!$saw{$_->custnum}++, @cust_main)
+% ) {
+%
+% if ( $bgcolor eq $bgcolor1 ) {
+% $bgcolor = $bgcolor2;
+% } else {
+% $bgcolor = $bgcolor1;
+% }
+%
+% my($custnum,$last,$first,$company)=(
+% $cust_main->custnum,
+% $cust_main->getfield('last'),
+% $cust_main->getfield('first'),
+% $cust_main->company,
+% );
+%
+% my(@lol_cust_svc);
+% my($rowspan)=0;#scalar( @{$all_pkgs{$custnum}} );
+% foreach ( @{$all_pkgs{$custnum}} ) {
+% #my(@cust_svc) = qsearch( 'cust_svc', { 'pkgnum' => $_->pkgnum } );
+% my @cust_svc = $_->cust_svc;
+% push @lol_cust_svc, \@cust_svc;
+% $rowspan += scalar(@cust_svc) || 1;
+% }
+%
+% #my($rowspan) = scalar(@{$all_pkgs{$custnum}});
+% my $view;
+% if ( defined $cgi->param('quickpay') && $cgi->param('quickpay') eq 'yes' ) {
+% $view = $p. 'edit/cust_pay.cgi?quickpay=yes;custnum='. $custnum;
+% } else {
+% $view = $p. 'view/cust_main.cgi?'. $custnum;
+% }
+% my $pcompany = $company
+% ? qq!<A HREF="$view"><FONT SIZE=-1>$company</FONT></A>!
+% : '<FONT SIZE=-1>&nbsp;</FONT>';
+%
+% my $status = $cust_main->status;
+% my $statuscol = $FS::cust_main::statuscolor{$status};
-if ( defined dbdef->table('cust_main')->column('ship_last') ) {
- print <<END;
- <TH>(service) name</TH>
- <TH>company</TH>
-END
-}
-
-foreach my $addl_header ( @addl_headers ) {
- print "<TH>$addl_header</TH>";
-}
-
-print <<END;
- <TH>Packages</TH>
- <TH COLSPAN=2>Services</TH>
- </TR>
-END
-
- my(%saw,$cust_main);
- foreach $cust_main (
- sort $sortby grep(!$saw{$_->custnum}++, @cust_main)
- ) {
- my($custnum,$last,$first,$company)=(
- $cust_main->custnum,
- $cust_main->getfield('last'),
- $cust_main->getfield('first'),
- $cust_main->company,
- );
-
- my(@lol_cust_svc);
- my($rowspan)=0;#scalar( @{$all_pkgs{$custnum}} );
- foreach ( @{$all_pkgs{$custnum}} ) {
- #my(@cust_svc) = qsearch( 'cust_svc', { 'pkgnum' => $_->pkgnum } );
- my @cust_svc = $_->cust_svc;
- push @lol_cust_svc, \@cust_svc;
- $rowspan += scalar(@cust_svc) || 1;
- }
-
- #my($rowspan) = scalar(@{$all_pkgs{$custnum}});
- my $view;
- if ( defined $cgi->param('quickpay') && $cgi->param('quickpay') eq 'yes' ) {
- $view = $p. 'edit/cust_pay.cgi?quickpay=yes;custnum='. $custnum;
- } else {
- $view = $p. 'view/cust_main.cgi?'. $custnum;
- }
- my $pcompany = $company
- ? qq!<A HREF="$view"><FONT SIZE=-1>$company</FONT></A>!
- : '<FONT SIZE=-1>&nbsp;</FONT>';
- print <<END;
<TR>
- <TD ROWSPAN=$rowspan><A HREF="$view"><FONT SIZE=-1>$custnum</FONT></A></TD>
- <TD ROWSPAN=$rowspan><A HREF="$view"><FONT SIZE=-1>$last, $first</FONT></A></TD>
- <TD ROWSPAN=$rowspan>$pcompany</TD>
-END
- if ( defined dbdef->table('cust_main')->column('ship_last') ) {
- my($ship_last,$ship_first,$ship_company)=(
- $cust_main->ship_last || $cust_main->getfield('last'),
- $cust_main->ship_last ? $cust_main->ship_first : $cust_main->first,
- $cust_main->ship_last ? $cust_main->ship_company : $cust_main->company,
- );
- my $pship_company = $ship_company
- ? qq!<A HREF="$view"><FONT SIZE=-1>$ship_company</FONT></A>!
- : '<FONT SIZE=-1>&nbsp;</FONT>';
- print <<END;
- <TD ROWSPAN=$rowspan><A HREF="$view"><FONT SIZE=-1>$ship_last, $ship_first</FONT></A></TD>
- <TD ROWSPAN=$rowspan>$pship_company</A></TD>
-END
- }
-
- foreach my $addl_col ( @addl_cols ) {
- print "<TD ROWSPAN=$rowspan ALIGN=right><FONT SIZE=-1>";
- if ( $addl_col eq 'tickets' ) {
- if ( @custom_priorities ) {
- print &itable('', 0);
- foreach my $priority ( @custom_priorities, '' ) {
-
- my $num =
- FS::TicketSystem->num_customer_tickets($custnum,$priority);
- my $ahref = '';
- $ahref= '<A HREF="'.
- FS::TicketSystem->href_customer_tickets($custnum,$priority).
- '">'
- if $num;
-
- print '<TR>'.
- " <TD ALIGN=right><FONT SIZE=-1>$ahref$num</A></FONT></TD>".
- "<TD ALIGN=left><FONT SIZE=-1>$ahref".
- ( $priority || '<i>(none)</i>' ).
- "</A></FONT></TD></TR>";
-
- }
- print '<TR><TD BGCOLOR="#000000" COLSPAN=2></TD></TR>'.
- '<TR><TD ALIGN=right><FONT SIZE=-1>';
- }
-
- my $ahref = '';
- $ahref = '<A HREF="'.
- FS::TicketSystem->href_customer_tickets($custnum).
- '">'
- if $cust_main->get($addl_col);
-
- print $ahref. $cust_main->get($addl_col). '</A>';
- print "</FONT></TD><TD ALIGN=left>".
- "<FONT SIZE=-1>${ahref}Total</A><FONT>".
- "</TD></TR></TABLE>"
- if @custom_priorities;
-
- } else {
- print $cust_main->get($addl_col);
- }
- print "</FONT></TD>";
- }
-
- my($n1)='';
- foreach ( @{$all_pkgs{$custnum}} ) {
- my $pkgnum = $_->pkgnum;
-# my $part_pkg = qsearchs( 'part_pkg', { pkgpart => $_->pkgpart } );
- my $part_pkg = $_->part_pkg;
+ <TD CLASS="grid" ALIGN="right" BGCOLOR="<% $bgcolor %>" ROWSPAN=<% $rowspan || 1 %>><A HREF="<% $view %>"><FONT SIZE=-1><% $custnum %></FONT></A></TD>
+ <TD CLASS="grid" ALIGN="center" BGCOLOR="<% $bgcolor %>" ROWSPAN=<% $rowspan || 1 %>><FONT SIZE=-1 COLOR=<% $statuscol %>><B><% ucfirst($status) %></B></FONT></TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>" ROWSPAN=<% $rowspan || 1 %>><A HREF="<% $view %>"><FONT SIZE=-1><% "$last, $first" %></FONT></A></TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>" ROWSPAN=<% $rowspan || 1 %>><% $pcompany %></TD>
+%
+% if ( defined dbdef->table('cust_main')->column('ship_last') ) {
+% my($ship_last,$ship_first,$ship_company)=(
+% $cust_main->ship_last || $cust_main->getfield('last'),
+% $cust_main->ship_last ? $cust_main->ship_first : $cust_main->first,
+% $cust_main->ship_last ? $cust_main->ship_company : $cust_main->company,
+% );
+% my $pship_company = $ship_company
+% ? qq!<A HREF="$view"><FONT SIZE=-1>$ship_company</FONT></A>!
+% : '<FONT SIZE=-1>&nbsp;</FONT>';
+%
+
+
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>" ROWSPAN=<% $rowspan || 1 %>><A HREF="<% $view %>"><FONT SIZE=-1><% "$ship_last, $ship_first" %></FONT></A></TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>" ROWSPAN=<% $rowspan || 1 %>><% $pship_company %></A></TD>
+% }
+%
+% foreach my $addl_col ( @addl_cols ) {
+% if ( $addl_col eq 'tickets' ) {
+% if ( @custom_priorities ) {
+
+
+ <TD CLASS="inv" BGCOLOR="<% $bgcolor %>" ROWSPAN=<% $rowspan || 1 %> ALIGN=right><FONT SIZE=-1>
+
+ <TABLE CLASS="inv" CELLSPACING=0 CELLPADDING=0>
+% foreach my $priority ( @custom_priorities, '' ) {
+%
+% my $num =
+% FS::TicketSystem->num_customer_tickets($custnum,$priority);
+% my $ahref = '';
+% $ahref= '<A HREF="'.
+% FS::TicketSystem->href_customer_tickets($custnum,$priority).
+% '">'
+% if $num;
+%
+
+
+ <TR>
+ <TD ALIGN=right>
+ <FONT SIZE=-1><% $ahref.$num %></A></FONT>
+ </TD>
+ <TD ALIGN=left>
+ <FONT SIZE=-1><% $ahref %><% $priority || '<i>(none)</i>' %></A></FONT>
+ </TD>
+ </TR>
+% }
+
+
+ <TR>
+ <TH ALIGN=right STYLE="border-top: dashed 1px black">
+ <FONT SIZE=-1>
+% } else {
+
+
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>" ROWSPAN=<% $rowspan || 1 %> ALIGN=right><FONT SIZE=-1>
+% }
+%
+% my $ahref = '';
+% $ahref = '<A HREF="'.
+% FS::TicketSystem->href_customer_tickets($custnum).
+% '">'
+% if $cust_main->get($addl_col);
+%
+
+
+ <% $ahref %><% $cust_main->get($addl_col) %></A>
+% if ( @custom_priorities ) {
+
+
+ </FONT></TH>
+ <TH ALIGN=left STYLE="border-top: dashed 1px black">
+ <FONT SIZE=-1><% ${ahref} %>Total</A><FONT>
+ </TH>
+ </TR>
+ </TABLE>
+% }
+
+
+ </FONT></TD>
+% } else {
+
+
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>" ROWSPAN=<% $rowspan || 1 %> ALIGN=right><FONT SIZE=-1>
+ <% $cust_main->get($addl_col) %>
+ </FONT></TD>
+%
+% }
+% }
+%
+% my($n1)='';
+% foreach ( @{$all_pkgs{$custnum}} ) {
+% my $pkgnum = $_->pkgnum;
+%# my $part_pkg = qsearchs( 'part_pkg', { pkgpart => $_->pkgpart } );
+% my $part_pkg = $_->part_pkg;
+%
+% my $pkg = $part_pkg->pkg;
+% my $comment = $part_pkg->comment;
+% my $pkgview = "${p}view/cust_main.cgi?$custnum#cust_pkg$pkgnum";
+% my @cust_svc = @{shift @lol_cust_svc};
+% #my(@cust_svc) = qsearch( 'cust_svc', { 'pkgnum' => $_->pkgnum } );
+% my $rowspan = scalar(@cust_svc) || 1;
+%
+% print $n1, qq!<TD CLASS="grid" BGCOLOR="$bgcolor" ROWSPAN=$rowspan><A HREF="$pkgview"><FONT SIZE=-1>$pkg - $comment</FONT></A></TD>!;
+%
+% my($n2)='';
+% foreach my $cust_svc ( @cust_svc ) {
+% my($label, $value, $svcdb) = $cust_svc->label;
+% my($svcnum) = $cust_svc->svcnum;
+% my($sview) = $p.'view';
+% print $n2,
+% qq!<TD CLASS="grid" BGCOLOR="$bgcolor" >!. FS::UI::Web::svc_link($m, $cust_svc->part_svc, $cust_svc) . qq!</TD> !.
+% qq!<TD CLASS="grid" BGCOLOR="$bgcolor" >!. FS::UI::Web::svc_label_link($m, $cust_svc->part_svc, $cust_svc) . qq!</TD> !;
+% $n2="</TR><TR>";
+% }
+%
+% unless ( @cust_svc ) {
+% print qq!<TD CLASS="grid" BGCOLOR="$bgcolor" COLSPAN=2>&nbsp;</TD>!;
+% }
+%
+% #print qq!</TR><TR>\n!;
+% $n1="</TR><TR>";
+% }
+%
+% unless ( @{$all_pkgs{$custnum}} ) {
+% print qq!<TD CLASS="grid" BGCOLOR="$bgcolor" COLSPAN=3>&nbsp;</TD>!;
+% }
+%
+% print "</TR>";
+% }
+%
+%
- my $pkg = $part_pkg->pkg;
- my $comment = $part_pkg->comment;
- my $pkgview = "${p}view/cust_main.cgi?$custnum#cust_pkg$pkgnum";
- my @cust_svc = @{shift @lol_cust_svc};
- #my(@cust_svc) = qsearch( 'cust_svc', { 'pkgnum' => $_->pkgnum } );
- my $rowspan = scalar(@cust_svc) || 1;
-
- print $n1, qq!<TD ROWSPAN=$rowspan><A HREF="$pkgview"><FONT SIZE=-1>$pkg - $comment</FONT></A></TD>!;
- my($n2)='';
- foreach my $cust_svc ( @cust_svc ) {
- my($label, $value, $svcdb) = $cust_svc->label;
- my($svcnum) = $cust_svc->svcnum;
- my($sview) = $p.'view';
- print $n2,qq!<TD><A HREF="$sview/$svcdb.cgi?$svcnum"><FONT SIZE=-1>$label</FONT></A></TD>!,
- qq!<TD><A HREF="$sview/$svcdb.cgi?$svcnum"><FONT SIZE=-1>$value</FONT></A></TD>!;
- $n2="</TR><TR>";
- }
- #print qq!</TR><TR>\n!;
- $n1="</TR><TR>";
- }
- print "</TR>";
- }
- print "</TABLE>$pager</BODY></HTML>";
-
-}
-
-#undef $cache; #does this help?
-
-#
-
-sub last_sort {
- lc($a->getfield('last')) cmp lc($b->getfield('last'))
- || lc($a->first) cmp lc($b->first);
-}
-
-sub company_sort {
- return -1 if $a->company && ! $b->company;
- return 1 if ! $a->company && $b->company;
- lc($a->company) cmp lc($b->company)
- || lc($a->getfield('last')) cmp lc($b->getfield('last'))
- || lc($a->first) cmp lc($b->first);;
-}
-
-sub custnum_sort {
- $a->getfield('custnum') <=> $b->getfield('custnum');
-}
-
-sub tickets_sort {
- $b->getfield('tickets') <=> $a->getfield('tickets');
-}
-
-sub custnumsearch {
-
- my $custnum = $cgi->param('custnum_text');
- $custnum =~ s/\D//g;
- $custnum =~ /^(\d{1,23})$/ or eidiot "Illegal customer number\n";
- $custnum = $1;
-
- [ qsearchs('cust_main', { 'custnum' => $custnum } ) ];
-}
-
-sub cardsearch {
-
- my($card)=$cgi->param('card');
- $card =~ s/\D//g;
- $card =~ /^(\d{13,16})$/ or eidiot "Illegal card number\n";
- my($payinfo)=$1;
-
- [ qsearch('cust_main',{'payinfo'=>$payinfo, 'payby'=>'CARD'}),
- qsearch('cust_main',{'payinfo'=>$payinfo, 'payby'=>'DCRD'})
- ];
-}
-
-sub referralsearch {
- $cgi->param('referral_custnum') =~ /^(\d+)$/
- or eidiot "Illegal referral_custnum";
- my $cust_main = qsearchs('cust_main', { 'custnum' => $1 } )
- or eidiot "Customer $1 not found";
- my $depth;
- if ( $cgi->param('referral_depth') ) {
- $cgi->param('referral_depth') =~ /^(\d+)$/
- or eidiot "Illegal referral_depth";
- $depth = $1;
- } else {
- $depth = 1;
- }
- [ $cust_main->referral_cust_main($depth) ];
-}
-
-sub lastsearch {
- my(%last_type);
- my @cust_main;
- foreach ( $cgi->param('last_type') ) {
- $last_type{$_}++;
- }
-
- $cgi->param('last_text') =~ /^([\w \,\.\-\']*)$/
- or eidiot "Illegal last name";
- my($last)=$1;
-
- if ( $last_type{'Exact'} || $last_type{'Fuzzy'} ) {
- push @cust_main, qsearch( 'cust_main',
- { 'last' => { 'op' => 'ILIKE',
- 'value' => $last } } );
-
- push @cust_main, qsearch( 'cust_main',
- { 'ship_last' => { 'op' => 'ILIKE',
- 'value' => $last } } )
- if defined dbdef->table('cust_main')->column('ship_last');
- }
-
- if ( $last_type{'Substring'} || $last_type{'All'} ) {
-
- push @cust_main, qsearch( 'cust_main',
- { 'last' => { 'op' => 'ILIKE',
- 'value' => "%$last%" } } );
-
- push @cust_main, qsearch( 'cust_main',
- { 'ship_last' => { 'op' => 'ILIKE',
- 'value' => "%$last%" } } )
- if defined dbdef->table('cust_main')->column('ship_last');
-
- }
-
- if ( $last_type{'Fuzzy'} || $last_type{'All'} ) {
- push @cust_main, FS::cust_main->fuzzy_search( { 'last' => $last } );
- }
-
- #if ($last_type{'Sound-alike'}) {
- #}
-
- \@cust_main;
-}
-
-sub companysearch {
-
- my(%company_type);
- my @cust_main;
- foreach ( $cgi->param('company_type') ) {
- $company_type{$_}++
- };
-
- $cgi->param('company_text') =~
- /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=]*)$/
- or eidiot "Illegal company";
- my $company = $1;
-
- if ( $company_type{'Exact'} || $company_type{'Fuzzy'} ) {
- push @cust_main, qsearch( 'cust_main',
- { 'company' => { 'op' => 'ILIKE',
- 'value' => $company } } );
-
- push @cust_main, qsearch( 'cust_main',
- { 'ship_company' => { 'op' => 'ILIKE',
- 'value' => $company } } )
- if defined dbdef->table('cust_main')->column('ship_last');
- }
-
- if ( $company_type{'Substring'} || $company_type{'All'} ) {
-
- push @cust_main, qsearch( 'cust_main',
- { 'company' => { 'op' => 'ILIKE',
- 'value' => "%$company%" } } );
-
- push @cust_main, qsearch( 'cust_main',
- { 'ship_company' => { 'op' => 'ILIKE',
- 'value' => "%$company%" } })
- if defined dbdef->table('cust_main')->column('ship_last');
-
- }
-
- if ( $company_type{'Fuzzy'} || $company_type{'All'} ) {
- push @cust_main, FS::cust_main->fuzzy_search( { 'company' => $company } );
- }
-
- if ($company_type{'Sound-alike'}) {
- }
-
- \@cust_main;
-}
-
-sub address2search {
- my @cust_main;
-
- $cgi->param('address2_text') =~
- /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=]*)$/
- or eidiot "Illegal address2";
- my $address2 = $1;
-
- push @cust_main, qsearch( 'cust_main',
- { 'address2' => { 'op' => 'ILIKE',
- 'value' => $address2 } } );
- push @cust_main, qsearch( 'cust_main',
- { 'address2' => { 'op' => 'ILIKE',
- 'value' => $address2 } } )
- if defined dbdef->table('cust_main')->column('ship_last');
-
- \@cust_main;
-}
-
-sub phonesearch {
- my @cust_main;
-
- my $phone = $cgi->param('phone_text');
-
- #(no longer really) false laziness with Record::ut_phonen
- #only works with US/CA numbers...
- $phone =~ s/\D//g;
- if ( $phone =~ /^(\d{3})(\d{3})(\d{4})(\d*)$/ ) {
- $phone = "$1-$2-$3";
- $phone .= " x$4" if $4;
- } elsif ( $phone =~ /^(\d{3})(\d{4})$/ ) {
- $phone = "$1-$2";
- } elsif ( $phone =~ /^(\d{3,4})$/ ) {
- $phone = $1;
- } else {
- eidiot gettext('illegal_phone'). ": $phone";
- }
-
- my @fields = qw(daytime night fax);
- push @fields, qw(ship_daytime ship_night ship_fax)
- if defined dbdef->table('cust_main')->column('ship_last');
-
- for my $field ( @fields ) {
- push @cust_main, qsearch ( 'cust_main',
- { $field => { 'op' => 'LIKE',
- 'value' => "%$phone%" } } );
- }
-
- \@cust_main;
-}
-
-%>
+ </TABLE><% $pager %>
+
+ <% include('/elements/footer.html') %>
+% }
+%
+%#undef $cache; #does this help?
+%
+%#
+%
+%sub last_sort {
+% lc($a->getfield('last')) cmp lc($b->getfield('last'))
+% || lc($a->first) cmp lc($b->first);
+%}
+%
+%sub company_sort {
+% return -1 if $a->company && ! $b->company;
+% return 1 if ! $a->company && $b->company;
+% lc($a->company) cmp lc($b->company)
+% || lc($a->getfield('last')) cmp lc($b->getfield('last'))
+% || lc($a->first) cmp lc($b->first);;
+%}
+%
+%sub custnum_sort {
+% $a->getfield('custnum') <=> $b->getfield('custnum');
+%}
+%
+%sub tickets_sort {
+% $b->getfield('tickets') <=> $a->getfield('tickets');
+%}
+%
+%sub custnumsearch {
+%
+% my $custnum = $cgi->param('custnum_text');
+% $custnum =~ s/\D//g;
+% $custnum =~ /^(\d{1,23})$/ or eidiot "Illegal customer number\n";
+% $custnum = $1;
+%
+% [ qsearchs('cust_main', { 'custnum' => $custnum } ) ];
+%}
+%
+%sub cardsearch {
+%
+% my($card)=$cgi->param('card');
+% $card =~ s/\D//g;
+% $card =~ /^(\d{13,16})$/ or eidiot "Illegal card number\n";
+% my($payinfo)=$1;
+%
+% [ qsearch('cust_main',{'payinfo'=>$payinfo, 'payby'=>'CARD'}),
+% qsearch('cust_main',{'payinfo'=>$payinfo, 'payby'=>'DCRD'})
+% ];
+%}
+%
+%sub referralsearch {
+% $cgi->param('referral_custnum') =~ /^(\d+)$/
+% or eidiot "Illegal referral_custnum";
+% my $cust_main = qsearchs('cust_main', { 'custnum' => $1 } )
+% or eidiot "Customer $1 not found";
+% my $depth;
+% if ( $cgi->param('referral_depth') ) {
+% $cgi->param('referral_depth') =~ /^(\d+)$/
+% or eidiot "Illegal referral_depth";
+% $depth = $1;
+% } else {
+% $depth = 1;
+% }
+% [ $cust_main->referral_cust_main($depth) ];
+%}
+%
+%sub lastsearch {
+% my(%last_type);
+% my @cust_main;
+% foreach ( $cgi->param('last_type') ) {
+% $last_type{$_}++;
+% }
+%
+% $cgi->param('last_text') =~ /^([\w \,\.\-\']*)$/
+% or eidiot "Illegal last name";
+% my($last)=$1;
+%
+% if ( $last_type{'Exact'} || $last_type{'Fuzzy'} ) {
+% push @cust_main, qsearch( 'cust_main',
+% { 'last' => { 'op' => 'ILIKE',
+% 'value' => $last } } );
+%
+% push @cust_main, qsearch( 'cust_main',
+% { 'ship_last' => { 'op' => 'ILIKE',
+% 'value' => $last } } )
+% if defined dbdef->table('cust_main')->column('ship_last');
+% }
+%
+% if ( $last_type{'Substring'} || $last_type{'All'} ) {
+%
+% push @cust_main, qsearch( 'cust_main',
+% { 'last' => { 'op' => 'ILIKE',
+% 'value' => "%$last%" } } );
+%
+% push @cust_main, qsearch( 'cust_main',
+% { 'ship_last' => { 'op' => 'ILIKE',
+% 'value' => "%$last%" } } )
+% if defined dbdef->table('cust_main')->column('ship_last');
+%
+% }
+%
+% if ( $last_type{'Fuzzy'} || $last_type{'All'} ) {
+% push @cust_main, FS::cust_main->fuzzy_search( { 'last' => $last } );
+% }
+%
+% #if ($last_type{'Sound-alike'}) {
+% #}
+%
+% \@cust_main;
+%}
+%
+%sub companysearch {
+%
+% my(%company_type);
+% my @cust_main;
+% foreach ( $cgi->param('company_type') ) {
+% $company_type{$_}++
+% };
+%
+% $cgi->param('company_text') =~
+% /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=]*)$/
+% or eidiot "Illegal company";
+% my $company = $1;
+%
+% if ( $company_type{'Exact'} || $company_type{'Fuzzy'} ) {
+% push @cust_main, qsearch( 'cust_main',
+% { 'company' => { 'op' => 'ILIKE',
+% 'value' => $company } } );
+%
+% push @cust_main, qsearch( 'cust_main',
+% { 'ship_company' => { 'op' => 'ILIKE',
+% 'value' => $company } } )
+% if defined dbdef->table('cust_main')->column('ship_last');
+% }
+%
+% if ( $company_type{'Substring'} || $company_type{'All'} ) {
+%
+% push @cust_main, qsearch( 'cust_main',
+% { 'company' => { 'op' => 'ILIKE',
+% 'value' => "%$company%" } } );
+%
+% push @cust_main, qsearch( 'cust_main',
+% { 'ship_company' => { 'op' => 'ILIKE',
+% 'value' => "%$company%" } })
+% if defined dbdef->table('cust_main')->column('ship_last');
+%
+% }
+%
+% if ( $company_type{'Fuzzy'} || $company_type{'All'} ) {
+% push @cust_main, FS::cust_main->fuzzy_search( { 'company' => $company } );
+% }
+%
+% if ($company_type{'Sound-alike'}) {
+% }
+%
+% \@cust_main;
+%}
+%
+%sub address2search {
+% my @cust_main;
+%
+% $cgi->param('address2_text') =~
+% /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=]*)$/
+% or eidiot "Illegal address2";
+% my $address2 = $1;
+%
+% push @cust_main, qsearch( 'cust_main',
+% { 'address2' => { 'op' => 'ILIKE',
+% 'value' => $address2 } } );
+% push @cust_main, qsearch( 'cust_main',
+% { 'address2' => { 'op' => 'ILIKE',
+% 'value' => $address2 } } )
+% if defined dbdef->table('cust_main')->column('ship_last');
+%
+% \@cust_main;
+%}
+%
+%sub phonesearch {
+% my @cust_main;
+%
+% my $phone = $cgi->param('phone_text');
+%
+% #(no longer really) false laziness with Record::ut_phonen
+% #only works with US/CA numbers...
+% $phone =~ s/\D//g;
+% if ( $phone =~ /^(\d{3})(\d{3})(\d{4})(\d*)$/ ) {
+% $phone = "$1-$2-$3";
+% $phone .= " x$4" if $4;
+% } elsif ( $phone =~ /^(\d{3})(\d{4})$/ ) {
+% $phone = "$1-$2";
+% } elsif ( $phone =~ /^(\d{3,4})$/ ) {
+% $phone = $1;
+% } else {
+% eidiot gettext('illegal_phone'). ": $phone";
+% }
+%
+% my @fields = qw(daytime night fax);
+% push @fields, qw(ship_daytime ship_night ship_fax)
+% if defined dbdef->table('cust_main')->column('ship_last');
+%
+% for my $field ( @fields ) {
+% push @cust_main, qsearch ( 'cust_main',
+% { $field => { 'op' => 'LIKE',
+% 'value' => "%$phone%" } } );
+% }
+%
+% \@cust_main;
+%}
diff --git a/httemplate/search/cust_main.html b/httemplate/search/cust_main.html
index 4f7508447..8ef1ecb9a 100755
--- a/httemplate/search/cust_main.html
+++ b/httemplate/search/cust_main.html
@@ -39,4 +39,9 @@
</UL>
</BODY>
</HTML>
+<%init>
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('List customers');
+
+</%init>
diff --git a/httemplate/search/cust_pay.cgi b/httemplate/search/cust_pay.cgi
index 99ffc3d20..6215b4b2f 100755
--- a/httemplate/search/cust_pay.cgi
+++ b/httemplate/search/cust_pay.cgi
@@ -1,150 +1,4 @@
-<%
- my $title = 'Payment Search Results';
- my( $count_query, $sql_query );
- if ( $cgi->param('magic') ) {
-
- my @search = ();
- my $orderby;
- if ( $cgi->param('magic') eq '_date' ) {
-
-
- if ( $cgi->param('agentnum') && $cgi->param('agentnum') =~ /^(\d+)$/ ) {
- push @search, "agentnum = $1"; # $search{'agentnum'} = $1;
- my $agent = qsearchs('agent', { 'agentnum' => $1 } );
- die "unknown agentnum $1" unless $agent;
- $title = $agent->agent. " $title";
- }
-
- if ( $cgi->param('payby') ) {
- $cgi->param('payby') =~
- /^(CARD|CHEK|BILL|PREP|CASH|WEST|MCRD)(-(VisaMC|Amex|Discover|Maestro))?$/
- or die "illegal payby ". $cgi->param('payby');
- push @search, "cust_pay.payby = '$1'";
- if ( $3 ) {
- if ( $3 eq 'VisaMC' ) {
- #avoid posix regexes for portability
- push @search,
- " ( ( substring(cust_pay.payinfo from 1 for 1) = '4' ".
- " AND substring(cust_pay.payinfo from 1 for 4) != '4936' ".
- " AND substring(cust_pay.payinfo from 1 for 6) ".
- " NOT SIMILAR TO '49030[2-9]' ".
- " AND substring(cust_pay.payinfo from 1 for 6) ".
- " NOT SIMILAR TO '49033[5-9]' ".
- " AND substring(cust_pay.payinfo from 1 for 6) ".
- " NOT SIMILAR TO '49110[1-2]' ".
- " AND substring(cust_pay.payinfo from 1 for 6) ".
- " NOT SIMILAR TO '49117[4-9]' ".
- " AND substring(cust_pay.payinfo from 1 for 6) ".
- " NOT SIMILAR TO '49118[1-2]' ".
- " )".
- " OR substring(cust_pay.payinfo from 1 for 2) = '51' ".
- " OR substring(cust_pay.payinfo from 1 for 2) = '52' ".
- " OR substring(cust_pay.payinfo from 1 for 2) = '53' ".
- " OR substring(cust_pay.payinfo from 1 for 2) = '54' ".
- " OR substring(cust_pay.payinfo from 1 for 2) = '54' ".
- " OR substring(cust_pay.payinfo from 1 for 2) = '55' ".
- " ) ";
- } elsif ( $3 eq 'Amex' ) {
- push @search,
- " ( substring(cust_pay.payinfo from 1 for 2 ) = '34' ".
- " OR substring(cust_pay.payinfo from 1 for 2 ) = '37' ".
- " ) ";
- } elsif ( $3 eq 'Discover' ) {
- push @search,
- " ( substring(cust_pay.payinfo from 1 for 4 ) = '6011' ".
- " OR substring(cust_pay.payinfo from 1 for 3 ) = '650' ".
- " ) ";
- } elsif ( $3 eq 'Maestro' ) {
- push @search,
- " ( substring(cust_pay.payinfo from 1 for 2 ) = '63' ".
- " OR substring(cust_pay.payinfo from 1 for 2 ) = '67' ".
- " OR substring(cust_pay.payinfo from 1 for 6 ) = '564182' ".
- " OR substring(cust_pay.payinfo from 1 for 4 ) = '4936' ".
- " OR substring(cust_pay.payinfo from 1 for 6 ) ".
- " SIMILAR TO '49030[2-9]' ".
- " OR substring(cust_pay.payinfo from 1 for 6 ) ".
- " SIMILAR TO '49033[5-9]' ".
- " OR substring(cust_pay.payinfo from 1 for 6 ) ".
- " SIMILAR TO '49110[1-2]' ".
- " OR substring(cust_pay.payinfo from 1 for 6 ) ".
- " SIMILAR TO '49117[4-9]' ".
- " OR substring(cust_pay.payinfo from 1 for 6 ) ".
- " SIMILAR TO '49118[1-2]' ".
- " ) ";
- } else {
- die "unknown card type $3";
- }
- }
- }
-
- my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi);
- push @search, "_date >= $beginning ",
- "_date <= $ending";
-
- $orderby = '_date';
-
- } elsif ( $cgi->param('magic') eq 'paybatch' ) {
-
- $cgi->param('paybatch') =~ /^([\w\/\:\-\.]+)$/
- or die "illegal paybatch: ". $cgi->param('paybatch');
-
- push @search, "paybatch = '$1'";
-
- $orderby = "LOWER(company || ' ' || last || ' ' || first )";
-
- } else {
- die "unknown search magic: ". $cgi->param('magic');
- }
-
- my $search = '';
- if ( @search ) {
- $search = ' WHERE '. join(' AND ', @search);
- }
-
- $count_query = "SELECT COUNT(*), SUM(paid) ".
- "FROM cust_pay LEFT JOIN cust_main USING ( custnum )".
- $search;
-
- $sql_query = {
- 'table' => 'cust_pay',
- 'select' => join(', ',
- 'cust_pay.*',
- 'cust_main.custnum as cust_main_custnum',
- FS::UI::Web::cust_sql_fields(),
- ),
- 'hashref' => {},
- 'extra_sql' => "$search ORDER BY $orderby",
- 'addl_from' => 'LEFT JOIN cust_main USING ( custnum )',
- };
-
- } else {
-
- $cgi->param('payinfo') =~ /^\s*(\d+)\s*$/ or die "illegal payinfo";
- my $payinfo = $1;
-
- $cgi->param('payby') =~ /^(\w+)$/ or die "illegal payby";
- my $payby = $1;
-
- $count_query = "SELECT COUNT(*), SUM(paid) FROM cust_pay ".
- "WHERE payinfo = '$payinfo' AND payby = '$payby'";
-
- $sql_query = {
- 'table' => 'cust_pay',
- 'hashref' => { 'payinfo' => $payinfo,
- 'payby' => $payby },
- 'extra_sql' => "ORDER BY _date",
- };
-
- }
-
- my $link = sub {
- my $cust_pay = shift;
- $cust_pay->cust_main_custnum
- ? [ "${p}view/cust_main.cgi?", 'custnum' ]
- : '';
- };
-
-%><%= include( 'elements/search.html',
+<% include( 'elements/search.html',
'title' => $title,
'name' => 'payments',
'query' => $sql_query,
@@ -159,7 +13,7 @@
sub {
my $cust_pay = shift;
if ( $cust_pay->payby eq 'CARD' ) {
- 'Card #'. $cust_pay->payinfo_masked;
+ 'Card #'. $cust_pay->paymask;
} elsif ( $cust_pay->payby eq 'CHEK' ) {
'E-check acct#'. $cust_pay->payinfo;
} elsif ( $cust_pay->payby eq 'BILL' ) {
@@ -181,12 +35,194 @@
\&FS::UI::Web::cust_fields,
],
#'align' => 'lrrrll',
- 'align' => 'rrr',
+ 'align' => 'rrr'.FS::UI::Web::cust_aligns(),
'links' => [
'',
'',
'',
- ( map { $link } FS::UI::Web::cust_header() ),
+ ( map { $_ ne 'Cust. Status' ? $link : '' }
+ FS::UI::Web::cust_header()
+ ),
],
+ 'color' => [
+ '',
+ '',
+ '',
+ FS::UI::Web::cust_colors(),
+ ],
+ 'style' => [
+ '',
+ '',
+ '',
+ FS::UI::Web::cust_styles(),
+ ],
)
%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
+
+my $title = 'Payment Search Results';
+my( $count_query, $sql_query );
+if ( $cgi->param('magic') ) {
+
+ my @search = ();
+ my $orderby;
+ if ( $cgi->param('magic') eq '_date' ) {
+
+
+ if ( $cgi->param('agentnum') && $cgi->param('agentnum') =~ /^(\d+)$/ ) {
+ push @search, "agentnum = $1"; # $search{'agentnum'} = $1;
+ my $agent = qsearchs('agent', { 'agentnum' => $1 } );
+ die "unknown agentnum $1" unless $agent;
+ $title = $agent->agent. " $title";
+ }
+
+ if ( $cgi->param('payby') ) {
+ $cgi->param('payby') =~
+ /^(CARD|CHEK|BILL|PREP|CASH|WEST|MCRD)(-(VisaMC|Amex|Discover|Maestro))?$/
+ or die "illegal payby ". $cgi->param('payby');
+ push @search, "cust_pay.payby = '$1'";
+ if ( $3 ) {
+
+ my $cardtype = $3;
+
+ my $search;
+ if ( $cardtype eq 'VisaMC' ) {
+ #avoid posix regexes for portability
+ $search =
+ " ( ( substring(cust_pay.payinfo from 1 for 1) = '4' ".
+ " AND substring(cust_pay.payinfo from 1 for 4) != '4936' ".
+ " AND substring(cust_pay.payinfo from 1 for 6) ".
+ " NOT SIMILAR TO '49030[2-9]' ".
+ " AND substring(cust_pay.payinfo from 1 for 6) ".
+ " NOT SIMILAR TO '49033[5-9]' ".
+ " AND substring(cust_pay.payinfo from 1 for 6) ".
+ " NOT SIMILAR TO '49110[1-2]' ".
+ " AND substring(cust_pay.payinfo from 1 for 6) ".
+ " NOT SIMILAR TO '49117[4-9]' ".
+ " AND substring(cust_pay.payinfo from 1 for 6) ".
+ " NOT SIMILAR TO '49118[1-2]' ".
+ " )".
+ " OR substring(cust_pay.payinfo from 1 for 2) = '51' ".
+ " OR substring(cust_pay.payinfo from 1 for 2) = '52' ".
+ " OR substring(cust_pay.payinfo from 1 for 2) = '53' ".
+ " OR substring(cust_pay.payinfo from 1 for 2) = '54' ".
+ " OR substring(cust_pay.payinfo from 1 for 2) = '54' ".
+ " OR substring(cust_pay.payinfo from 1 for 2) = '55' ".
+ " OR substring(cust_pay.payinfo from 1 for 2) = '36' ". #Diner's int'l processed as Visa/MC inside US
+ " ) ";
+ } elsif ( $cardtype eq 'Amex' ) {
+ $search =
+ " ( substring(cust_pay.payinfo from 1 for 2 ) = '34' ".
+ " OR substring(cust_pay.payinfo from 1 for 2 ) = '37' ".
+ " ) ";
+ } elsif ( $cardtype eq 'Discover' ) {
+ $search =
+ " ( substring(cust_pay.payinfo from 1 for 4 ) = '6011' ".
+ " OR substring(cust_pay.payinfo from 1 for 2 ) = '65' ".
+ " OR substring(cust_pay.payinfo from 1 for 3 ) = '622' ". #China Union Pay processed as Discover outside CN
+ " ) ";
+ } elsif ( $cardtype eq 'Maestro' ) {
+ $search =
+ " ( substring(cust_pay.payinfo from 1 for 2 ) = '63' ".
+ " OR substring(cust_pay.payinfo from 1 for 2 ) = '67' ".
+ " OR substring(cust_pay.payinfo from 1 for 6 ) = '564182' ".
+ " OR substring(cust_pay.payinfo from 1 for 4 ) = '4936' ".
+ " OR substring(cust_pay.payinfo from 1 for 6 ) ".
+ " SIMILAR TO '49030[2-9]' ".
+ " OR substring(cust_pay.payinfo from 1 for 6 ) ".
+ " SIMILAR TO '49033[5-9]' ".
+ " OR substring(cust_pay.payinfo from 1 for 6 ) ".
+ " SIMILAR TO '49110[1-2]' ".
+ " OR substring(cust_pay.payinfo from 1 for 6 ) ".
+ " SIMILAR TO '49117[4-9]' ".
+ " OR substring(cust_pay.payinfo from 1 for 6 ) ".
+ " SIMILAR TO '49118[1-2]' ".
+ " ) ";
+ } else {
+ die "unknown card type $cardtype";
+ }
+
+ my $masksearch = $search;
+ $masksearch =~ s/cust_pay\.payinfo/cust_pay.paymask/gi;
+
+ push @search,
+ "( $search OR ( cust_pay.paymask IS NOT NULL AND $masksearch ) )";
+
+ }
+ }
+
+ my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi);
+ push @search, "_date >= $beginning ",
+ "_date <= $ending";
+
+ push @search, FS::UI::Web::parse_lt_gt($cgi, 'paid' );
+
+ $orderby = '_date';
+
+ } elsif ( $cgi->param('magic') eq 'paybatch' ) {
+
+ $cgi->param('paybatch') =~ /^([\w\/\:\-\.]+)$/
+ or die "illegal paybatch: ". $cgi->param('paybatch');
+
+ push @search, "paybatch = '$1'";
+
+ $orderby = "LOWER(company || ' ' || last || ' ' || first )";
+
+ } else {
+ die "unknown search magic: ". $cgi->param('magic');
+ }
+
+ #here is the agent virtualization
+ push @search, $FS::CurrentUser::CurrentUser->agentnums_sql;
+
+ my $search = ' WHERE '. join(' AND ', @search);
+
+ $count_query = "SELECT COUNT(*), SUM(paid) ".
+ "FROM cust_pay LEFT JOIN cust_main USING ( custnum )".
+ $search;
+
+ $sql_query = {
+ 'table' => 'cust_pay',
+ 'select' => join(', ',
+ 'cust_pay.*',
+ 'cust_main.custnum as cust_main_custnum',
+ FS::UI::Web::cust_sql_fields(),
+ ),
+ 'hashref' => {},
+ 'extra_sql' => "$search ORDER BY $orderby",
+ 'addl_from' => 'LEFT JOIN cust_main USING ( custnum )',
+ };
+
+} else {
+
+ $cgi->param('payinfo') =~ /^\s*(\d+)\s*$/ or die "illegal payinfo";
+ my $payinfo = $1;
+
+ $cgi->param('payby') =~ /^(\w+)$/ or die "illegal payby";
+ my $payby = $1;
+
+ $count_query = "SELECT COUNT(*), SUM(paid) FROM cust_pay".
+ " WHERE payinfo = '$payinfo' AND payby = '$payby'".
+ " AND ". $FS::CurrentUser::CurrentUser->agentnums_sql;
+
+ $sql_query = {
+ 'table' => 'cust_pay',
+ 'hashref' => { 'payinfo' => $payinfo,
+ 'payby' => $payby },
+ 'extra_sql' => $FS::CurrentUser::CurrentUser->agentnums_sql.
+ " ORDER BY _date",
+ };
+
+}
+
+my $link = sub {
+ my $cust_pay = shift;
+ $cust_pay->cust_main_custnum
+ ? [ "${p}view/cust_main.cgi?", 'custnum' ]
+ : '';
+};
+
+</%init>
diff --git a/httemplate/search/cust_pay.html b/httemplate/search/cust_pay.html
deleted file mode 100755
index 6414cf771..000000000
--- a/httemplate/search/cust_pay.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<HTML>
- <HEAD>
- <TITLE>Check # Search</TITLE>
- </HEAD>
- <BODY BGCOLOR="#e8e8e8">
- <FONT SIZE=7>
- Check # Search
- </FONT>
- <BR><BR>
- <FORM ACTION="cust_pay.cgi" METHOD="GET">
- Search for <B>check #</B>:
- <INPUT TYPE="text" NAME="payinfo">
- <INPUT TYPE="hidden" NAME="payby" VALUE="BILL">
- <BR><BR><INPUT TYPE="submit" VALUE="Search">
- </FORM>
- </BODY>
-</HTML>
-
diff --git a/httemplate/search/cust_pay_batch.cgi b/httemplate/search/cust_pay_batch.cgi
new file mode 100755
index 000000000..e378ffae7
--- /dev/null
+++ b/httemplate/search/cust_pay_batch.cgi
@@ -0,0 +1,190 @@
+<% include('elements/search.html',
+ 'title' => 'Batch payment details',
+ 'name' => 'batch details',
+ 'menubar' => ['Main Menu' => $p,],
+ 'query' => $sql_query,
+ 'count_query' => $count_query,
+ 'html_init' => $pay_batch ? $html_init : '',
+ 'header' => [ '#',
+ 'Inv #',
+ 'Customer',
+ 'Customer',
+ 'Card Name',
+ 'Card',
+ 'Exp',
+ 'Amount',
+ 'Status',
+ ],
+ 'fields' => [ sub {
+ shift->[0];
+ },
+ sub {
+ shift->[1];
+ },
+ sub {
+ shift->[2];
+ },
+ sub {
+ my $cpb = shift;
+ $cpb->[3] . ', ' . $cpb->[4];
+ },
+ sub {
+ shift->[5];
+ },
+ sub {
+ my $cardnum = shift->[6];
+ 'x'x(length($cardnum)-4). substr($cardnum,(length($cardnum)-4));
+ },
+ sub {
+ shift->[7] =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/;
+ my( $mon, $year ) = ( $2, $1 );
+ $mon = "0$mon" if length($mon) == 1;
+ "$mon/$year";
+ },
+ sub {
+ shift->[8];
+ },
+ sub {
+ shift->[9];
+ },
+ ],
+ 'align' => 'lllllllrl',
+ 'links' => [ ['', sub{'#';}],
+ ["${p}view/cust_bill.cgi?", sub{shift->[1];},],
+ ["${p}view/cust_main.cgi?", sub{shift->[2];},],
+ ["${p}view/cust_main.cgi?", sub{shift->[2];},],
+ ],
+ )
+%>
+<%init>
+
+my $conf = new FS::Conf;
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Financial reports')
+ || $FS::CurrentUser::CurrentUser->access_right('Process batches')
+ || ( $cgi->param('custnum')
+ && $conf->exists('batch-enable')
+ #&& $FS::CurrentUser::CurrentUser->access_right('View customer batched payments')
+ );
+
+my( $count_query, $sql_query );
+my $hashref = {};
+my @search = ();
+my $orderby = 'paybatchnum';
+
+my( $pay_batch, $batchnum ) = ( '', '');
+if ( $cgi->param('batchnum') && $cgi->param('batchnum') =~ /^(\d+)$/ ) {
+ push @search, "batchnum = $1";
+ $pay_batch = qsearchs('pay_batch', { 'batchnum' => $1 } );
+ die "Batch $1 not found!" unless $pay_batch;
+ $batchnum = $pay_batch->batchnum;
+}
+
+if ( $cgi->param('custnum') && $cgi->param('custnum') =~ /^(\d+)$/ ) {
+ push @search, "custnum = $1";
+}
+
+if ( $cgi->param('status') && $cgi->param('status') =~ /^(\w)$/ ) {
+ push @search, "pay_batch.status = '$1'";
+}
+
+if ( $cgi->param('payby') ) {
+ $cgi->param('payby') =~ /^(CARD|CHEK)$/
+ or die "illegal payby " . $cgi->param('payby');
+
+ push @search, "cust_pay_batch.payby = '$1'";
+}
+
+if ( not $cgi->param('dcln') ) {
+ push @search, "cpb.status IS DISTINCT FROM 'Approved'";
+}
+
+my ($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi);
+unless ($pay_batch){
+ push @search, "pay_batch.upload >= $beginning" if ($beginning);
+ push @search, "pay_batch.upload <= $ending" if ($ending < 4294967295);#2^32-1
+ $orderby = "pay_batch.download,paybatchnum";
+}
+
+push @search, $FS::CurrentUser::CurrentUser->agentnums_sql;
+my $search = ' WHERE ' . join(' AND ', @search);
+
+$count_query = 'SELECT COUNT(*) FROM cust_pay_batch AS cpb ' .
+ 'LEFT JOIN cust_main USING ( custnum ) ' .
+ 'LEFT JOIN pay_batch USING ( batchnum )' .
+ $search;
+
+#grr
+$sql_query = "SELECT paybatchnum,invnum,custnum,cpb.last,cpb.first," .
+ "cpb.payname,cpb.payinfo,cpb.exp,amount,cpb.status " .
+ "FROM cust_pay_batch AS cpb " .
+ 'LEFT JOIN cust_main USING ( custnum ) ' .
+ 'LEFT JOIN pay_batch USING ( batchnum ) ' .
+ "$search ORDER BY $orderby";
+
+my $html_init = '';
+if ( $pay_batch ) {
+ my $fixed = $conf->config('batch-fixed_format-'. $pay_batch->payby);
+ if (
+ $pay_batch->status eq 'O'
+ || ( $pay_batch->status eq 'I'
+ && $FS::CurrentUser::CurrentUser->access_right('Reprocess batches')
+ )
+ ) {
+ $html_init .= qq!<FORM ACTION="$p/misc/download-batch.cgi" METHOD="POST">!;
+ if ( $fixed ) {
+ $html_init .= qq!<INPUT TYPE="hidden" NAME="format" VALUE="$fixed">!;
+ } else {
+ $html_init .= qq!Download batch in format <SELECT NAME="format">!.
+ qq!<OPTION VALUE="">Default batch mode</OPTION>!.
+ qq!<OPTION VALUE="csv-td_canada_trust-merchant_pc_batch">CSV file for TD Canada Trust Merchant PC Batch</OPTION>!.
+ qq!<OPTION VALUE="csv-chase_canada-E-xactBatch">CSV file for Chase Canada E-xactBatch</OPTION>!.
+ qq!<OPTION VALUE="PAP">80 byte file for TD Canada Trust PAP Batch</OPTION>!.
+ qq!<OPTION VALUE="BoM">Bank of Montreal ECA batch</OPTION>!.
+ qq!</SELECT>!;
+ }
+ $html_init .= qq!<INPUT TYPE="hidden" NAME="batchnum" VALUE="$batchnum"><INPUT TYPE="submit" VALUE="Download"></FORM><BR>!;
+ }
+
+ if (
+ $pay_batch->status eq 'I'
+ || ( $pay_batch->status eq 'R'
+ && $FS::CurrentUser::CurrentUser->access_right('Reprocess batches')
+ )
+ ) {
+ $html_init .= qq!<FORM ACTION="$p/misc/upload-batch.cgi" METHOD="POST" ENCTYPE="multipart/form-data">!.
+ qq!Upload results<BR>!.
+ qq!Filename <INPUT TYPE="file" NAME="batch_results"><BR>!;
+ if ( $fixed ) {
+ $html_init .= qq!<INPUT TYPE="hidden" NAME="format" VALUE="$fixed">!;
+ } else {
+ $html_init .= qq!Format <SELECT NAME="format">!.
+ qq!<OPTION VALUE="">Default batch mode</OPTION>!.
+ qq!<OPTION VALUE="csv-td_canada_trust-merchant_pc_batch">CSV results from TD Canada Trust Merchant PC Batch</OPTION>!.
+ qq!<OPTION VALUE="csv-chase_canada-E-xactBatch">CSV file for Chase Canada E-xactBatch</OPTION>!.
+ qq!<OPTION VALUE="PAP">264 byte results for TD Canada Trust PAP Batch</OPTION>!.
+ qq!<OPTION VALUE="BoM">Bank of Montreal ECA results</OPTION>!.
+ qq!</SELECT><BR>!;
+ }
+ $html_init .= qq!<INPUT TYPE="hidden" NAME="batchnum" VALUE="$batchnum">!;
+ $html_init .= '<INPUT TYPE="submit" VALUE="Upload"></FORM><BR>';
+ }
+
+}
+
+if ($pay_batch) {
+ my $sth = dbh->prepare($count_query) or die dbh->errstr. "doing $count_query";
+ $sth->execute or die "Error executing \"$count_query\": ". $sth->errstr;
+ my $cards = $sth->fetchrow_arrayref->[0];
+
+ my $st = "SELECT SUM(amount) from cust_pay_batch WHERE batchnum=". $batchnum;
+ $sth = dbh->prepare($st) or die dbh->errstr. "doing $st";
+ $sth->execute or die "Error executing \"$st\": ". $sth->errstr;
+ my $total = $sth->fetchrow_arrayref->[0];
+
+ $html_init .= "$cards credit card payments batched<BR>\$" .
+ sprintf("%.2f", $total) ." total in batch<BR>";
+}
+
+</%init>
diff --git a/httemplate/search/cust_pkg.cgi b/httemplate/search/cust_pkg.cgi
index 5da4d82fb..84b083a3d 100755
--- a/httemplate/search/cust_pkg.cgi
+++ b/httemplate/search/cust_pkg.cgi
@@ -1,149 +1,12 @@
-<%
-
-my %part_pkg = map { $_->pkgpart => $_ } qsearch('part_pkg', {});
-
-my($query) = $cgi->keywords;
-
-my $orderby;
-my @where;
-my $cjoin = '';
-
-if ( $cgi->param('agentnum') =~ /^(\d+)$/ and $1 ) {
- $cjoin = "LEFT JOIN cust_main USING ( custnum )";
- push @where,
- "agentnum = $1";
-}
-
-if ( $cgi->param('magic') && $cgi->param('magic') eq 'bill' ) {
- $orderby = 'ORDER BY bill';
-
- my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi);
- push @where,
- "bill >= $beginning ",
- "bill <= $ending",
- '( cancel IS NULL OR cancel = 0 )';
-
-} else {
-
- if ( $cgi->param('magic') &&
- $cgi->param('magic') =~ /^(active|suspended|cancell?ed)$/
- ) {
-
- $orderby = 'ORDER BY pkgnum';
-
- if ( $cgi->param('magic') eq 'active' ) {
-
- #push @where,
- # '( susp IS NULL OR susp = 0 )',
- # '( cancel IS NULL OR cancel = 0)';
- push @where, FS::cust_pkg->active_sql();
-
- } elsif ( $cgi->param('magic') eq 'suspended' ) {
-
- push @where,
- 'susp IS NOT NULL',
- 'susp != 0',
- '( cancel IS NULL OR cancel = 0)';
-
- } elsif ( $cgi->param('magic') =~ /^cancell?ed$/ ) {
-
- push @where,
- 'cancel IS NOT NULL',
- 'cancel != 0';
-
- } else {
- die "guru meditation #420";
- }
-
- if ( $cgi->param('pkgpart') =~ /^(\d+)$/ ) {
- push @where, "pkgpart = $1";
- }
-
- } elsif ( $query eq 'pkgnum' ) {
-
- $orderby = 'ORDER BY pkgnum';
-
- } elsif ( $query eq 'APKG_pkgnum' ) {
-
- $orderby = 'ORDER BY pkgnum';
-
- push @where, '0 < (
- SELECT count(*) FROM pkg_svc
- WHERE pkg_svc.pkgpart = cust_pkg.pkgpart
- AND pkg_svc.quantity > ( SELECT count(*) FROM cust_svc
- WHERE cust_svc.pkgnum = cust_pkg.pkgnum
- AND cust_svc.svcpart = pkg_svc.svcpart
- )
- )';
-
- } else {
- die "Empty or unknown QUERY_STRING!";
- }
-
-}
-
-my $extra_sql = scalar(@where) ? ' WHERE '. join(' AND ', @where) : '';
-
-my $count_query = "SELECT COUNT(*) FROM cust_pkg $cjoin $extra_sql";
-
-my $sql_query = {
- 'table' => 'cust_pkg',
- 'hashref' => {},
- 'select' => join(', ',
- 'cust_pkg.*',
- 'cust_main.custnum as cust_main_custnum',
- FS::UI::Web::cust_sql_fields(),
- ),
- 'extra_sql' => "$extra_sql $orderby",
- 'addl_from' => ' LEFT JOIN cust_main USING ( custnum ) ',
- #' LEFT JOIN part_pkg USING ( pkgpart ) '
-};
-
-my $link = sub {
- [ "${p}view/cust_main.cgi?".shift->custnum.'#cust_pkg', 'pkgnum' ];
-};
-
-my $clink = sub {
- my $cust_pkg = shift;
- $cust_pkg->cust_main_custnum
- ? [ "${p}view/cust_main.cgi?", 'custnum' ]
- : '';
-};
-
-#if ( scalar(@cust_pkg) == 1 ) {
-# print $cgi->redirect("${p}view/cust_main.cgi?". $cust_pkg[0]->custnum.
-# "#cust_pkg". $cust_pkg[0]->pkgnum );
-
-# my @cust_svc = qsearch( 'cust_svc', { 'pkgnum' => $pkgnum } );
-# my $rowspan = scalar(@cust_svc) || 1;
-
-# my $n2 = '';
-# foreach my $cust_svc ( @cust_svc ) {
-# my($label, $value, $svcdb) = $cust_svc->label;
-# my $svcnum = $cust_svc->svcnum;
-# my $sview = $p. "view";
-# print $n2,qq!<TD><A HREF="$sview/$svcdb.cgi?$svcnum"><FONT SIZE=-1>$label</FONT></A></TD>!,
-# qq!<TD><A HREF="$sview/$svcdb.cgi?$svcnum"><FONT SIZE=-1>$value</FONT></A></TD>!;
-# $n2="</TR><TR>";
-# }
-
-sub time_or_blank {
- my $column = shift;
- return sub {
- my $record = shift;
- my $value = $record->get($column); #mmm closures
- $value ? time2str('%b %d %Y', $value ) : '';
- };
-}
-
-%><%= include( 'elements/search.html',
+<% include( 'elements/search.html',
'title' => 'Package Search Results',
'name' => 'packages',
'query' => $sql_query,
'count_query' => $count_query,
- 'redirect' => $link,
+ #'redirect' => $link,
'header' => [ '#',
'Package',
+ 'Class',
'Status',
'Freq.',
'Setup',
@@ -152,18 +15,25 @@ sub time_or_blank {
'Susp.',
'Expire',
'Cancel',
- FS::UI::Web::cust_header(),
+ FS::UI::Web::cust_header(
+ $cgi->param('cust_fields')
+ ),
'Services',
],
'fields' => [
'pkgnum',
- sub { my $part_pkg = $part_pkg{shift->pkgpart};
- $part_pkg->pkg; # ' - '. $part_pkg->comment;
+ sub { #my $part_pkg = $part_pkg{shift->pkgpart};
+ #$part_pkg->pkg; # ' - '. $part_pkg->comment;
+ $_[0]->pkg; # ' - '. $_[0]->comment;
},
+ 'classname',
sub { ucfirst(shift->status); },
sub { #shift->part_pkg->freq_pretty;
- my $part_pkg = $part_pkg{shift->pkgpart};
- $part_pkg->freq_pretty;
+
+ #my $part_pkg = $part_pkg{shift->pkgpart};
+ #$part_pkg->freq_pretty;
+
+ FS::part_pkg::freq_pretty(shift);
},
#sub { time2str('%b %d %Y', shift->setup); },
@@ -202,6 +72,7 @@ sub time_or_blank {
'color' => [
'',
'',
+ '',
sub { shift->statuscolor; },
'',
'',
@@ -210,12 +81,13 @@ sub time_or_blank {
'',
'',
'',
- ( map { '' } FS::UI::Web::cust_header() ),
+ FS::UI::Web::cust_colors(),
'',
],
- 'style' => [ '', '', 'b' ],
- 'size' => [ '', '', '-1', ],
- 'align' => 'rlclrrrrrr',
+ 'style' => [ '', '', '', 'b', '', '', '', '', '', '', '',
+ FS::UI::Web::cust_styles() ],
+ 'size' => [ '', '', '', '-1', ],
+ 'align' => 'rllclrrrrrr'. FS::UI::Web::cust_aligns(). 'r',
'links' => [
$link,
$link,
@@ -227,8 +99,241 @@ sub time_or_blank {
'',
'',
'',
- ( map { $clink } FS::UI::Web::cust_header() ),
+ '',
+ ( map { $_ ne 'Cust. Status' ? $clink : '' }
+ FS::UI::Web::cust_header(
+ $cgi->param('cust_fields')
+ )
+ ),
'',
],
)
%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('List packages');
+
+# my %part_pkg = map { $_->pkgpart => $_ } qsearch('part_pkg', {});
+
+my($query) = $cgi->keywords;
+
+my @where = ();
+
+##
+# parse agent
+##
+
+if ( $cgi->param('agentnum') =~ /^(\d+)$/ and $1 ) {
+ push @where,
+ "agentnum = $1";
+}
+
+##
+# parse status
+##
+
+if ( $cgi->param('magic') eq 'active'
+ || $cgi->param('status') eq 'active' ) {
+
+ push @where, FS::cust_pkg->active_sql();
+
+} elsif ( $cgi->param('magic') eq 'inactive'
+ || $cgi->param('status') eq 'inactive' ) {
+
+ push @where, FS::cust_pkg->inactive_sql();
+
+
+} elsif ( $cgi->param('magic') eq 'suspended'
+ || $cgi->param('status') eq 'suspended' ) {
+
+ push @where, FS::cust_pkg->suspended_sql();
+
+} elsif ( $cgi->param('magic') =~ /^cancell?ed$/
+ || $cgi->param('status') =~ /^cancell?ed$/ ) {
+
+ push @where, FS::cust_pkg->cancelled_sql();
+
+} elsif ( $cgi->param('status') =~ /^(one-time charge|inactive)$/ ) {
+
+ push @where, FS::cust_pkg->inactive_sql();
+
+}
+
+###
+# parse package class
+###
+
+#false lazinessish w/graph/cust_bill_pkg.cgi
+my $classnum = 0;
+my @pkg_class = ();
+if ( exists($cgi->Vars->{'classnum'})
+ && $cgi->param('classnum') =~ /^(\d*)$/
+ )
+{
+ $classnum = $1;
+ if ( $classnum ) { #a specific class
+ push @where, "classnum = $classnum";
+
+ #@pkg_class = ( qsearchs('pkg_class', { 'classnum' => $classnum } ) );
+ #die "classnum $classnum not found!" unless $pkg_class[0];
+ #$title .= $pkg_class[0]->classname.' ';
+
+ } elsif ( $classnum eq '' ) { #the empty class
+
+ push @where, "classnum IS NULL";
+ #$title .= 'Empty class ';
+ #@pkg_class = ( '(empty class)' );
+ } elsif ( $classnum eq '0' ) {
+ #@pkg_class = qsearch('pkg_class', {} ); # { 'disabled' => '' } );
+ #push @pkg_class, '(empty class)';
+ } else {
+ die "illegal classnum";
+ }
+}
+#eslaf
+
+###
+# parse part_pkg
+###
+
+my $pkgpart = join (' OR pkgpart=',
+ grep {$_} map { /^(\d+)$/; } ($cgi->param('pkgpart')));
+push @where, '(pkgpart=' . $pkgpart . ')' if $pkgpart;
+
+###
+# parse dates
+###
+
+my $orderby = '';
+
+#false laziness w/report_cust_pkg.html
+my %disable = (
+ 'all' => {},
+ 'one-time charge' => { 'last_bill'=>1, 'bill'=>1, 'susp'=>1, 'expire'=>1, 'cancel'=>1, },
+ 'active' => { 'susp'=>1, 'cancel'=>1 },
+ 'suspended' => { 'cancel' => 1 },
+ 'cancelled' => {},
+ '' => {},
+);
+
+foreach my $field (qw( setup last_bill bill 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};
+
+ push @where,
+ "$field IS NOT NULL",
+ "$field >= $beginning",
+ "$field <= $ending";
+
+ $orderby ||= "ORDER BY $field";
+
+}
+
+$orderby ||= 'ORDER BY bill';
+
+###
+# parse magic, legacy, etc.
+###
+
+if ( $cgi->param('magic') &&
+ $cgi->param('magic') =~ /^(active|inactive|suspended|cancell?ed)$/
+) {
+
+ $orderby = 'ORDER BY pkgnum';
+
+ if ( $cgi->param('pkgpart') =~ /^(\d+)$/ ) {
+ push @where, "pkgpart = $1";
+ }
+
+} elsif ( $query eq 'pkgnum' ) {
+
+ $orderby = 'ORDER BY pkgnum';
+
+} elsif ( $query eq 'APKG_pkgnum' ) {
+
+ $orderby = 'ORDER BY pkgnum';
+
+ push @where, '0 < (
+ SELECT count(*) FROM pkg_svc
+ WHERE pkg_svc.pkgpart = cust_pkg.pkgpart
+ AND pkg_svc.quantity > ( SELECT count(*) FROM cust_svc
+ WHERE cust_svc.pkgnum = cust_pkg.pkgnum
+ AND cust_svc.svcpart = pkg_svc.svcpart
+ )
+ )';
+
+}
+
+##
+# setup queries, links, subs, etc. for the search
+##
+
+# here is the agent virtualization
+push @where, $FS::CurrentUser::CurrentUser->agentnums_sql;
+
+my $extra_sql = scalar(@where) ? ' WHERE '. join(' AND ', @where) : '';
+
+my $addl_from = 'LEFT JOIN cust_main USING ( custnum ) '.
+ 'LEFT JOIN part_pkg USING ( pkgpart ) '.
+ 'LEFT JOIN pkg_class USING ( classnum ) ';
+
+my $count_query = "SELECT COUNT(*) FROM cust_pkg $addl_from $extra_sql";
+
+my $sql_query = {
+ 'table' => 'cust_pkg',
+ 'hashref' => {},
+ 'select' => join(', ',
+ 'cust_pkg.*',
+ ( map "part_pkg.$_", qw( pkg freq ) ),
+ 'pkg_class.classname',
+ 'cust_main.custnum as cust_main_custnum',
+ FS::UI::Web::cust_sql_fields(
+ $cgi->param('cust_fields')
+ ),
+ ),
+ 'extra_sql' => "$extra_sql $orderby",
+ 'addl_from' => $addl_from,
+};
+
+my $link = sub {
+ [ "${p}view/cust_main.cgi?".shift->custnum.'#cust_pkg', 'pkgnum' ];
+};
+
+my $clink = sub {
+ my $cust_pkg = shift;
+ $cust_pkg->cust_main_custnum
+ ? [ "${p}view/cust_main.cgi?", 'custnum' ]
+ : '';
+};
+
+#if ( scalar(@cust_pkg) == 1 ) {
+# print $cgi->redirect("${p}view/cust_main.cgi?". $cust_pkg[0]->custnum.
+# "#cust_pkg". $cust_pkg[0]->pkgnum );
+
+# my @cust_svc = qsearch( 'cust_svc', { 'pkgnum' => $pkgnum } );
+# my $rowspan = scalar(@cust_svc) || 1;
+
+# my $n2 = '';
+# foreach my $cust_svc ( @cust_svc ) {
+# my($label, $value, $svcdb) = $cust_svc->label;
+# my $svcnum = $cust_svc->svcnum;
+# my $sview = $p. "view";
+# print $n2,qq!<TD><A HREF="$sview/$svcdb.cgi?$svcnum"><FONT SIZE=-1>$label</FONT></A></TD>!,
+# qq!<TD><A HREF="$sview/$svcdb.cgi?$svcnum"><FONT SIZE=-1>$value</FONT></A></TD>!;
+# $n2="</TR><TR>";
+# }
+
+sub time_or_blank {
+ my $column = shift;
+ return sub {
+ my $record = shift;
+ my $value = $record->get($column); #mmm closures
+ $value ? time2str('%b %d %Y', $value ) : '';
+ };
+}
+
+</%init>
diff --git a/httemplate/search/cust_pkg_report.cgi b/httemplate/search/cust_pkg_report.cgi
deleted file mode 100755
index 412c3f79d..000000000
--- a/httemplate/search/cust_pkg_report.cgi
+++ /dev/null
@@ -1,23 +0,0 @@
-<HTML>
- <HEAD>
- <TITLE>Packages</TITLE>
- </HEAD>
- <BODY BGCOLOR="#e8e8e8">
- <H1>Packages</H1>
- <FORM ACTION="cust_pkg.cgi" METHOD="GET">
- <INPUT TYPE="hidden" NAME="magic" VALUE="bill">
- Return packages with next bill date:<BR><BR>
- <TABLE>
- <%= include( '/elements/tr-input-beginning_ending.html' ) %>
- <%= include( '/elements/tr-select-agent.html',
- $cgi->param('agentnum'),
- )
- %>
- </TABLE>
- <BR><INPUT TYPE="submit" VALUE="Get Report">
-
- </FORM>
-
- </BODY>
-</HTML>
-
diff --git a/httemplate/search/cust_svc.html b/httemplate/search/cust_svc.html
new file mode 100644
index 000000000..6369b202e
--- /dev/null
+++ b/httemplate/search/cust_svc.html
@@ -0,0 +1,138 @@
+<% include( 'elements/search.html',
+ 'title' => 'Service search results',
+ 'name' => 'services',
+ 'query' => $sql_query,
+ 'count_query' => $count_query,
+ 'redirect' => $link,
+ 'header' => [ '#',
+ 'Service',
+ # package?
+ FS::UI::Web::cust_header(),
+ ],
+ 'fields' => [ 'svcnum',
+ sub {
+ #$_[0]->svc. ': '. $_[0]->label;
+ my($label, $value, $svcdb) = $_[0]->label;
+ "$label: $value";
+ },
+ # package?
+ \&FS::UI::Web::cust_fields,
+ ],
+ 'links' => [ $link,
+ $link,
+ # package?
+ ( map { $_ ne 'Cust. Status' ? $link_cust : '' }
+ FS::UI::Web::cust_header()
+ ),
+ ],
+ 'align' => 'rl'. FS::UI::Web::cust_aligns(),
+ 'color' => [
+ '',
+ '',
+ FS::UI::Web::cust_colors(),
+ ],
+ 'style' => [
+ '',
+ '',
+ FS::UI::Web::cust_styles(),
+ ],
+ )
+%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('List services');
+
+my $addl_from = ' LEFT JOIN part_svc USING ( svcpart ) '.
+ ' LEFT JOIN cust_pkg USING ( pkgnum ) '.
+ ' LEFT JOIN cust_main USING ( custnum ) ';
+
+my @extra_sql = ();
+my $orderby = 'ORDER BY svcnum'; #has to be ordered by something
+ #for pagination to work
+if ( length( $cgi->param('search_svc') ) ) {
+
+ my $string = $cgi->param('search_svc');
+ $string =~ s/(^\s+|\s+$)//; #trim leading & trailing whitespace
+
+ # implement fuzzy searching in subclasses too at some point?
+ # service searching maybe shouldn't be fuzzy...
+
+ push @extra_sql,
+ ' ( '. join(' OR ',
+ map { my $table = $_;
+ my $search_sql = "FS::$table"->search_sql($string);
+ " ( svcdb = '$table'
+ AND 0 < ( SELECT COUNT(*) FROM $table
+ WHERE $table.svcnum = cust_svc.svcnum
+ AND $search_sql
+ )
+ ) ";
+ }
+ FS::part_svc->svc_tables
+ ). ' ) ';
+
+} elsif ( $cgi->param('magic') =~ /^(all|unlinked)$/ ) {
+
+ $cgi->param('svcdb') =~ /^(svc_\w+)$/ or die "unknown svcdb";
+ push @extra_sql, "svcdb = '$1'";
+
+ push @extra_sql, 'pkgnum IS NULL'
+ if $cgi->param('magic') eq 'unlinked';
+
+ if ( $cgi->param('sortby') =~ /^(\w+)$/ ) {
+ my $sortby = $1;
+ $orderby = "ORDER BY $sortby";
+ }
+
+} elsif ( $cgi->param('svcpart') =~ /^(\d+)$/ ) {
+
+ push @extra_sql, "svcpart = $1";
+
+} else {
+ eidiot("No search term specified");
+}
+
+#here is the agent virtualization
+push @extra_sql, $FS::CurrentUser::CurrentUser->agentnums_sql;
+
+my $extra_sql = ' WHERE '. join(' AND ', @extra_sql );
+
+my $sql_query = {
+ 'select' => join(', ',
+ 'cust_svc.*',
+ 'part_svc.*',
+ 'cust_main.custnum',
+ FS::UI::Web::cust_sql_fields(),
+ ),
+ 'table' => 'cust_svc',
+ 'addl_from' => $addl_from,
+ 'hashref' => {},
+ 'extra_sql' => "$extra_sql $orderby",
+};
+
+my $count_query = "SELECT COUNT(*) FROM cust_svc $addl_from $extra_sql";
+
+my $link = sub {
+ my $cust_svc = shift;
+ my $url = FS::UI::Web::svc_url(
+ 'm' => $m,
+ 'action' => 'view',
+ #'part_svc' => $cust_svc->part_svc,
+ 'svcdb' => $cust_svc->svcdb, #we have it from the joined search
+ #'svc' => $cust_svc, #redundant
+ 'query' => '',
+ );
+ [ $url, 'svcnum' ];
+};
+
+my $link_cust = sub {
+ my $cust_svc = shift;
+ if ( $cust_svc->custnum ) {
+ [ "${p}view/cust_main.cgi?", 'custnum' ];
+ } else {
+ '';
+ }
+};
+
+</%init>
diff --git a/httemplate/search/cust_tax_exempt_pkg.cgi b/httemplate/search/cust_tax_exempt_pkg.cgi
new file mode 100644
index 000000000..604502d6f
--- /dev/null
+++ b/httemplate/search/cust_tax_exempt_pkg.cgi
@@ -0,0 +1,182 @@
+<% include( 'elements/search.html',
+ 'title' => 'Tax exemptions',
+ 'name' => 'tax exemptions',
+ 'query' => $query,
+ 'count_query' => $count_query,
+ 'count_addl' => [ $money_char. '%.2f total', ],
+ 'header' => [
+ '#',
+ 'Month',
+ 'Amount',
+ 'Line item',
+ 'Invoice',
+ 'Date',
+ FS::UI::Web::cust_header(),
+ ],
+ 'fields' => [
+ 'exemptpkgnum',
+ sub { $_[0]->month. '/'. $_[0]->year; },
+ sub { $money_char. $_[0]->amount; },
+
+ sub {
+ $_[0]->billpkgnum. ': '.
+ ( $_[0]->pkgnum > 0
+ ? $_[0]->get('pkg')
+ : $_[0]->get('itemdesc')
+ ).
+ ' ('.
+ ( $_[0]->setup > 0
+ ? $money_char. $_[0]->setup. ' setup'
+ : ''
+ ).
+ ( $_[0]->setup > 0 && $_[0]->recur > 0
+ ? ' / '
+ : ''
+ ).
+ ( $_[0]->recur > 0
+ ? $money_char. $_[0]->recur. ' recur'
+ : ''
+ ).
+ ')';
+ },
+
+ 'invnum',
+ sub { time2str('%b %d %Y', shift->_date ) },
+
+ \&FS::UI::Web::cust_fields,
+ ],
+ 'links' => [
+ '',
+ '',
+ '',
+
+ '',
+ $ilink,
+ $ilink,
+
+ ( map { $_ ne 'Cust. Status' ? $clink : '' }
+ FS::UI::Web::cust_header()
+ ),
+ ],
+ 'align' => 'rrrlrc'.FS::UI::Web::cust_aligns(), # 'rlrrrc',
+ 'color' => [
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ FS::UI::Web::cust_colors(),
+ ],
+ 'style' => [
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ FS::UI::Web::cust_styles(),
+ ],
+ )
+%>
+<%once>
+
+my $join_cust = "
+ JOIN cust_bill USING ( invnum )
+ LEFT JOIN cust_main USING ( custnum )
+";
+
+my $join_pkg = "
+ LEFT JOIN cust_pkg USING ( pkgnum )
+ LEFT JOIN part_pkg USING ( pkgpart )
+";
+
+my $join = "
+ JOIN cust_bill_pkg USING ( billpkgnum )
+ $join_cust
+ $join_pkg
+";
+
+</%once>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('View customer tax exemptions');
+
+my @where = ();
+
+my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi);
+if ( $beginning || $ending ) {
+ push @where, "_date >= $beginning",
+ "_date <= $ending";
+ #"payby != 'COMP';
+}
+
+if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) {
+ push @where, "agentnum = $1";
+}
+
+if ( $cgi->param('custnum') =~ /^(\d+)$/ ) {
+ push @where, "cust_main.custnum = $1";
+}
+
+if ( $cgi->param('out') ) {
+
+ push @where, "
+ 0 = (
+ SELECT COUNT(*) FROM cust_main_county AS county_out
+ WHERE ( county_out.county = cust_main.county
+ OR ( county_out.county IS NULL AND cust_main.county = '' )
+ OR ( county_out.county = '' AND cust_main.county IS NULL)
+ OR ( county_out.county IS NULL AND cust_main.county IS NULL)
+ )
+ AND ( county_out.state = cust_main.state
+ OR ( county_out.state IS NULL AND cust_main.state = '' )
+ OR ( county_out.state = '' AND cust_main.state IS NULL )
+ OR ( county_out.state IS NULL AND cust_main.state IS NULL )
+ )
+ AND county_out.country = cust_main.country
+ AND county_out.tax > 0
+ )
+ ";
+
+} elsif ( $cgi->param('country' ) ) {
+
+ my $county = dbh->quote( $cgi->param('county') );
+ my $state = dbh->quote( $cgi->param('state') );
+ my $country = dbh->quote( $cgi->param('country') );
+ push @where, "( county = $county OR $county = '' )",
+ "( state = $state OR $state = '' )",
+ " country = $country";
+ push @where, 'taxclass = '. dbh->quote( $cgi->param('taxclass') )
+ if $cgi->param('taxclass');
+
+}
+
+my $where = scalar(@where) ? 'WHERE '.join(' AND ', @where) : '';
+
+my $count_query = "SELECT COUNT(*), SUM(amount)".
+ " FROM cust_tax_exempt_pkg $join $where";
+
+my $query = {
+ 'table' => 'cust_tax_exempt_pkg',
+ 'addl_from' => $join,
+ 'hashref' => {},
+ 'select' => join(', ',
+ 'cust_tax_exempt_pkg.*',
+ 'cust_bill_pkg.*',
+ 'cust_bill.*',
+ 'part_pkg.pkg',
+ 'cust_main.custnum',
+ FS::UI::Web::cust_sql_fields(),
+ ),
+ 'extra_sql' => $where,
+};
+
+my $ilink = [ "${p}view/cust_bill.cgi?", 'invnum' ];
+my $clink = [ "${p}view/cust_main.cgi?", 'custnum' ];
+
+my $conf = new FS::Conf;
+my $money_char = $conf->config('money_char') || '$';
+
+</%init>
diff --git a/httemplate/search/elements/search.html b/httemplate/search/elements/search.html
index d19fb4acd..7d5e58a3b 100644
--- a/httemplate/search/elements/search.html
+++ b/httemplate/search/elements/search.html
@@ -1,392 +1,658 @@
-<%
-
- my(%opt) = @_;
- #warn join(' / ', map { "$_ => $opt{$_}" } keys %opt ). "\n";
-
- my %align = (
- 'l' => 'left',
- 'r' => 'right',
- 'c' => 'center',
- ' ' => '',
- '.' => '',
- );
- $opt{align} = [ map $align{$_}, split(//, $opt{align}) ],
- unless !$opt{align} || ref($opt{align});
-
- my $type = '';
- my $limit = '';
- my($maxrecords, $total, $offset, $count_arrayref);
-
- if ( $cgi->param('_type') =~ /^(csv|\w*\.xls)$/ ) {
-
- $type = $1;
+% # options example...
+% # (everything not commented required is optional)
+% #
+% # # basic options, required
+% # 'title' => 'Page title',
+% #
+% # 'name_singular' => 'item', #singular name for the records returned
+% # #OR# # (preferred, will be pluralized automatically)
+% # 'name' => 'items', #plural name for the records returned
+% # # (deprecated, will be singularlized
+% # # simplisticly)
+% #
+% # # some HTML callbacks...
+% # 'menubar' => '', #menubar arrayref
+% # 'html_init' => '', #after the header/menubar and before the pager
+% # 'html_form' => '', #after the pager, right before the results
+% # # (only shown if there are results)
+% # # (use this for any form-opening tag rather than
+% # # html_init, to avoid a nested form)
+% # 'html_foot' => '', #at the bottom
+% # 'html_posttotal' => '', #at the bottom
+% # # (these three can be strings or coderefs)
+% #
+% #
+% # #literal SQL query string or qsearch hashref, required
+% # 'query' => {
+% # 'table' => 'tablename',
+% # #everything else is optional...
+% # 'hashref' => { 'field' => 'value',
+% # 'field' => { 'op' => '<',
+% # 'value' => '54',
+% # },
+% # },
+% # 'select' => '*',
+% # 'addl_from' => '', #'LEFT JOIN othertable USING ( key )',
+% # 'extra_sql' => '', #'AND otherstuff', #'WHERE onlystuff',
+% #
+% #
+% # },
+% # # "select * from tablename";
+% #
+% # #required unless 'query' is an SQL query string (shouldn't be...)
+% # 'count_query' => 'SELECT COUNT(*) FROM tablename',
+% #
+% # 'count_addl' => [], #additional count fields listref of sprintf strings
+% # # [ $money_char.'%.2f total paid', ],
+% #
+% # #listref of column labels, <TH>
+% # #required unless 'query' is an SQL query string
+% # # (if not specified the database column names will be used)
+% # 'header' => [ '#', 'Item' ],
+% #
+% # 'disable_download' => '', # set true to hide the CSV/Excel download links
+% # 'disable_nonefound' => '', # set true to disable the "No matching Xs found"
+% # # message
+% #
+% # #listref - each item is a literal column name (or method) or coderef
+% # #if not specified all columns will be shown
+% # 'fields' => [
+% # 'column',
+% # sub { my $row = shift; $row->column; },
+% # ],
+% #
+% # #listref of column footers
+% # 'footer' => [],
+% #
+% # #listref - each item is the empty string, or a listref of ...
+% # 'links' =>
+% #
+% #
+% # 'align' => 'lrc.', #one letter for each column, left/right/center/none
+% # # can also pass a listref with full values:
+% # # [ 'left', 'right', 'center', '' ]
+% #
+% # #listrefs...
+% # #currently only HTML, maybe eventually Excel too
+% # 'color' => [],
+% # 'size' => [],
+% # 'style' => [],
+% #
+% # #redirect if there's only one item...
+% # # listref of URL base and column name (or method)
+% # # or a coderef that returns the same
+% # 'redirect' =>
+% #
+% # #set to 1 (or column position for "disabled" status col) to enable
+% # #"show disabled/hide disabled" links
+% # #(can't be used with a literal query)
+% # 'disableable' => 1,
+%
+% my $DEBUG = 0;
+%
+% my(%opt) = @_;
+% #warn join(' / ', map { "$_ => $opt{$_}" } keys %opt ). "\n";
+%
+% my %align = (
+% 'l' => 'left',
+% 'r' => 'right',
+% 'c' => 'center',
+% ' ' => '',
+% '.' => '',
+% );
+% $opt{align} = [ map $align{$_}, split(//, $opt{align}) ],
+% unless !$opt{align} || ref($opt{align});
+%
+% my $type = '';
+% my $limit = '';
+% my($confmax, $maxrecords, $total, $offset, $count_arrayref);
+%
+% if ( $cgi->param('_type') =~ /^(csv|\w*\.xls)$/ ) {
+%
+% $type = $1;
+%
+% } else { #setup some pagination things if we're in html mode
+%
+% unless (exists($opt{count_query}) && length($opt{count_query})) {
+% ( $opt{count_query} = $opt{query} ) =~
+% s/^\s*SELECT\s*(.*?)\s+FROM\s/SELECT COUNT(*) FROM /i; #silly vim:/
+% }
+%
+% if ( $opt{disableable} && ! $cgi->param('showdisabled') ) {
+% $opt{count_query} .=
+% ( ( $opt{count_query} =~ /WHERE/i ) ? ' AND ' : ' WHERE ' ).
+% "( disabled = '' OR disabled IS NULL )";
+% }
+%
+% my $conf = new FS::Conf;
+% $confmax = $conf->config('maxsearchrecordsperpage');
+% if ( $cgi->param('maxrecords') =~ /^(\d+)$/ ) {
+% $maxrecords = $1;
+% } else {
+% $maxrecords ||= $confmax;
+% }
+%
+% $limit = $maxrecords ? "LIMIT $maxrecords" : '';
+%
+% $offset = $cgi->param('offset') || 0;
+% $limit .= " OFFSET $offset" if $offset;
+%
+% my $count_sth = dbh->prepare($opt{'count_query'})
+% or die "Error preparing $opt{'count_query'}: ". dbh->errstr;
+% $count_sth->execute
+% or die "Error executing $opt{'count_query'}: ". $count_sth->errstr;
+% $count_arrayref = $count_sth->fetchrow_arrayref;
+% $total = $count_arrayref->[0];
+%
+% }
+%
+% #disableable handling
+% my $posttotal = '';
+% if ( $opt{disableable} ) {
+%
+% my $name= $opt{'name_singular'} ? PL($opt{'name_singular'}) : $opt{'name'};
+%
+% if ( $cgi->param('showdisabled') ) {
+% $cgi->param('showdisabled', 0);
+% $posttotal= '( <a href="'. $cgi->self_url. '">'.
+% "hide disabled $name</a> )";
+% $cgi->param('showdisabled', 1);
+% } else {
+% $cgi->param('showdisabled', 1);
+% $posttotal= '( <a href="'. $cgi->self_url. '">'.
+% "show disabled $name</a> )";
+% $cgi->param('showdisabled', 0);
+% }
+%
+% if ( $cgi->param('showdisabled') ) {
+%
+% my $offset = $opt{disableable};
+%
+% splice @{ $opt{header} }, $offset, 0, 'Status';
+%
+% splice @{ $opt{fields} }, $offset, 0,
+% sub { shift->disabled ? 'DISABLED' : 'Active' };
+%
+% if ( $opt{links} && scalar( @{ $opt{links} } ) ) {
+% splice @{ $opt{links} }, $offset, 0, '';
+% }
+%
+% if ( $opt{align} && scalar( @{ $opt{align} } ) ) {
+% splice @{ $opt{align} }, $offset, 0, 'center';
+% }
+%
+% unless ( $opt{color} && scalar( @{ $opt{color} } ) ) {
+% #$opt{color} = [ map { '000000'; } @{$opt{header}} ];
+% $opt{color} = [ map { ''; } @{$opt{header}} ];
+% }
+% splice @{ $opt{color} }, $offset, 0,
+% sub { shift->disabled ? 'FF0000' : '00CC00'; };
+%
+% if ( $opt{size} && scalar( @{ $opt{size} } ) ) {
+% splice @{ $opt{size} }, $offset, 0, '';
+% }
+%
+% unless ( $opt{style} && scalar( @{ $opt{style} } ) ) {
+% $opt{style} = [ map { ''; } @{$opt{header}} ];
+% }
+% splice @{ $opt{style} }, $offset, 0, 'b';
+%
+% }
+%
+% }
+%
+% # run the query
+%
+% my $header = $opt{header};
+% my $rows;
+% if ( ref($opt{query}) ) {
+%
+% if ( $opt{disableable} && ! $cgi->param('showdisabled') ) {
+% #%search = ( 'disabled' => '' );
+% $opt{'query'}->{'hashref'}->{'disabled'} = '';
+% $opt{'query'}->{'extra_sql'} =~ s/^\s*WHERE/ AND/i;
+% }
+%
+% #eval "use FS::$opt{'query'};";
+% $rows = [ qsearch(
+% $opt{'query'}->{'table'},
+% $opt{'query'}->{'hashref'} || {},
+% $opt{'query'}->{'select'},
+% $opt{'query'}->{'extra_sql'}. " $limit",
+% '',
+% (exists($opt{'query'}->{'addl_from'}) ? $opt{'query'}->{'addl_from'} : '')
+% ) ];
+%
+% } else {
+%
+% my $sth = dbh->prepare("$opt{'query'} $limit")
+% or die "Error preparing $opt{'query'}: ". dbh->errstr;
+% $sth->execute
+% or die "Error executing $opt{'query'}: ". $sth->errstr;
+%
+% #can get # of rows without fetching them all?
+% $rows = $sth->fetchall_arrayref;
+%
+% $header ||= $sth->{NAME};
+%
+% }
+%
+% warn scalar(@$rows). ' rows returned from '.
+% ( ref($opt{'query'}) ? 'qsearch query' : 'literal SQL query' )
+% if $DEBUG || $opt{'debug'};
+%
+% # display the results - csv, xls or html
+%
+% if ( $type eq 'csv' ) {
+%
+% #http_header('Content-Type' => 'text/comma-separated-values' ); #IE chokes
+% http_header('Content-Type' => 'text/plain' );
+%
+% my $csv = new Text::CSV_XS { 'always_quote' => 1,
+% 'eol' => "\n", #"\015\012", #"\012"
+% };
+%
+% $csv->combine(@$header); #or die $csv->status;
+%
+<% $csv->string %>
+%
+%
+% foreach my $row ( @$rows ) {
+%
+% if ( $opt{'fields'} ) {
+%
+% my @line = ();
+%
+% foreach my $field ( @{$opt{'fields'}} ) {
+% if ( ref($field) eq 'CODE' ) {
+% push @line, map {
+% ref($_) eq 'ARRAY'
+% ? '(N/A)' #unimplemented
+% : $_;
+% }
+% &{$field}($row);
+% } else {
+% push @line, $row->$field();
+% }
+% }
+%
+% $csv->combine(@line); #or die $csv->status;
+%
+% } else {
+% $csv->combine(@$row); #or die $csv->status;
+% }
+%
+%
+<% $csv->string %>
+%
+%
+% }
+%
+% #} elsif ( $type eq 'excel' ) {
+% } elsif ( $type =~ /\.xls$/ ) {
+%
+% #http_header('Content-Type' => 'application/excel' ); #eww
+% http_header('Content-Type' => 'application/vnd.ms-excel' );
+% #http_header('Content-Type' => 'application/msexcel' ); #alas
+%
+% my $data = '';
+% my $XLS = new IO::Scalar \$data;
+% my $workbook = Spreadsheet::WriteExcel->new($XLS)
+% or die "Error opening .xls file: $!";
+%
+% my $worksheet = $workbook->add_worksheet(substr($opt{'title'},0,31));
+%
+% my($r,$c) = (0,0);
+%
+% $worksheet->write($r, $c++, $_) foreach @$header;
+%
+% foreach my $row ( @$rows ) {
+% $r++;
+% $c = 0;
+%
+% if ( $opt{'fields'} ) {
+%
+% #my $links = $opt{'links'} ? [ @{$opt{'links'}} ] : '';
+% #my $aligns = $opt{'align'} ? [ @{$opt{'align'}} ] : '';
+%
+% foreach my $field ( @{$opt{'fields'}} ) {
+% #my $align = $aligns ? shift @$aligns : '';
+% #$align = " ALIGN=$align" if $align;
+% #my $a = '';
+% #if ( $links ) {
+% # my $link = shift @$links;
+% # $link = &{$link}($row) if ref($link) eq 'CODE';
+% # if ( $link ) {
+% # my( $url, $method ) = @{$link};
+% # if ( ref($method) eq 'CODE' ) {
+% # $a = $url. &{$method}($row);
+% # } else {
+% # $a = $url. $row->$method();
+% # }
+% # $a = qq(<A HREF="$a">);
+% # }
+% #}
+% if ( ref($field) eq 'CODE' ) {
+% foreach my $value ( &{$field}($row) ) {
+% if ( ref($value) eq 'ARRAY' ) {
+% $worksheet->write($r, $c++, '(N/A)' ); #unimplemented
+% } else {
+% $worksheet->write($r, $c++, $value );
+% }
+% }
+% } else {
+% $worksheet->write($r, $c++, $row->$field() );
+% }
+% }
+%
+% } else {
+% $worksheet->write($r, $c++, $_) foreach @$row;
+% }
+%
+% }
+%
+% $workbook->close();# or die "Error creating .xls file: $!";
+%
+% http_header('Content-Length' => length($data) );
+%
+<% $data %>
+%
+%
+% } else { # regular HTML
+%
+% if ( exists($opt{'redirect'}) && scalar(@$rows) == 1 && $total == 1 ) {
+% my $redirect = $opt{'redirect'};
+% $redirect = &{$redirect}($rows->[0]) if ref($redirect) eq 'CODE';
+% my( $url, $method ) = @$redirect;
+% redirect( $url. $rows->[0]->$method() );
+% } else {
+% if ( $opt{'name_singular'} ) {
+% $opt{'name'} = PL($opt{'name_singular'});
+% }
+% ( my $xlsname = $opt{'name'} ) =~ s/\W//g;
+% if ( $total == 1 ) {
+% if ( $opt{'name_singular'} ) {
+% $opt{'name'} = $opt{'name_singular'}
+% } else {
+% #$opt{'name'} =~ s/s$// if $total == 1;
+% $opt{'name'} =~ s/((s)e)?s$/$2/ if $total == 1;
+% }
+% }
+%
+% my @menubar = ();
+% if ( $opt{'menubar'} ) {
+% @menubar = @{ $opt{'menubar'} };
+% #} else {
+% # @menubar = ( 'Main menu' => $p );
+% }
+
+ <% include( '/elements/header.html', $opt{'title'},
+ include( '/elements/menubar.html', @menubar )
+ )
+ %>
+ <% defined($opt{'html_init'})
+ ? ( ref($opt{'html_init'})
+ ? &{$opt{'html_init'}}()
+ : $opt{'html_init'}
+ )
+ : ''
+ %>
+%
+% unless ( $total ) {
+% unless ( $opt{'disable_nonefound'} ) {
- } else { #setup some pagination things if we're in html mode
+ No matching <% $opt{'name'} %> found.<BR>
+% }
+% } else {
- unless (exists($opt{'count_query'}) && length($opt{'count_query'})) {
- ( $opt{'count_query'} = $opt{'query'} ) =~
- s/^\s*SELECT\s*(.*?)\s+FROM\s/SELECT COUNT(*) FROM /i;
- }
+ <TABLE>
+ <TR>
- my $conf = new FS::Conf;
- $maxrecords = $conf->config('maxsearchrecordsperpage');
+ <TD VALIGN="bottom">
- $limit = $maxrecords ? "LIMIT $maxrecords" : '';
+ <FORM>
- $offset = $cgi->param('offset') || 0;
- $limit .= " OFFSET $offset" if $offset;
+ <% $total %> total <% $opt{'name'} %>
- my $count_sth = dbh->prepare($opt{'count_query'})
- or die "Error preparing $opt{'count_query'}: ". dbh->errstr;
- $count_sth->execute
- or die "Error executing $opt{'count_query'}: ". $count_sth->errstr;
- $count_arrayref = $count_sth->fetchrow_arrayref;
- $total = $count_arrayref->[0];
+% if ( $confmax && $total > $confmax ) {
+% $cgi->delete('maxrecords');
+% $cgi->param('_dummy', 1);
- }
+%# ( show <SELECT NAME="maxrecords" onChange="this.form.submit();">
+ ( show <SELECT NAME="maxrecords" onChange="window.location = '<% $cgi->self_url %>;maxrecords=' + this.options[this.selectedIndex].value;">
- # run the query
+% foreach my $max ( map { $_ * $confmax } qw( 1 5 10 25 ) ) {
+ <OPTION VALUE="<% $max %>" <% ( $maxrecords == $max ) ? 'SELECTED' : '' %>><% $max %></OPTION>
+% }
+
+ </SELECT> per page )
+
+% $cgi->param('maxrecords', $maxrecords);
+% }
+
+ <% $posttotal %>
+
+ <% defined($opt{'html_posttotal'})
+ ? ( ref($opt{'html_posttotal'})
+ ? &{$opt{'html_posttotal'}}()
+ : $opt{'html_posttotal'}
+ )
+ : ''
+ %>
+ <BR>
+
+% if ( $opt{'count_addl'} ) {
+% my $n=0; foreach my $count ( @{$opt{'count_addl'}} ) {
+
+ <% sprintf( $count, $count_arrayref->[++$n] ) %><BR>
+
+% }
+% }
+ </FORM>
- my $header = $opt{'header'};
- my $rows;
- if ( ref($opt{'query'}) ) {
- #eval "use FS::$opt{'query'};";
- $rows = [ qsearch(
- $opt{'query'}->{'table'},
- $opt{'query'}->{'hashref'} || {},
- $opt{'query'}->{'select'},
- $opt{'query'}->{'extra_sql'}. " $limit",
- '',
- (exists($opt{'query'}->{'addl_from'}) ? $opt{'query'}->{'addl_from'} : '')
- ) ];
- } else {
- my $sth = dbh->prepare("$opt{'query'} $limit")
- or die "Error preparing $opt{'query'}: ". dbh->errstr;
- $sth->execute
- or die "Error executing $opt{'query'}: ". $sth->errstr;
-
- #can get # of rows without fetching them all?
- $rows = $sth->fetchall_arrayref;
-
- $header ||= $sth->{NAME};
- }
-
- if ( $type eq 'csv' ) {
-
- #http_header('Content-Type' => 'text/comma-separated-values' ); #IE chokes
- http_header('Content-Type' => 'text/plain' );
-
- my $csv = new Text::CSV_XS { 'always_quote' => 1,
- 'eol' => "\n", #"\015\012", #"\012"
- };
-
- $csv->combine(@$header); #or die $csv->status;
- %><%= $csv->string %><%
-
- foreach my $row ( @$rows ) {
-
- if ( $opt{'fields'} ) {
-
- my @line = ();
-
- foreach my $field ( @{$opt{'fields'}} ) {
- if ( ref($field) eq 'CODE' ) {
- push @line, map {
- ref($_) eq 'ARRAY'
- ? '(N/A)' #unimplemented
- : $_;
- }
- &{$field}($row);
- } else {
- push @line, $row->$field();
- }
- }
-
- $csv->combine(@line); #or die $csv->status;
-
- } else {
- $csv->combine(@$row); #or die $csv->status;
- }
-
- %><%= $csv->string %><%
-
- }
-
- #} elsif ( $type eq 'excel' ) {
- } elsif ( $type =~ /\.xls$/ ) {
-
- #http_header('Content-Type' => 'application/excel' ); #eww
- http_header('Content-Type' => 'application/vnd.ms-excel' );
- #http_header('Content-Type' => 'application/msexcel' ); #alas
-
- my $data = '';
- my $XLS = new IO::Scalar \$data;
- my $workbook = Spreadsheet::WriteExcel->new($XLS)
- or die "Error opening .xls file: $!";
-
- my $worksheet = $workbook->add_worksheet(substr($opt{'title'},0,31));
-
- my($r,$c) = (0,0);
-
- $worksheet->write($r, $c++, $_) foreach @$header;
-
- foreach my $row ( @$rows ) {
- $r++;
- $c = 0;
-
- if ( $opt{'fields'} ) {
-
- #my $links = $opt{'links'} ? [ @{$opt{'links'}} ] : '';
- #my $aligns = $opt{'align'} ? [ @{$opt{'align'}} ] : '';
-
- foreach my $field ( @{$opt{'fields'}} ) {
- #my $align = $aligns ? shift @$aligns : '';
- #$align = " ALIGN=$align" if $align;
- #my $a = '';
- #if ( $links ) {
- # my $link = shift @$links;
- # $link = &{$link}($row) if ref($link) eq 'CODE';
- # if ( $link ) {
- # my( $url, $method ) = @{$link};
- # if ( ref($method) eq 'CODE' ) {
- # $a = $url. &{$method}($row);
- # } else {
- # $a = $url. $row->$method();
- # }
- # $a = qq(<A HREF="$a">);
- # }
- #}
- if ( ref($field) eq 'CODE' ) {
- foreach my $value ( &{$field}($row) ) {
- if ( ref($value) eq 'ARRAY' ) {
- $worksheet->write($r, $c++, '(N/A)' ); #unimplemented
- } else {
- $worksheet->write($r, $c++, $value );
- }
- }
- } else {
- $worksheet->write($r, $c++, $row->$field() );
- }
- }
-
- } else {
- $worksheet->write($r, $c++, $_) foreach @$row;
- }
-
- }
-
- $workbook->close();# or die "Error creating .xls file: $!";
-
- http_header('Content-Length' => length($data) );
- %><%= $data %><%
-
- } else { # regular HTML
-
- if ( exists($opt{'redirect'}) && scalar(@$rows) == 1 && $total == 1 ) {
- my $redirect = $opt{'redirect'};
- $redirect = &{$redirect}($rows->[0]) if ref($redirect) eq 'CODE';
- my( $url, $method ) = @$redirect;
- redirect( $url. $rows->[0]->$method() );
- } else {
- ( my $xlsname = $opt{'name'} ) =~ s/\W//g;
- $opt{'name'} =~ s/s$// if $total == 1;
-
- my @menubar = ();
- if ( $opt{'menubar'} ) {
- @menubar = @{ $opt{'menubar'} };
- } else {
- @menubar = ( 'Main menu' => $p );
- }
- %>
- <%= include( '/elements/header.html', $opt{'title'},
- include( '/elements/menubar.html', @menubar )
- )
- %>
- <%= defined($opt{'html_init'}) ? $opt{'html_init'} : '' %>
- <% my $pager = include ( '/elements/pager.html',
- 'offset' => $offset,
- 'num_rows' => scalar(@$rows),
- 'total' => $total,
- 'maxrecords' => $maxrecords,
- );
- %>
- <% unless ( $total ) { %>
- No matching <%= $opt{'name'} %> found.<BR>
- <% } else { %>
-
- <TABLE>
- <TR>
- <TD VALIGN="bottom">
- <%= $total %> total <%= $opt{'name'} %><BR>
- <% if ( $opt{'count_addl'} ) { %>
- <% my $n=0; foreach my $count ( @{$opt{'count_addl'}} ) { %>
- <%= sprintf( $count, $count_arrayref->[++$n] ) %><BR>
- <% } %>
- <% } %>
- </TD>
- <TD ALIGN="right">
- <% $cgi->param('_type', "$xlsname.xls" ); %>
- Download full results<BR>
- as <A HREF="<%= $cgi->self_url %>">Excel spreadsheet</A><BR>
- <% $cgi->param('_type', 'csv'); %>
- as <A HREF="<%= $cgi->self_url %>">CSV file</A>
</TD>
+
+% unless ( $opt{'disable_download'} ) {
+
+ <TD ALIGN="right">
+% $cgi->param('_type', "$xlsname.xls" );
+
+ Download full results<BR>
+ as <A HREF="<% $cgi->self_url %>">Excel spreadsheet</A><BR>
+% $cgi->param('_type', 'csv');
+
+ as <A HREF="<% $cgi->self_url %>">CSV file</A>
+ </TD>
+% $cgi->param('_type', "html" );
+% }
+
</TR>
<TR>
<TD COLSPAN=2>
- <%= $pager %>
- <%= include('/elements/table-grid.html') %>
+ <% my $pager = include ( '/elements/pager.html',
+ 'offset' => $offset,
+ 'num_rows' => scalar(@$rows),
+ 'total' => $total,
+ 'maxrecords' => $maxrecords,
+ ) %>
+
+ <% defined($opt{'html_form'})
+ ? ( ref($opt{'html_form'})
+ ? &{$opt{'html_form'}}()
+ : $opt{'html_form'}
+ )
+ : ''
+ %>
+
+ <% include('/elements/table-grid.html') %>
<TR>
- <% foreach my $header ( @$header ) { %>
- <TH CLASS="grid" BGCOLOR="#cccccc"><%= $header %></TH>
- <% } %>
+%
+% foreach my $header ( @$header ) {
+
+ <TH CLASS="grid" BGCOLOR="#cccccc"><% $header %></TH>
+% }
+
</TR>
- <% my $bgcolor1 = '#eeeeee';
- my $bgcolor2 = '#ffffff';
- my $bgcolor;
- foreach my $row ( @$rows ) {
- if ( $bgcolor eq $bgcolor1 ) {
- $bgcolor = $bgcolor2;
- } else {
- $bgcolor = $bgcolor1;
- }
- %>
+% my $bgcolor1 = '#eeeeee';
+% my $bgcolor2 = '#ffffff';
+% my $bgcolor;
+% foreach my $row ( @$rows ) {
+% if ( $bgcolor eq $bgcolor1 ) {
+% $bgcolor = $bgcolor2;
+% } else {
+% $bgcolor = $bgcolor1;
+% }
+%
+
<TR>
- <% if ( $opt{'fields'} ) {
-
- my $links = $opt{'links'} ? [ @{$opt{'links'}} ] : '';
- my $aligns = $opt{'align'} ? [ @{$opt{'align'}} ] : '';
- my $colors = $opt{'color'} ? [ @{$opt{'color'}} ] : [];
- my $sizes = $opt{'size'} ? [ @{$opt{'size'}} ] : [];
- my $styles = $opt{'style'} ? [ @{$opt{'style'}} ] : [];
-
- foreach my $field (
-
- map {
- if ( ref($_) eq 'ARRAY' ) {
-
- my $tableref = $_;
-
- '<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0'.
- ' STYLE="border:none">'.
-
- join('', map {
-
- my $rowref = $_;
-
- '<tr>'.
-
- join('', map {
-
- my $element = $_;
-
- '<TD STYLE="border:none"'.
- ( $element->{'align'}
- ? ' ALIGN="'. $element->{'align'}. '"'
- : ''
- ). '>'.
- ( $element->{'link'}
- ? '<A HREF="'. $element->{'link'}.'">'
- : ''
- ).
- $element->{'data'}.
- ( $element->{'link'}
- ? '</A>'
- : ''
- ).
- '</td>';
-
- } @$rowref ).
-
- '</tr>';
- } @$tableref ).
-
- '</table>';
-
- } else {
- $_;
- }
- }
-
- map {
- if ( ref($_) eq 'CODE' ) {
- &{$_}($row);
- } else {
- $row->$_();
- }
- }
- @{$opt{'fields'}}
-
- ) {
-
- my $align = $aligns ? shift @$aligns : '';
- $align = " ALIGN=$align" if $align;
-
- my $a = '';
- if ( $links ) {
- my $link = shift @$links;
- $link = &{$link}($row) if ref($link) eq 'CODE';
- if ( $link ) {
- my( $url, $method ) = @{$link};
- if ( ref($method) eq 'CODE' ) {
- $a = $url. &{$method}($row);
- } else {
- $a = $url. $row->$method();
- }
- $a = qq(<A HREF="$a">);
- }
- }
-
- my $font = '';
- my $color = shift @$colors;
- $color = &{$color}($row) if ref($color) eq 'CODE';
- my $size = shift @$sizes;
- $size = &{$size}($row) if ref($size) eq 'CODE';
- if ( $color || $size ) {
- $font = '<FONT '.
- ( $color ? "COLOR=#$color " : '' ).
- ( $size ? qq(SIZE="$size" ) : '' ).
- '>';
- }
-
- my($s, $es) = ( '', '' );
- my $style = shift @$styles;
- $style = &{$style}($row) if ref($style) eq 'CODE';
- if ( $style ) {
- $s = join( '', map "<$_>", split('', $style) );
- $es = join( '', map "</$_>", split('', $style) );
- }
-
- %>
- <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>"<%= $align %>><%= $font %><%= $a %><%= $s %><%= $field %><%= $es %><%= $a ? '</A>' : '' %><%= $font ? '</FONT>' : '' %></TD>
- <% } %>
- <% } else { %>
- <% foreach ( @$row ) { %>
- <TD CLASS="grid" BGCOLOR="$bgcolor"><%= $_ %></TD>
- <% } %>
- <% } %>
+% if ( $opt{'fields'} ) {
+%
+% my $links = $opt{'links'} ? [ @{$opt{'links'}} ] : '';
+% my $aligns = $opt{'align'} ? [ @{$opt{'align'}} ] : '';
+% my $colors = $opt{'color'} ? [ @{$opt{'color'}} ] : [];
+% my $sizes = $opt{'size'} ? [ @{$opt{'size'}} ] : [];
+% my $styles = $opt{'style'} ? [ @{$opt{'style'}} ] : [];
+%
+% foreach my $field (
+%
+% map {
+% if ( ref($_) eq 'ARRAY' ) {
+%
+% my $tableref = $_;
+%
+% '<TABLE CLASS="inv" CELLSPACING=0 CELLPADDING=0>'.
+%
+% join('', map {
+%
+% my $rowref = $_;
+%
+% '<tr>'.
+%
+% join('', map {
+%
+% my $element = $_;
+%
+% '<TD'.
+% ( $element->{'align'}
+% ? ' ALIGN="'. $element->{'align'}. '"'
+% : ''
+% ). '>'.
+% ( $element->{'link'}
+% ? '<A HREF="'. $element->{'link'}.'">'
+% : ''
+% ).
+% $element->{'data'}.
+% ( $element->{'link'}
+% ? '</A>'
+% : ''
+% ).
+% '</td>';
+%
+% } @$rowref ).
+%
+% '</tr>';
+% } @$tableref ).
+%
+% '</table>';
+%
+% } else {
+% $_;
+% }
+% }
+%
+% map {
+% if ( ref($_) eq 'CODE' ) {
+% &{$_}($row);
+% } else {
+% $row->$_();
+% }
+% }
+% @{$opt{'fields'}}
+%
+% ) {
+%
+% my $class = ( $field =~ /^<TABLE/i ) ? 'inv' : 'grid';
+%
+% my $align = $aligns ? shift @$aligns : '';
+% $align = " ALIGN=$align" if $align;
+%
+% my $a = '';
+% if ( $links ) {
+% my $link = shift @$links;
+% $link = &{$link}($row) if ref($link) eq 'CODE';
+% if ( $link ) {
+% my( $url, $method ) = @{$link};
+% if ( ref($method) eq 'CODE' ) {
+% $a = $url. &{$method}($row);
+% } else {
+% $a = $url. $row->$method();
+% }
+% $a = qq(<A HREF="$a">);
+% }
+% }
+%
+% my $font = '';
+% my $color = shift @$colors;
+% $color = &{$color}($row) if ref($color) eq 'CODE';
+% my $size = shift @$sizes;
+% $size = &{$size}($row) if ref($size) eq 'CODE';
+% if ( $color || $size ) {
+% $font = '<FONT '.
+% ( $color ? "COLOR=#$color " : '' ).
+% ( $size ? qq(SIZE="$size" ) : '' ).
+% '>';
+% }
+%
+% my($s, $es) = ( '', '' );
+% my $style = shift @$styles;
+% $style = &{$style}($row) if ref($style) eq 'CODE';
+% if ( $style ) {
+% $s = join( '', map "<$_>", split('', $style) );
+% $es = join( '', map "</$_>", split('', $style) );
+% }
+%
+%
+
+ <TD CLASS="<% $class %>" BGCOLOR="<% $bgcolor %>"<% $align %>><% $font %><% $a %><% $s %><% $field %><% $es %><% $a ? '</A>' : '' %><% $font ? '</FONT>' : '' %></TD>
+% }
+% } else {
+% foreach ( @$row ) {
+
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $_ %></TD>
+% }
+% }
+
</TR>
- <% } %>
+% }
+% if ( $opt{'footer'} ) {
- <% if ( $opt{'footer'} ) { %>
<TR>
- <% foreach my $footer ( @{ $opt{'footer'} } ) { %>
- <TD CLASS="grid" BGCOLOR="#dddddd" STYLE="border-top: dashed 1px black;"><i><%= $footer %></i></TH>
- <% } %>
+% foreach my $footer ( @{ $opt{'footer'} } ) {
+
+ <TD CLASS="grid" BGCOLOR="#dddddd" STYLE="border-top: dashed 1px black;"><i><% $footer %></i></TH>
+% }
+
</TR>
- <% } %>
+% }
+
</TABLE>
- <%= $pager %>
+ <% $pager %>
</TD>
</TR>
</TABLE>
-
- <% } %>
- </BODY>
- </HTML>
- <% } %>
-<% } %>
+% }
+
+ <% defined($opt{'html_foot'})
+ ? ( ref($opt{'html_foot'})
+ ? &{$opt{'html_foot'}}()
+ : $opt{'html_foot'}
+ )
+ : ''
+ %>
+ <% include( '/elements/footer.html' ) %>
+% }
+% }
diff --git a/httemplate/search/inventory_item.html b/httemplate/search/inventory_item.html
new file mode 100644
index 000000000..1e7bdd91c
--- /dev/null
+++ b/httemplate/search/inventory_item.html
@@ -0,0 +1,125 @@
+<% include( 'elements/search.html',
+ 'title' => $title,
+
+ #less lame to use Lingua:: something to pluralize
+ 'name' => $inventory_class->classname. 's',
+
+ 'query' => {
+ 'table' => 'inventory_item',
+ 'hashref' => { 'classnum' => $classnum },
+ 'select' => join(', ',
+ 'inventory_item.*',
+ 'cust_main.custnum',
+ FS::UI::Web::cust_sql_fields(),
+ ),
+ 'extra_sql' => $extra_sql,
+ 'addl_from' => $addl_from,
+ },
+
+ 'count_query' => $count_query,
+
+ 'header' => [
+ '#',
+ $inventory_class->classname,
+ 'Service',
+ FS::UI::Web::cust_header(),
+ ],
+
+ 'fields' => [
+ 'itemnum',
+ 'item',
+ #'svcnum', #XXX proper full service customer link ala svc_acct
+ # "unallocated" ? "available" ?
+ sub {
+ #this could be way more efficient with a mixin
+ # like cust_main_Mixin that let us all all the methods
+ # on data we already have...
+ my $inventory_item = shift;
+ my $cust_svc = $inventory_item->cust_svc;
+ if ( $cust_svc ) {
+ my($label, $value) = $cust_svc->label;
+ "$label: $value";
+ } else {
+ '(available)';
+ }
+ },
+
+ \&FS::UI::Web::cust_fields,
+
+ ],
+ 'align' => 'rll'.FS::UI::Web::cust_aligns(),
+ 'links' => [
+ '',
+ '',
+ $link,
+ ( map { $_ ne 'Cust. Status' ? $link_cust : '' }
+ FS::UI::Web::cust_header()
+ ),
+ ],
+ 'color' => [
+ '',
+ '',
+ '',
+ FS::UI::Web::cust_colors(),
+ ],
+ 'style' => [
+ '',
+ '',
+ '',
+ FS::UI::Web::cust_styles(),
+ ],
+
+ )
+%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+my $classnum = $cgi->param('classnum');
+$classnum =~ /^(\d+)$/ or eidiot "illegal classnum $classnum";
+$classnum = $1;
+
+my $inventory_class = qsearchs( {
+ 'table' => 'inventory_class',
+ 'hashref' => { 'classnum' => $classnum },
+} );
+
+my $title = $inventory_class->classname. ' Inventory';
+
+#little false laziness with SQL fragments in inventory_class.pm
+my $extra_sql = '';
+if ( $cgi->param('avail') ) {
+ $extra_sql = 'AND ( svcnum IS NULL OR svcnum = 0 )';
+ $title .= ' - Available';
+} elsif ( $cgi->param('used') ) {
+ $extra_sql = 'AND svcnum IS NOT NULL AND svcnum > 0';
+ $title .= ' - In use';
+}
+
+my $count_query =
+ "SELECT COUNT(*) FROM inventory_item WHERE classnum = $classnum $extra_sql";
+
+my $link = sub {
+ my $inventory_item = shift;
+ if ( $inventory_item->svcnum ) {
+ [ "${p}view/svc_acct.cgi?", 'svcnum' ];
+ } else {
+ '';
+ }
+};
+my $link_cust = sub {
+ my $inventory_item = shift;
+ if ( $inventory_item->custnum ) {
+ [ "${p}view/cust_main.cgi?", 'custnum' ];
+ } else {
+ '';
+ }
+};
+
+my $addl_from = ' LEFT JOIN cust_svc USING ( svcnum ) '.
+ ' LEFT JOIN part_svc USING ( svcpart ) '.
+ ' LEFT JOIN cust_pkg USING ( pkgnum ) '.
+ ' LEFT JOIN cust_main USING ( custnum ) ';
+
+</%init>
diff --git a/httemplate/search/pay_batch.cgi b/httemplate/search/pay_batch.cgi
new file mode 100755
index 000000000..cb2171799
--- /dev/null
+++ b/httemplate/search/pay_batch.cgi
@@ -0,0 +1,130 @@
+<% include( 'elements/search.html',
+ 'title' => 'Payment Batches',
+ 'name_singular' => 'batch',
+ 'query' => { 'table' => 'pay_batch',
+ 'hashref' => $hashref,
+ 'extra_sql' => "$extra_sql ORDER BY batchnum DESC",
+ },
+ 'count_query' => "$count_query $extra_sql",
+ 'header' => [ 'Batch',
+ 'Type',
+ 'First Download',
+ 'Last Upload',
+ 'Item Count',
+ 'Amount',
+ 'Status',
+ ],
+ 'align' => 'rcllrrc',
+ 'fields' => [ 'batchnum',
+ sub {
+ FS::payby->shortname(shift->payby);
+ },
+ sub {
+ my $self = shift;
+ my $_date = $self->download;
+ if ( $_date ) {
+ time2str("%a %b %e %T %Y", $_date);
+ } elsif ( $self->status eq 'O' ) {
+ 'Download batch';
+ } else {
+ '';
+ }
+ },
+ sub {
+ my $self = shift;
+ my $_date = $self->upload;
+ if ( $_date ) {
+ time2str("%a %b %e %T %Y", $_date);
+ } elsif ( $self->status eq 'I' ) {
+ 'Upload results';
+ } else {
+ '';
+ }
+ },
+ sub {
+ my $st = "SELECT COUNT(*) from cust_pay_batch WHERE batchnum=" . shift->batchnum;
+ my $sth = dbh->prepare($st)
+ or die dbh->errstr. "doing $st";
+ $sth->execute
+ or die "Error executing \"$st\": ". $sth->errstr;
+ $sth->fetchrow_arrayref->[0];
+ },
+ sub {
+ my $st = "SELECT SUM(amount) from cust_pay_batch WHERE batchnum=" . shift->batchnum;
+ my $sth = dbh->prepare($st)
+ or die dbh->errstr. "doing $st";
+ $sth->execute
+ or die "Error executing \"$st\": ". $sth->errstr;
+ $sth->fetchrow_arrayref->[0];
+ },
+ sub {
+ $statusmap{shift->status};
+ },
+ ],
+ 'links' => [
+ $link,
+ '',
+ sub { shift->status eq 'O' ? $link : '' },
+ sub { shift->status eq 'I' ? $link : '' },
+ ],
+ 'size' => [
+ '',
+ '',
+ sub { shift->status eq 'O' ? "+1" : '' },
+ sub { shift->status eq 'I' ? "+1" : '' },
+ ],
+ 'style' => [
+ '',
+ '',
+ sub { shift->status eq 'O' ? "b" : '' },
+ sub { shift->status eq 'I' ? "b" : '' },
+ ],
+ )
+
+%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Financial reports')
+ || $FS::CurrentUser::CurrentUser->access_right('Process batches');
+
+my %statusmap = ('I'=>'In Transit', 'O'=>'Open', 'R'=>'Resolved');
+my $hashref = {};
+my $count_query = 'SELECT COUNT(*) FROM pay_batch';
+
+my($begin, $end) = ( '', '' );
+
+my @where;
+if ( $cgi->param('beginning')
+ && $cgi->param('beginning') =~ /^([ 0-9\-\/]{0,10})$/ ) {
+ $begin = str2time($1);
+ push @where, "download >= $begin";
+}
+if ( $cgi->param('ending')
+ && $cgi->param('ending') =~ /^([ 0-9\-\/]{0,10})$/ ) {
+ $end = str2time($1) + 86399;
+ push @where, "download < $end";
+}
+
+my @status;
+if ( $cgi->param('open') ) {
+ push @status, "O";
+}
+
+if ( $cgi->param('intransit') ) {
+ push @status, "I";
+}
+
+if ( $cgi->param('resolved') ) {
+ push @status, "R";
+}
+
+push @where,
+ scalar(@status) ? q!(status='! . join(q!' OR status='!, @status) . q!')!
+ : q!status='X'!; # kludgy, X is unused at present
+
+my $extra_sql = scalar(@where) ? 'WHERE ' . join(' AND ', @where) : '';
+
+my $link = [ "${p}search/cust_pay_batch.cgi?batchnum=", 'batchnum' ];
+
+</%init>
diff --git a/httemplate/search/pay_batch.html b/httemplate/search/pay_batch.html
new file mode 100644
index 000000000..5907169d8
--- /dev/null
+++ b/httemplate/search/pay_batch.html
@@ -0,0 +1,33 @@
+<% include('/elements/header.html', 'Batch criteria' ) %>
+
+<FORM ACTION="pay_batch.cgi" METHOD="GET">
+<INPUT TYPE="hidden" NAME="magic" VALUE="_date">
+
+<TABLE>
+ <% include( '/elements/tr-input-beginning_ending.html' ) %>
+ <TR>
+ <TD ALIGN="right"><INPUT TYPE="checkbox" NAME="open" VALUE="1" CHECKED></TD>
+ <TD>Show open batches</TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right"><INPUT TYPE="checkbox" NAME="intransit" VALUE="1" CHECKED></TD>
+ <TD>Show in-transit batches</TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right"><INPUT TYPE="checkbox" NAME="resolved" VALUE="1" CHECKED></TD>
+ <TD>Show resolved batches</TD>
+ </TR>
+</TABLE>
+
+<BR>
+<INPUT TYPE="submit" VALUE="Get Batches">
+
+</FORM>
+
+<% include('/elements/footer.html') %>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
+
+</%init>
diff --git a/httemplate/search/prepay_credit.html b/httemplate/search/prepay_credit.html
index 8c8f57b5a..ab6490d33 100644
--- a/httemplate/search/prepay_credit.html
+++ b/httemplate/search/prepay_credit.html
@@ -1,15 +1,4 @@
-<%
-my $agent = '';
-my $hashref = {};
-if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) {
- $hashref->{agentnum} = $1;
- $agent = qsearchs('agent', { 'agentnum' => $1 } );
-}
-
-my $count_query = 'SELECT COUNT(*) FROM prepay_credit';
-$count_query .= ' WHERE agentnum = '. $agent->agentnum if $agent;
-
-%><%= include( 'elements/search.html',
+<% include( 'elements/search.html',
'title' => 'Unused Prepaid Cards'.
($agent ? ' for '. $agent->agent : ''),
'menubar' => [
@@ -22,11 +11,28 @@ $count_query .= ' WHERE agentnum = '. $agent->agentnum if $agent;
},
'count_query' => $count_query,
#'redirect' => $link,
- 'header' => [ '#', qw(Amount Time Agent) ],
+ 'header' => [ '#', qw(Amount Time Upload Download Total Agent) ],
'fields' => [
'identifier',
sub { sprintf('$%.2f', shift->amount ) },
- sub { my $c = shift; $c ? duration_exact($c->seconds) : '' },
+ sub { my $c = shift;
+ $c->seconds ? duration_exact($c->seconds) : ''
+ },
+ sub { my $c = shift;
+ $c->upbytes
+ ? FS::UI::Web::bytecount_unexact($c->upbytes)
+ : ''
+ },
+ sub { my $c = shift;
+ $c->downbytes
+ ? FS::UI::Web::bytecount_unexact($c->downbytes)
+ : ''
+ },
+ sub { my $c = shift;
+ $c->totalbytes
+ ? FS::UI::Web::bytecount_unexact($c->totalbytes)
+ : ''
+ },
sub { my $agent = shift->agent;
$agent ? $agent->agent : '';
},
@@ -35,9 +41,28 @@ $count_query .= ' WHERE agentnum = '. $agent->agentnum if $agent;
'',
'',
'',
+ '',
+ '',
+ '',
sub { my $agent = shift->agent;
$agent ? [ "${p}view/agent.cgi?", 'agentnum' ] : '';
},
],
)
%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+my $agent = '';
+my $hashref = {};
+if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) {
+$hashref->{agentnum} = $1;
+$agent = qsearchs('agent', { 'agentnum' => $1 } );
+}
+
+my $count_query = 'SELECT COUNT(*) FROM prepay_credit';
+$count_query .= ' WHERE agentnum = '. $agent->agentnum if $agent;
+
+</%init>
diff --git a/httemplate/search/queue.html b/httemplate/search/queue.html
new file mode 100644
index 000000000..c343014cc
--- /dev/null
+++ b/httemplate/search/queue.html
@@ -0,0 +1,139 @@
+<% include( 'elements/search.html',
+ 'title' => 'Job Queue',
+ 'menubar' => [ 'Main menu' => $p, ],
+ 'name' => 'jobs',
+ 'html_form' => qq!<FORM NAME="jobForm" ACTION="$p/misc/queue.cgi" METHOD="POST">!,
+ 'query' => { 'table' => 'queue',
+ 'hashref' => $hashref,
+ 'extra_sql' => 'ORDER BY jobnum',
+ },
+ 'count_query' => $count_query,
+ 'header' => [ '#',
+ 'Job',
+ 'Args',
+ 'Date',
+ 'Status',
+ 'Account', # unless $hashref->{'svcnum'}
+ '', # checkbox column
+ ],
+ 'fields' => [
+ 'jobnum',
+ 'job',
+ sub {
+ my $queue = shift;
+ if ( $dangerous
+ || $queue->job !~ /^FS::part_export::/
+ || !$noactions
+ )
+ {
+ encode_entities( join(' ', $queue->args) );
+ } else {
+ '';
+ }
+ },
+ sub {
+ time2str( "%a %b %e %T %Y", shift->_date );
+ },
+ sub {
+ my $queue = shift;
+ my $jobnum = $queue->jobnum;
+ my $status = $queue->status;
+ $status .= ': '. $queue->statustext
+ if $queue->statustext;
+ my @queue_depend = $queue->queue_depend;
+ $status .= ' (waiting for '.
+ join(', ', map { $_->depend_jobnum }
+ @queue_depend
+ ).
+ ')'
+ if @queue_depend;
+ my $changable = $dangerous
+ || ( ! $noactions
+ && $status =~ /^failed/
+ || $status =~ /^locked/
+ );
+ if ( $changable ) {
+ $status .=
+ qq! (&nbsp;<A HREF="$p/misc/queue.cgi?jobnum=$jobnum&action=new">retry</A>&nbsp;|!.
+ qq!&nbsp;<A HREF="$p/misc/queue.cgi?jobnum=$jobnum&action=del">remove</A>&nbsp;)!;
+ }
+ $status;
+ },
+ sub {
+ my $queue = shift;
+ # return '' if $hashref->{'svcnum'}
+ my $cust_svc = $queue->cust_svc;
+ my $account;
+ if ( $cust_svc ) {
+ my $table = $cust_svc->part_svc->svcdb;
+ my $label = ( $cust_svc->label )[1];
+ qq!<A HREF="../view/$table.cgi?!. $queue->svcnum.
+ qq!">$label</A>!;
+ } else {
+ '';
+ }
+ },
+ sub {
+ my $queue = shift;
+ my $jobnum = $queue->jobnum;
+ my $status = $queue->status;
+ my $changable = $dangerous
+ || ( ! $noactions
+ && $status eq 'failed'
+ || $status eq 'locked'
+ );
+ if ( $changable ) {
+ $areboxes = 1;
+ qq!<INPUT NAME="jobnum$jobnum" TYPE="checkbox" VALUE="1">!;
+ } else {
+ '';
+ }
+ },
+ ],
+ #'links' => [
+ # '',
+ # '',
+ # '',
+ # '',
+ # '',
+ # '', #$acct_link,
+ # '',
+ # ],
+ 'html_foot' => sub {
+ if ( $areboxes ) {
+ '<BR><INPUT TYPE="button" VALUE="select all" onClick="setAll(true)">'.
+ '<INPUT TYPE="button" VALUE="unselect all" onClick="setAll(false)">'.
+ '<BR><INPUT TYPE="submit" NAME="action" VALUE="retry selected">'.
+ '<INPUT TYPE="submit" NAME="action" VALUE="remove selected"><BR>'.
+ '<SCRIPT TYPE="text/javascript">'.
+ ' function setAll(setTo) { '.
+ ' theForm = document.jobForm;'.
+ ' for (i=0,n=theForm.elements.length;i<n;i++)'.
+ ' if (theForm.elements[i].name.indexOf("jobnum") != -1)'.
+ ' theForm.elements[i].checked = setTo;'.
+ ' }'.
+ '</SCRIPT>';
+ } else {
+ '';
+ }
+ },
+ )
+
+%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Job queue');
+
+my $hashref = {};
+
+my $conf = new FS::Conf;
+my $dangerous = $conf->exists('queue_dangerous_controls');
+
+my $noactions = 0;
+
+my $count_query = 'SELECT COUNT(*) FROM queue'; # + $hashref
+
+my $areboxes = 0;
+
+</%init>
diff --git a/httemplate/search/reg_code.html b/httemplate/search/reg_code.html
index 52a99ff66..87e0fcdd5 100644
--- a/httemplate/search/reg_code.html
+++ b/httemplate/search/reg_code.html
@@ -1,13 +1,4 @@
-<%
-
-my $agentnum = $cgi->param('agentnum');
-$agentnum =~ /^(\d+)$/ or eidiot "illegal agentnum $agentnum";
-$agentnum = $1;
-my $agent = qsearchs('agent', { 'agentnum' => $agentnum } );
-
-my $count_query = "SELECT COUNT(*) FROM reg_code WHERE agentnum = $agentnum";
-
-%><%= include( 'elements/search.html',
+<% include( 'elements/search.html',
'title' => 'Unused Registration Codes for '.
$agent->agent,
'name' => 'registration codes',
@@ -34,3 +25,16 @@ my $count_query = "SELECT COUNT(*) FROM reg_code WHERE agentnum = $agentnum";
],
)
%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+my $agentnum = $cgi->param('agentnum');
+$agentnum =~ /^(\d+)$/ or eidiot "illegal agentnum $agentnum";
+$agentnum = $1;
+my $agent = qsearchs('agent', { 'agentnum' => $agentnum } );
+
+my $count_query = "SELECT COUNT(*) FROM reg_code WHERE agentnum = $agentnum";
+
+<%init>
diff --git a/httemplate/search/report_cdr.html b/httemplate/search/report_cdr.html
new file mode 100644
index 000000000..819ba2195
--- /dev/null
+++ b/httemplate/search/report_cdr.html
@@ -0,0 +1,17 @@
+<% include('/elements/header.html', 'Call Detail Record Search' ) %>
+
+<FORM ACTION="cdr.html" METHOD="GET">
+Status: <SELECT NAME="freesidestatus">
+ <OPTION VALUE="">(all)
+ <OPTION VALUE="NULL">unprocessed
+ <OPTION VALUE="done">processed
+</SELECT><BR>
+<INPUT TYPE="submit" VALUE="Search Call Detail Records">
+
+<% include('/elements/footer.html') %>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('List rating data');
+
+</%init>
diff --git a/httemplate/search/report_cust_bill.html b/httemplate/search/report_cust_bill.html
index a7be76689..4fa09f96c 100644
--- a/httemplate/search/report_cust_bill.html
+++ b/httemplate/search/report_cust_bill.html
@@ -1,28 +1,34 @@
- <HEAD>
- <TITLE>Invoice report criteria</TITLE>
- </HEAD>
- <BODY BGCOLOR="#e8e8e8">
- <H1>Invoice report criteria</H1>
- <FORM ACTION="cust_bill.html" METHOD="GET">
- <INPUT TYPE="hidden" NAME="magic" VALUE="_date">
- <TABLE>
- <%= include( '/elements/tr-select-agent.html',
- $cgi->param('agentnum'),
- 'label' => 'Invoices for agent: ',
- )
- %>
- <%= include( '/elements/tr-input-beginning_ending.html' ) %>
- <TR>
- <TD ALIGN="right"><INPUT TYPE="checkbox" NAME="open" VALUE="1" CHECKED></TD>
- <TD>Show only open invoices</TD>
- </TR>
- <TR>
- <TD ALIGN="right"><INPUT TYPE="checkbox" NAME="newest_percust" VALUE="1"></TD>
- <TD>Show only the single most recent invoice per-customer</TD>
- </TR>
- </TABLE>
- <BR><INPUT TYPE="submit" VALUE="Get Report">
- </FORM>
- </BODY>
-</HTML>
+<% include('/elements/header.html', 'Invoice report criteria' ) %>
+<FORM ACTION="cust_bill.html" METHOD="GET">
+<INPUT TYPE="hidden" NAME="magic" VALUE="_date">
+
+<TABLE>
+ <% include( '/elements/tr-select-agent.html',
+ $cgi->param('agentnum'),
+ 'label' => 'Invoices for agent: ',
+ )
+ %>
+ <% include( '/elements/tr-input-beginning_ending.html' ) %>
+ <TR>
+ <TD ALIGN="right"><INPUT TYPE="checkbox" NAME="open" VALUE="1" CHECKED></TD>
+ <TD>Show only open invoices</TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right"><INPUT TYPE="checkbox" NAME="newest_percust" VALUE="1"></TD>
+ <TD>Show only the single most recent invoice per-customer</TD>
+ </TR>
+</TABLE>
+
+<BR>
+<INPUT TYPE="submit" VALUE="Get Report">
+
+</FORM>
+
+<% include('/elements/footer.html') %>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('List invoices');
+
+</%init>
diff --git a/httemplate/search/report_cust_credit.html b/httemplate/search/report_cust_credit.html
index 56bbd0ac0..993209763 100644
--- a/httemplate/search/report_cust_credit.html
+++ b/httemplate/search/report_cust_credit.html
@@ -1,36 +1,53 @@
-<HTML>
- <HEAD>
- <TITLE>Credit report criteria</TITLE>
- </HEAD>
- <BODY BGCOLOR="#e8e8e8">
- <H1>Credit report criteria</H1>
- <FORM ACTION="cust_credit.html" METHOD="GET">
- <INPUT TYPE="hidden" NAME="magic" VALUE="_date">
- <TABLE>
- <TR>
- <TD ALIGN="right">Credits by employee: </TD>
-<%
- my $sth = dbh->prepare("SELECT DISTINCT otaker FROM cust_credit")
- or die dbh->errstr;
- $sth->execute or die $sth->errstr;
- my @otakers = map { $_->[0] } @{$sth->fetchall_arrayref};
-%>
- <TD><SELECT NAME="otaker">
- <OPTION VALUE="">all</OPTION>
- <% foreach my $otaker ( @otakers ) { %>
- <OPTION VALUE="<%= $otaker %>"><%= $otaker %></OPTION>
- <% } %>
- </SELECT>
- </TD>
- </TR>
- <%= include( '/elements/tr-select-agent.html',
- $cgi->param('agentnum'),
- 'label' => 'for agent: ',
- )
- %>
- <%= include( '/elements/tr-input-beginning_ending.html' ) %>
- </TABLE>
- <BR><INPUT TYPE="submit" VALUE="Get Report">
- </FORM>
- </BODY>
-</HTML>
+<% include('/elements/header.html', 'Credit report' ) %>
+
+<FORM ACTION="cust_credit.html" METHOD="GET">
+<INPUT TYPE="hidden" NAME="magic" VALUE="_date">
+
+<TABLE>
+ <TR>
+ <TD ALIGN="right">Credits by employee: </TD>
+
+ <TD>
+ <SELECT NAME="otaker">
+ <OPTION VALUE="">all</OPTION>
+% foreach my $otaker ( @otakers ) {
+ <OPTION VALUE="<% $otaker %>"><% $otaker %></OPTION>
+% }
+ </SELECT>
+ </TD>
+ </TR>
+
+ <% include( '/elements/tr-select-agent.html',
+ $cgi->param('agentnum'),
+ 'label' => 'for agent: ',
+ )
+ %>
+
+ <% include( '/elements/tr-input-beginning_ending.html' ) %>
+
+ <% include( '/elements/tr-input-lessthan_greaterthan.html',
+ 'label' => 'Amount',
+ 'field' => 'amount',
+ )
+ %>
+
+</TABLE>
+
+<BR>
+<INPUT TYPE="submit" VALUE="Get Report">
+
+</FORM>
+
+<% include('/elements/footer.html') %>
+
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
+
+my $sth = dbh->prepare("SELECT DISTINCT otaker FROM cust_credit")
+ or die dbh->errstr;
+$sth->execute or die $sth->errstr;
+my @otakers = map { $_->[0] } @{$sth->fetchall_arrayref};
+
+</%init>
diff --git a/httemplate/search/report_cust_main-zip.html b/httemplate/search/report_cust_main-zip.html
new file mode 100644
index 000000000..1cd07ef76
--- /dev/null
+++ b/httemplate/search/report_cust_main-zip.html
@@ -0,0 +1,52 @@
+<% include('/elements/header.html', 'Zip code report') %>
+
+ <FORM ACTION="cust_main-zip.html" METHOD="GET">
+
+ <TABLE>
+
+ <TR>
+ <TD ALIGN="right">Billing or service zip</TD>
+ <TD>
+ <SELECT NAME="column">
+ <OPTION VALUE="zip">Billing zip
+ <OPTION VALUE="ship_zip">Service zip
+ </SELECT>
+ </TD>
+ </TR>
+
+ <TR>
+ <TD ALIGN="right">Ignore +4 for US zip codes</TD>
+ <TD><INPUT TYPE="checkbox" NAME="ignore_plus4" VALUE="yes" CHECKED> </TD>
+ </TR>
+
+ <TR>
+ <TD ALIGN="right">Show customers with status:</TD>
+ <TD>
+ <SELECT NAME="status">
+ <OPTION VALUE="">all
+ <OPTION VALUE="prospect">prospect (no packages ever)
+ <OPTION SELECTED VALUE="uncancel">all except cancelled
+ <OPTION VALUE="active">active recurring packages
+ <OPTION VALUE="susp">suspended
+ <OPTION VALUE="cancel">cancelled
+ </SELECT>
+ </TD>
+ </TR>
+
+ <% include( '/elements/tr-select-agent.html',
+ $cgi->param('agentnum'),
+ 'label' => 'for agent: ',
+ )
+ %>
+
+ </TABLE>
+ <BR><INPUT TYPE="submit" VALUE="Get Report">
+ </FORM>
+
+<% include('/elements/footer.html') %>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('List zip codes');
+
+</%init>
diff --git a/httemplate/search/report_cust_pay.html b/httemplate/search/report_cust_pay.html
index 5d8b74e77..0327e042e 100644
--- a/httemplate/search/report_cust_pay.html
+++ b/httemplate/search/report_cust_pay.html
@@ -1,38 +1,78 @@
-<HTML>
- <HEAD>
- <TITLE>Payment report criteria</TITLE>
- </HEAD>
- <BODY BGCOLOR="#e8e8e8">
- <H1>Payment report criteria</H1>
- <FORM ACTION="cust_pay.cgi" METHOD="GET">
- <INPUT TYPE="hidden" NAME="magic" VALUE="_date">
- <TABLE>
- <TR>
- <TD ALIGN="right">Payments of type: </TD>
- <TD><SELECT NAME="payby">
- <OPTION VALUE="">all</OPTION>
- <OPTION VALUE="CARD">credit card (all)</OPTION>
- <OPTION VALUE="CARD-VisaMC">credit card (Visa/MasterCard)</OPTION>
- <OPTION VALUE="CARD-Amex">credit card (American Express)</OPTION>
- <OPTION VALUE="CARD-Discover">credit card (Discover)</OPTION>
- <OPTION VALUE="CARD-Maestro">credit card (Maestro/Switch/Solo)</OPTION>
- <OPTION VALUE="CHEK">electronic check / ACH</OPTION>
- <OPTION VALUE="BILL">check</OPTION>
- <OPTION VALUE="PREP">prepaid card</OPTION>
- <OPTION VALUE="CASH">cash</OPTION>
- <OPTION VALUE="WEST">Western Union</OPTION>
- <OPTION VALUE="MCRD">manual credit card</OPTION>
- </SELECT>
- </TD>
- </TR>
- <%= include( '/elements/tr-select-agent.html',
- $cgi->param('agentnum'),
- 'label' => 'for agent: ',
- )
- %>
- <%= include( '/elements/tr-input-beginning_ending.html' ) %>
- </TABLE>
- <BR><INPUT TYPE="submit" VALUE="Get Report">
- </FORM>
- </BODY>
-</HTML>
+<% include('/elements/header.html', 'Payment report' ) %>
+
+<FORM ACTION="cust_pay.cgi" METHOD="GET">
+<INPUT TYPE="hidden" NAME="magic" VALUE="_date">
+
+<TABLE>
+
+ <TR>
+ <TD ALIGN="right">Payments of type: </TD>
+ <TD>
+ <SELECT NAME="payby" onChange="payby_changed(this)">
+ <OPTION VALUE="">all</OPTION>
+ <OPTION VALUE="CARD">credit card (all)</OPTION>
+ <OPTION VALUE="CARD-VisaMC">credit card (Visa/MasterCard)</OPTION>
+ <OPTION VALUE="CARD-Amex">credit card (American Express)</OPTION>
+ <OPTION VALUE="CARD-Discover">credit card (Discover)</OPTION>
+ <OPTION VALUE="CARD-Maestro">credit card (Maestro/Switch/Solo)</OPTION>
+ <OPTION VALUE="CHEK">electronic check / ACH</OPTION>
+ <OPTION VALUE="BILL">check</OPTION>
+ <OPTION VALUE="PREP">prepaid card</OPTION>
+ <OPTION VALUE="CASH">cash</OPTION>
+ <OPTION VALUE="WEST">Western Union</OPTION>
+ <OPTION VALUE="MCRD">manual credit card</OPTION>
+ </SELECT>
+ </TD>
+ </TR>
+
+ <SCRIPT TYPE="text/javascript">
+
+ function payby_changed(what) {
+ if ( what.options[what.selectedIndex].value == 'BILL' ) {
+ document.getElementById('checkno_caption').style.color = '#000000';
+ what.form.payinfo.disabled = false;
+ what.form.payinfo.style.backgroundColor = '#ffffff';
+ } else {
+ document.getElementById('checkno_caption').style.color = '#bbbbbb';
+ what.form.payinfo.disabled = true;
+ what.form.payinfo.style.backgroundColor = '#dddddd';
+ }
+ }
+
+ </SCRIPT>
+
+ <TR>
+ <TD ALIGN="right"><FONT ID="checkno_caption" COLOR="#bbbbbb">Check #: </FONT></TD>
+ <TD>
+ <INPUT TYPE="text" NAME="payinfo" DISABLED STYLE="background-color: #dddddd">
+ </TD>
+ </TR>
+
+ <% include( '/elements/tr-select-agent.html',
+ $cgi->param('agentnum'),
+ 'label' => 'for agent: ',
+ )
+ %>
+
+ <% include( '/elements/tr-input-beginning_ending.html' ) %>
+
+ <% include( '/elements/tr-input-lessthan_greaterthan.html',
+ 'label' => 'Amount',
+ 'field' => 'paid',
+ )
+ %>
+
+</TABLE>
+
+<BR>
+<INPUT TYPE="submit" VALUE="Get Report">
+
+</FORM>
+
+<% include('/elements/footer.html') %>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
+
+</%init>
diff --git a/httemplate/search/report_cust_pay_batch.html b/httemplate/search/report_cust_pay_batch.html
new file mode 100644
index 000000000..f57a9557e
--- /dev/null
+++ b/httemplate/search/report_cust_pay_batch.html
@@ -0,0 +1,43 @@
+<% include('/elements/header.html', 'Batch payment report' ) %>
+
+<FORM ACTION="cust_pay_batch.cgi" METHOD="GET">
+
+<TABLE>
+
+ <TR>
+ <TD ALIGN="right">Payments of type: </TD>
+ <TD>
+ <SELECT NAME="payby">
+ <OPTION VALUE="">all</OPTION>
+ <OPTION VALUE="CARD">credit card</OPTION>
+ <OPTION VALUE="CHEK">electronic check / ACH</OPTION>
+ </SELECT>
+ </TD>
+ </TR>
+
+ <% include( '/elements/tr-select-agent.html',
+ $cgi->param('agentnum'),
+ 'label' => 'for agent: ',
+ )
+ %>
+
+ <% include( '/elements/tr-input-beginning_ending.html' ) %>
+
+ <TR>
+ <TD ALIGN="right"><INPUT TYPE="checkbox" NAME="dcln" VALUE="1" CHECKED></TD>
+ <TD>Include approved items</TD>
+ </TR>
+</TABLE>
+
+<BR>
+<INPUT TYPE="submit" VALUE="Get Report">
+
+</FORM>
+
+<% include('/elements/footer.html') %>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
+
+</%init>
diff --git a/httemplate/search/report_cust_pkg.html b/httemplate/search/report_cust_pkg.html
new file mode 100755
index 000000000..5b2efa2ca
--- /dev/null
+++ b/httemplate/search/report_cust_pkg.html
@@ -0,0 +1,144 @@
+<% include('/elements/header.html', 'Package Report' ) %>
+
+<FORM ACTION="cust_pkg.cgi" METHOD="GET">
+<INPUT TYPE="hidden" NAME="magic" VALUE="bill">
+
+ <TABLE BGCOLOR="#cccccc" CELLSPACING=0>
+
+ <TR>
+ <TH BGCOLOR="#e8e8e8" COLSPAN=2 ALIGN="left"><FONT SIZE="+1">Search options</FONT></TH>
+ </TR>
+ <% include( '/elements/tr-select-agent.html',
+ $cgi->param('agentnum'),
+ )
+ %>
+
+ <% include( '/elements/tr-select-cust_pkg-status.html', '',
+ 'onchange' => 'status_changed(this);',
+ )
+ %>
+
+ <SCRIPT TYPE="text/javascript">
+
+ function status_changed(what) {
+
+% foreach my $status ( '', FS::cust_pkg->statuses() ) {
+
+ if ( what.options[what.selectedIndex].value == '<% $status %>' ) {
+
+% foreach my $field (qw( setup last_bill bill susp expire cancel )) {
+% if ( $disable{$status}->{$field} ) {
+
+ what.form.<% $field %>_beginning_text.disabled = true;
+ what.form.<% $field %>_ending_text.disabled = true;
+ what.form.<% $field %>_beginning_text.style.backgroundColor = '#dddddd';
+ what.form.<% $field %>_ending_text.style.backgroundColor = '#dddddd';
+
+ what.form.<% $field %>_beginning_button.style.display = 'none';
+ what.form.<% $field %>_ending_button.style.display = 'none';
+ what.form.<% $field %>_beginning_disabled.style.display = '';
+ what.form.<% $field %>_ending_disabled.style.display = '';
+
+% } else {
+
+ what.form.<% $field %>_beginning_text.disabled = false;
+ what.form.<% $field %>_ending_text.disabled = false;
+ what.form.<% $field %>_beginning_text.style.backgroundColor = '#ffffff';
+ what.form.<% $field %>_ending_text.style.backgroundColor = '#ffffff';
+
+ what.form.<% $field %>_beginning_button.style.display = '';
+ what.form.<% $field %>_ending_button.style.display = '';
+ what.form.<% $field %>_beginning_disabled.style.display = 'none';
+ what.form.<% $field %>_ending_disabled.style.display = 'none';
+
+% }
+% }
+
+ }
+
+% }
+
+ }
+
+ </SCRIPT>
+
+ <% include( '/elements/tr-select-pkg_class.html', '',
+ 'pre_options' => [ '0' => 'all' ],
+ 'empty_label' => '(empty class)',
+ )
+ %>
+
+% foreach my $field (qw( setup last_bill bill susp expire cancel )) {
+
+ <TR>
+ <TD ALIGN="right" VALIGN="center"><% $label{$field} %></TD>
+ <TD>
+ <TABLE>
+ <% include( '/elements/tr-input-beginning_ending.html',
+ prefix => $field,
+ layout => 'horiz',
+ )
+ %>
+ </TABLE>
+ </TD>
+ </TR>
+
+% }
+
+ <% include( '/elements/tr-selectmultiple-part_pkg.html' ) %>
+
+ <TR>
+ <TH BGCOLOR="#e8e8e8" COLSPAN=2>&nbsp;</TH>
+ </TR>
+
+ <TR>
+ <TH BGCOLOR="#e8e8e8" COLSPAN=2 ALIGN="left"><FONT SIZE="+1">Display options</FONT></TH>
+ </TR>
+ <% include( '/elements/tr-select-cust-fields.html' ) %>
+
+ </TABLE>
+
+<BR>
+<INPUT TYPE="submit" VALUE="Get Report">
+
+</FORM>
+
+<% include('/elements/footer.html') %>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('List packages');
+
+</%init>
+<%once>
+
+my %label = (
+ 'setup' => 'Setup',
+ 'last_bill' => 'Last bill',
+ 'bill' => 'Next bill',
+ 'susp' => 'Suspended',
+ 'expire' => 'Expires',
+ 'cancel' => 'Cancelled',
+);
+
+#false laziness w/cust_pkg.cgi
+my %disable = (
+ 'all' => {},
+ 'one-time charge' => { 'last_bill'=>1, 'bill'=>1, 'susp'=>1, 'expire'=>1, 'cancel'=>1, },
+ 'active' => { 'susp'=>1, 'cancel'=>1 },
+ 'suspended' => { 'cancel' => 1 },
+ 'cancelled' => {},
+ '' => {},
+);
+
+#hmm?
+my %checkbox = (
+ 'setup' => 0,
+ 'last_bill' => 0,
+ 'bill' => 0,
+ 'susp' => 1,
+ 'expire' => 1,
+ 'cancel' => 1,
+);
+
+</%once>
diff --git a/httemplate/search/report_prepaid_income.cgi b/httemplate/search/report_prepaid_income.cgi
index 1677591a3..fd9b01ec1 100644
--- a/httemplate/search/report_prepaid_income.cgi
+++ b/httemplate/search/report_prepaid_income.cgi
@@ -1,75 +1,14 @@
-<!-- mason kludge -->
-<%
-
- #doesn't yet deal with daily/weekly packages
-
- #needs to be re-written in sql for efficiency
-
- my $time = time;
-
- my $now = $cgi->param('date') && str2time($cgi->param('date')) || $time;
- $now =~ /^(\d+)$/ or die "unparsable date?";
- $now = $1;
-
- my( $total, $total_legacy ) = ( 0, 0 );
-
- my @cust_bill_pkg =
- grep { $_->cust_pkg && $_->cust_pkg->part_pkg->freq !~ /^([01]|\d+[dw])$/ }
- qsearch( 'cust_bill_pkg', {
- 'recur' => { op=>'!=', value=>0 },
- 'edate' => { op=>'>', value=>$now },
- }, );
-
- my @cust_pkg =
- grep { $_->part_pkg->recur != 0
- && $_->part_pkg->freq !~ /^([01]|\d+[dw])$/
- }
- qsearch ( 'cust_pkg', {
- 'bill' => { op=>'>', value=>$now }
- } );
-
- foreach my $cust_bill_pkg ( @cust_bill_pkg) {
- my $period = $cust_bill_pkg->edate - $cust_bill_pkg->sdate;
-
- my $elapsed = $now - $cust_bill_pkg->sdate;
- $elapsed = 0 if $elapsed < 0;
-
- my $remaining = 1 - $elapsed/$period;
-
- my $unearned = $remaining * $cust_bill_pkg->recur;
- $total += $unearned;
-
- }
-
- foreach my $cust_pkg ( @cust_pkg ) {
- my $period = $cust_pkg->bill - $cust_pkg->last_bill;
-
- my $elapsed = $now - $cust_pkg->last_bill;
- $elapsed = 0 if $elapsed < 0;
-
- my $remaining = 1 - $elapsed/$period;
-
- my $unearned = $remaining * $cust_pkg->part_pkg->recur; #!! only works for flat/legacy
- $total_legacy += $unearned;
-
- }
-
- $total = sprintf('%.2f', $total);
- $total_legacy = sprintf('%.2f', $total_legacy);
-
-%>
-
-<%= header( 'Prepaid Income (Unearned Revenue) Report',
+<% include("/elements/header.html", 'Prepaid Income (Unearned Revenue) Report',
menubar( 'Main Menu'=>$p, ) ) %>
-<%= table() %>
+<% table() %>
<TR>
<TH>Actual Unearned Revenue</TH>
<TH>Legacy Unearned Revenue</TH>
</TR>
<TR>
- <TD ALIGN="right">$<%= $total %>
+ <TD ALIGN="right">$<% $total %>
<TD ALIGN="right">
- <%= $now == $time ? "\$$total_legacy" : '<i>N/A</i>'%>
+ <% $now == $time ? "\$$total_legacy" : '<i>N/A</i>'%>
</TD>
</TR>
@@ -84,3 +23,65 @@ revenue if you have imported longer-than monthly customer packages from
a previous billing system.
</BODY>
</HTML>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
+
+#doesn't yet deal with daily/weekly packages
+
+#needs to be re-written in sql for efficiency
+
+my $time = time;
+
+my $now = $cgi->param('date') && str2time($cgi->param('date')) || $time;
+$now =~ /^(\d+)$/ or die "unparsable date?";
+$now = $1;
+
+my( $total, $total_legacy ) = ( 0, 0 );
+
+my @cust_bill_pkg =
+ grep { $_->cust_pkg && $_->cust_pkg->part_pkg->freq !~ /^([01]|\d+[dw])$/ }
+ qsearch( 'cust_bill_pkg', {
+ 'recur' => { op=>'!=', value=>0 },
+ 'edate' => { op=>'>', value=>$now },
+ }, );
+
+my @cust_pkg =
+ grep { $_->part_pkg->recur != 0
+ && $_->part_pkg->freq !~ /^([01]|\d+[dw])$/
+ }
+ qsearch ( 'cust_pkg', {
+ 'bill' => { op=>'>', value=>$now }
+ } );
+
+foreach my $cust_bill_pkg ( @cust_bill_pkg) {
+ my $period = $cust_bill_pkg->edate - $cust_bill_pkg->sdate;
+
+ my $elapsed = $now - $cust_bill_pkg->sdate;
+ $elapsed = 0 if $elapsed < 0;
+
+ my $remaining = 1 - $elapsed/$period;
+
+ my $unearned = $remaining * $cust_bill_pkg->recur;
+ $total += $unearned;
+
+}
+
+foreach my $cust_pkg ( @cust_pkg ) {
+ my $period = $cust_pkg->bill - $cust_pkg->last_bill;
+
+ my $elapsed = $now - $cust_pkg->last_bill;
+ $elapsed = 0 if $elapsed < 0;
+
+ my $remaining = 1 - $elapsed/$period;
+
+ my $unearned = $remaining * $cust_pkg->part_pkg->recur; #!! only works for flat/legacy
+ $total_legacy += $unearned;
+
+}
+
+$total = sprintf('%.2f', $total);
+$total_legacy = sprintf('%.2f', $total_legacy);
+
+</%init>
diff --git a/httemplate/search/report_prepaid_income.html b/httemplate/search/report_prepaid_income.html
index 57c318eba..81adb64ad 100644
--- a/httemplate/search/report_prepaid_income.html
+++ b/httemplate/search/report_prepaid_income.html
@@ -1,13 +1,13 @@
-<HTML>
- <HEAD>
- <TITLE>Prepaid Income (Unearned Revenue) Report</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>
- </HEAD>
- <BODY BGCOLOR="#e8e8e8">
- <H1>Prepaid Income (Unearned Revenue) Report</H1>
+<% include('/elements/header.html', 'Prepaid Income (Unearned Revenue) Report',
+ '',
+ '',
+ '<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>
+ '
+) %>
+
<FORM ACTION="report_prepaid_income.cgi" METHOD="GET">
<TABLE>
<TR>
@@ -32,8 +32,12 @@
});
</SCRIPT>
- <INPUT TYPE="submit" VALUE="Generate report">
- </BODY>
-</HTML>
- <TABLE>
+<INPUT TYPE="submit" VALUE="Generate report">
+
+<% include('/elements/footer.html') %>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
+</%init>
diff --git a/httemplate/search/report_receivables.cgi b/httemplate/search/report_receivables.cgi
index d675346f0..6e5893870 100755
--- a/httemplate/search/report_receivables.cgi
+++ b/httemplate/search/report_receivables.cgi
@@ -1,136 +1,11 @@
-<%
-
- my $charged = <<END;
- sum( charged
- - coalesce(
- ( select sum(amount) from cust_bill_pay
- where cust_bill.invnum = cust_bill_pay.invnum )
- ,0
- )
- - coalesce(
- ( select sum(amount) from cust_credit_bill
- where cust_bill.invnum = cust_credit_bill.invnum )
- ,0
- )
-
- )
-END
-
- my $owed_cols = <<END;
- coalesce(
- ( select $charged from cust_bill
- where cust_bill._date > extract(epoch from now())-2592000
- and cust_main.custnum = cust_bill.custnum
- )
- ,0
- ) as owed_0_30,
-
- coalesce(
- ( select $charged from cust_bill
- where cust_bill._date > extract(epoch from now())-5184000
- and cust_bill._date <= extract(epoch from now())-2592000
- and cust_main.custnum = cust_bill.custnum
- )
- ,0
- ) as owed_30_60,
-
- coalesce(
- ( select $charged from cust_bill
- where cust_bill._date > extract(epoch from now())-7776000
- and cust_bill._date <= extract(epoch from now())-5184000
- and cust_main.custnum = cust_bill.custnum
- )
- ,0
- ) as owed_60_90,
-
- coalesce(
- ( select $charged from cust_bill
- where cust_bill._date <= extract(epoch from now())-7776000
- and cust_main.custnum = cust_bill.custnum
- )
- ,0
- ) as owed_90_pl,
-
- coalesce(
- ( select $charged from cust_bill
- where cust_main.custnum = cust_bill.custnum
- )
- ,0
- ) as owed_total
-END
-
- my $recurring = <<END;
- '0' != ( select freq from part_pkg
- where cust_pkg.pkgpart = part_pkg.pkgpart )
-END
-
- my $packages_cols = <<END;
-
- ( select count(*) from cust_pkg
- where cust_main.custnum = cust_pkg.custnum
- and $recurring
- and ( cancel = 0 or cancel is null )
- ) as uncancelled_pkgs,
-
- ( select count(*) from cust_pkg
- where cust_main.custnum = cust_pkg.custnum
- and $recurring
- and ( cancel = 0 or cancel is null )
- and ( susp = 0 or susp is null )
- ) as active_pkgs
-
-END
-
- my $where = <<END;
-where 0 <
- coalesce(
- ( select $charged from cust_bill
- where cust_main.custnum = cust_bill.custnum
- )
- ,0
- )
-END
-
- my $agentnum = '';
- if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) {
- $agentnum = $1;
- $where .= " AND agentnum = '$agentnum' ";
- }
-
- my $count_sql = "select count(*) from cust_main $where";
-
- my $sql_query = {
- 'table' => 'cust_main',
- 'hashref' => {},
- 'select' => "*, $owed_cols, $packages_cols",
- 'extra_sql' => "$where order by coalesce(lower(company), ''), lower(last)",
- };
-
- if ( $agentnum ) {
- $owed_cols =~
- s/cust_bill\.custnum/cust_bill.custnum AND cust_main.agentnum = '$agentnum'/g;
- }
- my $total_sql = "select $owed_cols";
- my $total_sth = dbh->prepare($total_sql) or die dbh->errstr;
- $total_sth->execute or die $total_sth->errstr;
- my $row = $total_sth->fetchrow_hashref();
-
- my $conf = new FS::Conf;
- my $money_char = $conf->config('money_char') || '$';
-
- my $align = join('', map { /#/ ? 'r' : 'l' } FS::UI::Web::cust_header() ).
- 'crrrrr';
-
- my $clink = [ "${p}view/cust_main.cgi?", 'custnum' ];
-
-%><%= include( 'elements/search.html',
+<% include( 'elements/search.html',
'title' => 'Accounts Receivable Aging Summary',
'name' => 'customers',
'query' => $sql_query,
'count_query' => $count_sql,
'header' => [
FS::UI::Web::cust_header(),
- 'Status', # (me)',
+ #'Status', # (me)',
#'Status', # (cust_main)',
'0-30',
'30-60',
@@ -145,7 +20,7 @@ END
scalar(FS::UI::Web::cust_header()-1)
)
),
- '',
+ #'',
#'',
sprintf( $money_char.'%.2f',
$row->{'owed_0_30'} ),
@@ -154,26 +29,13 @@ END
sprintf( $money_char.'%.2f',
$row->{'owed_60_90'} ),
sprintf( $money_char.'%.2f',
- $row->{'owed_90_pl'} ),
+ $row->{'owed_90_0'} ),
sprintf( '<b>'. $money_char.'%.2f'. '</b>',
- $row->{'owed_total'} ),
+ $row->{'owed_0_0'} ),
],
'fields' => [
\&FS::UI::Web::cust_fields,
- sub {
- my $row = shift;
- my $status = 'Cancelled';
- my $statuscol = 'FF0000';
- if ( $row->uncancelled_pkgs ) {
- $status = 'Suspended';
- $statuscol = 'FF9900';
- if ( $row->active_pkgs ) {
- $status = 'Active';
- $statuscol = '00CC00';
- }
- }
- $status;
- },
+ #sub { ( &{$status_statuscol}(shift) )[0] },
#sub { ucfirst(shift->status) },
sub { sprintf( $money_char.'%.2f',
shift->get('owed_0_30') ) },
@@ -182,13 +44,15 @@ END
sub { sprintf( $money_char.'%.2f',
shift->get('owed_60_90') ) },
sub { sprintf( $money_char.'%.2f',
- shift->get('owed_90_pl') ) },
+ shift->get('owed_90_0') ) },
sub { sprintf( $money_char.'%.2f',
- shift->get('owed_total') ) },
+ shift->get('owed_0_0') ) },
],
'links' => [
- ( map $clink, FS::UI::Web::cust_header() ),
- '',
+ ( map { $_ ne 'Cust. Status' ? $clink : '' }
+ FS::UI::Web::cust_header()
+ ),
+ #'',
#'',
'',
'',
@@ -197,29 +61,18 @@ END
'',
],
#'align' => 'rlccrrrrr',
- 'align' => $align,
+ 'align' => FS::UI::Web::cust_aligns(). 'rrrrr',
#'size' => [ '', '', '-1', '-1', '', '', '', '', '', ],
#'style' => [ '', '', 'b', 'b', '', '', '', '', 'b', ],
'size' => [ ( map '', FS::UI::Web::cust_header() ),
- '-1', '', '', '', '', '', ],
- 'style' => [ ( map '', FS::UI::Web::cust_header() ),
- 'b', '', '', '', '', 'b', ],
+ #'-1', '', '', '', '', '', ],
+ '', '', '', '', '', ],
+ 'style' => [ FS::UI::Web::cust_styles(),
+ #'b', '', '', '', '', 'b', ],
+ '', '', '', '', 'b', ],
'color' => [
- ( map '', FS::UI::Web::cust_header() ),
- sub {
- my $row = shift;
- my $status = 'Cancelled';
- my $statuscol = 'FF0000';
- if ( $row->uncancelled_pkgs ) {
- $status = 'Suspended';
- $statuscol = 'FF9900';
- if ( $row->active_pkgs ) {
- $status = 'Active';
- $statuscol = '00CC00';
- }
- }
- $statuscol;
- },
+ FS::UI::Web::cust_colors(),
+ #sub { ( &{$status_statuscol}(shift) )[1] },
#sub { shift->statuscolor; },
'',
'',
@@ -230,3 +83,147 @@ END
)
%>
+<%once>
+
+sub owed {
+ my($start, $end, %opt) = @_;
+
+ my @where = ();
+
+ #handle start and end ranges
+
+ #24h * 60m * 60s
+ push @where, "cust_bill._date <= extract(epoch from now())-".
+ ($start * 86400)
+ if $start;
+
+ push @where, "cust_bill._date > extract(epoch from now()) - ".
+ ($end * 86400)
+ if $end;
+
+ #handle 'cust' option
+
+ push @where, "cust_main.custnum = cust_bill.custnum"
+ if $opt{'cust'};
+
+ #handle 'agentnum' option
+ my $join = '';
+ if ( $opt{'agentnum'} ) {
+ $join = 'LEFT JOIN cust_main USING ( custnum )';
+ push @where, "agentnum = '$opt{'agentnum'}'";
+ }
+
+ my $where = scalar(@where) ? 'WHERE '.join(' AND ', @where) : '';
+
+ my $as = $opt{'noas'} ? '' : "as owed_${start}_$end";
+
+ my $charged = <<END;
+sum( charged
+ - coalesce(
+ ( select sum(amount) from cust_bill_pay
+ where cust_bill.invnum = cust_bill_pay.invnum )
+ ,0
+ )
+ - coalesce(
+ ( select sum(amount) from cust_credit_bill
+ where cust_bill.invnum = cust_credit_bill.invnum )
+ ,0
+ )
+
+ )
+END
+
+ "coalesce( ( select $charged from cust_bill $join $where ) ,0 ) $as";
+
+}
+
+</%once>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
+
+my @ranges = (
+ [ 0, 30 ],
+ [ 30, 60 ],
+ [ 60, 90 ],
+ [ 90, 0 ],
+ [ 0, 0 ],
+);
+
+my $owed_cols = join(',', map owed( @$_, 'cust'=>1 ), @ranges );
+
+my $select_count_pkgs = FS::cust_main->select_count_pkgs_sql;
+
+my $active_sql = FS::cust_pkg->active_sql;
+my $inactive_sql = FS::cust_pkg->inactive_sql;
+my $suspended_sql = FS::cust_pkg->suspended_sql;
+my $cancelled_sql = FS::cust_pkg->cancelled_sql;
+
+my $packages_cols = <<END;
+ ( $select_count_pkgs ) AS num_pkgs_sql,
+ ( $select_count_pkgs AND $active_sql ) AS active_pkgs,
+ ( $select_count_pkgs AND $inactive_sql ) AS inactive_pkgs,
+ ( $select_count_pkgs AND $suspended_sql ) AS suspended_pkgs,
+ ( $select_count_pkgs AND $cancelled_sql ) AS cancelled_pkgs
+END
+
+my $days = 0;
+if ( $cgi->param('days') =~ /^\s*(\d+)\s*$/ ) {
+ $days = $1;
+}
+
+#my $where = "where ". owed(0, 0, 'cust'=>1, 'noas'=>1). " > 0";
+my $where = "where ". owed($days, 0, 'cust'=>1, 'noas'=>1). " > 0";
+
+my $agentnum = '';
+if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) {
+ $agentnum = $1;
+ $where .= " AND agentnum = '$agentnum' ";
+}
+
+#here is the agent virtualization
+$where .= ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql;
+
+my $count_sql = "select count(*) from cust_main $where";
+
+my $sql_query = {
+ 'table' => 'cust_main',
+ 'hashref' => {},
+ 'select' => "*, $owed_cols, $packages_cols",
+ 'extra_sql' => "$where order by coalesce(lower(company), ''), lower(last)",
+};
+
+my $total_sql = "select ".
+ join(',', map owed( @$_, 'agentnum'=>$agentnum ), @ranges );
+
+my $total_sth = dbh->prepare($total_sql) or die dbh->errstr;
+$total_sth->execute or die "error executing $total_sql: ". $total_sth->errstr;
+my $row = $total_sth->fetchrow_hashref();
+
+my $conf = new FS::Conf;
+my $money_char = $conf->config('money_char') || '$';
+
+my $clink = [ "${p}view/cust_main.cgi?", 'custnum' ];
+
+my $status_statuscol = sub {
+ #conceptual false laziness with cust_main::status...
+ my $row = shift;
+
+ my $status = 'unknown';
+ if ( $row->num_pkgs_sql == 0 ) {
+ $status = 'prospect';
+ } elsif ( $row->active_pkgs > 0 ) {
+ $status = 'active';
+ } elsif ( $row->inactive_pkgs > 0 ) {
+ $status = 'inactive';
+ } elsif ( $row->suspended_pkgs > 0 ) {
+ $status = 'suspended';
+ } elsif ( $row->cancelled_pkgs > 0 ) {
+ $status = 'cancelled'
+ }
+
+ ( ucfirst($status), $FS::cust_main::statuscolor{$status} );
+};
+
+</%init>
diff --git a/httemplate/search/report_receivables.html b/httemplate/search/report_receivables.html
new file mode 100755
index 000000000..bb23f1f87
--- /dev/null
+++ b/httemplate/search/report_receivables.html
@@ -0,0 +1,26 @@
+<% include('/elements/header.html', 'Accounts Receivable Aging Summary' ) %>
+
+ <FORM ACTION="report_receivables.cgi" METHOD="GET">
+
+ <TABLE>
+
+ <% include( '/elements/tr-select-agent.html' ) %>
+
+ <TR>
+ <TD ALIGN="right">Over </TD>
+ <TD><INPUT NAME="days" TYPE="text" SIZE=4 MAXLENGTH=3> days</TD>
+ </TR>
+
+ </TABLE>
+
+ <BR><INPUT TYPE="submit" VALUE="Get Report">
+ </FORM>
+
+ </BODY>
+</HTML>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
+
+</%init>
diff --git a/httemplate/search/report_tax.cgi b/httemplate/search/report_tax.cgi
index 9062f0626..918383b67 100755
--- a/httemplate/search/report_tax.cgi
+++ b/httemplate/search/report_tax.cgi
@@ -1,4 +1,173 @@
-<%
+<% include("/elements/header.html", "$agentname Sales Tax Report - ".
+ ( $beginning
+ ? time2str('%h %o %Y ', $beginning )
+ : ''
+ ).
+ 'through '.
+ ( $ending == 4294967295
+ ? 'now'
+ : time2str('%h %o %Y', $ending )
+ ),
+ menubar( 'Main Menu'=>$p, )
+ )
+%>
+
+<% include('/elements/table-grid.html') %>
+
+ <TR>
+ <TH CLASS="grid" BGCOLOR="#cccccc" ROWSPAN=2></TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc" COLSPAN=9>Sales</TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc" ROWSPAN=2></TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc" ROWSPAN=2>Rate</TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc" ROWSPAN=2></TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc" ROWSPAN=2>Tax owed</TH>
+% unless ( $cgi->param('show_taxclasses') ) {
+
+ <TH CLASS="grid" BGCOLOR="#cccccc" ROWSPAN=2>Tax invoiced</TH>
+% }
+
+ </TR>
+ <TR>
+ <TH CLASS="grid" BGCOLOR="#cccccc">Total</TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc"></TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc">Non-taxable<BR><FONT SIZE=-1>(tax-exempt customer)</FONT></TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc"></TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc">Non-taxable<BR><FONT SIZE=-1>(tax-exempt package)</FONT></TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc"></TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc">Non-taxable<BR><FONT SIZE=-1>(monthly exemption)</FONT></TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc"></TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc">Taxable</TH>
+ </TR>
+% my $bgcolor1 = '#eeeeee';
+% my $bgcolor2 = '#ffffff';
+% my $bgcolor;
+%
+% foreach my $region ( @regions ) {
+%
+% if ( $bgcolor eq $bgcolor1 ) {
+% $bgcolor = $bgcolor2;
+% } else {
+% $bgcolor = $bgcolor1;
+% }
+%
+% my $link = '';
+% if ( $region->{'label'} ne 'Total' ) {
+% if ( $region->{'label'} eq $out ) {
+% $link = ';out=1';
+% } else {
+% $link = ';'. $region->{'url_param'};
+% }
+% }
+%
+%
+%
+%
+%
+
+
+ <TR>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $region->{'label'} %></TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>" ALIGN="right">
+ <A HREF="<% $baselink. $link %>;nottax=1"><% $money_char %><% sprintf('%.2f', $region->{'total'} ) %></A>
+ </TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><FONT SIZE="+1"><B> - </B></FONT></TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>" ALIGN="right">
+ <A HREF="<% $baselink. $link %>;nottax=1;cust_tax=Y"><% $money_char %><% sprintf('%.2f', $region->{'exempt_cust'} ) %></A>
+ </TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><FONT SIZE="+1"><B> - </B></FONT></TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>" ALIGN="right">
+ <A HREF="<% $baselink. $link %>;nottax=1;pkg_tax=Y"><% $money_char %><% sprintf('%.2f', $region->{'exempt_pkg'} ) %></A>
+ </TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><FONT SIZE="+1"><B> - </B></FONT></TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>" ALIGN="right">
+ <A HREF="<% $exemptlink. $link %>"><% $money_char %><% sprintf('%.2f', $region->{'exempt_monthly'} ) %></A>
+ </TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><FONT SIZE="+1"><B> = </B></FONT></TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>" ALIGN="right">
+ <% $money_char %><% sprintf('%.2f', $region->{'taxable'} ) %></A>
+ </TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $region->{'label'} eq 'Total' ? '' : '<FONT FACE="sans-serif" SIZE="+1"><B> X </B></FONT>' %></TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>" ALIGN="right"><% $region->{'rate'} %></TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $region->{'label'} eq 'Total' ? '' : '<FONT FACE="sans-serif" SIZE="+1"><B> = </B></FONT>' %></TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>" ALIGN="right">
+ <% $money_char %><% sprintf('%.2f', $region->{'owed'} ) %>
+ </TD>
+% unless ( $cgi->param('show_taxclasses') ) {
+
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>" ALIGN="right">
+ <A HREF="<% $baselink. $link %>;istax=1"><% $money_char %><% sprintf('%.2f', $region->{'tax'} ) %></A>
+ </TD>
+% }
+
+ </TR>
+% }
+
+
+</TABLE>
+% if ( $cgi->param('show_taxclasses') ) {
+
+
+ <BR>
+ <% include('/elements/table-grid.html') %>
+ <TR>
+ <TH CLASS="grid" BGCOLOR="#cccccc"></TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc">Tax invoiced</TH>
+ </TR>
+% #some false laziness w/above
+% $bgcolor1 = '#eeeeee';
+% $bgcolor2 = '#ffffff';
+% foreach my $region ( @base_regions ) {
+%
+% if ( $bgcolor eq $bgcolor1 ) {
+% $bgcolor = $bgcolor2;
+% } else {
+% $bgcolor = $bgcolor1;
+% }
+%
+% my $link = '';
+% #if ( $region->{'label'} ne 'Total' ) {
+% if ( $region->{'label'} eq $out ) {
+% $link = ';out=1';
+% } else {
+% $link = ';'. $region->{'url_param'};
+% }
+% #}
+%
+
+
+ <TR>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $region->{'label'} %></TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>" ALIGN="right">
+ <A HREF="<% $baselink. $link %>;istax=1"><% $money_char %><% sprintf('%.2f', $region->{'tax'} ) %></A>
+ </TD>
+ </TR>
+% }
+%
+% if ( $bgcolor eq $bgcolor1 ) {
+% $bgcolor = $bgcolor2;
+% } else {
+% $bgcolor = $bgcolor1;
+% }
+%
+
+
+ <TR>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">Total</TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>" ALIGN="right">
+ <A HREF="<% $baselink %>;istax=1"><% $money_char %><% sprintf('%.2f', $tax ) %></A>
+ </TD>
+ </TR>
+
+ </TABLE>
+% }
+
+
+</BODY>
+</HTML>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
my $conf = new FS::Conf;
my $money_char = $conf->config('money_char') || '$';
@@ -7,23 +176,50 @@ my $user = getotaker;
my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi);
-my $from_join_cust = "
- FROM cust_bill_pkg
+my $join_cust = "
JOIN cust_bill USING ( invnum )
- JOIN cust_main USING ( custnum )
+ LEFT JOIN cust_main USING ( custnum )
";
+my $from_join_cust = "
+ FROM cust_bill_pkg
+ $join_cust
+";
my $join_pkg = "
- JOIN cust_pkg USING ( pkgnum )
- JOIN part_pkg USING ( pkgpart )
-";
-my $where = "
- WHERE _date >= $beginning AND _date <= $ending
- AND ( county = ? OR ? = '' )
- AND ( state = ? OR ? = '' )
- AND country = ?
- AND payby != 'COMP'
+ LEFT JOIN cust_pkg USING ( pkgnum )
+ LEFT JOIN part_pkg USING ( pkgpart )
";
+
+my $where = "WHERE _date >= $beginning AND _date <= $ending ";
my @base_param = qw( county county state state country );
+if ( $conf->exists('tax-ship_address') ) {
+
+ $where .= "
+ AND ( ( ( ship_last IS NULL OR ship_last = '' )
+ AND ( county = ? OR ? = '' )
+ AND ( state = ? OR ? = '' )
+ AND country = ?
+ )
+ OR ( ship_last IS NOT NULL AND ship_last != ''
+ AND ( ship_county = ? OR ? = '' )
+ AND ( ship_state = ? OR ? = '' )
+ AND ship_country = ?
+ )
+ )
+ ";
+ # AND payby != 'COMP'
+
+ push @base_param, @base_param;
+
+} else {
+
+ $where .= "
+ AND ( county = ? OR ? = '' )
+ AND ( state = ? OR ? = '' )
+ AND country = ?
+ ";
+ # AND payby != 'COMP'
+
+}
my $agentname = '';
if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) {
@@ -35,19 +231,64 @@ if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) {
my $gotcust = "
WHERE 0 < ( SELECT COUNT(*) FROM cust_main
- WHERE ( cust_main.county = cust_main_county.county
- OR cust_main_county.county = ''
- OR cust_main_county.county IS NULL )
- AND ( cust_main.state = cust_main_county.state
- OR cust_main_county.state = ''
- OR cust_main_county.state IS NULL )
- AND ( cust_main.country = cust_main_county.country )
- LIMIT 1
- )
";
+if ( $conf->exists('tax-ship_address') ) {
+
+ $gotcust .= "
+ WHERE
+
+ ( cust_main_county.country = cust_main.country
+ OR cust_main_county.country = cust_main.ship_country
+ )
+
+ AND
+
+ (
+
+ ( ( ship_last IS NULL OR ship_last = '' )
+ AND ( cust_main_county.country = cust_main.country )
+ AND ( cust_main_county.state = cust_main.state
+ OR cust_main_county.state = ''
+ OR cust_main_county.state IS NULL )
+ AND ( cust_main_county.county = cust_main.county
+ OR cust_main_county.county = ''
+ OR cust_main_county.county IS NULL )
+ )
+
+ OR
+
+ ( ship_last IS NOT NULL AND ship_last != ''
+ AND ( cust_main_county.country = cust_main.ship_country )
+ AND ( cust_main_county.state = cust_main.ship_state
+ OR cust_main_county.state = ''
+ OR cust_main_county.state IS NULL )
+ AND ( cust_main_county.county = cust_main.ship_county
+ OR cust_main_county.county = ''
+ OR cust_main_county.county IS NULL )
+ )
+
+ )
+
+ LIMIT 1
+ )
+ ";
+
+} else {
+
+ $gotcust .= "
+ WHERE ( cust_main.county = cust_main_county.county
+ OR cust_main_county.county = ''
+ OR cust_main_county.county IS NULL )
+ AND ( cust_main.state = cust_main_county.state
+ OR cust_main_county.state = ''
+ OR cust_main_county.state IS NULL )
+ AND ( cust_main.country = cust_main_county.country )
+ LIMIT 1
+ )
+ ";
+
+}
-my $monthly_exempt_warning = 0;
-my $taxclass_flag = 0;
my($total, $tot_taxable, $owed, $tax) = ( 0, 0, 0, 0, 0 );
my( $exempt_cust, $exempt_pkg, $exempt_monthly ) = ( 0, 0 );
my $out = 'Out of taxable region(s)';
@@ -59,17 +300,18 @@ foreach my $r (qsearch('cust_main_county', {}, '', $gotcust) ) {
$regions{$label}->{'label'} = $label;
$regions{$label}->{'url_param'} = join(';', map "$_=".$r->$_(), qw( county state country ) );
- my $fromwhere = $from_join_cust. $join_pkg. $where;
my @param = @base_param;
+ my $mywhere = $where;
if ( $r->taxclass ) {
- $fromwhere .= " AND taxclass = ? ";
+ $mywhere .= " AND taxclass = ? ";
push @param, 'taxclass';
$regions{$label}->{'url_param'} .= ';taxclass='. $r->taxclass
if $cgi->param('show_taxclasses');
- $taxclass_flag = 1;
}
+ my $fromwhere = $from_join_cust. $join_pkg. $mywhere. " AND payby != 'COMP' ";
+
# my $label = getlabel($r);
# $regions{$label}->{'label'} = $label;
@@ -83,57 +325,80 @@ foreach my $r (qsearch('cust_main_county', {}, '', $gotcust) ) {
$total += $t;
$regions{$label}->{'total'} += $t;
- ## calculate package-exemption for this region
-
- foreach my $e ( grep { $r->get($_.'tax') =~ /^Y/i }
- qw( cust_bill_pkg.setup cust_bill_pkg.recur ) ) {
- my $x = scalar_sql($r, \@param,
- "SELECT SUM($e) $fromwhere AND $nottax"
- );
- $exempt_pkg += $x;
- $regions{$label}->{'exempt_pkg'} += $x;
- }
-
## calculate customer-exemption for this region
- my($taxable, $x_cust) = (0, 0);
- foreach my $e ( grep { $r->get($_.'tax') !~ /^Y/i }
- qw( cust_bill_pkg.setup cust_bill_pkg.recur ) ) {
- $taxable += scalar_sql($r, \@param,
- "SELECT SUM($e) $fromwhere AND $nottax AND ( tax != 'Y' OR tax IS NULL )"
- );
-
- $x_cust += scalar_sql($r, \@param,
- "SELECT SUM($e) $fromwhere AND $nottax AND tax = 'Y'"
- );
- }
+## my $taxable = $t;
+
+# my($taxable, $x_cust) = (0, 0);
+# foreach my $e ( grep { $r->get($_.'tax') !~ /^Y/i }
+# qw( cust_bill_pkg.setup cust_bill_pkg.recur ) ) {
+# $taxable += scalar_sql($r, \@param,
+# "SELECT SUM($e) $fromwhere AND $nottax AND ( tax != 'Y' OR tax IS NULL )"
+# );
+#
+# $x_cust += scalar_sql($r, \@param,
+# "SELECT SUM($e) $fromwhere AND $nottax AND tax = 'Y'"
+# );
+# }
+
+ my $x_cust = scalar_sql($r, \@param,
+ "SELECT SUM(cust_bill_pkg.setup+cust_bill_pkg.recur)
+ $fromwhere AND $nottax AND tax = 'Y' "
+ );
$exempt_cust += $x_cust;
$regions{$label}->{'exempt_cust'} += $x_cust;
+
+ ## calculate package-exemption for this region
- ## calculate monthly exemption (texas tax) for this region
+ my $x_pkg = scalar_sql($r, \@param,
+ "SELECT SUM(
+ ( CASE WHEN part_pkg.setuptax = 'Y'
+ THEN cust_bill_pkg.setup
+ ELSE 0
+ END
+ )
+ +
+ ( CASE WHEN part_pkg.recurtax = 'Y'
+ THEN cust_bill_pkg.recur
+ ELSE 0
+ END
+ )
+ )
+ $fromwhere
+ AND $nottax
+ AND (
+ ( part_pkg.setuptax = 'Y' AND cust_bill_pkg.setup > 0 )
+ OR ( part_pkg.recurtax = 'Y' AND cust_bill_pkg.recur > 0 )
+ )
+ AND ( tax != 'Y' OR tax IS NULL )
+ "
+ );
+ $exempt_pkg += $x_pkg;
+ $regions{$label}->{'exempt_pkg'} += $x_pkg;
- my($sday,$smon,$syear) = (localtime($beginning) )[ 3, 4, 5 ];
- $monthly_exempt_warning=1 if $sday != 1 && $beginning;
- $smon++; $syear+=1900;
+ ## calculate monthly exemption (texas tax) for this region
- my $eending = ( $ending == 4294967295 ) ? time : $ending;
- my($eday,$emon,$eyear) = (localtime($eending) )[ 3, 4, 5 ];
- $emon++; $eyear+=1900;
+ # count up all the cust_tax_exempt_pkg records associated with
+ # the actual line items.
- my $x_monthly = scalar_sql($r, [ 'taxnum' ],
- "SELECT SUM(amount) FROM cust_tax_exempt where taxnum = ? ".
- " AND ( year > $syear OR ( year = $syear and month >= $smon ) )".
- " AND ( year < $eyear OR ( year = $eyear and month <= $emon ) )"
+ my $x_monthly = scalar_sql($r, \@param,
+ "SELECT SUM(amount)
+ FROM cust_tax_exempt_pkg
+ JOIN cust_bill_pkg USING ( billpkgnum )
+ $join_cust $join_pkg
+ $mywhere"
);
- if ( $x_monthly ) {
- warn $r->taxnum(). ": $x_monthly\n";
- $taxable -= $x_monthly;
- }
+# if ( $x_monthly ) {
+# #warn $r->taxnum(). ": $x_monthly\n";
+# $taxable -= $x_monthly;
+# }
$exempt_monthly += $x_monthly;
$regions{$label}->{'exempt_monthly'} += $x_monthly;
+ my $taxable = $t - $x_cust - $x_pkg - $x_monthly;
+
$tot_taxable += $taxable;
$regions{$label}->{'taxable'} += $taxable;
@@ -149,7 +414,7 @@ foreach my $r (qsearch('cust_main_county', {}, '', $gotcust) ) {
}
-my $taxwhere = "$from_join_cust $where";
+my $taxwhere = "$from_join_cust $where AND payby != 'COMP' ";
my @taxparam = @base_param;
my %base_regions = ();
#foreach my $label ( keys %regions ) {
@@ -165,8 +430,8 @@ foreach my $r (
my $label = getlabel($r);
- my $fromwhere = $join_pkg. $where;
- my @param = @base_param;
+ #my $fromwhere = $join_pkg. $where. " AND payby != 'COMP' ";
+ #my @param = @base_param;
#match itemdesc if necessary!
my $named_tax =
@@ -246,7 +511,7 @@ sub getlabel {
$label = "$label (". $r->taxclass. ")"
if $r->taxclass
&& $cgi->param('show_taxclasses')
- && ! $opt{'no_taxclasses'};
+ && ! $opt{'no_taxclass'};
#$label = $r->taxname. " ($label)" if $r->taxname;
}
return $label;
@@ -263,170 +528,12 @@ sub scalar_sql {
$sth->fetchrow_arrayref->[0] || 0;
}
-%>
-
-<%
-
-my $baselink = $p. "search/cust_bill_pkg.cgi?begin=$beginning;end=$ending";
-
-%>
-
-
-<%= header( "$agentname Sales Tax Report - ".
- time2str('%h %o %Y through ', $beginning ).
- ( $ending == 4294967295
- ? 'now'
- : time2str('%h %o %Y', $ending )
- ),
- menubar( 'Main Menu'=>$p, )
- )
-%>
-
-<%= include('/elements/table-grid.html') %>
- <TR>
- <TH CLASS="grid" BGCOLOR="#cccccc" ROWSPAN=2></TH>
- <TH CLASS="grid" BGCOLOR="#cccccc" COLSPAN=9>Sales</TH>
- <TH CLASS="grid" BGCOLOR="#cccccc" ROWSPAN=2></TH>
- <TH CLASS="grid" BGCOLOR="#cccccc" ROWSPAN=2>Rate</TH>
- <TH CLASS="grid" BGCOLOR="#cccccc" ROWSPAN=2></TH>
- <TH CLASS="grid" BGCOLOR="#cccccc" ROWSPAN=2>Tax owed</TH>
- <% unless ( $cgi->param('show_taxclasses') ) { %>
- <TH CLASS="grid" BGCOLOR="#cccccc" ROWSPAN=2>Tax invoiced</TH>
- <% } %>
- </TR>
- <TR>
- <TH CLASS="grid" BGCOLOR="#cccccc">Total</TH>
- <TH CLASS="grid" BGCOLOR="#cccccc"></TH>
- <TH CLASS="grid" BGCOLOR="#cccccc">Non-taxable<BR><FONT SIZE=-1>(tax-exempt customer)</FONT></TH>
- <TH CLASS="grid" BGCOLOR="#cccccc"></TH>
- <TH CLASS="grid" BGCOLOR="#cccccc">Non-taxable<BR><FONT SIZE=-1>(tax-exempt package)</FONT></TH>
- <TH CLASS="grid" BGCOLOR="#cccccc"></TH>
- <TH CLASS="grid" BGCOLOR="#cccccc">Non-taxable<BR><FONT SIZE=-1>(monthly exemption)</FONT></TH>
- <TH CLASS="grid" BGCOLOR="#cccccc"></TH>
- <TH CLASS="grid" BGCOLOR="#cccccc">Taxable</TH>
- </TR>
-
-<% my $bgcolor1 = '#eeeeee';
- my $bgcolor2 = '#ffffff';
- my $bgcolor;
-%>
-
- <% foreach my $region ( @regions ) {
-
- if ( $bgcolor eq $bgcolor1 ) {
- $bgcolor = $bgcolor2;
- } else {
- $bgcolor = $bgcolor1;
- }
-
- my $link = $baselink;
- if ( $region->{'label'} ne 'Total' ) {
- if ( $region->{'label'} eq $out ) {
- $link .= ';out=1';
- } else {
- $link .= ';'. $region->{'url_param'};
- }
- }
- %>
-
- <TR>
- <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>"><%= $region->{'label'} %></TD>
- <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>" ALIGN="right">
- <A HREF="<%= $link %>;nottax=1"><%= $money_char %><%= sprintf('%.2f', $region->{'total'} ) %></A>
- </TD>
- <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>"><FONT SIZE="+1"><B> - </B></FONT></TD>
- <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>" ALIGN="right">
- <A HREF="<%= $link %>;nottax=1;cust_tax=Y"><%= $money_char %><%= sprintf('%.2f', $region->{'exempt_cust'} ) %></A>
- </TD>
- <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>"><FONT SIZE="+1"><B> - </B></FONT></TD>
- <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>" ALIGN="right">
- <A HREF="<%= $link %>;nottax=1;pkg_tax=Y"><%= $money_char %><%= sprintf('%.2f', $region->{'exempt_pkg'} ) %></A>
- </TD>
- <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>"><FONT SIZE="+1"><B> - </B></FONT></TD>
- <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>" ALIGN="right">
- <%= $money_char %><%= sprintf('%.2f', $region->{'exempt_monthly'} ) %></A>
- </TD>
- <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>"><FONT SIZE="+1"><B> = </B></FONT></TD>
- <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>" ALIGN="right">
- <%= $money_char %><%= sprintf('%.2f', $region->{'taxable'} ) %></A>
- </TD>
- <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>"><%= $region->{'label'} eq 'Total' ? '' : '<FONT FACE="sans-serif" SIZE="+1"><B> X </B></FONT>' %></TD>
- <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>" ALIGN="right"><%= $region->{'rate'} %></TD>
- <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>"><%= $region->{'label'} eq 'Total' ? '' : '<FONT FACE="sans-serif" SIZE="+1"><B> = </B></FONT>' %></TD>
- <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>" ALIGN="right">
- <%= $money_char %><%= sprintf('%.2f', $region->{'owed'} ) %>
- </TD>
- <% unless ( $cgi->param('show_taxclasses') ) { %>
- <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>" ALIGN="right">
- <A HREF="<%= $link %>;istax=1"><%= $money_char %><%= sprintf('%.2f', $region->{'tax'} ) %></A>
- </TD>
- <% } %>
- </TR>
-
- <% } %>
-
-</TABLE>
-
-
-<% if ( $cgi->param('show_taxclasses') ) { %>
-
- <BR>
- <%= include('/elements/table-grid.html') %>
- <TR>
- <TH CLASS="grid" BGCOLOR="#cccccc"></TH>
- <TH CLASS="grid" BGCOLOR="#cccccc">Tax invoiced</TH>
- </TR>
-
- <% #some false laziness w/above
- foreach my $region ( @base_regions ) {
-
- if ( $bgcolor eq $bgcolor1 ) {
- $bgcolor = $bgcolor2;
- } else {
- $bgcolor = $bgcolor1;
- }
-
- my $link = $baselink;
- #if ( $region->{'label'} ne 'Total' ) {
- if ( $region->{'label'} eq $out ) {
- $link .= ';out=1';
- } else {
- $link .= ';'. $region->{'url_param'};
- }
- #}
- %>
-
- <TR>
- <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>"><%= $region->{'label'} %></TD>
- <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>" ALIGN="right">
- <A HREF="<%= $link %>;istax=1"><%= $money_char %><%= sprintf('%.2f', $region->{'tax'} ) %></A>
- </TD>
- </TR>
-
- <% } %>
-
- <TR>
- <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>">Total</TD>
- <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>" ALIGN="right">
- <A HREF="<%= $baselink %>;istax=1"><%= $money_char %><%= sprintf('%.2f', $tax ) %></A>
- </TD>
- </TR>
-
- </TABLE>
-
-<% } %>
-
-
-<% if ( $monthly_exempt_warning ) { %>
- <BR>
- Partial-month tax reports (except for current month) may not be correct due
- to month-granularity tax exemption (usually "texas tax"). For an accurate
- report, start on the first of a month and end on the last day of a month (or
- leave blank for to now).
-<% } %>
-
-</BODY>
-</HTML>
+my $dateagentlink = "begin=$beginning;end=$ending";
+$dateagentlink .= ';agentnum='. $cgi->param('agentnum')
+ if length($agentname);
+my $baselink = $p. "search/cust_bill_pkg.cgi?$dateagentlink";
+my $exemptlink = $p. "search/cust_tax_exempt_pkg.cgi?$dateagentlink";
+</%init>
diff --git a/httemplate/search/report_tax.html b/httemplate/search/report_tax.html
index eeaccc1ab..35b290c19 100755
--- a/httemplate/search/report_tax.html
+++ b/httemplate/search/report_tax.html
@@ -1,22 +1,42 @@
-<HTML>
- <HEAD>
- <TITLE>Tax Report Criteria</TITLE>
- </HEAD>
- <BODY BGCOLOR="#e8e8e8">
- <H1>Tax Report Criteria</H1>
- <FORM ACTION="report_tax.cgi" METHOD="GET">
- <TABLE>
- <%= include( '/elements/tr-select-agent.html' ) %>
- <%= include( '/elements/tr-input-beginning_ending.html' ) %>
- <TR>
- <TD ALIGN="right"><INPUT TYPE="checkbox" NAME="show_taxclasses" VALUE="1"></TD>
- <TD>Show tax classes</TD>
- </TR>
- </TABLE>
-
- <BR><INPUT TYPE="submit" VALUE="Get Report">
-
- </FORM>
- </BODY>
-</HTML>
+<% include('/elements/header.html', 'Tax Report' ) %>
+<FORM ACTION="report_tax.cgi" METHOD="GET">
+
+<TABLE>
+
+ <% include( '/elements/tr-select-agent.html' ) %>
+
+ <% include( '/elements/tr-input-beginning_ending.html' ) %>
+% my $conf = new FS::Conf;
+% if ( $conf->exists('enable_taxclasses') ) {
+%
+
+ <TR>
+ <TD ALIGN="right"><INPUT TYPE="checkbox" NAME="show_taxclasses" VALUE="1"></TD>
+ <TD>Show tax classes</TD>
+ </TR>
+% }
+% my @pkg_class = qsearch('pkg_class', {});
+% if ( @pkg_class ) {
+%
+
+ <TR>
+ <TD ALIGN="right"><INPUT TYPE="checkbox" NAME="show_pkgclasses" VALUE="1"></TD>
+ <TD>Show package classes</TD>
+ </TR>
+% }
+
+
+</TABLE>
+
+<BR><INPUT TYPE="submit" VALUE="Get Report">
+
+</FORM>
+
+<% include('/elements/footer.html') %>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
+
+</%init>
diff --git a/httemplate/search/sql.html b/httemplate/search/sql.html
index b28c045d1..5f64ebc28 100644
--- a/httemplate/search/sql.html
+++ b/httemplate/search/sql.html
@@ -1,7 +1,13 @@
-<%= include( 'elements/search.html',
+<% include( 'elements/search.html',
'title' => 'Query Results',
'name' => 'rows',
'query' => 'SELECT '. ( $cgi->param('sql')
|| eidiot('Empty query') ),
)
%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Raw SQL');
+
+</%init>
diff --git a/httemplate/search/sqlradius.cgi b/httemplate/search/sqlradius.cgi
index b84df1a03..324729b6a 100644
--- a/httemplate/search/sqlradius.cgi
+++ b/httemplate/search/sqlradius.cgi
@@ -1,4 +1,4 @@
-<%= include( '/elements/header.html', 'RADIUS Sessions',
+<% include( '/elements/header.html', 'RADIUS Sessions',
include('/elements/menubar.html',
'Main menu' => $p, # popurl(2),
),
@@ -6,285 +6,306 @@
)
%>
-<%
- ###
- # parse cgi params
- ###
-
- #sort of false laziness w/cust_pay.cgi
- my $beginning = '';
- my $ending = '';
- if ( $cgi->param('beginning')
- && $cgi->param('beginning') =~ /^([ 0-9\-\/]{0,10})$/ ) {
- $beginning = str2time($1);
- }
- if ( $cgi->param('ending')
- && $cgi->param('ending') =~ /^([ 0-9\-\/]{0,10})$/ ) {
- $ending = str2time($1) + 86399;
- }
- if ( $cgi->param('begin') && $cgi->param('begin') =~ /^(\d+)$/ ) {
- $beginning = $1;
- }
- if ( $cgi->param('end') && $cgi->param('end') =~ /^(\d+)$/ ) {
- $ending = $1;
+% ###
+% # and finally, display the thing
+% ###
+%
+% foreach my $part_export (
+% #grep $_->can('usage_sessions'), qsearch( 'part_export' )
+% qsearch( 'part_export', { 'exporttype' => 'sqlradius' } ),
+% qsearch( 'part_export', { 'exporttype' => 'sqlradius_withdomain' } )
+% ) {
+% %user2svc_acct = ();
+%
+% my $efields = tie my %efields, 'Tie::IxHash', %fields;
+% delete $efields{'framedipaddress'} if $part_export->option('hide_ip');
+% if ( $part_export->option('hide_data') ) {
+% delete $efields{$_} foreach qw(acctinputoctets acctoutputoctets);
+% }
+% if ( $part_export->option('show_called_station') ) {
+% $efields->Splice(1, 0,
+% 'calledstationid' => {
+% 'name' => 'Destination',
+% 'attrib' => 'Called-Station-ID',
+% 'fmt' =>
+% sub { length($_[0]) ? shift : '&nbsp'; },
+% 'align' => 'left',
+% },
+% );
+% }
+%
+%
+
+ <% $part_export->exporttype %> to <% $part_export->machine %><BR>
+ <% include( '/elements/table-grid.html' ) %>
+% my $bgcolor1 = '#eeeeee';
+% my $bgcolor2 = '#ffffff';
+% my $bgcolor;
+
+ <TR>
+% foreach my $field ( keys %efields ) {
+
+ <TH CLASS="grid" BGCOLOR="#cccccc">
+ <% $efields{$field}->{name} %><BR>
+ <FONT SIZE=-2><% $efields{$field}->{attrib} %></FONT>
+ </TH>
+
+% }
+ </TR>
+
+% foreach my $session (
+% @{ $part_export->usage_sessions(
+% $beginning, $ending, $cgi_svc_acct, $ip, $prefix, ) }
+% ) {
+% if ( $bgcolor eq $bgcolor1 ) {
+% $bgcolor = $bgcolor2;
+% } else {
+% $bgcolor = $bgcolor1;
+% }
+
+ <TR>
+% foreach my $field ( keys %efields ) {
+% my $html = &{ $efields{$field}->{fmt} }( $session->{$field},
+% $session,
+% $part_export,
+% );
+% my $class = ( $html =~ /<TABLE/ ? 'inv' : 'grid' );
+
+ <TD CLASS="<%$class%>" BGCOLOR="<% $bgcolor %>" ALIGN="<% $efields{$field}->{align} %>">
+ <% $html %>
+ </TD>
+% }
+ </TR>
+
+% }
+
+</TABLE>
+<BR><BR>
+
+% }
+
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('List rating data');
+
+###
+# parse cgi params
+###
+
+#sort of false laziness w/cust_pay.cgi
+my $beginning = '';
+my $ending = '';
+if ( $cgi->param('beginning')
+ && $cgi->param('beginning') =~ /^([ 0-9\-\/\:\w]{0,54})$/ ) {
+ $beginning = str2time($1);
+}
+if ( $cgi->param('ending')
+ && $cgi->param('ending') =~ /^([ 0-9\-\/\:\w]{0,54})$/ ) {
+ $ending = str2time($1); # + 86399;
+}
+if ( $cgi->param('begin') && $cgi->param('begin') =~ /^(\d+)$/ ) {
+ $beginning = $1;
+}
+if ( $cgi->param('end') && $cgi->param('end') =~ /^(\d+)$/ ) {
+ $ending = $1;
+}
+
+my $cgi_svc_acct = '';
+if ( $cgi->param('svcnum') =~ /^(\d+)$/ ) {
+ $cgi_svc_acct = qsearchs( 'svc_acct', { 'svcnum' => $1 } );
+} elsif ( $cgi->param('username') =~ /^([^@]+)\@([^@]+)$/ ) {
+ my %search = { 'username' => $1 };
+ my $svc_domain = qsearchs('svc_domain', { 'domain' => $2 } );
+ if ( $svc_domain ) {
+ $search{'domsvc'} = $svc_domain->svcnum;
+ } else {
+ delete $search{'username'};
}
+ $cgi_svc_acct = qsearchs( 'svc_acct', \%search )
+ if keys %search;
+} elsif ( $cgi->param('username') =~ /^(.+)$/ ) {
+ $cgi_svc_acct = qsearchs( 'svc_acct', { 'username' => $1 } );
+}
+
+my $ip = '';
+if ( $cgi->param('ip') =~ /^((\d+\.){3}\d+)$/ ) {
+ $ip = $1;
+}
+
+my $prefix = $cgi->param('prefix');
+$prefix =~ s/\D//g;
+if ( $prefix =~ /^(\d+)$/ ) {
+ $prefix = $1;
+ $prefix = "011$prefix" unless $prefix =~ /^1/;
+} else {
+ $prefix = '';
+}
- my $cgi_svc_acct = '';
- if ( $cgi->param('svcnum') =~ /^(\d+)$/ ) {
- $cgi_svc_acct = qsearchs( 'svc_acct', { 'svcnum' => $1 } );
- } elsif ( $cgi->param('username') =~ /^([^@]+)\@([^@]+)$/ ) {
- my %search = { 'username' => $1 };
- my $svc_domain = qsearchs('svc_domain', { 'domain' => $2 } );
- if ( $svc_domain ) {
- $search{'domsvc'} = $svc_domain->svcnum;
+###
+# field formatting subroutines
+###
+
+my %user2svc_acct = ();
+my $user_format = sub {
+ my ( $user, $session, $part_export ) = @_;
+
+ my $svc_acct = '';
+ if ( exists $user2svc_acct{$user} ) {
+ $svc_acct = $user2svc_acct{$user};
+ } else {
+ my %search = ();
+ if ( $part_export->exporttype eq 'sqlradius_withdomain' ) {
+ my $domain;
+ if ( $user =~ /^([^@]+)\@([^@]+)$/ ) {
+ $search{'username'} = $1;
+ $domain = $2;
+ } else {
+ $search{'username'} = $user;
+ $domain = $session->{'realm'};
+ }
+ my $svc_domain = qsearchs('svc_domain', { 'domain' => $domain } );
+ if ( $svc_domain ) {
+ $search{'domsvc'} = $svc_domain->svcnum;
+ } else {
+ delete $search{'username'};
+ }
+ } elsif ( $part_export->exporttype eq 'sqlradius' ) {
+ $search{'username'} = $user;
} else {
- delete $search{'username'};
+ die 'unknown export type '. $part_export->exporttype.
+ " for $part_export\n";
}
- $cgi_svc_acct = qsearchs( 'svc_acct', \%search )
- if keys %search;
- } elsif ( $cgi->param('username') =~ /^(.+)$/ ) {
- $cgi_svc_acct = qsearchs( 'svc_acct', { 'username' => $1 } );
- }
-
- my $ip = '';
- if ( $cgi->param('ip') =~ /^((\d+\.){3}\d+)$/ ) {
- $ip = $1;
+ if ( keys %search ) {
+ my @svc_acct =
+ grep { qsearchs( 'export_svc', {
+ 'exportnum' => $part_export->exportnum,
+ 'svcpart' => $_->cust_svc->svcpart,
+ } )
+ } qsearch( 'svc_acct', \%search );
+ if ( @svc_acct ) {
+ warn 'multiple svc_acct records for user $user found; '.
+ 'using first arbitrarily'
+ if scalar(@svc_acct) > 1;
+ $user2svc_acct{$user} = $svc_acct = shift @svc_acct;
+ }
+ }
}
- my $prefix = $cgi->param('prefix');
- $prefix =~ s/\D//g;
- if ( $prefix =~ /^(\d+)$/ ) {
- $prefix = $1;
- $prefix = "011$prefix" unless $prefix =~ /^1/;
+ if ( $svc_acct ) {
+ my $svcnum = $svc_acct->svcnum;
+ qq(<A HREF="${p}view/svc_acct.cgi?$svcnum"><B>$user</B></A>);
} else {
- $prefix = '';
+ "<B>$user</B>";
}
- ###
- # field formatting subroutines
- ###
+};
- my %user2svc_acct = ();
- my $user_format = sub {
- my ( $user, $session, $part_export ) = @_;
+my $customer_format = sub {
+ my( $unused, $session ) = @_;
+ return '&nbsp;' unless exists $user2svc_acct{$session->{'username'}};
+ my $svc_acct = $user2svc_acct{$session->{'username'}};
+ my $cust_pkg = $svc_acct->cust_svc->cust_pkg;
+ return '&nbsp;' unless $cust_pkg;
+ my $cust_main = $cust_pkg->cust_main;
- my $svc_acct = '';
- if ( exists $user2svc_acct{$user} ) {
- $svc_acct = $user2svc_acct{$user};
- } else {
- my %search = ();
- if ( $part_export->exporttype eq 'sqlradius_withdomain' ) {
- my $domain;
- if ( $user =~ /^([^@]+)\@([^@]+)$/ ) {
- $search{'username'} = $1;
- $domain = $2;
- } else {
- $search{'username'} = $user;
- $domain = $session->{'realm'};
- }
- my $svc_domain = qsearchs('svc_domain', { 'domain' => $domain } );
- if ( $svc_domain ) {
- $search{'domsvc'} = $svc_domain->svcnum;
- } else {
- delete $search{'username'};
- }
- } elsif ( $part_export->exporttype eq 'sqlradius' ) {
- $search{'username'} = $user;
- } else {
- die 'unknown export type '. $part_export->exporttype.
- " for $part_export\n";
- }
- if ( keys %search ) {
- my @svc_acct =
- grep { qsearchs( 'export_svc', {
- 'exportnum' => $part_export->exportnum,
- 'svcpart' => $_->cust_svc->svcpart,
- } )
- } qsearch( 'svc_acct', \%search );
- if ( @svc_acct ) {
- warn 'multiple svc_acct records for user $user found; '.
- 'using first arbitrarily'
- if scalar(@svc_acct) > 1;
- $user2svc_acct{$user} = $svc_acct = shift @svc_acct;
- }
- }
- }
+ qq!<A HREF="${p}view/cust_main.cgi?!. $cust_main->custnum. '">'.
+ $cust_pkg->cust_main->name. '</A>';
+};
- if ( $svc_acct ) {
- my $svcnum = $svc_acct->svcnum;
- qq(<A HREF="${p}view/svc_acct.cgi?$svcnum"><B>$user</B></A>);
- } else {
- "<B>$user</B>";
- }
+my $time_format = sub {
+ my $time = shift;
+ return '&nbsp;' if $time == 0;
+ my $pretty = time2str('%T%P %a&nbsp;%b&nbsp;%o&nbsp;%Y', $time );
+ $pretty =~ s/ (\d)(st|dn|rd|th)/$1$2/;
+ $pretty;
+};
- };
-
- my $customer_format = sub {
- my( $unused, $session ) = @_;
- return '&nbsp;' unless exists $user2svc_acct{$session->{'username'}};
- my $svc_acct = $user2svc_acct{$session->{'username'}};
- my $cust_pkg = $svc_acct->cust_svc->cust_pkg;
- return '&nbsp;' unless $cust_pkg;
- my $cust_main = $cust_pkg->cust_main;
-
- qq!<A HREF="${p}view/cust_main.cgi?!. $cust_main->custnum. '">'.
- $cust_pkg->cust_main->name. '</A>';
- };
-
- my $time_format = sub {
- my $time = shift;
- return '&nbsp;' if $time == 0;
- my $pretty = time2str('%T%P %a&nbsp;%b&nbsp;%o&nbsp;%Y', $time );
- $pretty =~ s/ (\d)(st|dn|rd|th)/$1$2/;
- $pretty;
- };
-
- my $duration_format = sub {
- my $seconds = shift;
- my $hour = int($seconds/3600);
- my $min = int( ($seconds%3600) / 60 );
- my $sec = $seconds%60;
- '<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0>'.
- '<TR><TD ALIGN="right">'.
- ( $hour ? "<B>$hour</B>h" : '&nbsp;' ).
- '</TD><TD ALIGN="right">'.
- ( ( $hour || $min ) ? "<B>$min</B>m" : '&nbsp;' ).
- '</TD><TD ALIGN="right">'.
- "<B>$sec</B>s".
- '</TD></TR></TABLE>';
- };
-
- my $octets_format = sub {
- my $octets = shift;
- my $megs = $octets / 1048576;
- sprintf('<B>%.3f</B>&nbsp;megs', $megs);
- #my $gigs = $octets / 1073741824
- #sprintf('<B>%.3f</B> gigabytes', $gigs);
- };
-
- ###
- # the fields
- ###
-
- tie my %fields, 'Tie::IxHash',
- 'username' => {
- name => 'User',
- attrib => 'UserName',
- fmt => $user_format,
- align => 'left',
- },
- 'realm' => {
- name => 'Realm',
- attrib => 'Realm',
- align => 'left',
- },
- 'dummy' => {
- name => 'Customer',
- attrib => '',
- fmt => $customer_format,
- align => 'left',
- },
- 'framedipaddress' => {
- name => 'IP&nbsp;Address',
- attrib => 'Framed-IP-Address',
- fmt => sub { my $ip = shift;
- length($ip) ? $ip : '&nbsp';
- },
- align => 'right',
- },
- 'acctstarttime' => {
- name => 'Start&nbsp;time',
- attrib => 'Acct-Start-Time',
- fmt => $time_format,
- align => 'left',
- },
- 'acctstoptime' => {
- name => 'End&nbsp;time',
- attrib => 'Acct-Stop-Time',
- fmt => $time_format,
- align => 'left',
- },
- 'acctsessiontime' => {
- name => 'Duration',
- attrib => 'Acct-Session-Time',
- fmt => $duration_format,
- align => 'right',
- },
- 'acctinputoctets' => {
- name => 'Upload', # (from user)',
- attrib => 'Acct-Input-Octets',
- fmt => $octets_format,
- align => 'right',
- },
- 'acctoutputoctets' => {
- name => 'Download', # (to user)',
- attrib => 'Acct-Output-Octets',
- fmt => $octets_format,
- align => 'right',
- },
- ;
- $fields{$_}->{fmt} ||= sub { length($_[0]) ? shift : '&nbsp'; }
- foreach keys %fields;
-
- ###
- # and finally, display the thing
- ###
-
- foreach my $part_export (
- #grep $_->can('usage_sessions'), qsearch( 'part_export' )
- qsearch( 'part_export', { 'exporttype' => 'sqlradius' } ),
- qsearch( 'part_export', { 'exporttype' => 'sqlradius_withdomain' } )
- ) {
- %user2svc_acct = ();
-
- my $efields = tie my %efields, 'Tie::IxHash', %fields;
- delete $efields{'framedipaddress'} if $part_export->option('hide_ip');
- if ( $part_export->option('hide_data') ) {
- delete $efields{$_} foreach qw(acctinputoctets acctoutputoctets);
- }
- if ( $part_export->option('show_called_station') ) {
- $efields->Splice(1, 0,
- 'calledstationid' => {
- 'name' => 'Destination',
- 'attrib' => 'Called-Station-ID',
- 'fmt' =>
- sub { length($_[0]) ? shift : '&nbsp'; },
- 'align' => 'left',
- },
- );
- }
+my $duration_format = sub {
+ my $seconds = shift;
+ my $hour = int($seconds/3600);
+ my $min = int( ($seconds%3600) / 60 );
+ my $sec = $seconds%60;
+ '<TABLE CLASS="inv" BORDER=0 CELLSPACING=0 CELLPADDING=0>'.
+ '<TR><TD CLASS="inv" ALIGN="right">'.
+ ( $hour ? "<B>$hour</B>h" : '&nbsp;' ).
+ '</TD><TD CLASS="inv" ALIGN="right">'.
+ ( ( $hour || $min ) ? "<B>$min</B>m" : '&nbsp;' ).
+ '</TD><TD CLASS="inv" ALIGN="right">'.
+ "<B>$sec</B>s".
+ '</TD></TR></TABLE>';
+};
-%>
+my $octets_format = sub {
+ my $octets = shift;
+ my $megs = $octets / 1048576;
+ sprintf('<B>%.3f</B>&nbsp;megs', $megs);
+ #my $gigs = $octets / 1073741824
+ #sprintf('<B>%.3f</B> gigabytes', $gigs);
+};
-<%= $part_export->exporttype %> to <%= $part_export->machine %><BR>
-<%= include( '/elements/table.html' ) %>
-<TR>
- <% foreach my $field ( keys %efields ) { %>
- <TH>
- <%= $efields{$field}->{name} %><BR>
- <FONT SIZE=-2><%= $efields{$field}->{attrib} %></FONT>
- </TH>
- <% } %>
-</TR>
-<% foreach my $session (
- @{ $part_export->usage_sessions(
- $beginning, $ending, $cgi_svc_acct, $ip, $prefix, ) }
- ) {
-%>
- <TR>
- <% foreach my $field ( keys %efields ) { %>
- <TD ALIGN="<%= $efields{$field}->{align} %>">
- <%= &{ $efields{$field}->{fmt} }( $session->{$field},
- $session,
- $part_export,
- )
- %>
- </TD>
- <% } %>
- </TR>
-<% } %>
+###
+# the fields
+###
-</TABLE>
-<BR><BR>
+tie my %fields, 'Tie::IxHash',
+ 'username' => {
+ name => 'User',
+ attrib => 'UserName',
+ fmt => $user_format,
+ align => 'left',
+ },
+ 'realm' => {
+ name => 'Realm',
+ attrib => 'Realm',
+ align => 'left',
+ },
+ 'dummy' => {
+ name => 'Customer',
+ attrib => '',
+ fmt => $customer_format,
+ align => 'left',
+ },
+ 'framedipaddress' => {
+ name => 'IP&nbsp;Address',
+ attrib => 'Framed-IP-Address',
+ fmt => sub { my $ip = shift;
+ length($ip) ? $ip : '&nbsp';
+ },
+ align => 'right',
+ },
+ 'acctstarttime' => {
+ name => 'Start&nbsp;time',
+ attrib => 'Acct-Start-Time',
+ fmt => $time_format,
+ align => 'left',
+ },
+ 'acctstoptime' => {
+ name => 'End&nbsp;time',
+ attrib => 'Acct-Stop-Time',
+ fmt => $time_format,
+ align => 'left',
+ },
+ 'acctsessiontime' => {
+ name => 'Duration',
+ attrib => 'Acct-Session-Time',
+ fmt => $duration_format,
+ align => 'right',
+ },
+ 'acctinputoctets' => {
+ name => 'Upload', # (from user)',
+ attrib => 'Acct-Input-Octets',
+ fmt => $octets_format,
+ align => 'right',
+ },
+ 'acctoutputoctets' => {
+ name => 'Download', # (to user)',
+ attrib => 'Acct-Output-Octets',
+ fmt => $octets_format,
+ align => 'right',
+ },
+;
+$fields{$_}->{fmt} ||= sub { length($_[0]) ? shift : '&nbsp'; }
+ foreach keys %fields;
-<% } %>
+</%init>
diff --git a/httemplate/search/sqlradius.html b/httemplate/search/sqlradius.html
index 8f4878dbc..660a54f3c 100644
--- a/httemplate/search/sqlradius.html
+++ b/httemplate/search/sqlradius.html
@@ -1,12 +1,9 @@
-<%= include( '/elements/header.html', 'Search RADIUS sessions', '', '', '
-<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/header.html', 'Search RADIUS sessions' ) %>
+
<FORM NAME="OneTrueForm" ACTION="sqlradius.cgi" METHOD="GET">
-<% #include( '/elements/table.html' ) %>
-<%= ntable('#cccccc') %>
+% #include( '/elements/table.html' )
+
+<% ntable('#cccccc') %>
<TR>
<TD ALIGN="right">Username: </TD>
<TD><INPUT TYPE="text" NAME="username"></TD>
@@ -15,13 +12,12 @@
<TD></TD>
<TD><FONT SIZE="-1"><I>(leave blank to show all users)</I></FONT></TD>
</TR>
+% my @part_export = qsearch( 'part_export', { 'exporttype' => 'sqlradius' } );
+% push @part_export,
+% qsearch( 'part_export', { 'exporttype' => 'sqlradius_withdomain' } );
+%
+% if ( grep { ! $_->option('hide_ip') } @part_export ) {
-<% my @part_export = qsearch( 'part_export', { 'exporttype' => 'sqlradius' } );
- push @part_export,
- qsearch( 'part_export', { 'exporttype' => 'sqlradius_withdomain' } );
-%>
-
-<% if ( grep { ! $_->option('hide_ip') } @part_export ) { %>
<TR>
<TD ALIGN="right">IP address: </TD>
<TD><INPUT TYPE="text" NAME="ip"></TD>
@@ -30,9 +26,9 @@
<TD></TD>
<TD><FONT SIZE="-1"><I>(leave blank to show all IPs)</I></FONT></TD>
</TR>
-<% } %>
+% }
+% if ( grep { $_->option('show_called_station') } @part_export ) {
-<% if ( grep { $_->option('show_called_station') } @part_export ) { %>
<TR>
<TD ALIGN="right">Destination prefix:</TD>
<TD><INPUT TYPE="text" NAME="prefix"></TD>
@@ -45,50 +41,19 @@
<TD></TD>
<TD><FONT SIZE="-1"><I>(leave blank to show all destinations)</I></FONT></TD>
</TR>
-<% } %>
+% }
+
+
+<% include( '/elements/tr-input-beginning_ending.html', 'input_time'=>1 ) %>
-<TR>
- <TD ALIGN="right">From: </TD>
- <TD>
- <INPUT TYPE="text" NAME="beginning" ID="beginning_text" VALUE="" SIZE=11 MAXLENGTH=10> <IMG SRC="../images/calendar.png" ID="beginning_button" STYLE="cursor: pointer" TITLE="Select date">
- </TD>
- <SCRIPT TYPE="text/javascript">
- Calendar.setup({
- inputField: "beginning_text",
- ifFormat: "%m/%d/%Y",
- button: "beginning_button",
- align: "BR"
- });
- </SCRIPT>
-</TR>
-<TR>
- <TD></TD>
- <TD><i>m/d/y</i></TD>
-</TR>
-<TR>
- <TD ALIGN="right">To: </TD>
- <TD>
- <INPUT TYPE="text" NAME="ending" ID="ending_text" VALUE="" SIZE=11 MAXLENGTH=10> <IMG SRC="../images/calendar.png" ID="ending_button" STYLE="cursor:pointer" TITLE="Select date">
- </TD>
- <SCRIPT TYPE="text/javascript">
- Calendar.setup({
- inputField: "ending_text",
- ifFormat: "%m/%d/%Y",
- button: "ending_button",
- align: "BR"
- });
- </SCRIPT>
-</TR>
-<TR>
- <TD></TD>
- <TD><i>m/d/y</i>
- <BR><FONT SIZE="-1">(leave one or both dates blank for an open-ended search)</FONT>
- </TD>
-</TR>
</TABLE>
<BR><INPUT TYPE="submit" VALUE="View sessions">
</FORM>
-</BODY>
-</HTML>
+<% include('/elements/footer.html') %>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('List rating data');
+</%init>
diff --git a/httemplate/search/svc_acct.cgi b/httemplate/search/svc_acct.cgi
index b14591958..a702d604b 100755
--- a/httemplate/search/svc_acct.cgi
+++ b/httemplate/search/svc_acct.cgi
@@ -1,30 +1,84 @@
-<%
-
-my $orderby = 'ORDER BY svcnum';
+<% include( 'elements/search.html',
+ 'title' => 'Account Search Results',
+ 'name' => 'accounts',
+ 'query' => $sql_query,
+ 'count_query' => $count_query,
+ 'redirect' => $link,
+ 'header' => [ '#',
+ 'Service',
+ 'Account',
+ 'UID',
+ FS::UI::Web::cust_header(),
+ ],
+ 'fields' => [ 'svcnum',
+ 'svc',
+ 'email',
+ 'uid',
+ \&FS::UI::Web::cust_fields,
+ ],
+ 'links' => [ $link,
+ $link,
+ $link,
+ $link,
+ ( map { $_ ne 'Cust. Status' ? $link_cust : '' }
+ FS::UI::Web::cust_header()
+ ),
+ ],
+ 'align' => 'rlll'. FS::UI::Web::cust_aligns(),
+ 'color' => [
+ '',
+ '',
+ '',
+ '',
+ FS::UI::Web::cust_colors(),
+ ],
+ 'style' => [
+ '',
+ '',
+ '',
+ '',
+ FS::UI::Web::cust_styles(),
+ ],
+ )
+%>
+<%init>
-my($query)=$cgi->keywords;
-$query ||= ''; #to avoid use of unitialized value errors
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('List services');
-my $cjoin = '';
my @extra_sql = ();
-if ( $query =~ /^UN_(.*)$/ ) {
- $query = $1;
- $cjoin = 'LEFT JOIN cust_svc USING ( svcnum )';
- push @extra_sql, 'pkgnum IS NULL';
-}
-if ( $query eq 'svcnum' ) {
- #$orderby = "ORDER BY svcnum";
-} elsif ( $query eq 'username' ) {
- $orderby = "ORDER BY LOWER(username)";
-} elsif ( $query eq 'uid' ) {
- $orderby = "ORDER BY uid";
- push @extra_sql, "uid IS NOT NULL";
+ if ( $cgi->param('domain') ) {
+ my $svc_domain =
+ qsearchs('svc_domain', { 'domain' => $cgi->param('domain') } );
+ unless ( $svc_domain ) {
+ #it would be nice if this looked more like the other "not found"
+ #errors, but this will do for now.
+ eidiot "Domain ". $cgi->param('domain'). " not found at all";
+ } else {
+ push @extra_sql, 'domsvc = '. $svc_domain->svcnum;
+ }
+ }
+
+my $orderby = 'ORDER BY svcnum';
+if ( $cgi->param('magic') =~ /^(all|unlinked)$/ ) {
+
+ push @extra_sql, 'pkgnum IS NULL'
+ if $cgi->param('magic') eq 'unlinked';
+
+ if ( $cgi->param('sortby') =~ /^(\w+)$/ ) {
+ my $sortby = $1;
+ $sortby = "LOWER($sortby)"
+ if $sortby eq 'username';
+ push @extra_sql, "$sortby IS NOT NULL"
+ if $sortby eq 'uid';
+ $orderby = "ORDER BY $sortby";
+ }
+
} elsif ( $cgi->param('popnum') =~ /^(\d+)$/ ) {
push @extra_sql, "popnum = $1";
$orderby = "ORDER BY LOWER(username)";
} elsif ( $cgi->param('svcpart') =~ /^(\d+)$/ ) {
- $cjoin ||= 'LEFT JOIN cust_svc USING ( svcnum )';
push @extra_sql, "svcpart = $1";
$orderby = "ORDER BY uid";
#$orderby = "ORDER BY svcnum";
@@ -72,12 +126,20 @@ if ( $query eq 'svcnum' ) {
}
+my $addl_from = ' LEFT JOIN cust_svc USING ( svcnum ) '.
+ ' LEFT JOIN part_svc USING ( svcpart ) '.
+ ' LEFT JOIN cust_pkg USING ( pkgnum ) '.
+ ' LEFT JOIN cust_main USING ( custnum ) ';
+
+#here is the agent virtualization
+push @extra_sql, $FS::CurrentUser::CurrentUser->agentnums_sql;
+
my $extra_sql =
scalar(@extra_sql)
? ' WHERE '. join(' AND ', @extra_sql )
: '';
-my $count_query = "SELECT COUNT(*) FROM svc_acct $cjoin $extra_sql";
+my $count_query = "SELECT COUNT(*) FROM svc_acct $addl_from $extra_sql";
#if ( keys %svc_acct ) {
# $count_query .= ' WHERE '.
# join(' AND ', map "$_ = ". dbh->quote($svc_acct{$_}),
@@ -90,14 +152,12 @@ my $sql_query = {
'hashref' => {}, # \%svc_acct,
'select' => join(', ',
'svc_acct.*',
+ 'part_svc.svc',
'cust_main.custnum',
FS::UI::Web::cust_sql_fields(),
),
'extra_sql' => "$extra_sql $orderby",
- 'addl_from' => ' LEFT JOIN cust_svc USING ( svcnum ) '.
- ' LEFT JOIN part_svc USING ( svcpart ) '.
- ' LEFT JOIN cust_pkg USING ( pkgnum ) '.
- ' LEFT JOIN cust_main USING ( custnum ) ',
+ 'addl_from' => $addl_from,
};
my $link = [ "${p}view/svc_acct.cgi?", 'svcnum' ];
@@ -110,31 +170,5 @@ my $link_cust = sub {
}
};
-%><%= include( 'elements/search.html',
- 'title' => 'Account Search Results',
- 'name' => 'accounts',
- 'query' => $sql_query,
- 'count_query' => $count_query,
- 'redirect' => $link,
- 'header' => [ '#',
- 'Account',
- 'UID',
- 'Service',
- FS::UI::Web::cust_header(),
- ],
- 'fields' => [ 'svcnum',
- 'email',
- 'uid',
- 'svc',
- \&FS::UI::Web::cust_fields,
- ],
- 'links' => [ $link,
- $link,
- $link,
- '',
- ( map { $link_cust }
- FS::UI::Web::cust_header()
- ),
- ],
- )
-%>
+</%init>
+
diff --git a/httemplate/search/svc_acct.html b/httemplate/search/svc_acct.html
deleted file mode 100755
index c504c2f34..000000000
--- a/httemplate/search/svc_acct.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<HTML>
- <HEAD>
- <TITLE>Account Search</TITLE>
- </HEAD>
- <BODY BGCOLOR="#e8e8e8">
- <FONT SIZE=7>
- Account Search
- </FONT>
- <BR><BR>
- <FORM ACTION="svc_acct.cgi" METHOD="GET">
- Search for <B>username</B>:
- <INPUT TYPE="text" NAME="username">
-
- <P><INPUT TYPE="submit" VALUE="Search">
-
- </FORM>
- </BODY>
-</HTML>
-
diff --git a/httemplate/search/svc_broadband.cgi b/httemplate/search/svc_broadband.cgi
index efadce600..1bbdbfcdb 100755
--- a/httemplate/search/svc_broadband.cgi
+++ b/httemplate/search/svc_broadband.cgi
@@ -1,96 +1,121 @@
-<%
+%die "access denied"
+% unless $FS::CurrentUser::CurrentUser->access_right('List services');
+%
+%my $conf = new FS::Conf;
+%
+%my @svc_broadband = ();
+%my $sortby=\*svcnum_sort;
+%if ( $cgi->param('magic') =~ /^(all|unlinked)$/ ) {
+%
+% @svc_broadband=qsearch('svc_broadband',{});
+%
+% if ( $cgi->param('magic') eq 'unlinked' ) {
+% @svc_broadband = grep { qsearchs('cust_svc', {
+% 'svcnum' => $_->svcnum,
+% 'pkgnum' => '',
+% }
+% )
+% }
+% @svc_broadband;
+% }
+%
+% if ( $cgi->param('sortby') =~ /^(\w+)$/ ) {
+% my $sortby = $1;
+% if ( $sortby eq 'blocknum' ) {
+% $sortby = \*blocknum_sort;
+% }
+% }
+%
+%} elsif ( $cgi->param('svcpart') =~ /^(\d+)$/ ) {
+%
+% @svc_broadband =
+% qsearch( 'svc_broadband', {}, '',
+% " WHERE $1 = ( SELECT svcpart FROM cust_svc ".
+% " WHERE cust_svc.svcnum = svc_external.svcnum ) "
+% );
+%
+%} elsif ( $cgi->param('ip_addr') =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/ ) {
+% my $ip_addr = $1;
+% @svc_broadband = qsearchs('svc_broadband',{'ip_addr'=>$ip_addr});
+%}
+%
+%my %routerbyblock = ();
+%foreach my $router (qsearch('router', {})) {
+% foreach ($router->addr_block) {
+% $routerbyblock{$_->blocknum} = $router;
+% }
+%}
+%
+%if ( scalar(@svc_broadband) == 1 ) {
+% print $cgi->redirect(popurl(2). "view/svc_broadband.cgi?". $svc_broadband[0]->svcnum);
+% #exit;
+%} elsif ( scalar(@svc_broadband) == 0 ) {
+%
-my $conf = new FS::Conf;
-
-my($query)=$cgi->keywords;
-$query ||= ''; #to avoid use of unitialized value errors
-my(@svc_broadband,$sortby);
-if ( $query eq 'svcnum' ) {
- $sortby=\*svcnum_sort;
- @svc_broadband=qsearch('svc_broadband',{});
-} elsif ( $query eq 'blocknum' ) {
- $sortby=\*blocknum_sort;
- @svc_broadband=qsearch('svc_broadband',{});
-} else {
- $cgi->param('ip_addr') =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/;
- my($ip_addr)=$1;
- @svc_broadband = qsearchs('svc_broadband',{'ip_addr'=>$ip_addr});
-}
-
-my %routerbyblock = ();
-foreach my $router (qsearch('router', {})) {
- foreach ($router->addr_block) {
- $routerbyblock{$_->blocknum} = $router;
- }
-}
-
-if ( scalar(@svc_broadband) == 1 ) {
- print $cgi->redirect(popurl(2). "view/svc_broadband.cgi?". $svc_broadband[0]->svcnum);
- #exit;
-} elsif ( scalar(@svc_broadband) == 0 ) {
-%>
-<!-- mason kludge -->
-<%
- eidiot "No matching ip address found!\n";
-} else {
-%>
<!-- mason kludge -->
-<%
- my($total)=scalar(@svc_broadband);
- print header("IP Address Search Results",''), <<END;
-
- $total matching broadband services found
- <TABLE BORDER=4 CELLSPACING=0 CELLPADDING=0>
- <TR>
- <TH>Service #</TH>
- <TH>Router</TH>
- <TH>IP Address</TH>
- </TR>
-END
-
- foreach my $svc_broadband (
- sort $sortby (@svc_broadband)
- ) {
- my($svcnum,$ip_addr,$routername,$routernum)=(
- $svc_broadband->svcnum,
- $svc_broadband->ip_addr,
- $routerbyblock{$svc_broadband->blocknum}->routername,
- $routerbyblock{$svc_broadband->blocknum}->routernum,
- );
-
- my $rowspan = 1;
-
- print <<END;
- <TR>
- <TD ROWSPAN=$rowspan><A HREF="${p}view/svc_broadband.cgi?$svcnum">$svcnum</A></TD>
- <TD ROWSPAN=$rowspan><A HREF="${p}view/router.cgi?$routernum">$routername</A></TD>
- <TD ROWSPAN=$rowspan><A HREF="${p}view/svc_broadband.cgi?$svcnum">$ip_addr</A></TD>
-END
-
- #print @rows;
- print "</TR>";
-
- }
-
- print <<END;
- </TABLE>
- </BODY>
-</HTML>
-END
-
-}
-
-sub svcnum_sort {
- $a->getfield('svcnum') <=> $b->getfield('svcnum');
-}
-
-sub blocknum_sort {
- if ($a->getfield('blocknum') == $b->getfield('blocknum')) {
- $a->getfield('ip_addr') cmp $b->getfield('ip_addr');
- } else {
- $a->getfield('blocknum') cmp $b->getfield('blocknum');
- }
-}
+%
+% eidiot "No matching ip address found!\n";
+%} else {
+%
+<!-- mason kludge -->
+%
+% my($total)=scalar(@svc_broadband);
+% print header("IP Address Search Results",''), <<END;
+%
+% $total matching broadband services found
+% <TABLE BORDER=4 CELLSPACING=0 CELLPADDING=0>
+% <TR>
+% <TH>Service #</TH>
+% <TH>Router</TH>
+% <TH>IP Address</TH>
+% </TR>
+%END
+%
+% foreach my $svc_broadband (
+% sort $sortby (@svc_broadband)
+% ) {
+% my($svcnum,$ip_addr,$routername,$routernum)=(
+% $svc_broadband->svcnum,
+% $svc_broadband->ip_addr,
+% $routerbyblock{$svc_broadband->blocknum}->routername,
+% $routerbyblock{$svc_broadband->blocknum}->routernum,
+% );
+%
+% my $rowspan = 1;
+%
+% print <<END;
+% <TR>
+% <TD ROWSPAN=$rowspan><A HREF="${p}view/svc_broadband.cgi?$svcnum">$svcnum</A></TD>
+% <TD ROWSPAN=$rowspan><A HREF="${p}view/router.cgi?$routernum">$routername</A></TD>
+% <TD ROWSPAN=$rowspan><A HREF="${p}view/svc_broadband.cgi?$svcnum">$ip_addr</A></TD>
+%END
+%
+% #print @rows;
+% print "</TR>";
+%
+% }
+%
+% print <<END;
+% </TABLE>
+% </BODY>
+%</HTML>
+%END
+%
+%}
+%
+%sub svcnum_sort {
+% $a->getfield('svcnum') <=> $b->getfield('svcnum');
+%}
+%
+%sub blocknum_sort {
+% if ($a->getfield('blocknum') == $b->getfield('blocknum')) {
+% $a->getfield('ip_addr') cmp $b->getfield('ip_addr');
+% } else {
+% $a->getfield('blocknum') cmp $b->getfield('blocknum');
+% }
+%}
+%
+%
+%
-%>
diff --git a/httemplate/search/svc_domain.cgi b/httemplate/search/svc_domain.cgi
index f261ea9f3..b14a1cc4f 100755
--- a/httemplate/search/svc_domain.cgi
+++ b/httemplate/search/svc_domain.cgi
@@ -1,56 +1,102 @@
-<%
+<% include( 'elements/search.html',
+ 'title' => "Domain Search Results",
+ 'name' => 'domains',
+ 'query' => $sql_query,
+ 'count_query' => $count_query,
+ 'redirect' => $link,
+ 'header' => [ '#',
+ 'Service',
+ 'Domain',
+ FS::UI::Web::cust_header(),
+ ],
+ 'fields' => [ 'svcnum',
+ 'svc',
+ 'domain',
+ \&FS::UI::Web::cust_fields,
+ ],
+ 'links' => [ $link,
+ $link,
+ $link,
+ ( map { $_ ne 'Cust. Status' ? $link_cust : '' }
+ FS::UI::Web::cust_header()
+ ),
+ ],
+ 'align' => 'rll'. FS::UI::Web::cust_aligns(),
+ 'color' => [
+ '',
+ '',
+ '',
+ FS::UI::Web::cust_colors(),
+ ],
+ 'style' => [
+ '',
+ '',
+ '',
+ FS::UI::Web::cust_styles(),
+ ],
+ )
+%>
+<%init>
-my $conf = new FS::Conf;
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('List services');
-my($query)=$cgi->keywords;
-$query ||= ''; #to avoid use of unitialized value errors
+my $conf = new FS::Conf;
my $orderby = 'ORDER BY svcnum';
-my $join = '';
my %svc_domain = ();
-my $extra_sql = '';
-if ( $query eq 'svcnum' ) {
- #$orderby = 'ORDER BY svcnum';
-} elsif ( $query eq 'domain' ) {
- $orderby = 'ORDER BY domain';
-} elsif ( $query eq 'UN_svcnum' ) {
- #$orderby = 'ORDER BY svcnum';
- $join = 'LEFT JOIN cust_svc USING ( svcnum )';
- $extra_sql = ' WHERE pkgnum IS NULL';
-} elsif ( $query eq 'UN_domain' ) {
- $orderby = 'ORDER BY domain';
- $join = 'LEFT JOIN cust_svc USING ( svcnum )';
- $extra_sql = ' WHERE pkgnum IS NULL';
+my @extra_sql = ();
+if ( $cgi->param('magic') =~ /^(all|unlinked)$/ ) {
+
+ push @extra_sql, 'pkgnum IS NULL'
+ if $cgi->param('magic') eq 'unlinked';
+
+ if ( $cgi->param('sortby') =~ /^(\w+)$/ ) {
+ my $sortby = $1;
+ $orderby = "ORDER BY $sortby";
+ }
+
} elsif ( $cgi->param('svcpart') =~ /^(\d+)$/ ) {
- #$orderby = 'ORDER BY svcnum';
- $join = 'LEFT JOIN cust_svc USING ( svcnum )';
- $extra_sql = " WHERE svcpart = $1";
+ push @extra_sql, "svcpart = $1";
} else {
$cgi->param('domain') =~ /^([\w\-\.]+)$/;
- $join = '';
$svc_domain{'domain'} = $1;
}
-my $count_query = "SELECT COUNT(*) FROM svc_domain $join $extra_sql";
+my $addl_from = ' LEFT JOIN cust_svc USING ( svcnum ) '.
+ ' LEFT JOIN part_svc USING ( svcpart ) '.
+ ' LEFT JOIN cust_pkg USING ( pkgnum ) '.
+ ' LEFT JOIN cust_main USING ( custnum ) ';
+
+#here is the agent virtualization
+push @extra_sql, $FS::CurrentUser::CurrentUser->agentnums_sql;
+
+my $extra_sql = '';
+if ( @extra_sql ) {
+ $extra_sql = ( keys(%svc_domain) ? ' AND ' : ' WHERE ' ).
+ join(' AND ', @extra_sql );
+}
+
+my $count_query = "SELECT COUNT(*) FROM svc_domain $addl_from ";
if ( keys %svc_domain ) {
$count_query .= ' WHERE '.
join(' AND ', map "$_ = ". dbh->quote($svc_domain{$_}),
keys %svc_domain
);
}
+$count_query .= $extra_sql;
my $sql_query = {
'table' => 'svc_domain',
'hashref' => \%svc_domain,
'select' => join(', ',
'svc_domain.*',
- 'cust_main.custnum',
- FS::UI::Web::cust_sql_fields(),
+ 'part_svc.svc',
+ 'cust_main.custnum',
+ FS::UI::Web::cust_sql_fields(),
),
'extra_sql' => "$extra_sql $orderby",
- 'addl_from' => 'LEFT JOIN cust_svc USING ( svcnum ) '.
- 'LEFT JOIN cust_pkg USING ( pkgnum ) '.
- 'LEFT JOIN cust_main USING ( custnum ) ',
+ 'addl_from' => $addl_from,
};
my $link = [ "${p}view/svc_domain.cgi?", 'svcnum' ];
@@ -61,25 +107,4 @@ my $link_cust = sub {
$svc_x->custnum ? [ "${p}view/cust_main.cgi?", 'custnum' ] : '';
};
-%><%= include ('elements/search.html',
- 'title' => "Domain Search Results",
- 'name' => 'domains',
- 'query' => $sql_query,
- 'count_query' => $count_query,
- 'redirect' => $link,
- 'header' => [ '#',
- 'Domain',
- FS::UI::Web::cust_header(),
- ],
- 'fields' => [ 'svcnum',
- 'domain',
- \&FS::UI::Web::cust_fields,
- ],
- 'links' => [ $link,
- $link,
- ( map { $link_cust }
- FS::UI::Web::cust_header()
- ),
- ],
- )
-%>
+</%init>
diff --git a/httemplate/search/svc_domain.html b/httemplate/search/svc_domain.html
deleted file mode 100755
index b759102f4..000000000
--- a/httemplate/search/svc_domain.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<HTML>
- <HEAD>
- <TITLE>Domain Search</TITLE>
- </HEAD>
- <BODY BGCOLOR="#e8e8e8">
- <FONT SIZE=7>
- Domain Search
- </FONT>
- <BR><BR>
- <FORM ACTION="svc_domain.cgi" METHOD="GET">
- Search for <B>domain</B>:
- <INPUT TYPE="text" NAME="domain">
-
- <P><INPUT TYPE="submit" VALUE="Search">
-
- </FORM>
- </BODY>
-</HTML>
-
diff --git a/httemplate/search/svc_external.cgi b/httemplate/search/svc_external.cgi
index c5ac13498..2710d75bc 100755
--- a/httemplate/search/svc_external.cgi
+++ b/httemplate/search/svc_external.cgi
@@ -1,101 +1,153 @@
-<%
+%die "access denied"
+% unless $FS::CurrentUser::CurrentUser->access_right('List services');
+%
+%my $conf = new FS::Conf;
+%
+%my @svc_external = ();
+%my @h_svc_external = ();
+%my $sortby=\*svcnum_sort;
+%if ( $cgi->param('magic') =~ /^(all|unlinked)$/ ) {
+%
+% @svc_external=qsearch('svc_external',{});
+%
+% if ( $cgi->param('magic') eq 'unlinked' ) {
+% @svc_external = grep { qsearchs('cust_svc', {
+% 'svcnum' => $_->svcnum,
+% 'pkgnum' => '',
+% }
+% )
+% }
+% @svc_external;
+% }
+%
+% if ( $cgi->param('sortby') =~ /^(\w+)$/ ) {
+% my $sortby = $1;
+% if ( $sortby eq 'id' ) {
+% $sortby = \*id_sort;
+% }
+% }
+%
+%} elsif ( $cgi->param('svcpart') =~ /^(\d+)$/ ) {
+%
+% @svc_external =
+% qsearch( 'svc_external', {}, '',
+% " WHERE $1 = ( SELECT svcpart FROM cust_svc ".
+% " WHERE cust_svc.svcnum = svc_external.svcnum ) "
+% );
+%
+%} elsif ( $cgi->param('title') =~ /^(.*)$/ ) {
+% $sortby=\*id_sort;
+% @svc_external=qsearch('svc_external',{ title => $1 });
+% if( $cgi->param('history') == 1 ) {
+% @h_svc_external=qsearch('h_svc_external',{ title => $1 });
+% }
+%} elsif ( $cgi->param('id') =~ /^([\w\-\.]+)$/ ) {
+% my $id = $1;
+% @svc_external = qsearchs('svc_external',{'id'=>$id});
+%}
+%
+%if ( scalar(@svc_external) == 1 ) {
+%
+%
+<% $cgi->redirect(popurl(2). "view/svc_external.cgi?". $svc_external[0]->svcnum) %>
+%
+%
+%} elsif ( scalar(@svc_external) == 0 ) {
+%
+%
+<% include('/elements/header.html', 'External Search Results' ) %>
-my $conf = new FS::Conf;
+ No matching external services found
+% } else {
+%
+%
+<% include('/elements/header.html', 'External Search Results', '') %>
-my($query)=$cgi->keywords;
-$query ||= ''; #to avoid use of unitialized value errors
-my(@svc_external,$sortby);
-if ( $query eq 'svcnum' ) {
- $sortby=\*svcnum_sort;
- @svc_external=qsearch('svc_external',{});
-} elsif ( $query eq 'id' ) {
- $sortby=\*id_sort;
- @svc_external=qsearch('svc_external',{});
-} elsif ( $query eq 'UN_svcnum' ) {
- $sortby=\*svcnum_sort;
- @svc_external = grep qsearchs('cust_svc',{
- 'svcnum' => $_->svcnum,
- 'pkgnum' => '',
- }), qsearch('svc_external',{});
-} elsif ( $query eq 'UN_id' ) {
- $sortby=\*id_sort;
- @svc_external = grep qsearchs('cust_svc',{
- 'svcnum' => $_->svcnum,
- 'pkgnum' => '',
- }), qsearch('svc_external',{});
-} elsif ( $cgi->param('svcpart') =~ /^(\d+)$/ ) {
- @svc_external =
- qsearch( 'svc_external', {}, '',
- " WHERE $1 = ( SELECT svcpart FROM cust_svc ".
- " WHERE cust_svc.svcnum = svc_external.svcnum ) "
- );
- $sortby=\*svcnum_sort;
-} else {
- $cgi->param('id') =~ /^([\w\-\.]+)$/;
- my($id)=$1;
- #push @svc_domain, qsearchs('svc_domain',{'domain'=>$domain});
- @svc_external = qsearchs('svc_external',{'id'=>$id});
-}
-
-if ( scalar(@svc_external) == 1 ) {
- print $cgi->redirect(popurl(2). "view/svc_external.cgi?". $svc_external[0]->svcnum);
- #exit;
-} elsif ( scalar(@svc_external) == 0 ) {
-%>
-<!-- mason kludge -->
-<%
- eidiot "No matching external services found!\n";
-} else {
-%>
-<!-- mason kludge -->
-<%= header("External Search Results",'') %>
-
- <%= scalar(@svc_external) %> matching external services found
+ <% scalar(@svc_external) %> matching external services found
<TABLE BORDER=4 CELLSPACING=0 CELLPADDING=0>
<TR>
<TH>Service #</TH>
- <TH><%= FS::Msgcat::_gettext('svc_external-id') || 'External&nbsp;ID' %></TH>
- <TH><%= FS::Msgcat::_gettext('svc_external-title') || 'Title' %></TH>
+ <TH><% FS::Msgcat::_gettext('svc_external-id') || 'External&nbsp;ID' %></TH>
+ <TH><% FS::Msgcat::_gettext('svc_external-title') || 'Title' %></TH>
</TR>
+%
+% foreach my $svc_external (
+% sort $sortby (@svc_external)
+% ) {
+% my($svcnum, $id, $title)=(
+% $svc_external->svcnum,
+% $svc_external->id,
+% $svc_external->title,
+% );
+%
+% my $rowspan = 1;
+%
+% print <<END;
+% <TR>
+% <TD ROWSPAN=$rowspan><A HREF="${p}view/svc_external.cgi?$svcnum">$svcnum</A></TD>
+% <TD ROWSPAN=$rowspan><A HREF="${p}view/svc_external.cgi?$svcnum">$id</A></TD>
+% <TD ROWSPAN=$rowspan><A HREF="${p}view/svc_external.cgi?$svcnum">$title</A></TD>
+%END
+%
+% #print @rows;
+% print "</TR>";
+%
+% }
+% if( scalar(@h_svc_external) > 0 ) {
+% print <<HTML;
+% </TABLE>
+% <TABLE BORDER=4 CELLSPACING=0 CELLPADDING=0>
+% <TR>
+% <TH>Freeside ID</TH>
+% <TH>Service #</TH>
+% <TH>Title</TH>
+% <TH>Date</TH>
+% </TR>
+%HTML
+%
+% foreach my $h_svc ( @h_svc_external ) {
+% my($svcnum, $id, $title, $user, $date)=(
+% $h_svc->svcnum,
+% $h_svc->id,
+% $h_svc->title,
+% $h_svc->history_user,
+% $h_svc->history_date,
+% );
+% my $rowspan = 1;
+% my ($h_cust_svc) = qsearchs( 'h_cust_svc', {
+% svcnum => $svcnum,
+% });
+% my $cust_pkg = qsearchs( 'cust_pkg', {
+% pkgnum => $h_cust_svc->pkgnum,
+% });
+% my $custnum = $cust_pkg->custnum;
+%
+% print <<END;
+% <TR>
+% <TD ROWSPAN=$rowspan><A HREF="${p}view/cust_main.cgi?$custnum">$custnum</A></TD>
+% <TD ROWSPAN=$rowspan><A HREF="${p}view/cust_main.cgi?$custnum">$svcnum</A></TD>
+% <TD ROWSPAN=$rowspan><A HREF="${p}view/cust_main.cgi?$custnum">$title</A></TD>
+% <TD ROWSPAN=$rowspan><A HREF="${p}view/cust_main.cgi?$custnum">$date</A></TD>
+% </TR>
+%END
+% }
+% }
+%
+% print <<END;
+% </TABLE>
+% </BODY>
+%</HTML>
+%END
+%
+%}
+%
+%sub svcnum_sort {
+% $a->getfield('svcnum') <=> $b->getfield('svcnum');
+%}
+%
+%sub id_sort {
+% $a->getfield('id') <=> $b->getfield('id');
+%}
+%
+%
-<%
- foreach my $svc_external (
- sort $sortby (@svc_external)
- ) {
- my($svcnum, $id, $title)=(
- $svc_external->svcnum,
- $svc_external->id,
- $svc_external->title,
- );
-
- my $rowspan = 1;
-
- print <<END;
- <TR>
- <TD ROWSPAN=$rowspan><A HREF="${p}view/svc_external.cgi?$svcnum">$svcnum</A></TD>
- <TD ROWSPAN=$rowspan><A HREF="${p}view/svc_external.cgi?$svcnum">$id</A></TD>
- <TD ROWSPAN=$rowspan><A HREF="${p}view/svc_external.cgi?$svcnum">$title</A></TD>
-END
-
- #print @rows;
- print "</TR>";
-
- }
-
- print <<END;
- </TABLE>
- </BODY>
-</HTML>
-END
-
-}
-
-sub svcnum_sort {
- $a->getfield('svcnum') <=> $b->getfield('svcnum');
-}
-
-sub id_sort {
- $a->getfield('id') <=> $b->getfield('id');
-}
-
-%>
diff --git a/httemplate/search/svc_forward.cgi b/httemplate/search/svc_forward.cgi
index a204e345f..eeb4c1075 100755
--- a/httemplate/search/svc_forward.cgi
+++ b/httemplate/search/svc_forward.cgi
@@ -1,46 +1,95 @@
-<%
+<% include( 'elements/search.html',
+ 'title' => "Mail forward Search Results",
+ 'name' => 'mail forwards',
+ 'query' => $sql_query,
+ 'count_query' => $count_query,
+ 'redirect' => $link,
+ 'header' => [ '#',
+ 'Service',
+ 'Mail to',
+ 'Forwards to',
+ FS::UI::Web::cust_header(),
+ ],
+ 'fields' => [ 'svcnum',
+ 'svc',
+ $format_src,
+ $format_dst,
+ \&FS::UI::Web::cust_fields,
+ ],
+ 'links' => [ $link,
+ $link,
+ $link_src,
+ $link_dst,
+ ( map { $_ ne 'Cust. Status' ? $link_cust : '' }
+ FS::UI::Web::cust_header()
+ ),
+ ],
+ 'align' => 'rlll'. FS::UI::Web::cust_aligns(),
+ 'color' => [
+ '',
+ '',
+ '',
+ '',
+ FS::UI::Web::cust_colors(),
+ ],
+ 'style' => [
+ '',
+ '',
+ '',
+ '',
+ FS::UI::Web::cust_styles(),
+ ],
+ )
+%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('List services');
+
my $conf = new FS::Conf;
-my($query)=$cgi->keywords;
-$query ||= ''; #to avoid use of unitialized value errors
+my $orderby = 'ORDER BY svcnum';
+my @extra_sql = ();
+if ( $cgi->param('magic') =~ /^(all|unlinked)$/ ) {
+ push @extra_sql, 'pkgnum IS NULL'
+ if $cgi->param('magic') eq 'unlinked';
-my $orderby;
+ if ( $cgi->param('sortby') =~ /^(\w+)$/ ) {
+ my $sortby = $1;
+ $orderby = "ORDER BY $sortby";
+ }
-my $cjoin = '';
-my @extra_sql = ();
-if ( $query =~ /^UN_(.*)$/ ) {
- $query = $1;
- $cjoin = 'LEFT JOIN cust_svc USING ( svcnum )';
- push @extra_sql, 'pkgnum IS NULL';
+} elsif ( $cgi->param('svcpart') =~ /^(\d+)$/ ) {
+ push @extra_sql, "svcpart = $1";
}
-if ( $query eq 'svcnum' ) {
- $orderby = 'ORDER BY svcnum';
-} else {
- eidiot('unimplemented');
-}
+my $addl_from = ' LEFT JOIN cust_svc USING ( svcnum ) '.
+ ' LEFT JOIN part_svc USING ( svcpart ) '.
+ ' LEFT JOIN cust_pkg USING ( pkgnum ) '.
+ ' LEFT JOIN cust_main USING ( custnum ) ';
+
+#here is the agent virtualization
+push @extra_sql, $FS::CurrentUser::CurrentUser->agentnums_sql;
my $extra_sql =
scalar(@extra_sql)
? ' WHERE '. join(' AND ', @extra_sql )
: '';
-my $count_query = "SELECT COUNT(*) FROM svc_forward $cjoin $extra_sql";
+my $count_query = "SELECT COUNT(*) FROM svc_forward $addl_from $extra_sql";
my $sql_query = {
'table' => 'svc_forward',
'hashref' => {},
'select' => join(', ',
'svc_forward.*',
- 'cust_main.custnum',
- FS::UI::Web::cust_sql_fields(),
+ 'part_svc.svc',
+ 'cust_main.custnum',
+ FS::UI::Web::cust_sql_fields(),
),
'extra_sql' => "$extra_sql $orderby",
- 'addl_from' => ' LEFT JOIN cust_svc USING ( svcnum ) '.
- ' LEFT JOIN part_svc USING ( svcpart ) '.
- ' LEFT JOIN cust_pkg USING ( pkgnum ) '.
- ' LEFT JOIN cust_main USING ( custnum ) ',
+ 'addl_from' => $addl_from,
};
# <TH>Service #<BR><FONT SIZE=-1>(click to view forward)</FONT></TH>
@@ -93,28 +142,4 @@ my $link_cust = sub {
$svc_x->custnum ? [ "${p}view/cust_main.cgi?", 'custnum' ] : '';
};
-%><%= include( 'elements/search.html',
- 'title' => "Mail forward Search Results",
- 'name' => 'mail forwards',
- 'query' => $sql_query,
- 'count_query' => $count_query,
- 'redirect' => $link,
- 'header' => [ '#',
- 'Mail to',
- 'Forwards to',
- FS::UI::Web::cust_header(),
- ],
- 'fields' => [ 'svcnum',
- $format_src,
- $format_dst,
- \&FS::UI::Web::cust_fields,
- ],
- 'links' => [ $link,
- $link_src,
- $link_dst,
- ( map { $link_cust }
- FS::UI::Web::cust_header()
- ),
- ],
- )
-%>
+</%init>
diff --git a/httemplate/search/svc_phone.cgi b/httemplate/search/svc_phone.cgi
new file mode 100644
index 000000000..0c1d57887
--- /dev/null
+++ b/httemplate/search/svc_phone.cgi
@@ -0,0 +1,115 @@
+<% include( 'elements/search.html',
+ 'title' => "Phone number search results",
+ 'name' => 'phone numbers',
+ 'query' => $sql_query,
+ 'count_query' => $count_query,
+ 'redirect' => $link,
+ 'header' => [ '#',
+ 'Service',
+ 'Country code',
+ 'Phone number',
+ FS::UI::Web::cust_header(),
+ ],
+ 'fields' => [ 'svcnum',
+ 'svc',
+ 'countrycode',
+ 'phonenum',
+ \&FS::UI::Web::cust_fields,
+ ],
+ 'links' => [ $link,
+ $link,
+ $link,
+ $link,
+ ( map { $_ ne 'Cust. Status' ? $link_cust : '' }
+ FS::UI::Web::cust_header()
+ ),
+ ],
+ 'align' => 'rlrr'. FS::UI::Web::cust_aligns(),
+ 'color' => [
+ '',
+ '',
+ '',
+ '',
+ FS::UI::Web::cust_colors(),
+ ],
+ 'style' => [
+ '',
+ '',
+ '',
+ '',
+ FS::UI::Web::cust_styles(),
+ ],
+ )
+%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('List services');
+
+my $conf = new FS::Conf;
+
+my $orderby = 'ORDER BY svcnum';
+my %svc_phone = ();
+my @extra_sql = ();
+if ( $cgi->param('magic') =~ /^(all|unlinked)$/ ) {
+
+ push @extra_sql, 'pkgnum IS NULL'
+ if $cgi->param('magic') eq 'unlinked';
+
+ if ( $cgi->param('sortby') =~ /^(\w+)$/ ) {
+ my $sortby = $1;
+ $orderby = "ORDER BY $sortby";
+ }
+
+} elsif ( $cgi->param('svcpart') =~ /^(\d+)$/ ) {
+ push @extra_sql, "svcpart = $1";
+} else {
+ $cgi->param('phonenum') =~ /^([\d\- ]+)$/;
+ ( $svc_phone{'phonenum'} = $1 ) =~ s/\D//g;
+}
+
+my $addl_from = ' LEFT JOIN cust_svc USING ( svcnum ) '.
+ ' LEFT JOIN part_svc USING ( svcpart ) '.
+ ' LEFT JOIN cust_pkg USING ( pkgnum ) '.
+ ' LEFT JOIN cust_main USING ( custnum ) ';
+
+#here is the agent virtualization
+push @extra_sql, $FS::CurrentUser::CurrentUser->agentnums_sql;
+
+my $extra_sql = '';
+if ( @extra_sql ) {
+ $extra_sql = ( keys(%svc_phone) ? ' AND ' : ' WHERE ' ).
+ join(' AND ', @extra_sql );
+}
+
+my $count_query = "SELECT COUNT(*) FROM svc_phone $addl_from ";
+if ( keys %svc_phone ) {
+ $count_query .= ' WHERE '.
+ join(' AND ', map "$_ = ". dbh->quote($svc_phone{$_}),
+ keys %svc_phone
+ );
+}
+$count_query .= $extra_sql;
+
+my $sql_query = {
+ 'table' => 'svc_phone',
+ 'hashref' => \%svc_phone,
+ 'select' => join(', ',
+ 'svc_phone.*',
+ 'part_svc.svc',
+ 'cust_main.custnum',
+ FS::UI::Web::cust_sql_fields(),
+ ),
+ 'extra_sql' => "$extra_sql $orderby",
+ 'addl_from' => $addl_from,
+};
+
+my $link = [ "${p}view/svc_phone.cgi?", 'svcnum' ];
+
+#smaller false laziness w/svc_*.cgi here
+my $link_cust = sub {
+ my $svc_x = shift;
+ $svc_x->custnum ? [ "${p}view/cust_main.cgi?", 'custnum' ] : '';
+};
+
+</%init>
diff --git a/httemplate/search/svc_www.cgi b/httemplate/search/svc_www.cgi
index ae51c61fc..d9332e95d 100755
--- a/httemplate/search/svc_www.cgi
+++ b/httemplate/search/svc_www.cgi
@@ -1,53 +1,17 @@
-<%
-
-#my $conf = new FS::Conf;
-
-my($query)=$cgi->keywords;
-$query ||= ''; #to avoid use of unitialized value errors
-my $orderby;
-if ( $query eq 'svcnum' ) {
- $orderby = 'ORDER BY svcnum';
-} else {
- eidiot('unimplemented');
-}
-
-my $count_query = 'SELECT COUNT(*) FROM svc_www';
-my $sql_query = {
- 'table' => 'svc_www',
- 'hashref' => {},
- 'select' => join(', ',
- 'svc_www.*',
- 'cust_main.custnum',
- FS::UI::Web::cust_sql_fields(),
- ),
- 'extra_sql' => $orderby,
- 'addl_from' => 'LEFT JOIN cust_svc USING ( svcnum )'.
- 'LEFT JOIN cust_pkg USING ( pkgnum )'.
- 'LEFT JOIN cust_main USING ( custnum )',
-};
-
-my $link = [ "${p}view/svc_www.cgi?", 'svcnum', ];
-#my $dlink = [ "${p}view/svc_www.cgi?", 'svcnum', ];
-my $ulink = [ "${p}view/svc_acct.cgi?", 'usersvc', ];
-
-#smaller false laziness w/svc_*.cgi here
-my $link_cust = sub {
- my $svc_x = shift;
- $svc_x->custnum ? [ "${p}view/cust_main.cgi?", 'custnum' ] : '';
-};
-
-%><%= include( 'elements/search.html',
+<% include( 'elements/search.html',
'title' => 'Virtual Host Search Results',
'name' => 'virtual hosts',
'query' => $sql_query,
'count_query' => $count_query,
'redirect' => $link,
'header' => [ '#',
+ 'Service',
'Zone',
'User',
FS::UI::Web::cust_header(),
],
'fields' => [ 'svcnum',
+ 'svc',
sub { $_[0]->domain_record->zone },
sub {
my $svc_www = shift;
@@ -59,11 +23,89 @@ my $link_cust = sub {
\&FS::UI::Web::cust_fields,
],
'links' => [ $link,
+ $link,
'',
$ulink,
- ( map { $link_cust }
+ ( map { $_ ne 'Cust. Status' ? $link_cust : '' }
FS::UI::Web::cust_header()
),
],
+ 'align' => 'rlll'. FS::UI::Web::cust_aligns(),
+ 'color' => [
+ '',
+ '',
+ '',
+ '',
+ FS::UI::Web::cust_colors(),
+ ],
+ 'style' => [
+ '',
+ '',
+ '',
+ '',
+ FS::UI::Web::cust_styles(),
+ ],
)
%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('List services');
+
+#my $conf = new FS::Conf;
+
+my $orderby = 'ORDER BY svcnum';
+my @extra_sql = ();
+if ( $cgi->param('magic') =~ /^(all|unlinked)$/ ) {
+
+ push @extra_sql, 'pkgnum IS NULL'
+ if $cgi->param('magic') eq 'unlinked';
+
+ if ( $cgi->param('sortby') =~ /^(\w+)$/ ) {
+ my $sortby = $1;
+ $orderby = "ORDER BY $sortby";
+ }
+
+} elsif ( $cgi->param('svcpart') =~ /^(\d+)$/ ) {
+ push @extra_sql, "svcpart = $1";
+}
+
+my $addl_from = ' LEFT JOIN cust_svc USING ( svcnum ) '.
+ ' LEFT JOIN part_svc USING ( svcpart ) '.
+ ' LEFT JOIN cust_pkg USING ( pkgnum ) '.
+ ' LEFT JOIN cust_main USING ( custnum ) ';
+
+#here is the agent virtualization
+push @extra_sql, $FS::CurrentUser::CurrentUser->agentnums_sql;
+
+my $extra_sql =
+ scalar(@extra_sql)
+ ? ' WHERE '. join(' AND ', @extra_sql )
+ : '';
+
+
+my $count_query = "SELECT COUNT(*) FROM svc_www $addl_from $extra_sql";
+my $sql_query = {
+ 'table' => 'svc_www',
+ 'hashref' => {},
+ 'select' => join(', ',
+ 'svc_www.*',
+ 'part_svc.svc',
+ 'cust_main.custnum',
+ FS::UI::Web::cust_sql_fields(),
+ ),
+ 'extra_sql' => "$extra_sql $orderby",
+ 'addl_from' => $addl_from,
+};
+
+my $link = [ "${p}view/svc_www.cgi?", 'svcnum', ];
+#my $dlink = [ "${p}view/svc_www.cgi?", 'svcnum', ];
+my $ulink = [ "${p}view/svc_acct.cgi?", 'usersvc', ];
+
+#smaller false laziness w/svc_*.cgi here
+my $link_cust = sub {
+ my $svc_x = shift;
+ $svc_x->custnum ? [ "${p}view/cust_main.cgi?", 'custnum' ] : '';
+};
+
+</%init>