From 9ea31f98372bc897fd0b4d7e63284eecabf27aa2 Mon Sep 17 00:00:00 2001 From: Mitch Jackson Date: Mon, 17 Sep 2018 21:30:15 -0400 Subject: [PATCH] RT# 78547 Future autobill report - report runs in job queue --- FS/FS/Report/Queued/FutureAutobill.pm | 132 +++++++++++++++++++++ FS/FS/UI/Web.pm | 1 + httemplate/search/elements/grid-report.html | 14 ++- httemplate/search/future_autobill.html | 47 +++++++- .../search/report_future_autobill-queued_job.html | 11 ++ httemplate/search/report_future_autobill.html | 60 ++++++---- 6 files changed, 238 insertions(+), 27 deletions(-) create mode 100644 FS/FS/Report/Queued/FutureAutobill.pm create mode 100644 httemplate/search/report_future_autobill-queued_job.html diff --git a/FS/FS/Report/Queued/FutureAutobill.pm b/FS/FS/Report/Queued/FutureAutobill.pm new file mode 100644 index 000000000..82c902172 --- /dev/null +++ b/FS/FS/Report/Queued/FutureAutobill.pm @@ -0,0 +1,132 @@ +package FS::Report::Queued::FutureAutobill; +use strict; +use warnings; +use vars qw( $job ); + +use FS::Conf; +use FS::cust_main; +use FS::cust_main::Location; +use FS::cust_payby; +use FS::CurrentUser; +use FS::Log; +use FS::Mason qw(mason_interps); +use FS::Record qw( qsearch ); +use FS::UI::Web; +use FS::UID qw( dbh ); + +use DateTime; +use File::Temp; +use Data::Dumper; +use HTML::Entities qw( encode_entities ); + +=head1 NAME + +FS::Report::Queued::FutureAutobill - Future Auto-Bill Transactions Report + +=head1 DESCRIPTION + +Future Autobill report generated within the job queue. + +Report results are saved to temp storage as a Mason fragment +that is rendered by the queued report viewer. + +For every customer with a valid auto-bill payment method, +report runs bill_and_collect() for each day, from today through +the report target date. After recording the results, all +operations are rolled back. + +This report relies on the ability to safely run bill_and_collect(), +with all exports and messaging disabled, and then to roll back the +results. + +=head1 PARAMETERS + +C, C + +=cut + +sub make_report { + $job = shift; + my $param = shift; + my $outbuf; + my $DEBUG = 0; + + my $time_begin = time(); + + my $report_fh = File::Temp->new( + TEMPLATE => 'report.future_autobill.XXXXXXXX', + DIR => sprintf( '%s/cache.%s', $FS::Conf::base_dir, $FS::UID::datasrc ), + UNLINK => 0 + ) or die "Cannot create report file: $!"; + + if ( $DEBUG ) { + warn Dumper( $job ); + warn Dumper( $param ); + warn $report_fh; + warn $report_fh->filename; + } + + my $curuser = FS::CurrentUser->load_user( $param->{CurrentUser} ) + or die 'Unable to set report user'; + + my ( $fs_interp ) = FS::Mason::mason_interps( + 'standalone', + outbuf => \$outbuf, + ); + $fs_interp->error_mode('fatal'); + $fs_interp->error_format('text'); + + $FS::Mason::Request::QUERY_STRING = sprintf( + 'target_date=%s&agentnum=%s', + encode_entities( $param->{target_date} ), + encode_entities( $param->{agentnum} || '' ), + ); + $FS::Mason::Request::FSURL = $param->{RootURL}; + + my $mason_request = $fs_interp->make_request( + comp => '/search/future_autobill.html' + ); + + { + local $@; + eval{ $mason_request->exec() }; + if ( $@ ) { + my $error = ref $@ eq 'HTML::Mason::Exception' ? $@->error : $@; + + my $log = FS::Log->new('FS::Report::Queued::FutureAutobill'); + $log->error( + "Error generating report: $FS::Mason::Request::QUERY_STRING $error" + ); + die $error; + } + } + + my $report_fn; + if ( $report_fh->filename =~ /report\.(future_autobill.+)$/ ) { + $report_fn = $1 + } else { + die 'Error parsing report filename '.$report_fh->filename; + } + + my $report_title = FS::cust_payby->future_autobill_report_title(); + my $time_rendered = time() - $time_begin; + + if ( $DEBUG ) { + warn "Generated content:\n"; + warn $outbuf; + warn $report_fn; + warn $report_title; + } + + print $report_fh qq{<% include("/elements/header.html", '$report_title') %>\n}; + print $report_fh $outbuf; + print $report_fh qq{}; + print $report_fh qq{<% include("/elements/footer.html") %>\n}; + + die sprintf + "view\n", + $param->{RootURL}, + $report_fn; +} + +1; diff --git a/FS/FS/UI/Web.pm b/FS/FS/UI/Web.pm index 6cc04b9de..54128682e 100644 --- a/FS/FS/UI/Web.pm +++ b/FS/FS/UI/Web.pm @@ -743,6 +743,7 @@ use FS::CurrentUser; use FS::Record qw(qsearchs); use FS::queue; use FS::CGI qw(rooturl); +use FS::Report::Queued::FutureAutobill; $DEBUG = 0; diff --git a/httemplate/search/elements/grid-report.html b/httemplate/search/elements/grid-report.html index b1e543012..efc009725 100644 --- a/httemplate/search/elements/grid-report.html +++ b/httemplate/search/elements/grid-report.html @@ -141,13 +141,17 @@ Usage: $m->print($output); % } else { +% unless ( $suppress_header ) { <& /elements/header.html, $title &> +% } <% $head %> % my $myself = $cgi->self_url; +% unless ( $suppress_header ) {

Download full reports
as ">Excel spreadsheet

+% } ', + suppress_header => $job ? 1 : 0, + suppress_footer => $job ? 1 : 0, &> <%init> + use DateTime; + use FS::Misc::Savepoint; + use FS::Report::Queued::FutureAutobill; use FS::UID qw( dbh ); die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Financial reports'); + my $job = $FS::Report::Queued::FutureAutobill::job; + + $job->update_statustext('0,Finding customers') if $job; + my $DEBUG = $cgi->param('DEBUG') || 0; - my $report_title = FS::cust_payby->future_autobill_report_title; my $agentnum = $cgi->param('agentnum') if $cgi->param('agentnum') =~ /^\d+/; @@ -60,16 +73,20 @@ results. # Get target date from form if ($cgi->param('target_date')) { + # DateTime::Format::DateParse would be better my ($mm, $dd, $yy) = split /[\-\/]/,$cgi->param('target_date'); + ( $yy, $mm, $dd ) = ( $mm, $dd, $yy ) if $mm > 1900; + $target_dt = DateTime->new( month => $mm, day => $dd, year => $yy, %noon, - ) if $mm && $dd & $yy; + ) if $mm && $dd && $yy; # Catch a date from the past: time only travels in one direction - $target_dt = undef if $target_dt->epoch < $now_dt->epoch; + $target_dt = undef + unless $target_dt && $now_dt && $now_dt <= $target_dt; } # without a target date, default to tomorrow @@ -77,6 +94,13 @@ results. $target_dt = $now_dt->clone->add( days => 1 ); } + my $report_title = FS::cust_payby->future_autobill_report_title; + my $report_subtitle = sprintf( + '(%s through %s)', + $now_dt->mdy('/'), + $target_dt->mdy('/'), + ); + # Create a range of dates from today until the given report date # (leaving the probably useless 'quick-report' mode, but disabled) if ( 1 || $cgi->param('multiple_billing_dates')) { @@ -104,6 +128,9 @@ results. . ($agentnum ? "AND cust_main.agentnum = $agentnum" : ''), }); + my $completion_target = scalar(keys %cust_payby) * scalar( @target_dates ); + my $completion_progress = 0; + my $fakebill_time = time(); my %abreport; my @rows; @@ -125,6 +152,9 @@ results. local $FS::cust_main::Billing_Realtime::BOP_TESTING = 1; local $FS::cust_main::Billing_Realtime::BOP_TESTING_SUCCESS = 1; + my $savepoint_label = 'future_autobill'; + savepoint_create( $savepoint_label ); + warn sprintf "Report involves %s customers", scalar keys %cust_payby if $DEBUG; @@ -153,8 +183,18 @@ results. ); warn "!!! $error (simulating future billing)\n" if $error; + + my $statustext = sprintf( + '%s,Simulating upcoming invoices and payments', + int( ( ++$completion_progress / $completion_target ) * 100 ) + ); + $job->update_statustext( $statustext ) if $job; + warn "[ $completion_progress / $completion_target ] $statustext\n" + if $DEBUG; + } + # Generate report rows from recorded payments in cust_pay for my $cust_pay ( qsearch( cust_pay => { @@ -206,6 +246,7 @@ results. # locked at a time warn "-- custnum $custnum -- rollback()\n" if $DEBUG; + savepoint_rollback( $savepoint_label ); dbh->rollback if $oldAutoCommit; } # /foreach $custnum diff --git a/httemplate/search/report_future_autobill-queued_job.html b/httemplate/search/report_future_autobill-queued_job.html new file mode 100644 index 000000000..d23efb5b1 --- /dev/null +++ b/httemplate/search/report_future_autobill-queued_job.html @@ -0,0 +1,11 @@ +<% $server->process %> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Financial reports'); + +my $server = new FS::UI::Web::JSRPC + 'FS::Report::Queued::FutureAutobill::make_report', + $cgi; + + diff --git a/httemplate/search/report_future_autobill.html b/httemplate/search/report_future_autobill.html index ccde299e9..28f589ee7 100644 --- a/httemplate/search/report_future_autobill.html +++ b/httemplate/search/report_future_autobill.html @@ -1,6 +1,9 @@ <%doc> -Display date selector for the future_autobill.html report +Display pre-report page for the Future Auto Bill Transactions report + +Report runs in the queue. Once the report is generated, user is +redirected to the report results. <% include('/elements/header.html', $report_title ) %> @@ -14,30 +17,43 @@ Display date selector for the future_autobill.html report % } else { -
- - <& /elements/tr-input-date-field.html, - { - name => 'target_date', - value => $target_date, - label => emt('Target billing date').': ', - required => 1 - } - &> - - <% include('/elements/tr-select-agent.html', - 'label' => 'For agent: ', - 'disable_empty' => 0, + +
+ <& /elements/tr-input-date-field.html, + { + name => 'target_date', + value => $target_date, + label => emt('Target billing date').': ', + required => 1 + } + &> + + <% include('/elements/tr-select-agent.html', + 'label' => 'For agent: ', + 'disable_empty' => 0, + ) + %> +
+
+ + +
+ + <% include( '/elements/progress-init.html', + 'future_autobill', + [ qw( agentnum target_date ) ], + 'report_future_autobill-queued_job.html', ) %> - - -
- - - - + % } -- 2.11.0