per-agent invoice PDF batches, RT#13727
[freeside.git] / FS / FS / bill_batch.pm
1 package FS::bill_batch;
2
3 use strict;
4 use vars qw( @ISA $me $DEBUG );
5 use CAM::PDF;
6 use FS::Conf;
7 use FS::Record qw( qsearch qsearchs dbh );
8 use FS::agent;
9 use FS::cust_bill_batch;
10
11 @ISA = qw( FS::Record );
12 $me = '[ FS::bill_batch ]';
13 $DEBUG=0;
14
15 sub table { 'bill_batch' }
16
17 sub nohistory_fields { 'pdf' }
18
19 =head1 NAME
20
21 FS::bill_batch - Object methods for bill_batch records
22
23 =head1 SYNOPSIS
24
25   use FS::bill_batch;
26
27   $open_batch = FS::bill_batch->get_open_batch;
28   
29   my $pdf = $open_batch->print_pdf;
30   
31   $error = $open_batch->close;
32   
33 =head1 DESCRIPTION
34
35 An FS::bill_batch object represents a batch of invoices.  FS::bill_batch 
36 inherits from FS::Record.  The following fields are currently supported:
37
38 =over 4
39
40 =item batchnum - primary key
41
42 =item agentnum - empty for global batches or agent (see L<FS::agent>)
43
44 =item status - either 'O' (open) or 'R' (resolved/closed).
45
46 =item pdf - blob field for temporarily storing the invoice as a PDF.
47
48 =back
49
50 =head1 METHODS
51
52 =over 4
53
54 =item print_pdf
55
56 Typeset the entire batch as a PDF file.  Returns the PDF as a string.
57
58 =cut
59
60 sub print_pdf {
61   my $self = shift;
62   my $job = shift;
63   $job->update_statustext(0) if $job;
64   my @invoices = sort { $a->invnum <=> $b->invnum }
65                  qsearch('cust_bill_batch', { batchnum => $self->batchnum });
66   return "No invoices in batch ".$self->batchnum.'.' if !@invoices;
67
68   my $pdf_out;
69   my $num = 0;
70   foreach my $invoice (@invoices) {
71     my $part = $invoice->cust_bill->print_pdf({$invoice->options});
72     die 'Failed creating PDF from invoice '.$invoice->invnum.'\n' if !$part;
73
74     if($pdf_out) {
75       $pdf_out->appendPDF(CAM::PDF->new($part));
76     }
77     else {
78       $pdf_out = CAM::PDF->new($part);
79     }
80     if($job) {
81       # update progressbar
82       $num++;
83       my $error = $job->update_statustext(int(100 * $num/scalar(@invoices)));
84       die $error if $error;
85     }
86   }
87
88   return $pdf_out->toPDF;
89 }
90
91 =item close
92
93 Set the status of the batch to 'R' (resolved).
94
95 =cut
96
97 sub close {
98   my $self = shift;
99   $self->status('R');
100   return $self->replace;
101 }
102
103 sub check {
104   my $self = shift;
105
106   my $error =
107        $self->ut_numbern('batchnum')
108     || $self->ut_foreign_keyn('agentnum', 'agent', 'agentnum')
109     || $self->ut_enum('status', [ 'O', 'R' ] )
110   ;
111   return $error if $error;
112
113   $self->SUPER::check;
114 }
115
116 =item agent
117
118 Returns the agent (see L<FS::agent>) for this invoice batch.
119
120 =cut
121
122 sub agent {
123   my $self = shift;
124   qsearchs( 'agent', { 'agentnum' => $self->agentnum } );
125 }
126
127 =back
128
129 =head1 SUBROUTINES
130
131 =item process_print_pdf
132
133 =cut
134
135 use Storable 'thaw';
136 use Data::Dumper;
137 use MIME::Base64;
138
139 sub process_print_pdf {
140   my $job = shift;
141   my $param = thaw(decode_base64(shift));
142   warn Dumper($param) if $DEBUG;
143   die "no batchnum specified!\n" if ! exists($param->{batchnum});
144   my $batch = FS::bill_batch->by_key($param->{batchnum});
145   die "batch '$param->{batchnum}' not found!\n" if !$batch;
146
147   my $pdf = $batch->print_pdf($job);
148   $batch->pdf($pdf);
149   my $error = $batch->replace;
150   die $error if $error;
151 }
152
153 =back
154
155 =head1 BUGS
156
157 =head1 SEE ALSO
158
159 L<FS::Record>, schema.html from the base documentation.
160
161 =cut
162
163 1;
164