From e975ed0585280f4cbb90b02f57114dedc43f58be Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 14 May 2004 12:25:45 +0000 Subject: [PATCH 1/1] add per-agent invoice templates, add per-package suspend invoice events, fix automatic creation of invoice_latex alternate templates --- FS/FS/Conf.pm | 28 ++++++++++++++ FS/FS/cust_bill.pm | 51 +++++++++++++++++++----- FS/FS/cust_main.pm | 32 +++++++++++++++ FS/FS/part_bill_event.pm | 24 ++++++------ httemplate/edit/part_bill_event.cgi | 60 +++++++++++++++++++++++++++++ httemplate/edit/process/part_bill_event.cgi | 5 ++- 6 files changed, 176 insertions(+), 24 deletions(-) diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 3cddc20fe..e69a15622 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -108,6 +108,22 @@ sub exists { -e "$dir/$file"; } +=item config_orbase KEY SUFFIX + +Returns the configuration value or values (depending on context) for +KEY_SUFFIX, if it exists, otherwise for KEY + +=cut + +sub config_orbase { + my( $self, $file, $suffix ) = @_; + if ( $self->exists("${file}_$suffix") ) { + $self->config("${file}_$suffix"); + } else { + $self->config($file); + } +} + =item touch KEY Creates the specified configuration key if it does not exist. @@ -197,6 +213,18 @@ sub config_items { 'type' => 'textarea', } } glob($self->dir. '/invoice_latex_*') + ), + ( map { + my $basename = basename($_); + $basename =~ /^(.*)$/; + $basename = $1; + new FS::ConfItem { + 'key' => $basename, + 'section' => 'billing', + 'description' => 'Alternate Notes section for LaTeX typeset PostScript invoices. See the billing documentation for details.', + 'type' => 'textarea', + } + } glob($self->dir. '/invoice_latexnotes_*') ); } diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 7e2c8fb55..367e1bc5e 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -316,15 +316,23 @@ sub owed { $balance; } -=item send +=item send [ TEMPLATENAME [ , AGENTNUM ] ] Sends this invoice to the destinations configured for this customer: send emails or print. See L. +TEMPLATENAME, if specified, is the name of a suffix for alternate invoices. + +AGENTNUM, if specified, means that this invoice will only be sent for customers +of the specified agent. + =cut sub send { - my($self,$template) = @_; + my $self = shift; + my $template = scalar(@_) ? shift : ''; + return '' if scalar(@_) && $_[0] && $self->cust_main->agentnum ne shift; + my @print_text = $self->print_text('', $template); my @invoicing_list = $self->cust_main->invoicing_list; @@ -654,6 +662,31 @@ sub batch_card { ''; } +sub _agent_template { + my $self = shift; + + my $cust_bill_event = qsearchs( 'part_bill_event', + { + 'payby' => $self->cust_main->payby, + 'plan' => 'send_agent', + 'eventcode' => { 'op' => 'LIKE', + 'value' => '_%, '. $self->cust_main->agentnum. ');' }, + }, + '', + 'ORDER BY seconds LIMIT 1' + ); + + return '' unless $cust_bill_event; + + if ( $cust_bill_event->eventcode =~ /\(\s*'(.*)'\s*,\s*(\d+)\s*\)\;$/ ) { + return $1; + } else { + warn "can't parse eventcode for agent-specific invoice template"; + return ''; + } + +} + =item print_text [ TIME [ , TEMPLATE ] ] Returns an text invoice, as a list of lines. @@ -798,10 +831,11 @@ sub print_text { sprintf("%10.2f", $balance_due ) ]; #create the template + $template ||= $self->_agent_template; my $templatefile = 'invoice_template'; - $templatefile .= "_$template" if $template; + $templatefile .= "_$template" if length($template); my @invoice_template = $conf->config($templatefile) - or die "cannot load config file $templatefile"; + or die "cannot load config file $templatefile"; $invoice_lines = 0; my $wasfunc = 0; foreach ( grep /invoice_lines\(\d*\)/, @invoice_template ) { #kludgy @@ -923,8 +957,10 @@ sub print_latex { @buf = (); #create the template + $template ||= $self->_agent_template; my $templatefile = 'invoice_latex'; - $templatefile .= "_$template" if $template; + my $suffix = length($template) ? "_$template" : ''; + $templatefile .= $suffix; my @invoice_template = $conf->config($templatefile) or die "cannot load config file $templatefile"; @@ -954,7 +990,7 @@ sub print_latex { $invoice_data{'notes'} = join("\n", map { my $b=$_; $b =~ s/\$(\w+)/$invoice_data{$1}/eg; $b } - $conf->config('invoice_latexnotes') + $conf->config_orbase('invoice_latexnotes', $suffix) ); $invoice_data{'footer'} =~ s/\n+$//; @@ -1396,9 +1432,6 @@ The delete method. print_text formatting (and some logic :/) is in source, but needs to be slurped in from a file. Also number of lines ($=). -missing print_ps for a nice postscript copy (maybe HylaFAX-cover-page-style -or something similar so the look can be completely customized?) - =head1 SEE ALSO L, L, L, L, diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index f275d10fe..fbd461841 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -1028,6 +1028,38 @@ sub suspend { grep { $_->suspend } $self->unsuspended_pkgs; } +=item suspend_if_pkgpart PKGPART [ , PKGPART ... ] + +Suspends all unsuspended packages (see L) matching the listed +PKGPARTs (see L). Always returns a list: an empty list on +success or a list of errors. + +=cut + +sub suspend_if_pkgpart { + my $self = shift; + my @pkgparts = @_; + grep { $_->suspend } + grep { my $pkgpart = $_->pkgpart; grep { $pkgpart eq $_ } @pkgparts } + $self->unsuspended_pkgs; +} + +=item suspend_unless_pkgpart PKGPART [ , PKGPART ... ] + +Suspends all unsuspended packages (see L) unless they match the +listed PKGPARTs (see L). Always returns a list: an empty list +on success or a list of errors. + +=cut + +sub suspend_unless_pkgpart { + my $self = shift; + my @pkgparts = @_; + grep { $_->suspend } + grep { my $pkgpart = $_->pkgpart; ! grep { $pkgpart eq $_ } @pkgparts } + $self->unsuspended_pkgs; +} + =item cancel [ OPTION => VALUE ... ] Cancels all uncancelled packages (see L) for this customer. diff --git a/FS/FS/part_bill_event.pm b/FS/FS/part_bill_event.pm index 86f929424..4774b8df9 100644 --- a/FS/FS/part_bill_event.pm +++ b/FS/FS/part_bill_event.pm @@ -149,22 +149,20 @@ sub check { || $self->ut_textn('plan') || $self->ut_anything('plandata') ; + #|| $self->ut_snumber('seconds') return $error if $error; #quelle kludge - if ( $self->plandata =~ /^templatename\s+(.*)$/ ) { - my $name= $1; - unless ( $conf->exists("invoice_template_$name") ) { - $conf->set( - "invoice_template_$name" => - join("\n", $conf->config('invoice_template') ) - ); - } - unless ( $conf->exists("invoice_latex_$name") ) { - $conf->set( - "invoice_latex_$name" => - join("\n", $conf->config('invoice_latex') ) - ); + if ( $self->plandata =~ /^(agent_)?templatename\s+(.*)$/m ) { + my $name= $2; + + foreach my $file (qw( template latex latexnotes )) { + unless ( $conf->exists("invoice_${file}_$name") ) { + $conf->set( + "invoice_${file}_$name" => + join("\n", $conf->config("invoice_$file") ) + ); + } } } diff --git a/httemplate/edit/part_bill_event.cgi b/httemplate/edit/part_bill_event.cgi index 48ed7916b..d0fa973bf 100755 --- a/httemplate/edit/part_bill_event.cgi +++ b/httemplate/edit/part_bill_event.cgi @@ -68,6 +68,31 @@ print 'Action'; #print ntable(); +sub select_pkgpart { + my $label = shift; + my $plandata = shift; + my %selected = map { $_=>1 } split(/,\s*/, $plandata->{$label}); + qq('; +} + +sub select_agentnum { + my $plandata = shift; + my $agentnum = $plandata->{'agentnum'}; + ''; +} + #this is pretty kludgy right here. tie my %events, 'Tie::IxHash', @@ -84,6 +109,18 @@ tie my %events, 'Tie::IxHash', 'code' => '$cust_main->suspend();', 'weight' => 10, }, + 'suspend-if-pkgpart' => { + 'name' => 'Suspend packages', + 'code' => '$cust_main->suspend_if_pkgpart(%%%if_pkgpart%%%);', + 'html' => sub { &select_pkgpart('if_pkgpart', @_) }, + 'weight' => 10, + }, + 'suspend-unless-pkgpart' => { + 'name' => 'Suspend packages except', + 'code' => '$cust_main->suspend_unless_pkgpart(%%%unless_pkgpart%%%);', + 'html' => sub { &select_pkgpart('unless_pkgpart', @_) }, + 'weight' => 10, + }, 'cancel' => { 'name' => 'Cancel', 'code' => '$cust_main->cancel();', @@ -140,6 +177,26 @@ tie my %events, 'Tie::IxHash', 'weight' => 50, }, + 'send_agent' => { + 'name' => 'Send invoice (email/print) ', + 'code' => '$cust_bill->send(\'%%%agent_templatename%%%\', %%%agentnum%%%);', + 'html' => sub { + ' + + + + + + + + +
only for agent '. &select_agentnum(@_). '
with template + +
'; + }, + 'weight' => 50, + }, + 'send_csv_ftp' => { 'name' => 'Upload CSV invoice data to an FTP server', 'code' => '$cust_bill->send_csv( protocol => \'ftp\', @@ -188,6 +245,9 @@ foreach my $event ( keys %events ) { my %plandata = map { /^(\w+) (.*)$/; ($1, $2); } split(/\n/, $part_bill_event->plandata); my $html = $events{$event}{html}; + if ( ref($html) eq 'CODE' ) { + $html = &{$html}(\%plandata); + } while ( $html =~ /%%%(\w+)%%%/ ) { my $field = $1; $html =~ s/%%%$field%%%/$plandata{$field}/; diff --git a/httemplate/edit/process/part_bill_event.cgi b/httemplate/edit/process/part_bill_event.cgi index e224bf634..77dcd242a 100755 --- a/httemplate/edit/process/part_bill_event.cgi +++ b/httemplate/edit/process/part_bill_event.cgi @@ -5,7 +5,7 @@ my $eventpart = $cgi->param('eventpart'); my $old = qsearchs('part_bill_event',{'eventpart'=>$eventpart}) if $eventpart; #s/days/seconds/ -$cgi->param('seconds', $cgi->param('days') * 86400 ); +$cgi->param('seconds', int( $cgi->param('days') * 86400 ) ); my $error; if ( ! $cgi->param('plan_weight_eventcode') ) { @@ -21,7 +21,8 @@ if ( ! $cgi->param('plan_weight_eventcode') ) { my $plandata = ''; while ( $eventcode =~ /%%%(\w+)%%%/ ) { my $field = $1; - my $value = $cgi->param($field); + my $value = join(', ', $cgi->param($field) ); + $cgi->param($field, $value); #in case it errors out $eventcode =~ s/%%%$field%%%/$value/; $plandata .= "$field $value\n"; } -- 2.11.0