diff options
Diffstat (limited to 'httemplate')
-rw-r--r-- | httemplate/edit/cust_location-censustract.html | 66 | ||||
-rw-r--r-- | httemplate/edit/process/bulk-477_cust_pkg.html | 20 | ||||
-rw-r--r-- | httemplate/edit/process/cust_location-censustract.html | 34 | ||||
-rw-r--r-- | httemplate/graph/cust_bill_pkg_discount.html | 2 | ||||
-rw-r--r-- | httemplate/graph/report_cust_bill_pkg_discount.html | 2 | ||||
-rw-r--r-- | httemplate/search/477.html | 46 | ||||
-rw-r--r-- | httemplate/search/477_cust_pkg.html | 228 | ||||
-rw-r--r-- | httemplate/search/cust_bill_pkg.cgi | 62 | ||||
-rw-r--r-- | httemplate/search/report_tax.cgi | 9 |
9 files changed, 434 insertions, 35 deletions
diff --git a/httemplate/edit/cust_location-censustract.html b/httemplate/edit/cust_location-censustract.html new file mode 100644 index 000000000..bdb9823fa --- /dev/null +++ b/httemplate/edit/cust_location-censustract.html @@ -0,0 +1,66 @@ +<% include('/elements/header-popup.html', "Edit Census Tract") %> + +<% include('/elements/error.html') %> + +<FORM NAME="EditLocationForm" +ACTION="<% $p %>edit/process/cust_location-censustract.html" METHOD=POST> +<INPUT TYPE="hidden" NAME="locationnum" VALUE="<% $locationnum %>"> + +<% ntable('#cccccc') %> +<& /elements/location.html, + 'object' => $cust_location, + 'no_asterisks' => 1, + 'enable_censustract' => 1, + 'disabled' => 'DISABLED', +&> +<& /elements/standardize_locations.html, + 'form' => 'EditLocationForm', + 'callback' => 'document.EditLocationForm.submit();', + 'with_census' => 1, + 'with_census_functions' => 1, +&> +</TABLE> + +<BR> +<SCRIPT TYPE="text/javascript"> +<&| /elements/onload.js &> + document.getElementById('enter_censustract').disabled = false; +</&> +function go() { + confirm_censustract(); +} + +function submit_abort() { + nd(1); +} +</SCRIPT> +<INPUT TYPE="button" NAME="submitButton" VALUE="Submit" onclick="go()"> +</FORM> +</BODY> +</HTML> + +<%init> + +my $conf = new FS::Conf; + +my $curuser = $FS::CurrentUser::CurrentUser; + +# it's the same access right you'd need to do this by editing packages +die "access denied" + unless $curuser->access_right('Change customer package'); + +my $locationnum = scalar($cgi->param('locationnum')); +my $cust_location = qsearchs({ + 'select' => 'cust_location.*', + 'table' => 'cust_location', + 'addl_from' => 'LEFT JOIN cust_main USING ( custnum )', + 'hashref' => { 'locationnum' => $locationnum }, + 'extra_sql' => ' AND '. $curuser->agentnums_sql, + }) or die "unknown locationnum $locationnum"; + +# unlike the regular one, this allows editing disabled locations + +my $cust_main = qsearchs('cust_main', { 'custnum' => $cust_location->custnum }) + or die "can't get cust_main record for custnum ". $cust_location->custnum; + +</%init> diff --git a/httemplate/edit/process/bulk-477_cust_pkg.html b/httemplate/edit/process/bulk-477_cust_pkg.html new file mode 100644 index 000000000..064f73b60 --- /dev/null +++ b/httemplate/edit/process/bulk-477_cust_pkg.html @@ -0,0 +1,20 @@ +<% $cgi->redirect($fsurl.'search/477_cust_pkg.html?redirect='.$session) %> +<%init> +my $curuser = $FS::CurrentUser::CurrentUser; +my $edit_acl = $curuser->access_right('Edit FCC report configuration'); +my $global_edit_acl = $curuser->access_right('Edit FCC report configuration for all agents'); +die "access denied" unless $edit_acl or $global_edit_acl; + +my %error; +foreach my $param ($cgi->param) { + $param =~ /^pkgnum(\d+)pkgpart(\d+)$/ or next; + my $pkgpart = $2; + my $part_pkg = FS::part_pkg->by_key($pkgpart); + my $hashref = decode_json( $cgi->param($param) ); + my $error = $part_pkg->set_fcc_options($hashref); + $error{$pkgpart} = $error if $error; # XXX report this somehow +} + +my $session = $cgi->param('redirect'); + +</%init> diff --git a/httemplate/edit/process/cust_location-censustract.html b/httemplate/edit/process/cust_location-censustract.html new file mode 100644 index 000000000..bc9cd4f31 --- /dev/null +++ b/httemplate/edit/process/cust_location-censustract.html @@ -0,0 +1,34 @@ +% if ($error) { +% $cgi->param('error', $error); +% $cgi->redirect(popurl(3). 'edit/cust_location-censustract.html?'. $cgi->query_string ); +% } else { + + <% header("Census tract changed") %> + <SCRIPT TYPE="text/javascript"> + window.top.location.reload(); + </SCRIPT> + </BODY> + </HTML> + +% } +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right('Change customer package'); + +my $locationnum = $cgi->param('locationnum'); +my $cust_location = qsearchs({ + 'select' => 'cust_location.*', + 'table' => 'cust_location', + 'addl_from' => 'LEFT JOIN cust_main USING ( custnum )', + 'hashref' => { 'locationnum' => $locationnum }, + 'extra_sql' => ' AND '. $curuser->agentnums_sql, +}); +die "unknown locationnum $locationnum" unless $cust_location; + +$cust_location->set('censustract', $cgi->param('censustract')); +my $error = $cust_location->replace; + +</%init> diff --git a/httemplate/graph/cust_bill_pkg_discount.html b/httemplate/graph/cust_bill_pkg_discount.html index 0d66799a9..5074aa35c 100644 --- a/httemplate/graph/cust_bill_pkg_discount.html +++ b/httemplate/graph/cust_bill_pkg_discount.html @@ -74,7 +74,7 @@ foreach my $agent ( $sel_agent || qsearch('agent', { 'disabled' => '' } ) ) { #'average_per_cust_pkg' => $average_per_cust_pkg, ]; - push @links, "$link?agentnum=$row_agentnum"; #;classnum=$row_classnum;"; + push @links, $link . "agentnum=$row_agentnum;"; @_colors = ($col_scheme->colors)[0,4,8,1,5,9,2,6,10,3,7,11]; push @colors, shift @_colors; diff --git a/httemplate/graph/report_cust_bill_pkg_discount.html b/httemplate/graph/report_cust_bill_pkg_discount.html index 6de84f80b..36ad78252 100644 --- a/httemplate/graph/report_cust_bill_pkg_discount.html +++ b/httemplate/graph/report_cust_bill_pkg_discount.html @@ -1,4 +1,4 @@ -<& /elements/header.html', 'Discount Report' &> +<& /elements/header.html, 'Discount Report' &> <FORM ACTION="cust_bill_pkg_discount.html" METHOD="GET"> diff --git a/httemplate/search/477.html b/httemplate/search/477.html index ff2ac8638..2e9f9428e 100644 --- a/httemplate/search/477.html +++ b/httemplate/search/477.html @@ -32,26 +32,54 @@ table.fcc477part thead tr.subhead { font-size: large; float: left; } +.errortitle { + font-weight: bold; + color: #ff0000; +} +tr.error td { + background-color: #ffdddd; +} +tr.error td.error { + text-align: left; + border: none; +} +tr.error ul { + margin: 0px; + list-style-image: url("<% $fsurl %>images/cross.png"); +} a.download { float: right; } </STYLE> % foreach my $partname (@partnames) { +% my $this_part = $parts{$partname}; % $cgi->param('parts', $partname); % $cgi->param('type', 'csv'); <table class="fcc477part"> <caption> <span class="parttitle"><% $part_titles->{$partname} %></span> +% if ( $this_part->{num_errors} > 0 ) { +% # disable downloading while it contains errors + <span class="errortitle"> + <% emt('This section contains [quant,_1,error].', $this_part->{num_errors}) %> + </span> +% } else { <a class="download" href="<% $cgi->self_url %>">Download</a> +% } </caption> % my $header = ".header_$partname"; -% my $data = $parts{$partname}; +% my $data = $this_part->{data}; +% my $error = $this_part->{error}; <thead> <& $header &> </thead> % my $rownum = 0; % foreach my $row (@$data) { - <tr> +% my %eh; # error hash +% if ( $error->[$rownum] ) { +% %eh = %{ $error->[$rownum] }; +% } + <tr<% keys(%eh) ? ' class="error"' : ''%>> % my $first = 1; % foreach my $item (@$row) { <td> @@ -63,6 +91,14 @@ a.download { % } </td> % } #foreach $item +% # display errors +% if ( keys %eh ) { + <td class="error"><ul> +% foreach my $key (sort keys %eh) { + <li><% $eh{$key} %></li> +% } + </ul></td> +% } # if there are errors </tr> % $rownum++; % } #foreach $row @@ -98,10 +134,10 @@ foreach my $partname (@partnames) { date => $date, agentnum => $agentnum, ignore_quantity => $ignore_quantity, - ); + ); # includes error, detail, and data parts my $detail_table = FS::Report::FCC_477->part_table($partname); if ($detail_table eq 'cust_pkg') { - my $link = popurl(1).'cust_pkg.cgi?477part='.$partname.";date=$date;"; + my $link = popurl(1).'477_cust_pkg.html?477part='.$partname.";date=$date;"; if ($agentnum) { $link .= "agentnum=$agentnum;"; } @@ -114,7 +150,7 @@ my $title = 'FCC Form 477 Data - ' . time2str('%b %o, %Y', $date); if ( $cgi->param('type') eq 'csv' ) { my $partname = $partnames[0]; # ignore any beyond the first - my $data = $parts{$partname}; + my $data = $parts{$partname}->{data}; my $csv = Text::CSV_XS->new({ eol => "\r\n" }); # i think my $filename = time2str('%Y-%m-%d', $date) . '-'. $partname . '.csv'; diff --git a/httemplate/search/477_cust_pkg.html b/httemplate/search/477_cust_pkg.html new file mode 100644 index 000000000..b8df9fd0f --- /dev/null +++ b/httemplate/search/477_cust_pkg.html @@ -0,0 +1,228 @@ +<& elements/search.html, + 'html_init' => $html_init, + 'html_form' => $html_form, + 'html_foot' => '</FORM>', + 'title' => emt('Package Search Results'), + 'name' => 'packages', + 'query' => $query, + 'count_query' => $count_query, + 'header' => [ emt('#'), + emt('Quan.'), + emt('Package'), + emt('Class'), + emt('Status'), + emt('Freq.'), + emt('Setup'), + emt('Next bill'), + emt('Susp.'), + emt('Changed'), + emt('Cancel'), + FS::UI::Web::cust_header(), + emt('Census tract'), + emt('Package options'), + ], + 'fields' => [ + 'pkgnum', + 'quantity', + sub { $_[0]->pkg; }, + 'classname', + sub { ucfirst(shift->status); }, + sub { FS::part_pkg::freq_pretty(shift); }, + + ( map { time_or_blank($_) } + qw( setup bill susp change_date cancel ) ), + + \&FS::UI::Web::cust_fields, + + sub { # census tract + my $cust_pkg = shift; + my $cust_location = $cust_pkg->cust_location; + ($cust_location->censustract || '<b>unknown</b>'). + '<font size="-1"> (edit)</font>'; + }, + + # a hidden input in each row with the pkgnum, so that + # we can refresh back to this list of pkgnums + sub { + my $cust_pkg = shift; + my $part_pkg = $cust_pkg->part_pkg; + my %hash = $part_pkg->fcc_options; + '<INPUT NAME="pkgnum" TYPE="hidden" VALUE="' . + $cust_pkg->pkgnum . '">' . + include('/elements/input-fcc_options.html', + id => 'pkgnum'.$cust_pkg->pkgnum. + 'pkgpart'.$part_pkg->pkgpart, + curr_value => encode_json(\%hash), + html_only => 1 + ) + }, + ], + 'color' => [ + '', + '', + '', + '', + sub { shift->statuscolor; }, + '', '', '', '', '', '', + FS::UI::Web::cust_colors(), + '', + '', + ], + 'style' => [ '', '', '', '', 'b', + '', '', '', '', '', '', + FS::UI::Web::cust_styles() ], + 'size' => [ '', '', '', '', '-1' ], + 'align' => 'rrlcccrrrrr'. FS::UI::Web::cust_aligns(). 'cl', + 'links' => [ + $link, + $link, + $link, + '', '', '', '', '', '', '', '', + ( map { $_ ne 'Cust. Status' ? $clink : '' } + FS::UI::Web::cust_header() + ), + '', + '', + ], + 'link_onclicks' => [ + (('') x 11), + (map { '' } FS::UI::Web::cust_header()), + $pkg_edit_location_link, + '', + ], + +&> +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; +my $edit = 'Edit FCC report configuration'; +my $edit_global = 'Edit FCC report configuration for all agents'; +my $acl_edit = $curuser->access_right($edit); +my $acl_edit_global = $curuser->access_right($edit_global); + +die "access denied" + unless $acl_edit || $acl_edit_global; + +my $conf = new FS::Conf; + +my $session; + +my ($query, $count_query); + +if ( $cgi->param('redirect') ) { # then restore the pkgnum list + $session = $cgi->param('redirect'); + my $pref = $curuser->option("redirect$session"); # contains a list of pkgnums + die "unknown redirect session $session\n" unless length($pref); + my @pkgnums = grep /^\d+$/, split(',', $pref); + + $query = FS::cust_pkg->search({}); + $count_query = delete($query->{count_query}); + + my $where = "cust_pkg.pkgnum IN (".join(',', @pkgnums).")"; + if ( $count_query =~ /WHERE/i ) { + $where = " AND ($where) "; + } else { + $where = " WHERE ($where) "; + } + $query->{extra_sql} .= $where; + $count_query .= $where; +} else { + # build and run the query right now, and then cache the pkgnums it returned + my %search_hash = (); + + #scalars + for (qw( agentnum 477part 477rownum date )) { + $search_hash{$_} = $cgi->param($_) if length($cgi->param($_)); + } + + $query = FS::cust_pkg->search(\%search_hash); + $count_query = delete($query->{'count_query'}); + + my @cust_pkg = qsearch($query); + + my $pkgnums = join(',', map { $_->pkgnum } @cust_pkg); + $session = int(rand(4294967296)); #XXX + my $pref = new FS::access_user_pref({ + 'usernum' => $FS::CurrentUser::CurrentUser->usernum, + 'prefname' => "redirect$session", + 'prefvalue' => $pkgnums, + 'expiration' => time + 3600, #1h? 1m? + }); + my $pref_error = $pref->insert; + if ($pref_error) { + die "couldn't even set redirect cookie: $pref_error\n"; + } + + # and then bail out and reload using the redirect cookie + $cgi->delete_all(); + $cgi->param("redirect", $session); + $m->clear_buffer; + $m->print( $cgi->redirect($cgi->self_url) ); + $m->abort; +} + +my $show = $curuser->default_customer_view =~ /^(jumbo|packages)$/ + ? '' + : ';show=packages'; + +my $link = sub { + my $self = shift; + my $frag = 'cust_pkg'. $self->pkgnum; #hack for IE ignoring real #fragment + [ "${p}view/cust_main.cgi?custnum=".$self->custnum. + "$show;fragment=$frag#cust_pkg", + 'pkgnum' + ]; +}; + +my $html_init = + include('/elements/init_overlib.html') . + include('/elements/input-fcc_options.html', js_only => 1) . + include('.style') . + include('.script'); + +my $clink = sub { + my $cust_pkg = shift; + $cust_pkg->cust_main_custnum + ? [ "${p}view/cust_main.cgi?", 'custnum' ] + : ''; +}; + +my $html_form = qq! + <FORM ACTION="${p}edit/process/bulk-477_cust_pkg.html" METHOD="POST" NAME="477_cust_pkg"> + <INPUT NAME="redirect" TYPE="hidden" VALUE="$session"> +!; + +my $pkg_edit_location_link = sub { + my $cust_pkg = shift; + my $locationnum = $cust_pkg->locationnum; + include('/elements/popup_link_onclick.html', + 'action' => $p. "edit/cust_location-censustract.html?locationnum=$locationnum", + 'actionlabel' => emt('Edit census tract'), + 'width' => 700, + 'height' => 355, + ); +}; + +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> +<%def .style> +<style> + button.edit_fcc_button { float: right; } +</style> +</%def> +<%def .script> +<script type="text/javascript"> + function finish_edit_fcc(id) { + cClick(); + document.forms['477_cust_pkg'].submit(); //immediately save/refresh + } +</script> +</%def> diff --git a/httemplate/search/cust_bill_pkg.cgi b/httemplate/search/cust_bill_pkg.cgi index 67f618cdb..2d64466e1 100644 --- a/httemplate/search/cust_bill_pkg.cgi +++ b/httemplate/search/cust_bill_pkg.cgi @@ -338,7 +338,7 @@ if ( $cgi->param('nottax') ) { # 0: empty class # N: classnum if ( grep { $_ eq 'classnum' } $cgi->param ) { - my @classnums = grep /^\d*$/, $cgi->param('classnum'); + my @classnums = grep /^\d+$/, $cgi->param('classnum'); push @where, "COALESCE(part_fee.classnum, $part_pkg.classnum, 0) IN ( ". join(',', @classnums ). ' )' @@ -422,7 +422,6 @@ if ( $cgi->param('nottax') ) { # If we're showing 'out' (items that aren't region/class taxable), # then we need the set of all items minus the union of those. - if ( $cgi->param('out') ) { # separate from the rest, in that we're not going to join cust_main_county # in the outer query @@ -448,31 +447,39 @@ if ( $cgi->param('nottax') ) { # everything that returns things joined to a tax definition my $exempt_sub; - if ( @exempt_where or @tax_where or $cgi->param('taxable') ) { - # process exemption restrictions, including @tax_where - my $exempt_sub = 'SELECT SUM(amount) as exempt_amount, billpkgnum - FROM cust_tax_exempt_pkg JOIN cust_main_county USING (taxnum)'; + # process exemption restrictions, including @tax_where + my $exempt_sub = 'SELECT SUM(amount) as exempt_amount, billpkgnum + FROM cust_tax_exempt_pkg JOIN cust_main_county USING (taxnum)'; - $exempt_sub .= ' WHERE '.join(' AND ', @tax_where, @exempt_where) - if (@tax_where or @exempt_where); + $exempt_sub .= ' WHERE '.join(' AND ', @tax_where, @exempt_where) + if (@tax_where or @exempt_where); - $exempt_sub .= ' GROUP BY billpkgnum'; + $exempt_sub .= ' GROUP BY billpkgnum'; - $join_pkg .= " LEFT JOIN ($exempt_sub) AS item_exempt - USING (billpkgnum)"; + $join_pkg .= " LEFT JOIN ($exempt_sub) AS item_exempt + ON (cust_bill_pkg.billpkgnum = item_exempt.billpkgnum)"; + + my $credit_sub = 'SELECT SUM(amount) AS credit_amount, billpkgnum + FROM cust_credit_bill_pkg GROUP BY billpkgnum'; + + $join_pkg .= " LEFT JOIN ($credit_sub) AS item_credit + ON (cust_bill_pkg.billpkgnum = item_credit.billpkgnum)"; + if ( @tax_where or $cgi->param('taxable') ) { # process tax restrictions unshift @tax_where, - 'cust_bill_pkg_tax_location.taxable_billpkgnum = cust_bill_pkg.billpkgnum', 'cust_main_county.tax > 0'; - } - my $tax_sub = "SELECT 1 + my $tax_sub = "SELECT taxable_billpkgnum AS billpkgnum FROM cust_bill_pkg_tax_location - JOIN cust_bill_pkg AS tax_item USING (billpkgnum) JOIN cust_main_county USING (taxnum) - WHERE ". join(' AND ', @tax_where); + WHERE ". join(' AND ', @tax_where). + " GROUP BY taxable_billpkgnum"; + + $join_pkg .= " LEFT JOIN ($tax_sub) AS item_tax + ON (cust_bill_pkg.billpkgnum = item_tax.billpkgnum)" + } # now do something with that if ( @exempt_where ) { @@ -484,23 +491,28 @@ if ( $cgi->param('nottax') ) { push @total, 'SUM(exempt_amount)'; push @total_desc, "$money_char%.2f tax-exempt"; - } elsif ( $cgi->param('taxable') ) { + } elsif ( @tax_where or $cgi->param('taxable') ) { my $taxable = 'cust_bill_pkg.setup + cust_bill_pkg.recur '. - '- COALESCE(item_exempt.exempt_amount, 0)'; + '- COALESCE(item_exempt.exempt_amount, 0) '. + '- COALESCE(item_credit.credit_amount, 0)'; + push @where, "(item_tax.billpkgnum IS NOT NULL OR item_exempt.billpkgnum IS NOT NULL)"; push @select, "($taxable) AS taxable_amount"; - push @where, "EXISTS($tax_sub)"; push @peritem, 'taxable_amount'; push @peritem_desc, 'Taxable'; - push @total, "SUM($taxable)"; - push @total_desc, "$money_char%.2f taxable"; - - } elsif ( @tax_where ) { - # union of taxable + all exempt_ cases - push @where, "(EXISTS($tax_sub) OR item_exempt.billpkgnum IS NOT NULL)"; + if ( $cgi->param('taxable') ) { + push @where, "($taxable) > 0"; + } else { + push @total, 'SUM('. + 'cust_bill_pkg.setup + cust_bill_pkg.recur '. + '- COALESCE(item_credit.credit_amount, 0) )'; + push @total_desc, "$money_char%.2f net sales"; + } + push @total, "SUM($taxable)"; + push @total_desc, "$money_char%.2f taxable"; } } # handle all joins to cust_main_county diff --git a/httemplate/search/report_tax.cgi b/httemplate/search/report_tax.cgi index 3e9d7653a..83f2fc5d3 100644 --- a/httemplate/search/report_tax.cgi +++ b/httemplate/search/report_tax.cgi @@ -73,8 +73,9 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px } % # construct base links that limit to the tax rates described by this row % my $rowlink = ';taxnum=' . $row->{taxnums}; % # and also the package class, if we're limiting package class -% $rowlink .= ';pkgclass='.$row->{pkgclass} -% if $params{breakdown}->{pkgclass}; +% if ( $params{breakdown}->{pkgclass} ) { +% $rowlink .= ';classnum=' . ($row->{pkgclass} || 0); +% } % % if ( $row->{total} ) { </TBODY><TBODY CLASS="total"> @@ -210,7 +211,9 @@ my $money_sprintf = sub { }; my $dateagentlink = "begin=$beginning;end=$ending"; -$dateagentlink .= $params{agentnum} if $params{agentnum}; +if ( $params{agentnum} ) { + $dateagentlink .= ';agentnum=' . $params{agentnum}; +} my $saleslink = $p. "search/cust_bill_pkg.cgi?$dateagentlink;nottax=1"; my $taxlink = $p. "search/cust_bill_pkg.cgi?$dateagentlink;istax=1"; my $exemptlink = $p. "search/cust_tax_exempt_pkg.cgi?$dateagentlink"; |