From 74c9101d79b0dfd2f2d3a2996bd3d3575ada9252 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Wed, 25 Jul 2012 16:16:02 -0700 Subject: fix ordering packages with no unit price, #13136 --- httemplate/misc/order_pkg.html | 2 ++ 1 file changed, 2 insertions(+) (limited to 'httemplate') diff --git a/httemplate/misc/order_pkg.html b/httemplate/misc/order_pkg.html index 7aa024a34..c5d3fa3a8 100644 --- a/httemplate/misc/order_pkg.html +++ b/httemplate/misc/order_pkg.html @@ -39,6 +39,8 @@ +% } else { + % } -- cgit v1.2.1 From c1cabbc4cea2e0cfd9e1db668100b97069140cf5 Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Thu, 26 Jul 2012 14:02:36 -0700 Subject: add anniversary date, RT#18631 --- httemplate/edit/cust_main.cgi | 1 + httemplate/edit/cust_main/birthdate.html | 16 ++++++++++++++++ httemplate/edit/process/cust_main.cgi | 5 ++++- httemplate/search/cust_main.html | 2 +- httemplate/search/report_cust_main.html | 14 ++++++++++++++ httemplate/view/cust_main/misc.html | 14 ++++++++++++++ 6 files changed, 50 insertions(+), 2 deletions(-) (limited to 'httemplate') diff --git a/httemplate/edit/cust_main.cgi b/httemplate/edit/cust_main.cgi index ef81ebab1..1ad031d81 100755 --- a/httemplate/edit/cust_main.cgi +++ b/httemplate/edit/cust_main.cgi @@ -30,6 +30,7 @@ %# birthdate % if ( $conf->exists('cust_main-enable_birthdate') % || $conf->exists('cust_main-enable_spouse_birthdate') +% || $conf->exists('cust_main-enable_anniversary_date') % ) % {
diff --git a/httemplate/edit/cust_main/birthdate.html b/httemplate/edit/cust_main/birthdate.html index 5d6a123b1..5447a3ad0 100644 --- a/httemplate/edit/cust_main/birthdate.html +++ b/httemplate/edit/cust_main/birthdate.html @@ -1,5 +1,7 @@ <% ntable("#cccccc", 2) %> + % # maybe put after the contact names? + % if ( $conf->exists('cust_main-enable_birthdate') ) { <% include( '/elements/tr-input-date-field.html', { 'name' => 'birthdate', @@ -11,6 +13,7 @@ }) %> % } + % if ( $conf->exists('cust_main-enable_spouse_birthdate') ) { <% include( '/elements/tr-input-date-field.html', { 'name' => 'spouse_birthdate', @@ -22,6 +25,19 @@ }) %> % } + +% if ( $conf->exists('cust_main-enable_anniversary_date') ) { + <% include( '/elements/tr-input-date-field.html', { + 'name' => 'anniversary_date', + 'value' => $cust_main->anniversary_date, + 'label' => 'Anniversary Date', + 'format' => ( $conf->config('date_format') || "%m/%d/%Y" ), + 'usedatetime' => 1, + 'noinit' => $noinit++, + }) + %> +% } + <%init> diff --git a/httemplate/edit/process/cust_main.cgi b/httemplate/edit/process/cust_main.cgi index 5ee553b32..866452de1 100755 --- a/httemplate/edit/process/cust_main.cgi +++ b/httemplate/edit/process/cust_main.cgi @@ -112,9 +112,12 @@ $new->tagnum( [ $cgi->param('tagnum') ] ); my %usedatetime = ( 'birthdate' => 1, 'spouse_birthdate' => 1, + 'anniversary_date' => 1, ); -foreach my $dfield (qw( birthdate spouse_birthdate signupdate )) { +foreach my $dfield (qw( + signupdate birthdate spouse_birthdate anniversary_date +)) { if ( $cgi->param($dfield) && $cgi->param($dfield) =~ /^([ 0-9\-\/]{0,10})$/) { diff --git a/httemplate/search/cust_main.html b/httemplate/search/cust_main.html index e164b98f4..f75b45197 100755 --- a/httemplate/search/cust_main.html +++ b/httemplate/search/cust_main.html @@ -61,7 +61,7 @@ for my $param (qw( classnum refnum payby tagnum )) { # parse dates ### -foreach my $field (qw( signupdate birthdate spouse_birthdate )) { +foreach my $field (qw( signupdate birthdate spouse_birthdate anniversary_date )) { my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi, $field); diff --git a/httemplate/search/report_cust_main.html b/httemplate/search/report_cust_main.html index 39cf695d8..526bce26c 100755 --- a/httemplate/search/report_cust_main.html +++ b/httemplate/search/report_cust_main.html @@ -76,6 +76,20 @@ % } +% if ( $conf->exists('cust_main-enable_anniversary_date') ) { + + <% mt('Anniversary Date') |h %> + + + <& /elements/tr-input-beginning_ending.html, + prefix => 'anniversary_date', + layout => 'horiz', + &> +
+ + +% } + <& /elements/tr-select-cust_tag.html, 'cgi' => $cgi, 'is_report' => 1, diff --git a/httemplate/view/cust_main/misc.html b/httemplate/view/cust_main/misc.html index a0ab403e8..dc6da53f1 100644 --- a/httemplate/view/cust_main/misc.html +++ b/httemplate/view/cust_main/misc.html @@ -130,6 +130,20 @@ % } +% if ( $conf->exists('cust_main-enable_anniversary_date') ) { +% my $dt = $cust_main->anniversary_date ne '' +% ? DateTime->from_epoch( 'epoch' => $cust_main->anniversary_date, +% 'time_zone' =>'floating', +% ) +% : ''; + + + <% mt('Anniversary Date') |h %> + <% $dt ? $dt->strftime($date_format) : '' %> + + +% } + % if ( $conf->exists('cust_main-require_censustract') ) { -- cgit v1.2.1 From 2528cc7b182781a82844d8bbb1b555560487abc7 Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Thu, 26 Jul 2012 14:05:05 -0700 Subject: quotations, RT#16996 --- httemplate/misc/order_pkg.html | 62 ++++++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 17 deletions(-) (limited to 'httemplate') diff --git a/httemplate/misc/order_pkg.html b/httemplate/misc/order_pkg.html index 7aa024a34..57fdd64ee 100644 --- a/httemplate/misc/order_pkg.html +++ b/httemplate/misc/order_pkg.html @@ -1,4 +1,6 @@ -<& /elements/header-popup.html, mt('Order new package') &> +<& /elements/header-popup.html, $quotationnum ? mt('Add package to quotation') + : mt('Order new package') +&> @@ -11,8 +13,10 @@
- + + + % if ( $svcpart ) { % } @@ -26,9 +30,10 @@ % } else { <& /elements/tr-select-cust-part_pkg.html, - 'curr_value' => $pkgpart, - 'classnum' => -1, - 'cust_main' => $cust_main, + 'curr_value' => $pkgpart, + 'classnum' => -1, + 'cust_main' => $cust_main, + 'prospect_main' => $prospect_main, &> % } @@ -54,7 +59,7 @@ -% if ( $cust_main->payby =~ /^(CARD|CHEK)$/ ) { +% if ( $cust_main && $cust_main->payby =~ /^(CARD|CHEK)$/ ) { % my $what = lc(FS::payby->shortname($cust_main->payby)); <% mt("Disable automatic $what charge") |h %> @@ -97,8 +102,9 @@ % } else { <& /elements/tr-select-cust_location.html, - 'cgi' => $cgi, - 'cust_main' => $cust_main, + 'cgi' => $cgi, + 'cust_main' => $cust_main, + 'prospect_main' => $prospect_main, &> % } @@ -152,20 +158,42 @@ die "access denied" my $conf = new FS::Conf; my $date_format = $conf->config('date_format') || '%m/%d/%Y'; -$cgi->param('custnum') =~ /^(\d+)$/ or die "no custnum"; -my $custnum = $1; -my $cust_main = qsearchs({ - 'table' => 'cust_main', - 'hashref' => { 'custnum' => $custnum }, - 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, -}); +my $cust_main = ''; +if ( $cgi->param('custnum') =~ /^(\d+)$/ ) { + my $custnum = $1; + $cust_main = qsearchs({ + 'table' => 'cust_main', + 'hashref' => { 'custnum' => $custnum }, + 'extra_sql' => ' AND '. $curuser->agentnums_sql, + }); +} + +my $prospect_main = ''; +if ( $cgi->param('prospectnum') =~ /^(\d+)$/ ) { + my $prospectnum = $1; + $prospect_main = qsearchs({ + 'table' => 'prospect_main', + 'hashref' => { 'prospectnum' => $prospectnum }, + 'extra_sql' => ' AND '. $curuser->agentnums_sql, + }); +} + +my $quotationnum = ''; +if ( $cgi->param('quotationnum') =~ /^(\d+)$/ ) { + $quotationnum = $1; +} + +die 'no custnum or prospectnum' unless $cust_main || $prospect_main; my $part_pkg = ''; if ( $cgi->param('lock_pkgpart') ) { $part_pkg = qsearchs({ 'table' => 'part_pkg', 'hashref' => { 'pkgpart' => scalar($cgi->param('lock_pkgpart')) }, - 'extra_sql' => ' AND '. FS::part_pkg->agent_pkgs_sql( $cust_main->agent ), + 'extra_sql' => ' AND '. FS::part_pkg->agent_pkgs_sql( + $cust_main ? $cust_main->agent + : $prospect_main->agent + ), }) or die "unknown pkgpart ". $cgi->param('lock_pkgpart'); } @@ -179,7 +207,7 @@ if ( $cgi->param('quantity') =~ /^\s*(\d+)\s*$/ ) { my $format = $date_format. ' %T %z (%Z)'; #false laziness w/REAL_cust_pkg.cgi? my $start_date = ''; -if( ! $conf->exists('order_pkg-no_start_date') ) { +if( ! $conf->exists('order_pkg-no_start_date') && $cust_main ) { $start_date = $cust_main->next_bill_date; $start_date = $start_date ? time2str($format, $start_date) : ''; } -- cgit v1.2.1 From 437fb0a25140cd5a181f8d26204f4949874a00db Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Sun, 29 Jul 2012 16:11:01 -0700 Subject: more efficient ticket counting on dashboard page, #17067 --- httemplate/elements/dashboard-toplist.html | 81 ++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 14 deletions(-) (limited to 'httemplate') diff --git a/httemplate/elements/dashboard-toplist.html b/httemplate/elements/dashboard-toplist.html index 72f596f4a..f6ebb60fe 100644 --- a/httemplate/elements/dashboard-toplist.html +++ b/httemplate/elements/dashboard-toplist.html @@ -32,18 +32,21 @@ -% foreach my $priority ( @custom_priorities, '' ) { -% my $num = -% FS::TicketSystem->num_customer_tickets($custnum,$priority); -% my $ahref = ''; -% $ahref= '' -% if $num; - +% foreach my $priority ( @custom_priorities ) { - <% $ahref.$num %> - +% my $num = $num_tickets_by_priority{$priority}->{$custnum}; +% if ( $num ) { + <% $num %> +% if ( $priority && +% exists($num_tickets_by_priority{''}{$custnum}) ) { +% # decrement the customer's total by the number in +% # this priority bin +% $num_tickets_by_priority{''}{$custnum} -= $num; +% } +% } + % } @@ -77,7 +80,7 @@ <% $line %> <% mt('Lint') |h %> -% foreach my $priority ( @custom_priorities, '' ) { +% foreach my $priority ( @custom_priorities ) { <% $priority || '(none)'%> @@ -105,11 +108,61 @@ my $conf = new FS::Conf; #false laziness w/httemplate/search/cust_main.cgi... care if # custom_priority_field becomes anything but a local hack... + my @custom_priorities = (); -if ( $conf->config('ticket_system-custom_priority_field') +my $custom_priority_field = $conf->config('ticket_system-custom_priority_field'); +if ( $custom_priority_field && @{[ $conf->config('ticket_system-custom_priority_field-values') ]} ) { @custom_priorities = $conf->config('ticket_system-custom_priority_field-values'); } - +push @custom_priorities, ''; + +my %num_tickets_by_priority = map { $_ => {} } @custom_priorities; +# "optimization" (i.e. "terrible hack") to avoid constructing +# (@custom_priorities) x (cust_main) queries with a bazillion +# joins each just to count tickets +if ( $FS::TicketSystem::system eq 'RT_Internal' ) { + my $text = (driver_name =~ /^Pg/) ? 'text' : 'char'; + # The RT API does not play nicely with aggregate queries, + # so we're going to go around it. + my $sql = + "SELECT cust_main.custnum AS custnum, + ObjectCustomFieldValues.Content as priority, + COUNT(DISTINCT Tickets.Id) AS num_tickets + FROM cust_main + LEFT JOIN cust_pkg USING (custnum) + LEFT JOIN cust_svc USING (pkgnum) + JOIN Links ON ( + ( Links.Target = 'freeside://freeside/cust_main/' || CAST(cust_main.custnum AS $text) OR + Links.Target = 'freeside://freeside/cust_svc/' || CAST(cust_svc.svcnum AS $text) + ) AND + Links.Base LIKE '%rt://%/ticket/%' AND + Links.Type = 'MemberOf' + ) + JOIN Tickets ON (Links.LocalBase = Tickets.Id) + LEFT JOIN ObjectCustomFields ON ( + ObjectCustomFields.ObjectId = '0' OR + ObjectCustomFields.ObjectId = Tickets.Queue + ) + LEFT JOIN CustomFields ON ( + ObjectCustomFields.CustomField = CustomFields.Id AND + CustomFields.Name = '$custom_priority_field' + ) + LEFT JOIN ObjectCustomFieldValues ON ( + ObjectCustomFieldValues.CustomField = CustomFields.Id AND + ObjectCustomFieldValues.ObjectType = 'RT::Ticket' AND + ObjectCustomFieldValues.Disabled = '0' AND + ObjectCustomFieldValues.ObjectId = Tickets.Id + ) + GROUP BY cust_main.custnum, ObjectCustomFieldValues.Content"; + #warn $sql."\n"; + my $sth = dbh->prepare($sql) or die dbh->errstr; + $sth->execute or die $sth->errstr; + while ( my $row = $sth->fetchrow_hashref ) { + #warn to_json($row)."\n"; + $num_tickets_by_priority{ $row->{priority} }->{ $row->{custnum} } = + $row->{num_tickets}; + } +} -- cgit v1.2.1 From 7b6434395ecdbf8013309d22564b146736d6e927 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Sun, 29 Jul 2012 16:42:43 -0700 Subject: remove unearned junk from cust_bill_pkg.cgi now that it's a separate report --- httemplate/search/cust_bill_pkg.cgi | 203 ++++++++---------------------------- 1 file changed, 43 insertions(+), 160 deletions(-) (limited to 'httemplate') diff --git a/httemplate/search/cust_bill_pkg.cgi b/httemplate/search/cust_bill_pkg.cgi index 1a46b0097..5032542d0 100644 --- a/httemplate/search/cust_bill_pkg.cgi +++ b/httemplate/search/cust_bill_pkg.cgi @@ -3,25 +3,14 @@ 'name' => emt('line items'), 'query' => $query, 'count_query' => $count_query, - 'count_addl' => [ $money_char. '%.2f total', - $unearned ? ( $money_char. '%.2f unearned revenue' ) : (), - ], + 'count_addl' => [ $money_char. '%.2f total', ], 'header' => [ emt('Description'), - ( $unearned - ? ( emt('Unearned'), - emt('Owed'), # useful in 'paid' mode? - emt('Payment date') ) - : ( emt('Setup charge') ) - ), + emt('Setup charge'), ( $use_usage eq 'usage' ? emt('Usage charge') : emt('Recurring charge') ), - ( $unearned - ? ( emt('Charge start'), emt('Charge end') ) - : () - ), emt('Invoice'), emt('Date'), FS::UI::Web::cust_header(), @@ -34,22 +23,11 @@ #strikethrough or "N/A ($amount)" or something these when # they're not applicable to pkg_tax search sub { my $cust_bill_pkg = shift; - if ( $unearned ) { - - sprintf($money_char.'%.2f', - $cust_bill_pkg->unearned_revenue) - - } else { - sprintf($money_char.'%.2f', $cust_bill_pkg->setup ); - } + sprintf($money_char.'%.2f', $cust_bill_pkg->setup ); }, - ( $unearned - ? ( $owed_sub, $payment_date_sub, ) - : () - ), sub { my $row = shift; my $value = 0; - if ( $use_usage eq 'recurring' or $unearned ) { + if ( $use_usage eq 'recurring' ) { $value = $row->recur - $row->usage; } elsif ( $use_usage eq 'usage' ) { $value = $row->usage; @@ -58,30 +36,19 @@ } sprintf($money_char.'%.2f', $value ); }, - ( $unearned - ? ( sub { time2str('%b %d %Y', shift->sdate ) }, - # shift edate back a day - # 82799 = 3600*23 - 1 - # (to avoid skipping a day during DST) - sub { time2str('%b %d %Y', shift->edate - 82799 ) }, - ) - : () - ), 'invnum', sub { time2str('%b %d %Y', shift->_date ) }, \&FS::UI::Web::cust_fields, ], 'sort_fields' => [ '', - 'setup', #broken in $unearned case i guess - ( $unearned ? ('', '') : () ), - ( $use_usage eq 'recurring' or $unearned + 'setup', + ( $use_usage eq 'recurring' ? 'recur - usage' : $use_usage eq 'usage' ? 'usage' : 'recur' ), - ( $unearned ? ('sdate', 'edate') : () ), 'invnum', '_date', ], @@ -89,9 +56,7 @@ #'', '', '', - ( $unearned ? ( '', '' ) : () ), '', - ( $unearned ? ( '', '' ) : () ), $ilink, $ilink, ( map { $_ ne 'Cust. Status' ? $clink : '' } @@ -100,18 +65,14 @@ ], #'align' => 'rlrrrc'.FS::UI::Web::cust_aligns(), 'align' => 'lr'. - ( $unearned ? 'rc' : '' ). 'r'. - ( $unearned ? 'cc' : '' ). 'rc'. FS::UI::Web::cust_aligns(), 'color' => [ #'', '', '', - ( $unearned ? ( '', '' ) : () ), '', - ( $unearned ? ( '', '' ) : () ), '', '', FS::UI::Web::cust_colors(), @@ -120,9 +81,7 @@ #'', '', '', - ( $unearned ? ( '', '' ) : () ), '', - ( $unearned ? ( '', '' ) : () ), '', '', FS::UI::Web::cust_styles(), @@ -137,11 +96,6 @@ die "access denied" my $conf = new FS::Conf; -my $unearned = ''; -my $unearned_mode = ''; -my $unearned_base = ''; -my $unearned_sql = ''; - my @select = ( 'cust_bill_pkg.*', 'cust_bill._date' ); my ($join_cust, $join_pkg ) = ('', ''); @@ -207,44 +161,23 @@ if ( $cgi->param('taxclass') { #override taxclass when use_override is specified? probably - #if ( $use_override ) { - # - # push @where, - # ' ( '. join(' OR ', - # map { - # ' ( part_pkg.taxclass = '. dbh->quote($_). - # ' AND pkgpart_override IS NULL '. - # ' OR '. - # ' override.taxclass = '. dbh->quote($_). - # ' AND pkgpart_override IS NOT NULL '. - # ' ) ' - # } - # $cgi->param('taxclass') - # ). - # ' ) '; - # - #} else { push @where, ' part_pkg.taxclass IN ( '. join(', ', map dbh->quote($_), $cgi->param('taxclass') ). ' ) '; - #} - } my @loc_param = qw( district city county state country ); if ( $cgi->param('out') ) { - my ( $loc_sql, @param ) = FS::cust_pkg->location_sql( 'ornull' => 1 ); - while ( $loc_sql =~ /\?/ ) { #easier to do our own substitution - $loc_sql =~ s/\?/'cust_main_county.'.shift(@param)/e; - } - - $loc_sql =~ s/cust_pkg\.locationnum/cust_bill_pkg_tax_location.locationnum/g - if $cgi->param('istax'); + my ( $loc_sql, @param ) = FS::cust_location->in_county_sql( 'ornull' => 1 ); +# while ( $loc_sql =~ /\?/ ) { #easier to do our own substitution +# $loc_sql =~ s/\?/'cust_main_county.'.shift(@param)/e; +# } + warn "\nLOC_SQL:\n$loc_sql\n"; push @where, " 0 = ( SELECT COUNT(*) FROM cust_main_county @@ -258,16 +191,17 @@ if ( $cgi->param('out') ) { my %ph = map { $_ => dbh->quote( scalar($cgi->param($_)) ) } @loc_param; - my ( $loc_sql, @param ) = FS::cust_pkg->location_sql; + my ( $loc_sql, @param ) = FS::cust_location->in_county_sql(param => 1); while ( $loc_sql =~ /\?/ ) { #easier to do our own substitution $loc_sql =~ s/\?/$ph{shift(@param)}/e; } + warn "\nLOC_SQL:\n$loc_sql\n"; push @where, $loc_sql; } -} elsif ( $cgi->param('country') ) { +} elsif ( $cgi->param('country') ) { # and not $cgi->param('out') my @counties = $cgi->param('county'); @@ -284,7 +218,7 @@ if ( $cgi->param('out') ) { qw( district city state country ) ); - my ( $loc_sql, @param ) = FS::cust_pkg->location_sql; + my ( $loc_sql, @param ) = FS::cust_location->in_county_sql(param => 1); while ( $loc_sql =~ /\?/ ) { #easier to do our own substitution $loc_sql =~ s/\?/$ph{shift(@param)}/e; } @@ -295,17 +229,20 @@ if ( $cgi->param('out') ) { ). ' ) '; + warn "\nLOC_SQL:\n$locs_sql\n"; push @where, $locs_sql; - } else { + } else { #scalar(@counties) <= 1 my %ph = map { $_ => dbh->quote( scalar($cgi->param($_)) ) } @loc_param; - my ( $loc_sql, @param ) = FS::cust_pkg->location_sql; + + my ( $loc_sql, @param ) = FS::cust_location->in_county_sql(param => 1); while ( $loc_sql =~ /\?/ ) { #easier to do our own substitution $loc_sql =~ s/\?/$ph{shift(@param)}/e; } + warn "\nLOC_SQL:\n$loc_sql\n"; push @where, $loc_sql; } @@ -342,6 +279,7 @@ if ( $cgi->param('out') ) { } } elsif ( scalar( grep( /locationtaxid/, $cgi->param ) ) ) { +# and not $cgi->param('out' or 'country') push @where, FS::tax_rate_location->location_sql( map { $_ => (scalar($cgi->param($_)) || '') } @@ -350,69 +288,6 @@ if ( $cgi->param('out') ) { } -# unearned revenue mode -if ( $cgi->param('unearned_now') =~ /^(\d+)$/ ) { - - $unearned = $1; - $unearned_mode = $cgi->param('mode'); - - push @where, "cust_bill_pkg.sdate < $unearned", - "cust_bill_pkg.edate > $unearned", - "cust_bill_pkg.recur != 0", - "part_pkg.freq != '0'"; - - if ( !$cgi->param('include_monthly') ) { - push @where, - "part_pkg.freq != '1'", - "part_pkg.freq NOT LIKE '%h'", - "part_pkg.freq NOT LIKE '%d'", - "part_pkg.freq NOT LIKE '%w'"; - } - - my $usage_sql = FS::cust_bill_pkg->usage_sql; - push @select, "($usage_sql) AS usage"; # we need this - my $paid_sql = 'GREATEST(' . - FS::cust_bill_pkg->paid_sql($unearned, '', setuprecur => 'recur') . - " - $usage_sql, 0)"; - - push @select, "$paid_sql AS paid_no_usage"; # need this either way - - if ( $unearned_mode eq 'paid' ) { - # then use the amount paid, minus usage charges - $unearned_base = $paid_sql; - } - else { - # use the amount billed, minus usage charges and credits - $unearned_base = "GREATEST( cust_bill_pkg.recur - ". - FS::cust_bill_pkg->credited_sql($unearned, '', setuprecur => 'recur') . - " - $usage_sql, 0)"; - # include only rows that have some non-usage, non-credited portion - } - # whatever we're using as the base, only show rows where it's positive - push @where, "$unearned_base > 0"; - - my $period = "CAST(cust_bill_pkg.edate - cust_bill_pkg.sdate AS REAL)"; - my $elapsed = "GREATEST( $unearned - cust_bill_pkg.sdate, 0 )"; - my $remaining = "(1 - $elapsed/$period)"; - - $unearned_sql = "CAST( $unearned_base * $remaining AS DECIMAL(10,2) )"; - push @select, "$unearned_sql AS unearned_revenue"; - - # last payment/credit date - my %t = (pay => 'cust_bill_pay', credit => 'cust_credit_bill'); - foreach my $x (qw(pay credit)) { - my $table = $t{$x}; - my $link = $table.'_pkg'; - my $pkey = dbdef->table($table)->primary_key; - my $last_date_sql = "SELECT MAX(_date) - FROM $table JOIN $link USING ($pkey) - WHERE $link.billpkgnum = cust_bill_pkg.billpkgnum - AND $table._date <= $unearned"; - push @select, "($last_date_sql) AS last_$x"; - } - -} - if ( $cgi->param('itemdesc') ) { if ( $cgi->param('itemdesc') eq 'Tax' ) { push @where, "(itemdesc='Tax' OR itemdesc is null)"; @@ -516,9 +391,9 @@ if ( $cgi->param('pkg_tax') ) { AND cust_bill_pkg.recur > 0 ) )", #not a tax_exempt customer - "( tax != 'Y' OR tax IS NULL )"; + "( tax != 'Y' OR tax IS NULL )", # assume this was intended? #not covered in full by a monthly tax exemption (texas tax) - "0 < ( $setup_taxable + $recur_taxable - $exempt )", + "0 < ( $setup_taxable + $recur_taxable - $exempt )"; } else { @@ -528,9 +403,7 @@ if ( $cgi->param('pkg_tax') ) { $count_query = "SELECT COUNT(DISTINCT billpkgnum), "; } - if ( $unearned ) { - $count_query .= "SUM( $unearned_base ), SUM( $unearned_sql )"; - } elsif ( $use_usage eq 'recurring' ) { + if ( $use_usage eq 'recurring' ) { $count_query .= "SUM(cust_bill_pkg.setup + cust_bill_pkg.recur - usage)"; } elsif ( $use_usage eq 'usage' ) { $count_query .= "SUM(usage)"; @@ -552,9 +425,10 @@ if ( $cgi->param('nottax') ) { $join_pkg .= ' LEFT JOIN cust_pkg USING ( pkgnum ) LEFT JOIN part_pkg USING ( pkgpart ) LEFT JOIN part_pkg AS override - ON pkgpart_override = override.pkgpart '; - $join_pkg .= ' LEFT JOIN cust_location USING ( locationnum ) ' - if $conf->exists('tax-pkg_address'); + ON pkgpart_override = override.pkgpart + LEFT JOIN cust_location + ON cust_location.locationnum = '. + FS::cust_pkg->tax_locationnum_sql; } elsif ( $cgi->param('istax') ) { @@ -562,17 +436,26 @@ if ( $cgi->param('nottax') ) { if ( scalar( grep( /locationtaxid/, $cgi->param ) ) || $cgi->param('iscredit') eq 'rate') { + # using tax_rate_location and friends $join_pkg .= ' LEFT JOIN cust_bill_pkg_tax_rate_location USING ( billpkgnum ) '. ' LEFT JOIN tax_rate_location USING ( taxratelocationnum ) '; - } elsif ( $conf->exists('tax-pkg_address') ) { + #} elsif ( $conf->exists('tax-pkg_address') ) { + } else { + + # using cust_bill_pkg_tax_location to relate tax items to locations + # ...but for consolidated taxes we don't want to duplicate this + my $tax_item_location = '(SELECT DISTINCT billpkgnum, locationnum + FROM cust_bill_pkg_tax_location) AS tax_item_location'; - $join_pkg .= ' LEFT JOIN cust_bill_pkg_tax_location USING ( billpkgnum ) - LEFT JOIN cust_location USING ( locationnum ) '; + $join_pkg .= " LEFT JOIN $tax_item_location USING ( billpkgnum ) + LEFT JOIN cust_location + ON tax_item_location.locationnum = + cust_location.locationnum "; #quelle kludge, somewhat false laziness w/report_tax.cgi - s/cust_pkg\.locationnum/cust_bill_pkg_tax_location.locationnum/g for @where; + s/cust_pkg\.locationnum/tax_item_location.locationnum/g for @where; } if ( $cgi->param('iscredit') ) { @@ -591,7 +474,7 @@ if ( $cgi->param('nottax') ) { } else { #die? - warn "neiether nottax nor istax parameters specified"; + warn "neither nottax nor istax parameters specified"; #same as before? $join_pkg = ' LEFT JOIN cust_pkg USING ( pkgnum ) LEFT JOIN part_pkg USING ( pkgpart ) '; @@ -644,5 +527,5 @@ my $payment_date_sub = sub { or return ''; time2str('%b %d %Y', $cust_pay[-1]->_date ); }; - +warn $count_query; -- cgit v1.2.1 From f578e57b593adb9254b2e465c73116a0e0e617b5 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Sun, 29 Jul 2012 17:57:24 -0700 Subject: update customer list and zip code report to use cust_location, #940 --- httemplate/search/cust_main-zip.html | 48 +++++++++++------------------ httemplate/search/cust_main.cgi | 28 ++--------------- httemplate/search/cust_main.html | 2 +- httemplate/search/elements/search-html.html | 5 +++ httemplate/search/report_cust_main-zip.html | 4 +-- httemplate/search/report_cust_main.html | 5 +++ 6 files changed, 33 insertions(+), 59 deletions(-) (limited to 'httemplate') diff --git a/httemplate/search/cust_main-zip.html b/httemplate/search/cust_main-zip.html index c317dc36f..08800d431 100644 --- a/httemplate/search/cust_main-zip.html +++ b/httemplate/search/cust_main-zip.html @@ -4,8 +4,8 @@ 'query' => $sql_query, 'count_query' => $count_sql, 'header' => [ 'Zip code', 'Customers', ], - #'fields' => [ 'zip', 'num_cust', ], - #'links' => [ '', sub { 'somewhere'; } ], + 'fields' => [ 0, 1 ], + 'links' => [ '', $link ], ) %> <%init> @@ -63,48 +63,36 @@ sub strip_plus4 { END"; } -my( $zip, $czip); -if ( $cgi->param('column') eq 'ship_zip' ) { - - my $casewhen_noship = - "CASE WHEN ( ship_last IS NULL OR ship_last = '' ) THEN "; - - $czip = "$casewhen_noship zip ELSE ship_zip END"; - - if ( $cgi->param('ignore_plus4') ) { - $zip = $casewhen_noship. strip_plus4('zip'). - " ELSE ". strip_plus4('ship_zip'). ' END'; - - } else { - $zip = $casewhen_noship. fieldorempty('zip'). - " ELSE ". fieldorempty('ship_zip'). ' END'; - } +$cgi->param('column') =~ /^(bill|ship)$/; +my $location = $1 || 'bill'; +$location .= '_locationnum'; +my $zip; +if ( $cgi->param('ignore_plus4') ) { + $zip = strip_plus4('cust_location.zip'); } else { - - $czip = 'zip'; - - if ( $cgi->param('ignore_plus4') ) { - $zip = strip_plus4('zip'); - } else { - $zip = fieldorempty('zip'); - } - + $zip = fieldorempty('cust_location.zip'); } # construct the queries and send 'em off +my $join = "JOIN cust_location ON (cust_main.$location = cust_location.locationnum)"; + my $sql_query = "SELECT $zip AS zipcode, COUNT(*) AS num_cust FROM cust_main + $join $where GROUP BY zipcode - ORDER BY num_cust DESC + ORDER BY num_cust DESC, $zip ASC "; -my $count_sql = "select count(distinct $czip) from cust_main $where"; +my $count_sql = + "SELECT COUNT(DISTINCT cust_location.zip) + FROM cust_main $join $where"; -# XXX should link... +my $link = [ $p.'search/cust_main.html?zip=', + sub { $_[0]->[0] } ]; diff --git a/httemplate/search/cust_main.cgi b/httemplate/search/cust_main.cgi index 859ef04e6..a81958e20 100755 --- a/httemplate/search/cust_main.cgi +++ b/httemplate/search/cust_main.cgi @@ -81,13 +81,8 @@ <% mt('#') |h %> <% mt('Status') |h %> - <% mt('(bill) name') |h %> - <% mt('company') |h %> - -%if ( defined dbdef->table('cust_main')->column('ship_last') ) { - <% mt('(service) name') |h %> - <% mt('company') |h %> -%} + <% mt('Name') |h %> + <% mt('Company') |h %> %foreach my $addl_header ( @addl_headers ) { <% $addl_header %> @@ -172,25 +167,6 @@ <% $pcompany %> -% if ( defined dbdef->table('cust_main')->column('ship_last') ) { -% my($ship_last,$ship_first,$ship_company)=( -% $cust_main->ship_last || $cust_main->getfield('last'), -% $cust_main->ship_last ? $cust_main->ship_first : $cust_main->first, -% $cust_main->ship_last ? $cust_main->ship_company : $cust_main->company, -% ); -% my $pship_company = $ship_company -% ? qq!$ship_company! -% : ' '; -% - - > - <% "$ship_last, $ship_first" %> - - > - <% $pship_company %> - -% } -% % foreach my $addl_col ( @addl_cols ) { % if ( $addl_col eq 'tickets' ) { % if ( @custom_priorities ) { diff --git a/httemplate/search/cust_main.html b/httemplate/search/cust_main.html index f75b45197..fa79b4dfb 100755 --- a/httemplate/search/cust_main.html +++ b/httemplate/search/cust_main.html @@ -41,7 +41,7 @@ my %search_hash = (); #scalars my @scalars = qw ( - agentnum status address paydate_year paydate_month invoice_terms + agentnum status address zip paydate_year paydate_month invoice_terms no_censustract with_geocode custbatch usernum cancelled_pkgs cust_fields flattened_pkgs diff --git a/httemplate/search/elements/search-html.html b/httemplate/search/elements/search-html.html index 53167c26e..c27771494 100644 --- a/httemplate/search/elements/search-html.html +++ b/httemplate/search/elements/search-html.html @@ -337,6 +337,11 @@ % map { % if ( ref($_) eq 'CODE' ) { % &{$_}($row); +% } elsif ( ref($row) eq 'ARRAY' and +% $_ =~ /^\d+$/ ) { +% # for the 'straight SQL' case: specify fields +% # by position +% $row->[$_]; % } else { % $row->$_(); % } diff --git a/httemplate/search/report_cust_main-zip.html b/httemplate/search/report_cust_main-zip.html index 00cb9ed2c..8bad332a9 100644 --- a/httemplate/search/report_cust_main-zip.html +++ b/httemplate/search/report_cust_main-zip.html @@ -8,8 +8,8 @@ Billing or service zip diff --git a/httemplate/search/report_cust_main.html b/httemplate/search/report_cust_main.html index 526bce26c..a2c6f1c4c 100755 --- a/httemplate/search/report_cust_main.html +++ b/httemplate/search/report_cust_main.html @@ -35,6 +35,11 @@ <% mt('Address') |h %> + + + <% mt('Zip') |h %> + + <% mt('Signup date') |h %> -- cgit v1.2.1 From 66e35f4c5ce2125f252d63f024f2d72eb3ec5c5d Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Mon, 30 Jul 2012 15:23:13 -0700 Subject: remove debug cruft --- httemplate/search/cust_bill_pkg.cgi | 4 ---- 1 file changed, 4 deletions(-) (limited to 'httemplate') diff --git a/httemplate/search/cust_bill_pkg.cgi b/httemplate/search/cust_bill_pkg.cgi index 5032542d0..b6b70a080 100644 --- a/httemplate/search/cust_bill_pkg.cgi +++ b/httemplate/search/cust_bill_pkg.cgi @@ -177,7 +177,6 @@ if ( $cgi->param('out') ) { # $loc_sql =~ s/\?/'cust_main_county.'.shift(@param)/e; # } - warn "\nLOC_SQL:\n$loc_sql\n"; push @where, " 0 = ( SELECT COUNT(*) FROM cust_main_county @@ -196,7 +195,6 @@ if ( $cgi->param('out') ) { $loc_sql =~ s/\?/$ph{shift(@param)}/e; } - warn "\nLOC_SQL:\n$loc_sql\n"; push @where, $loc_sql; } @@ -229,7 +227,6 @@ if ( $cgi->param('out') ) { ). ' ) '; - warn "\nLOC_SQL:\n$locs_sql\n"; push @where, $locs_sql; } else { #scalar(@counties) <= 1 @@ -242,7 +239,6 @@ if ( $cgi->param('out') ) { $loc_sql =~ s/\?/$ph{shift(@param)}/e; } - warn "\nLOC_SQL:\n$loc_sql\n"; push @where, $loc_sql; } -- cgit v1.2.1 From 271ebf1222eabd8180eb318ea0e1a65f1f3103ff Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Mon, 30 Jul 2012 17:21:23 -0700 Subject: fix NAS association with sqlradius_withdomain exports, RT#18540 --- httemplate/edit/nas.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'httemplate') diff --git a/httemplate/edit/nas.html b/httemplate/edit/nas.html index 2e66fc3be..8e6232cdb 100644 --- a/httemplate/edit/nas.html +++ b/httemplate/edit/nas.html @@ -49,7 +49,7 @@ sub html_bottom { 'link_table' => 'export_nas', 'target_table' => 'part_export', 'hashref' => { 'exporttype' => - { op => 'LIKE', value => '%sqlradius' } + { op => 'LIKE', value => '%sqlradius%' } }, 'name_callback' => sub { $_[0]->label }, 'default' => 'yes', -- cgit v1.2.1 From f24c4bebce257bfcc61ba07fd3d16c5c0d730071 Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Tue, 31 Jul 2012 23:02:14 -0700 Subject: invoice voiding, RT#18677 --- httemplate/misc/process/void-cust_bill.html | 22 +++++++++ httemplate/misc/void-cust_bill.html | 45 +++++++++++++++++ httemplate/view/cust_bill_void.html | 56 ++++++++++++++++++++++ httemplate/view/cust_main/payment_history.html | 13 ++++- .../view/cust_main/payment_history/invoice.html | 14 +++++- .../cust_main/payment_history/voided_invoice.html | 52 ++++++++++++++++++++ 6 files changed, 200 insertions(+), 2 deletions(-) create mode 100755 httemplate/misc/process/void-cust_bill.html create mode 100644 httemplate/misc/void-cust_bill.html create mode 100755 httemplate/view/cust_bill_void.html create mode 100644 httemplate/view/cust_main/payment_history/voided_invoice.html (limited to 'httemplate') diff --git a/httemplate/misc/process/void-cust_bill.html b/httemplate/misc/process/void-cust_bill.html new file mode 100755 index 000000000..f2930ec01 --- /dev/null +++ b/httemplate/misc/process/void-cust_bill.html @@ -0,0 +1,22 @@ +%if ( $error ) { +% $cgi->param('error', $error); +<% $cgi->redirect(popurl(1). "void-cust_bill.html?". $cgi->query_string ) %> +%} else { +<% $cgi->redirect(popurl(3). "view/cust_main.cgi?". $custnum) %> +%} +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Void invoices'); + +#untaint invnum +$cgi->param('invnum') =~ /^(\d+)$/ || die "Illegal invnum"; +my $invnum = $1; + +my $cust_bill = qsearchs('cust_bill',{'invnum'=>$invnum}); + +my $custnum = $cust_bill->custnum; + +my $error = $cust_bill->void( $cgi->param('reason') ); + + diff --git a/httemplate/misc/void-cust_bill.html b/httemplate/misc/void-cust_bill.html new file mode 100644 index 000000000..1608fd051 --- /dev/null +++ b/httemplate/misc/void-cust_bill.html @@ -0,0 +1,45 @@ +<& /elements/header-popup.html, mt('Void invoice') &> + +<% include('/elements/error.html') %> + +<% emt('Are you sure you want to void this invoice?') %> +

+ +<% emt("Invoice #[_1] ([_2])",$cust_bill->display_invnum, $money_char. $cust_bill->owed) %> +

+ + + + +<% ntable("#cccccc", 2) %> + + Reason + + + + + +
+
+   \ + +
+ + + + +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Void invoices'); + +my $conf = new FS::Conf; +my $money_char = $conf->config('money_char') || '$'; + +#untaint invnum +$cgi->param('invnum') =~ /^(\d+)$/ || die "Illegal invnum"; +my $invnum = $1; + +my $cust_bill = qsearchs('cust_bill',{'invnum'=>$invnum}); + + diff --git a/httemplate/view/cust_bill_void.html b/httemplate/view/cust_bill_void.html new file mode 100755 index 000000000..c7c5da146 --- /dev/null +++ b/httemplate/view/cust_bill_void.html @@ -0,0 +1,56 @@ +<& /elements/header.html, mt('Voided Invoice'), menubar( + emt("View this customer (#[_1])",$display_custnum) => "${p}view/cust_main.cgi?$custnum", +) &> + +%#XXX something very big and obvious showing its voided... + +% #voided PDFs? +% #if ( $conf->exists('invoice_latex') ) { +%# +%# <% mt('View typeset invoice PDF') |h %> +%#

+% #} + +% if ( $conf->exists('invoice_html') ) { + <% join('', $cust_bill_void->print_html(\%opt) ) %> +% } else { +
<% join('', $cust_bill_void->print_text(\%opt) ) %>
+% } + +<& /elements/footer.html &> +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right('View invoices'); + +my $invnum; +my($query) = $cgi->keywords; +if ( $query =~ /^(\d+)$/ ) { + $invnum = $1; +} else { + $invnum = $cgi->param('invnum'); +} + +my $conf = new FS::Conf; + +my %opt = ( + 'unsquelch_cdr' => $conf->exists('voip-cdr_email'), +); + +my $cust_bill_void = qsearchs({ + 'select' => 'cust_bill_void.*', + 'table' => 'cust_bill_void', + #'addl_from' => 'LEFT JOIN cust_main USING ( custnum )', + 'hashref' => { 'quotationnum' => $quotationnum }, + #'extra_sql' => ' AND '. $curuser->agentnums_sql, +}); +die "Quotation #$quotationnum not found!" unless $quotation; + +my $custnum = $cust_bill->custnum; +my $display_custnum = $cust_bill->cust_main->display_custnum; + +#my $link = "invnum=$invnum"; + + diff --git a/httemplate/view/cust_main/payment_history.html b/httemplate/view/cust_main/payment_history.html index 9e08c0c5d..166addbf4 100644 --- a/httemplate/view/cust_main/payment_history.html +++ b/httemplate/view/cust_main/payment_history.html @@ -277,7 +277,9 @@ % ? sprintf("$money_char\%.2f", $item->{'charge'}) % : exists($item->{'charge_nobal'}) % ? sprintf("$money_char\%.2f", $item->{'charge_nobal'}) -% : ''; +% : exists($item->{'void_charge'}) +% ? sprintf("$money_char\%.2f", $item->{'void_charge'}) +% : ''; % % my $payment = exists($item->{'payment'}) % ? sprintf("- $money_char\%.2f", $item->{'payment'}) @@ -428,6 +430,15 @@ foreach my $cust_bill ($cust_main->cust_bill) { $num_cust_bill++; } +#voided invoices +foreach my $cust_bill_void ($cust_main->cust_bill_void) { + push @history, { + 'date' => $cust_bill_void->_date, + 'desc' => include('payment_history/voided_invoice.html', $cust_bill_void, %opt ), + 'void_charge' => $cust_bill_void->charged, + }; +} + #statements foreach my $cust_statement ($cust_main->cust_statement) { push @history, { diff --git a/httemplate/view/cust_main/payment_history/invoice.html b/httemplate/view/cust_main/payment_history/invoice.html index 3028f0f69..96a9f5456 100644 --- a/httemplate/view/cust_main/payment_history/invoice.html +++ b/httemplate/view/cust_main/payment_history/invoice.html @@ -1,4 +1,4 @@ -<% $link %><% $invoice %><% $link ? '' : '' %><% $delete %><% $under %> +<% $link %><% $invoice %><% $link ? '' : '' %><% "$void$delete$under" %> <%init> my( $cust_bill, %opt ) = @_; @@ -26,6 +26,18 @@ my $link = $curuser->access_right('View invoices') ? qq!! : ''; +my $void = ''; +if ( $cust_bill->closed !~ /^Y/i && $curuser->access_right('Void invoices') ) { + $void = + ' ('. include('/elements/popup_link.html', + 'label' => emt('void'), + 'action' => "${p}misc/void-cust_bill.html?;invnum=". + $cust_bill->invnum, + 'actionlabel' => emt('Void Invoice'), + ). + ')'; +} + my $delete = ''; $delete = areyousure_link("${p}misc/delete-cust_bill.html?$invnum", emt('Are you sure you want to delete this invoice?'), diff --git a/httemplate/view/cust_main/payment_history/voided_invoice.html b/httemplate/view/cust_main/payment_history/voided_invoice.html new file mode 100644 index 000000000..422edb2f6 --- /dev/null +++ b/httemplate/view/cust_main/payment_history/voided_invoice.html @@ -0,0 +1,52 @@ +<% $link %><% $invoice %><% $link ? '' : '' %> +<% mt("voided [_1]", time2str($date_format, $cust_bill_void->void_date) ) |h %> +% my $void_user = $cust_bill_void->void_access_user; +% if ($void_user) { + by <% $void_user->username %> +% } +<% "$unvoid$delete$under" %> +<%init> + +my( $cust_bill_void, %opt ) = @_; + +my $date_format = $opt{'date_format'} || '%m/%d/%Y'; + +my $conf = new FS::Conf; + +my $curuser = $FS::CurrentUser::CurrentUser; + +my $invoice = emt("Invoice #[_1] (Balance [_2])",$cust_bill_void->display_invnum, $cust_bill_void->charged); + +my $under = ''; + +my $invnum = $cust_bill_void->invnum; + +#XXX use cust_bill.cgi or? +my $link = $curuser->access_right('View invoices') + ? qq!! + : ''; + +my $unvoid = ''; #XXX unvoid + +my $delete = ''; +$delete = areyousure_link("${p}misc/delete-cust_bill.html?$invnum", + emt('Are you sure you want to delete this invoice?'), + emt('Delete this invoice from the database completely'), + emt('delete') + ) + if ( $opt{'deleteinvoices'} && $curuser->access_right('Delete invoices') ); + +my $events = ''; +#1.9 +if ( $cust_bill_void->num_cust_event + && ( $curuser->access_right('Billing event reports') + || $curuser->access_right('View customer billing events') + ) + ) { + $under .= + qq!
( !. + emt('View invoice events').' )'; +} +$under = ''.$under.'' if length($under); + + -- cgit v1.2.1 From 55675d6cdd93f00b7c0ac93403e8c4d66567a729 Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Wed, 1 Aug 2012 13:16:42 -0700 Subject: invoice voiding, RT#18677 --- httemplate/view/cust_bill_void.html | 13 +++++++++---- .../view/cust_main/payment_history/voided_invoice.html | 3 +-- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'httemplate') diff --git a/httemplate/view/cust_bill_void.html b/httemplate/view/cust_bill_void.html index c7c5da146..148c0ed7e 100755 --- a/httemplate/view/cust_bill_void.html +++ b/httemplate/view/cust_bill_void.html @@ -11,6 +11,11 @@ %#

% #} +
VOID
+ % if ( $conf->exists('invoice_html') ) { <% join('', $cust_bill_void->print_html(\%opt) ) %> % } else { @@ -43,13 +48,13 @@ my $cust_bill_void = qsearchs({ 'select' => 'cust_bill_void.*', 'table' => 'cust_bill_void', #'addl_from' => 'LEFT JOIN cust_main USING ( custnum )', - 'hashref' => { 'quotationnum' => $quotationnum }, + 'hashref' => { 'invnum' => $invnum }, #'extra_sql' => ' AND '. $curuser->agentnums_sql, }); -die "Quotation #$quotationnum not found!" unless $quotation; +die "Voided invoice #$invnum not found!" unless $cust_bill_void; -my $custnum = $cust_bill->custnum; -my $display_custnum = $cust_bill->cust_main->display_custnum; +my $custnum = $cust_bill_void->custnum; +my $display_custnum = $cust_bill_void->cust_main->display_custnum; #my $link = "invnum=$invnum"; diff --git a/httemplate/view/cust_main/payment_history/voided_invoice.html b/httemplate/view/cust_main/payment_history/voided_invoice.html index 422edb2f6..7bf206352 100644 --- a/httemplate/view/cust_main/payment_history/voided_invoice.html +++ b/httemplate/view/cust_main/payment_history/voided_invoice.html @@ -21,9 +21,8 @@ my $under = ''; my $invnum = $cust_bill_void->invnum; -#XXX use cust_bill.cgi or? my $link = $curuser->access_right('View invoices') - ? qq!! + ? qq!! : ''; my $unvoid = ''; #XXX unvoid -- cgit v1.2.1 From bec3b6c2bf97d66b992866d7ee7295f1f05452e6 Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Wed, 1 Aug 2012 14:01:14 -0700 Subject: invoice voiding, RT#18677 --- httemplate/misc/process/void-cust_bill.html | 6 +++++- httemplate/misc/unvoid-cust_bill_void.html | 25 ++++++++++++++++++++++ httemplate/misc/unvoid-cust_pay_void.cgi | 2 +- httemplate/misc/void-cust_pay.cgi | 2 +- .../view/cust_main/payment_history/payment.html | 2 +- .../cust_main/payment_history/voided_invoice.html | 8 ++++++- .../cust_main/payment_history/voided_payment.html | 2 +- 7 files changed, 41 insertions(+), 6 deletions(-) create mode 100755 httemplate/misc/unvoid-cust_bill_void.html (limited to 'httemplate') diff --git a/httemplate/misc/process/void-cust_bill.html b/httemplate/misc/process/void-cust_bill.html index f2930ec01..899901a50 100755 --- a/httemplate/misc/process/void-cust_bill.html +++ b/httemplate/misc/process/void-cust_bill.html @@ -2,7 +2,11 @@ % $cgi->param('error', $error); <% $cgi->redirect(popurl(1). "void-cust_bill.html?". $cgi->query_string ) %> %} else { -<% $cgi->redirect(popurl(3). "view/cust_main.cgi?". $custnum) %> +<& /elements/header-popup.html, 'Invoice voided' &> + + %} <%init> diff --git a/httemplate/misc/unvoid-cust_bill_void.html b/httemplate/misc/unvoid-cust_bill_void.html new file mode 100755 index 000000000..f61416549 --- /dev/null +++ b/httemplate/misc/unvoid-cust_bill_void.html @@ -0,0 +1,25 @@ +%if ( $error ) { +% errorpage($error); +%} else { +% my $show = $curuser->default_customer_view =~ /^(jumbo|payment_history)$/ +% ? '' +% : ';show=payment_history'; +<% $cgi->redirect($p. "view/cust_main.cgi?custnum=$custnum$show" ) %> +%} +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right('Unvoid invoices'); + +#untaint invnum +$cgi->param('invnum') =~ /^(\d+)$/ || die "Illegal invnum"; +my $invnum = $1; + +my $cust_bill_void = qsearchs('cust_bill_void', { 'invnum' => $invnum } ); +my $custnum = $cust_bill_void->custnum; + +my $error = $cust_bill_void->unvoid; + + diff --git a/httemplate/misc/unvoid-cust_pay_void.cgi b/httemplate/misc/unvoid-cust_pay_void.cgi index 91fe1c223..4726ee576 100755 --- a/httemplate/misc/unvoid-cust_pay_void.cgi +++ b/httemplate/misc/unvoid-cust_pay_void.cgi @@ -6,7 +6,7 @@ <%init> die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Unvoid'); + unless $FS::CurrentUser::CurrentUser->access_right('Unvoid payments'); #untaint paynum my($query) = $cgi->keywords; diff --git a/httemplate/misc/void-cust_pay.cgi b/httemplate/misc/void-cust_pay.cgi index 7b484e93e..31b7a6201 100755 --- a/httemplate/misc/void-cust_pay.cgi +++ b/httemplate/misc/void-cust_pay.cgi @@ -12,7 +12,7 @@ my $paynum = $1; my $cust_pay = qsearchs('cust_pay',{'paynum'=>$paynum}); -my $right = 'Regular void'; +my $right = 'Void payments'; $right = 'Credit card void' if $cust_pay->payby eq 'CARD'; $right = 'Echeck void' if $cust_pay->payby eq 'CHEK'; diff --git a/httemplate/view/cust_main/payment_history/payment.html b/httemplate/view/cust_main/payment_history/payment.html index d7322a2d6..ff269bfaf 100644 --- a/httemplate/view/cust_main/payment_history/payment.html +++ b/httemplate/view/cust_main/payment_history/payment.html @@ -181,7 +181,7 @@ $void = areyousure_link("${p}misc/void-cust_pay.cgi?".$cust_pay->paynum, && $curuser->access_right('Echeck void') ) || ( $cust_pay->payby !~ /^(CARD|CHEK)$/ - && $curuser->access_right('Regular void') + && $curuser->access_right('Void payments') ) ) ); diff --git a/httemplate/view/cust_main/payment_history/voided_invoice.html b/httemplate/view/cust_main/payment_history/voided_invoice.html index 7bf206352..15393cbf5 100644 --- a/httemplate/view/cust_main/payment_history/voided_invoice.html +++ b/httemplate/view/cust_main/payment_history/voided_invoice.html @@ -25,7 +25,13 @@ my $link = $curuser->access_right('View invoices') ? qq!! : ''; -my $unvoid = ''; #XXX unvoid +my $unvoid = ''; +$unvoid = areyousure_link("${p}misc/unvoid-cust_bill_void.html?invnum=". $cust_bill_void->invnum, + emt('Are you sure you want to unvoid this invoice?'), + emt('Unvoid this invoice'), + emt('unvoid') + ) + if $cust_bill_void->closed !~ /^Y/ && $curuser->access_right('Unvoid invoices'); my $delete = ''; $delete = areyousure_link("${p}misc/delete-cust_bill.html?$invnum", diff --git a/httemplate/view/cust_main/payment_history/voided_payment.html b/httemplate/view/cust_main/payment_history/voided_payment.html index 2f038be41..88b5e0a84 100644 --- a/httemplate/view/cust_main/payment_history/voided_payment.html +++ b/httemplate/view/cust_main/payment_history/voided_payment.html @@ -31,6 +31,6 @@ $unvoid = areyousure_link("${p}misc/unvoid-cust_pay_void.cgi?".$cust_pay_void->p emt('Unvoid this payment from the database') . $unvoidmsg, emt('unvoid') ) - if ( $cust_pay_void->closed !~ /^Y/i && $curuser->access_right('Unvoid') ); + if ( $cust_pay_void->closed !~ /^Y/i && $curuser->access_right('Unvoid payments') ); -- cgit v1.2.1 From 4d6c465f4b32a49f8bce091f6cb5abb209123ec2 Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Wed, 1 Aug 2012 14:04:50 -0700 Subject: invoice voiding, RT#18677 --- httemplate/view/cust_bill.cgi | 2 -- httemplate/view/cust_bill_void.html | 20 +++++++++++++++++++- httemplate/view/quotation.html | 2 -- 3 files changed, 19 insertions(+), 5 deletions(-) (limited to 'httemplate') diff --git a/httemplate/view/cust_bill.cgi b/httemplate/view/cust_bill.cgi index a8b4ac15c..95ce60b1d 100755 --- a/httemplate/view/cust_bill.cgi +++ b/httemplate/view/cust_bill.cgi @@ -166,8 +166,6 @@ die "Invoice #$invnum not found!" unless $cust_bill; my $custnum = $cust_bill->custnum; my $display_custnum = $cust_bill->cust_main->display_custnum; -#my $printed = $cust_bill->printed; - my $link = "invnum=$invnum"; $link .= ';template='. uri_escape($template) if $template; $link .= ';notice_name='. $notice_name if $notice_name; diff --git a/httemplate/view/cust_bill_void.html b/httemplate/view/cust_bill_void.html index 148c0ed7e..2c526747b 100755 --- a/httemplate/view/cust_bill_void.html +++ b/httemplate/view/cust_bill_void.html @@ -2,7 +2,19 @@ emt("View this customer (#[_1])",$display_custnum) => "${p}view/cust_main.cgi?$custnum", ) &> -%#XXX something very big and obvious showing its voided... + +<% areyousure_link("${p}misc/unvoid-cust_bill_void.html?invnum=". $cust_bill_void->invnum, + emt('Are you sure you want to unvoid this invoice?'), + emt('Unvoid this invoice'), #tooltip + emt('Unvoid this invoice') #link + ) +%> +

% #voided PDFs? % #if ( $conf->exists('invoice_latex') ) { @@ -11,6 +23,7 @@ %#

% #} +%#something very big and obvious showing its voided...
'.$label.''; +} + diff --git a/httemplate/view/quotation.html b/httemplate/view/quotation.html index 461b5dfb6..a88acf82b 100755 --- a/httemplate/view/quotation.html +++ b/httemplate/view/quotation.html @@ -44,8 +44,6 @@ XXX resending quotations % } % #plaintext quotations?
<% join('', $quotation->print_text() ) %>
- - <& /elements/footer.html &> <%init> -- cgit v1.2.1 From 0f2d1070bc6f1521ab50dd07e475587f1117eec6 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Thu, 2 Aug 2012 15:54:31 -0700 Subject: sales by ad source report: filter by ad source, #17971 --- httemplate/elements/tr-select-part_referral.html | 8 +------- httemplate/search/cust_bill_pkg_referral.html | 10 ++++++++++ httemplate/search/report_cust_bill_pkg_referral.html | 5 +++++ 3 files changed, 16 insertions(+), 7 deletions(-) (limited to 'httemplate') diff --git a/httemplate/elements/tr-select-part_referral.html b/httemplate/elements/tr-select-part_referral.html index 765aa8400..5041f7f73 100644 --- a/httemplate/elements/tr-select-part_referral.html +++ b/httemplate/elements/tr-select-part_referral.html @@ -14,13 +14,7 @@ % } else { - - -% if ( $opt{'label'} ) { - <% $opt{'label'} %> -% } else { - <%$r%><% mt('Advertising source') |h %> -% } + <& /elements/tr-td-label.html, label => 'Advertising source', %opt &> <& /elements/select-part_referral.html, 'curr_value' => $refnum, diff --git a/httemplate/search/cust_bill_pkg_referral.html b/httemplate/search/cust_bill_pkg_referral.html index 3cb434caa..77b486021 100644 --- a/httemplate/search/cust_bill_pkg_referral.html +++ b/httemplate/search/cust_bill_pkg_referral.html @@ -146,6 +146,16 @@ if ( @status_where ) { ') IN (' . join(',', @status_where) .')'; } +my @refnum; +foreach my $refnum ($cgi->param('refnum')) { + if ( $refnum =~ /^\d+$/ ) { + push @refnum, $refnum; + } +} +if ( @refnum ) { + push @where, 'cust_main.refnum IN ('.join(',', @refnum).')'; +} + if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) { push @where, "cust_main.agentnum = $1"; } diff --git a/httemplate/search/report_cust_bill_pkg_referral.html b/httemplate/search/report_cust_bill_pkg_referral.html index ff2caa1fa..b4716d4fc 100644 --- a/httemplate/search/report_cust_bill_pkg_referral.html +++ b/httemplate/search/report_cust_bill_pkg_referral.html @@ -18,6 +18,11 @@ 'disable_empty' => 1, &> +<& /elements/tr-select-part_referral.html, + 'multiple' => 1, + 'disable_empty' => 1, +&> + <& /elements/tr-select-pkg_class.html, 'pre_options' => [ '' => 'all', '0' => '(empty class)' ], 'disable_empty' => 1, -- cgit v1.2.1 From e881063d6e46d991003cf8fae96d8d36780fedcd Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Thu, 2 Aug 2012 19:39:20 -0700 Subject: per-customer prorate day, RT#17891 --- httemplate/edit/cust_main/billing.html | 11 +++++++++++ httemplate/view/cust_main/billing.html | 8 ++++++++ 2 files changed, 19 insertions(+) (limited to 'httemplate') diff --git a/httemplate/edit/cust_main/billing.html b/httemplate/edit/cust_main/billing.html index d7082f23a..2925ca87c 100644 --- a/httemplate/edit/cust_main/billing.html +++ b/httemplate/edit/cust_main/billing.html @@ -522,6 +522,17 @@ % } +% if ( $conf->exists('cust_main-select-prorate_day') ) { + + <% mt('Prorate day (1-28)') |h %> + + + + +% } else { + +% } + <% mt('Invoice terms') |h %> diff --git a/httemplate/view/cust_main/billing.html b/httemplate/view/cust_main/billing.html index b2a0efdef..5c46803d2 100644 --- a/httemplate/view/cust_main/billing.html +++ b/httemplate/view/cust_main/billing.html @@ -23,6 +23,14 @@ <% $balance %> +% if ( $conf->exists('cust_main-select-prorate_day') ) { + + <% mt('Prorate day of month') |h %> + <% $cust_main->prorate_day %> + + +% } + % if ( $conf->exists('cust_main-select-billday') % && ($cust_main->payby eq 'CARD' || $cust_main->payby eq 'CHEK') ) { -- cgit v1.2.1 From 8b4b2a97a84d17087c3fac19b8f768ca146cf897 Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Fri, 3 Aug 2012 13:02:19 -0700 Subject: fix pending payment popups --- httemplate/search/cust_pay_pending.html | 1 - 1 file changed, 1 deletion(-) (limited to 'httemplate') diff --git a/httemplate/search/cust_pay_pending.html b/httemplate/search/cust_pay_pending.html index 8b7350853..2afce0ce9 100755 --- a/httemplate/search/cust_pay_pending.html +++ b/httemplate/search/cust_pay_pending.html @@ -5,7 +5,6 @@ 'name_verb' => 'pending', 'disable_link' => 1, 'disable_by' => 1, #add otaker to cust_pay_pending? - 'html_init' => include('/elements/init_overlib.html'), 'addl_header' => [ 'Time', 'Payment Status', ], 'addl_fields' => [ sub { time2str('%r', shift->_date ) }, $status_sub, -- cgit v1.2.1 From 45346fd655ba53b82c80b920da945cc0b87ece01 Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Fri, 3 Aug 2012 13:09:05 -0700 Subject: selfservice payment fees, RT#18345 --- httemplate/elements/tr-amount_fee.html | 4 +++- httemplate/misc/payment.cgi | 15 +-------------- 2 files changed, 4 insertions(+), 15 deletions(-) (limited to 'httemplate') diff --git a/httemplate/elements/tr-amount_fee.html b/httemplate/elements/tr-amount_fee.html index a1a9e3433..12488521a 100644 --- a/httemplate/elements/tr-amount_fee.html +++ b/httemplate/elements/tr-amount_fee.html @@ -90,7 +90,9 @@ if ( $amount > 0 ) { $amount += $fee if $fee && $fee_display eq 'subtract'; - &{ $opt{post_fee_callback} }( \$amount ) if $opt{post_fee_callback}; + #&{ $opt{post_fee_callback} }( \$amount ) if $opt{post_fee_callback}; + $amount += $amount * $opt{'surcharge_percentage'}/100 + if $opt{'surcharge_percentage'} > 0; $amount = sprintf("%.2f", $amount); } diff --git a/httemplate/misc/payment.cgi b/httemplate/misc/payment.cgi index 1ae15b930..e221c600a 100644 --- a/httemplate/misc/payment.cgi +++ b/httemplate/misc/payment.cgi @@ -16,7 +16,7 @@ 'process-display' => scalar($conf->config('manual_process-display')), 'process-skip-first' => $conf->exists('manual_process-skip_first'), 'num_payments' => scalar($cust_main->cust_pay), - 'post_fee_callback' => $post_fee_callback, + 'surcharge_percentage' => scalar($conf->config('credit-card-surcharge-percentage')), &> <& /elements/tr-select-discount_term.html, @@ -269,19 +269,6 @@ if ( $balance > 0 ) { $amount = $balance; } -my $post_fee_callback = sub { - my( $amountref ) = @_; - - return unless $$amountref > 0; - - my $conf = new FS::Conf; - - my $cc_surcharge_pct = $conf->config('credit-card-surcharge-percentage'); - $$amountref += $$amountref * $cc_surcharge_pct/100 if $cc_surcharge_pct > 0; - - $$amountref = sprintf("%.2f", $$amountref); -}; - my $payunique = "webui-payment-". time. "-$$-". rand() * 2**32; -- cgit v1.2.1 From 0d8eb2d4d4a372680d0fa564fbfcba0d6674b259 Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Sat, 4 Aug 2012 09:26:23 -0700 Subject: fix skipping processing fee for first payment, RT#18345 --- httemplate/misc/payment.cgi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'httemplate') diff --git a/httemplate/misc/payment.cgi b/httemplate/misc/payment.cgi index e221c600a..2d7307233 100644 --- a/httemplate/misc/payment.cgi +++ b/httemplate/misc/payment.cgi @@ -14,7 +14,7 @@ 'amount' => $amount, 'process-pkgpart' => scalar($conf->config('manual_process-pkgpart')), 'process-display' => scalar($conf->config('manual_process-display')), - 'process-skip-first' => $conf->exists('manual_process-skip_first'), + 'process-skip_first' => $conf->exists('manual_process-skip_first'), 'num_payments' => scalar($cust_main->cust_pay), 'surcharge_percentage' => scalar($conf->config('credit-card-surcharge-percentage')), &> -- cgit v1.2.1 From 21254f0e0062b92c19530c49c6eacc9ce3e93827 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Tue, 7 Aug 2012 18:39:05 -0700 Subject: Business::BatchPayment fixes for TD EFT format, #17878 --- httemplate/edit/payment_gateway.html | 3 ++- httemplate/search/elements/cust_pay_batch_top.html | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'httemplate') diff --git a/httemplate/edit/payment_gateway.html b/httemplate/edit/payment_gateway.html index e5897b035..dfe52f109 100644 --- a/httemplate/edit/payment_gateway.html +++ b/httemplate/edit/payment_gateway.html @@ -91,6 +91,7 @@ my %modules = ( 'KeyBank' => 'Business::BatchPayment', 'Paymentech' => 'Business::BatchPayment', + 'TD_EFT' => 'Business::BatchPayment', ); my %modules_for_namespace; @@ -141,7 +142,7 @@ my $fields = [ { field => 'gateway_options', type => 'textarea', - rows => '8', + rows => '12', cols => '40', curr_value_callback => sub { my($cgi, $object, $fref) = @_; join("\r", $object->options ); diff --git a/httemplate/search/elements/cust_pay_batch_top.html b/httemplate/search/elements/cust_pay_batch_top.html index 739e65b50..1dcc37ac1 100644 --- a/httemplate/search/elements/cust_pay_batch_top.html +++ b/httemplate/search/elements/cust_pay_batch_top.html @@ -33,6 +33,7 @@ Download batch in format +% } + + <% include( '/elements/tr-input-text.html', + 'field' => 'national_id1', + 'value' => $nric, + 'label' => 'NRIC', + ) + %> + <% include( '/elements/tr-input-text.html', + 'field' => 'national_id2', + 'value' => $old, + 'label' => 'Old IC/Passport', + ) + %> + +% } else { +% warn "unknown national_id-country $id_country"; +% } +% } + % if ( $conf->exists('cust_main-enable_birthdate') ) { <% include( '/elements/tr-input-date-field.html', { 'name' => 'birthdate', diff --git a/httemplate/edit/process/cust_main.cgi b/httemplate/edit/process/cust_main.cgi index 866452de1..622dd87c5 100755 --- a/httemplate/edit/process/cust_main.cgi +++ b/httemplate/edit/process/cust_main.cgi @@ -110,6 +110,36 @@ if ( $cgi->param('no_credit_limit') ) { $new->tagnum( [ $cgi->param('tagnum') ] ); +if ( my $id_country = $conf->config('national_id-country') ) { + if ( $id_country eq 'MY' ) { + + if ( $cgi->param('national_id1') =~ /\S/ ) { + my $nric = $cgi->param('national_id1'); + $nric =~ s/\s//g; + if ( $nric =~ /^(\d{6})\-?(\d{2})\-?(\d{4})$/ ) { + $new->national_id( "$1-$2-$3" ); + } else { + $error ||= "Illegal NRIC: ". $cgi->param('national_id1'); + } + } elsif ( $cgi->param('national_id2') =~ /\S/ ) { + my $oldic = $cgi->param('national_id2'); + $oldic =~ s/\s//g; + if ( $oldic =~ /^\w\d{9}$/ ) { + $new->national_id($oldic); + } else { + $error ||= "Illegal Old IC/Passport: ". $cgi->param('national_id2'); + } + } else { + $error ||= 'Either NRIC or Old IC/Passport is required'; + } + + } else { + warn "unknown national_id-country $id_country"; + } +} elsif ( $cgi->param('national_id0') ) { + $new->national_id( $cgi->param('national_id0') ); +} + my %usedatetime = ( 'birthdate' => 1, 'spouse_birthdate' => 1, 'anniversary_date' => 1, diff --git a/httemplate/view/cust_main/misc.html b/httemplate/view/cust_main/misc.html index dc6da53f1..9713b2469 100644 --- a/httemplate/view/cust_main/misc.html +++ b/httemplate/view/cust_main/misc.html @@ -102,6 +102,26 @@ <% $cust_main->signupdate ? time2str($date_format, $cust_main->signupdate) : '' %> +% my $id_country = $conf->config('national_id-country'); +% if ( $id_country ) { +% if ( $id_country eq 'MY' ) { + +% my($old, $nric) = ( '', ''); +% if ( $cust_main->national_id =~ /^\w\d{9}$/ ) { + <% mt('Old IC/Passport') |h %> +% } elsif ( $cust_main->national_id =~ /^\d{6}\-\d{2}\-\d{4}$/ ) { + <% mt('NRIC') |h %> +% } else { +% warn "unknown national_id format"; + +% } + <% $cust_main->national_id |h %> + +% } else { +% warn "unknown national_id-country $id_country"; +% } +% } + % if ( $conf->exists('cust_main-enable_birthdate') ) { % my $dt = $cust_main->birthdate ne '' % ? DateTime->from_epoch( 'epoch' => $cust_main->birthdate, -- cgit v1.2.1 From 7b19b666fc36f8dc28747a11bd2b389d8d2ef75f Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Fri, 10 Aug 2012 16:07:50 -0700 Subject: sqlradius data usage report, #18823 --- httemplate/elements/menu.html | 2 ++ httemplate/search/elements/search-html.html | 4 ++-- httemplate/search/elements/search.html | 6 +++++- 3 files changed, 9 insertions(+), 3 deletions(-) (limited to 'httemplate') diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html index 019afe94e..c656cb9eb 100644 --- a/httemplate/elements/menu.html +++ b/httemplate/elements/menu.html @@ -256,6 +256,8 @@ tie my %report_inventory, 'Tie::IxHash', tie my %report_rating, 'Tie::IxHash'; $report_rating{'RADIUS sessions'} = [ $fsurl.'search/sqlradius.html', '' ] if $curuser->access_right("Usage: RADIUS sessions"); +$report_rating{'RADIUS data usage'} = [ $fsurl.'search/report_sqlradius_usage.html', '' ] + if $curuser->access_right("Usage: RADIUS sessions"); $report_rating{'Call Detail Records (CDRs)'} = [ $fsurl.'search/report_cdr.html', '' ] if $curuser->access_right("Usage: Call Detail Records (CDRs)"); $report_rating{'Unrateable CDRs'} = [ $fsurl.'search/cdr.html?freesidestatus=failed;cdrbatchnum=_ALL_' ] diff --git a/httemplate/search/elements/search-html.html b/httemplate/search/elements/search-html.html index c27771494..cf60d8f82 100644 --- a/httemplate/search/elements/search-html.html +++ b/httemplate/search/elements/search-html.html @@ -134,9 +134,9 @@ % and !$opt{'disable_download'} % and $type ne 'html-print' ) { - + - Download full results
+ <% $opt{'download_label'} || 'Download full results' %>
% $cgi->param('_type', "$xlsname.xls" ); as query_string %>">Excel spreadsheet
diff --git a/httemplate/search/elements/search.html b/httemplate/search/elements/search.html index 9bc66b6fa..eca68a2f8 100644 --- a/httemplate/search/elements/search.html +++ b/httemplate/search/elements/search.html @@ -162,7 +162,11 @@ Example: # Excel-specific listref of ( hashrefs or coderefs ) # each hashref: http://search.cpan.org/dist/Spreadsheet-WriteExcel/lib/Spreadsheet/WriteExcel.pm#Format_methods_and_Format_properties 'xls_format' => => [], - + + + # miscellany + 'download_label' => 'Download this report', + # defaults to 'Download full results' &> -- cgit v1.2.1 From db80d13447786bc554d40d4817a1b0d7a5b5e09f Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Fri, 10 Aug 2012 17:09:46 -0700 Subject: rest of sqlradius data usage report --- httemplate/search/report_sqlradius_usage.html | 40 ++++++ httemplate/search/sqlradius_usage.html | 194 ++++++++++++++++++++++++++ 2 files changed, 234 insertions(+) create mode 100644 httemplate/search/report_sqlradius_usage.html create mode 100644 httemplate/search/sqlradius_usage.html (limited to 'httemplate') diff --git a/httemplate/search/report_sqlradius_usage.html b/httemplate/search/report_sqlradius_usage.html new file mode 100644 index 000000000..01215e834 --- /dev/null +++ b/httemplate/search/report_sqlradius_usage.html @@ -0,0 +1,40 @@ +<& /elements/header.html, mt($title) &> + +
+ + 'all', +&> + +% my @exporttypes = map { "'$_'" } qw(sqlradius broadband_sqlradius); +<& /elements/tr-select-table.html, + 'label' => 'Export', + 'table' => 'part_export', + 'name_col' => 'label', + 'hashref' => {}, + 'extra_sql' => ' WHERE exporttype IN('.join(',', @exporttypes).')', + 'disable_empty' => 1, + 'order_by' => 'ORDER BY exportnum', +&> + +<& /elements/tr-input-beginning_ending.html &> + +
+ +
+ + +
+ +<& /elements/footer.html &> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Usage: RADIUS sessions'); + # yes? + +my $title = 'Data Usage Report'; + + diff --git a/httemplate/search/sqlradius_usage.html b/httemplate/search/sqlradius_usage.html new file mode 100644 index 000000000..dd06c10fa --- /dev/null +++ b/httemplate/search/sqlradius_usage.html @@ -0,0 +1,194 @@ +% if ( @include_agents ) { +% # jumbo report +<& /elements/header.html, $title &> +% foreach my $agent ( @include_agents ) { +% $cgi->param('agentnum', $agent->agentnum); #for download links +
+<% $agent->agent %>

+ <& sqlradius_usage.html, + export => $export, + agentnum => $agent->agentnum, + nohtmlheader => 1, + usage_by_username => \%usage_by_username, + download_label => 'Download this section', + &> +
+

+% } +<& /elements/footer.html &> +% } else { +<& elements/search.html, + 'title' => $title, + 'name' => 'services', + 'query' => $sql_query, + 'count_query' => $sql_query->{'count_query'}, + 'header' => [ #FS::UI::Web::cust_header(), + '#', + 'Customer', + 'Package', + @svc_header, + 'Upload', + 'Download', + 'Total', + ], + 'footer' => \@footer, + 'fields' => [ #\&FS::UI::Web::cust_fields, + 'display_custnum', + 'name', + 'pkg', + @svc_fields, + @svc_usage, + ], + 'links' => [ #( map { $_ ne 'Cust. Status' ? $link_cust : '' } + # FS::UI::Web::cust_header() ), + $link_cust, + $link_cust, + '', #package + ( map { $link_svc } @svc_header ), + '', + '', + '', + ], + 'align' => #FS::UI::Web::cust_aligns() . + 'rlc' . ('l' x scalar(@svc_header)) . 'rrr' , + 'nohtmlheader' => ($opt{'nohtmlheader'} || 0), + 'download_label' => $opt{'download_label'}, +&> +% } +<%init> + +my %opt = @_; + +die "access denied" unless + $FS::CurrentUser::CurrentUser->access_right('List services'); + +my $title = 'Data Usage Report - '; +my $agentnum; +my @include_agents; + +if ( $opt{'agentnum'} ) { + $agentnum = $opt{'agentnum'}; +} elsif ( $cgi->param('agentnum') =~ /^(\d+)$/ ) { + $agentnum = $1; +} + +if ( $agentnum ) { + my $agent = FS::agent->by_key($agentnum); + $title = $agent->agent." $title"; +} else { + @include_agents = qsearch('agent', {}); +} + +# usage query params +my( $beginning, $ending ) = FS::UI::Web::parse_beginning_ending($cgi); + +if ( $beginning ) { + $title .= time2str('%h %o %Y ', $beginning); +} +$title .= 'through '; +if ( $ending == 4294967295 ) { + $title .= 'now'; +} else { + $title .= time2str('%h %o %Y', $ending); +} + +my $export; +my %usage_by_username; +if ( exists($opt{usage_by_username}) ) { + # There's no agent separation in the radacct data. So in the jumbo report + # do this procedure once, and pass the hash into all the per-agent sections. + %usage_by_username = %{ $opt{usage_by_username} }; + $export = $opt{export}; +} else { + + $cgi->param('exportnum') =~ /^(\d+)$/ + or die "illegal export: '".$cgi->param('exportnum')."'"; + $export = FS::part_export->by_key($1) + or die "exportnum $1 not found"; + $export->exporttype =~ /sqlradius/ + or die "exportnum ".$export->exportnum." is type ".$export->exporttype. + ", not sqlradius"; + + my $usage = $export->usage_sessions( { + stoptime_start => $beginning, + stoptime_end => $ending, + summarize => 1 + } ); + # arrayref of hashrefs of + # (username, acctsessiontime, acctinputoctets, acctoutputoctets) + # (XXX needs to include 'realm' for sqlradius_withdomain) + # rearrange to be indexed by username. + + foreach (@$usage) { + my $username = $_->{'username'}; + my @row = ( + $_->{'acctinputoctets'}, + $_->{'acctoutputoctets'}, + $_->{'acctinputoctets'} + $_->{'acctoutputoctets'} + ); + $usage_by_username{$username} = \@row; + } +} + +#warn Dumper(\%usage_by_username); +my @total_usage = (0, 0, 0, 0); # session time, input, output, input + output +my @svc_usage = map { + my $i = $_; + sub { + my $username = $export->export_username(shift); + return '' if !exists($usage_by_username{$username}); + my $value = $usage_by_username{ $username }->[$i]; + $total_usage[$i] += $value; + FS::UI::bytecount::display_bytecount($value); + } +} (0,1,2); + +# set up svcdb-specific stuff +my $export_username = sub { + $export->export_username(shift); # countrycode + phone, formatted MAC, etc. +}; + +my %svc_header = ( + svc_acct => [ 'Username' ], + svc_broadband => [ 'MAC address', 'IP address' ], +# svc_phone => [ 'Phone' ], #not yet supported, no search method + # (not sure input/output octets is relevant) +); +my %svc_fields = ( + svc_acct => [ $export_username ], + svc_broadband => [ $export_username, 'ip_addr' ], +# svc_phone => [ $export_username ], +); + +# what kind of service we're operating on +my $svcdb = FS::part_export::export_info()->{$export->exporttype}->{'svc'}; +my $class = "FS::$svcdb"; +my @svc_header = @{ $svc_header{$svcdb} }; +my @svc_fields = @{ $svc_fields{$svcdb} }; + +# svc_x search params +my %search_hash = ( 'agentnum' => $agentnum ); + +my $sql_query = $class->search(\%search_hash); +$sql_query->{'select'} .= ', part_pkg.pkg'; +$sql_query->{'addl_from'} .= ' LEFT JOIN part_pkg USING (pkgpart)'; + +my $link_svc = [ $p.'view/cust_svc.cgi?', 'svcnum' ]; + +my $link_cust = [ $p.'view/cust_main.cgi?', 'custnum' ]; + +# columns between the customer name and the usage fields +my $skip_cols = 1 + scalar(@svc_header); + +my @footer = ( + '', + FS::Record->scalar_sql($sql_query->{count_query}) . ' services', + (' ') x $skip_cols, + map { + sub { # defer this until the rows have been processed + FS::UI::bytecount::display_bytecount($total_usage[$_]) + } + } (0,1,2) +); + + -- cgit v1.2.1 From 0bd09a9eff467033be42f922f2297a7b488e7dc1 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Mon, 13 Aug 2012 16:21:36 -0700 Subject: per-agent subtotals on sales report, #18566 --- httemplate/graph/cust_bill_pkg.cgi | 54 ++++++++++++++++++++++-- httemplate/graph/elements/monthly.html | 36 ++++++++++------ httemplate/graph/elements/report.html | 15 ++++++- httemplate/graph/report_cust_bill_pkg.html | 67 ++++++++++++++++++++---------- 4 files changed, 133 insertions(+), 39 deletions(-) (limited to 'httemplate') diff --git a/httemplate/graph/cust_bill_pkg.cgi b/httemplate/graph/cust_bill_pkg.cgi index e7a3bd27e..c334ae9e7 100644 --- a/httemplate/graph/cust_bill_pkg.cgi +++ b/httemplate/graph/cust_bill_pkg.cgi @@ -8,6 +8,7 @@ 'graph_labels' => \@labels, 'colors' => \@colors, 'links' => \@links, + 'no_graph' => \@no_graph, 'remove_empty' => 1, 'bottom_total' => 1, 'bottom_link' => $bottom_link, @@ -118,6 +119,7 @@ my @params = (); my @labels = (); my @colors = (); my @links = (); +my @no_graph; my @components = ( 'SRU' ); # split/omit components as appropriate @@ -134,6 +136,11 @@ elsif ( $use_usage == 2 ) { $components[-1] =~ s/U//; } +# Categorization of line items goes +# Agent -> Referral -> Package class -> Component (setup/recur/usage) +# If per-agent totals are enabled, they go under the Agent level. +# There aren't any other kinds of subtotals. + foreach my $agent ( $all_agent || $sel_agent || qsearch('agent', { 'disabled' => '' } ) ) { my $col_scheme = Color::Scheme->new @@ -146,7 +153,11 @@ foreach my $agent ( $all_agent || $sel_agent || qsearch('agent', { 'disabled' => ### fixup the color handling for package classes... ### and usage - foreach my $part_referral ( $all_part_referral || $sel_part_referral || qsearch('part_referral', { 'disabled' => '' } ) ) { + foreach my $part_referral ( + $all_part_referral || + $sel_part_referral || + qsearch('part_referral', { 'disabled' => '' } ) + ) { foreach my $pkg_class ( @pkg_class ) { foreach my $component ( @components ) { @@ -186,9 +197,46 @@ foreach my $agent ( $all_agent || $sel_agent || qsearch('agent', { 'disabled' => @onetime_colors = ($col_scheme->colors)[2,6,10,3,7,11] unless @onetime_colors; push @colors, shift @recur_colors; - - } + push @no_graph, 0; + + } #foreach $component + } #foreach $pkg_class + } #foreach $part_referral + + if ( $cgi->param('agent_totals') and !$all_agent ) { + my $row_agentnum = $agent->agentnum; + # Include all components that are anywhere on this report + my $component = join('', @components); + + my @row_params = ( 'agentnum' => $row_agentnum, + 'use_override' => $use_override, + 'average_per_cust_pkg' => $average_per_cust_pkg, + 'distribute' => $distribute, + 'charges' => $component, + ); + my $row_link = "$link;". + "agentnum=$row_agentnum;". + "distribute=$distribute;". + "charges=$component"; + + # Also apply any refnum/classnum filters + if ( !$all_class and scalar(@pkg_class) == 1 ) { + # then a specific class has been chosen, but it may be the empty class + my $row_classnum = ref($pkg_class[0]) ? $pkg_class[0]->classnum : 0; + push @row_params, 'classnum' => $row_classnum; + $row_link .= ";classnum=$row_classnum"; } + if ( $sel_part_referral ) { + push @row_params, 'refnum' => $sel_part_referral->refnum; + $row_link .= ";refnum=".$sel_part_referral->refnum; + } + + push @items, 'cust_bill_pkg'; + push @labels, mt('[_1] - Subtotal', $agent->agent); + push @params, \@row_params; + push @links, $row_link; + push @colors, '000000'; # better idea? + push @no_graph, 1; } $hue += $hue_increment; diff --git a/httemplate/graph/elements/monthly.html b/httemplate/graph/elements/monthly.html index 839a3873e..c736de696 100644 --- a/httemplate/graph/elements/monthly.html +++ b/httemplate/graph/elements/monthly.html @@ -20,6 +20,7 @@ Example: 'link_fromparam' => 'param_from', #defaults to 'begin' 'link_toparam' => 'param_to', #defaults to 'end' 'daily' => 1, # omit for monthly granularity + 'no_graph' => \@no_graph, # items to leave off the graph (subtotals) #optional, pulled from CGI params if not specified 'start_month' => $smonth, @@ -49,18 +50,19 @@ Example: 'items' => $data->{'items'}, 'data' => $data->{'data'}, 'row_labels' => $data->{'item_labels'}, - 'graph_labels' => $opt{'graph_labels'} || $data->{'item_labels'}, + 'graph_labels' => \@graph_labels, 'col_labels' => $col_labels, 'axis_labels' => $data->{label}, - 'colors' => $data->{colors}, + 'colors' => \@colors, 'links' => \@links, + 'no_graph' => \@no_graph, 'bottom_link' => \@bottom_link, 'transpose' => $opt{'daily'}, - map { $_, $opt{$_} } (qw(title - nototal - graph_type - bottom_total - sprintf + map { $_, $opt{$_} } (qw(title + nototal + graph_type + bottom_total + sprintf disable_money chart_options)), ) %> @@ -103,7 +105,7 @@ if ( $opt{'daily'} ) { # daily granularity my %reportopts = ( 'items' => \@items, 'params' => $opt{'params'}, - 'item_labels' => ( $cgi->param('_type') =~ /^(png)$/ + 'item_labels' => ( $cgi->param('_type') =~ /^(png)$/ ? $opt{'graph_labels'} : $opt{'labels'} ), @@ -140,12 +142,20 @@ my $col_labels = [ map { my $m = $_; $m =~ s/^(\d+)\//$mon[$1-1] / ; $m } @{$data->{label}} ]; $col_labels = $data->{label} if $opt{'daily'}; +my @colors; +my @graph_labels; +my @no_graph; if ( $opt{'remove_empty'} ) { - # need to filter out series labels for collapsed rows - $opt{'graph_labels'} = [ - map { $opt{'graph_labels'}[$_] } - @{ $data->{indices} } - ]; + # then filter out per-item things for collapsed rows + foreach my $i (@{ $data->{'indices'} }) { + push @colors, $opt{'colors'}[$i]; + push @graph_labels, $opt{'graph_labels'}[$i]; + push @no_graph, $opt{'no_graph'}[$i]; + } +} else { + @colors = @{ $opt{'colors'} }; + @graph_labels = @{ $opt{'graph_labels'} }; + @no_graph = @{ $opt{'no_graph'} || [] }; } my @links; diff --git a/httemplate/graph/elements/report.html b/httemplate/graph/elements/report.html index f7746165a..98b477826 100644 --- a/httemplate/graph/elements/report.html +++ b/httemplate/graph/elements/report.html @@ -14,6 +14,7 @@ Example: 'graph_labels' => \@graph_labels, #defaults to row_labels 'links' => \@links, #optional + 'no_graph' => \@no_graph, #optional #these run parallel to the elements of each @item 'col_labels' => \@col_labels, #required @@ -128,7 +129,19 @@ any delimiter and linked from the elements in @data. % <% $output %> % } elsif ( $cgi->param('_type') eq 'png' ) { -% +% # delete any items that shouldn't be on the graph +% if ( my $no_graph = $opt{'no_graph'} ) { +% my $i = 0; +% while (@$no_graph) { +% if ( shift @$no_graph ) { +% splice @data, $i, 1; +% splice @{$opt{'graph_labels'}}, $i, 1; +% splice @{$opt{'colors'}}, $i, 1; +% $i--; # because everything is shifted down +% } +% $i++; +% } +% } % my $graph_type = 'LinesPoints'; % if ( $opt{'graph_type'} =~ /^(LinesPoints|Mountain|Bars)$/ ) { % $graph_type = $1; diff --git a/httemplate/graph/report_cust_bill_pkg.html b/httemplate/graph/report_cust_bill_pkg.html index 4cedcef17..31792e8dd 100644 --- a/httemplate/graph/report_cust_bill_pkg.html +++ b/httemplate/graph/report_cust_bill_pkg.html @@ -11,28 +11,45 @@ Show projected data for future months -<% include('/elements/tr-select-agent.html', - 'label' => 'Agent ', - 'disable_empty' => 0, - 'pre_options' => [ 'all' => 'all (aggregate)' ], - 'empty_label' => 'all (breakdown)', - ) -%> - -<% include('/elements/tr-select-part_referral.html', - 'label' => 'Advertising source ', - 'disable_empty' => 0, - 'pre_options' => [ 'all' => 'all (aggregate)' ], - 'empty_label' => 'all (breakdown)', - ) -%> - -<% include('/elements/tr-select-pkg_class.html', - 'pre_options' => [ 'all' => 'all (aggregate)', - '0' => 'all (breakdown)' ], - 'empty_label' => '(empty class)', - ) -%> + + +<& /elements/tr-select-agent.html, + 'field' => 'agentnum', + 'label' => 'Agent ', + 'disable_empty' => 0, + 'pre_options' => [ 'all' => 'all (aggregate)' ], + 'empty_label' => 'all (breakdown)', + 'onchange' => 'enable_agent_totals', +&> + +<& /elements/tr-select-part_referral.html, + 'field' => 'refnum', + 'label' => 'Advertising source ', + 'disable_empty' => 0, + 'pre_options' => [ 'all' => 'all (aggregate)' ], + 'empty_label' => 'all (breakdown)', + 'onchange' => 'enable_agent_totals' +&> + +<& /elements/tr-select-pkg_class.html, + 'field' => 'classnum', + 'pre_options' => [ 'all' => 'all (aggregate)', + '0' => 'all (breakdown)' ], + 'empty_label' => '(empty class)', + 'onchange' => 'enable_agent_totals', +&>