From 1e34f4a5d142bd58f5918219db0931e81ad0418e Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 20 Aug 2009 09:47:05 +0000 Subject: [PATCH] email statements, RT#4860 --- FS/FS/Cron/bill.pm | 2 +- FS/FS/Mason.pm | 1 + FS/FS/cust_statement.pm | 37 ++++++++++++++++++----- FS/FS/part_event/Action/cust_statement.pm | 5 ++-- FS/FS/part_event/Action/cust_statement_send.pm | 2 +- FS/FS/part_event/Condition/has_pkg_class.pm | 40 +++++++++++++++++++++++++ FS/FS/part_event/Condition/has_pkgpart.pm | 41 ++++++++++++++++++++++++++ FS/FS/part_event/Condition/hasnt_pkgpart.pm | 40 +++++++++++++++++++++++++ httemplate/misc/email-statement.cgi | 19 ++++++++++++ httemplate/view/cust_statement-pdf.cgi | 28 ++++++++++++++++++ httemplate/view/cust_statement.html | 13 ++++---- 11 files changed, 211 insertions(+), 17 deletions(-) create mode 100644 FS/FS/part_event/Condition/has_pkg_class.pm create mode 100644 FS/FS/part_event/Condition/has_pkgpart.pm create mode 100644 FS/FS/part_event/Condition/hasnt_pkgpart.pm create mode 100755 httemplate/misc/email-statement.cgi create mode 100755 httemplate/view/cust_statement-pdf.cgi diff --git a/FS/FS/Cron/bill.pm b/FS/FS/Cron/bill.pm index 2bdb12025..d727d923d 100644 --- a/FS/FS/Cron/bill.pm +++ b/FS/FS/Cron/bill.pm @@ -194,7 +194,7 @@ END my $where = FS::part_event_condition->where_conditions_sql( $eventtable, 'time'=>$time, ); - my $where = "AND $where" if $where; + $where = $where ? "AND $where" : ''; my $are_part_event = "EXISTS ( SELECT 1 FROM part_event $join diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index d73d3810a..f71db208e 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -197,6 +197,7 @@ Initializes the Mason environment, loads all Freeside and RT libraries, etc. use FS::h_svc_phone; #use FS::h_phone_device; use FS::h_svc_www; + use FS::cust_statement; # Sammath Naur if ( %%%RT_ENABLED%%% ) { diff --git a/FS/FS/cust_statement.pm b/FS/FS/cust_statement.pm index cd3e7cec8..83dd5c1be 100644 --- a/FS/FS/cust_statement.pm +++ b/FS/FS/cust_statement.pm @@ -180,6 +180,18 @@ sub _aggregate { @agg; } +sub _total { + my( $self, $method ) = ( shift, shift ); + + my $total = 0; + + foreach my $cust_bill ( $self->cust_bill ) { + $total += $cust_bill->$method( @_ ); + } + + $total; +} + =item cust_bill_pkg Returns the line items (see L) for all associated invoices. @@ -221,20 +233,29 @@ sub cust_bill_pkg_pkgnum { shift->_aggregate('cust_bill_pkg_pkgnum', @_); } =item tax -Returns the tax amount (see L) for this invoice. +Returns the total tax amount for all assoicated invoices.0 =cut -sub tax { - my $self = shift; +=item charged - my $total = 0; +Returns the total amount charged for all associated invoices. - foreach my $cust_bill ( $self->cust_bill ) { - $total += $cust_bill->tax; - } +=cut - $total; +=item owed + +Returns the total amount owed for all associated invoices. + +=cut + +sub tax { shift->_total('tax', @_); } +sub charged { shift->_total('charged', @_); } +sub owed { shift->_total('owed', @_); } + +#don't show previous info +sub previous { + ( 0 ); # 0, empty list } =back diff --git a/FS/FS/part_event/Action/cust_statement.pm b/FS/FS/part_event/Action/cust_statement.pm index 8d8f12770..2d9e8773c 100644 --- a/FS/FS/part_event/Action/cust_statement.pm +++ b/FS/FS/part_event/Action/cust_statement.pm @@ -11,8 +11,9 @@ sub description { } sub eventtable_hashref { - { 'cust_main' => 1, }; - { 'cust_pkg' => 1, }; + { 'cust_main' => 1, + 'cust_pkg' => 1, + }; } sub default_weight { diff --git a/FS/FS/part_event/Action/cust_statement_send.pm b/FS/FS/part_event/Action/cust_statement_send.pm index 34f023e0c..74cc48ca8 100644 --- a/FS/FS/part_event/Action/cust_statement_send.pm +++ b/FS/FS/part_event/Action/cust_statement_send.pm @@ -19,7 +19,7 @@ sub default_weight { sub do_action { my( $self, $cust_statement ) = @_; - $cust_statement->send; + $cust_statement->send( 'statement' ); #XXX configure } diff --git a/FS/FS/part_event/Condition/has_pkg_class.pm b/FS/FS/part_event/Condition/has_pkg_class.pm new file mode 100644 index 000000000..59a3675c3 --- /dev/null +++ b/FS/FS/part_event/Condition/has_pkg_class.pm @@ -0,0 +1,40 @@ +package FS::part_event::Condition::has_pkg_class; + +use strict; + +use base qw( FS::part_event::Condition ); +use FS::Record qw( qsearch ); +use FS::pkg_class; + +sub description { + 'Customer has uncancelled package with class'; +} + +sub eventtable_hashref { + { 'cust_main' => 1, + 'cust_bill' => 1, + 'cust_pkg' => 1, + }; +} + +#something like this +sub option_fields { + ( + 'pkgclass' => { 'label' => 'Package Class', + 'type' => 'select-pkg_class', + 'multiple' => 1, + }, + ); +} + +sub condition { + my( $self, $object ) = @_; + + my $cust_main = $self->cust_main($object); + + #XXX test + my $hashref = $self->option('pkgclass') || {}; + grep $hashref->{ $_->part_pkg->classnum }, $cust_main->ncancelled_pkgs; +} + +1; diff --git a/FS/FS/part_event/Condition/has_pkgpart.pm b/FS/FS/part_event/Condition/has_pkgpart.pm new file mode 100644 index 000000000..c54b7e256 --- /dev/null +++ b/FS/FS/part_event/Condition/has_pkgpart.pm @@ -0,0 +1,41 @@ +package FS::part_event::Condition::has_pkgpart; + +use strict; + +use base qw( FS::part_event::Condition ); + +sub description { 'Customer has uncancelled package of specified definitions'; } + +sub eventtable_hashref { + { 'cust_main' => 1, + 'cust_bill' => 1, + 'cust_pkg' => 1, + }; +} + +sub option_fields { + ( + 'if_pkgpart' => { 'label' => 'Only packages: ', + 'type' => 'select-part_pkg', + 'multiple' => 1, + }, + ); +} + +sub condition { + my( $self, $object) = @_; + + my $cust_main = $self->cust_main($object); + + #XXX test + my $if_pkgpart = $self->option('if_pkgpart') || {}; + grep $if_pkgpart->{ $_->pkgpart }, $cust_main->ncancelled_pkgs; + +} + +#XXX +#sub condition_sql { +# +#} + +1; diff --git a/FS/FS/part_event/Condition/hasnt_pkgpart.pm b/FS/FS/part_event/Condition/hasnt_pkgpart.pm new file mode 100644 index 000000000..421d0232c --- /dev/null +++ b/FS/FS/part_event/Condition/hasnt_pkgpart.pm @@ -0,0 +1,40 @@ +package FS::part_event::Condition::hasnt_pkgpart; + +use strict; + +use base qw( FS::part_event::Condition ); + +sub description { 'Customer does not have uncancelled package of specified definitions'; } + +sub eventtable_hashref { + { 'cust_main' => 1, + 'cust_bill' => 1, + 'cust_pkg' => 1, + }; +} + +sub option_fields { + ( + 'unless_pkgpart' => { 'label' => 'Packages: ', + 'type' => 'select-part_pkg', + 'multiple' => 1, + }, + ); +} + +sub condition { + my( $self, $object ) = @_; + + my $cust_main = $self->cust_main($object); + + #XXX test + my $unless_pkgpart = $self->option('unless_pkgpart') || {}; + ! grep $unless_pkgpart->{ $_->pkgpart }, $cust_main->ncancelled_pkgs; +} + +#XXX +#sub condition_sql { +# +#} + +1; diff --git a/httemplate/misc/email-statement.cgi b/httemplate/misc/email-statement.cgi new file mode 100755 index 000000000..67f654d64 --- /dev/null +++ b/httemplate/misc/email-statement.cgi @@ -0,0 +1,19 @@ +<% $cgi->redirect("${p}view/cust_main.cgi?$custnum") %> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Resend invoices'); + +#untaint statementnum +my($query) = $cgi->keywords; +$query =~ /^((.+)-)?(\d+)$/; +my $template = $2 || 'statement'; #XXX configure... via event?? eh.. +my $statementnum = $3; +my $cust_statement = qsearchs('cust_statement',{'statementnum'=>$statementnum}); +die "Can't find statement!\n" unless $cust_statement; + +$cust_statement->email($template); + +my $custnum = $cust_statement->getfield('custnum'); + + diff --git a/httemplate/view/cust_statement-pdf.cgi b/httemplate/view/cust_statement-pdf.cgi new file mode 100755 index 000000000..a1739e04c --- /dev/null +++ b/httemplate/view/cust_statement-pdf.cgi @@ -0,0 +1,28 @@ +<% $pdf %> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('View invoices'); + +#untaint statementnum +my($query) = $cgi->keywords; +$query =~ /^((.+)-)?(\d+)(.pdf)?$/; +my $templatename = $2 || 'statement'; #XXX configure... via event?? eh.. +my $statementnum = $3; + +my $cust_statement = qsearchs({ + 'select' => 'cust_statement.*', + 'table' => 'cust_statement', + 'addl_from' => 'LEFT JOIN cust_main USING ( custnum )', + 'hashref' => { 'statementnum' => $statementnum }, + 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, +}); +die "Statement #$statementnum not found!" unless $cust_statement; + +my $pdf = $cust_statement->print_pdf( '', $templatename); + +http_header('Content-Type' => 'application/pdf' ); +http_header('Content-Length' => length($pdf) ); +http_header('Cache-control' => 'max-age=60' ); + + diff --git a/httemplate/view/cust_statement.html b/httemplate/view/cust_statement.html index ec4ee9ebd..b078c9d07 100755 --- a/httemplate/view/cust_statement.html +++ b/httemplate/view/cust_statement.html @@ -4,13 +4,15 @@ % if ( $FS::CurrentUser::CurrentUser->access_right('Resend invoices') ) { - Re-print this statement +%# Re-print this statement % if ( grep { $_ ne 'POST' } $cust_statement->cust_main->invoicing_list ) { - | Re-email this statement +%# | + Re-email this statement % } -% if ( $conf->exists('hylafax') && length($cust_statement->cust_main->fax) ) { +% if ( 0 ) { +% #if ( $conf->exists('hylafax') && length($cust_statement->cust_main->fax) ) { | Re-fax this statement % } @@ -19,7 +21,8 @@ % } -% if ( $conf->exists('invoice_latex') ) { +% #if ( $conf->exists('invoice_latex') ) { +% if ( 0 ) { #broken??? View typeset statement

@@ -47,7 +50,7 @@ die "access denied" #untaint statement my($query) = $cgi->keywords; $query =~ /^((.+)-)?(\d+)$/; -my $templatename = $2; +my $templatename = $2 || 'statement'; #XXX configure... via event?? eh.. my $statementnum = $3; my $conf = new FS::Conf; -- 2.11.0