diff options
Diffstat (limited to 'httemplate/search')
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> </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> </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> </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> </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> </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> </TD>!; +% } +% +% #print qq!</TR><TR>\n!; +% $n1="</TR><TR>"; +% } +% +% unless ( @{$all_pkgs{$custnum}} ) { +% print qq!<TD CLASS="grid" BGCOLOR="$bgcolor" COLSPAN=3> </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! ( <A HREF="$p/misc/queue.cgi?jobnum=$jobnum&action=new">retry</A> |!. + qq! <A HREF="$p/misc/queue.cgi?jobnum=$jobnum&action=del">remove</A> )!; + } + $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> </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 : ' '; }, +% '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 ' ' unless exists $user2svc_acct{$session->{'username'}}; + my $svc_acct = $user2svc_acct{$session->{'username'}}; + my $cust_pkg = $svc_acct->cust_svc->cust_pkg; + return ' ' 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 ' ' if $time == 0; + my $pretty = time2str('%T%P %a %b %o %Y', $time ); + $pretty =~ s/ (\d)(st|dn|rd|th)/$1$2/; + $pretty; +}; - }; - - my $customer_format = sub { - my( $unused, $session ) = @_; - return ' ' unless exists $user2svc_acct{$session->{'username'}}; - my $svc_acct = $user2svc_acct{$session->{'username'}}; - my $cust_pkg = $svc_acct->cust_svc->cust_pkg; - return ' ' 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 ' ' if $time == 0; - my $pretty = time2str('%T%P %a %b %o %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" : ' ' ). - '</TD><TD ALIGN="right">'. - ( ( $hour || $min ) ? "<B>$min</B>m" : ' ' ). - '</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> 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 Address', - attrib => 'Framed-IP-Address', - fmt => sub { my $ip = shift; - length($ip) ? $ip : ' '; - }, - align => 'right', - }, - 'acctstarttime' => { - name => 'Start time', - attrib => 'Acct-Start-Time', - fmt => $time_format, - align => 'left', - }, - 'acctstoptime' => { - name => 'End 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 : ' '; } - 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 : ' '; }, - '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" : ' ' ). + '</TD><TD CLASS="inv" ALIGN="right">'. + ( ( $hour || $min ) ? "<B>$min</B>m" : ' ' ). + '</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> 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 Address', + attrib => 'Framed-IP-Address', + fmt => sub { my $ip = shift; + length($ip) ? $ip : ' '; + }, + align => 'right', + }, + 'acctstarttime' => { + name => 'Start time', + attrib => 'Acct-Start-Time', + fmt => $time_format, + align => 'left', + }, + 'acctstoptime' => { + name => 'End 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 : ' '; } + 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 ID' %></TH> - <TH><%= FS::Msgcat::_gettext('svc_external-title') || 'Title' %></TH> + <TH><% FS::Msgcat::_gettext('svc_external-id') || 'External 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> |