From 27625d6ad7411e16c118e328514391cef0b6c110 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 3 Aug 2010 02:11:30 +0000 Subject: fix active customers sometimes showing in search results for new "ordered" status, RT#9381 --- FS/FS/cust_main.pm | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 002b0c1d1..47eccd7f8 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -7488,7 +7488,8 @@ recurring packages not yet setup). =cut sub ordered_sql { - " 0 < ( $select_count_pkgs AND ". FS::cust_pkg->ordered_sql. " ) "; + FS::cust_main->none_active_sql. + " AND 0 < ( $select_count_pkgs AND ". FS::cust_pkg->ordered_sql. " ) "; } =item active_sql @@ -7502,6 +7503,18 @@ sub active_sql { " 0 < ( $select_count_pkgs AND ". FS::cust_pkg->active_sql. " ) "; } +=item none_active_sql + +Returns an SQL expression identifying cust_main records with no active +recurring packages. This includes customers of status prospect, ordered, +inactive, and suspended. + +=cut + +sub none_active_sql { + " 0 = ( $select_count_pkgs AND ". FS::cust_pkg->active_sql. " ) "; +} + =item inactive_sql Returns an SQL expression identifying inactive cust_main records (customers with @@ -7509,11 +7522,10 @@ no active recurring packages, but otherwise unsuspended/uncancelled). =cut -sub inactive_sql { " - 0 = ( $select_count_pkgs AND ". FS::cust_pkg->active_sql. " ) - AND - 0 < ( $select_count_pkgs AND ". FS::cust_pkg->inactive_sql. " ) -"; } +sub inactive_sql { + FS::cust_main->none_active_sql. + " AND 0 < ( $select_count_pkgs AND ". FS::cust_pkg->inactive_sql. " ) "; +} =item susp_sql =item suspended_sql @@ -7524,11 +7536,10 @@ Returns an SQL expression identifying suspended cust_main records. sub suspended_sql { susp_sql(@_); } -sub susp_sql { " - 0 < ( $select_count_pkgs AND ". FS::cust_pkg->suspended_sql. " ) - AND - 0 = ( $select_count_pkgs AND ". FS::cust_pkg->active_sql. " ) -"; } +sub susp_sql { + FS::cust_main->none_active_sql. + " AND 0 < ( $select_count_pkgs AND ". FS::cust_pkg->suspended_sql. " ) "; +} =item cancel_sql =item cancelled_sql -- cgit v1.2.1 From c8bdf37b4d6d1496b217a0af7114c4a86a1348fc Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 3 Aug 2010 02:57:15 +0000 Subject: cleaner timeworked results w/link to customer --- httemplate/misc/timeworked.html | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/httemplate/misc/timeworked.html b/httemplate/misc/timeworked.html index 46063e829..5c3c95560 100755 --- a/httemplate/misc/timeworked.html +++ b/httemplate/misc/timeworked.html @@ -8,22 +8,11 @@ - Trans Ticket - Time + Hours Customer Multiplier - - - # - # - Subject - hours - # - Name - - @@ -35,9 +24,9 @@ % my ($custnum, $name) = split(':', pop @customers, 2); % my $link = $p. 'rt/Ticket/Display.html?id='. $ticketmap{$tr_id}. % '#txn-'. $tr_id; +% my $clink = $p. 'view/cust_main.cgi?'. $custnum; - <% $tr_id %> <% $ticketmap{$tr_id} %> <% $ticket{$ticketmap{$tr_id}} |h %> @@ -47,8 +36,8 @@ % } <% sprintf("%0.2f", $seconds/3600) %> - <% $custnum %> - <% $name %> + <% $custnum %> + <% $name %> @@ -67,7 +56,7 @@ % ($custnum, $name) = split(':', $_, 2); - <% $custnum %> + <% $custnum %> <% $name %> -- cgit v1.2.1 From 746eb018918ec4660870c79d0ff907fe0920696a Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 3 Aug 2010 02:58:47 +0000 Subject: cleaner timeworked results w/link to customer --- httemplate/misc/timeworked.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/httemplate/misc/timeworked.html b/httemplate/misc/timeworked.html index 5c3c95560..672fad8d6 100755 --- a/httemplate/misc/timeworked.html +++ b/httemplate/misc/timeworked.html @@ -54,10 +54,11 @@ % foreach ( @customers ) { % ($custnum, $name) = split(':', $_, 2); +% $clink = $p. 'view/cust_main.cgi?'. $custnum; - <% $custnum %> - <% $name %> + <% $custnum %> + <% $name %> % $multiplier = $default_multiplier; -- cgit v1.2.1 From 720cf723d2c8e88760704e2fdc50ebf48e0574f2 Mon Sep 17 00:00:00 2001 From: mark Date: Tue, 3 Aug 2010 03:30:20 +0000 Subject: customer view tab for an external info page, RT#8903 --- FS/FS/Conf.pm | 13 +++++++++++++ FS/FS/Mason.pm | 1 + httemplate/misc/custom_link_proxy.cgi | 24 ++++++++++++++++++++++++ httemplate/view/cust_main.cgi | 6 ++++++ httemplate/view/cust_main/custom.html | 21 +++++++++++++++++++++ 5 files changed, 65 insertions(+) create mode 100644 httemplate/misc/custom_link_proxy.cgi create mode 100644 httemplate/view/cust_main/custom.html diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index ce8bd296e..fdb6e9a38 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -3891,6 +3891,19 @@ and customer address. Include units.', 'type' => 'checkbox', }, + { + 'key' => 'cust_main-custom_link', + 'section' => 'UI', + 'description' => 'URL to use as source for the "Custom" tab in the View Customer page. The custnum will be appended.', + 'type' => 'text', + }, + + { + 'key' => 'cust_main-custom_title', + 'section' => 'UI', + 'description' => 'Title for the "Custom" tab in the View Customer page.', + 'type' => 'text', + }, { key => "apacheroot", section => "deprecated", description => "DEPRECATED", type => "text" }, { key => "apachemachine", section => "deprecated", description => "DEPRECATED", type => "text" }, diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index 0f1415009..bcf727e3c 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -111,6 +111,7 @@ if ( -e $addl_handler_use_file ) { #selectlayers.html use Locale::Country; use Business::US::USPS::WebTools::AddressStandardization; + use LWP::UserAgent; use FS; use FS::UID qw( getotaker dbh datasrc driver_name ); use FS::Record qw( qsearch qsearchs fields dbdef diff --git a/httemplate/misc/custom_link_proxy.cgi b/httemplate/misc/custom_link_proxy.cgi new file mode 100644 index 000000000..e5934e4a6 --- /dev/null +++ b/httemplate/misc/custom_link_proxy.cgi @@ -0,0 +1,24 @@ +% if( $response->is_success ) { +<% $response->decoded_content %> +% } +% else { +<% $response->error_as_HTML %> +% } +<%init> + +my( $custnum ) = $cgi->param('custnum'); +my $cust_main = qsearchs('cust_main', { custnum => $custnum } ) + or die "custnum '$custnum' not found"; # just check for existence + +my $conf = new FS::Conf; +my $url = $conf->config('cust_main-custom_link') . $cust_main->custnum; +#warn $url; + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right('View customer'); + +my $ua = new LWP::UserAgent; +my $response = $ua->get($url); + diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi index f6bef43ba..0b6148da0 100755 --- a/httemplate/view/cust_main.cgi +++ b/httemplate/view/cust_main.cgi @@ -233,6 +233,10 @@ Comments <% include('cust_main/change_history.html', $cust_main ) %> % } +% if ( $view eq 'custom' ) { +<% include('cust_main/custom.html', $cust_main ) %> +% } + <% include('/elements/footer.html') %> <%init> @@ -273,6 +277,8 @@ $views{'Payment History'} = 'payment_history' unless $conf->config('payby-default' eq 'HIDE'); $views{'Change History'} = 'change_history' if $curuser->access_right('View customer history'); +$views{$conf->config('cust_main-custom_title') || 'Custom'} = 'custom' + if $conf->config('cust_main-custom_link'); $views{'Jumbo'} = 'jumbo'; my %viewname = reverse %views; diff --git a/httemplate/view/cust_main/custom.html b/httemplate/view/cust_main/custom.html new file mode 100644 index 000000000..8e2e07b75 --- /dev/null +++ b/httemplate/view/cust_main/custom.html @@ -0,0 +1,21 @@ + + +<%init> + +my( $cust_main ) = @_; + +my $proxyurl = $p.'/misc/custom_link_proxy.cgi?custnum='.$cust_main->custnum; + -- cgit v1.2.1 From dbab5e19dd56c2439a7c74c1dad5dcbd43e82865 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 3 Aug 2010 06:31:09 +0000 Subject: fix problem with expiring discounts, RT#6679 --- FS/FS/part_pkg/flat.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FS/FS/part_pkg/flat.pm b/FS/FS/part_pkg/flat.pm index 6db6eee24..cc2310503 100644 --- a/FS/FS/part_pkg/flat.pm +++ b/FS/FS/part_pkg/flat.pm @@ -192,7 +192,7 @@ sub calc_discount { my $months = $discount->months ? min( $chg_months, - $discount->months - $cust_pkg->months_used ) + $discount->months - $cust_pkg_discount->months_used ) : $chg_months; my $error = $cust_pkg_discount->increment_months_used($months); -- cgit v1.2.1 From 3af040458de2eb5825dc4a9718a1a289cedaa706 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 3 Aug 2010 18:00:22 +0000 Subject: spelling --- httemplate/search/cust_main.cgi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httemplate/search/cust_main.cgi b/httemplate/search/cust_main.cgi index e65dc7117..93519b740 100755 --- a/httemplate/search/cust_main.cgi +++ b/httemplate/search/cust_main.cgi @@ -270,7 +270,7 @@ % $cgi->param('offset', 0); % print qq!( hide!; % } -% print ' cancelled customers )'; +% print ' canceled customers )'; % } % % if ( $cgi->param('referral_custnum') ) { -- cgit v1.2.1 From e3a938e4a47e4426122932a4adfa944f83abdabe Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 3 Aug 2010 18:07:20 +0000 Subject: default config turns off svc_acct access number selectios --- conf/svc_acct-disable_access_number | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 conf/svc_acct-disable_access_number diff --git a/conf/svc_acct-disable_access_number b/conf/svc_acct-disable_access_number new file mode 100644 index 000000000..e69de29bb -- cgit v1.2.1 From dfb6ad5c96f3a18553ef4b0e81d51c6bc5d44c92 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 3 Aug 2010 23:12:06 +0000 Subject: don't allow addition of a domain rule template to itself, RT#7514 --- httemplate/browse/cgp_rule.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/httemplate/browse/cgp_rule.html b/httemplate/browse/cgp_rule.html index 8a427b828..8ea7571d0 100644 --- a/httemplate/browse/cgp_rule.html +++ b/httemplate/browse/cgp_rule.html @@ -44,11 +44,12 @@ my $html_init = if ( $part_svc->svcdb eq 'svc_domain' ) { - #areyousure for adding these? + #XXX add areyousure javscript confirmation for adding these foreach my $line ( FS::Conf->new->config('cgp_rule-domain_templates') ) { $line =~ /^\s*(\d+)\s+(.+)\s*$/ or next; my($t_svcnum, $t_name) = ( $1, $2 ); + next if $t_svcnum == $svcnum; $html_init .= qq!! ."Add $t_name rule
"; -- cgit v1.2.1 From f936f59edf460c72f4e4c4da4d701b99f4456890 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 3 Aug 2010 23:20:24 +0000 Subject: margin and padding css defined properly in px --- httemplate/elements/header.html | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/httemplate/elements/header.html b/httemplate/elements/header.html index 90ab0b71c..c83529e2b 100644 --- a/httemplate/elements/header.html +++ b/httemplate/elements/header.html @@ -15,7 +15,6 @@ Example: #old-style include( '/elements/header.html', 'Title', $menubar, $etc, $head); - %# @@ -43,8 +42,8 @@ Example: <% $head |n %> - STYLE="margin-top:0; margin-bottom:0; margin-left:0; margin-right:0"> - + STYLE="margin-top:0; margin-bottom:0; margin-left:0px; margin-right:0px"> +
+% foreach (@head) { + +% } + +% my $r=0; +% foreach my $row (@rows) { + +% foreach (@$row) { + +% } + +% $r++; +% } + +% foreach (@totals) { + +% } + +
freeside -- cgit v1.2.1 From f07fc98b146cdaa5861d766cc7c84ea0136f38ec Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 4 Aug 2010 01:15:52 +0000 Subject: better serialization on debugging data, RT#7514 --- FS/FS/part_export/communigate_pro.pm | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/FS/FS/part_export/communigate_pro.pm b/FS/FS/part_export/communigate_pro.pm index 3ac0dfd9c..76fd60815 100644 --- a/FS/FS/part_export/communigate_pro.pm +++ b/FS/FS/part_export/communigate_pro.pm @@ -732,7 +732,11 @@ sub export_getsettings_svc_domain { { my $value = $effective_settings->{$key}; if ( ref($value) eq 'ARRAY' ) { - $effective_settings->{$key} = join(' ', @$value); + $effective_settings->{$key} = + join(' ', map { ref($_) ? '['.join(', ', @$_).']' : $_ } @$value ); + } elsif ( ref($value) eq 'HASH' ) { + $effective_settings->{$key} = + join(', ', map { "$_:".$value->{$_} } keys %$value ); } else { #XXX warn "serializing ". ref($value). " for table display not yet handled"; @@ -821,7 +825,11 @@ sub export_getsettings_svc_acct { { my $value = $effective_settings->{$key}; if ( ref($value) eq 'ARRAY' ) { - $effective_settings->{$key} = join(' ', @$value); + $effective_settings->{$key} = + join(' ', map { ref($_) ? '['.join(', ', @$_).']' : $_ } @$value ); + } elsif ( ref($value) eq 'HASH' ) { + $effective_settings->{$key} = + join(', ', map { "$_:".$value->{$_} } keys %$value ); } else { #XXX warn "serializing ". ref($value). " for table display not yet handled"; -- cgit v1.2.1 From 6dcc4e277f46157a3df6c5d0b7ebde0fb848bb0b Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 4 Aug 2010 01:22:34 +0000 Subject: better serialization on debugging data, RT#7514 --- FS/FS/part_export/communigate_pro.pm | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/FS/FS/part_export/communigate_pro.pm b/FS/FS/part_export/communigate_pro.pm index 76fd60815..a3847bf2e 100644 --- a/FS/FS/part_export/communigate_pro.pm +++ b/FS/FS/part_export/communigate_pro.pm @@ -823,17 +823,7 @@ sub export_getsettings_svc_acct { foreach my $key ( grep ref($effective_settings->{$_}), keys %$effective_settings ) { - my $value = $effective_settings->{$key}; - if ( ref($value) eq 'ARRAY' ) { - $effective_settings->{$key} = - join(' ', map { ref($_) ? '['.join(', ', @$_).']' : $_ } @$value ); - } elsif ( ref($value) eq 'HASH' ) { - $effective_settings->{$key} = - join(', ', map { "$_:".$value->{$_} } keys %$value ); - } else { - #XXX - warn "serializing ". ref($value). " for table display not yet handled"; - } + $effective_settings->{$key} = _pretty( $effective_settings->{$key} ); } %{$settingsref} = %$effective_settings; @@ -843,6 +833,22 @@ sub export_getsettings_svc_acct { } +sub _pretty { + my $value = shift; + if ( ref($value) eq 'ARRAY' ) { + '['. join(' ', map { ref($_) ? _pretty($_) : $_ } @$value ). ']'; + } elsif ( ref($value) eq 'HASH' ) { + my $hv = $value->{$_}; + join(', ', map { my $v = $value->{$_}; + "$_:". ref($v) ? _pretty($v) : $_ + } + keys %$value + ); + } else { + warn "serializing ". ref($value). " for table display not yet handled"; + } +} + sub export_getsettings_svc_forward { my($self, $svc_forward, $settingsref, $defaultref ) = @_; -- cgit v1.2.1 From b80e90fc31364d7cad415d4c236c8429ec7c1e00 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 4 Aug 2010 01:23:05 +0000 Subject: better serialization on debugging data, RT#7514 --- FS/FS/part_export/communigate_pro.pm | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/FS/FS/part_export/communigate_pro.pm b/FS/FS/part_export/communigate_pro.pm index a3847bf2e..3d7d76ce3 100644 --- a/FS/FS/part_export/communigate_pro.pm +++ b/FS/FS/part_export/communigate_pro.pm @@ -730,17 +730,7 @@ sub export_getsettings_svc_domain { foreach my $key ( grep ref($effective_settings->{$_}), keys %$effective_settings ) { - my $value = $effective_settings->{$key}; - if ( ref($value) eq 'ARRAY' ) { - $effective_settings->{$key} = - join(' ', map { ref($_) ? '['.join(', ', @$_).']' : $_ } @$value ); - } elsif ( ref($value) eq 'HASH' ) { - $effective_settings->{$key} = - join(', ', map { "$_:".$value->{$_} } keys %$value ); - } else { - #XXX - warn "serializing ". ref($value). " for table display not yet handled"; - } + $effective_settings->{$key} = _pretty( $effective_settings->{$key} ); } %{$settingsref} = %$effective_settings; -- cgit v1.2.1 From 6f5d1fb4f6d927fed8171e93559e96644406729f Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 4 Aug 2010 01:26:32 +0000 Subject: better serialization on debugging data, RT#7514 --- FS/FS/part_export/communigate_pro.pm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/FS/FS/part_export/communigate_pro.pm b/FS/FS/part_export/communigate_pro.pm index 3d7d76ce3..86ae105b3 100644 --- a/FS/FS/part_export/communigate_pro.pm +++ b/FS/FS/part_export/communigate_pro.pm @@ -828,9 +828,8 @@ sub _pretty { if ( ref($value) eq 'ARRAY' ) { '['. join(' ', map { ref($_) ? _pretty($_) : $_ } @$value ). ']'; } elsif ( ref($value) eq 'HASH' ) { - my $hv = $value->{$_}; join(', ', map { my $v = $value->{$_}; - "$_:". ref($v) ? _pretty($v) : $_ + "$_:". ( ref($v) ? _pretty($v) : $_ ); } keys %$value ); -- cgit v1.2.1 From 01472ccb7460f5be007f11ae054c46844b3a7300 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 4 Aug 2010 01:29:09 +0000 Subject: better serialization on debugging data, RT#7514 --- FS/FS/part_export/communigate_pro.pm | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/FS/FS/part_export/communigate_pro.pm b/FS/FS/part_export/communigate_pro.pm index 86ae105b3..90e697705 100644 --- a/FS/FS/part_export/communigate_pro.pm +++ b/FS/FS/part_export/communigate_pro.pm @@ -828,11 +828,12 @@ sub _pretty { if ( ref($value) eq 'ARRAY' ) { '['. join(' ', map { ref($_) ? _pretty($_) : $_ } @$value ). ']'; } elsif ( ref($value) eq 'HASH' ) { - join(', ', map { my $v = $value->{$_}; - "$_:". ( ref($v) ? _pretty($v) : $_ ); - } - keys %$value - ); + '{'. join(', ', + map { my $v = $value->{$_}; + "$_:". ( ref($v) ? _pretty($v) : $_ ); + } + keys %$value + ). '}'; } else { warn "serializing ". ref($value). " for table display not yet handled"; } -- cgit v1.2.1 From df08772b72f5a9231afc90eb12591a62dfdfbf9e Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 4 Aug 2010 01:31:28 +0000 Subject: better serialization on debugging data, RT#7514 --- FS/FS/part_export/communigate_pro.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FS/FS/part_export/communigate_pro.pm b/FS/FS/part_export/communigate_pro.pm index 90e697705..2cad24467 100644 --- a/FS/FS/part_export/communigate_pro.pm +++ b/FS/FS/part_export/communigate_pro.pm @@ -830,7 +830,7 @@ sub _pretty { } elsif ( ref($value) eq 'HASH' ) { '{'. join(', ', map { my $v = $value->{$_}; - "$_:". ( ref($v) ? _pretty($v) : $_ ); + "$_:". ( ref($v) ? _pretty($v) : $v ); } keys %$value ). '}'; -- cgit v1.2.1 From 24970e7b3fde1d521f4039fb1dbd9d858ca96eed Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 4 Aug 2010 09:25:11 +0000 Subject: fix additional instance of rt/rt problem, RT#9280 --- rt/share/html/Admin/Elements/EditCustomFields | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rt/share/html/Admin/Elements/EditCustomFields b/rt/share/html/Admin/Elements/EditCustomFields index 0767e4ae4..10f254006 100755 --- a/rt/share/html/Admin/Elements/EditCustomFields +++ b/rt/share/html/Admin/Elements/EditCustomFields @@ -47,7 +47,9 @@ %# END BPS TAGGED BLOCK }}} <& /Elements/ListActions, actions => \@results &> -
+% my $path = $m->request_comp->path; +% $path =~ s(^/rt)(); #hacky, dunno why this happens + -- cgit v1.2.1 From 2a3f01ee52079e883b04b3f603dbdf9f339a034b Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 4 Aug 2010 09:34:01 +0000 Subject: fix additional instance of rt/rt problem, RT#9280 --- rt/FREESIDE_MODIFIED | 1 + 1 file changed, 1 insertion(+) diff --git a/rt/FREESIDE_MODIFIED b/rt/FREESIDE_MODIFIED index 71ec13508..ec551c818 100644 --- a/rt/FREESIDE_MODIFIED +++ b/rt/FREESIDE_MODIFIED @@ -18,6 +18,7 @@ lib/RT/Tickets_Overlay.pm #customfield date patch lib/RT/URI/freeside.pm lib/RT/URI/freeside/Internal.pm lib/RT/URI/freeside/XMLRPC.pm + share/html/Admin/Elements/EditCustomFields share/html/Admin/Users/Modify.html share/html/Elements/ColumnMap share/html/Elements/CollectionList -- cgit v1.2.1 From 543cb4d548e42826e377c4790e28bb730d7ddf66 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 4 Aug 2010 18:50:08 +0000 Subject: fix scalar_sql not to return empty string for zero --- FS/FS/Record.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/FS/FS/Record.pm b/FS/FS/Record.pm index cd5e2d4ca..44bc28d46 100644 --- a/FS/FS/Record.pm +++ b/FS/FS/Record.pm @@ -2817,7 +2817,8 @@ sub scalar_sql { my $sth = dbh->prepare($sql) or die dbh->errstr; $sth->execute or die "Unexpected error executing statement $sql: ". $sth->errstr; - $sth->fetchrow_arrayref->[0] || ''; + my $scalar = $sth->fetchrow_arrayref->[0]; + defined($scalar) ? $scalar : ''; } =back -- cgit v1.2.1 From 42a1267af992831cb8069835a18b8672a5f9afcb Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 4 Aug 2010 19:14:50 +0000 Subject: show cust_pay_pending attempted payments on customer payment history, RT#8815 --- FS/FS/Record.pm | 17 ++++---- FS/FS/cust_main.pm | 47 +++++++++++++++++++--- httemplate/view/cust_main/payment_history.html | 10 +++++ .../payment_history/attempted_payment.html | 41 +++++++++++++++++++ 4 files changed, 102 insertions(+), 13 deletions(-) create mode 100644 httemplate/view/cust_main/payment_history/attempted_payment.html diff --git a/FS/FS/Record.pm b/FS/FS/Record.pm index 44bc28d46..bc075dde9 100644 --- a/FS/FS/Record.pm +++ b/FS/FS/Record.pm @@ -2801,21 +2801,22 @@ sub h_date { $h ? $h->history_date : ''; } -=item scalar_sql SQL +=item scalar_sql SQL [ PLACEHOLDER, ... ] -A class method with a propensity for becoming an instance method. This -method executes the sql statement represented by SQL and returns a scalar -representing the result. Don't ask for rows -- you get the first column -of the first row. Don't give me bogus SQL or I'll die on you. +A class or object method. Executes the sql statement represented by SQL and +returns a scalar representing the result: the first column of the first row. -Returns an empty string in the event of no rows. +Dies on bogus SQL. Returns an empty string if no row is returned. + +Typically used for statments which return a single value such as "SELECT +COUNT(*) FROM table WHERE something" OR "SELECT column FROM table WHERE key = ?" =cut sub scalar_sql { - my($self, $sql ) = ( shift, shift ); + my($self, $sql) = (shift, shift); my $sth = dbh->prepare($sql) or die dbh->errstr; - $sth->execute + $sth->execute(@_) or die "Unexpected error executing statement $sql: ". $sth->errstr; my $scalar = $sth->fetchrow_arrayref->[0]; defined($scalar) ? $scalar : ''; diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 47eccd7f8..b1bf1791c 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -7097,6 +7097,26 @@ sub cust_pay_pending { ); } +=item cust_pay_pending_attempt + +Returns all payment attempts / declined payments for this customer, as pending +payments objects (see L), with status "done" but without +a corresponding payment (see L). + +=cut + +sub cust_pay_pending_attempt { + my $self = shift; + return $self->num_cust_pay_pending_attempt unless wantarray; + sort { $a->_date <=> $b->_date } + qsearch( 'cust_pay_pending', { + 'custnum' => $self->custnum, + 'status' => 'done', + 'paynum' => '', + }, + ); +} + =item num_cust_pay_pending Returns the number of pending payments (see L) for this @@ -7107,11 +7127,28 @@ cust_pay_pending method is used in a scalar context. sub num_cust_pay_pending { my $self = shift; - my $sql = " SELECT COUNT(*) FROM cust_pay_pending ". - " WHERE custnum = ? AND status != 'done' "; - my $sth = dbh->prepare($sql) or die dbh->errstr; - $sth->execute($self->custnum) or die $sth->errstr; - $sth->fetchrow_arrayref->[0]; + $self->scalar_sql( + " SELECT COUNT(*) FROM cust_pay_pending ". + " WHERE custnum = ? AND status != 'done' ", + $self->custnum + ); +} + +=item num_cust_pay_pending_attempt + +Returns the number of pending payments (see L) for this +customer, with status "done" but without a corresp. Also called automatically when the +cust_pay_pending method is used in a scalar context. + +=cut + +sub num_cust_pay_pending_attempt { + my $self = shift; + $self->scalar_sql( + " SELECT COUNT(*) FROM cust_pay_pending ". + " WHERE custnum = ? AND status = 'done' AND paynum IS NULL", + $self->custnum + ); } =item cust_refund diff --git a/httemplate/view/cust_main/payment_history.html b/httemplate/view/cust_main/payment_history.html index 0dc4c41d5..60d33ac23 100644 --- a/httemplate/view/cust_main/payment_history.html +++ b/httemplate/view/cust_main/payment_history.html @@ -422,6 +422,16 @@ foreach my $cust_pay_void ($cust_main->cust_pay_void) { } +#declined payments +foreach my $cust_pay_pending ($cust_main->cust_pay_pending_attempt) { + push @history, { + 'date' => $cust_pay_pending->_date, + 'desc' => include('payment_history/attempted_payment.html', $cust_pay_pending, %opt ), + 'void_payment' => $cust_pay_pending->paid, #?? + #'target' => $target, #XXX + }; +} + #credits (some false laziness w/payments) foreach my $cust_credit ($cust_main->cust_credit) { push @history, { diff --git a/httemplate/view/cust_main/payment_history/attempted_payment.html b/httemplate/view/cust_main/payment_history/attempted_payment.html new file mode 100644 index 000000000..554aa737d --- /dev/null +++ b/httemplate/view/cust_main/payment_history/attempted_payment.html @@ -0,0 +1,41 @@ +Payment attempt <% $info |h %> +<%init> + +my( $cust_pay_pending, %opt ) = @_; + +my $date_format = $opt{'date_format'} || '%m/%d/%Y'; + +my $curuser = $FS::CurrentUser::CurrentUser; + +my $payby = $cust_pay_pending->payby; + +my $payinfo; +if ( $payby eq 'CARD' ) { + $payinfo = $cust_pay_pending->paymask; +} elsif ( $payby eq 'CHEK' ) { + my( $account, $aba ) = split('@', $cust_pay_pending->paymask ); + $payinfo = "ABA $aba, Acct #$account"; +} else { + $payinfo = $cust_pay_pending->payinfo; +} + +$payby =~ s/^BILL$/Check #/ if $payinfo; +$payby =~ s/^CHEK$/Electronic check /; +$payby =~ s/^PREP$/Prepaid card /; +$payby =~ s/^CARD$/Credit card #/; +$payby =~ s/^COMP$/Complimentary by /; +$payby =~ s/^CASH$/Cash/; +$payby =~ s/^WEST$/Western Union/; +$payby =~ s/^MCRD$/Manual credit card/; +$payby =~ s/^BILL$//; +my $info = $payby ? "($payby$payinfo)" : ''; + +if ( $opt{'pkg-balances'} && $cust_pay_pending->pkgnum ) { + my $cust_pkg = qsearchs('cust_pkg', { 'pkgnum'=>$cust_pay_pending->pkgnum } ); + $info .= ' for '. $cust_pkg->pkg_label_long; +} + +$info .= ': '. $cust_pay_pending->statustext + if length($cust_pay_pending->statustext); + + -- cgit v1.2.1 From 824b97e97e4e5ee914a4c936815a4413def71a4f Mon Sep 17 00:00:00 2001 From: mark Date: Thu, 5 Aug 2010 00:24:57 +0000 Subject: error message in decline templates, RT#9507 --- FS/FS/cust_main.pm | 5 ++++- FS/FS/msg_template.pm | 25 +++++++++++++++++++++++-- httemplate/edit/msg_template.html | 2 ++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index b1bf1791c..5898a6a07 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -5116,8 +5116,11 @@ sub _realtime_bop_result { my $msgnum = $conf->config('decline_msgnum', $self->agentnum); my $error = ''; if ( $msgnum ) { + # include the raw error message in the transaction state + $cust_pay_pending->setfield('error', $transaction->error_message); my $msg_template = qsearchs('msg_template', { msgnum => $msgnum }); - $error = $msg_template->send( 'cust_main' => $self ); + $error = $msg_template->send( 'cust_main' => $self, + 'object' => $cust_pay_pending ); } else { #!$msgnum diff --git a/FS/FS/msg_template.pm b/FS/FS/msg_template.pm index 7d507f4fb..d1db17dbc 100644 --- a/FS/FS/msg_template.pm +++ b/FS/FS/msg_template.pm @@ -166,7 +166,7 @@ Customer object (required). =item object Additional context object (currently, can be a cust_main, cust_pkg, -cust_bill, svc_acct, or cust_pay object). +cust_bill, svc_acct, cust_pay, or cust_pay_pending object). =back @@ -324,6 +324,9 @@ sub substitutions { [ company_name => sub { $conf->config('company_name', shift->agentnum) } ], + [ company_address => sub { + $conf->config('company_address', shift->agentnum) + } ], ], # next_bill_date 'cust_pkg' => [qw( @@ -351,11 +354,13 @@ sub substitutions { )], #XXX not really thinking about cust_bill substitutions quite yet + # for welcome and limit warning messages 'svc_acct' => [qw( username ), [ password => sub { shift->getfield('_password') } ], - ], # for welcome messages + ], + # for payment receipts 'cust_pay' => [qw( paynum _date @@ -370,6 +375,22 @@ sub substitutions { $cust_pay->paymask : $cust_pay->decrypt($cust_pay->payinfo) } ], ], + # for payment decline messages + # try to support all cust_pay fields + # 'error' is a special case, it contains the raw error from the gateway + 'cust_pay_pending' => [qw( + _date + error + ), + [ paid => sub { sprintf("%.2f", shift->paid) } ], + [ payby => sub { FS::payby->shortname(shift->payby) } ], + [ date => sub { time2str("%a %B %o, %Y", shift->_date) } ], + [ payinfo => sub { + my $pending = shift; + ($pending->payby eq 'CARD' || $pending->payby eq 'CHEK') ? + $pending->paymask : $pending->decrypt($pending->payinfo) + } ], + ], }; } diff --git a/httemplate/edit/msg_template.html b/httemplate/edit/msg_template.html index 67eae185d..c38c40e4a 100644 --- a/httemplate/edit/msg_template.html +++ b/httemplate/edit/msg_template.html @@ -51,6 +51,7 @@ my %substitutions = ( '$ucfirst_cust_status' => 'Status, capitalized', '$cust_statuscolor' => 'Status color code', '$company_name' => 'Our company name', + '$company_address'=> 'Our company address', ], 'contact' => [ # duplicate this for shipping '$name' => 'Company and contact name', @@ -101,6 +102,7 @@ my %substitutions = ( '$payby' => 'Payment method', '$date' => 'Payment date', '$payinfo' => 'Card/account# (masked)', + '$error' => 'Decline reason', ], ); my @c = @{ $substitutions{'contact'} }; -- cgit v1.2.1 From b90c466e6b0d4477855ff3ff7b8f40937b129364 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 5 Aug 2010 04:17:07 +0000 Subject: add options to only process account records from a particular realm and to ignore sessions that span billing periods RT8082 --- FS/FS/cust_svc.pm | 43 +++++++++++++++++--- FS/FS/part_export/sqlradius.pm | 90 ++++++++++++++++++++++++++---------------- 2 files changed, 95 insertions(+), 38 deletions(-) diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm index c0766e582..7b866fad3 100644 --- a/FS/FS/cust_svc.pm +++ b/FS/FS/cust_svc.pm @@ -539,15 +539,24 @@ sub seconds_since_sqlradacct { warn "$mes finding closed sessions completely within the given range\n" if $DEBUG; + my $realm = ''; + my $realmparam = ''; + if ($part_export->option('process_single_realm')) { + $realm = 'AND Realm = ?'; + $realmparam = $part_export->option('realm'); + } + my $sth = $dbh->prepare("SELECT SUM(acctsessiontime) FROM radacct WHERE UserName = ? + $realm AND $str2time AcctStartTime) >= ? AND $str2time AcctStopTime ) < ? AND $str2time AcctStopTime ) > 0 AND AcctStopTime IS NOT NULL" ) or die $dbh->errstr; - $sth->execute($username, $start, $end) or die $sth->errstr; + $sth->execute($username, ($realm ? $realmparam : ()), $start, $end) + or die $sth->errstr; my $regular = $sth->fetchrow_arrayref->[0]; warn "$mes finding open sessions which start in the range\n" @@ -557,13 +566,19 @@ sub seconds_since_sqlradacct { $query = "SELECT SUM( ? - $str2time AcctStartTime ) ) FROM radacct WHERE UserName = ? + $realm AND $str2time AcctStartTime ) >= ? AND $str2time AcctStartTime ) < ? AND ( ? - $str2time AcctStartTime ) ) < 86400 AND ( $str2time AcctStopTime ) = 0 OR AcctStopTime IS NULL )"; $sth = $dbh->prepare($query) or die $dbh->errstr; - $sth->execute($end, $username, $start, $end, $end) + $sth->execute( $end, + $username, + ($realm ? $realmparam : ()), + $start, + $end, + $end ) or die $sth->errstr. " executing query $query"; my $start_during = $sth->fetchrow_arrayref->[0]; @@ -574,13 +589,20 @@ sub seconds_since_sqlradacct { $sth = $dbh->prepare("SELECT SUM( $str2time AcctStopTime ) - ? ) FROM radacct WHERE UserName = ? + $realm AND $str2time AcctStartTime ) < ? AND $str2time AcctStopTime ) >= ? AND $str2time AcctStopTime ) < ? AND $str2time AcctStopTime ) > 0 AND AcctStopTime IS NOT NULL" ) or die $dbh->errstr; - $sth->execute($start, $username, $start, $start, $end ) or die $sth->errstr; + $sth->execute( $start, + $username, + ($realm ? $realmparam : ()), + $start, + $start, + $end ) + or die $sth->errstr; my $end_during = $sth->fetchrow_arrayref->[0]; warn "$mes finding closed sessions which start before the range but stop after\n" @@ -591,13 +613,15 @@ sub seconds_since_sqlradacct { $sth = $dbh->prepare("SELECT COUNT(*) FROM radacct WHERE UserName = ? + $realm AND $str2time AcctStartTime ) < ? AND ( $str2time AcctStopTime ) >= ? )" # OR AcctStopTime = 0 # OR AcctStopTime IS NULL )" ) or die $dbh->errstr; - $sth->execute($username, $start, $end ) or die $sth->errstr; + $sth->execute($username, ($realm ? $realmparam : ()), $start, $end ) + or die $sth->errstr; my $entire_range = ($end-$start) * $sth->fetchrow_arrayref->[0]; $seconds += $regular + $end_during + $start_during + $entire_range; @@ -658,14 +682,23 @@ sub attribute_since_sqlradacct { warn "$mes SUMing $attrib sessions\n" if $DEBUG; + my $realm = ''; + my $realmparam = ''; + if ($part_export->option('process_single_realm')) { + $realm = 'AND Realm = ?'; + $realmparam = $part_export->option('realm'); + } + my $sth = $dbh->prepare("SELECT SUM($attrib) FROM radacct WHERE UserName = ? + $realm AND $str2time AcctStopTime ) >= ? AND $str2time AcctStopTime ) < ? AND AcctStopTime IS NOT NULL" ) or die $dbh->errstr; - $sth->execute($username, $start, $end) or die $sth->errstr; + $sth->execute($username, ($realm ? $realmparam : ()), $start, $end) + or die $sth->errstr; my $row = $sth->fetchrow_arrayref; $sum += $row->[0] if defined($row->[0]); diff --git a/FS/FS/part_export/sqlradius.pm b/FS/FS/part_export/sqlradius.pm index 4f67ac6c3..d8c5e0424 100644 --- a/FS/FS/part_export/sqlradius.pm +++ b/FS/FS/part_export/sqlradius.pm @@ -22,6 +22,15 @@ tie %options, 'Tie::IxHash', type => 'checkbox', label => 'Ignore accounting records from this database' }, + 'process_single_realm' => { + type => 'checkbox', + label => 'Only process one realm of accounting records', + }, + 'realm' => { label => 'The realm of of accounting records to be processed' }, + 'ignore_long_sessions' => { + type => 'checkbox', + label => 'Ignore sessions which span billing periods', + }, 'hide_ip' => { type => 'checkbox', label => 'Hide IP address information on session reports', @@ -617,7 +626,7 @@ sub usage_sessions { if ( $svc_acct ) { my $username = $self->export_username($svc_acct); - if ( $svc_acct =~ /^([^@]+)\@([^@]+)$/ ) { + if ( $username =~ /^([^@]+)\@([^@]+)$/ ) { push @where, '( UserName = ? OR ( UserName = ? AND Realm = ? ) )'; push @param, $username, $1, $2; } else { @@ -626,6 +635,11 @@ sub usage_sessions { } } + if ($self->option('process_single_realm')) { + push @where, 'Realm = ?'; + push @param, $self->option('realm'); + } + if ( length($ip) ) { push @where, ' FramedIPAddress = ?'; push @param, $ip; @@ -719,43 +733,53 @@ sub update_svc { my $oldAutoCommit = $FS::UID::AutoCommit; # can't undo side effects, but at local $FS::UID::AutoCommit = 0; # least we can avoid over counting - my @svc_acct = - grep { qsearch( 'export_svc', { 'exportnum' => $self->exportnum, - 'svcpart' => $_->cust_svc->svcpart, } ) - } - qsearch( 'svc_acct', - { 'username' => $UserName }, - '', - $extra_sql - ); - + my $status = 'skipped'; my $errinfo = "for RADIUS detail RadAcctID $RadAcctId ". "(UserName $UserName, Realm $Realm)"; - my $status = 'skipped'; - if ( !@svc_acct ) { - warn "WARNING: no svc_acct record found $errinfo - skipping\n"; - } elsif ( scalar(@svc_acct) > 1 ) { - warn "WARNING: multiple svc_acct records found $errinfo - skipping\n"; - } else { - - my $svc_acct = $svc_acct[0]; - warn "found svc_acct ". $svc_acct->svcnum. " $errinfo\n" if $DEBUG; - $svc_acct->last_login($AcctStartTime); - $svc_acct->last_logout($AcctStopTime); - - my $cust_pkg = $svc_acct->cust_svc->cust_pkg; - if ( $cust_pkg && $AcctStopTime < ( $cust_pkg->last_bill - || $cust_pkg->setup ) ) { - $status = 'skipped (too old)'; + if ( $self->option('process_single_realm') + && $self->option('realm') ne $Realm ) + { + warn "WARNING: wrong realm $errinfo - skipping\n" if $DEBUG; + } else { + my @svc_acct = + grep { qsearch( 'export_svc', { 'exportnum' => $self->exportnum, + 'svcpart' => $_->cust_svc->svcpart, } ) + } + qsearch( 'svc_acct', + { 'username' => $UserName }, + '', + $extra_sql + ); + + if ( !@svc_acct ) { + warn "WARNING: no svc_acct record found $errinfo - skipping\n"; + } elsif ( scalar(@svc_acct) > 1 ) { + warn "WARNING: multiple svc_acct records found $errinfo - skipping\n"; } else { - my @st; - push @st, _try_decrement($svc_acct, 'seconds', $AcctSessionTime ); - push @st, _try_decrement($svc_acct, 'upbytes', $AcctInputOctets ); - push @st, _try_decrement($svc_acct, 'downbytes', $AcctOutputOctets ); - push @st, _try_decrement($svc_acct, 'totalbytes', $AcctInputOctets + + my $svc_acct = $svc_acct[0]; + warn "found svc_acct ". $svc_acct->svcnum. " $errinfo\n" if $DEBUG; + + $svc_acct->last_login($AcctStartTime); + $svc_acct->last_logout($AcctStopTime); + + my $session_time = $AcctStopTime; + $session_time = $AcctStartTime if $self->option('ignore_long_sessions'); + + my $cust_pkg = $svc_acct->cust_svc->cust_pkg; + if ( $cust_pkg && $session_time < ( $cust_pkg->last_bill + || $cust_pkg->setup ) ) { + $status = 'skipped (too old)'; + } else { + my @st; + push @st, _try_decrement($svc_acct, 'seconds', $AcctSessionTime); + push @st, _try_decrement($svc_acct, 'upbytes', $AcctInputOctets); + push @st, _try_decrement($svc_acct, 'downbytes', $AcctOutputOctets); + push @st, _try_decrement($svc_acct, 'totalbytes', $AcctInputOctets + $AcctOutputOctets); - $status=join(' ', @st); + $status=join(' ', @st); + } } } -- cgit v1.2.1 From b93983d6758cd67b7bcb6c4118344981d8bb6e8d Mon Sep 17 00:00:00 2001 From: mark Date: Thu, 5 Aug 2010 20:10:42 +0000 Subject: Package summary report, RT#8461 --- httemplate/elements/menu.html | 1 + httemplate/search/cust_pkg_summary.cgi | 87 +++++++++++++++++++++++++++++++++ httemplate/search/cust_pkg_summary.html | 24 +++++++++ 3 files changed, 112 insertions(+) create mode 100644 httemplate/search/cust_pkg_summary.cgi create mode 100644 httemplate/search/cust_pkg_summary.html diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html index a5bcdeb19..2404ef291 100644 --- a/httemplate/elements/menu.html +++ b/httemplate/elements/menu.html @@ -207,6 +207,7 @@ if ( $curuser->access_right('Financial reports') ) { $report_packages{'separator2'} = ''; } $report_packages{'All customer packages'} = [ $fsurl.'search/cust_pkg.cgi?pkgnum', 'List all customer packages', ]; +$report_packages{'Package summary'} = [ $fsurl.'search/cust_pkg_summary.html', 'Show package sales summary', ]; $report_packages{'Suspended customer packages'} = [ $fsurl.'search/cust_pkg.cgi?magic=suspended', 'List suspended packages' ]; $report_packages{'Customer packages with unconfigured services'} = [ $fsurl.'search/cust_pkg.cgi?APKG_pkgnum', 'List packages which have provisionable services' ]; $report_packages{'FCC Form 477 packages'} = [ $fsurl.'search/report_477.html', 'Summarize packages by census tract for particular types' ] diff --git a/httemplate/search/cust_pkg_summary.cgi b/httemplate/search/cust_pkg_summary.cgi new file mode 100644 index 000000000..fc71c81d8 --- /dev/null +++ b/httemplate/search/cust_pkg_summary.cgi @@ -0,0 +1,87 @@ +<% include('/elements/header.html', $title) %> +<% include('/elements/table-grid.html') %> +
<% $_ %>
<% $_ %>
<% $_ %>
+<%init> +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('List packages'); + +my $title = 'Package Summary Report'; +my ($begin, $end) = FS::UI::Web::parse_beginning_ending($cgi); +if($begin > 0) { + $title = "$title (". + $cgi->param('beginning').' - '.$cgi->param('ending').')'; +} + +my @h_sql = FS::h_cust_pkg->sql_h_search($end); + +my ($end_sql, $addl_from) = @h_sql[1,3]; +$end_sql =~ s/ORDER BY.*//; # breaks aggregate queries + +my $begin_sql = $end_sql; +$begin_sql =~ s/$end/$begin/g; + +my $active_sql = FS::cust_pkg->active_sql; +my $suspended_sql = FS::cust_pkg->suspended_sql; +my @conds = ( + # SQL WHERE clauses for each column of the table. + " $begin_sql AND ($active_sql OR $suspended_sql)", + '', + " $end_sql AND ($active_sql OR $suspended_sql)", + " $end_sql AND $active_sql", + " $end_sql AND $suspended_sql", + ); + +$_ =~ s/\bcust_pkg/maintable/g foreach @conds; + +my @head = ('Package', 'Before Period', 'Sales', 'Total', 'Active', 'Suspended'); +my @rows = (); +my @totals = ('Total', 0, 0, 0, 0, 0); + +if( !$begin ) { + splice @conds, 1, 1; + splice @head, 1, 1; +} + +foreach my $part_pkg (qsearch('part_pkg', {} )) { + my @row = (); + next if !$part_pkg->freq; # exclude one-time packages + push @row, $part_pkg->pkg; + my $i=1; + foreach my $cond (@conds) { + if($cond) { + my $result = qsearchs({ + 'table' => 'h_cust_pkg', + 'hashref' => {}, + 'select' => 'count(*)', + 'addl_from' => $addl_from, + 'extra_sql' => 'WHERE pkgpart = '.$part_pkg->pkgpart.$cond, + }); + $row[$i] = $result->getfield('count'); + $totals[$i] += $row[$i]; + } + $i++; + } + $row[2] = $row[3]-$row[1]; + $totals[2] += $row[2]; + push @rows, \@row; +} + diff --git a/httemplate/search/cust_pkg_summary.html b/httemplate/search/cust_pkg_summary.html new file mode 100644 index 000000000..a0ef47210 --- /dev/null +++ b/httemplate/search/cust_pkg_summary.html @@ -0,0 +1,24 @@ +<% include( '/elements/header.html', 'Package Summary Report' ) %> + + + + + + + + + + <% include ('/elements/tr-input-beginning_ending.html') %> + +
+ Search options +
+ +
+ + + + +<% include('/elements/footer.html') %> +<%init> + -- cgit v1.2.1 From 0715eb639658bfde2c21c39cd5ccaf4bf22b18d4 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 6 Aug 2010 00:45:29 +0000 Subject: communigate account rules: vacation & redirect all, RT#7514 --- httemplate/edit/cgp_rule-redirect_all.html | 52 +++++++++++++++++---- httemplate/edit/cgp_rule-vacation.html | 45 ++++++++++++------ httemplate/edit/process/cgp_rule-redirect_all.html | 24 ++++++++++ httemplate/edit/process/cgp_rule-simplified.html | 53 ++++++++++++++++++++++ httemplate/edit/process/cgp_rule-vacation.html | 29 ++++++++++++ httemplate/view/svc_acct/communigate.html | 21 ++++++--- 6 files changed, 194 insertions(+), 30 deletions(-) create mode 100644 httemplate/edit/process/cgp_rule-redirect_all.html create mode 100644 httemplate/edit/process/cgp_rule-simplified.html create mode 100644 httemplate/edit/process/cgp_rule-vacation.html diff --git a/httemplate/edit/cgp_rule-redirect_all.html b/httemplate/edit/cgp_rule-redirect_all.html index 898eef8fc..c8c9e010c 100644 --- a/httemplate/edit/cgp_rule-redirect_all.html +++ b/httemplate/edit/cgp_rule-redirect_all.html @@ -1,37 +1,49 @@ <% include('/elements/header-popup.html', 'Redirect all mail') %> +<% include('/elements/error.html') %> +
-%# XXX upstream Redirect 1 + <% ntable("#cccccc", 2) %> Redirect all mail to - + <% include('/elements/tr-checkbox.html', - 'name' => 'RedirKeep', + 'field' => 'RedirKeep', 'label' => 'Keep a copy', 'value' => 1, - 'curr_value' => '', #XXX + 'curr_value' => ( $cgi->param('error') + ? scalar($cgi->param('RedirKeep')) + : ( ($redir_keep || !$cgp_rule) ? '' : 1 ) + ), ) %> <% include('/elements/tr-checkbox.html', - 'name' => 'RedirHuman', + 'field' => 'RedirHuman', 'label' => 'Do not redirect automatic messages', 'value' => 1, - 'curr_value' => '', #XXX + 'curr_value' => ( $cgi->param('error') + ? scalar($cgi->param('RedirHuman')) + : ( $redir_human ? 1 : '' ) + ), ) %> <% include('/elements/tr-checkbox.html', - 'name' => 'KeepToAndCc', + 'field' => 'KeepToAndCc', 'label' => 'Preserve To/Cc fields', 'value' => 1, - 'curr_value' => '', #XXX + 'curr_value' => ( $cgi->param('error') + ? scalar($cgi->param('KeepToAndCc')) + : ( $mirror_or_redir && + $mirror_or_redir->action eq 'Mirror To' ) + ), ) %> @@ -39,7 +51,6 @@
-%#XXX Add/Edit
@@ -52,6 +63,27 @@ my %opt = @_; my $svc_acct = qsearchs('svc_acct', { 'svcnum' => $opt{'svcnum'} } ) or die "unknown svcnum"; -#XXX look for existing redirect all rule +#look for existing rule +my $cgp_rule = qsearchs('cgp_rule', { 'svcnum' => $svc_acct->svcnum, + 'name' => '#Redirect' + } + ); + +my( $redir_human, $mirror_or_redir, $redir_keep ) = ( '', '', '' ); +if ( $cgp_rule ) { + $redir_human = qsearchs('cgp_rule_condition', { + 'rulenum' => $cgp_rule->rulenum, + 'conditionname' => 'Human Generated', + }); + $mirror_or_redir = qsearchs({ + 'table' => 'cgp_rule_action', + 'hashref' => { 'rulenum' => $cgp_rule->rulenum, }, + 'extra_sql' => " AND action IN ('Mirror To', 'Redirect To') ", + }); + $redir_keep = qsearchs('cgp_rule_action', { + 'rulenum' => $cgp_rule->rulenum, + 'action' => 'Discard', + }); +} diff --git a/httemplate/edit/cgp_rule-vacation.html b/httemplate/edit/cgp_rule-vacation.html index efdc5417e..8c288852b 100644 --- a/httemplate/edit/cgp_rule-vacation.html +++ b/httemplate/edit/cgp_rule-vacation.html @@ -1,35 +1,35 @@ <% include('/elements/header-popup.html', 'Vacation rule') %> +<% include('/elements/error.html') %> +
-%# XXX upstream Vacation 1 + <% ntable("#cccccc", 2) %> Vacation message - + <% include('/elements/tr-input-date-field.html', { - 'label' => 'Ends', - 'name' => 'vacationTill', - 'value' => '', #XXX + 'label' => 'Ends', + 'name' => 'vacationTill', + 'format' => '%d %b %Y', + 'value' => ( $cgi->param('error') + ? scalar($cgi->param('vacationTill')) + : ( $curr_date ? $curr_date->params : '' ) + ), }) %> -%# XXX upstream: -%# VacationTill 1 -%# vacationDay -%# vacationMonth -%# vacationYear -%#XXX Clear 'Replied Addresses' List +%#Clear 'Replied Addresses' List ?
- -%#XXX Add/Edit +
@@ -42,6 +42,23 @@ my %opt = @_; my $svc_acct = qsearchs('svc_acct', { 'svcnum' => $opt{'svcnum'} } ) or die "unknown svcnum"; -#XXX look for existing vacation rule +#look for existing rule +my $cgp_rule = qsearchs('cgp_rule', { 'svcnum' => $svc_acct->svcnum, + 'name' => '#Vacation' + } + ); + +my( $curr_date, $reply_with ) = ( '', '' ); +if ( $cgp_rule ) { + $curr_date = qsearchs('cgp_rule_condition', { + 'rulenum' => $cgp_rule->rulenum, + 'conditionname' => 'Current Date', + 'op' => 'less than', + }); + $reply_with = qsearchs('cgp_rule_action', { + 'rulenum' => $cgp_rule->rulenum, + 'action' => 'Reply with', + }); +} diff --git a/httemplate/edit/process/cgp_rule-redirect_all.html b/httemplate/edit/process/cgp_rule-redirect_all.html new file mode 100644 index 000000000..162d857c2 --- /dev/null +++ b/httemplate/edit/process/cgp_rule-redirect_all.html @@ -0,0 +1,24 @@ +<% include('cgp_rule-simplified.html', + 'name' => '#Redirect', + 'priority' => 1, + 'redirect' => 'cgp_rule-redirect_all.html', + 'conditions' => [ + ( $cgi->param('RedirHuman') + ? { conditionname => 'Human Generated', } + : () + ), + ], + 'actions' => [ + { action => ( $cgi->param('KeepToAndCc') + ? 'Mirror To' + : 'Redirect To' + ), + params => scalar($cgi->param('RedirectText')), + }, + ( $cgi->param('RedirKeep') + ? () + : ( { 'action' => 'Discard' } ) + ), + ], + ) +%> diff --git a/httemplate/edit/process/cgp_rule-simplified.html b/httemplate/edit/process/cgp_rule-simplified.html new file mode 100644 index 000000000..60769d4e6 --- /dev/null +++ b/httemplate/edit/process/cgp_rule-simplified.html @@ -0,0 +1,53 @@ +% if ( $error ) { #redirect back to edit... +% $cgi->param('error', $error); +<% $cgi->redirect(popurl(3).'edit/'.$opt{'redirect'}.'?'. $cgi->query_string) %> +% } else { #success XXX better msg talking about vacation vs. redirect all + <% include('/elements/header-popup.html', 'Rule updated') %> + + + + +% } +<%init> + +my %opt = @_; + +my %hash = ( + 'svcnum' => scalar($cgi->param('svcnum')), + 'name' => $opt{'name'}, +); + +my $cgp_rule = qsearchs('cgp_rule', \%hash); + +my $error = ''; +if ( $cgp_rule ) { #updating + $error = $cgp_rule->delete; +} + +$cgp_rule = new FS::cgp_rule { %hash, 'priority' => $opt{'priority'} }; +$error ||= $cgp_rule->insert; + +foreach my $condition ( @{ $opt{'conditions'} } ) { + my $cgp_rule_condition = new FS::cgp_rule_condition { + %$condition, + 'rulenum' => $cgp_rule->rulenum, + }; + $error ||= $cgp_rule_condition->insert; +} + +foreach my $action ( @{ $opt{'actions'} } ) { + my $cgp_rule_action = new FS::cgp_rule_action { + %$action, + 'rulenum' => $cgp_rule->rulenum, + }; + $error ||= $cgp_rule_action->insert; +} + +unless ( $error ) { + my $export_error = $cgp_rule->svc_export; + die $export_error if $export_error; #error handling sucks wrt this... shouldn't happen though +} + + diff --git a/httemplate/edit/process/cgp_rule-vacation.html b/httemplate/edit/process/cgp_rule-vacation.html new file mode 100644 index 000000000..f10d72b73 --- /dev/null +++ b/httemplate/edit/process/cgp_rule-vacation.html @@ -0,0 +1,29 @@ +<% include('cgp_rule-simplified.html', + 'name' => '#Vacation', + 'priority' => 2, + 'redirect' => 'cgp_rule-vacation.html', + 'conditions' => [ + { conditionname => 'Human Generated', }, + { conditionname => 'From', + op => 'not in', + params => '#RepliedAddresses', + }, + ( $cgi->param('VacationTill') + ? ( { conditionname => 'Current Date', + op => 'less than', #is less? + params => scalar($cgi->param('VacationTill')), + } + ) + : () + ), + ], + 'actions' => [ + { action => 'Reply with', + params => scalar($cgi->param('VacationText')), + }, + { action => "Remember 'From' in", + params => 'RepliedAddresses', + }, + ], + ) +%> diff --git a/httemplate/view/svc_acct/communigate.html b/httemplate/view/svc_acct/communigate.html index 0f090fdb9..870744a87 100644 --- a/httemplate/view/svc_acct/communigate.html +++ b/httemplate/view/svc_acct/communigate.html @@ -54,17 +54,16 @@ value=>$svc_acct->cgp_sendmdnmode ) %> %# vacation message -%#XXX finish me... do we need to search for specific rules -%# (and hide them?) need to see what CGP gives back after we've added a rule <% include('/elements/init_overlib.html') %> Vacation message + <% $vacation_rule ? 'Active' : '' %> <% include('/elements/popup_link.html', 'action' => $p.'edit/cgp_rule-vacation.html?'. 'svcnum='. $svc_acct->svcnum, - 'label' => '(add)', #XXX (edit) + 'label' => $vacation_rule ? '(edit)' : '(add)', 'actionlabel' => 'Vacation message', 'width' => 600, 'height' => 300, @@ -75,15 +74,15 @@ %# redirect all mail -%#XXX finish me... Redirect all mail + <% $redirect_rule ? 'Active' : '' %> <% include('/elements/popup_link.html', 'action' => $p.'edit/cgp_rule-redirect_all.html?'. 'svcnum='. $svc_acct->svcnum, - 'label' => '(add)', #XXX (edit) + 'label' => $redirect_rule ? '(edit)' : '(add)', 'actionlabel' => 'Redirect all mail', 'width' => 763, #'height' @@ -110,6 +109,16 @@ my $svc_acct = $opt{'svc_acct'}; #my $part_svc = $opt{'part_svc'}; my $rule_link = qq(View/edit mail rules'; + $svc_acct->svcnum. '">View/edit mail rules'; #'dum vim + +my $vacation_rule = qsearchs('cgp_rule', { 'svcnum' => $svc_acct->svcnum, + 'name' => '#Vacation' + } + ); + +my $redirect_rule = qsearchs('cgp_rule', { 'svcnum' => $svc_acct->svcnum, + 'name' => '#Redirect' + } + ); -- cgit v1.2.1 From d311f62f655dc5cad8b9319f07f8c0e6bf344cc2 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 6 Aug 2010 21:28:09 +0000 Subject: communigate phase 3: archive messages, RT#7515 --- FS/FS/Schema.pm | 8 +++----- FS/FS/svc_acct.pm | 26 +++++++++++++++++++++++--- FS/FS/svc_domain.pm | 24 ++++++++++++++++++++++-- httemplate/edit/part_svc.cgi | 12 +++++++++++- 4 files changed, 59 insertions(+), 11 deletions(-) diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 60d2bcef5..557ee6295 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -1698,7 +1698,8 @@ sub tables_hashref { 'cgp_rpopallowed', 'char', 'NULL', 1, '', '', #RPOPAllowed 'cgp_mailtoall', 'char', 'NULL', 1, '', '', #MailToAll 'cgp_addmailtrailer', 'char', 'NULL', 1, '', '', #AddMailTrailer - #XXX archive messages, mailing lists + 'cgp_archiveafter', 'int', 'NULL', '', '', '', #ArchiveMessagesAfter + #XXX mailing lists #preferences 'cgp_deletemode', 'varchar', 'NULL', $char_d, '', '',#DeleteMode 'cgp_emptytrash', 'varchar', 'NULL', $char_d, '', '',#EmptyTrash @@ -1708,7 +1709,6 @@ sub tables_hashref { 'cgp_prontoskinname', 'varchar', 'NULL', $char_d, '', '',#ProntoSkinName 'cgp_sendmdnmode', 'varchar', 'NULL', $char_d, '', '',#SendMDNMode #mail -#vacation message, redirect all mail, mail rules #XXX RPOP settings ], 'primary_key' => 'svcnum', @@ -1770,7 +1770,7 @@ sub tables_hashref { 'acct_def_cgp_rpopallowed', 'char', 'NULL', 1, '', '', 'acct_def_cgp_mailtoall', 'char', 'NULL', 1, '', '', 'acct_def_cgp_addmailtrailer', 'char', 'NULL', 1, '', '', - #XXX archive messages + 'acct_def_cgp_archiveafter', 'int', 'NULL', '', '', '', #preferences 'acct_def_cgp_deletemode', 'varchar', 'NULL', $char_d, '', '', 'acct_def_cgp_emptytrash', 'varchar', 'NULL', $char_d, '', '', @@ -1779,8 +1779,6 @@ sub tables_hashref { 'acct_def_cgp_skinname', 'varchar', 'NULL', $char_d, '', '', 'acct_def_cgp_prontoskinname', 'varchar', 'NULL', $char_d, '', '', 'acct_def_cgp_sendmdnmode', 'varchar', 'NULL', $char_d, '', '', - #mail - #XXX rules, archive rule, spam foldering rule(s) ], 'primary_key' => 'svcnum', 'unique' => [ ], diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index 3b26688bf..707b33a6f 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -440,7 +440,28 @@ sub table_info { 'cgp_addmailtrailer' => { label => 'Add trailer to sent mail', type => 'checkbox', }, - #XXX archive messages, mailing lists + 'cgp_archiveafter' => { + label => 'Archive messages after', + type => 'select', + select_hash => [ + -2 => 'default(730 day(s))', + 0 => 'Never', + 86400 => '24 hour(s)', + 172800 => '2 day(s)', + 259200 => '3 day(s)', + 432000 => '5 day(s)', + 604800 => '7 day(s)', + 1209600 => '2 week(s)', + 2592000 => '30 day(s)', + 7776000 => '90 day(s)', + 15552000 => '180 day(s)', + 31536000 => '365 day(s)', + 63072000 => '730 day(s)', + ], + disable_inventory => 1, + disable_select => 1, + }, + #XXX mailing lists #preferences 'cgp_deletemode' => { @@ -494,7 +515,6 @@ sub table_info { }, #mail - #XXX vacation message, redirect all mail, mail rules #XXX RPOP settings }, @@ -1190,6 +1210,7 @@ sub check { || $self->ut_enum('cgp_rpopallowed', [ '', 'Y' ]) || $self->ut_enum('cgp_mailtoall', [ '', 'Y' ]) || $self->ut_enum('cgp_addmailtrailer', [ '', 'Y' ]) + || $self->ut_snumbern('cgp_archiveafter') #preferences || $self->ut_alphasn('cgp_deletemode') || $self->ut_enum('cgp_emptytrash', $self->cgp_emptytrash_values) @@ -1198,7 +1219,6 @@ sub check { || $self->ut_textn('cgp_skinname') || $self->ut_textn('cgp_prontoskinname') || $self->ut_alphan('cgp_sendmdnmode') - #XXX vacation message, redirect all mail, mail rules #XXX RPOP settings ; return $error if $error; diff --git a/FS/FS/svc_domain.pm b/FS/FS/svc_domain.pm index 4d85060d3..3dc352b7a 100644 --- a/FS/FS/svc_domain.pm +++ b/FS/FS/svc_domain.pm @@ -207,6 +207,27 @@ sub table_info { label => 'Acct. default Add trailer to sent mail', type => 'checkbox', }, + 'acct_def_cgp_archiveafter' => { + label => 'Archive messages after', + type => 'select', + select_hash => [ + -2 => 'default(730 days)', + 0 => 'Never', + 86400 => '24 hours', + 172800 => '2 days', + 259200 => '3 days', + 432000 => '5 days', + 604800 => '7 days', + 1209600 => '2 weeks', + 2592000 => '30 days', + 7776000 => '90 days', + 15552000 => '180 days', + 31536000 => '365 days', + 63072000 => '730 days', + ], + disable_inventory => 1, + disable_select => 1, + }, 'trailer' => { label => 'Mail trailer', type => 'textarea', @@ -490,7 +511,7 @@ sub check { || $self->ut_enum('acct_def_cgp_rpopallowed', [ '', 'Y' ]) || $self->ut_enum('acct_def_cgp_mailtoall', [ '', 'Y' ]) || $self->ut_enum('acct_def_cgp_addmailtrailer', [ '', 'Y' ]) - #XXX archive messages + || $self->ut_snumbern('acct_def_cgp_archiveafter') #preferences || $self->ut_alphasn('acct_def_cgp_deletemode') || $self->ut_enum('acct_def_cgp_emptytrash', @@ -501,7 +522,6 @@ sub check { || $self->ut_textn('acct_def_cgp_prontoskinname') || $self->ut_alphan('acct_def_cgp_sendmdnmode') #mail - #XXX rules, archive rule, spam foldering rule(s) ; return $error if $error; diff --git a/httemplate/edit/part_svc.cgi b/httemplate/edit/part_svc.cgi index 6fe015ab5..7f2e3aa3c 100755 --- a/httemplate/edit/part_svc.cgi +++ b/httemplate/edit/part_svc.cgi @@ -291,12 +291,22 @@ that field. % (grep(/^$rvalue$/, split(',',$value)) ? ' SELECTED>' : '>' ). % $record->$select_label(). ''; % } #next $record -% } else { # select_list +% } elsif ( $def->{select_list} ) { % foreach my $item ( @{$def->{select_list}} ) { % $html .= qq!'; % } #next $item +% } elsif ( $def->{select_hash} ) { +% $def->{select_hash} = tie %{ $def->{select_hash} }, +% 'Tie::IxHash', +% @{ $def->{select_hash} } +% if ref($def->{select_hash}) eq 'ARRAY'; +% foreach my $key ( keys %{$def->{select_hash}} ) { +% $html .= qq!'; +% } #next $key % } #endif % $html .= ''; % -- cgit v1.2.1 From 89da4b96c4e2fce7079be8d2729750c088f8035b Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 6 Aug 2010 21:31:04 +0000 Subject: communigate phase 3: archive messages, RT#7515 --- FS/FS/part_export/communigate_pro.pm | 10 +- FS/FS/svc_acct.pm | 24 +- httemplate/edit/part_svc.cgi | 8 +- httemplate/edit/svc_acct.cgi | 222 +---------------- httemplate/edit/svc_acct/communigate.html | 249 +++++++++++++++++++ httemplate/edit/svc_domain.cgi | 272 +-------------------- .../edit/svc_domain/communigate-acct_defaults.html | 223 +++++++++++++++++ httemplate/edit/svc_domain/communigate-basics.html | 82 +++++++ httemplate/view/svc_acct/communigate.html | 8 + httemplate/view/svc_domain/acct_defaults.html | 8 + 10 files changed, 613 insertions(+), 493 deletions(-) create mode 100644 httemplate/edit/svc_acct/communigate.html create mode 100644 httemplate/edit/svc_domain/communigate-acct_defaults.html create mode 100644 httemplate/edit/svc_domain/communigate-basics.html diff --git a/FS/FS/part_export/communigate_pro.pm b/FS/FS/part_export/communigate_pro.pm index 2cad24467..3e1213e84 100644 --- a/FS/FS/part_export/communigate_pro.pm +++ b/FS/FS/part_export/communigate_pro.pm @@ -85,10 +85,12 @@ sub _export_insert_svc_acct { 'MailToAll' =>($svc_acct->cgp_mailtoall ?'YES':'NO'), 'AddMailTrailer' =>($svc_acct->cgp_addmailtrailer ?'YES':'NO'), + 'ArchiveMessagesAfter' => $svc_acct->cgp_archiveafter, + map { $quotas{$_} => $svc_acct->$_() } grep $svc_acct->$_(), keys %quotas ); - #XXX phase 3: archive messages, mailing lists + #XXX phase 3: mailing lists my @options = ( 'CreateAccount', 'accountName' => $self->export_username($svc_acct), @@ -194,6 +196,7 @@ sub _export_insert_svc_domain { 'RPOPAllowed' =>($svc_domain->acct_def_cgp_rpopallowed ?'YES':'NO'), 'MailToAll' =>($svc_domain->acct_def_cgp_mailtoall ?'YES':'NO'), 'AddMailTrailer' =>($svc_domain->acct_def_cgp_addmailtrailer ?'YES':'NO'), + 'ArchiveMessagesAfter' => $svc_domain->acct_def_cgp_archiveafter, ); warn "WARNING: error queueing SetAccountDefaults job: $def_err" if $def_err; @@ -318,8 +321,10 @@ sub _export_replace_svc_acct { if $old->cgp_mailtoall ne $new->cgp_mailtoall; $settings{'AddMailTrailer'} = ( $new->cgp_addmailtrailer ? 'YES':'NO' ) if $old->cgp_addmailtrailer ne $new->cgp_addmailtrailer; + $settings{'ArchiveMessagesAfter'} = $new->cgp_archiveafter + if $old->cgp_archiveafter ne $new->cgp_archiveafter; - #XXX phase 3: archive messages, mailing lists + #XXX phase 3: mailing lists if ( keys %settings ) { my $error = $self->communigate_pro_queue( @@ -441,6 +446,7 @@ sub _export_replace_svc_domain { 'RPOPAllowed' => ( $new->acct_def_cgp_rpopallowed ? 'YES' : 'NO' ), 'MailToAll' => ( $new->acct_def_cgp_mailtoall ? 'YES' : 'NO' ), 'AddMailTrailer' => ( $new->acct_def_cgp_addmailtrailer ? 'YES' : 'NO' ), + 'ArchiveMessagesAfter' => $new->acct_def_cgp_archiveafter, ); warn "WARNING: error queueing SetAccountDefaults job: $def_err" if $def_err; diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index 707b33a6f..801c46533 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -444,19 +444,19 @@ sub table_info { label => 'Archive messages after', type => 'select', select_hash => [ - -2 => 'default(730 day(s))', + -2 => 'default(730 days)', 0 => 'Never', - 86400 => '24 hour(s)', - 172800 => '2 day(s)', - 259200 => '3 day(s)', - 432000 => '5 day(s)', - 604800 => '7 day(s)', - 1209600 => '2 week(s)', - 2592000 => '30 day(s)', - 7776000 => '90 day(s)', - 15552000 => '180 day(s)', - 31536000 => '365 day(s)', - 63072000 => '730 day(s)', + 86400 => '24 hours', + 172800 => '2 days', + 259200 => '3 days', + 432000 => '5 days', + 604800 => '7 days', + 1209600 => '2 weeks', + 2592000 => '30 days', + 7776000 => '90 days', + 15552000 => '180 days', + 31536000 => '365 days', + 63072000 => '730 days', ], disable_inventory => 1, disable_select => 1, diff --git a/httemplate/edit/part_svc.cgi b/httemplate/edit/part_svc.cgi index 7f2e3aa3c..940ea8d25 100755 --- a/httemplate/edit/part_svc.cgi +++ b/httemplate/edit/part_svc.cgi @@ -298,10 +298,10 @@ that field. % $item. ''; % } #next $item % } elsif ( $def->{select_hash} ) { -% $def->{select_hash} = tie %{ $def->{select_hash} }, -% 'Tie::IxHash', -% @{ $def->{select_hash} } -% if ref($def->{select_hash}) eq 'ARRAY'; +% if ( ref($def->{select_hash}) eq 'ARRAY' ) { +% tie my %hash, 'Tie::IxHash', @{ $def->{select_hash} }; +% $def->{select_hash} = \%hash; +% } % foreach my $key ( keys %{$def->{select_hash}} ) { % $html .= qq!