diff options
author | Mark Wells <mark@freeside.biz> | 2013-09-27 17:29:17 -0700 |
---|---|---|
committer | Mark Wells <mark@freeside.biz> | 2013-09-27 17:29:17 -0700 |
commit | 1d6a32338660e3d7202faa7e4ce14736b4569a48 (patch) | |
tree | 681f6a7887f43974b7e58508e5aeb5b59db531b7 /FS | |
parent | c64ff892b9067f7aa719e78b20379d3274907946 (diff) |
invoice configurations, #24723
Diffstat (limited to 'FS')
-rw-r--r-- | FS/FS/Mason.pm | 2 | ||||
-rw-r--r-- | FS/FS/Schema.pm | 45 | ||||
-rw-r--r-- | FS/FS/Template_Mixin.pm | 117 | ||||
-rw-r--r-- | FS/FS/agent.pm | 17 | ||||
-rw-r--r-- | FS/FS/cust_bill.pm | 274 | ||||
-rw-r--r-- | FS/FS/cust_main.pm | 4 | ||||
-rw-r--r-- | FS/FS/invoice_conf.pm | 274 | ||||
-rw-r--r-- | FS/FS/invoice_mode.pm | 157 | ||||
-rw-r--r-- | FS/FS/part_event/Action/cust_bill_email.pm | 10 | ||||
-rw-r--r-- | FS/FS/part_event/Action/cust_bill_print.pm | 9 | ||||
-rw-r--r-- | FS/FS/part_event/Action/cust_bill_print_pdf.pm | 9 | ||||
-rw-r--r-- | FS/FS/part_event/Action/cust_bill_send.pm | 9 | ||||
-rw-r--r-- | FS/FS/part_event/Action/cust_bill_send_agent.pm | 17 | ||||
-rw-r--r-- | FS/FS/part_event/Action/cust_bill_send_alternate.pm | 5 | ||||
-rw-r--r-- | FS/FS/part_event/Action/cust_bill_send_if_newest.pm | 18 | ||||
-rw-r--r-- | FS/FS/part_event/Action/cust_bill_send_reminder.pm | 12 | ||||
-rw-r--r-- | FS/FS/part_event/Action/cust_statement_send.pm | 3 | ||||
-rw-r--r-- | FS/MANIFEST | 4 | ||||
-rw-r--r-- | FS/t/invoice_conf.t | 5 | ||||
-rw-r--r-- | FS/t/invoice_mode.t | 5 |
20 files changed, 742 insertions, 254 deletions
diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index a946ebf9f..9c6a0fba2 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -342,6 +342,8 @@ if ( -e $addl_handler_use_file ) { use FS::sales_pkg_class; use FS::svc_alarm; use FS::cable_model; + use FS::invoice_mode; + use FS::invoice_conf; # Sammath Naur if ( $FS::Mason::addl_handler_use ) { diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 9927eb3d6..05699dee4 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -4208,6 +4208,51 @@ sub tables_hashref { 'index' => [ [ 'derivenum', ], ], }, + 'invoice_mode' => { + 'columns' => [ + 'modenum', 'serial', '', '', '', '', + 'agentnum', 'int', 'NULL', '', '', '', + 'modename', 'varchar', '', 32, '', '', + ], + 'primary_key' => 'modenum', + 'unique' => [ ], + 'index' => [ ], + }, + + 'invoice_conf' => { + 'columns' => [ + 'confnum', 'serial', '', '', '', '', + 'modenum', 'int', '', '', '', '', + 'locale', 'varchar', 'NULL', 16, '', '', + 'notice_name', 'varchar', 'NULL', 64, '', '', + 'subject', 'varchar', 'NULL', 64, '', '', + 'htmlnotes', 'text', 'NULL', '', '', '', + 'htmlfooter', 'text', 'NULL', '', '', '', + 'htmlsummary', 'text', 'NULL', '', '', '', + 'htmlreturnaddress', 'text', 'NULL', '', '', '', + 'latexnotes', 'text', 'NULL', '', '', '', + 'latexfooter', 'text', 'NULL', '', '', '', + 'latexsummary', 'text', 'NULL', '', '', '', + 'latexcoupon', 'text', 'NULL', '', '', '', + 'latexsmallfooter', 'text', 'NULL', '', '', '', + 'latexreturnaddress', 'text', 'NULL', '', '', '', + 'latextopmargin', 'varchar', 'NULL', 16, '', '', + 'latexheadsep', 'varchar', 'NULL', 16, '', '', + 'latexaddresssep', 'varchar', 'NULL', 16, '', '', + 'latextextheight', 'varchar', 'NULL', 16, '', '', + 'latexextracouponspace','varchar', 'NULL', 16, '', '', + 'latexcouponfootsep', 'varchar', 'NULL', 16, '', '', + 'latexcouponamountenclosedsep', 'varchar', 'NULL', 16, '', '', + 'latexcoupontoaddresssep', 'varchar', 'NULL', 16, '', '', + 'latexverticalreturnaddress', 'char', 'NULL', 1, '', '', + 'latexcouponaddcompanytoaddress', 'char', 'NULL', 1, '', '', + 'logo_png', 'blob', 'NULL', '', '', '', + 'logo_eps', 'blob', 'NULL', '', '', '', + 'lpr', 'varchar', 'NULL', $char_d, '', '', + ], + 'primary_key' => 'confnum', + 'unique' => [ [ 'modenum', 'locale' ] ], + }, # name type nullability length default local diff --git a/FS/FS/Template_Mixin.pm b/FS/FS/Template_Mixin.pm index 356de5bed..840df7558 100644 --- a/FS/FS/Template_Mixin.pm +++ b/FS/FS/Template_Mixin.pm @@ -18,6 +18,7 @@ use FS::Record qw( qsearch qsearchs ); use FS::Misc qw( generate_ps generate_pdf ); use FS::pkg_category; use FS::pkg_class; +use FS::invoice_mode; use FS::L10N; $DEBUG = 0; @@ -30,12 +31,51 @@ FS::UID->install_callback( sub { $date_format_long = $conf->config('date_format_long') || '%b %o, %Y'; } ); -=item print_text HASHREF | [ TIME [ , TEMPLATE [ , OPTION => VALUE ... ] ] ] +=item conf [ MODE ] + +Returns a configuration handle (L<FS::Conf>) set to the customer's locale. + +If the "mode" pseudo-field is set on the object, the configuration handle +will be an L<FS::invoice_conf> for that invoice mode (and the customer's +locale). + +=cut + +sub conf { + my $self = shift; + my $mode = $self->get('mode'); + if ($self->{_conf} and !defined($mode)) { + return $self->{_conf}; + } + + my $cust_main = $self->cust_main; + my $locale = $cust_main ? $cust_main->locale : ''; + my $conf; + if ( $mode ) { + if ( ref $mode and $mode->isa('FS::invoice_mode') ) { + $mode = $mode->modenum; + } elsif ( $mode =~ /\D/ ) { + die "invalid invoice mode $mode"; + } + $conf = qsearchs('invoice_conf', { modenum => $mode, locale => $locale }); + if (!$conf) { + $conf = qsearchs('invoice_conf', { modenum => $mode, locale => '' }); + # it doesn't have a locale, but system conf still might + $conf->set('locale' => $locale) if $conf; + } + } + # if $mode is unspecified, or if there is no invoice_conf matching this mode + # and locale, then use the system config only (but with the locale) + $conf ||= FS::Conf->new({ 'locale' => $locale }); + # cache it + return $self->{_conf} = $conf; +} + +=item print_text OPTIONS Returns an text invoice, as a list of lines. -Options can be passed as a hashref (recommended) or as a list of time, template -and then any key/value pairs for any other options. +Options can be passed as a hash. I<time>, if specified, is used to control the printing of overdue messages. The default is now. It isn't the date of the invoice; that's the `_date' field. @@ -50,25 +90,19 @@ I<notice_name>, if specified, overrides "Invoice" as the name of the sent docume sub print_text { my $self = shift; - my( $today, $template, %opt ); + my %params; if ( ref($_[0]) ) { - %opt = %{ shift() }; - $today = delete($opt{'time'}) || ''; - $template = delete($opt{template}) || ''; + %params = %{ shift() }; } else { - ( $today, $template, %opt ) = @_; + %params = @_; } - my %params = ( 'format' => 'template' ); - $params{'time'} = $today if $today; - $params{'template'} = $template if $template; - $params{$_} = $opt{$_} - foreach grep $opt{$_}, qw( unsquelch_cdr notice_name ); + $params{'format'} = 'template'; # for some reason $self->print_generic( %params ); } -=item print_latex HASHREF | [ TIME [ , TEMPLATE [ , OPTION => VALUE ... ] ] ] +=item print_latex HASHREF Internal method - returns a filename of a filled-in LaTeX template for this invoice (Note: add ".tex" to get the actual filename), and a filename of @@ -76,15 +110,16 @@ an associated logo (with the .eps extension included). See print_ps and print_pdf for methods that return PostScript and PDF output. -Options can be passed as a hashref (recommended) or as a list of time, template -and then any key/value pairs for any other options. +Options can be passed as a hash. I<time>, if specified, is used to control the printing of overdue messages. The default is now. It isn't the date of the invoice; that's the `_date' field. It is specified as a UNIX timestamp; see L<perlfunc/"time">. Also see L<Time::Local> and L<Date::Parse> for conversion functions. -I<template>, if specified, is the name of a suffix for alternate invoices. +I<template>, if specified, is the name of a suffix for alternate invoices. +This is strongly deprecated; see L<FS::invoice_conf> for the right way to +customize invoice templates for different purposes. I<notice_name>, if specified, overrides "Invoice" as the name of the sent document (templates from 10/2009 or newer required) @@ -92,22 +127,20 @@ I<notice_name>, if specified, overrides "Invoice" as the name of the sent docume sub print_latex { my $self = shift; - my $conf = $self->conf; - my( $today, $template, %opt ); + my %params; + if ( ref($_[0]) ) { - %opt = %{ shift() }; - $today = delete($opt{'time'}) || ''; - $template = delete($opt{template}) || ''; + %params = %{ shift() }; } else { - ( $today, $template, %opt ) = @_; + %params = @_; } - my %params = ( 'format' => 'latex' ); - $params{'time'} = $today if $today; - $params{'template'} = $template if $template; - $params{$_} = $opt{$_} - foreach grep $opt{$_}, qw( unsquelch_cdr notice_name no_date no_number ); + $params{'format'} = 'latex'; + my $conf = $self->conf; + # this needs to go away + my $template = $params{'template'}; + # and this especially $template ||= $self->_agent_template if $self->can('_agent_template'); @@ -191,7 +224,8 @@ Non optional options include Optional options include -template - a value used as a suffix for a configuration template +template - a value used as a suffix for a configuration template. Please +don't use this. time - a value used to control the printing of overdue messages. The default is now. It isn't the date of the invoice; that's the `_date' field. @@ -214,6 +248,7 @@ locale - override customer's locale sub print_generic { my( $self, %params ) = @_; my $conf = $self->conf; + my $today = $params{today} ? $params{today} : time; warn "$me print_generic called on $self with suffix $params{template}\n" if $DEBUG; @@ -227,6 +262,8 @@ sub print_generic { unless $cust_main->payname && $cust_main->payby !~ /^(CARD|DCRD|CHEK|DCHK)$/; + my $locale = $params{'locale'} || $cust_main->locale; + my %delimiters = ( 'latex' => [ '[@--', '--@]' ], 'html' => [ '<%=', '%>' ], 'template' => [ '{', '}' ], @@ -235,11 +272,18 @@ sub print_generic { warn "$me print_generic creating template\n" if $DEBUG > 1; + # set the notice name here, and nowhere else. + my $notice_name = $params{notice_name} + || $conf->config('notice_name') + || $self->notice_name; + #create the template my $template = $params{template} ? $params{template} : $self->_agent_template; my $templatefile = $self->template_conf. $format; $templatefile .= "_$template" if length($template) && $conf->exists($templatefile."_$template"); + + # the base template my @invoice_template = map "$_\n", $conf->config($templatefile) or die "cannot load config data $templatefile"; @@ -380,6 +424,7 @@ sub print_generic { # generate template variables my $returnaddress; + if ( defined( $conf->config_orbase( "invoice_${format}returnaddress", $template @@ -457,7 +502,7 @@ sub print_generic { 'today' => time2str($date_format_long, $today), 'terms' => $self->terms, 'template' => $template, #params{'template'}, - 'notice_name' => ($params{'notice_name'} || $self->notice_name),#escape_function? + 'notice_name' => $notice_name, # escape? 'current_charges' => sprintf("%.2f", $self->charged), 'duedate' => $self->due_date2str($rdate_format), #date_format? @@ -499,7 +544,7 @@ sub print_generic { ); #localization - my $lh = FS::L10N->get_handle( $params{'locale'} || $cust_main->locale ); + my $lh = FS::L10N->get_handle( $locale ); $invoice_data{'emt'} = sub { &$escape_function($self->mt(@_)) }; my %info = FS::Locales->locale_info($cust_main->locale || 'en_US'); # eval to avoid death for unimplemented languages @@ -942,9 +987,6 @@ sub print_generic { foreach my $section (@sections, @$late_sections) { - warn "$me adding section \n". Dumper($section) - if $DEBUG > 1; - # begin some normalization $section->{'subtotal'} = $section->{'amount'} if $multisection @@ -1544,12 +1586,9 @@ sub print_html { my %params; if ( ref($_[0]) ) { %params = %{ shift() }; - }else{ - $params{'time'} = shift; - $params{'template'} = shift; - $params{'cid'} = shift; + } else { + %params = @_; } - $params{'format'} = 'html'; $self->print_generic( %params ); diff --git a/FS/FS/agent.pm b/FS/FS/agent.pm index 68a5912f2..b46d447aa 100644 --- a/FS/FS/agent.pm +++ b/FS/FS/agent.pm @@ -354,6 +354,23 @@ sub payment_gateway { $payment_gateway; } +=item invoice_modes + +Returns all L<FS::invoice_mode> objects that are valid for this agent (i.e. +those with this agentnum or null agentnum). + +=cut + +sub invoice_modes { + my $self = shift; + qsearch( { + table => 'invoice_mode', + hashref => { agentnum => $self->agentnum }, + extra_sql => ' OR agentnum IS NULL', + order_by => ' ORDER BY modename', + } ); +} + =item num_prospect_cust_main Returns the number of prospects (customers with no packages ever ordered) for diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 97dd38be5..a747a782d 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -80,7 +80,7 @@ FS::cust_bill - Object methods for cust_bill records $tax_amount = $record->tax; @lines = $cust_bill->print_text; - @lines = $cust_bill->print_text $time; + @lines = $cust_bill->print_text('time' => $time); =head1 DESCRIPTION @@ -153,7 +153,13 @@ Invoices are normally created by calling the bill method of a customer object =cut sub table { 'cust_bill'; } -sub notice_name { 'Invoice'; } + +# should be the ONLY occurrence of "Invoice" in invoice rendering code. +# (except email_subject and invnum_date_pretty) +sub notice_name { + my $self = shift; + $self->conf->config('notice_name') || 'Invoice' +} sub cust_linked { $_[0]->cust_main_custnum; } sub cust_unlinked_msg { @@ -1043,7 +1049,7 @@ Options: sender address, required -=item tempate +=item template alternate template name, optional @@ -1077,15 +1083,10 @@ sub generate_email { my %return = ( 'from' => $args{'from'}, - 'subject' => (($args{'subject'}) ? $args{'subject'} : 'Invoice'), + 'subject' => ($args{'subject'} || $self->email_subject), ); - my %opt = ( - 'unsquelch_cdr' => $conf->exists('voip-cdr_email'), - 'template' => $args{'template'}, - 'notice_name' => ( $args{'notice_name'} || 'Invoice' ), - 'no_coupon' => $args{'no_coupon'}, - ); + $args{'unsquelch_cdr'} = $conf->exists('voip-cdr_email'); my $cust_main = $self->cust_main; @@ -1127,7 +1128,7 @@ sub generate_email { if ( ref($args{'print_text'}) eq 'ARRAY' ) { $data = $args{'print_text'}; } else { - $data = [ $self->print_text(\%opt) ]; + $data = [ $self->print_text(\%args) ]; } } @@ -1184,10 +1185,10 @@ sub generate_email { 'Filename' => 'barcode.png', 'Content-ID' => "<$barcode_content_id>", ; - $opt{'barcode_cid'} = $barcode_content_id; + $args{'barcode_cid'} = $barcode_content_id; } - $htmldata = $self->print_html({ 'cid'=>$content_id, %opt }); + $htmldata = $self->print_html({ 'cid'=>$content_id, %args }); } $alternative->attach( @@ -1249,7 +1250,7 @@ sub generate_email { $related->add_part($image) if $image; - my $pdf = build MIME::Entity $self->mimebuild_pdf(\%opt); + my $pdf = build MIME::Entity $self->mimebuild_pdf(\%args); $return{'mimeparts'} = [ $related, $pdf, @otherparts ]; @@ -1281,7 +1282,7 @@ sub generate_email { #mime parts arguments a la MIME::Entity->build(). $return{'mimeparts'} = [ - { $self->mimebuild_pdf(\%opt) } + { $self->mimebuild_pdf(\%args) } ]; } @@ -1301,7 +1302,7 @@ sub generate_email { if ( ref($args{'print_text'}) eq 'ARRAY' ) { $return{'body'} = $args{'print_text'}; } else { - $return{'body'} = [ $self->print_text(\%opt) ]; + $return{'body'} = [ $self->print_text(\%args) ]; } } @@ -1330,105 +1331,48 @@ sub mimebuild_pdf { ); } -=item send HASHREF | [ TEMPLATE [ , AGENTNUM [ , INVOICE_FROM [ , AMOUNT ] ] ] ] +=item send HASHREF Sends this invoice to the destinations configured for this customer: sends email, prints and/or faxes. See L<FS::cust_main_invoice>. -Options can be passed as a hashref (recommended) or as a list of up to -four values for templatename, agentnum, invoice_from and amount. +Options can be passed as a hashref. Positional parameters are no longer +allowed. -I<template>, if specified, is the name of a suffix for alternate invoices. +I<template>: a suffix for alternate invoices -I<agentnum>, if specified, means that this invoice will only be sent for customers -of the specified agent or agent(s). AGENTNUM can be a scalar agentnum (for a -single agent) or an arrayref of agentnums. +I<agentnum>: obsolete, now does nothing. -I<invoice_from>, if specified, overrides the default email invoice From: address. +I<invoice_from> overrides the default email invoice From: address. -I<amount>, if specified, only sends the invoice if the total amount owed on this -invoice and all older invoices is greater than the specified amount. +I<amount>: obsolete, does nothing -I<notice_name>, if specified, overrides "Invoice" as the name of the sent document (templates from 10/2009 or newer required) +I<notice_name> overrides "Invoice" as the name of the sent document +(templates from 10/2009 or newer required). -I<lpr>, if specified, is passed to +I<lpr> overrides the system 'lpr' option as the command to print a document +from standard input. =cut -sub queueable_send { - my %opt = @_; - - my $self = qsearchs('cust_bill', { 'invnum' => $opt{invnum} } ) - or die "invalid invoice number: " . $opt{invnum}; - - my @args = ( $opt{template}, $opt{agentnum} ); - push @args, $opt{invoice_from} - if exists($opt{invoice_from}) && $opt{invoice_from}; - - my $error = $self->send( @args ); - die $error if $error; - -} - sub send { my $self = shift; + my $opt = ref($_[0]) ? $_[0] : +{ @_ }; my $conf = $self->conf; - my( $template, $invoice_from, $notice_name ); - my $agentnums = ''; - my $balance_over = 0; - my $lpr = ''; - - if ( ref($_[0]) ) { - my $opt = shift; - $template = $opt->{'template'} || ''; - if ( $agentnums = $opt->{'agentnum'} ) { - $agentnums = [ $agentnums ] unless ref($agentnums); - } - $invoice_from = $opt->{'invoice_from'}; - $balance_over = $opt->{'balance_over'} if $opt->{'balance_over'}; - $notice_name = $opt->{'notice_name'}; - $lpr = $opt->{'lpr'} - } else { - $template = scalar(@_) ? shift : ''; - if ( scalar(@_) && $_[0] ) { - $agentnums = ref($_[0]) ? shift : [ shift ]; - } - $invoice_from = shift if scalar(@_); - $balance_over = shift if scalar(@_) && $_[0] !~ /^\s*$/; - } - my $cust_main = $self->cust_main; - return 'N/A' unless ! $agentnums - or grep { $_ == $cust_main->agentnum } @$agentnums; - - return '' - unless $cust_main->total_owed_date($self->_date) > $balance_over; - - $invoice_from ||= $self->_agent_invoice_from || #XXX should go away - $conf->config('invoice_from', $cust_main->agentnum ); - - my %opt = ( - 'template' => $template, - 'invoice_from' => $invoice_from, - 'notice_name' => ( $notice_name || 'Invoice' ), - ); - my @invoicing_list = $cust_main->invoicing_list; - #$self->email_invoice(\%opt) - $self->email(\%opt) + $self->email($opt) if ( grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list or !@invoicing_list ) && ! $self->invoice_noemail; - $opt{'lpr'} = $lpr; - #$self->print_invoice(\%opt) - $self->print(\%opt) + $self->print($opt) if grep { $_ eq 'POST' } @invoicing_list; #postal #this has never been used post-$ORIGINAL_ISP afaik - $self->fax_invoice(\%opt) + $self->fax_invoice($opt) if grep { $_ eq 'FAX' } @invoicing_list; #fax ''; @@ -1437,16 +1381,17 @@ sub send { =item email HASHREF | [ TEMPLATE [ , INVOICE_FROM ] ] -Emails this invoice. +Sends this invoice to the customer's email destination(s). -Options can be passed as a hashref (recommended) or as a list of up to -two values for templatename and invoice_from. +Options must be passed as a hashref. Positional parameters are no longer +allowed. I<template>, if specified, is the name of a suffix for alternate invoices. -I<invoice_from>, if specified, overrides the default email invoice From: address. +I<invoice_from>, if specified, overrides the default email invoice From: +address. -I<notice_name>, if specified, overrides "Invoice" as the name of the sent document (templates from 10/2009 or newer required) +I<notice_name> is the name of the sent document. =cut @@ -1456,38 +1401,30 @@ sub queueable_email { my $self = qsearchs('cust_bill', { 'invnum' => $opt{invnum} } ) or die "invalid invoice number: " . $opt{invnum}; - my %args = ( 'template' => $opt{template} ); - $args{$_} = $opt{$_} - foreach grep { exists($opt{$_}) && $opt{$_} } - qw( invoice_from notice_name no_coupon ); + my %args = map {$_ => $opt{$_}} + grep { $opt{$_} } + qw( invoice_from notice_name no_coupon template ); my $error = $self->email( \%args ); die $error if $error; } -#sub email_invoice { sub email { my $self = shift; return if $self->hide; my $conf = $self->conf; - - my( $template, $invoice_from, $notice_name, $no_coupon ); - if ( ref($_[0]) ) { - my $opt = shift; - $template = $opt->{'template'} || ''; - $invoice_from = $opt->{'invoice_from'}; - $notice_name = $opt->{'notice_name'} || 'Invoice'; - $no_coupon = $opt->{'no_coupon'} || 0; - } else { - $template = scalar(@_) ? shift : ''; - $invoice_from = shift if scalar(@_); - $notice_name = 'Invoice'; - $no_coupon = 0; + my $opt = shift; + if ($opt and !ref($opt)) { + die "FS::cust_bill::email called with positional parameters"; } - $invoice_from ||= $self->_agent_invoice_from || #XXX should go away - $conf->config('invoice_from', $self->cust_main->agentnum ); + my $template = $opt->{template}; + my $from = delete $opt->{invoice_from}; + + # this is where we set the From: address + $from ||= $self->_agent_invoice_from || #XXX should go away + $conf->config('invoice_from', $self->cust_main->agentnum ); my @invoicing_list = grep { $_ !~ /^(POST|FAX)$/ } $self->cust_main->invoicing_list; @@ -1497,20 +1434,19 @@ sub email { die 'No recipients for customer #'. $self->custnum; } else { #default: better to notify this person than silence - @invoicing_list = ($invoice_from); + @invoicing_list = ($from); } } + # this is where we set the Subject: my $subject = $self->email_subject($template); my $error = send_email( $self->generate_email( - 'from' => $invoice_from, + 'from' => $from, 'to' => [ grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list ], 'subject' => $subject, - 'template' => $template, - 'notice_name' => $notice_name, - 'no_coupon' => $no_coupon, + %$opt, # template, etc. ) ); die "can't email invoice: $error\n" if $error; @@ -1537,12 +1473,12 @@ sub email_subject { eval qq("$subject"); } -=item lpr_data HASHREF | [ TEMPLATE ] +=item lpr_data HASHREF Returns the postscript or plaintext for this invoice as an arrayref. -Options can be passed as a hashref (recommended) or as a single optional value -for template. +Options must be passed as a hashref. Positional parameters are no longer +allowed. I<template>, if specified, is the name of a suffix for alternate invoices. @@ -1553,31 +1489,21 @@ I<notice_name>, if specified, overrides "Invoice" as the name of the sent docume sub lpr_data { my $self = shift; my $conf = $self->conf; - my( $template, $notice_name ); - if ( ref($_[0]) ) { - my $opt = shift; - $template = $opt->{'template'} || ''; - $notice_name = $opt->{'notice_name'} || 'Invoice'; - } else { - $template = scalar(@_) ? shift : ''; - $notice_name = 'Invoice'; + my $opt = shift; + if ($opt and !ref($opt)) { + # nobody does this anyway + die "FS::cust_bill::lpr_data called with positional parameters"; } - my %opt = ( - 'template' => $template, - 'notice_name' => $notice_name, - ); - my $method = $conf->exists('invoice_latex') ? 'print_ps' : 'print_text'; - [ $self->$method( \%opt ) ]; + [ $self->$method( $opt ) ]; } -=item print HASHREF | [ TEMPLATE ] +=item print HASHREF Prints this invoice. -Options can be passed as a hashref (recommended) or as a single optional -value for template. +Options must be passed as a hashref. I<template>, if specified, is the name of a suffix for alternate invoices. @@ -1585,48 +1511,34 @@ I<notice_name>, if specified, overrides "Invoice" as the name of the sent docume =cut -#sub print_invoice { sub print { my $self = shift; return if $self->hide; my $conf = $self->conf; - - my( $template, $notice_name, $lpr ); - if ( ref($_[0]) ) { - my $opt = shift; - $template = $opt->{'template'} || ''; - $notice_name = $opt->{'notice_name'} || 'Invoice'; - $lpr = $opt->{'lpr'} - } else { - $template = scalar(@_) ? shift : ''; - $notice_name = 'Invoice'; - $lpr = ''; + my $opt = shift; + if ($opt and !ref($opt)) { + die "FS::cust_bill::print called with positional parameters"; } - my %opt = ( - 'template' => $template, - 'notice_name' => $notice_name, - ); - + my $lpr = delete $opt->{lpr}; if($conf->exists('invoice_print_pdf')) { # Add the invoice to the current batch. - $self->batch_invoice(\%opt); + $self->batch_invoice($opt); } else { do_print( - $self->lpr_data(\%opt), + $self->lpr_data($opt), 'agentnum' => $self->cust_main->agentnum, 'lpr' => $lpr, ); } } -=item fax_invoice HASHREF | [ TEMPLATE ] +=item fax_invoice HASHREF Faxes this invoice. -Options can be passed as a hashref (recommended) or as a single optional -value for template. +Options must be passed as a hashref. I<template>, if specified, is the name of a suffix for alternate invoices. @@ -1638,15 +1550,9 @@ sub fax_invoice { my $self = shift; return if $self->hide; my $conf = $self->conf; - - my( $template, $notice_name ); - if ( ref($_[0]) ) { - my $opt = shift; - $template = $opt->{'template'} || ''; - $notice_name = $opt->{'notice_name'} || 'Invoice'; - } else { - $template = scalar(@_) ? shift : ''; - $notice_name = 'Invoice'; + my $opt = shift; + if ($opt and !ref($opt)) { + die "FS::cust_bill::fax_invoice called with positional parameters"; } die 'FAX invoice destination not (yet?) supported with plain text invoices.' @@ -1655,12 +1561,7 @@ sub fax_invoice { my $dialstring = $self->cust_main->getfield('fax'); #Check $dialstring? - my %opt = ( - 'template' => $template, - 'notice_name' => $notice_name, - ); - - my $error = send_fax( 'docdata' => $self->lpr_data(\%opt), + my $error = send_fax( 'docdata' => $self->lpr_data($opt), 'dialstring' => $dialstring, ); die $error if $error; @@ -1749,29 +1650,6 @@ sub spool_invoice { ); } -=item send_if_newest [ TEMPLATENAME [ , AGENTNUM [ , INVOICE_FROM ] ] ] - -Like B<send>, but only sends the invoice if it is the newest open invoice for -this customer. - -=cut - -sub send_if_newest { - my $self = shift; - - return '' - if scalar( - grep { $_->owed > 0 } - qsearch('cust_bill', { - 'custnum' => $self->custnum, - #'_date' => { op=>'>', value=>$self->_date }, - 'invnum' => { op=>'>', value=>$self->invnum }, - } ) - ); - - $self->send(@_); -} - =item send_csv OPTION => VALUE, ... Sends invoice as a CSV data-file to a remote host with the specified protocol. diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 7dc6ac4f9..ec13cb967 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -4905,9 +4905,9 @@ sub queueable_print { my %opt = @_; my $self = qsearchs('cust_main', { 'custnum' => $opt{custnum} } ) - or die "invalid customer number: " . $opt{custvnum}; + or die "invalid customer number: " . $opt{custnum}; - my $error = $self->print( $opt{template} ); + my $error = $self->print( { 'template' => $opt{template} } ); die $error if $error; } diff --git a/FS/FS/invoice_conf.pm b/FS/FS/invoice_conf.pm new file mode 100644 index 000000000..043cab03c --- /dev/null +++ b/FS/FS/invoice_conf.pm @@ -0,0 +1,274 @@ +package FS::invoice_conf; + +use strict; +use base qw( FS::Record FS::Conf ); +use FS::Record qw( qsearch qsearchs ); + +=head1 NAME + +FS::invoice_conf - Object methods for invoice_conf records + +=head1 SYNOPSIS + + use FS::invoice_conf; + + $record = new FS::invoice_conf \%hash; + $record = new FS::invoice_conf { 'column' => 'value' }; + + $error = $record->insert; + + $error = $new_record->replace($old_record); + + $error = $record->delete; + + $error = $record->check; + +=head1 DESCRIPTION + +An FS::invoice_conf object represents a set of localized invoice +configuration values. FS::invoice_conf inherits from FS::Record and FS::Conf, +and supports the FS::Conf interface. The following fields are supported: + +=over 4 + +=item confnum - primary key + +=item modenum - L<FS::invoice_mode> foreign key + +=item locale - locale string (see L<FS::Locales>) + +=item notice_name - the title to display on the invoice + +=item subject - subject line of the email + +=item htmlnotes - "notes" section (HTML) + +=item htmlfooter - footer (HTML) + +=item htmlsummary - summary header, for invoices in summary format (HTML) + +=item htmlreturnaddress - return address (HTML) + +=item latexnotes - "notes" section (LaTeX) + +=item latexfooter - footer (LaTeX) + +=item latexsummary - summary header, for invoices in summary format (LaTeX) + +=item latexreturnaddress - return address (LaTeX) + +=item latexcoupon - payment coupon section (LaTeX) + +=item latexsmallfooter - footer for pages after the first (LaTeX) + +=item latextopmargin - top margin + +=item latexheadsep - distance from bottom of header to top of body + +=item latexaddresssep - distance from top of body to customer address + +=item latextextheight - maximum height of invoice body text + +=item latexextracouponspace - additional footer space to allow for coupon + +=item latexcouponfootsep - distance from bottom of coupon content to top +of page footer + +=item latexcouponamountenclosedsep - distance from coupon balance line to +"Amount Enclosed" box + +=item latexcoupontoaddresssep - distance from "Amount Enclosed" box to +coupon mailing address + +=item latexverticalreturnaddress - 'Y' to place the return address below +the company logo rather than beside it + +=item latexcouponaddcompanytoaddress - 'Y' to add the company name to the +address on the payment coupon + +=item logo_png - company logo, as a PNG, for HTML invoices + +=item logo_eps - company logo, as an EPS, for LaTeX invoices + +=item lpr - command to print the invoice (passed on stdin as a PDF) + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF + +Creates a new invoice configuration. To add it to the database, see +L<"insert">. + +=cut + +# the new method can be inherited from FS::Record, if a table method is defined + +sub table { 'invoice_conf'; } + +=item insert + +Adds this record to the database. If there is an error, returns the error, +otherwise returns false. + +=cut + +# slightly special: you can insert/replace the invoice mode this way + +sub insert { + my $self = shift; + if (!$self->modenum) { + my $invoice_mode = FS::invoice_mode->new({ + 'modename' => $self->modename, + 'agentnum' => $self->agentnum, + }); + my $error = $invoice_mode->insert; + return $error if $error; + $self->set('modenum' => $invoice_mode->modenum); + } else { + my $invoice_mode = FS::invoice_mode->by_key($self->modenum); + my $changed = 0; + foreach (qw(agentnum modename)) { + $changed ||= ($invoice_mode->get($_) eq $self->get($_)); + $invoice_mode->set($_, $self->get($_)); + } + my $error = $invoice_mode->replace if $changed; + return $error if $error; + } + $self->SUPER::insert(@_); +} + +=item delete + +Delete this record from the database. + +=cut + +sub delete { + my $self = shift; + my $error = $self->FS::Record::delete; # not Conf::delete + return $error if $error; + my $invoice_mode = FS::invoice_mode->by_key($self->modenum); + if ( $invoice_mode and + FS::invoice_conf->count('modenum = '.$invoice_mode->modenum) == 0 ) { + $error = $invoice_mode->delete; + return $error if $error; + } + ''; +} + +=item replace OLD_RECORD + +Replaces the OLD_RECORD with this one in the database. If there is an error, +returns the error, otherwise returns false. + +=cut + +sub replace { + my $self = shift; + my $error = $self->SUPER::replace(@_); + return $error if $error; + + my $invoice_mode = FS::invoice_mode->by_key($self->modenum); + my $changed = 0; + foreach (qw(agentnum modename)) { + $changed ||= ($invoice_mode->get($_) eq $self->get($_)); + $invoice_mode->set($_, $self->get($_)); + } + $error = $invoice_mode->replace if $changed; + return $error if $error; +} + +=item check + +Checks all fields to make sure this is a valid example. If there is +an error, returns the error, otherwise returns false. Called by the insert +and replace methods. + +=cut + +# the check method should currently be supplied - FS::Record contains some +# data checking routines + +sub check { + my $self = shift; + + my $error = + $self->ut_numbern('confnum') + || $self->ut_number('modenum') + || $self->ut_textn('locale') + || $self->ut_anything('notice_name') + || $self->ut_anything('subject') + || $self->ut_anything('htmlnotes') + || $self->ut_anything('htmlfooter') + || $self->ut_anything('htmlsummary') + || $self->ut_anything('htmlreturnaddress') + || $self->ut_anything('latexnotes') + || $self->ut_anything('latexfooter') + || $self->ut_anything('latexsummary') + || $self->ut_anything('latexcoupon') + || $self->ut_anything('latexsmallfooter') + || $self->ut_anything('latexreturnaddress') + || $self->ut_textn('latextopmargin') + || $self->ut_textn('latexheadsep') + || $self->ut_textn('latexaddresssep') + || $self->ut_textn('latextextheight') + || $self->ut_textn('latexextracouponspace') + || $self->ut_textn('latexcouponfootsep') + || $self->ut_textn('latexcouponamountenclosedsep') + || $self->ut_textn('latexcoupontoaddresssep') + || $self->ut_flag('latexverticalreturnaddress') + || $self->ut_flag('latexcouponaddcompanytoaddress') + || $self->ut_anything('logo_png') + || $self->ut_anything('logo_eps') + ; + return $error if $error; + + $self->SUPER::check; +} + +# hook _config to substitute our own values; let FS::Conf do the rest of +# the interface + +sub _config { + my $self = shift; + # if we fall back, we still want FS::Conf to respect our locale + $self->{locale} = $self->get('locale'); + my ($key, $agentnum, $nodefault) = @_; + # some fields, but not all, start with invoice_ + my $colname = $key; + if ( $key =~ /^invoice_(.*)$/ ) { + $colname = $1; + } + if ( length($self->get($colname)) ) { + return FS::conf->new({ 'name' => $key, + 'value' => $self->get($colname) }); + } else { + return $self->FS::Conf::_config(@_); + } +} + +# disambiguation +sub set { + my $self = shift; + $self->FS::Record::set(@_); +} + +sub exists { + my $self = shift; + $self->FS::Conf::exists(@_); +} + +=back + +=head1 SEE ALSO + +L<FS::Template_Mixin>, L<FS::Record>, schema.html from the base documentation. + +=cut + +1; + diff --git a/FS/FS/invoice_mode.pm b/FS/FS/invoice_mode.pm new file mode 100644 index 000000000..115dd4469 --- /dev/null +++ b/FS/FS/invoice_mode.pm @@ -0,0 +1,157 @@ +package FS::invoice_mode; + +use strict; +use base qw( FS::Record ); +use FS::Record qw( qsearch qsearchs ); +use FS::invoice_conf; + +=head1 NAME + +FS::invoice_mode - Object methods for invoice_mode records + +=head1 SYNOPSIS + + use FS::invoice_mode; + + $record = new FS::invoice_mode \%hash; + $record = new FS::invoice_mode { 'column' => 'value' }; + + $error = $record->insert; + + $error = $new_record->replace($old_record); + + $error = $record->delete; + + $error = $record->check; + +=head1 DESCRIPTION + +An FS::invoice_mode object represents an invoice rendering style. +FS::invoice_mode inherits from FS::Record. The following fields are +currently supported: + +=over 4 + +=item modenum - primary key + +=item agentnum - the agent who owns this invoice mode (can be null) + +=item modename - descriptive name for internal use + + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF + +Creates a new invoice mode. To add the object to the database, +see L<"insert">. + +Note that this stores the hash reference, not a distinct copy of the hash it +points to. You can ask the object for a copy with the I<hash> method. + +=cut + +# the new method can be inherited from FS::Record, if a table method is defined + +sub table { 'invoice_mode'; } + +=item insert + +Adds this record to the database. If there is an error, returns the error, +otherwise returns false. + +=cut + +# the insert method can be inherited from FS::Record + +=item delete + +Delete this record from the database. + +=cut + +# the delete method can be inherited from FS::Record + +=item replace OLD_RECORD + +Replaces the OLD_RECORD with this one in the database. If there is an error, +returns the error, otherwise returns false. + +=cut + +# the replace method can be inherited from FS::Record + +=item check + +Checks all fields to make sure this is a valid example. If there is +an error, returns the error, otherwise returns false. Called by the insert +and replace methods. + +=cut + +# the check method should currently be supplied - FS::Record contains some +# data checking routines + +sub check { + my $self = shift; + + my $error = + $self->ut_numbern('modenum') + || $self->ut_foreign_keyn('agentnum', 'agent', 'agentnum') + || $self->ut_text('modename') + ; + return $error if $error; + + $self->SUPER::check; +} + +=item invoice_conf [ LOCALE ] + +Returns the L<FS::invoice_conf> for this invoice mode, with the specified +locale. If there isn't one with that locale, returns the one with null +locale. If that doesn't exist, returns nothing. + +=cut + +sub invoice_conf { + my $self = shift; + my $locale = shift; + my $invoice_conf; + if ( $locale ) { + $invoice_conf = qsearchs('invoice_conf', { + modenum => $self->modenum, + locale => $locale, + }); + } + $invoice_conf ||= qsearchs('invoice_conf', { + modenum => $self->modenum, + locale => '', + }); + $invoice_conf; +} + +=item agent + +Returns the agent associated with this invoice mode, if any. + +=cut + +sub agent { + my $self = shift; + $self->agentnum ? FS::agent->by_key($self->agentnum) : ''; +} + +=back + +=head1 SEE ALSO + +L<FS::Record>, schema.html from the base documentation. + +=cut + +1; + diff --git a/FS/FS/part_event/Action/cust_bill_email.pm b/FS/FS/part_event/Action/cust_bill_email.pm index 1a3bca4b7..3331a4cb6 100644 --- a/FS/FS/part_event/Action/cust_bill_email.pm +++ b/FS/FS/part_event/Action/cust_bill_email.pm @@ -9,14 +9,22 @@ sub eventtable_hashref { { 'cust_bill' => 1 }; } +sub option_fields { + ( + 'modenum' => { label => 'Invoice mode', + type => 'select-invoice_mode', + }, + ); +} + sub default_weight { 51; } sub do_action { my( $self, $cust_bill ) = @_; - #my $cust_main = $self->cust_main($cust_bill); my $cust_main = $cust_bill->cust_main; + $cust_bill->set('mode' => $self->option('modenum')); $cust_bill->email unless $cust_main->invoice_noemail; } diff --git a/FS/FS/part_event/Action/cust_bill_print.pm b/FS/FS/part_event/Action/cust_bill_print.pm index 6b3e6f460..ea6e0aa8e 100644 --- a/FS/FS/part_event/Action/cust_bill_print.pm +++ b/FS/FS/part_event/Action/cust_bill_print.pm @@ -9,6 +9,14 @@ sub eventtable_hashref { { 'cust_bill' => 1 }; } +sub option_fields { + ( + 'modenum' => { label => 'Invoice mode', + type => 'select-invoice_mode', + }, + ); +} + sub default_weight { 51; } sub do_action { @@ -17,6 +25,7 @@ sub do_action { #my $cust_main = $self->cust_main($cust_bill); my $cust_main = $cust_bill->cust_main; + $cust_bill->set('mode' => $self->option('modenum')); $cust_bill->print; } diff --git a/FS/FS/part_event/Action/cust_bill_print_pdf.pm b/FS/FS/part_event/Action/cust_bill_print_pdf.pm index 6b37f389f..6c01d4294 100644 --- a/FS/FS/part_event/Action/cust_bill_print_pdf.pm +++ b/FS/FS/part_event/Action/cust_bill_print_pdf.pm @@ -9,6 +9,14 @@ sub eventtable_hashref { { 'cust_bill' => 1 }; } +sub option_fields { + ( + 'modenum' => { label => 'Invoice mode', + type => 'select-invoice_mode' + }, + ); +} + sub default_weight { 51; } sub do_action { @@ -20,6 +28,7 @@ sub do_action { my $opt = { $self->options }; $opt->{'notice_name'} ||= 'Invoice'; + $cust_bill->set('mode' => $self->option('modenum')); $cust_bill->batch_invoice($opt); } diff --git a/FS/FS/part_event/Action/cust_bill_send.pm b/FS/FS/part_event/Action/cust_bill_send.pm index 587a7c664..c6928dc00 100644 --- a/FS/FS/part_event/Action/cust_bill_send.pm +++ b/FS/FS/part_event/Action/cust_bill_send.pm @@ -9,11 +9,20 @@ sub eventtable_hashref { { 'cust_bill' => 1 }; } +sub option_fields { + ( + 'modenum' => { label => 'Invoice mode', + type => 'select-invoice_mode', + }, + ); +} + sub default_weight { 50; } sub do_action { my( $self, $cust_bill ) = @_; + $cust_bill->set('mode' => $self->option('modenum')); $cust_bill->send; } diff --git a/FS/FS/part_event/Action/cust_bill_send_agent.pm b/FS/FS/part_event/Action/cust_bill_send_agent.pm index 670a32c5b..bbb757b59 100644 --- a/FS/FS/part_event/Action/cust_bill_send_agent.pm +++ b/FS/FS/part_event/Action/cust_bill_send_agent.pm @@ -7,6 +7,9 @@ sub description { 'Send invoice (email/print/fax) with alternate template, for specific agents'; } +# this event is just cust_bill_send_alternate + an implicit (and inefficient) +# 'agent' condition + sub eventtable_hashref { { 'cust_bill' => 1 }; } @@ -17,6 +20,9 @@ sub option_fields { type => 'select-agent', multiple => 1 }, + 'modenum' => { label => 'Invoice mode', + type => 'select-invoice_mode', + }, 'agent_templatename' => { label => 'Template', type => 'select-invoice_template', }, @@ -32,10 +38,15 @@ sub do_action { #my $cust_main = $self->cust_main($cust_bill); my $cust_main = $cust_bill->cust_main; + my %agentnums = map { $_=>1 } split(/\s*,\s*/, $self->option('agentnum')); + if (keys(%agentnums) and !exists($agentnums{$cust_main->agentnum})) { + return; + } + + $cust_bill->set('mode' => $self->option('modenum')); $cust_bill->send( - $self->option('agent_templatename'), - [ split(/\s*,\s*/, $self->option('agentnum') ) ], - $self->option('agent_invoice_from'), + 'template' => $self->option('agent_templatename'), + 'invoice_from' => $self->option('agent_invoice_from'), ); } diff --git a/FS/FS/part_event/Action/cust_bill_send_alternate.pm b/FS/FS/part_event/Action/cust_bill_send_alternate.pm index cfd9264d8..fb71a5a39 100644 --- a/FS/FS/part_event/Action/cust_bill_send_alternate.pm +++ b/FS/FS/part_event/Action/cust_bill_send_alternate.pm @@ -11,6 +11,8 @@ sub eventtable_hashref { sub option_fields { ( + 'modenum' => { label => 'Invoice mode', + type => 'select-invoice_mode' }, 'templatename' => { label => 'Template', type => 'select-invoice_template', }, @@ -25,7 +27,8 @@ sub do_action { #my $cust_main = $self->cust_main($cust_bill); my $cust_main = $cust_bill->cust_main; - $cust_bill->send( $self->option('templatename') ); + $cust_bill->set('mode' => $self->option('modenum')); + $cust_bill->send({'template' => $self->option('templatename')}); } 1; diff --git a/FS/FS/part_event/Action/cust_bill_send_if_newest.pm b/FS/FS/part_event/Action/cust_bill_send_if_newest.pm index 083da8b08..c744362ce 100644 --- a/FS/FS/part_event/Action/cust_bill_send_if_newest.pm +++ b/FS/FS/part_event/Action/cust_bill_send_if_newest.pm @@ -18,6 +18,9 @@ sub eventtable_hashref { sub option_fields { ( + 'modenum' => { label => 'Invoice mode', + type => 'select-invoice_mode', + }, 'if_newest_templatename' => { label => 'Template', type => 'select-invoice_template', }, @@ -29,10 +32,17 @@ sub default_weight { 50; } sub do_action { my( $self, $cust_bill ) = @_; - #my $cust_main = $self->cust_main($cust_bill); - my $cust_main = $cust_bill->cust_main; - - $cust_bill->send( $self->option('templatename') ); + my $invnum = $cust_bill->invnum; + my $custnum = $cust_bill->custnum; + return '' if scalar( + grep { $_->owed > 0 } + qsearch('cust_bill', { + 'custnum' => $custnum, + 'invnum' => { op=>'>', value=>$invnum }, + }) + ); + $cust_bill->set('mode' => $self->option('modenum')); + $cust_bill->send( 'template' => $self->option('templatename') ); } 1; diff --git a/FS/FS/part_event/Action/cust_bill_send_reminder.pm b/FS/FS/part_event/Action/cust_bill_send_reminder.pm index 073bb8fd3..354f969d4 100644 --- a/FS/FS/part_event/Action/cust_bill_send_reminder.pm +++ b/FS/FS/part_event/Action/cust_bill_send_reminder.pm @@ -11,9 +11,13 @@ sub eventtable_hashref { sub option_fields { ( + 'modenum' => { label => 'Invoice mode', + type => 'select-invoice_mode', + }, + # totally unnecessary, since the invoice mode can set notice_name and lpr, + # but for compatibility... 'notice_name' => 'Reminder name', - #'notes' => { 'label' => 'Reminder notes' }, - #include standard notes? no/prepend/append + #'notes' => { 'label' => 'Reminder notes' }, # invoice mode does this 'lpr' => 'Optional alternate print command', ); } @@ -23,9 +27,7 @@ sub default_weight { 50; } sub do_action { my( $self, $cust_bill ) = @_; - #my $cust_main = $self->cust_main($cust_bill); - #my $cust_main = $cust_bill->cust_main; - + $cust_bill->set('mode' => $self->option('modenum')); $cust_bill->send({ 'notice_name' => $self->option('notice_name'), 'lpr' => $self->option('lpr'), diff --git a/FS/FS/part_event/Action/cust_statement_send.pm b/FS/FS/part_event/Action/cust_statement_send.pm index 74cc48ca8..67a94aaa1 100644 --- a/FS/FS/part_event/Action/cust_statement_send.pm +++ b/FS/FS/part_event/Action/cust_statement_send.pm @@ -19,7 +19,8 @@ sub default_weight { sub do_action { my( $self, $cust_statement ) = @_; - $cust_statement->send( 'statement' ); #XXX configure + $cust_statement->send( 'template' => 'statement' ); #XXX configure + #XXX use an invoice mode? } diff --git a/FS/MANIFEST b/FS/MANIFEST index 0ef0fa39c..ed1a0cdcf 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -698,3 +698,7 @@ FS/svc_alarm.pm t/svc_alarm.t FS/cable_model.pm t/cable_model.t +FS/invoice_mode.pm +t/invoice_mode.t +FS/invoice_conf.pm +t/invoice_conf.t diff --git a/FS/t/invoice_conf.t b/FS/t/invoice_conf.t new file mode 100644 index 000000000..b707fa3f0 --- /dev/null +++ b/FS/t/invoice_conf.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::invoice_conf; +$loaded=1; +print "ok 1\n"; diff --git a/FS/t/invoice_mode.t b/FS/t/invoice_mode.t new file mode 100644 index 000000000..5f945f0d4 --- /dev/null +++ b/FS/t/invoice_mode.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::invoice_mode; +$loaded=1; +print "ok 1\n"; |