diff options
Diffstat (limited to 'FS')
-rw-r--r-- | FS/FS/Conf.pm | 6 | ||||
-rw-r--r-- | FS/FS/Mason.pm | 2 | ||||
-rw-r--r-- | FS/FS/Schema.pm | 35 | ||||
-rw-r--r-- | FS/FS/bill_batch.pm | 151 | ||||
-rw-r--r-- | FS/FS/cust_bill.pm | 27 | ||||
-rw-r--r-- | FS/FS/cust_bill_batch.pm | 70 | ||||
-rw-r--r-- | FS/FS/cust_bill_batch_option.pm | 126 |
7 files changed, 416 insertions, 1 deletions
diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 89a36af43..9046b261b 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -1036,6 +1036,12 @@ worry that config_items is freeside-specific and icky. 'type' => 'textarea' }, + { + 'key' => 'invoice_print_pdf', + 'section' => 'invoicing', + 'description' => 'Store postal invoices for download in PDF format rather than printing them directly.', + 'type' => 'checkbox', + }, { 'key' => 'invoice_default_terms', diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index 150a6c081..84c9f7fa9 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -240,6 +240,8 @@ if ( -e $addl_handler_use_file ) { use FS::cgp_rule; use FS::cgp_rule_condition; use FS::cgp_rule_action; + use FS::bill_batch; + use FS::cust_bill_batch; # Sammath Naur if ( $FS::Mason::addl_handler_use ) { diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 859224fb0..01512f9f6 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -2848,6 +2848,41 @@ sub tables_hashref { 'index' => [['listnum'],['svcnum'],['contactemailnum'],['email']], }, + 'bill_batch' => { + 'columns' => [ + 'batchnum', 'serial', '', '', '', '', + 'status', 'char', 'NULL','1', '', '', + 'pdf', 'blob', 'NULL', '', '', '', + ], + 'primary_key' => 'batchnum', + 'unique' => [], + 'index' => [], + }, + + 'cust_bill_batch' => { + 'columns' => [ + 'billbatchnum', 'serial', '', '', '', '', + 'batchnum', 'int', '', '', '', '', + 'invnum', 'int', '', '', '', '', + ], + 'primary_key' => 'billbatchnum', + 'unique' => [], + 'index' => [ [ 'batchnum' ], [ 'invnum' ] ], + }, + + 'cust_bill_batch_option' => { + 'columns' => [ + 'optionnum', 'serial', '', '', '', '', + 'billbatchnum', 'int', '', '', '', '', + 'optionname', 'varchar', '', $char_d, '', '', + 'optionvalue', 'text', 'NULL', '', '', '', + ], + 'primary_key' => 'optionnum', + 'unique' => [], + 'index' => [ [ 'billbatchnum' ], [ 'optionname' ] ], + }, + + # name type nullability length default local diff --git a/FS/FS/bill_batch.pm b/FS/FS/bill_batch.pm new file mode 100644 index 000000000..136db0d9e --- /dev/null +++ b/FS/FS/bill_batch.pm @@ -0,0 +1,151 @@ +package FS::bill_batch; + +use strict; +use vars qw( @ISA $me $DEBUG ); +use FS::Record qw( qsearch qsearchs dbh ); +use FS::cust_bill_batch; + +@ISA = qw( FS::Record ); +$me = '[ FS::bill_batch ]'; +$DEBUG=0; + +sub table { 'bill_batch' } + +sub nohistory_fields { 'pdf' } + +=head1 NAME + +FS::bill_batch - Object methods for bill_batch records + +=head1 SYNOPSIS + + use FS::bill_batch; + + $open_batch = FS::bill_batch->get_open_batch; + + my $pdf = $open_batch->print_pdf; + + $error = $open_batch->close; + +=head1 DESCRIPTION + +An FS::bill_batch object represents a batch of invoices. FS::bill_batch +inherits from FS::Record. The following fields are currently supported: + +=over 4 + +=item batchnum - primary key + +=item status - either 'O' (open) or 'R' (resolved/closed). + +=item pdf - blob field for temporarily storing the invoice as a PDF. + +=back + +=head1 METHODS + +=over 4 + +=item print_pdf + +Typeset the entire batch as a PDF file. Returns the PDF as a string. + +=cut + +sub print_pdf { + eval 'use CAM::PDF'; + warn "Failed to load CAM::PDF: '$@'\n" if $@; + + my $self = shift; + my $job = shift; + $job->update_statustext(0) if $job; + my @invoices = sort { $a->invnum <=> $b->invnum } + qsearch('cust_bill_batch', { batchnum => $self->batchnum }); + return "No invoices in batch ".$self->batchnum.'.' if !@invoices; + + my $pdf_out; + my $num = 0; + foreach my $invoice (@invoices) { + my $part = $invoice->cust_bill->print_pdf({$invoice->options}); + die 'Failed creating PDF from invoice '.$invoice->invnum.'\n' if !$part; + + if($pdf_out) { + $pdf_out->appendPDF(CAM::PDF->new($part)); + } + else { + $pdf_out = CAM::PDF->new($part); + } + if($job) { + # update progressbar + $num++; + my $error = $job->update_statustext(int(100 * $num/scalar(@invoices))); + die $error if $error; + } + } + + return $pdf_out->toPDF; +} + +=item close + +Set the status of the batch to 'R' (resolved). + +=cut + +sub close { + my $self = shift; + $self->status('R'); + return $self->replace; +} + +=back + +=head1 CLASS METHODS + +=item get_open_batch + +Returns the currently open batch. There should only be one at a time. + +=cut + +sub get_open_batch { + my $class = shift; + my $batch = qsearchs('bill_batch', { status => 'O' }); + return $batch if $batch; + $batch = FS::bill_batch->new({status => 'O'}); + my $error = $batch->insert; + die $error if $error; + return $batch; +} + +use Storable 'thaw'; +use Data::Dumper; +use MIME::Base64; + +sub process_print_pdf { + my $job = shift; + my $param = thaw(decode_base64(shift)); + warn Dumper($param) if $DEBUG; + die "no batchnum specified!\n" if ! exists($param->{batchnum}); + my $batch = FS::bill_batch->by_key($param->{batchnum}); + die "batch '$param->{batchnum}' not found!\n" if !$batch; + + my $pdf = $batch->print_pdf($job); + $batch->pdf($pdf); + my $error = $batch->replace; + die $error if $error; +} + + +=back + +=head1 BUGS + +=head1 SEE ALSO + +L<FS::Record>, schema.html from the base documentation. + +=cut + +1; + diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 127053013..a1dab4ac0 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -34,6 +34,8 @@ use FS::cust_bill_pay; use FS::cust_bill_pay_batch; use FS::part_bill_event; use FS::payby; +use FS::bill_batch; +use FS::cust_bill_batch; @ISA = qw( FS::cust_main_Mixin FS::Record ); @@ -1300,7 +1302,13 @@ sub print { 'notice_name' => $notice_name, ); - do_print $self->lpr_data(\%opt); + if($conf->exists('invoice_print_pdf')) { + # Add the invoice to the current batch. + $self->batch_invoice(\%opt); + } + else { + do_print $self->lpr_data(\%opt); + } } =item fax_invoice HASHREF | [ TEMPLATE ] @@ -1346,6 +1354,23 @@ sub fax_invoice { } +=item batch_invoice [ HASHREF ] + +Place this invoice into the open batch (see C<FS::bill_batch>). If there +isn't an open batch, one will be created. + +=cut + +sub batch_invoice { + my ($self, $opt) = @_; + my $batch = FS::bill_batch->get_open_batch; + my $cust_bill_batch = FS::cust_bill_batch->new({ + batchnum => $batch->batchnum, + invnum => $self->invnum, + }); + return $cust_bill_batch->insert($opt); +} + =item ftp_invoice [ TEMPLATENAME ] Sends this invoice data via FTP. diff --git a/FS/FS/cust_bill_batch.pm b/FS/FS/cust_bill_batch.pm new file mode 100644 index 000000000..4569e6bc8 --- /dev/null +++ b/FS/FS/cust_bill_batch.pm @@ -0,0 +1,70 @@ +package FS::cust_bill_batch; + +use strict; +use vars qw( @ISA $me $DEBUG ); +use FS::Record qw( qsearch qsearchs dbh ); + +@ISA = qw( FS::option_Common ); +$me = '[ FS::cust_bill_batch ]'; +$DEBUG=0; + +sub table { 'cust_bill_batch' } + +=head1 NAME + +FS::cust_bill_batch - Object methods for cust_bill_batch records + +=head1 DESCRIPTION + +An FS::cust_bill_batch object represents the inclusion of an invoice in a +processing batch. FS::cust_bill_batch inherits from FS::option_Common. The +following fields are currently supported: + +=over 4 + +=item billbatchnum - primary key + +=item invnum - invoice number (see C<FS::cust_bill>) + +=item batchnum - batchn number (see C<FS::bill_batch>) + +=back + +=head1 METHODS + +=over 4 + +=item bill_batch + +Returns the C<FS::bill_batch> object. + +=cut + +sub bill_batch { + my $self = shift; + FS::bill_batch->by_key($self->batchnum); +} + +=item cust_bill + +Returns the C<FS::cust_bill> object. + +=cut + +sub cust_bill { + my $self = shift; + FS::cust_bill->by_key($self->invnum); +} + +=back + +=head1 BUGS + +=head1 SEE ALSO + +L<FS::Record>, schema.html from the base documentation. + +=cut + +1; + diff --git a/FS/FS/cust_bill_batch_option.pm b/FS/FS/cust_bill_batch_option.pm new file mode 100644 index 000000000..9bba830fd --- /dev/null +++ b/FS/FS/cust_bill_batch_option.pm @@ -0,0 +1,126 @@ +package FS::cust_bill_batch_option; + +use strict; +use vars qw( @ISA ); +use FS::Record qw( qsearch qsearchs ); + +@ISA = qw(FS::Record); + +=head1 NAME + +FS::cust_bill_batch_option - Object methods for cust_bill_batch_option records + +=head1 SYNOPSIS + + use FS::cust_bill_batch_option; + + $record = new FS::cust_bill_batch_option \%hash; + $record = new FS::cust_bill_batch_option { 'column' => 'value' }; + + $error = $record->insert; + + $error = $new_record->replace($old_record); + + $error = $record->delete; + + $error = $record->check; + +=head1 DESCRIPTION + +An FS::cust_bill_batch_option object represents an option key and value for +an invoice batch entry. FS::cust_bill_batch_option inherits from +FS::Record. The following fields are currently supported: + +=over 4 + +=item optionnum - primary key + +=item billbatchnum - + +=item optionname - + +=item optionvalue - + + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF + +Creates a new option. To add the option 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 { 'cust_bill_batch_option'; } + +=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 option. 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('optionnum') + || $self->ut_foreign_key('billbatchnum', 'cust_bill_batch', 'billbatchnum') + || $self->ut_text('optionname') + || $self->ut_textn('optionvalue') + ; + return $error if $error; + + $self->SUPER::check; +} + +=back + +=head1 BUGS + +=head1 SEE ALSO + +L<FS::Record>, schema.html from the base documentation. + +=cut + +1; + |