3 Business::BatchPayment::Processor - Common interface for batch payment gateways
7 Business::BatchPayment::Processor is a Moose role. Modules implementing
8 the protocol to talk to specific payment processing services should compose
11 There are two general schemes for interacting with a batch payment gateway:
17 In this mode, you (the merchant) assemble a batch of payment requests,
18 including account numbers, and send it to the gateway. At some point in
19 the future, the gateway sends back one or more reply batches indicating the
20 results of processing the payments.
22 When submitting a request batch, the merchant software marks each payment
23 request with a unique transaction ID (the "tid" field). This should be
24 stored somewhere. When the reply batch is processed, each item will have
25 a tid matching its request.
27 Note that some gateways will provide results only for approved payments,
28 or even only for declined payments. It is then up to the merchant software
29 to follow a sensible policy for approving or declining payments whose
30 ultimate status is unconfirmed.
34 In this mode, the gateway transmits a batch file containing approved
35 payments, without those payments being requested. For example, most
36 commercial banks provide check lockbox services and periodically
37 send the merchant a statement of payments received to the lockbox.
38 This statement would be processed as a one-way batch.
44 Most attributes for Processor objects are defined by the module.
50 See L<Business::BatchPayment::Transport>. This must be set before calling
51 submit() or receive(). Some modules will set it themselves; others require a
52 transport to be supplied. Check for the existence of a 'default_transport'
57 Debug level. This may be interpreted in various ways by the module.
61 Communicate with a test server instead of the production gateway. Not all
62 processors support this. Test for the L<Business::BatchPayment::TestMode>
63 role to determine if it's supported.
67 Callback to handle errors when formatting items. Arguments are the Processor
68 object, the Item object, and the error thrown by C<format_item>. The callback
69 can die to stop submitting the batch.
73 Callback to handle errors when parsing items. Arguments are the Processor
74 object, the Item object, and the error thrown by C<parse_item>. The callback
75 can die to stop receiving the batch.
79 =head1 OTHER PARAMETERS
87 If either of these is passed when constructing a Processor object, the
88 transport will be replaced with a File transport with those parameters.
89 Specifying only 'input' will direct 'output' to /dev/null, and vice versa.
99 Send a batch of requests to the gateway. BATCH must be a
100 L<Business::BatchPayment::Batch>. No defined return value,
101 but processors may optionally set the 'processor_id' field
102 on the input batch, which should then be stored and passed
107 Download/otherwise acquire the available confirmed transactions from the
108 gateway, parse them, and return a list of L<Business::BatchPayment::Batch>
109 objects. The items in these batches will have, at minimum, the 'approved'
110 field and either the 'tid' or 'amount' field set. Accepts an optional
111 list of processor_id strings, if required by your processor.
113 =item format_request BATCH
115 Default method to serialize BATCH for submission. Returns the formatted
116 text as a string. By default, this calls C<format_header>, then
117 C<format_item> on each Item in the batch, then C<format_trailer>,
118 joining the output with no delimiters. Override this if your processor
119 needs something different.
121 =item format_header BATCH
123 =item format_trailer BATCH
125 Optional methods to produce the header and trailer sections of the
126 formatted batch. By default these are empty strings.
128 =item format_item ITEM, BATCH
130 Required method (if using the default C<format_request>) to produce
131 the per-item part of the formatted batch. By default this throws
134 =item parse_response DATA
136 Default method to deserialize a received batch. Takes the string received
137 from the gateway, returns a L<Business::BatchPayment::Batch>. By default,
138 calls C<parse_batch_id> on the entire batch, then splits DATA into lines
139 and calls C<parse_item> on each line.
141 =item parse_batch_id DATA
143 Optional method to obtain the batch identifier from the received file.
144 By default this returns nothing.
146 =item parse_item LINE
148 Required method to parse a line from the received file. Should
149 return zero or more L<Business::BatchPayment::Item>s.
157 package Business::BatchPayment::Processor;
162 with 'Business::BatchPayment::Debug';
166 does => 'Business::BatchPayment::Transport',
167 # possibly this part should be a separate role
169 builder => 'default_transport',
172 sub default_transport {
174 die blessed($self). " requires a transport or input/output files\n";
177 has 'on_format_error' => (
180 handles => { format_error => 'execute_method' },
181 default => sub { \&default_on_error },
184 has 'on_parse_error' => (
187 handles => { parse_error => 'execute_method' },
188 default => sub { \&default_on_error },
191 sub default_on_error { #re-throw it
192 my ($self, $item, $error) = @_;
193 $DB::single = 1 if defined($DB::single);
197 # No error callbacks for other parts of this. The per-item case
198 # is special in that it might make sense to continue with the
201 around BUILDARGS => sub {
202 my ($orig, $class, %args) = @_;
203 %args = %{ $class->$orig(%args) }; #process as usual
205 if ( $args{input} or $args{output} ) {
206 $args{transport} = Business::BatchPayment->create( 'Transport::File',
207 input => $args{input},
208 output => $args{output},
214 # override this if your processor produces one-way batches
222 my $request = $self->format_request($batch);
223 warn $request if $self->debug >= 2;
224 $self->transport->upload($request);
229 my @responses = $self->transport->download;
230 warn join("\n\n", @responses) if $self->debug >= 2 and scalar(@responses);
232 foreach my $response (@responses) {
233 push @batches, $self->parse_response($response);
243 my $output = $self->format_header($batch);
245 foreach my $item ($batch->elements) {
247 $output .= $self->format_item($item, $batch);
248 $batch->num( $batch->num + 1 );
250 $self->format_error($item, $_);
253 $output .= $self->format_trailer($batch);
260 my $batch = Business::BatchPayment->create(Batch =>
261 incoming => $self->incoming,
262 batch_id => $self->parse_batch_id($input),
265 while ( $input =~ s/(.*)\n//m ) {
268 $batch->push( $self->parse_item($row) );
269 $batch->num( $batch->num + 1 );
271 $self->parse_error($row, $_);
279 sub format_header { '' };
280 sub format_trailer { '' };
281 sub format_item { die "format_item unimplemented\n" }
283 sub parse_batch_id { '' };
284 sub parse_item { die "parse_item unimplemented\n" }