From 4a6b0868fabbc617f05b1f9981c52b28d3cb2bcb Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Wed, 12 Aug 2015 21:48:43 -0500 Subject: RT#25026: Option to include taxes in sales report --- httemplate/graph/cust_bill_pkg.cgi | 18 ++++++++++++++---- httemplate/graph/report_cust_bill_pkg.html | 7 ++++++- httemplate/search/cust_bill_pkg.cgi | 12 ------------ 3 files changed, 20 insertions(+), 17 deletions(-) (limited to 'httemplate') diff --git a/httemplate/graph/cust_bill_pkg.cgi b/httemplate/graph/cust_bill_pkg.cgi index b5486f4af..83eb0e837 100644 --- a/httemplate/graph/cust_bill_pkg.cgi +++ b/httemplate/graph/cust_bill_pkg.cgi @@ -1,5 +1,4 @@ <% include('elements/monthly.html', - #Dumper( 'title' => $title, 'graph_type' => $graph_type, 'items' => \@items, @@ -28,6 +27,7 @@ my $bottom_link = "$link;"; my $use_usage = $cgi->param('use_usage') || 0; my $use_setup = $cgi->param('use_setup') || 0; my $use_discount = $cgi->param('use_discount') || 2; +my $use_taxes = $cgi->param('use_taxes') || 0; my $use_override = $cgi->param('use_override') ? 1 : 0; my $average_per_cust_pkg = $cgi->param('average_per_cust_pkg') ? 1 : 0; @@ -50,6 +50,7 @@ my %charge_labels = ( 'R' => 'recurring', 'U' => 'usage', 'D' => 'discount', + 'T' => 'taxes', ); #XXX or virtual @@ -194,8 +195,14 @@ if ( $use_discount == 1 ) { push @components, 'D'; } # else leave discounts off entirely; never combine them with setup/recur +# could in theory combine with setup/recur/usage, +# but would require reverse engineering the tax calculation +if ( $use_taxes == 1 ) { + push @components, 'T'; +} + # Categorization of line items goes -# Agent -> Referral -> Package class -> Component (setup/recur/usage) +# Agent -> Referral -> Package class -> Component (setup/recur/usage/discount/taxes) # If per-agent totals are enabled, they go under the Agent level. # There aren't any other kinds of subtotals. @@ -255,6 +262,8 @@ foreach my $agent ( $all_agent || $sel_agent || $FS::CurrentUser::CurrentUser->a if ( $component eq 'D' ) { # discounts ignore 'charges' and 'distribute' $row_link = "${p}search/cust_bill_pkg_discount.html?"; + } elsif ( $component eq 'T' ) { + $row_link = "${p}search/cust_bill_pkg.cgi?istax=1;"; } $row_link .= ($all_agent ? '' : "agentnum=$row_agentnum;"). @@ -314,6 +323,8 @@ foreach my $agent ( $all_agent || $sel_agent || $FS::CurrentUser::CurrentUser->a if ( $component eq 'D' ) { # discounts ignore 'charges' and 'distribute' $row_link ="${p}search/cust_bill_pkg_discount.html?"; + } elsif ( $component eq 'T' ) { + $row_link = "${p}search/cust_bill_pkg.cgi?istax=1;"; } $row_link .= ($all_agent ? '' : "agentnum=$row_agentnum;"). @@ -386,9 +397,8 @@ foreach my $agent ( $all_agent || $sel_agent || $FS::CurrentUser::CurrentUser->a $anum++; -} +} # foreach $agent -#use Data::Dumper; if ( $cgi->param('debug') == 1 ) { $FS::Report::Table::DEBUG = 1; } diff --git a/httemplate/graph/report_cust_bill_pkg.html b/httemplate/graph/report_cust_bill_pkg.html index 1db86e393..96bfdc09a 100644 --- a/httemplate/graph/report_cust_bill_pkg.html +++ b/httemplate/graph/report_cust_bill_pkg.html @@ -165,7 +165,6 @@ window.onload = class_mode_changed; -   @@ -196,6 +195,12 @@ window.onload = class_mode_changed; 'options' => [ 1, 2 ], 'labels' => { 1 => 'Separate', 2 => 'Do not show' }, &> +<& /elements/tr-select.html, + 'label' => 'Taxes', + 'field' => 'use_taxes', + 'options' => [ 1, 2 ], + 'labels' => { 1 => 'Separate', 2 => 'Do not show' }, +&> Colors diff --git a/httemplate/search/cust_bill_pkg.cgi b/httemplate/search/cust_bill_pkg.cgi index 82e87fba9..c59a6d0e7 100644 --- a/httemplate/search/cust_bill_pkg.cgi +++ b/httemplate/search/cust_bill_pkg.cgi @@ -659,18 +659,6 @@ if ( $cgi->param('nottax') ) { } #end of "normal case" - # classnum (of underlying package) - # not specified: all classes - # 0: empty class - # N: classnum - if ( grep { $_ eq 'classnum' } $cgi->param ) { - my @classnums = grep /^\d+$/, $cgi->param('classnum'); - push @where, "COALESCE(part_fee.classnum, $part_pkg.classnum, 0) IN ( ". - join(',', @classnums ). - ' )' - if @classnums; - } - } # nottax / istax -- cgit v1.2.1 From 039381569561964c572407409fe61f6d4da97afe Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Fri, 14 Aug 2015 14:43:02 -0700 Subject: fix anomalous behavior in line item report with consolidated taxes, needed for #26770, from...#18676, I think? --- httemplate/search/cust_bill_pkg.cgi | 181 +++++++++++++---------------------- httemplate/search/report_tax-xls.cgi | 9 +- httemplate/search/report_tax.cgi | 21 ++-- 3 files changed, 87 insertions(+), 124 deletions(-) (limited to 'httemplate') diff --git a/httemplate/search/cust_bill_pkg.cgi b/httemplate/search/cust_bill_pkg.cgi index c59a6d0e7..ac686eab8 100644 --- a/httemplate/search/cust_bill_pkg.cgi +++ b/httemplate/search/cust_bill_pkg.cgi @@ -461,6 +461,9 @@ if ( $cgi->param('nottax') ) { } + # This is the only place we should attempt to show credits on here: + # the total of credit applications to the line item. + my $credit_sub = 'SELECT SUM(amount) AS credit_amount, billpkgnum FROM cust_credit_bill_pkg GROUP BY billpkgnum'; @@ -579,51 +582,51 @@ if ( $cgi->param('nottax') ) { } elsif ( $cgi->param('istax') ) { - @peritem = ( 'setup' ); # taxes only have setup - @peritem_desc = ( 'Tax charge' ); + # ensure that it is a tax: + push @where, 'cust_bill_pkg.pkgnum = 0', + 'cust_bill_pkg.feepart IS NULL'; + + # We MUST NOT join cust_bill_pkg to any table that it's 1:many to. + # Otherwise we get duplication of the cust_bill_pkg records, + # inaccurate totals, nonsensical paging behavior, etc. + # We CAN safely join it to a subquery that has unique billpkgnums, and + # that's what we'll do. - push @where, 'cust_bill_pkg.pkgnum = 0'; + my $tax_subquery; + my @tax_where; # tax location when using tax_rate_location if ( $cgi->param('vendortax') ) { - $join_pkg .= ' LEFT JOIN cust_bill_pkg_tax_rate_location USING ( billpkgnum ) '. - ' LEFT JOIN tax_rate_location USING ( taxratelocationnum )'; + $tax_subquery = ' + SELECT billpkgnum, SUM(amount) as tax_total + FROM cust_bill_pkg_tax_rate_location AS tax + JOIN tax_rate_location USING (taxratelocationnum) + '; foreach (qw( state county city locationtaxid)) { if ( scalar($cgi->param($_)) ) { my $place = dbh->quote( $cgi->param($_) ); - push @where, "tax_rate_location.$_ = $place"; + push @tax_where, "tax_rate_location.$_ = $place"; } } - push @total, 'SUM( - COALESCE(cust_bill_pkg_tax_rate_location.amount, - cust_bill_pkg.setup + cust_bill_pkg.recur) - )'; - push @total_desc, "$money_char%.2f total"; - } else { # the internal-tax case - $join_pkg .= ' - LEFT JOIN cust_bill_pkg_tax_location USING (billpkgnum) - JOIN cust_main_county USING (taxnum) - '; - - # don't double-count the components of consolidated taxes - @total = ( 'COUNT(DISTINCT cust_bill_pkg.billpkgnum)', - 'SUM(cust_bill_pkg_tax_location.amount)' ); - @total_desc = "$money_char%.2f total"; + my $tax_select = 'SELECT tax.billpkgnum, SUM(tax.amount) as tax_total'; + my $tax_from = ' FROM cust_bill_pkg_tax_location AS tax JOIN cust_main_county USING (taxnum)'; # package classnum if ( grep { $_ eq 'classnum' } $cgi->param ) { my @classnums = grep /^\d*$/, $cgi->param('classnum'); - $join_pkg .= ' - JOIN cust_pkg AS taxed_pkg - ON (cust_bill_pkg_tax_location.pkgnum = taxed_pkg.pkgnum) - JOIN part_pkg AS taxed_part_pkg - ON (taxed_pkg.pkgpart = taxed_part_pkg.pkgpart) + $tax_from .= ' + JOIN cust_bill_pkg AS taxed_item + ON (tax.taxable_billpkgnum = taxed_item.billpkgnum) + LEFT JOIN cust_pkg AS taxed_pkg ON (taxed_item.pkgnum = taxed_pkg.pkgnum) + LEFT JOIN part_pkg AS taxed_part_pkg ON (taxed_pkg.pkgpart = taxed_part_pkg.pkgpart) + LEFT JOIN part_fee AS taxed_part_fee ON (taxed_item.feepart = taxed_part_fee.feepart) '; - push @where, "COALESCE(taxed_part_pkg.classnum, 0) IN ( ". + push @tax_where, + "COALESCE(taxed_part_pkg.classnum, taxed_part_fee.classnum,0) IN ( ". join(',', @classnums ). ' )' if @classnums; @@ -631,19 +634,20 @@ if ( $cgi->param('nottax') ) { # taxclass if ( $cgi->param('taxclassNULL') ) { - push @where, 'cust_main_county.taxclass IS NULL'; + push @tax_where, 'cust_main_county.taxclass IS NULL'; } # taxname if ( $cgi->param('taxnameNULL') ) { - push @where, 'cust_main_county.taxname IS NULL OR '. + push @tax_where, 'cust_main_county.taxname IS NULL OR '. 'cust_main_county.taxname = \'Tax\''; } elsif ( $cgi->param('taxname') ) { - push @where, 'cust_main_county.taxname = '. + push @tax_where, 'cust_main_county.taxname = '. dbh->quote($cgi->param('taxname')); } # itemdesc, for breakdown from the vendor tax report + # (is this even used? vendor tax report shouldn't use cust_bill_pkg.cgi) if ( $cgi->param('itemdesc') ) { if ( $cgi->param('itemdesc') eq 'Tax' ) { push @where, "($itemdesc = 'Tax' OR $itemdesc is null)"; @@ -652,103 +656,54 @@ if ( $cgi->param('nottax') ) { } } - # specific taxnums + # specific taxnums (the usual way) if ( $cgi->param('taxnum') =~ /^([\d,]+)$/) { - push @where, "cust_main_county.taxnum IN ($1)"; + push @tax_where, "cust_main_county.taxnum IN ($1)"; } - } #end of "normal case" - -} # nottax / istax - - -#total payments -my $pay_sub = "SELECT SUM(cust_bill_pay_pkg.amount) - FROM cust_bill_pay_pkg - WHERE cust_bill_pkg.billpkgnum = cust_bill_pay_pkg.billpkgnum - "; -push @select, "($pay_sub) AS pay_amount"; - - -# credit -if ( $cgi->param('credit') ) { + $tax_subquery = "$tax_select $tax_from"; - my $credit_where; + } # end of internal-tax case - my($cr_begin, $cr_end) = FS::UI::Web::parse_beginning_ending($cgi, 'credit'); - $credit_where = "WHERE cust_credit_bill._date >= $cr_begin " . - "AND cust_credit_bill._date <= $cr_end"; - - my $credit_sub; - - if ( $cgi->param('istax') ) { - # then we need to group/join by billpkgtaxlocationnum, to get only the - # relevant part of partial taxes - my $credit_sub = "SELECT SUM(cust_credit_bill_pkg.amount) AS credit_amount, - reason.reason as reason_text, access_user.username AS username_text, - billpkgtaxlocationnum, billpkgnum - FROM cust_credit_bill_pkg - JOIN cust_credit_bill USING (creditbillnum) - JOIN cust_credit USING (crednum) - LEFT JOIN reason USING (reasonnum) - LEFT JOIN access_user USING (usernum) - $credit_where - GROUP BY billpkgnum, billpkgtaxlocationnum, reason.reason, - access_user.username"; - - if ( $cgi->param('out') ) { + if (@tax_where) { + $tax_subquery .= ' + WHERE ' . join(' AND ', map "($_)", @tax_where); + } + $tax_subquery .= ' GROUP BY tax.billpkgnum '; - # find credits that are applied to the line items, but not to - # a cust_bill_pkg_tax_location link - $join_pkg .= " LEFT JOIN ($credit_sub) AS item_credit - USING (billpkgnum)"; - push @where, 'item_credit.billpkgtaxlocationnum IS NULL'; + # now join THAT into the main report + # (inner join, so that tax line items that don't match the tax_where + # conditions don't appear in the output.) - } else { + $join_pkg .= " JOIN ($tax_subquery) AS _istax USING (billpkgnum) "; - # find credits that are applied to the CBPTL links that are - # considered "interesting" by the report criteria - $join_pkg .= " LEFT JOIN ($credit_sub) AS item_credit - USING (billpkgtaxlocationnum)"; + push @select, 'tax_total'; - } + @peritem = ( 'setup' ); # total tax on the invoice, not just the filtered tax + @peritem_desc = ( 'Tax charge' ); - } else { - # then only group by billpkgnum - my $credit_sub = "SELECT SUM(cust_credit_bill_pkg.amount) AS credit_amount, - reason.reason as reason_text, access_user.username AS username_text, - billpkgnum - FROM cust_credit_bill_pkg - JOIN cust_credit_bill USING (creditbillnum) - JOIN cust_credit USING (crednum) - LEFT JOIN reason USING (reasonnum) - LEFT JOIN access_user USING (usernum) - $credit_where - GROUP BY billpkgnum, reason.reason, access_user.username"; - $join_pkg .= " LEFT JOIN ($credit_sub) AS item_credit USING (billpkgnum)"; + @total = ( 'COUNT(cust_bill_pkg.billpkgnum)', + 'SUM(cust_bill_pkg.setup)' ); + @total_desc = ( "$money_char%.2f total tax" ); + + if ( @tax_where ) { + # then also show the filtered tax + push @peritem, 'tax_total'; + push @peritem_desc, 'Tax in category'; + push @total, 'SUM(tax_total)'; + push @total_desc, "$money_char%.2f tax in this category"; + # would also be nice to include a line explaining what the category is } - push @where, 'item_credit.billpkgnum IS NOT NULL'; - push @select, 'item_credit.credit_amount', - 'item_credit.username_text', - 'item_credit.reason_text'; - push @peritem, 'credit_amount', 'username_text', 'reason_text'; - push @peritem_desc, 'Credited', 'By', 'Reason'; - push @total, 'SUM(credit_amount)'; - push @total_desc, "$money_char%.2f credited"; - -} else { - - #still want a credit total column +} # nottax / istax - my $credit_sub = " - SELECT SUM(cust_credit_bill_pkg.amount) - FROM cust_credit_bill_pkg - WHERE cust_bill_pkg.billpkgnum = cust_credit_bill_pkg.billpkgnum - "; - push @select, "($credit_sub) AS credit_amount"; +#total payments +my $pay_sub = "SELECT SUM(cust_bill_pay_pkg.amount) + FROM cust_bill_pay_pkg + WHERE cust_bill_pkg.billpkgnum = cust_bill_pay_pkg.billpkgnum + "; +push @select, "($pay_sub) AS pay_amount"; -} push @select, 'cust_main.custnum', FS::UI::Web::cust_sql_fields(); diff --git a/httemplate/search/report_tax-xls.cgi b/httemplate/search/report_tax-xls.cgi index d0ef434f4..743f14788 100755 --- a/httemplate/search/report_tax-xls.cgi +++ b/httemplate/search/report_tax-xls.cgi @@ -146,7 +146,7 @@ my $colhead = $format[0]->{colhead}; # print header $ws->merge_range($y, 1, $y, 5, 'Sales', $colhead); $ws->merge_range($y, 6, $y+1, 8, 'Rate', $colhead); -$ws->merge_range($y, 9, $y, 14, 'Tax', $colhead); +$ws->merge_range($y, 9, $y, 15, 'Tax', $colhead); $y++; $colhead = $format[0]->{colhead_small}; @@ -156,16 +156,17 @@ $ws->write($y, 9, 'Estimated', $colhead); $ws->write($y, 10, 'Invoiced', $colhead); $ws->write($y, 12, 'Credited', $colhead); $ws->write($y, 14, 'Net due', $colhead); +$ws->write($y, 15, 'Collected',$colhead); $y++; # print data -my $rownum = 0; +my $rownum = 1; my $prev_row = { pkgclass => 'DUMMY PKGCLASS' }; foreach my $row (@rows) { $x = 0; if ( $row->{pkgclass} ne $prev_row->{pkgclass} ) { - $rownum = 0; + $rownum = 1; if ( $params{breakdown}->{pkgclass} ) { $ws->merge_range($y, 0, $y, 14, $pkgclass_name{$row->{pkgclass}}, @@ -206,6 +207,8 @@ foreach my $row (@rows) { $ws->write_string($y, $x, " = ", $f->{bigmath}); $x++; $ws->write($y, $x, $row->{tax} - $row->{credit}, $f->{currency}); + $x++; + $ws->write($y, $x, $row->{tax_paid} || 0, $f->{currency}); $rownum++; $y++; diff --git a/httemplate/search/report_tax.cgi b/httemplate/search/report_tax.cgi index 491cd42c5..1d906473e 100644 --- a/httemplate/search/report_tax.cgi +++ b/httemplate/search/report_tax.cgi @@ -32,6 +32,8 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px } Tax credited Net tax due + + Tax collected @@ -131,13 +133,16 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px } % # credited tax − - +%# currently broken <% $money_sprintf->( $row->{credit} ) %> - +%# % # net tax due = <% $money_sprintf->( $row->{tax} - $row->{credit} ) %> +% # tax collected +   + <% $money_sprintf->( $row->{tax_paid} ) %> % $rownum++; % $prev_row = $row; @@ -218,12 +223,12 @@ if ( $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"; -my $creditlink = $p. "search/cust_bill_pkg.cgi?$dateagentlink;credit=1;istax=1"; - -if ( $params{'credit_date'} eq 'cust_credit_bill' ) { - $creditlink =~ s/begin/credit_begin/; - $creditlink =~ s/end/credit_end/; -} +#my $creditlink = $p. "search/cust_bill_pkg.cgi?$dateagentlink;credit=1;istax=1"; +#if ( $params{'credit_date'} eq 'cust_credit_bill' ) { +# $creditlink =~ s/begin/credit_begin/; +# $creditlink =~ s/end/credit_end/; +#} +my $creditlink = ''; # disabled until we find a sane way to do this my %pkgclass_name = map { $_->classnum, $_->classname } qsearch('pkg_class'); $pkgclass_name{''} = 'Unclassified'; -- cgit v1.2.1 From 324209d9ea24ca2f6a6f387088263933c06e39df Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Fri, 14 Aug 2015 16:32:21 -0700 Subject: fix links from package report to services that use view/svc_Common, #37621 --- httemplate/search/cust_pkg.cgi | 9 ++++++--- httemplate/view/cust_svc.cgi | 8 +++++++- 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'httemplate') diff --git a/httemplate/search/cust_pkg.cgi b/httemplate/search/cust_pkg.cgi index c88b3a1d5..f1e686a83 100755 --- a/httemplate/search/cust_pkg.cgi +++ b/httemplate/search/cust_pkg.cgi @@ -310,11 +310,14 @@ my $process_svc_labels = sub { foreach ( map { [ $_->label ] } @{ $part_svc->cust_pkg_svc } ) { push @out, [ { 'data' => $_->[0]. ':', - 'align'=> 'right', }, + 'align'=> 'right', + }, + { 'data' => $_->[1], 'align'=> 'left', - 'link' => $p. 'view/' . - $_->[2]. '.cgi?'. $_->[3], }, + 'link' => $p. 'view/cust_svc.cgi?' . $_->[3], + }, + ]; } } diff --git a/httemplate/view/cust_svc.cgi b/httemplate/view/cust_svc.cgi index 8ccfce3ff..aaf367882 100644 --- a/httemplate/view/cust_svc.cgi +++ b/httemplate/view/cust_svc.cgi @@ -1,4 +1,4 @@ -<% $cgi->redirect(popurl(1)."$svcdb.cgi?". $svcnum ) %> +<% $cgi->redirect($url) %> <%init> #needed here? we're just redirecting. i guess it could reveal the svcdb of a @@ -18,6 +18,12 @@ my $part_svc = qsearchs('part_svc',{'svcpart'=> $cust_svc->svcpart } ); die "Unknown svcpart" unless $part_svc; my $svcdb = $part_svc->svcdb; +my $url = svc_url( + 'm' => $m, + 'action' => 'view', + 'svcdb' => $svcdb, + 'query' => $svcnum, + ); -- cgit v1.2.1 From 45b87d63b047f23626a3ad9301a0dc0fd8797cae Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Sun, 16 Aug 2015 15:34:47 -0700 Subject: debug --- httemplate/elements/tr-select-months.html | 1 - 1 file changed, 1 deletion(-) (limited to 'httemplate') diff --git a/httemplate/elements/tr-select-months.html b/httemplate/elements/tr-select-months.html index 3ff28f99b..b90ce1ed7 100644 --- a/httemplate/elements/tr-select-months.html +++ b/httemplate/elements/tr-select-months.html @@ -7,6 +7,5 @@ $opt{labels} = { '' => '', map { $_ => emt('[quant,_1,month]', $_) } 1 .. $max }; -warn Dumper(\%opt); <& tr-select.html, %opt &> -- cgit v1.2.1 From ef2bc5dcb69e67077ce45a624c107894765e3907 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Mon, 17 Aug 2015 12:13:14 -0700 Subject: but still show credited amount on line item report, #18676 fixes --- httemplate/search/cust_bill_pkg.cgi | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'httemplate') diff --git a/httemplate/search/cust_bill_pkg.cgi b/httemplate/search/cust_bill_pkg.cgi index ac686eab8..4fb9b662b 100644 --- a/httemplate/search/cust_bill_pkg.cgi +++ b/httemplate/search/cust_bill_pkg.cgi @@ -44,8 +44,8 @@ @currency, 'invnum', '_date', - '', #'pay_amount', - '', #'credit_amount', + 'pay_amount', + 'credit_amount', FS::UI::Web::cust_sort_fields(), ], 'links' => [ @@ -461,15 +461,6 @@ if ( $cgi->param('nottax') ) { } - # This is the only place we should attempt to show credits on here: - # the total of credit applications to the line item. - - 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, @@ -704,7 +695,15 @@ my $pay_sub = "SELECT SUM(cust_bill_pay_pkg.amount) "; push @select, "($pay_sub) AS pay_amount"; +#total credits +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)"; +push @select, 'credit_amount'; +# standard customer fields push @select, 'cust_main.custnum', FS::UI::Web::cust_sql_fields(); #salesnum -- cgit v1.2.1 From 89525f062092c185344ec7318406b1c9086d1eda Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Mon, 17 Aug 2015 23:01:31 -0500 Subject: RT#18830: Upload file to message template --- httemplate/browse/msg_template.html | 3 +- httemplate/browse/template_image.html | 68 +++++ httemplate/edit/msg_template.html | 11 +- httemplate/elements/form-file_upload.html | 1 + .../elements/images/ui-icons_ef8c08_256x240.png | Bin 0 -> 4369 bytes httemplate/elements/template_image-dialog.html | 279 +++++++++++++++++++++ httemplate/misc/email-customers.html | 2 +- httemplate/misc/process/template_image-delete.cgi | 28 +++ httemplate/misc/process/template_image-upload.cgi | 26 ++ httemplate/misc/xmlhttp-template_image.cgi | 48 ++++ 10 files changed, 462 insertions(+), 4 deletions(-) create mode 100644 httemplate/browse/template_image.html create mode 100644 httemplate/elements/images/ui-icons_ef8c08_256x240.png create mode 100644 httemplate/elements/template_image-dialog.html create mode 100644 httemplate/misc/process/template_image-delete.cgi create mode 100644 httemplate/misc/process/template_image-upload.cgi create mode 100644 httemplate/misc/xmlhttp-template_image.cgi (limited to 'httemplate') diff --git a/httemplate/browse/msg_template.html b/httemplate/browse/msg_template.html index ef0b2dafd..1646bc169 100644 --- a/httemplate/browse/msg_template.html +++ b/httemplate/browse/msg_template.html @@ -28,6 +28,7 @@ my @menubar = (); if ( $curuser->access_right(['Edit templates', 'Edit global templates']) ) { push @menubar, 'Add a new template' => $p.'edit/msg_template.html'; } +push @menubar, 'View template images' => $p.'browse/template_image.html'; my $link = [ "${p}edit/msg_template.html?msgnum=", 'msgnum' ]; @@ -52,7 +53,7 @@ my $disable_link = sub { action => $p.'misc/disable-msg_template.cgi?msgnum=' . $template->msgnum . ($template->disabled ? ';enable=1' : ''), - actionlabel => 'Disable lemplate', + actionlabel => 'Disable template', ); }; diff --git a/httemplate/browse/template_image.html b/httemplate/browse/template_image.html new file mode 100644 index 000000000..eb4325f15 --- /dev/null +++ b/httemplate/browse/template_image.html @@ -0,0 +1,68 @@ +<% include('/elements/init_overlib.html') %> + +<% include( 'elements/browse.html', + 'title' => 'Template images', + 'name_singular' => 'image', + 'menubar' => \@menubar, + 'query' => { 'table' => 'template_image', }, + 'count_query' => 'SELECT COUNT(*) FROM template_image', + 'agent_virt' => 1, + 'agent_null_right' => ['View global templates','Edit global templates'], + 'agent_pos' => 1, + 'header' => [ 'Name', '', '' ], + 'fields' => [ 'name', $tag, $delete_text ], + 'links' => [ '', '', '' ], + 'cell_style' => [ '', '', '' ], + ) +%> + +<% include('/elements/template_image-dialog.html', + 'url' => $p.'browse/template_image.html' + ) %> + +<%init> +use FS::template_image; + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right([ 'View templates', 'View global templates', + 'Edit templates', 'Edit global templates', ]); + +my $canedit = $curuser->access_right(['Edit templates', 'Edit global templates']); + +my @menubar = (); +if ($canedit) { + push @menubar, 'Upload a new image' => 'javascript:insertImageDialog(\'upload\')'; +} +push @menubar, ( 'View message templates' => $p.'browse/msg_template.html' ); + +my $tag = sub { qq!view! }; + +my $delete_text = $canedit ? sub { + my $image = shift; + my $imgnum = $image->imgnum; + unless ($image->agentnum) { + unless ($FS::CurrentUser::CurrentUser->access_right('Edit global templates')) { + return ''; + } + } + my $out = < + + +EOF + $out .= include('/elements/progress-init.html', + "delete_template_image_$imgnum", + [ 'imgnum' ], + $p.'misc/process/template_image-delete.cgi', + $p.'browse/template_image.html', + "imgnum$imgnum", + ); + my $onclick = 'if ( confirm(\''; + $onclick .= emt('Are you sure you want to delete template image ') . $imgnum; + $onclick .= '\') ) { imgnum' . $imgnum . 'process() }'; + return $out . 'delete'; +} : ''; + + diff --git a/httemplate/edit/msg_template.html b/httemplate/edit/msg_template.html index 7f3824127..df72c5b66 100644 --- a/httemplate/edit/msg_template.html +++ b/httemplate/edit/msg_template.html @@ -27,6 +27,7 @@ 'no_submit' => $no_submit, &> <%init> +use FS::template_image; my $curuser = $FS::CurrentUser::CurrentUser; @@ -345,10 +346,16 @@ function areyousure(url, message) {
Substitutions: ' . $widget->html . -'
Click links to insert. -
Enclose substitutions and other Perl expressions in braces: +'

Click above links to insert substitution code.

+

+Enclose substitutions and other Perl expressions in braces:
{ $name } = ExampleCo (Smith, John)
{ time2str("%D", time) } = '.time2str("%D", time).' +

'; +$sidebar .= include('/elements/template_image-dialog.html', + 'callback' => 'insertHtml' + ); +$sidebar .= '

Insert Uploaded Image

'; diff --git a/httemplate/elements/form-file_upload.html b/httemplate/elements/form-file_upload.html index 45b6c97f2..3542a5a8e 100644 --- a/httemplate/elements/form-file_upload.html +++ b/httemplate/elements/form-file_upload.html @@ -69,6 +69,7 @@ Example:
+ +Creates a jquery dialog box that opens when javascript function insertImageDialog +is called, allows user to select an image and specify attributes for it, then passes +img tag with base64 encoded data url to a callback javascript function. + +Accepts the following options: + +callback - pass the html for the selected img to this javascript function; +if omitted, will only include fields for viewing/uploading image + +url - to redirect to after upload, otherwise just refreshes dialog window + + + +<% include('/elements/xmlhttp.html', + 'url' => $p.'misc/xmlhttp-template_image.cgi', + 'subs' => [ 'get_template_image' ], + ) %> + +
+ + + + + +% if ($opt{'callback'}) { + + + + + + + + + + + + + + + + + + + +% } # if $opt{'callback'} + +
+ + + +<% &ntable("#cccccc", 2) %> + +
Image + +
Width
Height
Align + +
Alt Text
+ +
+ + + +% if ($canedit) { + +

<% emt('Upload New Image') %>

+ +<% include('/elements/form-file_upload.html', + 'name' => 'TemplateImageUploadForm', + 'id' => 'TemplateImageUploadForm', + 'action' => $p.'misc/process/template_image-upload.cgi', + 'num_files' => 1, + 'fields' => [ 'name', 'agentnum' ], + 'url' => $opt{'url'} || 'javascript:refreshImageList(1)', + ) + %> + + <% &ntable("#cccccc", 2) %> + + <% include( '/elements/tr-input-text.html', + 'field' => 'name', + 'label' => 'Name', + 'required' => 1, + 'id' => 'upload_form_name', + ) + %> + + <% include( '/elements/tr-select-agent.html', + 'label' => "Agent", + 'empty_label' => 'Select agent', + 'agent_virt' => 1, + 'agent_null_right' => 'Edit global templates', + ) + %> + + <% include( '/elements/tr-file-upload.html', + 'field' => 'file', + 'label' => 'File', + ) + %> + + + + + + + + + + + +% } #if canedit + + + +
+

<% emt('Image Preview') %>

+ (<% emt('Loading image...') %>) + +
+ + +
+ + + +<%init> +my %opt = @_; + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right([ 'View templates', 'View global templates', + 'Edit templates', 'Edit global templates', ]); + +my $canedit = $curuser->access_right([ 'Edit templates', 'Edit global templates' ]); + + diff --git a/httemplate/misc/email-customers.html b/httemplate/misc/email-customers.html index 47e6a5b48..8ac44afc1 100644 --- a/httemplate/misc/email-customers.html +++ b/httemplate/misc/email-customers.html @@ -36,7 +36,7 @@ should be used to set msgnum or from/subject/html_body cgi params % } -
+ %# Mixing search params with from address, subject, etc. required special-case %# handling of those, risked name conflicts, and caused massive problems with diff --git a/httemplate/misc/process/template_image-delete.cgi b/httemplate/misc/process/template_image-delete.cgi new file mode 100644 index 000000000..58c3f2c68 --- /dev/null +++ b/httemplate/misc/process/template_image-delete.cgi @@ -0,0 +1,28 @@ +<% $server->process %> + +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +# make sure user can generally edit +die "access denied" + unless $curuser->access_right([ 'Edit templates', 'Edit global templates' ]); + +# make sure user can edit this particular image +my %arg = $cgi->param('arg'); +my $imgnum = $arg{'imgnum'}; +die "bad imgnum" unless $imgnum =~ /^\d+$/; +die "access denied" unless qsearchs({ + 'table' => 'template_image', + 'select' => 'imgnum', + 'hashref' => { 'imgnum' => $imgnum }, + 'extra_sql' => ' AND ' . + $curuser->agentnums_sql( + 'null_right' => ['Edit global templates'] + ), + }); + +my $server = + new FS::UI::Web::JSRPC 'FS::template_image::process_image_delete', $cgi; + + diff --git a/httemplate/misc/process/template_image-upload.cgi b/httemplate/misc/process/template_image-upload.cgi new file mode 100644 index 000000000..c3c905981 --- /dev/null +++ b/httemplate/misc/process/template_image-upload.cgi @@ -0,0 +1,26 @@ +<% $server->process %> + +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right([ 'Edit templates', 'Edit global templates' ]); + +my %arg = $cgi->param('arg'); +my $agentnum = $arg{'agentnum'}; + +if (!$agentnum) { + die "access denied" + unless $curuser->access_right([ 'Edit global templates' ]); +} else { + die "bad agentnum" + unless $agentnum =~ /^\d+$/; + die "access denied" + unless $curuser->agentnum($agentnum); +} + +my $server = + new FS::UI::Web::JSRPC 'FS::template_image::process_image_upload', $cgi; + + diff --git a/httemplate/misc/xmlhttp-template_image.cgi b/httemplate/misc/xmlhttp-template_image.cgi new file mode 100644 index 000000000..a8c50edf0 --- /dev/null +++ b/httemplate/misc/xmlhttp-template_image.cgi @@ -0,0 +1,48 @@ +<%doc> +Returns JSON encoded array of objects with details about FS::template_image +objects. Attributes in each returned object are imgnum, name, and src. + +Accepts the following options: + +imgnum - only return object for this imgnum + +no_src - do not include the src field + + +<% encode_json(\@result) %>\ +<%init> +use FS::template_image; + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right([ 'View templates', 'View global templates', + 'Edit templates', 'Edit global templates', ]); + +my %arg = $cgi->param('arg'); + +my $search = { + 'table' => 'template_image', + 'hashref' => {}, +}; + +my $imgnum = $arg{'imgnum'} || ''; +die "Bad imgnum" unless $imgnum =~ /^\d*$/; +$search->{'hashref'}->{'imgnum'} = $imgnum if $imgnum; + +$search->{'select'} = 'imgnum, name' if $arg{'no_src'}; + +$search->{'extra_sql'} = ($imgnum ? ' AND ' : ' WHERE ') + . $curuser->agentnums_sql( + 'null_right' => ['View global templates','Edit global templates'] + ); + +my @images = qsearch($search); #needs agent virtualization + +my @result = map { +{ + 'imgnum' => $_->imgnum, + 'name' => $_->name, + 'src' => $arg{'no_src'} ? '' : $_->src, +} } @images; + + -- cgit v1.2.1 From 2dddd8e1742bf2e8ebe9f2d3e560bc78bba95cff Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Thu, 20 Aug 2015 01:42:15 -0500 Subject: RT#14829: automatic payments triggered by bill now show up as Payment by fs_queue --- httemplate/search/queue.html | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'httemplate') diff --git a/httemplate/search/queue.html b/httemplate/search/queue.html index 141c535da..22032b13c 100644 --- a/httemplate/search/queue.html +++ b/httemplate/search/queue.html @@ -13,6 +13,7 @@ 'Date', 'Status', 'Account', # unless $hashref->{'svcnum'} + 'Employee', '', # checkbox column ], 'fields' => [ @@ -76,6 +77,11 @@ ''; } }, + sub { + my $queue = shift; + my $access_user = $queue->access_user; + return $access_user ? $access_user->username : ''; + }, sub { my $queue = shift; my $jobnum = $queue->jobnum; -- cgit v1.2.1 From ed673c4be67ad4d3b549df3b5f20fe5d76d6e944 Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Mon, 24 Aug 2015 19:28:54 -0500 Subject: RT#18361: Delay package from billing until services are provisioned [text change] --- httemplate/elements/template_image-dialog.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'httemplate') diff --git a/httemplate/elements/template_image-dialog.html b/httemplate/elements/template_image-dialog.html index 5691d52b5..f7fb0c291 100644 --- a/httemplate/elements/template_image-dialog.html +++ b/httemplate/elements/template_image-dialog.html @@ -94,7 +94,7 @@ url - to redirect to after upload, otherwise just refreshes dialog window <% include( '/elements/tr-select-agent.html', 'label' => "Agent", - 'empty_label' => 'Select agent', + 'empty_label' => '(global)', 'agent_virt' => 1, 'agent_null_right' => 'Edit global templates', ) -- cgit v1.2.1 From 33b89d345f9f3f687c958056aeb85471f7f4c8f5 Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Tue, 25 Aug 2015 01:17:24 -0500 Subject: RT#18361: Delay package from billing until services are provisioned [start_on_hold toggles checkboxes display] --- httemplate/elements/tr-pkg_svc.html | 39 +++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) (limited to 'httemplate') diff --git a/httemplate/elements/tr-pkg_svc.html b/httemplate/elements/tr-pkg_svc.html index cfef51ce2..1e9c0a38b 100644 --- a/httemplate/elements/tr-pkg_svc.html +++ b/httemplate/elements/tr-pkg_svc.html @@ -4,6 +4,12 @@ <% itable('', 4, 1) %> <% $thead %> + + %foreach my $part_svc ( @part_svc ) { % my $svcpart = $part_svc->svcpart; % my $pkg_svc = $pkg_svc{$svcpart} @@ -78,9 +84,13 @@ > - - > + + > + % foreach ( 1 .. $columns-1 ) { @@ -92,10 +102,31 @@ % } % $count++; % -% } +% } # foreach $part_svc + + % if ( scalar(@possible_exports) > 0 || scalar(@mapped_exports) > 0 ) { @@ -137,7 +168,7 @@ my $thead = "\n\n". ntable('#cccccc', 2). ''. ''. ''. - ''. + ''. ''; my $part_pkg = $opt{'object'}; -- cgit v1.2.1 From 9e4ef67fa35a301ba23a8f6107e12b7db33f83c8 Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Tue, 25 Aug 2015 09:25:37 -0700 Subject: warning about param in list context (in a substitution?) --- httemplate/misc/void-cust_bill.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'httemplate') diff --git a/httemplate/misc/void-cust_bill.html b/httemplate/misc/void-cust_bill.html index 1608fd051..39b071229 100644 --- a/httemplate/misc/void-cust_bill.html +++ b/httemplate/misc/void-cust_bill.html @@ -14,7 +14,7 @@ <% ntable("#cccccc", 2) %> - +
ExportServiceHide
from
Invoices
Bulk
Charge
Hold
Until
Provision
Remove Hold After Provisioning
Reason
-- cgit v1.2.1 From f4fc0bd2f813272ed1a878dd9f130fe155a6e3ff Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Tue, 25 Aug 2015 09:32:05 -0700 Subject: param in list context --- httemplate/misc/process/void-cust_bill.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'httemplate') diff --git a/httemplate/misc/process/void-cust_bill.html b/httemplate/misc/process/void-cust_bill.html index accee27fd..7773b0ba9 100755 --- a/httemplate/misc/process/void-cust_bill.html +++ b/httemplate/misc/process/void-cust_bill.html @@ -21,6 +21,6 @@ my $cust_bill = qsearchs('cust_bill',{'invnum'=>$invnum}); my $custnum = $cust_bill->custnum; -my $error = $cust_bill->void( $cgi->param('reason') ); +my $error = $cust_bill->void( scalar($cgi->param('reason')) ); -- cgit v1.2.1 From c13a7adf63cc830d092bbf4a8e9bda2aa3beee56 Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Tue, 25 Aug 2015 21:25:15 -0500 Subject: RT#18361: Delay package from billing until services are provisioned [bug fix to javascript] --- httemplate/elements/tr-pkg_svc.html | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'httemplate') diff --git a/httemplate/elements/tr-pkg_svc.html b/httemplate/elements/tr-pkg_svc.html index 1e9c0a38b..7ac67b7ec 100644 --- a/httemplate/elements/tr-pkg_svc.html +++ b/httemplate/elements/tr-pkg_svc.html @@ -1,15 +1,14 @@ -<% itable('', 4, 1) %> -<% $thead %> - +<% itable('', 4, 1) %> +<% pkg_svc_thead() %> + %foreach my $part_svc ( @part_svc ) { % my $svcpart = $part_svc->svcpart; % my $pkg_svc = $pkg_svc{$svcpart} @@ -97,7 +96,7 @@ provision_hold_input.push(document.getElementById('input_provision_hold<% $svcpa % if ( $count == int( $_ * scalar(@part_svc) / $columns ) ) { % - <% $thead %> + <% pkg_svc_thead() %> % } % } % $count++; @@ -161,15 +160,21 @@ provision_hold_init(); my %opt = @_; my $cgi = $opt{'cgi'}; -my $thead = "\n\n". ntable('#cccccc', 2). - ''. - 'Quan.'. - 'Primary'. - 'Service'. - 'Hide
from
Invoices
'. - 'Bulk
Charge
'. - 'Remove Hold After Provisioning'. - ''; +my $thead_count = 0; +sub pkg_svc_thead { + $thead_count += 1; + return "\n\n". ntable('#cccccc', 2). + ''. + 'Quan.'. + 'Primary'. + 'Service'. + 'Hide
from
Invoices
'. + 'Bulk
Charge
'. + 'Remove Hold After Provisioning'. + ''. + qq!!; +; +} my $part_pkg = $opt{'object'}; my $pkgpart = $part_pkg->pkgpart; -- cgit v1.2.1 From dd0de30cf562e4e31359a9d9108fec974ecb4299 Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Tue, 25 Aug 2015 21:46:01 -0500 Subject: RT#18361: Delay package from billing until services are provisioned [bug fix to javascript] --- httemplate/elements/tr-pkg_svc.html | 3 +++ 1 file changed, 3 insertions(+) (limited to 'httemplate') diff --git a/httemplate/elements/tr-pkg_svc.html b/httemplate/elements/tr-pkg_svc.html index 7ac67b7ec..de3f95a3a 100644 --- a/httemplate/elements/tr-pkg_svc.html +++ b/httemplate/elements/tr-pkg_svc.html @@ -114,6 +114,9 @@ function provision_hold_check () { for (i = 0; i < provision_hold_td.length; i++) { provision_hold_td[i].style.display = start_on_hold.checked ? '' : 'none'; } + for (i = 0; i < provision_hold_input.length; i++) { + provision_hold_input[i].disabled = start_on_hold.checked ? false : true; + } } } function provision_hold_init () { -- cgit v1.2.1 From 76e8fffdfe3b6f6f8ab422038b62e40cc10f95e8 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Thu, 27 Aug 2015 19:18:42 -0700 Subject: #21564, external message services: preview and send messages through the UI --- httemplate/misc/email-customers.html | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'httemplate') diff --git a/httemplate/misc/email-customers.html b/httemplate/misc/email-customers.html index 8ac44afc1..bffd0cf81 100644 --- a/httemplate/misc/email-customers.html +++ b/httemplate/misc/email-customers.html @@ -1,10 +1,11 @@ <%doc> -Allows emailing one or more customers, based on a search for customers. Search can -be specified either through cust_main fields as cgi params, or through a base64 encoded -frozen hash in the 'search' cgi param. Form allows selecting an existing msg_template, -or creating a custom message, and shows a preview of the message before sending. -If linked to as a popup, include the cgi parameter 'popup' for proper header handling. +Allows emailing one or more customers, based on a search for customers. +Search can be specified either through cust_main fields as cgi params, or +through a base64 encoded frozen hash in the 'search' cgi param. Form allows +selecting an existing msg_template, or creating a custom message, and shows a +preview of the message before sending. If linked to as a popup, include the +cgi parameter 'popup' for proper header handling. This may also be used as an element in other pages, enabling you to provide an alternate initial form while using this for search freezing/thawing and @@ -21,12 +22,13 @@ title - the title of the page no_search_fields - arrayref of additional fields that are not search parameters alternate_form - subroutine that returns alternate html for the initial form, -replaces msgnum/from/subject/html_body/action inputs and submit button, -not used if an action is specified +replaces msgnum/from/subject/html_body/action inputs and submit button, not +used if an action is specified -post_search_hook - sub hook for additional processing after search has been processed from cgi, -gets passed options 'conf' and 'search' (a reference to the unfrozen %search hash), -should be used to set msgnum or from/subject/html_body cgi params +post_search_hook - sub hook for additional processing after search has been +processed from cgi, gets passed options 'conf' and 'search' (a reference to +the unfrozen %search hash), should be used to set msgnum or +from/subject/html_body cgi params % if ($popup) { @@ -288,8 +290,13 @@ if ( $cgi->param('action') eq 'preview' ) { 'cust_main' => $cust, 'object' => $object, ); - my %message = $msg_template->prepare(%msgopts); - ($from, $subject, $html_body) = @message{'from', 'subject', 'html_body'}; + + my $cust_msg = $msg_template->prepare(%msgopts); + $from = $cust_msg->env_from; + $html_body = $cust_msg->preview; + if ( $cust_msg->header =~ /^subject: (.*)/mi ) { + $subject = $1; + } } } -- cgit v1.2.1 From 46bbbb1a78fd822805226abea832b6206273c091 Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Fri, 28 Aug 2015 00:56:49 -0500 Subject: RT#37064: Add action link to manually refund a payment --- httemplate/edit/cust_refund.cgi | 10 +------ httemplate/edit/process/cust_refund.cgi | 31 +++++++++++----------- httemplate/misc/unapply-cust_pay.cgi | 6 ++--- httemplate/view/cust_main/payment_history.html | 1 + .../view/cust_main/payment_history/payment.html | 13 ++++----- 5 files changed, 26 insertions(+), 35 deletions(-) (limited to 'httemplate') diff --git a/httemplate/edit/cust_refund.cgi b/httemplate/edit/cust_refund.cgi index fa049a39a..bfcbfe725 100755 --- a/httemplate/edit/cust_refund.cgi +++ b/httemplate/edit/cust_refund.cgi @@ -139,16 +139,8 @@ my $payinfo = $cgi->param('payinfo'); my $reason = $cgi->param('reason'); my $link = $cgi->param('popup') ? 'popup' : ''; -my @rights = (); -push @rights, 'Post refund' if $payby =~ /^(BILL|CASH|MCRD|MCHK)$/; -push @rights, 'Post check refund' if $payby eq 'BILL'; -push @rights, 'Post cash refund ' if $payby eq 'CASH'; -push @rights, 'Refund payment' if $payby =~ /^(CARD|CHEK)$/; -push @rights, 'Refund credit card payment' if $payby eq 'CARD'; -push @rights, 'Refund Echeck payment' if $payby eq 'CHEK'; - die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right(\@rights); + unless $FS::CurrentUser::CurrentUser->refund_access_right($payby); my( $paynum, $cust_pay ) = ( '', '' ); if ( $cgi->param('paynum') =~ /^(\d+)$/ ) { diff --git a/httemplate/edit/process/cust_refund.cgi b/httemplate/edit/process/cust_refund.cgi index 52fede8ec..ce72c9253 100755 --- a/httemplate/edit/process/cust_refund.cgi +++ b/httemplate/edit/process/cust_refund.cgi @@ -12,7 +12,7 @@ % } else { -<% $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum") %> +<% $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum;show=payment_history") %> % } %} <%init> @@ -30,16 +30,8 @@ my $link = $cgi->param('popup') ? 'popup' : ''; my $payby = $cgi->param('payby'); -my @rights = (); -push @rights, 'Post refund' if $payby =~ /^(BILL|CASH|MCRD|MCHK)$/; -push @rights, 'Post check refund' if $payby eq 'BILL'; -push @rights, 'Post cash refund ' if $payby eq 'CASH'; -push @rights, 'Refund payment' if $payby =~ /^(CARD|CHEK)$/; -push @rights, 'Refund credit card payment' if $payby eq 'CARD'; -push @rights, 'Refund Echeck payment' if $payby eq 'CHEK'; - die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right(\@rights); + unless $FS::CurrentUser::CurrentUser->refund_access_right($payby); $cgi->param('reasonnum') =~ /^(-?\d+)$/ or die "Illegal reasonnum"; my ($reasonnum, $error) = $m->comp('/misc/process/elements/reason'); @@ -63,12 +55,19 @@ if ( $error ) { 'reason' => $reason, %options ); } else { - my $new = new FS::cust_refund ( { - map { - $_, scalar($cgi->param($_)); - } fields('cust_refund') #huh? , 'paynum' ) - } ); - $error = $new->insert; + my %hash = map { + $_, scalar($cgi->param($_)) + } fields('cust_refund'); + my $paynum = $cgi->param('paynum'); + $paynum =~ /^(\d*)$/ or die "Illegal paynum!"; + if ($paynum) { + my $cust_pay = qsearchs('cust_pay',{ 'paynum' => $paynum }); + die "Could not find paynum $paynum" unless $cust_pay; + $error = $cust_pay->refund(\%hash); + } else { + my $new = new FS::cust_refund ( \%hash ); + $error = $new->insert; + } } diff --git a/httemplate/misc/unapply-cust_pay.cgi b/httemplate/misc/unapply-cust_pay.cgi index 8cdac180b..b0343d034 100755 --- a/httemplate/misc/unapply-cust_pay.cgi +++ b/httemplate/misc/unapply-cust_pay.cgi @@ -12,9 +12,7 @@ my $paynum = $1; my $cust_pay = qsearchs('cust_pay', { 'paynum' => $paynum } ); my $custnum = $cust_pay->custnum; -foreach my $cust_bill_pay ( $cust_pay->cust_bill_pay ) { - my $error = $cust_bill_pay->delete; - errorpage($error) if $error; -} +my $error = $cust_pay->delete_cust_bill_pay; +errorpage($error) if $error; diff --git a/httemplate/view/cust_main/payment_history.html b/httemplate/view/cust_main/payment_history.html index e3599bc06..1525e9314 100644 --- a/httemplate/view/cust_main/payment_history.html +++ b/httemplate/view/cust_main/payment_history.html @@ -228,6 +228,7 @@ my %opt = ( ( 'View invoices', 'Void invoices', 'Unvoid invoices', 'Apply payment', 'Refund credit card payment', 'Refund Echeck payment', + 'Post refund', 'Post check refund', 'Post cash refund ', 'Refund payment', 'Credit card void', 'Echeck void', 'Void payments', 'Unvoid payments', 'Delete payment', 'Unapply payment', 'Apply credit', 'Delete credit', 'Unapply credit', 'Void credit', 'Unvoid credit', diff --git a/httemplate/view/cust_main/payment_history/payment.html b/httemplate/view/cust_main/payment_history/payment.html index bf88a6607..0ed2f8003 100644 --- a/httemplate/view/cust_main/payment_history/payment.html +++ b/httemplate/view/cust_main/payment_history/payment.html @@ -154,18 +154,19 @@ if ( $apply && $opt{'pkg-balances'} && $cust_pay->pkgnum ) { my $refund = ''; my $refund_days = $opt{'card_refund-days'} || 120; -my $refund_right = ''; -$refund_right = 'Refund credit card payment' if $cust_pay->payby eq 'CARD'; -$refund_right = 'Refund Echeck payment' if $cust_pay->payby eq 'CHEK'; +my @refund_right = grep { $opt{$_} } $FS::CurrentUser::CurrentUser->refund_rights($cust_pay->payby); if ( $cust_pay->closed !~ /^Y/i - && $cust_pay->payby =~ /^(CARD|CHEK)$/ + && $cust_pay->payby =~ /^(CARD|CHEK|BILL)$/ && time-$cust_pay->_date < $refund_days*86400 && $cust_pay->unrefunded > 0 - && $opt{$refund_right} + && scalar(@refund_right) ) { + my $refundtitle = ($cust_pay->payby =~ /^(CARD|CHEK)$/) + ? emt('Send a refund for this payment to the payment gateway') + : emt('Record a refund for this payment'); $refund = qq! (' . emt('refund') . ')'; } -- cgit v1.2.1 From 1d4c8f82596a7f3695ba2203e301e497dec9194c Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Sat, 29 Aug 2015 17:17:44 -0500 Subject: RT#37064: Add action link to manually refund a payment [fixed redir link] --- httemplate/edit/process/cust_refund.cgi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'httemplate') diff --git a/httemplate/edit/process/cust_refund.cgi b/httemplate/edit/process/cust_refund.cgi index ce72c9253..6ad468b6c 100755 --- a/httemplate/edit/process/cust_refund.cgi +++ b/httemplate/edit/process/cust_refund.cgi @@ -12,7 +12,7 @@ % } else { -<% $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum;show=payment_history") %> +<% $cgi->redirect(popurl(3). "view/cust_main.cgi?custnum=$custnum;show=payment_history") %> % } %} <%init> -- cgit v1.2.1 From d622148c3ad8e98aef7ae1ca163e28483e023609 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Sat, 29 Aug 2015 21:26:34 -0700 Subject: fix typo --- httemplate/search/elements/search.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'httemplate') diff --git a/httemplate/search/elements/search.html b/httemplate/search/elements/search.html index beb017300..a279f5327 100644 --- a/httemplate/search/elements/search.html +++ b/httemplate/search/elements/search.html @@ -348,8 +348,8 @@ if ( $opt{'disableable'} ) { sub { shift->disabled ? 'FF0000' : '00CC00'; }; splice @{ $opt{'links'} }, $pos, 0, '' if $opt{'links'}; - splice @{ $opt{'link_onlicks'} }, $pos, 0, '' - if $opt{'link_onlicks'}; + splice @{ $opt{'link_onclicks'} }, $pos, 0, '' + if $opt{'link_onclicks'}; } #add show/hide disabled links -- cgit v1.2.1 From 9fd03716b831bd00a725a63edbe19cfe6b88aea0 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Sat, 29 Aug 2015 21:27:20 -0700 Subject: #21564: user interface for REST client --- httemplate/browse/msg_template.html | 65 ----- httemplate/browse/msg_template/email.html | 74 ++++++ httemplate/browse/msg_template/http.html | 68 ++++++ httemplate/edit/msg_template.html | 383 +---------------------------- httemplate/edit/msg_template/email.html | 385 ++++++++++++++++++++++++++++++ httemplate/edit/msg_template/http.html | 82 +++++++ httemplate/edit/process/msg_template.html | 18 +- httemplate/elements/menu.html | 2 +- 8 files changed, 631 insertions(+), 446 deletions(-) delete mode 100644 httemplate/browse/msg_template.html create mode 100644 httemplate/browse/msg_template/email.html create mode 100644 httemplate/browse/msg_template/http.html create mode 100644 httemplate/edit/msg_template/email.html create mode 100644 httemplate/edit/msg_template/http.html (limited to 'httemplate') diff --git a/httemplate/browse/msg_template.html b/httemplate/browse/msg_template.html deleted file mode 100644 index 1646bc169..000000000 --- a/httemplate/browse/msg_template.html +++ /dev/null @@ -1,65 +0,0 @@ -<% include( 'elements/browse.html', - 'title' => 'Message templates', - 'name_singular' => 'template', - 'menubar' => \@menubar, - 'query' => { 'table' => 'msg_template', }, - 'count_query' => 'SELECT COUNT(*) FROM msg_template', - 'disableable' => 1, - 'disabled_statuspos' => (scalar(@locales) + 3), - 'agent_virt' => 1, - 'agent_null_right' => ['View global templates','Edit global templates'], - 'agent_pos' => 1, - 'header' => [ 'Name', '', map ('', @locales), '' ], - 'fields' => [ 'msgname', @locales, $disable_link_label ], - 'links' => [ $link, @locale_links, '' ], - 'link_onclicks' => [ '', map('', @locale_links), $disable_link ], - 'cell_style' => [ '', '', map ($locale_style, @locales), $locale_style ], - ) -%> -<%init> - -my $curuser = $FS::CurrentUser::CurrentUser; - -die "access denied" - unless $curuser->access_right([ 'View templates', 'View global templates', - 'Edit templates', 'Edit global templates', ]); - -my @menubar = (); -if ( $curuser->access_right(['Edit templates', 'Edit global templates']) ) { - push @menubar, 'Add a new template' => $p.'edit/msg_template.html'; -} -push @menubar, 'View template images' => $p.'browse/template_image.html'; - -my $link = [ "${p}edit/msg_template.html?msgnum=", 'msgnum' ]; - -my $locale_style = 'font-size:0.8em; padding:3px'; - -my (@locales, @locale_links); -foreach my $l ( FS::Locales->locales ) { - push @locales, sub { - exists ( $_[0]->content_locales->{$l} ) - ? +{ FS::Locales->locale_info($l) }->{'label'} - : ''; - }; - push @locale_links, sub { - my $content = $_[0]->content_locales->{$l} or return ''; - [ "${p}edit/msg_template.html?locale=$l;msgnum=", 'msgnum' ]; - }; -} - -my $disable_link = sub { - my $template = shift; - include('/elements/popup_link_onclick.html', - action => $p.'misc/disable-msg_template.cgi?msgnum=' . - $template->msgnum . - ($template->disabled ? ';enable=1' : ''), - actionlabel => 'Disable template', - ); -}; - -my $disable_link_label = sub { - my $template = shift; - $template->disabled ? '(enable)' : '(disable)' ; -}; - - diff --git a/httemplate/browse/msg_template/email.html b/httemplate/browse/msg_template/email.html new file mode 100644 index 000000000..d0ef4e3e9 --- /dev/null +++ b/httemplate/browse/msg_template/email.html @@ -0,0 +1,74 @@ +<& /browse/elements/browse.html, + 'title' => 'Message templates', + 'name_singular' => 'template', + 'menubar' => \@menubar, + 'query' => $query, + 'count_query' => $count_query, + 'disableable' => 1, + 'disabled_statuspos' => (scalar(@locales) + 3), + 'agent_virt' => 1, + 'agent_null_right' => ['View global templates','Edit global templates'], + 'agent_pos' => 1, + 'header' => [ 'Name', '', map ('', @locales), '' ], + 'fields' => [ 'msgname', @locales, $disable_link_label ], + 'links' => [ $link, @locale_links, '' ], + 'link_onclicks' => [ '', map('', @locale_links), $disable_link ], + 'cell_style' => [ '', '', map ($locale_style, @locales), $locale_style ], +&> +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right([ 'View templates', 'View global templates', + 'Edit templates', 'Edit global templates', ]); + +my @menubar = (); +if ( $curuser->access_right(['Edit templates', 'Edit global templates']) ) { + push @menubar, 'Add a new template' => $fsurl.'edit/msg_template/email.html'; +} +push @menubar, 'Template images' => $fsurl.'browse/template_image.html'; + +push @menubar, 'External message interfaces' => $fsurl.'browse/msg_template/http.html'; + +my $query = { + 'table' => 'msg_template', + 'select' => '*', + 'hashref' => { 'msgclass' => 'email' }, +}; + +my $count_query = "SELECT COUNT(*) FROM msg_template WHERE msgclass = 'email'"; + +my $link = [ $fsurl.'edit/msg_template/email.html?msgnum=', 'msgnum' ]; + +my $locale_style = 'font-size:0.8em; padding:3px'; + +my (@locales, @locale_links); +foreach my $l ( FS::Locales->locales ) { + push @locales, sub { + exists ( $_[0]->content_locales->{$l} ) + ? +{ FS::Locales->locale_info($l) }->{'label'} + : ''; + }; + push @locale_links, sub { + my $content = $_[0]->content_locales->{$l} or return ''; + [ $fsurl."edit/msg_template/email.html?locale=$l;msgnum=", 'msgnum' ]; + }; +} + +my $disable_link = sub { + my $template = shift; + include('/elements/popup_link_onclick.html', + action => $fsurl.'misc/disable-msg_template.cgi?msgnum=' . + $template->msgnum . + ($template->disabled ? ';enable=1' : ''), + actionlabel => 'Disable template', + ); +}; + +my $disable_link_label = sub { + my $template = shift; + $template->disabled ? '(enable)' : '(disable)' ; +}; + + diff --git a/httemplate/browse/msg_template/http.html b/httemplate/browse/msg_template/http.html new file mode 100644 index 000000000..888fda441 --- /dev/null +++ b/httemplate/browse/msg_template/http.html @@ -0,0 +1,68 @@ +<& /browse/elements/browse.html, + 'title' => 'External message interfaces', + 'name_singular' => 'interface', # what else do we call them? + 'menubar' => \@menubar, + 'query' => $query, + 'count_query' => $count_query, + 'disableable' => 1, + 'disabled_statuspos' => 4, + 'agent_virt' => 1, + 'agent_null_right' => ['View global templates','Edit global templates'], + 'agent_pos' => 1, + 'header' => [ 'Name', + # 'Agent', + 'Prepare', + 'Send', + '' ], + 'fields' => [ 'msgname', + 'prepare_url', + 'send_url', + $disable_link_label + ], + 'links' => [ $link, ], + 'link_onclicks' => [ '', '', '', $disable_link ], + 'cell_style' => [ '', '', $url_style, $url_style ], +&> +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right([ 'View templates', 'View global templates', + 'Edit templates', 'Edit global templates', ]); + +my @menubar = (); +if ( $curuser->access_right(['Edit templates', 'Edit global templates']) ) { + push @menubar, 'Add a new interface' => $fsurl.'edit/msg_template/http.html'; +} +push @menubar, 'Email templates' => $fsurl.'browse/msg_template/email.html'; +push @menubar, 'Template images' => $fsurl.'browse/template_image.html'; + +my $query = { + 'table' => 'msg_template', + 'select' => '*', + 'hashref' => { 'msgclass' => 'http' }, +}; + +my $count_query = "SELECT COUNT(*) FROM msg_template WHERE msgclass = 'http'"; + +my $link = [ $fsurl.'edit/msg_template/http.html?msgnum=', 'msgnum' ]; + +my $url_style = 'font-size:0.8em; padding:3px'; # also for (disable) label + +my $disable_link = sub { + my $template = shift; + include('/elements/popup_link_onclick.html', + action => $fsurl.'misc/disable-msg_template.cgi?msgnum=' . + $template->msgnum . + ($template->disabled ? ';enable=1' : ''), + actionlabel => 'Disable template', + ); +}; + +my $disable_link_label = sub { + my $template = shift; + $template->disabled ? '(enable)' : '(disable)' ; +}; + + diff --git a/httemplate/edit/msg_template.html b/httemplate/edit/msg_template.html index df72c5b66..889b10731 100644 --- a/httemplate/edit/msg_template.html +++ b/httemplate/edit/msg_template.html @@ -1,380 +1,9 @@ -<& elements/edit.html, - 'html_init' => '$sidebar
', - 'body_etc' => $body_etc, - 'name_singular' => 'template', - 'table' => 'msg_template', - 'viewall_dir' => 'browse', - 'agent_virt' => 1, - 'agent_null' => 1, - 'agent_null_right' => [ 'View global templates', 'Edit global templates' ], - - 'fields' => \@fields, - 'labels' => { - 'msgnum' => 'Template', - 'agentnum' => 'Agent', - 'msgname' => 'Template name', - 'from_addr' => 'From: ', - 'bcc_addr' => 'Bcc: ', - 'locale' => 'Locale', - 'subject' => 'Subject: ', - 'body' => 'Message body', - }, - 'edit_callback' => \&edit_callback, - 'error_callback' => \&edit_callback, - 'html_bottom' => '', - 'html_table_bottom'=> \&html_table_bottom, - 'html_foot' => ( $no_submit ? '' : "
" ), - 'no_submit' => $no_submit, -&> <%init> -use FS::template_image; - -my $curuser = $FS::CurrentUser::CurrentUser; - -die "access denied" - unless $curuser->access_right([ 'View templates', 'View global templates', - 'Edit templates', 'Edit global templates', - ]); - -my $body_etc = ''; -$body_etc = q!onload="document.getElementById('locale').onchange()"! - if $cgi->param('locale') eq 'new'; - -my $msgnum = $cgi->param('msgnum'); -my $msg_template = $msgnum ? qsearchs('msg_template', {msgnum=>$msgnum}) : ''; - -my $no_submit = 0; -my @fields = (); -if ( $curuser->access_right('Edit global templates') - || ( $curuser->access_right('Edit templates') - && $msg_template - && $msg_template->agentnum - && $curuser->agentnums_href->{$msg_template->agentnum} - ) - ) -{ - push @fields, - { field => 'agentnum', - type => 'select-agent', - }, - { field => 'msgname', size=>60, }, - { field => 'from_addr', size=>60, }, - { field => 'bcc_addr', size=>60, }, - { type => 'tablebreak-tabs', - include_opt_callback => \&menubar_opt_callback, - }, - # template_content fields - { field => 'locale', type => 'hidden' }, - { field => 'subject', size=>60, }, - { field => 'body', - type => 'htmlarea', - width => 763, - config=> { extraPlugins => 'blockprotect' }, - }, - ; -} else { #readonly - - $no_submit = 1; - - push @fields, - { field => 'agentnum', - type => 'select-agent', - fixed => 1, - }, - { field => 'msgname', type => 'fixed', }, - { field => 'from_addr', type => 'fixed', }, - { field => 'bcc_addr', type => 'fixed', }, - { type => 'tablebreak-tabs', - include_opt_callback => \&menubar_opt_callback, - }, - # template_content fields - { field => 'locale', type => 'hidden' }, - { field => 'subject', type => 'fixed', }, - { field => 'body', - type => 'fixed', - noescape => 1, - }, - ; - +my $msgclass = 'email'; +if ( $cgi->param('msgnum') =~ /^(\d+)$/ ) { + my $msg_template = FS::msg_template->by_key($1) + or die "unknown msgnum $1"; + $msgclass = $msg_template->msgclass; } - -sub new_callback { - my ($cgi, $object, $fields_listref, $opt_hashref) = @_; - my $template_content = new FS::template_content { 'locale' => '' }; - $object->{'Hash'} = { $object->hash, $template_content->hash }; -} - -sub edit_callback { - my ($cgi, $object, $fields_listref, $opt_hashref) = @_; - $cgi->param('locale') =~ /^(\w*)$/ or die 'bad locale '.$cgi->param('locale'); - my $locale = $1; - - # fetch the content object and merge its fields - my %args = ( - 'msgnum' => $object->msgnum, - 'locale' => $locale - ); - my $template_content = qsearchs('template_content', \%args) - || new FS::template_content( { %args }); - $object->{'Hash'} = { $object->hash, $template_content->hash }; - - # set up the locale selector if this is a new content - if ( $locale eq 'new' ) { - - # make a list of available locales - my $content_locales = $object->content_locales; - my @locales = grep { !exists($content_locales->{$_}) } - FS::Conf->new->config('available-locales'); - my %labels; - foreach (@locales) { - my %info = FS::Locales->locale_info($_); - $labels{$_} = $info{'label'}; - } - unshift @locales, 'new'; - $labels{'new'} = 'Select language'; - - # insert a field def - my $i = 0; - $i++ until ( $fields_listref->[$i]->{'field'} eq 'locale' ); - my $locale_field = $fields_listref->[$i]; - - my $onchange_locale = "document.getElementById('submit').disabled = - (this.options[this.selectedIndex].value == 'new');"; - - %$locale_field = ( - field => 'locale', - type => 'select', - options => \@locales, - labels => \%labels, - curr_value => 'new', - onchange => $onchange_locale, - ); - } -} - -sub menubar_opt_callback { - my $object = shift; - # generate no tabs for new msg_templates. - my $msgnum = $object->msgnum or return; - my (@tabs, @options, %labels); - push @tabs, mt('Default'), ''; - my $display_new = 0; - my $selected = ''; - foreach my $l (FS::Locales->locales) { - if ( exists $object->content_locales->{$l} ) { - my %info = FS::Locales->locale_info($l); - push @tabs, - $info{'label'}, - ';locale='.$l; - $selected = $info{'label'} if $object->locale eq $l; - } - else { - $display_new = 1; # there is at least one unused locale left - } - } - push @tabs, mt('New'), ';locale=new' if $display_new; - $selected = mt('New') if $object->locale eq 'new'; - $selected ||= mt('Default'); - ( - 'url_base' => $p.'edit/msg_template.html?msgnum='.$msgnum, - 'selected' => $selected, - 'tabs' => \@tabs - ); -} - -my $onchange_locale = ''; - -# Create hints pane - -my %substitutions = ( - 'cust_main' => [ - '$display_custnum'=> 'Customer#', - '$agentnum' => 'Agent#', - '$agent_name' => 'Agent name', - '$payby' => 'Payment method', - '$paymask' => 'Card/account# (masked)', - '$payname' => 'Name on card/bank name', - '$paytype' => 'Account type', - '$payip' => 'IP address used to submit payment info', - '$num_ncancelled_pkgs' => '# of active packages', - '$num_cancelled_pkgs' => '# of cancelled packages', - '$num_pkgs' => '# of packages', - '$classname' => 'Customer class', - '$categoryname' => 'Customer category', - '$balance' => 'Current balance', - '$credit_limit' => 'Credit limit', - '$invoicing_list_emailonly' => 'Billing email address', - #'$cust_status' => 'Status (raw internal label)', - '$cust_status_label' => 'Status (display label)', - '$cust_statuscolor' => 'Status color code', - '$company_name' => 'Our company name', - '$company_address'=> 'Our company address', - '$company_phonenum' => 'Our phone number', - '$selfservice_server_base_url' => 'Base URL of customer self-service', - ], - 'contact' => [ # duplicate this for shipping - '$name' => 'Company and contact name', - '$name_short' => 'Company or contact name', - '$company' => 'Company name', - '$contact' => 'Contact name (last, first)', - '$contact_firstlast'=> 'Contact name (first last)', - '$first' => 'First name', - '$last' => 'Last name', - '$address1' => 'Address line 1', - '$address2' => 'Address line 2', - '$city' => 'City', - '$county' => 'County', - '$state' => 'State', - '$zip' => 'Zip', - '$country' => 'Country', - '$daytime' => 'Day phone', - '$night' => 'Night phone', - '$mobile' => 'Mobile phone', - '$fax' => 'Fax', - ], - 'service' => [ - '$ship_address1' => 'Address line 1', - '$ship_address2' => 'Address line 2', - '$ship_city' => 'City', - '$ship_county' => 'County', - '$ship_state' => 'State', - '$ship_zip' => 'Zip', - '$ship_country' => 'Country', - ], - 'cust_bill' => [ - '$invnum' => 'Invoice#', - '$_date_pretty' => 'Invoice date', - '$due_date' => 'Invoice due date (timestamp)', - '$due_date2str' => 'Invoice due date (human readable)', - ], - 'cust_pkg' => [ - '$pkgnum' => 'Package#', - '$pkg' => 'Package description', - '$pkg_label' => 'Description + comment', - '$status' => 'Status', - '$statuscolor' => 'Status color code', - '$start_ymd' => 'Start date', - '$setup_ymd' => 'Setup date', - '$last_bill_ymd' => 'Last bill date', - '$next_bill_ymd' => 'Next bill date', - '$susp_ymd' => 'Suspended on date', - '$cancel_ymd' => 'Canceled on date', - '$adjourn_ymd' => 'Adjournment date', - '$expire_ymd' => 'Expiration date', - '$labels_short' => 'Service labels', - '$location_label' => 'Service location', - ], - 'svc_acct' => [ - '$svcnum' => 'Service#', - '$username' => 'Login name', - '$password' => 'Password', - '$domain' => 'Domain name', - ], - 'svc_domain' => [ - '$svcnum' => 'Service#', - '$domain' => 'Domain name', - '$registrar' => 'Registrar name', - '$catchall' => 'Catchall email', - ], - 'svc_phone' => [ - '$svcnum' => 'Service#', - '$phonenum' => 'Phone number', - '$countrycode' => 'Country code', - '$domain' => 'Domain name' - ], - 'svc_broadband' => [ - '$svcnum' => 'Service#', - '$ip_addr' => 'IP address', - '$mac_addr' => 'MAC address', - '$speed_up' => 'Upstream speed', - '$speed_down' => 'Downstream speed', - ], - 'cust_pay' => [ - '$paynum' => 'Payment#', - '$paid' => 'Amount', - '$payby' => 'Payment method', - '$date' => 'Payment date', - '$payinfo' => 'Card/account# (masked)', - '$error' => 'Decline reason', - ], -); - -tie my %sections, 'Tie::IxHash', ( -'contact' => 'Name and contact info (billing)', -'service' => 'Service address', -'cust_main' => 'Customer status and payment info', -'cust_pkg' => 'Package fields', -'cust_bill' => 'Invoice fields', -'cust_pay' => 'Payment fields', -'svc_acct' => 'Login service fields', -'svc_domain'=> 'Domain service fields', -'svc_phone' => 'Phone service fields', -'svc_broadband' => 'Broadband service fields', -); - -my $widget = new HTML::Widgets::SelectLayers( - 'options' => \%sections, - 'form_name' => 'dummy', - 'html_between'=>'', - 'selected_layer'=>(keys(%sections))[0], - 'layer_callback' => sub { - my $section = shift; - my $html = include('/elements/table-grid.html'); - my @hints = @{ $substitutions{$section} }; - while(@hints) { - my $key = shift @hints; - $html .= qq!\n$key!; - $html .= "\n".shift(@hints).''; - } - $html .= "\n"; - return $html; - }, -); - -my $sidebar = ' - -
-Substitutions: ' -. $widget->html . -'

Click above links to insert substitution code.

-

-Enclose substitutions and other Perl expressions in braces: -
{ $name } = ExampleCo (Smith, John) -
{ time2str("%D", time) } = '.time2str("%D", time).' -

'; -$sidebar .= include('/elements/template_image-dialog.html', - 'callback' => 'insertHtml' - ); -$sidebar .= '

Insert Uploaded Image

-
-'; - -sub html_table_bottom { - my $object = shift; - $cgi->param('locale') =~ /^(\w+)$/; - my $locale = $1; - my $html; - if ( $locale and $locale ne 'new' ) { - # set up a delete link - my $msgnum = $object->msgnum; - my $url = $p."misc/delete-template_content.html?msgnum=$msgnum;locale=$1"; - my $link = qq!! . - 'Delete this template' . - ''; - $html = qq! - $link!; - } - $html; -} - +print $cgi->redirect($fsurl."edit/msg_template/$msgclass.html?".$cgi->query_string); diff --git a/httemplate/edit/msg_template/email.html b/httemplate/edit/msg_template/email.html new file mode 100644 index 000000000..dc70ef6ec --- /dev/null +++ b/httemplate/edit/msg_template/email.html @@ -0,0 +1,385 @@ +<& /edit/elements/edit.html, + 'post_url' => $fsurl.'edit/process/msg_template.html', + 'html_init' => '$sidebar
', + 'body_etc' => $body_etc, + 'name_singular' => 'template', + 'table' => 'msg_template', + 'viewall_dir' => 'browse', + 'agent_virt' => 1, + 'agent_null' => 1, + 'agent_null_right' => [ 'View global templates', 'Edit global templates' ], + + 'fields' => \@fields, + 'labels' => { + 'msgnum' => 'Template', + 'agentnum' => 'Agent', + 'msgname' => 'Template name', + 'from_addr' => 'From: ', + 'bcc_addr' => 'Bcc: ', + 'locale' => 'Locale', + 'subject' => 'Subject: ', + 'body' => 'Message body', + }, + 'edit_callback' => \&edit_callback, + 'error_callback' => \&edit_callback, + 'html_bottom' => '', + 'html_table_bottom'=> \&html_table_bottom, + 'html_foot' => ( $no_submit ? '' : "
" ), + 'no_submit' => $no_submit, +&> +<%init> +use FS::template_image; + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right([ 'View templates', 'View global templates', + 'Edit templates', 'Edit global templates', + ]); + +my $body_etc = ''; +$body_etc = q!onload="document.getElementById('locale').onchange()"! + if $cgi->param('locale') eq 'new'; + +my $msgnum = $cgi->param('msgnum'); +my $msg_template = $msgnum ? qsearchs('msg_template', {msgnum=>$msgnum}) : ''; + +my $no_submit = 0; +my @fields = (); +if ( $curuser->access_right('Edit global templates') + || ( $curuser->access_right('Edit templates') + && $msg_template + && $msg_template->agentnum + && $curuser->agentnums_href->{$msg_template->agentnum} + ) + ) +{ + push @fields, + { field => 'msgclass', + type => 'hidden', + value => 'email', + }, + { field => 'agentnum', + type => 'select-agent', + }, + { field => 'msgname', size=>60, }, + { field => 'from_addr', size=>60, }, + { field => 'bcc_addr', size=>60, }, + { type => 'tablebreak-tabs', + include_opt_callback => \&menubar_opt_callback, + }, + # template_content fields + { field => 'locale', type => 'hidden' }, + { field => 'subject', size=>60, }, + { field => 'body', + type => 'htmlarea', + width => 763, + config=> { extraPlugins => 'blockprotect' }, + }, + ; +} else { #readonly + + $no_submit = 1; + + push @fields, + { field => 'agentnum', + type => 'select-agent', + fixed => 1, + }, + { field => 'msgname', type => 'fixed', }, + { field => 'from_addr', type => 'fixed', }, + { field => 'bcc_addr', type => 'fixed', }, + { type => 'tablebreak-tabs', + include_opt_callback => \&menubar_opt_callback, + }, + # template_content fields + { field => 'locale', type => 'hidden' }, + { field => 'subject', type => 'fixed', }, + { field => 'body', + type => 'fixed', + noescape => 1, + }, + ; + +} + +sub new_callback { + my ($cgi, $object, $fields_listref, $opt_hashref) = @_; + my $template_content = new FS::template_content { 'locale' => '' }; + $object->{'Hash'} = { $object->hash, $template_content->hash }; +} + +sub edit_callback { + my ($cgi, $object, $fields_listref, $opt_hashref) = @_; + $cgi->param('locale') =~ /^(\w*)$/ or die 'bad locale '.$cgi->param('locale'); + my $locale = $1; + + # fetch the content object and merge its fields + my %args = ( + 'msgnum' => $object->msgnum, + 'locale' => $locale + ); + my $template_content = qsearchs('template_content', \%args) + || new FS::template_content( { %args }); + $object->{'Hash'} = { $object->hash, $template_content->hash }; + + # set up the locale selector if this is a new content + if ( $locale eq 'new' ) { + + # make a list of available locales + my $content_locales = $object->content_locales; + my @locales = grep { !exists($content_locales->{$_}) } + FS::Conf->new->config('available-locales'); + my %labels; + foreach (@locales) { + my %info = FS::Locales->locale_info($_); + $labels{$_} = $info{'label'}; + } + unshift @locales, 'new'; + $labels{'new'} = 'Select language'; + + # insert a field def + my $i = 0; + $i++ until ( $fields_listref->[$i]->{'field'} eq 'locale' ); + my $locale_field = $fields_listref->[$i]; + + my $onchange_locale = "document.getElementById('submit').disabled = + (this.options[this.selectedIndex].value == 'new');"; + + %$locale_field = ( + field => 'locale', + type => 'select', + options => \@locales, + labels => \%labels, + curr_value => 'new', + onchange => $onchange_locale, + ); + } +} + +sub menubar_opt_callback { + my $object = shift; + # generate no tabs for new msg_templates. + my $msgnum = $object->msgnum or return; + my (@tabs, @options, %labels); + push @tabs, mt('Default'), ''; + my $display_new = 0; + my $selected = ''; + foreach my $l (FS::Locales->locales) { + if ( exists $object->content_locales->{$l} ) { + my %info = FS::Locales->locale_info($l); + push @tabs, + $info{'label'}, + ';locale='.$l; + $selected = $info{'label'} if $object->locale eq $l; + } + else { + $display_new = 1; # there is at least one unused locale left + } + } + push @tabs, mt('New'), ';locale=new' if $display_new; + $selected = mt('New') if $object->locale eq 'new'; + $selected ||= mt('Default'); + ( + 'url_base' => $fsurl.'edit/msg_template.html?msgnum='.$msgnum, + 'selected' => $selected, + 'tabs' => \@tabs + ); +} + +my $onchange_locale = ''; + +# Create hints pane + +my %substitutions = ( + 'cust_main' => [ + '$display_custnum'=> 'Customer#', + '$agentnum' => 'Agent#', + '$agent_name' => 'Agent name', + '$payby' => 'Payment method', + '$paymask' => 'Card/account# (masked)', + '$payname' => 'Name on card/bank name', + '$paytype' => 'Account type', + '$payip' => 'IP address used to submit payment info', + '$num_ncancelled_pkgs' => '# of active packages', + '$num_cancelled_pkgs' => '# of cancelled packages', + '$num_pkgs' => '# of packages', + '$classname' => 'Customer class', + '$categoryname' => 'Customer category', + '$balance' => 'Current balance', + '$credit_limit' => 'Credit limit', + '$invoicing_list_emailonly' => 'Billing email address', + #'$cust_status' => 'Status (raw internal label)', + '$cust_status_label' => 'Status (display label)', + '$cust_statuscolor' => 'Status color code', + '$company_name' => 'Our company name', + '$company_address'=> 'Our company address', + '$company_phonenum' => 'Our phone number', + '$selfservice_server_base_url' => 'Base URL of customer self-service', + ], + 'contact' => [ # duplicate this for shipping + '$name' => 'Company and contact name', + '$name_short' => 'Company or contact name', + '$company' => 'Company name', + '$contact' => 'Contact name (last, first)', + '$contact_firstlast'=> 'Contact name (first last)', + '$first' => 'First name', + '$last' => 'Last name', + '$address1' => 'Address line 1', + '$address2' => 'Address line 2', + '$city' => 'City', + '$county' => 'County', + '$state' => 'State', + '$zip' => 'Zip', + '$country' => 'Country', + '$daytime' => 'Day phone', + '$night' => 'Night phone', + '$mobile' => 'Mobile phone', + '$fax' => 'Fax', + ], + 'service' => [ + '$ship_address1' => 'Address line 1', + '$ship_address2' => 'Address line 2', + '$ship_city' => 'City', + '$ship_county' => 'County', + '$ship_state' => 'State', + '$ship_zip' => 'Zip', + '$ship_country' => 'Country', + ], + 'cust_bill' => [ + '$invnum' => 'Invoice#', + '$_date_pretty' => 'Invoice date', + '$due_date' => 'Invoice due date (timestamp)', + '$due_date2str' => 'Invoice due date (human readable)', + ], + 'cust_pkg' => [ + '$pkgnum' => 'Package#', + '$pkg' => 'Package description', + '$pkg_label' => 'Description + comment', + '$status' => 'Status', + '$statuscolor' => 'Status color code', + '$start_ymd' => 'Start date', + '$setup_ymd' => 'Setup date', + '$last_bill_ymd' => 'Last bill date', + '$next_bill_ymd' => 'Next bill date', + '$susp_ymd' => 'Suspended on date', + '$cancel_ymd' => 'Canceled on date', + '$adjourn_ymd' => 'Adjournment date', + '$expire_ymd' => 'Expiration date', + '$labels_short' => 'Service labels', + '$location_label' => 'Service location', + ], + 'svc_acct' => [ + '$svcnum' => 'Service#', + '$username' => 'Login name', + '$password' => 'Password', + '$domain' => 'Domain name', + ], + 'svc_domain' => [ + '$svcnum' => 'Service#', + '$domain' => 'Domain name', + '$registrar' => 'Registrar name', + '$catchall' => 'Catchall email', + ], + 'svc_phone' => [ + '$svcnum' => 'Service#', + '$phonenum' => 'Phone number', + '$countrycode' => 'Country code', + '$domain' => 'Domain name' + ], + 'svc_broadband' => [ + '$svcnum' => 'Service#', + '$ip_addr' => 'IP address', + '$mac_addr' => 'MAC address', + '$speed_up' => 'Upstream speed', + '$speed_down' => 'Downstream speed', + ], + 'cust_pay' => [ + '$paynum' => 'Payment#', + '$paid' => 'Amount', + '$payby' => 'Payment method', + '$date' => 'Payment date', + '$payinfo' => 'Card/account# (masked)', + '$error' => 'Decline reason', + ], +); + +tie my %sections, 'Tie::IxHash', ( +'contact' => 'Name and contact info (billing)', +'service' => 'Service address', +'cust_main' => 'Customer status and payment info', +'cust_pkg' => 'Package fields', +'cust_bill' => 'Invoice fields', +'cust_pay' => 'Payment fields', +'svc_acct' => 'Login service fields', +'svc_domain'=> 'Domain service fields', +'svc_phone' => 'Phone service fields', +'svc_broadband' => 'Broadband service fields', +); + +my $widget = new HTML::Widgets::SelectLayers( + 'options' => \%sections, + 'form_name' => 'dummy', + 'html_between'=>'
', + 'selected_layer'=>(keys(%sections))[0], + 'layer_callback' => sub { + my $section = shift; + my $html = include('/elements/table-grid.html'); + my @hints = @{ $substitutions{$section} }; + while(@hints) { + my $key = shift @hints; + $html .= qq!\n$key!; + $html .= "\n".shift(@hints).''; + } + $html .= "\n"; + return $html; + }, +); + +my $sidebar = ' + +
+Substitutions: ' +. $widget->html . +'

Click above links to insert substitution code.

+

+Enclose substitutions and other Perl expressions in braces: +
{ $name } = ExampleCo (Smith, John) +
{ time2str("%D", time) } = '.time2str("%D", time).' +

'; +$sidebar .= include('/elements/template_image-dialog.html', + 'callback' => 'insertHtml' + ); +$sidebar .= '

Insert Uploaded Image

+
+'; + +sub html_table_bottom { + my $object = shift; + $cgi->param('locale') =~ /^(\w+)$/; + my $locale = $1; + my $html; + if ( $locale and $locale ne 'new' ) { + # set up a delete link + my $msgnum = $object->msgnum; + my $url = $fsurl."misc/delete-template_content.html?msgnum=$msgnum;locale=$1"; + my $link = qq!! . + 'Delete this template' . + ''; + $html = qq! + $link!; + } + $html; +} + + diff --git a/httemplate/edit/msg_template/http.html b/httemplate/edit/msg_template/http.html new file mode 100644 index 000000000..e82cc0c60 --- /dev/null +++ b/httemplate/edit/msg_template/http.html @@ -0,0 +1,82 @@ +<& /edit/elements/edit.html, + 'post_url' => $fsurl.'edit/process/msg_template.html', + 'name_singular' => 'message interface', + 'table' => 'msg_template', + 'viewall_dir' => 'browse', + 'agent_virt' => 1, + 'agent_null' => 1, + 'agent_null_right' => [ 'View global templates', 'Edit global templates' ], + + 'fields' => [], # callback takes care of this + 'new_callback' => $edit_callback, + 'edit_callback' => $edit_callback, + 'error_callback' => $edit_callback, + 'labels' => \%labels, + 'no_submit' => $no_submit, +&> +<%init> +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right([ 'View templates', 'View global templates', + 'Edit templates', 'Edit global templates', + ]); + +my %labels = ( + 'msgnum' => 'Template', # it's still a template number + 'agentnum' => 'Agent', + 'msgname' => 'Interface name', + 'prepare_url' => 'Prepare URL', + 'send_url' => 'Send URL', + 'username' => 'HTTP username', + 'password' => 'HTTP password', + 'content' => 'Additional POST content', +); + +my $no_submit = 0; + +my $edit_callback = sub { + my ($cgi, $msg_template, $fields, $opt) = @_; + if ( $curuser->access_right('Edit global templates') + || ( $curuser->access_right('Edit templates') + && $msg_template + && $msg_template->agentnum + && $curuser->agentnums_href->{$msg_template->agentnum} + ) + ) { + @$fields = ( + { field => 'msgclass', + type => 'hidden', + value => 'http', + }, + { field => 'agentnum', + type => 'select-agent', + }, + { field => 'msgname', size=>60, required => 1 }, + { field => 'prepare_url', size=>60, required => 1 }, + { field => 'send_url', size=>60, required => 1 }, + { field => 'username', size=>20 }, + { field => 'password', size=>20 }, + { field => 'content', type => 'textarea' }, + ); + } else { #readonly + + $no_submit = 1; + + @$fields = ( + { field => 'agentnum', + type => 'select-agent', + fixed => 1, + }, + { field => 'msgname', type => 'fixed', }, + { field => 'prepare_url', type => 'fixed', }, + { field => 'send_url', type => 'fixed', }, + { field => 'username', type => 'fixed', }, + { field => 'password', type => 'fixed', }, + { field => 'content', type => 'fixed' }, + ); + + } +}; + + diff --git a/httemplate/edit/process/msg_template.html b/httemplate/edit/process/msg_template.html index e146adf76..d8b125ae0 100644 --- a/httemplate/edit/process/msg_template.html +++ b/httemplate/edit/process/msg_template.html @@ -1,7 +1,7 @@ <% include( 'elements/process.html', 'table' => 'msg_template', - 'viewall_dir' => 'browse', - #'popup_reload'=> 1, + 'fields' => $fields, + 'viewall_url' => "browse/msg_template/$msgclass.html", 'debug' => 0, 'precheck_callback' => \&precheck_callback, 'args_callback' => \&args_callback, @@ -11,9 +11,21 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right(['Edit templates','Edit global templates']); +my $msgclass = 'email'; +if ( $cgi->param('msgclass') =~ /^(\w+)$/ ) { + $msgclass = $1; +} + +my $fields = [ fields('msg_template') ]; +my $class = "FS::msg_template::$msgclass"; +eval "use $class;"; +if ( $class->extension_table ) { + push @$fields, fields($class->extension_table); +} + sub precheck_callback { my $cgi = shift; - # validate some fields + # validate locale field (for email-type records) $cgi->param('locale') =~ /^(\w*)$/; my $locale = $1; return mt('Language required') if $locale eq 'new'; # the user didn't choose diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html index a5fb15bc2..55645cf31 100644 --- a/httemplate/elements/menu.html +++ b/httemplate/elements/menu.html @@ -767,7 +767,7 @@ tie my %config_nms, 'Tie::IxHash', ; tie my %config_misc, 'Tie::IxHash'; -$config_misc{'Message templates'} = [ $fsurl.'browse/msg_template.html', 'Templates for customer notices' ] +$config_misc{'Message templates'} = [ $fsurl.'browse/msg_template/email.html', 'Templates for customer notices' ] if $curuser->access_right(['View templates', 'View global templates', 'Edit templates', 'Edit global templates', ]); $config_misc{'Advertising sources'} = [ $fsurl.'browse/part_referral.html', 'Where a customer heard about your service.' ] -- cgit v1.2.1 From 1f343115f761ab39020a6aa76d3698fe4c8f2d61 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Sat, 29 Aug 2015 21:27:39 -0700 Subject: fix improper relative paths, incidental to #21564 --- httemplate/elements/htmlarea.html | 4 ++-- httemplate/elements/template_image-dialog.html | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'httemplate') diff --git a/httemplate/elements/htmlarea.html b/httemplate/elements/htmlarea.html index 7c40e61c7..d8b25121a 100644 --- a/httemplate/elements/htmlarea.html +++ b/httemplate/elements/htmlarea.html @@ -12,7 +12,7 @@ Example: % #init - % #editor @@ -35,7 +35,7 @@ my $config = { 'skin' => 'kama', 'toolbarCanCollapse' => JSON::true, 'removePlugins' => 'elementspath', - 'basePath' => $p.'elements/ckeditor/', + 'basePath' => $fsurl.'elements/ckeditor/', 'enterMode' => 2, %{ $opt{config} || {} }, }; diff --git a/httemplate/elements/template_image-dialog.html b/httemplate/elements/template_image-dialog.html index f7fb0c291..b471d28da 100644 --- a/httemplate/elements/template_image-dialog.html +++ b/httemplate/elements/template_image-dialog.html @@ -14,7 +14,7 @@ url - to redirect to after upload, otherwise just refreshes dialog window <% include('/elements/xmlhttp.html', - 'url' => $p.'misc/xmlhttp-template_image.cgi', + 'url' => $fsurl.'misc/xmlhttp-template_image.cgi', 'subs' => [ 'get_template_image' ], ) %> @@ -75,7 +75,7 @@ url - to redirect to after upload, otherwise just refreshes dialog window <% include('/elements/form-file_upload.html', 'name' => 'TemplateImageUploadForm', 'id' => 'TemplateImageUploadForm', - 'action' => $p.'misc/process/template_image-upload.cgi', + 'action' => $fsurl.'misc/process/template_image-upload.cgi', 'num_files' => 1, 'fields' => [ 'name', 'agentnum' ], 'url' => $opt{'url'} || 'javascript:refreshImageList(1)', -- cgit v1.2.1 From b5cfff7585a9107889dfd55208c52d24d27c4b1c Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Mon, 31 Aug 2015 13:32:38 -0700 Subject: repeatability cleanup, #37340 --- httemplate/browse/part_pkg.cgi | 1 + httemplate/browse/part_svc.cgi | 2 +- httemplate/edit/part_pkg.cgi | 23 +++++++++++++++-------- httemplate/elements/email-link.html | 3 ++- httemplate/elements/form-create_ticket.html | 2 +- httemplate/search/cust_bill.html | 4 ++-- 6 files changed, 22 insertions(+), 13 deletions(-) (limited to 'httemplate') diff --git a/httemplate/browse/part_pkg.cgi b/httemplate/browse/part_pkg.cgi index c2f1430d7..07f104e55 100755 --- a/httemplate/browse/part_pkg.cgi +++ b/httemplate/browse/part_pkg.cgi @@ -591,6 +591,7 @@ push @fields, }, ]; } + sort grep { $options{$_} =~ /\S/ } grep { $_ !~ /^(setup|recur)_fee$/ and $_ !~ /^report_option_\d+$/ } diff --git a/httemplate/browse/part_svc.cgi b/httemplate/browse/part_svc.cgi index ec5f321dd..88f8d8d19 100755 --- a/httemplate/browse/part_svc.cgi +++ b/httemplate/browse/part_svc.cgi @@ -161,7 +161,7 @@ function part_export_areyousure(href) { % } % % my($n1)=''; -% foreach my $field ( @fields ) { +% foreach my $field ( sort @fields ) { % % #a few lines of false laziness w/edit/part_svc.cgi % my $def = FS::part_svc->svc_table_fields($svcdb)->{$field}; diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi index 9f5510d65..570c5ac75 100755 --- a/httemplate/edit/part_pkg.cgi +++ b/httemplate/edit/part_pkg.cgi @@ -989,9 +989,13 @@ my $html_bottom = sub { #$html .= ''; my $href = $plans{$layer}->{'fields'}; - my @fields = exists($plans{$layer}->{'fieldorder'}) - ? @{$plans{$layer}->{'fieldorder'}} - : keys %{ $href }; + my @fields; + if ( $plans{$layer}->{'fieldorder'} ) { + @fields = @{ $plans{$layer}->{'fieldorder'} }; + } else { + warn "FS::part_pkg::$layer has no fieldorder.\n"; + @fields = keys %$href; + } # hash of dependencies for each of the Pricing Plan fields. # make sure NOT to use double-quotes inside the 'msg' value. @@ -1015,7 +1019,7 @@ my $html_bottom = sub { } } }; - + foreach my $field ( grep $_ !~ /^(setup|recur)_fee$/, @fields ) { if(!exists($href->{$field})) { @@ -1029,7 +1033,8 @@ my $html_bottom = sub { next if !$display; } - $html .= ''. $href->{$field}{'name'}. ''; + $html .= ''. $href->{$field}{'name'}. ' + '; my $format = sub { shift }; $format = $href->{$field}{'format'} if exists($href->{$field}{'format'}); @@ -1128,9 +1133,11 @@ my $html_bottom = sub { $html .= ''; } $html .= ''; - - $html .= qq('; + + $html .= include('/elements/hidden.html', + field => $layer.'__OPTIONS', + value => join(',', @fields) + ); $html; diff --git a/httemplate/elements/email-link.html b/httemplate/elements/email-link.html index 2612faabb..16935cf98 100644 --- a/httemplate/elements/email-link.html +++ b/httemplate/elements/email-link.html @@ -10,7 +10,8 @@ die "'table' required" if !$table; die "'search_hash' required" if !$search_hash; my $uri = new URI; -$uri->query_form($search_hash); +my @params = map { $_, $search_hash->{$_} } sort keys %$search_hash; +$uri->query_form(@params); my $query = $uri->query; my $label = ($opt{'label'} || 'Email a notice to these customers'); diff --git a/httemplate/elements/form-create_ticket.html b/httemplate/elements/form-create_ticket.html index 362e82397..d76c0d83e 100644 --- a/httemplate/elements/form-create_ticket.html +++ b/httemplate/elements/form-create_ticket.html @@ -6,7 +6,7 @@ function updateTicketLink() { link.href = "<% $new_base.'?'. join(';', map( { ($_ eq 'Queue') ? () : "$_=$new_param{$_}"} - keys %new_param),'Queue=') %>" + selector.options[selector.selectedIndex].value; + sort keys %new_param),'Queue=') %>" + selector.options[selector.selectedIndex].value; } Tickets diff --git a/httemplate/search/cust_bill.html b/httemplate/search/cust_bill.html index 017e8298f..6e3617b28 100755 --- a/httemplate/search/cust_bill.html +++ b/httemplate/search/cust_bill.html @@ -196,7 +196,7 @@ my $html_init = join("\n", map { ( my $action = $_ ) =~ s/_$//; include('/elements/progress-init.html', $_.'form', - [ keys %search ], + [ sort keys %search ], "../misc/${_}invoices.cgi", { 'message' => "Invoices re-${action}ed" }, #would be nice to show the number of them, but... $_, #key @@ -206,7 +206,7 @@ my $html_init = join("\n", map { my @values = ref($search{$f}) ? @{ $search{$f} } : $search{$f}; map qq!!, @values; } - keys %search + sort keys %search ), qq!! } qw( print_ email_ fax_ ftp_ spool_ ) ). -- cgit v1.2.1 From 6163b943f45e083a87cc03344eb775a9edd553ce Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Mon, 31 Aug 2015 22:16:37 -0700 Subject: allow services with a tower but no sector to appear in search results, #33056 --- httemplate/elements/select-tower_sector.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'httemplate') diff --git a/httemplate/elements/select-tower_sector.html b/httemplate/elements/select-tower_sector.html index a16d3bfa0..59b016359 100644 --- a/httemplate/elements/select-tower_sector.html +++ b/httemplate/elements/select-tower_sector.html @@ -12,7 +12,7 @@ table => 'tower', name_col => 'towername', id => 'towernum', - field => 'dummy_towernum', + field => 'towernum', onchange => 'change_towernum(this.value);', element_etc => 'STYLE="vertical-align:top"', &> @@ -63,5 +63,5 @@ foreach my $towernum (keys %sectors_of) { } } -my $empty_label = $opt{'empty_label'} || 'Include services with no tower/sector'; +my $empty_label = $opt{'empty_label'} || 'Include services with no sector'; -- cgit v1.2.1 From e0e76b55a2f83c19e4114eefe4dabcab092808b4 Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Tue, 1 Sep 2015 23:11:05 -0500 Subject: RT#32892: Monthly Sales Tax Report --- httemplate/search/report_tax_sales.cgi | 158 ++++++++++++++++++++++++++++++++ httemplate/search/report_tax_sales.html | 35 +++++++ 2 files changed, 193 insertions(+) create mode 100644 httemplate/search/report_tax_sales.cgi create mode 100755 httemplate/search/report_tax_sales.html (limited to 'httemplate') diff --git a/httemplate/search/report_tax_sales.cgi b/httemplate/search/report_tax_sales.cgi new file mode 100644 index 000000000..5c531c343 --- /dev/null +++ b/httemplate/search/report_tax_sales.cgi @@ -0,0 +1,158 @@ + +<% include('/graph/elements/report.html', + 'title' => 'Monthly Sales Tax Report', + 'items' => \@row_labels, + 'data' => \@rowdata, + 'row_labels' => \@row_labels, + 'colors' => [], + 'col_labels' => \@col_labels, + ) %> + +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Financial reports'); + +# validate cgi input +my $start_month = $cgi->param('start_month'); +die "Bad start month" unless $start_month =~ /^\d*$/; +my $start_year = $cgi->param('start_year'); +die "Bad start year" unless $start_year =~ /^\d*$/; +my $end_month = $cgi->param('end_month'); +die "Bad end month" unless $end_month =~ /^\d*$/; +my $end_year = $cgi->param('end_year'); +die "Bad end year" unless $end_year =~ /^\d*$/; +die "End year before start year" if $end_year < $start_year; +die "End month before start month" if ($start_year == $end_year) && ($end_month < $start_month); +my $country = $cgi->param('country'); +die "Bad country code" unless $country =~ /^\w\w$/; + +# Data structure for building final table +# row order will be calculated separately +# +# $data->{$rowlabel} = \@rowvalues +# + +my $data = {}; + +### Calculate package values + +my @pkg_class = qsearch('pkg_class'); +my @pkg_classnum = map { $_->classnum } @pkg_class; +unshift(@pkg_classnum,0); +my @pkg_classname = map { $_->classname } @pkg_class; +unshift(@pkg_classname,'(empty class)'); + +# some false laziness with graph/elements/monthly.html +my %reportopts = ( + 'items' => [ qw( cust_bill_pkg cust_bill_pkg_credits ) ], + 'cross_params' => [ map { [ 'classnum', $_ ] } @pkg_classnum ], + 'start_month' => $start_month, + 'start_year' => $start_year, + 'end_month' => $end_month, + 'end_year' => $end_year, +); +my $pkgreport = new FS::Report::Table::Monthly(%reportopts); +my $pkgdata = $pkgreport->data; + +# assuming every month/year combo is included in results, +# just use this list for the final table +my @col_labels = @{$pkgdata->{'label'}}; + +# unpack report data into a more manageable format +foreach my $item ( qw( invoiced credited ) ) { # invoiced, credited + my $itemref = shift @{$pkgdata->{'data'}}; + foreach my $label (@{$pkgdata->{'label'}}) { # month/year + my $labelref = shift @$itemref; + foreach my $classname (@pkg_classname) { # pkg class + my $value = shift @$labelref; + my $rowlabel = $classname.' '.$item; + $data->{$rowlabel} ||= []; + push(@{$data->{$rowlabel}},$value); + } + } +} + +### Calculate tax values + +# false laziness w report_tax.html, put this in FS::Report::Tax? +my $sth = dbh->prepare('SELECT DISTINCT(COALESCE(taxname, \'Tax\')) FROM cust_main_county'); +$sth->execute or die $sth->errstr; +my @taxnames = map { $_->[0] } @{ $sth->fetchall_arrayref }; +$sth->finish; + +# get DateTime objects for start & end +my $startdate = DateTime->new( + year => $start_year, + month => $start_month, + day => 1 + ); +my $enddate = DateTime->new( + year => $end_year, + month => $end_month, + day => 1 + ); +$enddate->add( months => 1 )->subtract( seconds => 1 ); # the last second of the month + +# common to all tax reports +my %params = ( + 'country' => $country, + 'credit_date' => 'cust_bill', +); + +# run a report for each month, for each tax +my $countdate = $startdate->clone; +while ($countdate < $enddate) { + + # set report start date, iterate to end of this month, set report end date + $params{'beginning'} = $countdate->epoch; + $params{'ending'} = $countdate->add( months => 1 )->subtract( seconds => 1 )->epoch; + + # run a report for each tax name + foreach my $taxname (@taxnames) { + $params{'taxname'} = $taxname; + my $report = FS::Report::Tax->report_internal(%params); + + # extract totals from report, kinda awkward + my $pkgclass = ''; # this will get more complicated if we breakdown by pkgclass + my @values = (0,0); + if ($report->{'total'}->{$pkgclass}) { + my %totals = map { $$_[0] => $$_[2] } @{$report->{'total'}->{$pkgclass}}; + $values[0] = $totals{'tax'}; + $values[1] = $totals{'credit'}; + } + + # treat each tax class like it's an additional pkg class + foreach my $item ( qw ( invoiced credited ) ) { + my $rowlabel = $taxname . ' ' . $item; + my $value = shift @values; + $data->{$rowlabel} ||= []; + push(@{$data->{$rowlabel}},$value); + } + + } + + # iterate to next month + $countdate->add( seconds => 1 ); +} + +# put the data in the order we want it +my @row_labels; +my @rowdata; +foreach my $classname (@pkg_classname,@taxnames) { + my @classlabels = (); + my @classdata = (); + my $hasdata = 0; + foreach my $item ( qw( invoiced credited ) ) { + my $rowlabel = $classname . ' ' . $item; + my $rowdata = $data->{$rowlabel}; + $hasdata = 1 if grep { $_ } @$rowdata; + push(@classlabels,$rowlabel); + push(@classdata,$rowdata); + } + next unless $hasdata; # don't include class if it has no data in time range + push(@row_labels,@classlabels); + push(@rowdata,@classdata); +} + + diff --git a/httemplate/search/report_tax_sales.html b/httemplate/search/report_tax_sales.html new file mode 100755 index 000000000..374a15601 --- /dev/null +++ b/httemplate/search/report_tax_sales.html @@ -0,0 +1,35 @@ +<% include('/elements/header.html', 'Monthly Sales Tax Report' ) %> + +
+ + + + <% include('/elements/tr-select-from_to.html') %> + + <% include('/elements/tr-select.html', + 'label' => 'Country', + 'field' => 'country', + 'options' => \@countries, + 'curr_value' => ($conf->config('countrydefault') || 'US'), + ) %> + +
+ +
+ +
+ +<% include('/elements/footer.html') %> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Financial reports'); + +my $conf = new FS::Conf; + +# false laziness w report_tax.html, put this in FS::Report::Tax? +my $sth = dbh->prepare('SELECT DISTINCT(country) FROM cust_location'); +$sth->execute or die $sth->errstr; +my @countries = map { $_->[0] } @{ $sth->fetchall_arrayref }; + + -- cgit v1.2.1 From 5cbb1285d26ffe2f7fbf8aed14b5b3d7c037fe83 Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Wed, 2 Sep 2015 21:05:28 -0500 Subject: RT#32892: Monthly Sales Tax Report [fixed names and colors] --- httemplate/elements/menu.html | 2 + httemplate/graph/elements/report.html | 6 +- httemplate/search/report_tax_sales.cgi | 158 ----------------------------- httemplate/search/report_tax_sales.html | 35 ------- httemplate/search/tax_sales.cgi | 172 ++++++++++++++++++++++++++++++++ httemplate/search/tax_sales.html | 35 +++++++ 6 files changed, 213 insertions(+), 195 deletions(-) delete mode 100644 httemplate/search/report_tax_sales.cgi delete mode 100755 httemplate/search/report_tax_sales.html create mode 100644 httemplate/search/tax_sales.cgi create mode 100755 httemplate/search/tax_sales.html (limited to 'httemplate') diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html index 55645cf31..ea6933198 100644 --- a/httemplate/elements/menu.html +++ b/httemplate/elements/menu.html @@ -381,6 +381,8 @@ if( $curuser->access_right('Financial reports') ) { $report_financial{'Tax Liability (vendor tax data)'} = [ $fsurl.'search/report_newtax.html', 'Tax liability report (vendor tax data)' ] if $taxproducts; + $report_financial{'Monthly Sales and Taxes'} = [$fsurl.'search/tax_sales.html', 'Monthly sales and taxes report']; + # most sites don't need this but there isn't really a config to enable it $report_financial{'E911 Fee Summary'} = [ $fsurl.'search/report_e911.html', 'E911 fee summary' ]; diff --git a/httemplate/graph/elements/report.html b/httemplate/graph/elements/report.html index f1b0d166d..b5d214816 100644 --- a/httemplate/graph/elements/report.html +++ b/httemplate/graph/elements/report.html @@ -11,6 +11,7 @@ Example: #these run parallel to items, and can be given as hashes 'row_labels' => \@row_labels, #required 'colors' => \@colors, #required + 'bgcolors' => \@bgcolors, #optional 'graph_labels' => \@graph_labels, #defaults to row_labels 'links' => \@links, #optional @@ -22,7 +23,7 @@ Example: #optional 'nototal' => 1, - 'graph_type' => 'LinesPoints', + 'graph_type' => 'LinesPoints', #can be 'none' for no graph 'bottom_total' => 1, 'sprintf' => '%u', #sprintf format, overrides default %.2f 'disable_money' => 1, @@ -231,7 +232,8 @@ any delimiter and linked from the elements in @data. % foreach my $row ( @items ) { % #make a style % my $color = shift @{ $opt{'colors'} }; -% push @styles, ".i$i { text-align: right; color: #$color; }"; +% my $bgcolor = $opt{'bgcolors'} ? (shift @{ $opt{'bgcolors'} }) : 'ffffff'; +% push @styles, ".i$i { text-align: right; color: #$color; background: #$bgcolor; }"; % #create the data row % my $links = shift @{$opt{'links'}} || ['']; % my $link_prefix = shift @$links; diff --git a/httemplate/search/report_tax_sales.cgi b/httemplate/search/report_tax_sales.cgi deleted file mode 100644 index 5c531c343..000000000 --- a/httemplate/search/report_tax_sales.cgi +++ /dev/null @@ -1,158 +0,0 @@ - -<% include('/graph/elements/report.html', - 'title' => 'Monthly Sales Tax Report', - 'items' => \@row_labels, - 'data' => \@rowdata, - 'row_labels' => \@row_labels, - 'colors' => [], - 'col_labels' => \@col_labels, - ) %> - -<%init> - -die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Financial reports'); - -# validate cgi input -my $start_month = $cgi->param('start_month'); -die "Bad start month" unless $start_month =~ /^\d*$/; -my $start_year = $cgi->param('start_year'); -die "Bad start year" unless $start_year =~ /^\d*$/; -my $end_month = $cgi->param('end_month'); -die "Bad end month" unless $end_month =~ /^\d*$/; -my $end_year = $cgi->param('end_year'); -die "Bad end year" unless $end_year =~ /^\d*$/; -die "End year before start year" if $end_year < $start_year; -die "End month before start month" if ($start_year == $end_year) && ($end_month < $start_month); -my $country = $cgi->param('country'); -die "Bad country code" unless $country =~ /^\w\w$/; - -# Data structure for building final table -# row order will be calculated separately -# -# $data->{$rowlabel} = \@rowvalues -# - -my $data = {}; - -### Calculate package values - -my @pkg_class = qsearch('pkg_class'); -my @pkg_classnum = map { $_->classnum } @pkg_class; -unshift(@pkg_classnum,0); -my @pkg_classname = map { $_->classname } @pkg_class; -unshift(@pkg_classname,'(empty class)'); - -# some false laziness with graph/elements/monthly.html -my %reportopts = ( - 'items' => [ qw( cust_bill_pkg cust_bill_pkg_credits ) ], - 'cross_params' => [ map { [ 'classnum', $_ ] } @pkg_classnum ], - 'start_month' => $start_month, - 'start_year' => $start_year, - 'end_month' => $end_month, - 'end_year' => $end_year, -); -my $pkgreport = new FS::Report::Table::Monthly(%reportopts); -my $pkgdata = $pkgreport->data; - -# assuming every month/year combo is included in results, -# just use this list for the final table -my @col_labels = @{$pkgdata->{'label'}}; - -# unpack report data into a more manageable format -foreach my $item ( qw( invoiced credited ) ) { # invoiced, credited - my $itemref = shift @{$pkgdata->{'data'}}; - foreach my $label (@{$pkgdata->{'label'}}) { # month/year - my $labelref = shift @$itemref; - foreach my $classname (@pkg_classname) { # pkg class - my $value = shift @$labelref; - my $rowlabel = $classname.' '.$item; - $data->{$rowlabel} ||= []; - push(@{$data->{$rowlabel}},$value); - } - } -} - -### Calculate tax values - -# false laziness w report_tax.html, put this in FS::Report::Tax? -my $sth = dbh->prepare('SELECT DISTINCT(COALESCE(taxname, \'Tax\')) FROM cust_main_county'); -$sth->execute or die $sth->errstr; -my @taxnames = map { $_->[0] } @{ $sth->fetchall_arrayref }; -$sth->finish; - -# get DateTime objects for start & end -my $startdate = DateTime->new( - year => $start_year, - month => $start_month, - day => 1 - ); -my $enddate = DateTime->new( - year => $end_year, - month => $end_month, - day => 1 - ); -$enddate->add( months => 1 )->subtract( seconds => 1 ); # the last second of the month - -# common to all tax reports -my %params = ( - 'country' => $country, - 'credit_date' => 'cust_bill', -); - -# run a report for each month, for each tax -my $countdate = $startdate->clone; -while ($countdate < $enddate) { - - # set report start date, iterate to end of this month, set report end date - $params{'beginning'} = $countdate->epoch; - $params{'ending'} = $countdate->add( months => 1 )->subtract( seconds => 1 )->epoch; - - # run a report for each tax name - foreach my $taxname (@taxnames) { - $params{'taxname'} = $taxname; - my $report = FS::Report::Tax->report_internal(%params); - - # extract totals from report, kinda awkward - my $pkgclass = ''; # this will get more complicated if we breakdown by pkgclass - my @values = (0,0); - if ($report->{'total'}->{$pkgclass}) { - my %totals = map { $$_[0] => $$_[2] } @{$report->{'total'}->{$pkgclass}}; - $values[0] = $totals{'tax'}; - $values[1] = $totals{'credit'}; - } - - # treat each tax class like it's an additional pkg class - foreach my $item ( qw ( invoiced credited ) ) { - my $rowlabel = $taxname . ' ' . $item; - my $value = shift @values; - $data->{$rowlabel} ||= []; - push(@{$data->{$rowlabel}},$value); - } - - } - - # iterate to next month - $countdate->add( seconds => 1 ); -} - -# put the data in the order we want it -my @row_labels; -my @rowdata; -foreach my $classname (@pkg_classname,@taxnames) { - my @classlabels = (); - my @classdata = (); - my $hasdata = 0; - foreach my $item ( qw( invoiced credited ) ) { - my $rowlabel = $classname . ' ' . $item; - my $rowdata = $data->{$rowlabel}; - $hasdata = 1 if grep { $_ } @$rowdata; - push(@classlabels,$rowlabel); - push(@classdata,$rowdata); - } - next unless $hasdata; # don't include class if it has no data in time range - push(@row_labels,@classlabels); - push(@rowdata,@classdata); -} - - diff --git a/httemplate/search/report_tax_sales.html b/httemplate/search/report_tax_sales.html deleted file mode 100755 index 374a15601..000000000 --- a/httemplate/search/report_tax_sales.html +++ /dev/null @@ -1,35 +0,0 @@ -<% include('/elements/header.html', 'Monthly Sales Tax Report' ) %> - -
- - - - <% include('/elements/tr-select-from_to.html') %> - - <% include('/elements/tr-select.html', - 'label' => 'Country', - 'field' => 'country', - 'options' => \@countries, - 'curr_value' => ($conf->config('countrydefault') || 'US'), - ) %> - -
- -
- -
- -<% include('/elements/footer.html') %> -<%init> - -die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Financial reports'); - -my $conf = new FS::Conf; - -# false laziness w report_tax.html, put this in FS::Report::Tax? -my $sth = dbh->prepare('SELECT DISTINCT(country) FROM cust_location'); -$sth->execute or die $sth->errstr; -my @countries = map { $_->[0] } @{ $sth->fetchall_arrayref }; - - diff --git a/httemplate/search/tax_sales.cgi b/httemplate/search/tax_sales.cgi new file mode 100644 index 000000000..4b28c934a --- /dev/null +++ b/httemplate/search/tax_sales.cgi @@ -0,0 +1,172 @@ + +<% include('/graph/elements/report.html', + 'title' => 'Monthly Sales and Taxes Report', + 'items' => \@row_labels, + 'data' => \@rowdata, + 'row_labels' => \@row_labels, + 'colors' => \@rowcolors, + 'bgcolors' => \@rowbgcolors, + 'col_labels' => \@col_labels, + 'graph_type' => 'none', + ) %> + +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Financial reports'); + +# validate cgi input +my $start_month = $cgi->param('start_month'); +die "Bad start month" unless $start_month =~ /^\d*$/; +my $start_year = $cgi->param('start_year'); +die "Bad start year" unless $start_year =~ /^\d*$/; +my $end_month = $cgi->param('end_month'); +die "Bad end month" unless $end_month =~ /^\d*$/; +my $end_year = $cgi->param('end_year'); +die "Bad end year" unless $end_year =~ /^\d*$/; +die "End year before start year" if $end_year < $start_year; +die "End month before start month" if ($start_year == $end_year) && ($end_month < $start_month); +my $country = $cgi->param('country'); +die "Bad country code" unless $country =~ /^\w\w$/; + +# Data structure for building final table +# row order will be calculated separately +# +# $data->{$rowlabel} = \@rowvalues +# + +my $data = {}; + +### Calculate package values + +my @pkg_class = qsearch('pkg_class'); +my @pkg_classnum = map { $_->classnum } @pkg_class; +unshift(@pkg_classnum,0); +my @pkg_classname = map { $_->classname } @pkg_class; +unshift(@pkg_classname,'(empty class)'); + +# some false laziness with graph/elements/monthly.html +my %reportopts = ( + 'items' => [ qw( cust_bill_pkg cust_bill_pkg_credits ) ], + 'cross_params' => [ map { [ 'classnum', $_ ] } @pkg_classnum ], + 'start_month' => $start_month, + 'start_year' => $start_year, + 'end_month' => $end_month, + 'end_year' => $end_year, +); +my $pkgreport = new FS::Report::Table::Monthly(%reportopts); +my $pkgdata = $pkgreport->data; + +# assuming every month/year combo is included in results, +# just use this list for the final table +my @col_labels = @{$pkgdata->{'label'}}; + +# unpack report data into a more manageable format +foreach my $item ( qw( invoiced credited ) ) { # invoiced, credited + my $itemref = shift @{$pkgdata->{'data'}}; + foreach my $label (@{$pkgdata->{'label'}}) { # month/year + my $labelref = shift @$itemref; + foreach my $classname (@pkg_classname) { # pkg class + my $value = shift @$labelref; + my $rowlabel = $classname.' '.$item; + $data->{$rowlabel} ||= []; + push(@{$data->{$rowlabel}},$value); + } + } +} + +### Calculate tax values + +# false laziness w report_tax.html, put this in FS::Report::Tax? +my $sth = dbh->prepare('SELECT DISTINCT(COALESCE(taxname, \'Tax\')) FROM cust_main_county'); +$sth->execute or die $sth->errstr; +my @taxnames = map { $_->[0] } @{ $sth->fetchall_arrayref }; +$sth->finish; + +# get DateTime objects for start & end +my $startdate = DateTime->new( + year => $start_year, + month => $start_month, + day => 1 + ); +my $enddate = DateTime->new( + year => $end_year, + month => $end_month, + day => 1 + ); +$enddate->add( months => 1 )->subtract( seconds => 1 ); # the last second of the month + +# common to all tax reports +my %params = ( + 'country' => $country, + 'credit_date' => 'cust_bill', +); + +# run a report for each month, for each tax +my $countdate = $startdate->clone; +while ($countdate < $enddate) { + + # set report start date, iterate to end of this month, set report end date + $params{'beginning'} = $countdate->epoch; + $params{'ending'} = $countdate->add( months => 1 )->subtract( seconds => 1 )->epoch; + + # run a report for each tax name + foreach my $taxname (@taxnames) { + $params{'taxname'} = $taxname; + my $report = FS::Report::Tax->report_internal(%params); + + # extract totals from report, kinda awkward + my $pkgclass = ''; # this will get more complicated if we breakdown by pkgclass + my @values = (0,0); + if ($report->{'total'}->{$pkgclass}) { + my %totals = map { $$_[0] => $$_[2] } @{$report->{'total'}->{$pkgclass}}; + $values[0] = $totals{'tax'}; + $values[1] = $totals{'credit'}; + } + + # treat each tax class like it's an additional pkg class + foreach my $item ( qw ( invoiced credited ) ) { + my $rowlabel = $taxname . ' ' . $item; + my $value = shift @values; + $data->{$rowlabel} ||= []; + push(@{$data->{$rowlabel}},$value); + } + + } + + # iterate to next month + $countdate->add( seconds => 1 ); +} + +# put the data in the order we want it +my @row_labels; +my @rowdata; +my @rowcolors; +my @rowbgcolors; +my $pkgcount = 0; #for colors +foreach my $classname (@pkg_classname,@taxnames) { + my $istax = ($pkgcount++ < @pkg_classname) ? 0 : 1; + my @classlabels = (); + my @classdata = (); + my @classcolors = (); + my @classbgcolors = (); + my $hasdata = 0; + foreach my $item ( qw( invoiced credited ) ) { + my $rowlabel = $classname . ' ' . $item; + my $rowdata = $data->{$rowlabel}; + my $rowcolor = $istax ? '0000ff' : '000000'; + my $rowbgcolor = ($item eq 'credited') ? 'cccccc' : 'ffffff'; + $hasdata = 1 if grep { $_ } @$rowdata; + push(@classlabels,$rowlabel); + push(@classdata,$rowdata); + push(@classcolors,$rowcolor); + push(@classbgcolors,$rowbgcolor); + } + next unless $hasdata; # don't include class if it has no data in time range + push(@row_labels,@classlabels); + push(@rowdata,@classdata); + push(@rowcolors,@classcolors); + push(@rowbgcolors,@classbgcolors); +} + + diff --git a/httemplate/search/tax_sales.html b/httemplate/search/tax_sales.html new file mode 100755 index 000000000..61cf86e2e --- /dev/null +++ b/httemplate/search/tax_sales.html @@ -0,0 +1,35 @@ +<% include('/elements/header.html', 'Monthly Sales and Taxes Report' ) %> + +
+ + + + <% include('/elements/tr-select-from_to.html') %> + + <% include('/elements/tr-select.html', + 'label' => 'Country', + 'field' => 'country', + 'options' => \@countries, + 'curr_value' => ($conf->config('countrydefault') || 'US'), + ) %> + +
+ +
+ +
+ +<% include('/elements/footer.html') %> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Financial reports'); + +my $conf = new FS::Conf; + +# false laziness w report_tax.html, put this in FS::Report::Tax? +my $sth = dbh->prepare('SELECT DISTINCT(country) FROM cust_location'); +$sth->execute or die $sth->errstr; +my @countries = map { $_->[0] } @{ $sth->fetchall_arrayref }; + + -- cgit v1.2.1 From bb70ee978959d0489e6a049aedbb18250ee2e594 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Thu, 3 Sep 2015 13:42:45 -0700 Subject: quick payment entry: fix preloading of rows when some of them contain bad amounts, #15861 --- httemplate/misc/batch-cust_pay.html | 97 +++++++++++++++++++++++++++---------- 1 file changed, 71 insertions(+), 26 deletions(-) (limited to 'httemplate') diff --git a/httemplate/misc/batch-cust_pay.html b/httemplate/misc/batch-cust_pay.html index 9f2540cc7..197ade14f 100644 --- a/httemplate/misc/batch-cust_pay.html +++ b/httemplate/misc/batch-cust_pay.html @@ -101,6 +101,10 @@ function select_discount_term(row) { var invoices_for_row = new Object; +var preloading = 0; // the number of preloading threads currently running + +// callback from toggle_application_row: we've received a list of +// the customer's open invoices. store them. function update_invoices(rownum, invoices) { invoices_for_row[rownum] = new Object; // only called before create_application_row @@ -113,6 +117,12 @@ function toggle_application_row(ev, next) { if (!next) next = function(){}; //optional continuation var rownum = this.getAttribute('rownum'); if ( this.checked ) { + // the user has opted to apply the payment to specific invoices. + // - lock the customer + // - fetch the list of open invoices + // - create a row to select an invoice + // - then optionally call "next", with this as the invocant + // and the rownum as argument; we use this to preload rows. var custnum = document.getElementById('custnum'+rownum).value; if (!custnum) return; lock_payment_row(rownum, true); @@ -124,6 +134,9 @@ function toggle_application_row(ev, next) { } ); } else { + // the user has opted not to do that. + // - remove all application rows + // - unlock the customer var row = document.getElementById('row'+rownum); var table_rows = row.parentNode.rows; for (i = row.sectionRowIndex; i < table_rows.count; i++) { @@ -183,6 +196,16 @@ function amount_unapplied(rownum) { var change_app_amount; +// the user has chosen an invoice. the previously chosen invoice is still +// in curr_invoice +// - if there is a value there, put it back on the invoices_for_row list for +// this customer. +// - then _remove_ the newly chosen invoice from that list. +// - find the "owed" element for this application row and set its value to the +// amount owed on that invoice. +// - find the "amount" element for this application row and set its value to +// either "owed" or the remaining payment amount, whichever is less. +// - call change_app_amount() on that element. function choose_app_invnum() { var rownum = this.getAttribute('rownum'); var appnum = this.getAttribute('appnum'); @@ -210,8 +233,10 @@ function choose_app_invnum() { } } +// the invoice selector has gained focus. clear its list of options, and +// replace them with the list of open invoices (from invoices_for_row). +// if there's already a selected invoice, prepend that to the list. function focus_app_invnum() { -% # invoice numbers just display as invoice numbers var rownum = this.getAttribute('rownum'); var add_opt = function(obj, value, label) { var o = document.createElement('OPTION'); @@ -233,14 +258,15 @@ function focus_app_invnum() { } } +// an application amount has been changed. if there's any unapplied payment +// amount, and any remaining invoices_for_row, add a blank application row. +// (but don't do this while preloading; it will unconditionally add enough +// rows to show all the attempted applications) function change_app_amount() { var rownum = this.getAttribute('rownum'); var appnum = this.getAttribute('appnum'); -%# maybe some kind of warning if amount_unapplied < 0? -%# only spawn a new application row if there are open invoices left, -%# and this is the highest-numbered application row for the customer, -%# and the sum of the applied amounts is < the amount of the payment, - if ( Object.keys(invoices_for_row[rownum]).length > 0 + if ( preloading == 0 + && Object.keys(invoices_for_row[rownum]).length > 0 && !document.getElementById( 'row'+rownum+'.'+(parseInt(appnum) + 1) ) && amount_unapplied(rownum) > 0 ) { @@ -248,6 +274,9 @@ function change_app_amount() { } } +// we're creating a payment application row. +// create the following elements: , s, "Apply to invoice" caption, +// invnum selector, "owed" display, amount input box, delete button. function create_application_row(rownum, appnum) { var payment_row = document.getElementById('row'+rownum); var tr_app = document.createElement('TR'); @@ -341,29 +370,45 @@ function preload() { var enable = document.getElementById('enable_app'+rownum); enable.checked = true; var preload_row = function(r) {//continuation from toggle_application_row - for (appnum=0; appnum < row_obj[r].length; appnum++) { - this_app = row_obj[r][appnum]; - var x = r + '.' + appnum; - //set invnum - var select_invnum = document.getElementById('invnum'+x); - focus_app_invnum.call(select_invnum); - for (i=0; i Date: Wed, 9 Sep 2015 19:18:45 -0700 Subject: fix itemdesc filter, #38020, from #26770 --- httemplate/search/cust_bill_pkg.cgi | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'httemplate') diff --git a/httemplate/search/cust_bill_pkg.cgi b/httemplate/search/cust_bill_pkg.cgi index 4fb9b662b..278382feb 100644 --- a/httemplate/search/cust_bill_pkg.cgi +++ b/httemplate/search/cust_bill_pkg.cgi @@ -601,6 +601,16 @@ if ( $cgi->param('nottax') ) { } } + # itemdesc, for breakdown from the vendor tax report + # (this is definitely used) + if ( $cgi->param('itemdesc') ) { + if ( $cgi->param('itemdesc') eq 'Tax' ) { + push @where, "($itemdesc = 'Tax' OR $itemdesc is null)"; + } else { + push @where, "$itemdesc = ". dbh->quote($cgi->param('itemdesc')); + } + } + } else { # the internal-tax case my $tax_select = 'SELECT tax.billpkgnum, SUM(tax.amount) as tax_total'; -- cgit v1.2.1 From 8eeac13d3a8b231efd786eca0555087de5dbb17e Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Thu, 10 Sep 2015 21:33:37 -0500 Subject: RT#33410: Package GB add-ons --- httemplate/edit/process/change-cust_pkg.html | 39 +++++++- httemplate/elements/cust_pkg_usageprice.html | 9 +- httemplate/elements/order_pkg.js | 68 +------------ httemplate/misc/change_pkg.cgi | 23 ++++- httemplate/misc/cust_pkg_usageprice.html | 121 +++++++++++++++++++++++ httemplate/misc/order_pkg.html | 21 +--- httemplate/misc/xmlhttp-part_pkg_usageprice.html | 18 +++- 7 files changed, 199 insertions(+), 100 deletions(-) create mode 100644 httemplate/misc/cust_pkg_usageprice.html (limited to 'httemplate') diff --git a/httemplate/edit/process/change-cust_pkg.html b/httemplate/edit/process/change-cust_pkg.html index 046a9795c..308ea8ffd 100644 --- a/httemplate/edit/process/change-cust_pkg.html +++ b/httemplate/edit/process/change-cust_pkg.html @@ -59,6 +59,40 @@ unless ($error) { $error = $cust_pkg->change_later(\%change); } } else { + + # for now, can't change usageprice with change_later + my @old_cust_pkg_usageprice = $cust_pkg->cust_pkg_usageprice; + + # build new usageprice array + # false laziness with /edit/process/quick-cust_pkg.cgi + my @cust_pkg_usageprice = (); + foreach my $quantity_param ( grep { $cgi->param($_) && $cgi->param($_) > 0 } + grep /^usagepricenum(\d+)_quantity$/, + $cgi->param + ) + { + $quantity_param =~ /^usagepricenum(\d+)_quantity$/ or die 'unpossible'; + my $num = $1; + push @cust_pkg_usageprice, new FS::cust_pkg_usageprice { + usagepricepart => scalar($cgi->param("usagepricenum${num}_usagepricepart")), + quantity => scalar($cgi->param($quantity_param)), + }; + } + + # Need to figure out if usagepricepart quantities changed + my %oldup = map { $_->usagepricepart, $_->quantity } @old_cust_pkg_usageprice; + my %newup = map { $_->usagepricepart, $_->quantity } @cust_pkg_usageprice; + my $usagechanged = 0; + foreach my $up (keys %oldup) { + last if $usagechanged; + $usagechanged = 1 unless $oldup{$up} == $newup{$up}; + } + foreach my $up (keys %newup) { + last if $usagechanged; + $usagechanged = 1 unless $oldup{$up} == $newup{$up}; + } + $change{'cust_pkg_usageprice'} = \@cust_pkg_usageprice; + # special case: if there's a package change scheduled, and it matches # the parameters the user requested this time, then change to the existing # future package. @@ -68,12 +102,13 @@ unless ($error) { $change_to->pkgpart == $change{'pkgpart'} and $change_to->locationnum == $change{'locationnum'} and $change_to->quantity == $change{'quantity'} and - $change_to->contract_end == $change{'contract_end'} + $change_to->contract_end == $change{'contract_end'} and + !$usagechanged ) { %change = ( 'cust_pkg' => $change_to ); } } - + # do a package change right now my $pkg_or_error = $cust_pkg->change( \%change ); $error = ref($pkg_or_error) ? '' : $pkg_or_error; diff --git a/httemplate/elements/cust_pkg_usageprice.html b/httemplate/elements/cust_pkg_usageprice.html index 729099320..74b7842be 100644 --- a/httemplate/elements/cust_pkg_usageprice.html +++ b/httemplate/elements/cust_pkg_usageprice.html @@ -23,15 +23,16 @@ > % my $info = $part_pkg_usageprice->target_info; % my $amount = $part_pkg_usageprice->amount / ($info->{multiplier}||1); - % for (1..100) { #100? arbitrary. - % } @@ -42,8 +43,6 @@ % } <%init> -#my $targets = FS::part_pkg_usageprice->targets; - my( %opt ) = @_; my $conf = new FS::Conf; diff --git a/httemplate/elements/order_pkg.js b/httemplate/elements/order_pkg.js index 3586a54cb..a850d2193 100644 --- a/httemplate/elements/order_pkg.js +++ b/httemplate/elements/order_pkg.js @@ -1,10 +1,12 @@ function pkg_changed () { var form = document.OrderPkgForm; var discountnum = form.discountnum; + var opt = form.pkgpart.options[form.pkgpart.selectedIndex]; + + usageprice_pkg_changed( opt.value ); if ( form.pkgpart.selectedIndex > 0 ) { - var opt = form.pkgpart.options[form.pkgpart.selectedIndex]; var date_button = document.getElementById('start_date_button'); var date_button_disabled = document.getElementById('start_date_disabled'); var date_text = document.getElementById('start_date_text'); @@ -68,78 +70,14 @@ function pkg_changed () { } } - get_part_pkg_usageprice( opt.value, update_part_pkg_usageprice ); - } else { form.submitButton.disabled = true; if ( discountnum ) { form.discountnum.disabled = true; } discountnum_changed(form.discountnum); } -} - -function update_part_pkg_usageprice(part_pkg_usageprice) { - - var table = document.getElementById('cust_pkg_usageprice_table'); - - // black the current usage price rows - for ( var r = table.rows.length - 1; r >= 0; r-- ) { - table.deleteRow(r); - } - - // add the new usage price rows - var rownum = 0; - var usagepriceArray = eval('(' + part_pkg_usageprice + ')' ); - for ( var s = 0; s < usagepriceArray.length; s=s+2 ) { - //surely this should be some kind of JSON structure - var html = usagepriceArray[s+0]; - var javascript = usagepriceArray[s+1]; - - // a lot like ("inspiried by") edit/elements/edit.html function spawn_<%$field%> - - // XXX evaluate the javascript - //if (window.ActiveXObject) { - // window.execScript(newfunc); - //} else { /* (window.XMLHttpRequest) */ - // //window.eval(newfunc); - // setTimeout(newfunc, 0); - //} - - var row = table.insertRow(rownum++); - - //var label_cell = document.createElement('TD'); - - //label_cell.id = '<% $field %>_label' + <%$field%>_fieldnum; - - //label_cell.style.textAlign = "right"; - //label_cell.style.verticalAlign = "top"; - //label_cell.style.borderTop = "1px solid black"; - //label_cell.style.paddingTop = "5px"; - - //label_cell.innerHTML = '<% $label %>'; - - //row.appendChild(label_cell); - - var widget_cell = document.createElement('TD'); - - //widget_cell.style.borderTop = "1px solid black"; - widget_cell.style.paddingTop = "3px"; - widget_cell.colSpan = "2"; - - widget_cell.innerHTML = html; - - row.appendChild(widget_cell); - - } - - if ( rownum > 0 ) { - document.getElementById('cust_pkg_usageprice_title').style.display = ''; - } else { - document.getElementById('cust_pkg_usageprice_title').style.display = 'none'; - } } - function standardize_new_location() { var form = document.OrderPkgForm; var loc = form.locationnum; diff --git a/httemplate/misc/change_pkg.cgi b/httemplate/misc/change_pkg.cgi index e74747e82..b562d24cd 100755 --- a/httemplate/misc/change_pkg.cgi +++ b/httemplate/misc/change_pkg.cgi @@ -19,13 +19,13 @@ <& /elements/tr-select-cust-part_pkg.html, 'pre_label' => emt('New'), - 'curr_value' => scalar($cgi->param('pkgpart')), + 'curr_value' => scalar($cgi->param('pkgpart')) || $cust_pkg->pkgpart, 'classnum' => $part_pkg->classnum, 'cust_main' => $cust_main, &> <& /elements/tr-input-pkg-quantity.html, - 'curr_value' => $cust_pkg->quantity + 'curr_value' => scalar($cgi->param('quantity')) || $cust_pkg->quantity &> % if ($use_contract_end) { @@ -39,6 +39,11 @@
+<% include('/misc/cust_pkg_usageprice.html', + 'pkgpart' => (scalar($cgi->param('pkgpart')) || $cust_pkg->pkgpart), + 'pkgnum' => ($cust_pkg->change_to_pkgnum || $pkgnum), + ) %> +
<% mt('Change') |h %> <% ntable('#cccccc') %> @@ -49,8 +54,16 @@ document.getElementById('start_date_text').disabled = !enable; document.getElementById('start_date_button').style.display = (enable ? '' : 'none'); - document.getElementById('start_date_button_disabled').style.display = - (enable ? 'none' : ''); + if (document.getElementById('start_date_button_disabled')) { // does this ever exist anymore? + document.getElementById('start_date_button_disabled').style.display = + (enable ? 'none' : ''); + } + if (enable) { + usageprice_disable(1); + } else { + var form = document.OrderPkgForm; + usageprice_disable(0,form.pkgpart.options[form.pkgpart.selectedIndex].value); + } } <&| /elements/onload.js &> delay_changed(); @@ -96,7 +109,7 @@ TYPE = "button" VALUE = "<% mt("Change package") |h %>" onClick = "this.disabled=true; standardize_new_location();" - <% scalar($cgi->param('pkgpart')) ? '' : 'DISABLED' %> + <% #scalar($cgi->param('pkgpart')) ? '' : 'DISABLED' %> > diff --git a/httemplate/misc/cust_pkg_usageprice.html b/httemplate/misc/cust_pkg_usageprice.html new file mode 100644 index 000000000..f2e0f57e6 --- /dev/null +++ b/httemplate/misc/cust_pkg_usageprice.html @@ -0,0 +1,121 @@ +<%doc> +Sets up the xmlhttp, javascript and initial (empty) table for selecting cust_pkg_usageprice. +Available values are based on pkgpart, and can be updated when changing pkgpart +by passing the new pkgpart to the following javascript: + + usageprice_pkg_changed( pkgpart, pkgnum ) + +The pkgnum input is optional, and will be used to set initial selected values. + +If pkgpart is passed as an option to this element, will run usageprice_pkg_changed +once to initialize table; pkgnum can be passed as an option along with this. + +You can disable usageprice selection temporarily (remove the fields from the form) +with the javascript usageprice_disable(1), and restore it with usageprice_disable(0,pkgnum). +While disabled, calling usageprice_pkg_changed will have no effect. + + +<& /elements/xmlhttp.html, + 'url' => $p.'misc/xmlhttp-part_pkg_usageprice.html', + 'subs' => [ 'get_part_pkg_usageprice' ], +&> + + + + +
+ + + +<%init> +my %opt = @_; + + + diff --git a/httemplate/misc/order_pkg.html b/httemplate/misc/order_pkg.html index 799165fe0..cb2bd4832 100644 --- a/httemplate/misc/order_pkg.html +++ b/httemplate/misc/order_pkg.html @@ -5,11 +5,6 @@ } &> -<& /elements/xmlhttp.html, - 'url' => $p.'misc/xmlhttp-part_pkg_usageprice.html', - 'subs' => [ 'get_part_pkg_usageprice' ], -&> - <& /elements/init_calendar.html &> @@ -121,19 +116,9 @@
-%#so: -%# - hide until you selecdt a pacakge with add-ons -%# -lookup and display the available add-ons when -%# -add them to the (recur if there is one, otherwise setup) price and display magically like processing fees do on edit/cust_pay.cgi - -%# better label? - - - -
+<% include('/misc/cust_pkg_usageprice.html', + 'pkgpart' => $pkgpart + ) %>
% my $discount_cust_pkg = $curuser->access_right('Discount customer package'); diff --git a/httemplate/misc/xmlhttp-part_pkg_usageprice.html b/httemplate/misc/xmlhttp-part_pkg_usageprice.html index d4e2d8469..9decdeff9 100644 --- a/httemplate/misc/xmlhttp-part_pkg_usageprice.html +++ b/httemplate/misc/xmlhttp-part_pkg_usageprice.html @@ -1,24 +1,32 @@ <% encode_json( \@return ) %>\ <%init> -my( $pkgpart ) = $cgi->param('arg'); +my( $pkgpart, $pkgnum ) = $cgi->param('arg'); #could worry about agent-virting this so you can't see the add-on pricing of # other agents, but not a real-world big worry my $part_pkg = qsearchs( 'part_pkg', { pkgpart=>$pkgpart } ); +my %curr_quantity; +if ($pkgnum) { + my $cust_pkg = qsearchs( 'cust_pkg', { pkgnum=>$pkgnum } ); + %curr_quantity = map { $_->usagepricepart, $_->quantity } $cust_pkg->cust_pkg_usageprice; +} + my $num = 0; -my @return = map { +# probably don't need to be returning js_only anymore? +my @return = ($pkgpart, map { + my $usagepricepart = $_->usagepricepart; my @inc = ('/elements/cust_pkg_usageprice.html', - 'usagepricepart' => $_->usagepricepart, + 'usagepricepart' => $usagepricepart, ); - + push(@inc,'curr_quantity',($curr_quantity{$usagepricepart} || 0)); ( include(@inc, field=>'usagepricenum'.$num, html_only=>1 ), include(@inc, field=>'usagepricenum'.$num++, js_only=>1 ), ); } - $part_pkg->part_pkg_usageprice; + $part_pkg->part_pkg_usageprice); -- cgit v1.2.1 From 58d388d4354f18477e9863ad95c78e73772d1768 Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Mon, 14 Sep 2015 13:01:38 -0700 Subject: don't show disabled towers in dropdown, RT#37488 --- httemplate/elements/select-tower_sector.html | 1 + 1 file changed, 1 insertion(+) (limited to 'httemplate') diff --git a/httemplate/elements/select-tower_sector.html b/httemplate/elements/select-tower_sector.html index 59b016359..458bcddcf 100644 --- a/httemplate/elements/select-tower_sector.html +++ b/httemplate/elements/select-tower_sector.html @@ -11,6 +11,7 @@ <& /elements/select-table.html, table => 'tower', name_col => 'towername', + hashref => { 'disabled' => '', }, id => 'towernum', field => 'towernum', onchange => 'change_towernum(this.value);', -- cgit v1.2.1 From 62bfe13409a16e04599f52edb3ce00ee3031a0f9 Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Wed, 16 Sep 2015 01:59:07 -0500 Subject: RT#36813: Monthly Recurring Total [change_to_pkgnum handling] --- httemplate/view/cust_main/billing.html | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'httemplate') diff --git a/httemplate/view/cust_main/billing.html b/httemplate/view/cust_main/billing.html index c031ce929..f7ea68a65 100644 --- a/httemplate/view/cust_main/billing.html +++ b/httemplate/view/cust_main/billing.html @@ -44,11 +44,13 @@ % 'hashref' => { 'custnum' => $cust_main->custnum, }, % 'extra_sql' => 'AND ( cancel IS NULL OR cancel = 0 ) % AND freq = '. dbh->quote($freq), +% 'order_by' => 'ORDER BY pkgnum', # to ensure old pkgs come before change_to_pkg % }) or next; % % my $freq_pretty = $cust_pkg[0]->part_pkg->freq_pretty; % % my $amount = 0; +% my $skip_pkg = {}; % foreach my $cust_pkg (@cust_pkg) { % my $part_pkg = $cust_pkg->part_pkg; % next if $cust_pkg->susp @@ -57,6 +59,15 @@ % || $cust_pkg->option('no_suspend_bill') % ); % +% #pkg change handling +% next if $skip_pkg->{$cust_pkg->pkgnum}; +% if ($cust_pkg->change_to_pkgnum) { +% #if change is on or before next bill date, use new pkg +% next if $cust_pkg->expire <= $cust_pkg->bill; +% #if change is after next bill date, use old (this) pkg +% $skip_pkg->{$cust_pkg->change_to_pkgnum} = 1; +% } +% % my $pkg_amount = 0; % % #add recurring amounts for this package and its billing add-ons -- cgit v1.2.1 From 7ee96ef046f8e5167a4dda7c4322485549ec29c3 Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Thu, 17 Sep 2015 19:27:10 -0500 Subject: RT#35197: Apply changes button in Edit rate plan screen clears the global default --- httemplate/edit/process/rate_detail.html | 1 - 1 file changed, 1 deletion(-) (limited to 'httemplate') diff --git a/httemplate/edit/process/rate_detail.html b/httemplate/edit/process/rate_detail.html index 0709d5079..f8a744418 100644 --- a/httemplate/edit/process/rate_detail.html +++ b/httemplate/edit/process/rate_detail.html @@ -12,7 +12,6 @@ die "access denied" my $set_default_detail = sub { my ($cgi, $rate_detail) = @_; -warn Dumper $rate_detail; if (!$rate_detail->dest_regionnum) { # then this is a global default rate my $rate = $rate_detail->rate; -- cgit v1.2.1 From 5aafaf2e4efe3a7b57ec9afd563ced32e70b581f Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Fri, 18 Sep 2015 00:40:10 -0700 Subject: fix HTML --- httemplate/elements/tr-td-label.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'httemplate') diff --git a/httemplate/elements/tr-td-label.html b/httemplate/elements/tr-td-label.html index 78690f1fb..f7067221b 100644 --- a/httemplate/elements/tr-td-label.html +++ b/httemplate/elements/tr-td-label.html @@ -9,7 +9,7 @@ Actually $label VALIGN = "<% $opt{'valign'} || 'top' %>" STYLE = "<% $style %>" ID = "<% $opt{label_id} || $opt{id}. '_label0' %>" - ><% $required %><% $opt{label} %> + ><% $required %><% $opt{label} %> <%init> -- cgit v1.2.1 From c0c5709fb022b83a482d0b35f7094505766d5868 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Fri, 18 Sep 2015 10:18:43 -0700 Subject: send commission reports by email, #33101 --- .../elements/popup_link-send_report_batch.html | 28 ++++ httemplate/misc/process/send-report.html | 7 + httemplate/misc/send-report.html | 166 +++++++++++++++++++++ httemplate/search/cust_msg.html | 3 +- httemplate/search/report_sales_commission_pkg.html | 10 ++ httemplate/search/sales_commission_pkg.html | 7 + 6 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 httemplate/elements/popup_link-send_report_batch.html create mode 100644 httemplate/misc/process/send-report.html create mode 100644 httemplate/misc/send-report.html (limited to 'httemplate') diff --git a/httemplate/elements/popup_link-send_report_batch.html b/httemplate/elements/popup_link-send_report_batch.html new file mode 100644 index 000000000..5f4471054 --- /dev/null +++ b/httemplate/elements/popup_link-send_report_batch.html @@ -0,0 +1,28 @@ +<%doc> + +Example: + +<& /elements/popup_link-send_report_batch.html, + reportname => 'sales_commission_pkg', + label => 'Click here to send reports by email', +&> + +<& /elements/popup_link.html, $params &>\ +<%init> + +my $params = { 'closetext' => emt('Close') }; + +if (ref($_[0]) eq 'HASH') { + $params = { %$params, %{ $_[0] } }; +} else { + $params = { %$params, @_ }; +} + +$params->{'label'} ||= emt('Send reports by email'); +$params->{'actionlabel'} ||= emt('Send reports'); +#$params->{'width'} ||= 350; +$params->{'height'} ||= 650; + +$params->{'action'} = $fsurl. 'misc/send-report.html?reportname='. $params->{'reportname'}; + + diff --git a/httemplate/misc/process/send-report.html b/httemplate/misc/process/send-report.html new file mode 100644 index 000000000..3bceebc0c --- /dev/null +++ b/httemplate/misc/process/send-report.html @@ -0,0 +1,7 @@ +<%init> +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Send reports to customers'); + +my $server = FS::UI::Web::JSRPC->new('FS::report_batch::process_send_report', $cgi); + +<% $server->process %> diff --git a/httemplate/misc/send-report.html b/httemplate/misc/send-report.html new file mode 100644 index 000000000..557767a57 --- /dev/null +++ b/httemplate/misc/send-report.html @@ -0,0 +1,166 @@ +<%doc> + +Parameters: + +- reportname: the report name (per FS::report_batch) + + +<& /elements/header-popup.html, { title => $report_info->{name} } &> + +
+ + + + + <& /elements/tr-select-agent.html &> + + <& /elements/tr-td-label.html, label => emt('Message template') &> + + + + <& /elements/tr-input-beginning_ending.html &> + + <& /elements/progress-init.html, + 'OneTrueForm', + [ qw( reportname msgnum agentnum beginning ending ) ], + $p.'misc/process/send-report.html', + { message => 'Reports sent', + url => $cgi->referer } + &> + +
+ <& /elements/select-msg_template.html, field => 'msgnum' &> +
+ + +
+ + + +% if ( @report_history ) { +
+ + + + + + + + + +% my $row = 0; +% foreach my $report (@report_history) { +% my $agent = ($report->agentnum ? +% $report->agent->agent : 'All agents'); + + + + + + + +% $row++; +% } + +
<% emt('Report history') %>
AgentSent onDate rangeUser
<% $agent %><% time2str($date_format, $report->send_date) %><% time2str($date_format, $report->sdate) %><% time2str($date_format, $report->edate) %><% $report->access_user->username %>
+% } + +<& /elements/footer.html &> + +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Send reports to customers'); + +$cgi->param('reportname') =~ /^(\w+)$/ + or die "bad reportname"; +my $reportname = $1; +my $report_info = $FS::report_batch::sendable_reports{$reportname} + or die "bad reportname"; + +my $date_format = FS::Conf->new->config('date_format') || '%x'; + +my @report_history = qsearch({ + table => 'report_batch', + hashref => { reportname => $reportname }, + order_by => ' ORDER BY send_date DESC', +}); + +# defaults per agent that could be selected for the report +my %agent; + +foreach my $report ( @report_history ) { + my $agentnum = $report->agentnum; + next if $agent{$agentnum}; + + # estimate the width of the report period, in months + my $last_sdate = DateTime->from_epoch( epoch => $report->sdate ); + my $last_edate = DateTime->from_epoch( epoch => $report->edate ); + + my $days = $last_sdate->delta_days( $last_edate )->delta_days; + my $months = sprintf('%.0f', $days / 6) / 5; + + my $next_sdate = $last_edate->clone->add(days => 1); + my $next_edate = $next_sdate->clone; + if ( $months >= 1 ) { # then treat as an interval in months + $next_edate->add( months => sprintf('%.0f', $months) ); + $next_edate->subtract(days => 1); + } else { # treat as a number of days + $next_edate->add( days => $days ); + } + + my $name = $agentnum ? FS::agent->by_key($agentnum)->agent : 'All agents'; + $agent{$agentnum} = { + name => $name, + beginning => $next_sdate->strftime($date_format), + ending => $next_edate->strftime($date_format), + msgnum => $report->msgnum, + }; +} + + diff --git a/httemplate/search/cust_msg.html b/httemplate/search/cust_msg.html index 401f52ebb..e9aece202 100644 --- a/httemplate/search/cust_msg.html +++ b/httemplate/search/cust_msg.html @@ -144,11 +144,12 @@ include('/elements/select.html', include('/elements/select.html', 'field' => 'msgtype', 'curr_value' => $cgi->param('msgtype') || '', - 'options' => [ '', 'invoice', 'receipt', 'admin' ], + 'options' => [ '', 'invoice', 'receipt', 'admin', 'report' ], 'labels' => { '' => '(any)', 'invoice' => 'Invoices', 'receipt' => 'Receipts', 'admin' => 'Admin notices', + 'report' => 'Reports', }, ) . ' diff --git a/httemplate/search/report_sales_commission_pkg.html b/httemplate/search/report_sales_commission_pkg.html index 6adf090e9..27906e0c3 100644 --- a/httemplate/search/report_sales_commission_pkg.html +++ b/httemplate/search/report_sales_commission_pkg.html @@ -1,5 +1,15 @@ <& /elements/header.html, 'Sales commission report per package' &> +% if ($FS::CurrentUser::CurrentUser->access_right('Send reports to customers')) +% { +

+<& /elements/popup_link-send_report_batch.html, + reportname => 'sales_commission_pkg', + label => emt('Send these reports by email'), +&> +

+% } +
diff --git a/httemplate/search/sales_commission_pkg.html b/httemplate/search/sales_commission_pkg.html index 2b5f2bb0a..9fbe22eca 100644 --- a/httemplate/search/sales_commission_pkg.html +++ b/httemplate/search/sales_commission_pkg.html @@ -1,12 +1,17 @@ %# still not a good way to do rows grouped by some field in a search.html %# report +%# (there is now, but we're not yet sponsored to switch this over to it) % if ( $type eq 'xls' ) { <% $data %>\ % } else { +% if ( $type eq 'html-print' ) { +<& /elements/header-popup.html, $title &> +% } else { <& /elements/header.html, $title &>

Download full results
as Excel spreadsheet

+% }
<& /elements/table-grid.html &> + + % my ($custnum, $sales, $commission, $row, $bgcolor) = (0, 0, 0, 0); % foreach my $cust_pkg ( @cust_pkg ) { % if ( $custnum ne $cust_pkg->custnum ) { -- cgit v1.2.1 From 15278bb4dcfaf4bdb79c7f8781320e24ef8f1e7d Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Sat, 19 Sep 2015 18:11:54 -0500 Subject: RT#35197: Apply changes button in Edit rate plan screen clears the global default [removed preserve_rate_detail, always true] --- httemplate/edit/rate.cgi | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'httemplate') diff --git a/httemplate/edit/rate.cgi b/httemplate/edit/rate.cgi index 183ea8a42..1b052d62d 100644 --- a/httemplate/edit/rate.cgi +++ b/httemplate/edit/rate.cgi @@ -5,7 +5,7 @@ <% include('/elements/progress-init.html', 'OneTrueForm', - [ 'rate', 'agentnum', 'preserve_rate_detail' ], # 'rate', 'min_', 'sec_' ], + [ 'rate', 'agentnum' ], 'process/rate.cgi', $p.'browse/rate.cgi', ) @@ -27,8 +27,6 @@
Package Sales Percentage Commission

- - " onClick="document.OneTrueForm.submit.disabled=true; process();"> -- cgit v1.2.1 From 0cf5ea1f85245f80e595f853b86aee03e3438042 Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Sat, 19 Sep 2015 19:36:55 -0500 Subject: RT#36813: Monthly Recurring Total [fixed order by] --- httemplate/view/cust_main/billing.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'httemplate') diff --git a/httemplate/view/cust_main/billing.html b/httemplate/view/cust_main/billing.html index f7ea68a65..0c9f74a7c 100644 --- a/httemplate/view/cust_main/billing.html +++ b/httemplate/view/cust_main/billing.html @@ -44,7 +44,7 @@ % 'hashref' => { 'custnum' => $cust_main->custnum, }, % 'extra_sql' => 'AND ( cancel IS NULL OR cancel = 0 ) % AND freq = '. dbh->quote($freq), -% 'order_by' => 'ORDER BY pkgnum', # to ensure old pkgs come before change_to_pkg +% 'order_by' => 'ORDER BY COALESCE(start_date,0), pkgnum', # to ensure old pkgs come before change_to_pkg % }) or next; % % my $freq_pretty = $cust_pkg[0]->part_pkg->freq_pretty; -- cgit v1.2.1 From 1f688eba76414dfb81882d3ac800a6710312202a Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Sat, 19 Sep 2015 20:32:00 -0500 Subject: RT#37488: Tower/sector selection box is showing disabled towers [removed disabled when using tower_sector] --- httemplate/elements/select-tower_sector.html | 2 ++ 1 file changed, 2 insertions(+) (limited to 'httemplate') diff --git a/httemplate/elements/select-tower_sector.html b/httemplate/elements/select-tower_sector.html index 458bcddcf..76ff25223 100644 --- a/httemplate/elements/select-tower_sector.html +++ b/httemplate/elements/select-tower_sector.html @@ -2,6 +2,8 @@ <& /elements/select-table.html, table => 'tower_sector', name_col => 'description', + addl_from => 'JOIN tower USING (towernum)', + extra_sql => q(WHERE disabled = '' OR disabled IS NULL), order_by => 'ORDER BY towernum,sectorname', empty_label => ' ', @_ -- cgit v1.2.1 From 01698260f2624212ab71be26bb4c644c0aeea2e4 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Sat, 19 Sep 2015 10:56:59 -0700 Subject: add credited sales column to tax report, #37088 --- httemplate/search/cust_credit_bill_pkg.html | 24 ++++++++++++++++------ httemplate/search/report_tax.cgi | 31 ++++++++++++++++++++++++----- 2 files changed, 44 insertions(+), 11 deletions(-) (limited to 'httemplate') diff --git a/httemplate/search/cust_credit_bill_pkg.html b/httemplate/search/cust_credit_bill_pkg.html index 63d70c27e..b5a0ee9f6 100644 --- a/httemplate/search/cust_credit_bill_pkg.html +++ b/httemplate/search/cust_credit_bill_pkg.html @@ -203,6 +203,7 @@ if ( $cgi->param('taxclass') my @loc_param = qw( district city county state country ); if ( $cgi->param('out') ) { + # probably don't need this part my ( $loc_sql, @param ) = FS::cust_pkg->location_sql( 'ornull' => 1 ); while ( $loc_sql =~ /\?/ ) { #easier to do our own substitution @@ -242,6 +243,8 @@ if ( $cgi->param('out') ) { #hacky, could be more efficient. care if it is ever used for more than the # tax-report_groups filtering kludge + # (does that even still exist? if so, correct this (or location_sql itself) + # to work with modern cust_location links) my $locs_sql = ' ( '. join(' OR ', map { @@ -266,15 +269,24 @@ if ( $cgi->param('out') ) { } else { - my %ph = map { $_ => dbh->quote( scalar($cgi->param($_)) ) } @loc_param; - - my ( $loc_sql, @param ) = FS::cust_pkg->location_sql; - while ( $loc_sql =~ /\?/ ) { #easier to do our own substitution - $loc_sql =~ s/\?/$ph{shift(@param)}/e; + my @loc_where; + foreach (@loc_param) { + if ( length($cgi->param($_)) ) { + my $quoted = dbh->quote($cgi->param($_)); + push @loc_where, "(COALESCE(cust_location.$_, '') = $quoted)"; + } } + my $loc_sql = join(' AND ', @loc_where); - push @where, $loc_sql; + #my %ph = map { $_ => dbh->quote( scalar($cgi->param($_)) ) } @loc_param; + # + #my ( $loc_sql, @param ) = FS::cust_pkg->location_sql; + #while ( $loc_sql =~ /\?/ ) { #easier to do our own substitution + # $loc_sql =~ s/\?/$ph{shift(@param)}/e; + #} + push @where, $loc_sql; +warn $loc_sql; } my($title, $name); diff --git a/httemplate/search/report_tax.cgi b/httemplate/search/report_tax.cgi index 1d906473e..6d0e95d2a 100644 --- a/httemplate/search/report_tax.cgi +++ b/httemplate/search/report_tax.cgi @@ -22,7 +22,7 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px } - Sales + Sales Rate @@ -41,6 +41,7 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px } Non-taxable Non-taxable Non-taxable + Credited Taxable @@ -73,10 +74,19 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px } % } # if $row->{pkgclass} ne ... % # construct base links that limit to the tax rates described by this row +% # cust_bill_pkg.cgi wants a list of specific taxnums (and package class) +% # cust_credit_bill_pkg.html wants a geographic scope (and package class) % my $rowlink = ';taxnum=' . $row->{taxnums}; +% my $rowregion = ''; +% foreach my $loc (qw(state county city district)) { +% if ( $row->{$loc} ) { +% $rowregion .= ";$loc=" . uri_escape($row->{$loc}); +% } +% } % # and also the package class, if we're limiting package class % if ( $params{breakdown}->{pkgclass} ) { % $rowlink .= ';classnum=' . ($row->{pkgclass} || 0); +% $rowregion .= ';classnum=' . ($row->{pkgclass} || 0); % } % % if ( $row->{total} ) { @@ -109,14 +119,20 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px } <% $money_sprintf->( $row->{exempt_monthly} ) %> +% # credited sales + + + <% $money_sprintf->( $row->{sales_credited} ) %> + + + × + <% $row->{rate} %> % # taxable sales "> <% $money_sprintf->( $row->{taxable} ) %> - × - <% $row->{rate} %> % # estimated tax = @@ -134,12 +150,12 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px } − %# currently broken - <% $money_sprintf->( $row->{credit} ) %> + <% $money_sprintf->( $row->{tax_credited} ) %> %# % # net tax due = - <% $money_sprintf->( $row->{tax} - $row->{credit} ) %> + <% $money_sprintf->( $row->{tax} - $row->{tax_credited} ) %> % # tax collected   <% $money_sprintf->( $row->{tax_paid} ) %> @@ -223,6 +239,11 @@ if ( $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"; +my $salescreditlink = $p. "search/cust_credit_bill_pkg.html?$dateagentlink;nottax=1"; +if ( $params{'credit_date'} eq 'cust_credit_bill' ) { + $salescreditlink =~ s/begin/credit_begin/; + $salescreditlink =~ s/end/credit_end/; +} #my $creditlink = $p. "search/cust_bill_pkg.cgi?$dateagentlink;credit=1;istax=1"; #if ( $params{'credit_date'} eq 'cust_credit_bill' ) { # $creditlink =~ s/begin/credit_begin/; -- cgit v1.2.1 From 15a4e1674694b76ecc2af87de479aabe370ac03d Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Tue, 22 Sep 2015 01:08:04 -0500 Subject: RT#37908: Convert existing email-sending code to use common interface [removals and switches to FS::Log] --- httemplate/misc/delete-cust_credit.cgi | 21 --------------------- httemplate/view/cust_main/payment_history.html | 2 +- .../view/cust_main/payment_history/credit.html | 11 +---------- 3 files changed, 2 insertions(+), 32 deletions(-) delete mode 100755 httemplate/misc/delete-cust_credit.cgi (limited to 'httemplate') diff --git a/httemplate/misc/delete-cust_credit.cgi b/httemplate/misc/delete-cust_credit.cgi deleted file mode 100755 index 03eb47299..000000000 --- a/httemplate/misc/delete-cust_credit.cgi +++ /dev/null @@ -1,21 +0,0 @@ -% if ( $error ) { -% errorpage($error); -% } else { -<% $cgi->redirect($p. "view/cust_main.cgi?". $custnum) %> -% } -<%init> - -die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Delete credit'); - -#untaint crednum -my($query) = $cgi->keywords; -$query =~ /^(\d+)$/ || die "Illegal crednum"; -my $crednum = $1; - -my $cust_credit = qsearchs('cust_credit',{'crednum'=>$crednum}); -my $custnum = $cust_credit->custnum; - -my $error = $cust_credit->delete; - - diff --git a/httemplate/view/cust_main/payment_history.html b/httemplate/view/cust_main/payment_history.html index 1525e9314..c85559543 100644 --- a/httemplate/view/cust_main/payment_history.html +++ b/httemplate/view/cust_main/payment_history.html @@ -231,7 +231,7 @@ my %opt = ( 'Post refund', 'Post check refund', 'Post cash refund ', 'Refund payment', 'Credit card void', 'Echeck void', 'Void payments', 'Unvoid payments', 'Delete payment', 'Unapply payment', - 'Apply credit', 'Delete credit', 'Unapply credit', 'Void credit', 'Unvoid credit', + 'Apply credit', 'Unapply credit', 'Void credit', 'Unvoid credit', 'Delete refund', 'Billing event reports', 'View customer billing events', ) diff --git a/httemplate/view/cust_main/payment_history/credit.html b/httemplate/view/cust_main/payment_history/credit.html index 3eed833d3..db2e5e582 100644 --- a/httemplate/view/cust_main/payment_history/credit.html +++ b/httemplate/view/cust_main/payment_history/credit.html @@ -1,4 +1,4 @@ -<% $credit. ' '. $reason. $desc. $change_pkg. $apply. $delete. $unapply. $void %> +<% $credit. ' '. $reason. $desc. $change_pkg. $apply . $unapply. $void %> <%init> my( $cust_credit, %opt ) = @_; @@ -138,15 +138,6 @@ $void = ' ('. if $cust_credit->closed !~ /^Y/i && $opt{'Void credit'}; -my $delete = ''; -$delete = areyousure_link("${p}misc/delete-cust_credit.cgi?".$cust_credit->crednum, - emt('Are you sure you want to delete this credit?'), - '', - emt('delete') - ) - if $cust_credit->closed !~ /^Y/i - && $opt{'Delete credit'}; - my $unapply = ''; $unapply = areyousure_link("${p}misc/unapply-cust_credit.cgi?".$cust_credit->crednum, emt('Are you sure you want to unapply this credit?'), -- cgit v1.2.1 From 076f8cdad3dea2c56859df36479be398074c4807 Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Mon, 28 Sep 2015 20:17:40 -0700 Subject: remove credit voiding ACL, RT#37908 --- httemplate/edit/process/cust_credit_bill.cgi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'httemplate') diff --git a/httemplate/edit/process/cust_credit_bill.cgi b/httemplate/edit/process/cust_credit_bill.cgi index d3847dc40..db15eac18 100755 --- a/httemplate/edit/process/cust_credit_bill.cgi +++ b/httemplate/edit/process/cust_credit_bill.cgi @@ -12,8 +12,7 @@ die "access denied" if ( $cgi->param('src_amount') ) { die "access denied" - unless ( $FS::CurrentUser::CurrentUser->access_right('Post credit') && - $FS::CurrentUser::CurrentUser->access_right('Delete credit') ); + unless $FS::CurrentUser::CurrentUser->access_right('Post credit') } -- cgit v1.2.1 From 727d620374a9798dd2fe630d57e707fe16a63e49 Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Mon, 28 Sep 2015 20:21:12 -0700 Subject: remove payment deletion, RT#37908 --- httemplate/view/cust_main/payment_history.html | 2 +- httemplate/view/cust_main/payment_history/payment.html | 12 +----------- 2 files changed, 2 insertions(+), 12 deletions(-) (limited to 'httemplate') diff --git a/httemplate/view/cust_main/payment_history.html b/httemplate/view/cust_main/payment_history.html index c85559543..d81fe9935 100644 --- a/httemplate/view/cust_main/payment_history.html +++ b/httemplate/view/cust_main/payment_history.html @@ -230,7 +230,7 @@ my %opt = ( 'Apply payment', 'Refund credit card payment', 'Refund Echeck payment', 'Post refund', 'Post check refund', 'Post cash refund ', 'Refund payment', 'Credit card void', 'Echeck void', 'Void payments', 'Unvoid payments', - 'Delete payment', 'Unapply payment', + 'Unapply payment', 'Apply credit', 'Unapply credit', 'Void credit', 'Unvoid credit', 'Delete refund', 'Billing event reports', 'View customer billing events', diff --git a/httemplate/view/cust_main/payment_history/payment.html b/httemplate/view/cust_main/payment_history/payment.html index 0ed2f8003..fd336b86c 100644 --- a/httemplate/view/cust_main/payment_history/payment.html +++ b/httemplate/view/cust_main/payment_history/payment.html @@ -1,5 +1,5 @@ <% $payment. ' '. $info. $desc. - $view. $change_pkg. $apply. $refund. $void. $delete. $unapply + $view. $change_pkg. $apply. $refund. $void. $unapply %> <%init> @@ -185,16 +185,6 @@ $void = areyousure_link("${p}misc/void-cust_pay.cgi?".$cust_pay->paynum, || ( $cust_pay->payby !~ /^(CARD|CHEK)$/ && $opt{'Void payments'} ) ); -my $delete = ''; -$delete = areyousure_link("${p}misc/delete-cust_pay.cgi?".$cust_pay->paynum, - emt('Are you sure you want to delete this payment?'), - emt('Delete this payment from the database completely - not recommended'), - emt('delete') - ) - if $cust_pay->closed !~ /^Y/i - && $opt{'deletepayments'} - && $opt{'Delete payment'}; - my $unapply = ''; $unapply = areyousure_link("${p}misc/unapply-cust_pay.cgi?".$cust_pay->paynum, emt('Are you sure you want to unapply this payment?'), -- cgit v1.2.1 From d3880a1402fd46454ab448d59c2e4ff861094981 Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Mon, 28 Sep 2015 20:21:27 -0700 Subject: remove payment deletion, RT#37908 --- httemplate/misc/delete-cust_pay.cgi | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100755 httemplate/misc/delete-cust_pay.cgi (limited to 'httemplate') diff --git a/httemplate/misc/delete-cust_pay.cgi b/httemplate/misc/delete-cust_pay.cgi deleted file mode 100755 index 38e7e4ba1..000000000 --- a/httemplate/misc/delete-cust_pay.cgi +++ /dev/null @@ -1,21 +0,0 @@ -% if ( $error ) { -% errorpage($error); -% } else { -<% $cgi->redirect($p. "view/cust_main.cgi?". $custnum) %> -% } -<%init> - -die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Delete payment'); - -#untaint paynum -my($query) = $cgi->keywords; -$query =~ /^(\d+)$/ || die "Illegal paynum"; -my $paynum = $1; - -my $cust_pay = qsearchs('cust_pay',{'paynum'=>$paynum}); -my $custnum = $cust_pay->custnum; - -my $error = $cust_pay->delete; - - -- cgit v1.2.1 From c74ee632580cc2b90175bb266e442bce54d4b400 Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Tue, 29 Sep 2015 00:00:42 -0500 Subject: RT#38048 not storing credit card #s --- httemplate/misc/process/payment.cgi | 77 +++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 38 deletions(-) (limited to 'httemplate') diff --git a/httemplate/misc/process/payment.cgi b/httemplate/misc/process/payment.cgi index 27b818660..d9299e5bd 100644 --- a/httemplate/misc/process/payment.cgi +++ b/httemplate/misc/process/payment.cgi @@ -135,6 +135,45 @@ $cgi->param('discount_term') =~ /^(\d*)$/ or errorpage("illegal discount_term"); my $discount_term = $1; +# save first, for proper tokenization later +if ( $cgi->param('save') ) { + my $new = new FS::cust_main { $cust_main->hash }; + if ( $payby eq 'CARD' ) { + $new->set( 'payby' => ( $cgi->param('auto') ? 'CARD' : 'DCRD' ) ); + } elsif ( $payby eq 'CHEK' ) { + $new->set( 'payby' => ( $cgi->param('auto') ? 'CHEK' : 'DCHK' ) ); + } else { + die "unknown payby $payby"; + } + $new->payinfo($payinfo); #to properly set paymask + $new->set( 'paydate' => "$year-$month-01" ); + $new->set( 'payname' => $payname ); + + #false laziness w/FS:;cust_main::realtime_bop - check both to make sure + # working correctly + if ( $payby eq 'CARD' && + grep { $_ eq cardtype($payinfo) } $conf->config('cvv-save') ) { + $new->set( 'paycvv' => $paycvv ); + } else { + $new->set( 'paycvv' => ''); + } + + if ( $payby eq 'CARD' ) { + my $bill_location = FS::cust_location->new; + $bill_location->set( $_ => $cgi->param($_) ) + foreach @{$payby2fields{$payby}}; + $new->set('bill_location' => $bill_location); + # will do nothing if the fields are all unchanged + } else { + $new->set( $_ => $cgi->param($_) ) foreach @{$payby2fields{$payby}}; + } + + my $error = $new->replace($cust_main); + errorpage("error saving info, payment not processed: $error") + if $error; + $cust_main = $new; +} + my $error = ''; my $paynum = ''; if ( $cgi->param('batch') ) { @@ -190,44 +229,6 @@ if ( $cgi->param('batch') ) { } -if ( $cgi->param('save') ) { - my $new = new FS::cust_main { $cust_main->hash }; - if ( $payby eq 'CARD' ) { - $new->set( 'payby' => ( $cgi->param('auto') ? 'CARD' : 'DCRD' ) ); - } elsif ( $payby eq 'CHEK' ) { - $new->set( 'payby' => ( $cgi->param('auto') ? 'CHEK' : 'DCHK' ) ); - } else { - die "unknown payby $payby"; - } - $new->set( 'payinfo' => $cust_main->card_token || $payinfo ); - $new->set( 'paydate' => "$year-$month-01" ); - $new->set( 'payname' => $payname ); - - #false laziness w/FS:;cust_main::realtime_bop - check both to make sure - # working correctly - if ( $payby eq 'CARD' && - grep { $_ eq cardtype($payinfo) } $conf->config('cvv-save') ) { - $new->set( 'paycvv' => $paycvv ); - } else { - $new->set( 'paycvv' => ''); - } - - if ( $payby eq 'CARD' ) { - my $bill_location = FS::cust_location->new; - $bill_location->set( $_ => $cgi->param($_) ) - foreach @{$payby2fields{$payby}}; - $new->set('bill_location' => $bill_location); - # will do nothing if the fields are all unchanged - } else { - $new->set( $_ => $cgi->param($_) ) foreach @{$payby2fields{$payby}}; - } - - my $error = $new->replace($cust_main); - errorpage("payment processed successfully, but error saving info: $error") - if $error; - $cust_main = $new; -} - #success! -- cgit v1.2.1 From d07c72046444319e0811c6a00b504885da091992 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Wed, 30 Sep 2015 22:49:38 -0700 Subject: graphical selection of deployment zones and automatic block lookup, #30260 --- httemplate/browse/deploy_zone.html | 6 +- httemplate/edit/deploy_zone-fixed.html | 85 +++++++------- httemplate/edit/deploy_zone-mobile.html | 21 ++-- httemplate/edit/process/deploy_zone-fixed.html | 35 ++++-- httemplate/edit/process/deploy_zone-mobile.html | 19 ++- httemplate/edit/process/elements/process.html | 21 +++- httemplate/elements/polygon.html | 127 +++++++++++++++++++++ httemplate/elements/tr-polygon.html | 5 + .../misc/process/deploy_zone-block_lookup.cgi | 13 +++ 9 files changed, 275 insertions(+), 57 deletions(-) create mode 100644 httemplate/elements/polygon.html create mode 100644 httemplate/elements/tr-polygon.html create mode 100644 httemplate/misc/process/deploy_zone-block_lookup.cgi (limited to 'httemplate') diff --git a/httemplate/browse/deploy_zone.html b/httemplate/browse/deploy_zone.html index 3bd9d07dd..02ebb8b8c 100644 --- a/httemplate/browse/deploy_zone.html +++ b/httemplate/browse/deploy_zone.html @@ -17,6 +17,7 @@ 'Market', 'Advertised Mbps', 'Contractual Mbps', + 'Vertices', 'Census blocks', ], fields => [ 'zonenum', @@ -41,6 +42,9 @@ $self->cir_speed_up ) }, + sub { my $self = shift; + FS::deploy_zone_vertex->count('zonenum = '.$self->zonenum) + }, sub { my $self = shift; FS::deploy_zone_block->count('zonenum = '.$self->zonenum) }, @@ -53,7 +57,7 @@ '(cir_speed_down, cir_speed_up)', ], links => [ $link_fixed, $link_fixed, ], - align => 'clllllr', + align => 'cllllrr', nohtmlheader => 1, disable_maxselect => 1, disable_total => 1, diff --git a/httemplate/edit/deploy_zone-fixed.html b/httemplate/edit/deploy_zone-fixed.html index 90d1b6667..b8d9f8bbc 100644 --- a/httemplate/edit/deploy_zone-fixed.html +++ b/httemplate/edit/deploy_zone-fixed.html @@ -54,29 +54,36 @@ value => 'Contractually guaranteed speed (Mbps)' }, 'cir_speed_down', 'cir_speed_up', - - { type => 'tablebreak-tr-title', value => 'Census blocks'}, - { field => 'file', - type => 'file-upload', - }, - { field => 'format', - type => 'hidden', - value => 'plain', - }, - { field => 'censusyear', - type => 'select', - options => [ '', qw( 2013 2012 2011 ) ], - }, - - { type => 'tablebreak-tr-title', value => '', }, - { field => 'blocknum', - type => 'deploy_zone_block', - o2m_table => 'deploy_zone_block', - m2_label => ' ', - m2_error_callback => $m2_error_callback, - }, + { type => 'tablebreak-tr-title', value => 'Footprint'}, + { field => 'vertices', + type => 'polygon', + curr_value_callback => sub { + my ($cgi, $object) = @_; + $cgi->param('vertices') || $object->vertices_json; + }, + } +# +# { type => 'tablebreak-tr-title', value => 'Census blocks'}, +# { field => 'file', +# type => 'file-upload', +# }, +# { field => 'format', +# type => 'hidden', +# value => 'plain', +# }, +# { field => 'censusyear', +# type => 'hidden', +# options => [ '', qw( 2013 2012 2011 ) ], +# }, +# +# { type => 'tablebreak-tr-title', value => '', }, +# { field => 'blocknum', +# type => 'deploy_zone_block', +# o2m_table => 'deploy_zone_block', +# m2_label => ' ', +# m2_error_callback => $m2_error_callback, +# }, ], - &> <%init> my $curuser = $FS::CurrentUser::CurrentUser; @@ -90,22 +97,22 @@ my $technology_labels = FS::part_pkg_fcc_option->technology_labels; my $media_types = FS::part_pkg_fcc_option->media_types; delete $media_types->{'Mobile Wireless'}; # cause this is the fixed zone page -my $m2_error_callback = sub { - my ($cgi, $deploy_zone) = @_; - my @blocknums = grep { - /^blocknum\d+/ and length($cgi->param($_.'_censusblock')) - } $cgi->param; - - sort { $a->censusblock <=> $b->censusblock } - map { - my $k = $_; - FS::deploy_zone_block->new({ - blocknum => scalar($cgi->param($k)), - zonenum => $deploy_zone->zonenum, - censusblock => scalar($cgi->param($k.'_censusblock')), - censusyear => scalar($cgi->param($k.'_censusyear')), - }) - } @blocknums; -}; +#my $m2_error_callback = sub { +# my ($cgi, $deploy_zone) = @_; +# my @blocknums = grep { +# /^blocknum\d+/ and length($cgi->param($_.'_censusblock')) +# } $cgi->param; +# +# sort { $a->censusblock <=> $b->censusblock } +# map { +# my $k = $_; +# FS::deploy_zone_block->new({ +# blocknum => scalar($cgi->param($k)), +# zonenum => $deploy_zone->zonenum, +# censusblock => scalar($cgi->param($k.'_censusblock')), +# censusyear => scalar($cgi->param($k.'_censusyear')), +# }) +# } @blocknums; +#}; diff --git a/httemplate/edit/deploy_zone-mobile.html b/httemplate/edit/deploy_zone-mobile.html index d049cb018..8cec298bf 100644 --- a/httemplate/edit/deploy_zone-mobile.html +++ b/httemplate/edit/deploy_zone-mobile.html @@ -49,14 +49,21 @@ 'adv_speed_down', 'adv_speed_up', { type => 'tablebreak-tr-title', value => 'Footprint'}, - { field => 'vertexnum', - type => 'deploy_zone_vertex', - o2m_table => 'deploy_zone_vertex', - m2_label => ' ', - m2_error_callback => $m2_error_callback, - }, - ], + { field => 'vertices', + type => 'polygon', + curr_value_callback => sub { + my ($cgi, $object) = @_; + $cgi->param('vertices') || $object->vertices_json; + }, + } +# { field => 'vertexnum', +# type => 'deploy_zone_vertex', +# o2m_table => 'deploy_zone_vertex', +# m2_label => ' ', +# m2_error_callback => $m2_error_callback, +# }, + ], &> <%init> my $curuser = $FS::CurrentUser::CurrentUser; diff --git a/httemplate/edit/process/deploy_zone-fixed.html b/httemplate/edit/process/deploy_zone-fixed.html index eae3a746d..0033bbe52 100644 --- a/httemplate/edit/process/deploy_zone-fixed.html +++ b/httemplate/edit/process/deploy_zone-fixed.html @@ -3,12 +3,31 @@ error_redirect => popurl(2).'deploy_zone-fixed.html', table => 'deploy_zone', viewall_dir => 'browse', - process_o2m => { - 'table' => 'deploy_zone_block', - 'fields' => [qw( censusblock censusyear )] - }, - process_upload => { - 'process' => 'misc/process/deploy_zone-import.html', - 'fields' => [qw( censusyear format )], - }, + precheck_callback => $precheck_callback, + process_o2m => + { 'table' => 'deploy_zone_vertex', + 'fields' => [qw( latitude longitude )] + }, + progress_init => [ + 'PostForm', + [ 'zonenum' ], + $fsurl.'misc/process/deploy_zone-block_lookup.cgi', + $fsurl.'browse/deploy_zone.html', + ], &> +<%init> +my $precheck_callback = sub { + # convert the vertex list into a process_o2m-style parameter list + if ( $cgi->param('vertices') ) { + my $vertices = decode_json($cgi->param('vertices')); + my $i = 0; + foreach (@$vertices) { + $cgi->param("vertexnum${i}", ''); + $cgi->param("vertexnum${i}_latitude", $_->[0]); + $cgi->param("vertexnum${i}_longitude", $_->[1]); + $i++; + } + } + ''; +}; + diff --git a/httemplate/edit/process/deploy_zone-mobile.html b/httemplate/edit/process/deploy_zone-mobile.html index 7b8f911ec..d36d5d448 100644 --- a/httemplate/edit/process/deploy_zone-mobile.html +++ b/httemplate/edit/process/deploy_zone-mobile.html @@ -2,8 +2,25 @@ error_redirect => popurl(2).'deploy_zone-mobile.html', table => 'deploy_zone', viewall_dir => 'browse', - process_o2m => + precheck_callback => $precheck_callback, + process_o2m => { 'table' => 'deploy_zone_vertex', 'fields' => [qw( latitude longitude )] }, &> +<%init> +my $precheck_callback = sub { + # convert the vertex list into a process_o2m-style parameter list + if ( $cgi->param('vertices') ) { + my $vertices = decode_json($cgi->param('vertices')); + my $i = 0; + foreach (@$vertices) { + $cgi->param("vertexnum${i}", ''); + $cgi->param("vertexnum${i}_latitude", $_->[0]); + $cgi->param("vertexnum${i}_longitude", $_->[1]); + $i++; + } + } + ''; +}; + diff --git a/httemplate/edit/process/elements/process.html b/httemplate/edit/process/elements/process.html index 69bd605f6..a76f4befb 100644 --- a/httemplate/edit/process/elements/process.html +++ b/httemplate/edit/process/elements/process.html @@ -160,7 +160,26 @@ process(); <& /elements/footer.html &> -%} elsif ( $opt{'popup_reload'} ) { +% } elsif ( $opt{'progress_init'} ) { +% # some false laziness with the above +% my ($form_name, $job_fields) = @{ $opt{'progress_init'} }; + +% foreach my $field (@$job_fields) { + +% } +<& /elements/progress-init.html, + @{ $opt{'progress_init'} } +&> + + + +<& /elements/footer.html &> + +% } elsif ( $opt{'popup_reload'} ) { <% include('/elements/header-popup.html', $opt{'popup_reload'} ) %> diff --git a/httemplate/elements/polygon.html b/httemplate/elements/polygon.html new file mode 100644 index 000000000..c26e98546 --- /dev/null +++ b/httemplate/elements/polygon.html @@ -0,0 +1,127 @@ +<%init> +my %opt = @_; +my $field = $opt{'field'}; +my $id = $opt{'id'} || $opt{'field'}; +my $div_id = "div_$id"; + +my $vertices_json = $opt{'curr_value'} || '[]'; + +<& hidden.html, %opt &> +
+ + + + + diff --git a/httemplate/elements/tr-polygon.html b/httemplate/elements/tr-polygon.html new file mode 100644 index 000000000..6990d3da6 --- /dev/null +++ b/httemplate/elements/tr-polygon.html @@ -0,0 +1,5 @@ + + +<& polygon.html, @_ &> + + diff --git a/httemplate/misc/process/deploy_zone-block_lookup.cgi b/httemplate/misc/process/deploy_zone-block_lookup.cgi new file mode 100644 index 000000000..8f4eac7e9 --- /dev/null +++ b/httemplate/misc/process/deploy_zone-block_lookup.cgi @@ -0,0 +1,13 @@ +<% $server->process %> +<%init> +my $curuser = $FS::CurrentUser::CurrentUser; +die "access denied" + unless $curuser->access_right([ + 'Edit FCC report configuration', + 'Edit FCC report configuration for all agents', + ]); + +my $server = FS::UI::Web::JSRPC->new( + 'FS::deploy_zone::process_block_lookup', $cgi +); + -- cgit v1.2.1 From 55de788f065cebc8273bcc52befb82cec9eff129 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Thu, 1 Oct 2015 10:25:37 -0400 Subject: 38406 Net 7 Terms --- httemplate/elements/select-terms.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'httemplate') diff --git a/httemplate/elements/select-terms.html b/httemplate/elements/select-terms.html index 716832f52..a330df17c 100644 --- a/httemplate/elements/select-terms.html +++ b/httemplate/elements/select-terms.html @@ -36,7 +36,7 @@ my $empty_value = $opt{'empty_value'} || ''; my @terms = ( emt('Payable upon receipt'), ( map "Net $_", - 0, 3, 5, 9, 10, 14, 15, 18, 20, 21, 25, 30, 45, 60, 90 ), + 0, 3, 5, 7, 9, 10, 14, 15, 18, 20, 21, 25, 30, 45, 60, 90 ), ); my @pre_options = $opt{pre_options} ? @{ $opt{pre_options} } : (); -- cgit v1.2.1 From c62c90543fcd5de9e57b1d2ce442fa37c71358c8 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Fri, 2 Oct 2015 17:19:14 -0700 Subject: fix placement of "taxable" column, #37088 --- httemplate/search/report_tax.cgi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'httemplate') diff --git a/httemplate/search/report_tax.cgi b/httemplate/search/report_tax.cgi index 6d0e95d2a..615abe5b2 100644 --- a/httemplate/search/report_tax.cgi +++ b/httemplate/search/report_tax.cgi @@ -125,14 +125,14 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px } <% $money_sprintf->( $row->{sales_credited} ) %> - × - <% $row->{rate} %> % # taxable sales "> <% $money_sprintf->( $row->{taxable} ) %> + × + <% $row->{rate} %> % # estimated tax = -- cgit v1.2.1 From 323d6a0c3ee3d7752225b712f5bdcfbb1581d61f Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Sat, 3 Oct 2015 16:12:38 -0700 Subject: fix region-filtering of credit application search from tax report, #37088 --- httemplate/search/report_tax.cgi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'httemplate') diff --git a/httemplate/search/report_tax.cgi b/httemplate/search/report_tax.cgi index 615abe5b2..0ad143f01 100644 --- a/httemplate/search/report_tax.cgi +++ b/httemplate/search/report_tax.cgi @@ -77,7 +77,7 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px } % # cust_bill_pkg.cgi wants a list of specific taxnums (and package class) % # cust_credit_bill_pkg.html wants a geographic scope (and package class) % my $rowlink = ';taxnum=' . $row->{taxnums}; -% my $rowregion = ''; +% my $rowregion = ';country=' . $cgi->param('country'); % foreach my $loc (qw(state county city district)) { % if ( $row->{$loc} ) { % $rowregion .= ";$loc=" . uri_escape($row->{$loc}); @@ -88,6 +88,7 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px } % $rowlink .= ';classnum=' . ($row->{pkgclass} || 0); % $rowregion .= ';classnum=' . ($row->{pkgclass} || 0); % } +%warn $rowregion; % % if ( $row->{total} ) { -- cgit v1.2.1 From 5e6bfa1548ac370d2cf316e0db44785d83baa453 Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Mon, 5 Oct 2015 19:09:33 -0700 Subject: ticket_system-appointment-custom_field, RT#34237 --- httemplate/view/cust_main/appointments.html | 36 +++++++++++++++++------------ 1 file changed, 21 insertions(+), 15 deletions(-) (limited to 'httemplate') diff --git a/httemplate/view/cust_main/appointments.html b/httemplate/view/cust_main/appointments.html index c907b25bb..9bf5be1d5 100644 --- a/httemplate/view/cust_main/appointments.html +++ b/httemplate/view/cust_main/appointments.html @@ -19,7 +19,9 @@ - <% mt('Type') |h %> +% if ( $custom_field ) { + <% mt('Type') |h %> +% } <% mt('Date') |h %> <% mt('Status') |h %> <% mt('Owner') |h %> @@ -41,10 +43,12 @@ % if $starts > 86400; - - - ><% 'custom field magic type' %> - + +% if ( $custom_field ) { + + ><% $ticket->{"CF.{$custom_field}"} |h %> + +% } ><% $starts_pretty %> @@ -78,20 +82,22 @@ return '' unless $conf->config('ticket_system'); #my $object = $opt{'object'}; #$object = $object->cust_svc if $object->isa('FS::svc_Common'); -my( @tickets ) = $object->tickets; #XXX but actually appointments... filter by presense of the necessary CF? RT::Appointment instead of RT::Ticket ? +my @tickets = $object->appointments; -my ($openlabel, $open_link, $res_link, $thing); -$openlabel = join('/', FS::TicketSystem->statuses ); +my $custom_field = $conf->config('ticket_system-appointment-custom_field'); + +# my ($openlabel, $open_link, $res_link, $thing); +# $openlabel = join('/', FS::TicketSystem->statuses ); # not the nicest way to do this--FS::has_tickets_Common? #if ( $object->isa('FS::cust_main') ) { - $thing = 'customer'; - $open_link = FS::TicketSystem->href_customer_tickets($object->custnum); - - $res_link = FS::TicketSystem->href_customer_tickets( - $object->custnum, - { 'statuses' => [ 'resolved' ] } - ); +# $thing = 'customer'; +# $open_link = FS::TicketSystem->href_customer_tickets($object->custnum); +# +# $res_link = FS::TicketSystem->href_customer_tickets( +# $object->custnum, +# { 'statuses' => [ 'resolved' ] } +# ); #} elsif ( $object->isa('FS::cust_svc') ) { # # return '' unless $object->pkgnum; -- cgit v1.2.1 From ecc93e41eac485b6e84b844d9db8d25576dab3b9 Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Mon, 5 Oct 2015 20:13:55 -0700 Subject: show customer name on appointments, RT#34237 --- httemplate/misc/xmlhttp-ticket-update.html | 66 ++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 httemplate/misc/xmlhttp-ticket-update.html (limited to 'httemplate') diff --git a/httemplate/misc/xmlhttp-ticket-update.html b/httemplate/misc/xmlhttp-ticket-update.html new file mode 100644 index 000000000..147fbef16 --- /dev/null +++ b/httemplate/misc/xmlhttp-ticket-update.html @@ -0,0 +1,66 @@ +<% encode_json($return) %>\ +<%init> + +my $id = $cgi->param('id'); +my $starts = $cgi->param('starts'); +my $due = $cgi->param('due'); +my $username = $cgi->param('username'); + +my $ticket = FS::TicketSystem->get_ticket_object( \%session, ticket_id=>$id ); + +#hmm, this should happen in a single transaction and either commit or rollback, +# but in reality failures "Don't Happen" so its not like a ticket gets +# half changed + +my $return; +if ( $ticket ) { + + my($orv, $omsg) = $ticket->SetOwner( $username, 'Steal' ); + $orv = 1 if ! $orv && $omsg =~ /already owns/i; + + if ( $orv ) { + + my $date = RT::Date->new( $session{CurrentUser} ); + $date->Set( Format=>'unix', Value=>$starts, ); + my($srv, $smsg) = $ticket->SetStarts( $date->ISO ); + + my $ddate; + unless ( ! $srv ) { + $ddate = RT::Date->new( $session{CurrentUser} ); + $ddate->Set( Format=>'unix', Value=>$due, ); + my($drv, $dmsg) = $ticket->SetDue( $ddate->ISO ); + #XXX lame + } + + if ( $srv ) { + + my ($sm, $sh) = ( $date->Localtime('user'))[1,2]; + my ($em, $eh) = ($ddate->Localtime('user'))[1,2]; + + #false laziness w/CalendarSlotSchedule and CalendarDaySchedule + my %hash = $m->comp('/rt/Ticket/Elements/Customers', Ticket => $ticket); + my @cust_main = values( %{$hash{cust_main}} ); + + $return = { 'error' => '', + #'starts' => $starts, + #'due' => $due, + #'username' => $username, + #false laziness w/CalendarSlotSchedule + 'sched_label' => + FS::sched_avail::pretty_time($sh*60+$sm). '-'. + FS::sched_avail::pretty_time($eh*60+$em). ': '. + $cust_main[0]->_FreesideURILabel, + }; + } else { + $return = { 'error' => $smsg }; + } + + } else { + $return = { 'error' => $omsg }; + } + +} else { + $return = { 'error' => 'Unknown ticket id' }; +} + + -- cgit v1.2.1 From a267a869ad2f2c9b6ba4e306aea6103e3a6bfe4e Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Tue, 6 Oct 2015 00:35:18 -0500 Subject: RT#38314: Declined payment shows card as tokenized after first attempt --- httemplate/misc/process/payment.cgi | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'httemplate') diff --git a/httemplate/misc/process/payment.cgi b/httemplate/misc/process/payment.cgi index d9299e5bd..efba9ed9a 100644 --- a/httemplate/misc/process/payment.cgi +++ b/httemplate/misc/process/payment.cgi @@ -74,11 +74,13 @@ $cgi->param('balance') =~ /^\s*(\-?\s*\d*(\.\d\d)?)\s*$/ my $balance = $1; my $payinfo; +my $paymask; # override only used by loaded cust payinfo, only implemented for realtime processing my $paycvv = ''; if ( $payby eq 'CHEK' ) { if ($cgi->param('payinfo1') =~ /xx/i || $cgi->param('payinfo2') =~ /xx/i ) { $payinfo = $cust_main->payinfo; + $paymask = $cust_main->paymask; } else { $cgi->param('payinfo1') =~ /^(\d+)$/ or errorpage("Illegal account number ". $cgi->param('payinfo1')); @@ -99,6 +101,7 @@ if ( $payby eq 'CHEK' ) { $payinfo = $cgi->param('payinfo'); if ($payinfo eq $cust_main->paymask) { $payinfo = $cust_main->payinfo; + $paymask = $cust_main->paymask; } $payinfo =~ s/\D//g; $payinfo =~ /^(\d{13,16}|\d{8,9})$/ @@ -145,7 +148,8 @@ if ( $cgi->param('save') ) { } else { die "unknown payby $payby"; } - $new->payinfo($payinfo); #to properly set paymask + $new->payinfo($payinfo); # sets default paymask, but not if it's already tokenized + $new->paymask($paymask) if $paymask; # in case it's been tokenized, override with loaded paymask $new->set( 'paydate' => "$year-$month-01" ); $new->set( 'payname' => $payname ); @@ -199,6 +203,7 @@ if ( $cgi->param('batch') ) { 'manual' => 1, 'balance' => $balance, 'payinfo' => $payinfo, + 'paymask' => $paymask, 'paydate' => "$year-$month-01", 'payname' => $payname, 'payunique' => $payunique, -- cgit v1.2.1 From cf512ab17435a0199ae13a8faefef94600a7a61b Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Tue, 6 Oct 2015 01:46:31 -0500 Subject: RT#37038 Add Card Type Name to Payment Report --- httemplate/search/cust_pay.html | 1 + httemplate/search/elements/cust_pay_or_refund.html | 10 ++++++++++ 2 files changed, 11 insertions(+) (limited to 'httemplate') diff --git a/httemplate/search/cust_pay.html b/httemplate/search/cust_pay.html index 03474c1ef..e466f6afa 100755 --- a/httemplate/search/cust_pay.html +++ b/httemplate/search/cust_pay.html @@ -3,4 +3,5 @@ 'amount_field' => 'paid', 'name_singular' => emt('payment'), 'name_verb' => emt('paid'), + 'show_card_type' => 1, &> diff --git a/httemplate/search/elements/cust_pay_or_refund.html b/httemplate/search/elements/cust_pay_or_refund.html index 5808e5f3e..1fea67c19 100755 --- a/httemplate/search/elements/cust_pay_or_refund.html +++ b/httemplate/search/elements/cust_pay_or_refund.html @@ -184,6 +184,16 @@ push @fields, 'payby_payinfo_pretty', push @link_onclicks, $sub_receipt, ''; push @sort_fields, 'paysort', $amount_field; +if ($opt{'show_card_type'}) { + push @header, emt('Card Type'); + $align .= 'r'; + push @links, ''; + push @fields, sub { + (($_[0]->payby eq 'CARD') && ($_[0]->paymask !~ /N\/A/)) ? cardtype($_[0]->paymask) : '' + }; + push @sort_fields, ''; +} + if ( $unapplied ) { push @header, emt('Unapplied'); $align .= 'r'; -- cgit v1.2.1 From f27e48e51e2154468d960f1be656538373332ee5 Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Tue, 6 Oct 2015 20:17:42 -0500 Subject: RT#38481: installer scheduling: redirect to basics (custom field edit) page instead of ticket view --- httemplate/elements/schedule-appointment.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'httemplate') diff --git a/httemplate/elements/schedule-appointment.html b/httemplate/elements/schedule-appointment.html index 45a8a5bab..69b9f422b 100644 --- a/httemplate/elements/schedule-appointment.html +++ b/httemplate/elements/schedule-appointment.html @@ -12,7 +12,8 @@ my $custnum = encode_entities( $cgi->param('custnum') ); my $query = join('&', map "username=$_", @username). "&LengthMin=$LengthMin". - "&custnum=$custnum"; + "&custnum=$custnum". + "&RedirectToBasics=1"; #XXX '&pkgnum=$pkgnum";need to be for specific package/location, not just for a customer... default to active(/ordered) package in a pkg_class w/ticketing_queueid, otherwise, a popup? we're getting complicated like form-creat_ticket.html my $url = $p. 'rt/Search/Schedule.html?'. $query; -- cgit v1.2.1 From fc672686f119da0b3b34fd3c73acc3fea81262e6 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Wed, 7 Oct 2015 14:18:15 -0700 Subject: #37098: convert one-shot email notices to use message templates --- httemplate/misc/email-customers.html | 191 +++++++++++++++++++++-------------- 1 file changed, 115 insertions(+), 76 deletions(-) (limited to 'httemplate') diff --git a/httemplate/misc/email-customers.html b/httemplate/misc/email-customers.html index bffd0cf81..8e2863455 100644 --- a/httemplate/misc/email-customers.html +++ b/httemplate/misc/email-customers.html @@ -22,13 +22,13 @@ title - the title of the page no_search_fields - arrayref of additional fields that are not search parameters alternate_form - subroutine that returns alternate html for the initial form, -replaces msgnum/from/subject/html_body/action inputs and submit button, not +replaces msgnum/from/subject/body/action inputs and submit button, not used if an action is specified post_search_hook - sub hook for additional processing after search has been processed from cgi, gets passed options 'conf' and 'search' (a reference to the unfrozen %search hash), should be used to set msgnum or -from/subject/html_body cgi params +from/subject/body cgi params % if ($popup) { @@ -37,6 +37,7 @@ from/subject/html_body cgi params <& /elements/header.html, $title &> % } +<& /elements/error.html &>
@@ -48,48 +49,40 @@ from/subject/html_body cgi params -% if ( $cgi->param('action') eq 'send' ) { - - Sending notice +% if ( $cgi->param('preview') ) { +% # preview mode: at this point we have a msg_template (either "real" or +% # draft) and $html_body and $text_body contain the preview message. +% # give the user a chance to back out (by going back to edit mode). + Preview notice <& /elements/progress-init.html, 'OneTrueForm', - [ qw( search table from subject html_body text_body msgnum ) ], + [ qw( search table msgnum ) ], $process_url, $pdest, &> -% } elsif ( $cgi->param('action') eq 'preview' ) { - - Preview notice - -% } - -% if ( $cgi->param('action') ) { - - - -% if ( $msg_template ) { - <& /elements/tr-fixed.html, - 'label' => 'Template:', - 'value' => $msg_template->msgname, - &> -% } + +% # kludge these through hidden inputs because they're not really part +% # of the template, but should be sticky during draft editing + + + +% if ( !$msg_template->disabled ) { + <& /elements/tr-td-label.html, 'label' => 'Template:' &> + + +% } - <& /elements/tr-fixed.html, - 'field' => 'from', - 'label' => 'From:', - 'value' => $from, - &> + <& /elements/tr-td-label.html, 'label' => 'From:' &> + + - <& /elements/tr-fixed.html, - 'field' => 'subject', - 'label' => 'Subject:', - 'value' => $subject, - &> + <& /elements/tr-td-label.html, 'label' => 'Subject:' &> + + -
<% $msg_template->msgname |h %>
<% $from |h %>
<% $subject |h %>
 
Message (HTML display): @@ -101,7 +94,6 @@ from/subject/html_body cgi params % $html_body % ) % ); -
 
Message (Text display): @@ -114,38 +106,37 @@ from/subject/html_body cgi params
-% if ( $cgi->param('action') eq 'preview' ) { + + } + -
- - - -% } +
+ + % } elsif ($opt{'alternate_form'}) { <% &{$opt{'alternate_form'}}() %> % } else { +% # Edit mode. +% if ( $msg_template and $msg_template->disabled ) { +% # if we've already established a draft template, don't let msgnum be changed + <& /elements/hidden.html, + field => 'msgnum', + curr_value => ($cgi->param('msgnum') || ''), + &> +% } else { Template: <& /elements/select-msg_template.html, - onchange => 'toggle(this)', + onchange => 'toggle(this)', + curr_value => ($cgi->param('msgnum') || ''), &>
+% } <& /elements/tr-td-label.html, 'label' => 'From:' &> <& /elements/tr-input-text.html, 'field' => 'subject', 'label' => 'Subject:', 'size' => 50, + 'curr_value' => $subject, &>
<& /elements/input-text.html, @@ -165,46 +165,41 @@ Template: 'value' => $conf->config('invoice_from_name', $agent_virt_agentnum) || $conf->config('company_name', $agent_virt_agentnum), #? 'size' => 20, + 'curr_value' => $cgi->param('from_name'), &> <\ <& /elements/input-text.html, 'field' => 'from_addr', 'type' => 'email', # HTML5, woot 'value' => $conf->config('invoice_from', $agent_virt_agentnum), 'size' => 20, + 'curr_value' => $cgi->param('from_addr'), &>>
Message: <& /elements/htmlarea.html, - 'field' => 'html_body', + 'field' => 'body', 'width' => 763, + 'curr_value' => $body, &>
-%#Substitution vars: - - - + % } #end not action or alternate form
-% if ( $cgi->param('action') eq 'send' ) { - -% } - <& /elements/footer.html &> <%init> @@ -217,7 +212,7 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right($opt{'acl'}); my $conf = FS::Conf->new; -my @no_search_fields = qw( action table from subject html_body text_body popup url ); +my @no_search_fields = qw( table from subject html_body text_body popup url ); my $form_action = $opt{'form_action'} || 'email-customers.html'; my $process_url = $opt{'process_url'} || 'process/email-customers.html'; @@ -261,12 +256,26 @@ if ( $cgi->param('from') ) { $from = $cgi->param('from_addr'); } -my $subject = $cgi->param('subject') || ''; -my $html_body = $cgi->param('html_body') || ''; - my $msg_template = ''; +if ( $cgi->param('msgnum') =~ /^(\d+)$/ ) { + $msg_template = FS::msg_template->by_key($1) + or die "template not found: ".$cgi->param('msgnum'); +} + +my $subject = $cgi->param('subject'); +my $body = $cgi->param('body'); +my ($html_body, $text_body); -if ( $cgi->param('action') eq 'preview' ) { +if ( !$cgi->param('preview') ) { + + # edit mode: initialize the fields from the saved draft, if there is one + if ( $msg_template and $msg_template->disabled eq 'D' ) { + my $content = $msg_template->content(''); # no localization on these yet + $subject ||= $content->subject; + $body ||= $content->body; + } + +} else { my $sql_query = "FS::$table"->search(\%search); my $count_query = delete($sql_query->{'count_query'}); @@ -277,10 +286,40 @@ if ( $cgi->param('action') eq 'preview' ) { my $count_arrayref = $count_sth->fetchrow_arrayref; $num_cust = $count_arrayref->[0]; - if ( $cgi->param('msgnum') ) { - $msg_template = qsearchs('msg_template', - { msgnum => scalar($cgi->param('msgnum')) } ) - or die "template not found: ".$cgi->param('msgnum'); + if ( !$msg_template or $msg_template->disabled eq 'D' ) { + # then this is a one-off template; edit it in place + my $subject = $cgi->param('subject') || ''; + my $body = $cgi->param('body') || ''; + + # create a draft template + $msg_template ||= FS::msg_template->new({ + msgclass => 'email', + disabled => 'D', + }); + # anyone have a better idea for msgname? + $msg_template->set('msgname' => "Notice " . DateTime->now->iso8601); + $msg_template->set('from_addr' => $from); + my %content = ( + subject => $subject, + body => $body, + ); + my $error; + if ( $msg_template->msgnum ) { + $error = $msg_template->replace(%content); + } else { + $error = $msg_template->insert(%content); + } + + if ( $error ) { + $cgi->param('error', $error); + $cgi->delete('preview'); # don't go on to preview stage yet + undef $msg_template; + } + } + # unless creating the msg_template failed, we now have one, so construct a + # preview message from the first customer/whatever in the search results + + if ( $msg_template ) { $sql_query->{'extra_sql'} .= ' LIMIT 1'; $sql_query->{'select'} = "$table.*"; $sql_query->{'order_by'} = ''; -- cgit v1.2.1 From 6b1a8c7316892165fa4dc8b66bb962bf113aa3d8 Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Thu, 8 Oct 2015 13:46:55 -0700 Subject: remove fax from short contact info, RT#25536 --- httemplate/elements/contact.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'httemplate') diff --git a/httemplate/elements/contact.html b/httemplate/elements/contact.html index ef74481c0..87e15debe 100644 --- a/httemplate/elements/contact.html +++ b/httemplate/elements/contact.html @@ -135,7 +135,7 @@ tie my %label, 'Tie::IxHash', my $first = 0; foreach my $phone_type ( qsearch({table=>'phone_type', order_by=>'weight'}) ) { - next if $phone_type->typename eq 'Home'; + next if $phone_type->typename =~ /^(Home|Fax)$/; my $f = 'phonetypenum'.$phone_type->phonetypenum; $label{$f} = $phone_type->typename. ' phone'; $size{$f} = $first++ ? 10 : 15; -- cgit v1.2.1 From 294e2ce31d6bbd2784a812d20438f9b223de0490 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Thu, 8 Oct 2015 15:31:31 -0700 Subject: more detailed tax-credit report, #37088 --- httemplate/search/cust_credit_bill_pkg.html | 49 +++++++++++++-- httemplate/search/report_tax-xls.cgi | 94 +++++++++++++++++++++++++---- httemplate/search/report_tax.cgi | 86 +++++++++++++++++++++++++- 3 files changed, 210 insertions(+), 19 deletions(-) (limited to 'httemplate') diff --git a/httemplate/search/cust_credit_bill_pkg.html b/httemplate/search/cust_credit_bill_pkg.html index b5a0ee9f6..5e70c23bd 100644 --- a/httemplate/search/cust_credit_bill_pkg.html +++ b/httemplate/search/cust_credit_bill_pkg.html @@ -3,11 +3,12 @@ 'name_singular' => 'credit application', 'query' => $query, 'count_query' => $count_query, - 'count_addl' => [ $money_char. '%.2f total', ], + 'count_addl' => \@count_addl, 'header' => [ #'#', 'Amount', + 'Tax exempt', #credit 'Date', @@ -26,7 +27,9 @@ ], 'fields' => [ #'creditbillpkgnum', - sub { sprintf($money_char.'%.2f', shift->amount ) }, + sub { sprintf($money_char.'%.2f', shift->amount ) }, + + sub { sprintf($money_char.'%.2f', shift->get('exempt_credited') ) }, sub { time2str('%b %d %Y', shift->get('cust_credit_date') ) }, sub { shift->cust_credit_bill->cust_credit->otaker }, @@ -44,6 +47,7 @@ ], 'sort_fields' => [ 'amount', + 'exempt_credited', 'cust_credit_date', '', #'otaker', '', #reason @@ -55,6 +59,7 @@ #cust fields ], 'links' => [ + '', '', '', '', @@ -68,11 +73,12 @@ FS::UI::Web::cust_header() ), ], - 'align' => 'rrllll'. + 'align' => 'rrrllll'. $post_desc_align. 'rr'. FS::UI::Web::cust_aligns(), - 'color' => [ + 'color' => [ + '', '', '', '', @@ -85,6 +91,7 @@ FS::UI::Web::cust_colors(), ], 'style' => [ + '', '', '', '', @@ -286,7 +293,6 @@ if ( $cgi->param('out') ) { #} push @where, $loc_sql; -warn $loc_sql; } my($title, $name); @@ -393,6 +399,9 @@ if ( $cgi->param('cust_tax') ) { my $count_query = "SELECT COUNT(DISTINCT creditbillpkgnum), SUM(cust_credit_bill_pkg.amount)"; +if ( $cgi->param('nottax') ) { + $count_query .= ", SUM(exempt_credited)"; +} my $join_cust = ' JOIN cust_bill ON ( cust_bill_pkg.invnum = cust_bill.invnum )'. @@ -405,6 +414,21 @@ my $join_cust_bill_pkg = 'LEFT JOIN cust_bill_pkg USING ( billpkgnum )'; if ( $cgi->param('nottax') ) { + # There can be multiple cust_tax_exempt_pkg records with the same + # creditbillpkgnum iff the line item is exempt from multiple taxes. + # They will all have the same amount, except in the case where there are + # different exemption types and so the exemption amounts are different. + # In that case, show the amount of the largest exemption. + + $join_cust_bill_pkg .= ' + LEFT JOIN( + SELECT creditbillpkgnum, + MAX(0 - cust_tax_exempt_pkg.amount) AS exempt_credited + FROM cust_tax_exempt_pkg + WHERE creditbillpkgnum IS NOT NULL + GROUP BY creditbillpkgnum + ) AS exempt_credit USING (creditbillpkgnum) + '; $join_pkg = ' LEFT JOIN cust_pkg USING ( pkgnum ) LEFT JOIN part_pkg USING ( pkgpart ) LEFT JOIN part_pkg AS override @@ -472,6 +496,12 @@ push @select, 'part_pkg.pkg' unless $cgi->param('istax'); push @select, 'cust_main.custnum', FS::UI::Web::cust_sql_fields(); +if ( $cgi->param('istax') ) { + push @select, 'NULL AS exempt_credited'; # just display zero +} elsif ( $cgi->param('nottax') ) { + push @select, 'exempt_credited'; +} + my @post_desc_header = (); my @post_desc = (); my @post_desc_null = (); @@ -555,4 +585,13 @@ my $location_sub = sub { }; +my @count_addl = ( $money_char. '%.2f total', ); +if ( $cgi->param('nottax') ) { + push @count_addl, ( $money_char. '%.2f tax exempt' ); +} + +if ( $cgi->param('debug') ) { + warn "\nQUERY:\n" . Dumper($query) . "\nCOUNT_QUERY:\n$count_query\n\n"; +} + diff --git a/httemplate/search/report_tax-xls.cgi b/httemplate/search/report_tax-xls.cgi index 743f14788..773b403f1 100755 --- a/httemplate/search/report_tax-xls.cgi +++ b/httemplate/search/report_tax-xls.cgi @@ -122,7 +122,7 @@ my %default = ( border => 1, ); my @widths = ( #ick - 30, (13) x 5, 3, 7.5, 3, 11, 11, 3, 11, 3, 11 + 30, (13) x 6, 3, 7.5, 3, 11, 11, 3, 11, 3, 11 ); my @format = ( {}, {}, {} ); # white row, gray row, yellow (totals) row @@ -134,29 +134,34 @@ foreach (keys(%formatdef)) { italic => 1, %f); } -my $ws = $workbook->add_worksheet('taxreport'); +my $ws = $workbook->add_worksheet('Sales and Tax'); # main title $ws->merge_range(0, 0, 0, 14, $report->title, $format[0]->{title}); +$ws->set_row(0, 30); # excel position my $x = 0; my $y = 2; my $colhead = $format[0]->{colhead}; # print header -$ws->merge_range($y, 1, $y, 5, 'Sales', $colhead); -$ws->merge_range($y, 6, $y+1, 8, 'Rate', $colhead); -$ws->merge_range($y, 9, $y, 15, 'Tax', $colhead); +$ws->merge_range($y, 1, $y, 6, 'Sales', $colhead); +$ws->merge_range($y, 7, $y+1, 9, 'Rate', $colhead); +$ws->merge_range($y, 10, $y, 16, 'Tax', $colhead); $y++; $colhead = $format[0]->{colhead_small}; -$ws->write($y, 1, [ 'Total', 'Exempt customer', 'Exempt package', 'Monthly exemption', +$ws->write($y, 1, [ 'Total', + 'Exempt customer', + 'Exempt package', + 'Monthly exemption', + 'Credited', 'Taxable' ], $colhead); -$ws->write($y, 9, 'Estimated', $colhead); -$ws->write($y, 10, 'Invoiced', $colhead); -$ws->write($y, 12, 'Credited', $colhead); -$ws->write($y, 14, 'Net due', $colhead); -$ws->write($y, 15, 'Collected',$colhead); +$ws->write($y, 10, 'Estimated', $colhead); +$ws->write($y, 11, 'Invoiced', $colhead); +$ws->write($y, 13, 'Credited', $colhead); +$ws->write($y, 15, 'Net due', $colhead); +$ws->write($y, 16, 'Collected',$colhead); $y++; # print data @@ -168,7 +173,7 @@ foreach my $row (@rows) { if ( $row->{pkgclass} ne $prev_row->{pkgclass} ) { $rownum = 1; if ( $params{breakdown}->{pkgclass} ) { - $ws->merge_range($y, 0, $y, 14, + $ws->merge_range($y, 0, $y, 15, $pkgclass_name{$row->{pkgclass}}, $format[0]->{sectionhead} ); @@ -182,7 +187,7 @@ foreach my $row (@rows) { } $ws->write($y, $x, $row->{label}, $f->{rowhead}); $x++; - foreach (qw(sales exempt_cust exempt_pkg exempt_monthly taxable)) { + foreach (qw(sales exempt_cust exempt_pkg exempt_monthly sales_credited taxable)) { $ws->write($y, $x, $row->{$_} || 0, $f->{currency}); $x++; } @@ -229,6 +234,69 @@ for my $x (0..scalar(@widths)-1) { $ws->set_column($x, $x, $widths[$x]); } +# do the same for the credit worksheet +$ws = $workbook->add_worksheet('Credits'); + +my $title = $report->title; +$title =~ s/Tax Report/Credits/; +# main title +$ws->merge_range(0, 0, 0, 14, $title, $format[0]->{title}); +$ws->set_row(0, 30); # height +# excel position +$x = 0; +$y = 2; + +$colhead = $format[0]->{colhead}; +# print header +$ws->merge_range($y, 1, $y+1, 1, 'Total', $colhead); +$ws->merge_range($y, 2, $y, 4, 'Applied to', $colhead); + +$y++; +$colhead = $format[0]->{colhead_small}; +$ws->write($y, 2, [ 'Taxable sales', + 'Tax-exempt sales', + 'Taxes' + ], $colhead); +$y++; + +# print data +$rownum = 1; +$prev_row = { pkgclass => 'DUMMY PKGCLASS' }; + +foreach my $row (@rows) { + $x = 0; + if ( $row->{pkgclass} ne $prev_row->{pkgclass} ) { + $rownum = 1; + if ( $params{breakdown}->{pkgclass} ) { + $ws->merge_range($y, 0, $y, 4, + $pkgclass_name{$row->{pkgclass}}, + $format[0]->{sectionhead} + ); + $y++; + } + } + # pick a format set + my $f = $format[$rownum % 2]; + if ( $row->{total} ) { + $f = $format[2]; + } + $ws->write($y, $x, $row->{label}, $f->{rowhead}); + $x++; + foreach (qw(credits sales_credited exempt_credited tax_credited)) { + $ws->write($y, $x, $row->{$_} || 0, $f->{currency}); + $x++; + } + + $rownum++; + $y++; + $prev_row = $row; +} + +for my $x (0..4) { + $ws->set_column($x, $x, $widths[$x]); +} + + $workbook->close; http_header('Content-Length' => length($data)); diff --git a/httemplate/search/report_tax.cgi b/httemplate/search/report_tax.cgi index 0ad143f01..2b531ea46 100644 --- a/httemplate/search/report_tax.cgi +++ b/httemplate/search/report_tax.cgi @@ -18,6 +18,7 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px } .bigmath { font-size: large; font-weight: bold; font: sans-serif; text-align: center } .total { font-style: italic } + <& /elements/table-grid.html &> @@ -88,7 +89,6 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px } % $rowlink .= ';classnum=' . ($row->{pkgclass} || 0); % $rowregion .= ';classnum=' . ($row->{pkgclass} || 0); % } -%warn $rowregion; % % if ( $row->{total} ) { @@ -183,6 +183,90 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px } % } +
+<& /elements/table-grid.html &> + + + + Total credits + Applied to + + + Taxable sales + Tax-exempt sales + Taxes + + + +% $rownum = 0; +% $prev_row = { pkgclass => 'DUMMY PKGCLASS' }; + + +% # mostly duplicates the stuff above... +% # but putting it all in one giant table is no good +% foreach my $row (@rows) { +% if ( $row->{pkgclass} ne $prev_row->{pkgclass} ) { +% if ( $rownum > 0 ) { # start a new section +% $rownum = 0; + +% } +% if ( $params{breakdown}->{pkgclass} ) { # and caption the new section + + + <% $pkgclass_name{$row->{pkgclass}} %> + + +% } +% } # if $row->{pkgclass} ne ... + +% my $rowlink = ';taxnum=' . $row->{taxnums}; +% my $rowregion = ';country=' . $cgi->param('country'); +% foreach my $loc (qw(state county city district)) { +% if ( $row->{$loc} ) { +% $rowregion .= ";$loc=" . uri_escape($row->{$loc}); +% } +% } +% if ( $params{breakdown}->{pkgclass} ) { +% $rowlink .= ';classnum=' . ($row->{pkgclass} || 0); +% $rowregion .= ';classnum=' . ($row->{pkgclass} || 0); +% } +% +% if ( $row->{total} ) { + +% } + + <% $row->{label} |h %> + +% # Total credits + <% $money_sprintf->( $row->{credits} ) %> + +% # Credits to taxable sales + + + <% $money_sprintf->( $row->{sales_credited} ) %> + + +% # ... to exempt sales (link is the same, it shows both exempt and taxable) + + + <% $money_sprintf->( $row->{exempt_credited} ) %> + + +% # ... to taxes + +%# currently broken + <% $money_sprintf->( $row->{tax_credited} ) %> +%# + + +% $rownum++; +% $prev_row = $row; +% } # foreach my $row +% # no "out of taxable region" for credits (yet) + + + + <& /elements/footer.html &> <%init> -- cgit v1.2.1 From 37b0f7bbb5737d02444dca82da5c3234be069f20 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Thu, 8 Oct 2015 23:46:58 -0700 Subject: restore credit-date filtering on line item report so we can use it for #37088 --- httemplate/search/cust_bill_pkg.cgi | 25 ++++++++++++++++++---- httemplate/search/cust_credit_bill_pkg.html | 2 +- httemplate/search/report_tax.cgi | 33 +++++++++++------------------ 3 files changed, 34 insertions(+), 26 deletions(-) (limited to 'httemplate') diff --git a/httemplate/search/cust_bill_pkg.cgi b/httemplate/search/cust_bill_pkg.cgi index 278382feb..4dc300d2f 100644 --- a/httemplate/search/cust_bill_pkg.cgi +++ b/httemplate/search/cust_bill_pkg.cgi @@ -705,9 +705,16 @@ my $pay_sub = "SELECT SUM(cust_bill_pay_pkg.amount) "; push @select, "($pay_sub) AS pay_amount"; -#total credits -my $credit_sub = 'SELECT SUM(amount) AS credit_amount, billpkgnum - FROM cust_credit_bill_pkg GROUP BY billpkgnum'; +# showing credited amount, optionally with date filtering +my $credit_where = ''; +if ( $cgi->param('credit_begin') or $cgi->param('credit_end') ) { + my($cr_begin, $cr_end) = FS::UI::Web::parse_beginning_ending($cgi, 'credit'); + $credit_where = "WHERE cust_credit_bill._date >= $cr_begin " . + "AND cust_credit_bill._date <= $cr_end"; +} + +my $credit_sub = "SELECT SUM(amount) AS credit_amount, billpkgnum + FROM cust_credit_bill_pkg $credit_where GROUP BY billpkgnum"; $join_pkg .= " LEFT JOIN ($credit_sub) AS item_credit ON (cust_bill_pkg.billpkgnum = item_credit.billpkgnum)"; @@ -737,6 +744,10 @@ if ( $cgi->param('salesnum') =~ /^(\d+)$/ ) { $cgi->param('classnum', 0) unless $cgi->param('classnum'); } +#credit flag (include only those that have credit(s) applied) +if ( $cgi->param('credit') ) { + push @where, 'credit_amount > 0'; +} my $where = join(' AND ', @where); $where &&= "WHERE $where"; @@ -775,7 +786,13 @@ my $ilink = [ "${p}view/cust_bill.cgi?", 'invnum' ]; my $clink = [ "${p}view/cust_main.cgi?", 'custnum' ]; my $pay_link = ''; #[, 'billpkgnum', ]; -my $credit_link = [ "${p}search/cust_credit_bill_pkg.html?billpkgnum=", 'billpkgnum', ]; +my $credit_param = ''; +foreach ('credit_begin', 'credit_end') { + if ( $cgi->param($_) ) { + $credit_param .= "$_=" . $cgi->param($_) . ';'; + } +} +my $credit_link = [ "${p}search/cust_credit_bill_pkg.html?${credit_param}billpkgnum=", 'billpkgnum', ]; warn "\n\nQUERY:\n".Dumper($query)."\n\nCOUNT_QUERY:\n$count_query\n\n" if $cgi->param('debug'); diff --git a/httemplate/search/cust_credit_bill_pkg.html b/httemplate/search/cust_credit_bill_pkg.html index 5e70c23bd..5facd4ab3 100644 --- a/httemplate/search/cust_credit_bill_pkg.html +++ b/httemplate/search/cust_credit_bill_pkg.html @@ -375,7 +375,7 @@ if ( $cgi->param('report_group') =~ /^(=|!=) (.*)$/ && $cgi->param('istax') ) { } -push @where, 'cust_bill_pkg.pkgnum != 0' if $cgi->param('nottax'); +push @where, '(cust_bill_pkg.pkgnum != 0 OR cust_bill_pkg.feepart is not null)' if $cgi->param('nottax'); push @where, 'cust_bill_pkg.pkgnum = 0' if $cgi->param('istax'); if ( $cgi->param('cust_tax') ) { diff --git a/httemplate/search/report_tax.cgi b/httemplate/search/report_tax.cgi index 2b531ea46..04bdf12ad 100644 --- a/httemplate/search/report_tax.cgi +++ b/httemplate/search/report_tax.cgi @@ -78,16 +78,17 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px } % # cust_bill_pkg.cgi wants a list of specific taxnums (and package class) % # cust_credit_bill_pkg.html wants a geographic scope (and package class) % my $rowlink = ';taxnum=' . $row->{taxnums}; -% my $rowregion = ';country=' . $cgi->param('country'); -% foreach my $loc (qw(state county city district)) { -% if ( $row->{$loc} ) { -% $rowregion .= ";$loc=" . uri_escape($row->{$loc}); -% } -% } +% # DON'T EVER USE THIS +% # my $rowregion = ';country=' . $cgi->param('country'); +% # foreach my $loc (qw(state county city district)) { +% # if ( $row->{$loc} ) { +% # $rowregion .= ";$loc=" . uri_escape($row->{$loc}); +% # } +% # } % # and also the package class, if we're limiting package class % if ( $params{breakdown}->{pkgclass} ) { % $rowlink .= ';classnum=' . ($row->{pkgclass} || 0); -% $rowregion .= ';classnum=' . ($row->{pkgclass} || 0); +% # $rowregion .= ';classnum=' . ($row->{pkgclass} || 0); % } % % if ( $row->{total} ) { @@ -122,7 +123,7 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px } % # credited sales - + <% $money_sprintf->( $row->{sales_credited} ) %> @@ -220,16 +221,6 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px } % } # if $row->{pkgclass} ne ... % my $rowlink = ';taxnum=' . $row->{taxnums}; -% my $rowregion = ';country=' . $cgi->param('country'); -% foreach my $loc (qw(state county city district)) { -% if ( $row->{$loc} ) { -% $rowregion .= ";$loc=" . uri_escape($row->{$loc}); -% } -% } -% if ( $params{breakdown}->{pkgclass} ) { -% $rowlink .= ';classnum=' . ($row->{pkgclass} || 0); -% $rowregion .= ';classnum=' . ($row->{pkgclass} || 0); -% } % % if ( $row->{total} ) { @@ -242,13 +233,13 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px } % # Credits to taxable sales - + <% $money_sprintf->( $row->{sales_credited} ) %> % # ... to exempt sales (link is the same, it shows both exempt and taxable) - + <% $money_sprintf->( $row->{exempt_credited} ) %> @@ -324,7 +315,7 @@ if ( $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"; -my $salescreditlink = $p. "search/cust_credit_bill_pkg.html?$dateagentlink;nottax=1"; +my $salescreditlink = $p. "search/cust_bill_pkg.cgi?$dateagentlink;nottax=1;credit=1"; if ( $params{'credit_date'} eq 'cust_credit_bill' ) { $salescreditlink =~ s/begin/credit_begin/; $salescreditlink =~ s/end/credit_end/; -- cgit v1.2.1 From 22ee75c6f67806c9b4c366eea4510d4410dfe8df Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Fri, 9 Oct 2015 00:05:25 -0700 Subject: make credit date filtering work, #37088 --- httemplate/search/cust_bill_pkg.cgi | 7 +++++-- httemplate/search/report_tax.cgi | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'httemplate') diff --git a/httemplate/search/cust_bill_pkg.cgi b/httemplate/search/cust_bill_pkg.cgi index 4dc300d2f..ab5aad776 100644 --- a/httemplate/search/cust_bill_pkg.cgi +++ b/httemplate/search/cust_bill_pkg.cgi @@ -713,8 +713,11 @@ if ( $cgi->param('credit_begin') or $cgi->param('credit_end') ) { "AND cust_credit_bill._date <= $cr_end"; } -my $credit_sub = "SELECT SUM(amount) AS credit_amount, billpkgnum - FROM cust_credit_bill_pkg $credit_where GROUP BY billpkgnum"; +my $credit_sub = "SELECT SUM(cust_credit_bill_pkg.amount) AS credit_amount, billpkgnum + FROM cust_credit_bill_pkg + JOIN cust_credit_bill USING (creditbillnum) + $credit_where + GROUP BY billpkgnum"; $join_pkg .= " LEFT JOIN ($credit_sub) AS item_credit ON (cust_bill_pkg.billpkgnum = item_credit.billpkgnum)"; diff --git a/httemplate/search/report_tax.cgi b/httemplate/search/report_tax.cgi index 04bdf12ad..9e625c80f 100644 --- a/httemplate/search/report_tax.cgi +++ b/httemplate/search/report_tax.cgi @@ -319,6 +319,7 @@ my $salescreditlink = $p. "search/cust_bill_pkg.cgi?$dateagentlink;nottax=1;cred if ( $params{'credit_date'} eq 'cust_credit_bill' ) { $salescreditlink =~ s/begin/credit_begin/; $salescreditlink =~ s/end/credit_end/; + $saleslink .= ";credit_begin=$beginning;credit_end=$ending"; } #my $creditlink = $p. "search/cust_bill_pkg.cgi?$dateagentlink;credit=1;istax=1"; #if ( $params{'credit_date'} eq 'cust_credit_bill' ) { -- cgit v1.2.1 From cd468ecb9a321ca96254b7204f6dc193b11cd903 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Sat, 10 Oct 2015 11:56:46 -0700 Subject: minor fixes to deploy zone editing, #30260 --- httemplate/browse/deploy_zone.html | 2 +- httemplate/edit/process/elements/process.html | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'httemplate') diff --git a/httemplate/browse/deploy_zone.html b/httemplate/browse/deploy_zone.html index 02ebb8b8c..a1bd57f15 100644 --- a/httemplate/browse/deploy_zone.html +++ b/httemplate/browse/deploy_zone.html @@ -57,7 +57,7 @@ '(cir_speed_down, cir_speed_up)', ], links => [ $link_fixed, $link_fixed, ], - align => 'cllllrr', + align => 'cllllrrr', nohtmlheader => 1, disable_maxselect => 1, disable_total => 1, diff --git a/httemplate/edit/process/elements/process.html b/httemplate/edit/process/elements/process.html index a76f4befb..fd12c61d9 100644 --- a/httemplate/edit/process/elements/process.html +++ b/httemplate/edit/process/elements/process.html @@ -164,7 +164,9 @@ process(); % # some false laziness with the above % my ($form_name, $job_fields) = @{ $opt{'progress_init'} };
+ % foreach my $field (@$job_fields) { +% next if $field eq $pkey; % } <& /elements/progress-init.html, -- cgit v1.2.1