1 package FS::cust_pay_batch;
4 use vars qw( @ISA $DEBUG );
5 use FS::Record qw(dbh qsearch qsearchs);
7 use FS::part_bill_event qw(due_events);
8 use Business::CreditCard 0.28;
10 @ISA = qw( FS::Record FS::payinfo_Mixin );
12 # 1 is mostly method/subroutine entry and options
13 # 2 traces progress of some operations
14 # 3 is even more information including possibly sensitive data
19 FS::cust_pay_batch - Object methods for batch cards
23 use FS::cust_pay_batch;
25 $record = new FS::cust_pay_batch \%hash;
26 $record = new FS::cust_pay_batch { 'column' => 'value' };
28 $error = $record->insert;
30 $error = $new_record->replace($old_record);
32 $error = $record->delete;
34 $error = $record->check;
36 $error = $record->retriable;
40 An FS::cust_pay_batch object represents a credit card transaction ready to be
41 batched (sent to a processor). FS::cust_pay_batch inherits from FS::Record.
42 Typically called by the collect method of an FS::cust_main object. The
43 following fields are currently supported:
47 =item paybatchnum - primary key (automatically assigned)
49 =item batchnum - indentifies group in batch
51 =item payby - CARD/CHEK/LECB/BILL/COMP
55 =item exp - card expiration
59 =item invnum - invoice
61 =item custnum - customer
63 =item payname - name on card
91 Creates a new record. To add the record to the database, see L<"insert">.
93 Note that this stores the hash reference, not a distinct copy of the hash it
94 points to. You can ask the object for a copy with the I<hash> method.
98 sub table { 'cust_pay_batch'; }
102 Adds this record to the database. If there is an error, returns the error,
103 otherwise returns false.
107 Delete this record from the database. If there is an error, returns the error,
108 otherwise returns false.
110 =item replace OLD_RECORD
112 Replaces the OLD_RECORD with this one in the database. If there is an error,
113 returns the error, otherwise returns false.
117 Checks all fields to make sure this is a valid transaction. If there is
118 an error, returns the error, otherwise returns false. Called by the insert
127 $self->ut_numbern('paybatchnum')
128 || $self->ut_numbern('trancode') #deprecated
129 || $self->ut_money('amount')
130 || $self->ut_number('invnum')
131 || $self->ut_number('custnum')
132 || $self->ut_text('address1')
133 || $self->ut_textn('address2')
134 || $self->ut_text('city')
135 || $self->ut_textn('state')
138 return $error if $error;
140 $self->getfield('last') =~ /^([\w \,\.\-\']+)$/ or return "Illegal last name";
141 $self->setfield('last',$1);
143 $self->first =~ /^([\w \,\.\-\']+)$/ or return "Illegal first name";
146 $error = $self->payinfo_check();
147 return $error if $error;
149 if ( $self->exp eq '' ) {
150 return "Expiration date required"
151 unless $self->payby =~ /^(CHEK|DCHK|LECB|WEST)$/;
154 if ( $self->exp =~ /^(\d{4})[\/\-](\d{1,2})[\/\-](\d{1,2})$/ ) {
155 $self->exp("$1-$2-$3");
156 } elsif ( $self->exp =~ /^(\d{1,2})[\/\-](\d{2}(\d{2})?)$/ ) {
157 if ( length($2) == 4 ) {
158 $self->exp("$2-$1-01");
159 } elsif ( $2 > 98 ) { #should pry change to check for "this year"
160 $self->exp("19$2-$1-01");
162 $self->exp("20$2-$1-01");
165 return "Illegal expiration date";
169 if ( $self->payname eq '' ) {
170 $self->payname( $self->first. " ". $self->getfield('last') );
172 $self->payname =~ /^([\w \,\.\-\']+)$/
173 or return "Illegal billing name";
177 #we have lots of old zips in there... don't hork up batch results cause of em
178 $self->zip =~ /^\s*(\w[\w\-\s]{2,8}\w)\s*$/
179 or return "Illegal zip: ". $self->zip;
182 $self->country =~ /^(\w\w)$/ or return "Illegal country: ". $self->country;
185 #$error = $self->ut_zip('zip', $self->country);
186 #return $error if $error;
188 #check invnum, custnum, ?
195 Returns the customer (see L<FS::cust_main>) for this batched credit card
202 qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
207 Marks the corresponding event (see L<FS::cust_bill_event>) for this batched
208 credit card payment as retriable. Useful if the corresponding financial
209 institution account was declined for temporary reasons and/or a manual
212 Implementation details: For the named customer's invoice, changes the
213 statustext of the 'done' (without statustext) event to 'retriable.'
220 local $SIG{HUP} = 'IGNORE'; #Hmm
221 local $SIG{INT} = 'IGNORE';
222 local $SIG{QUIT} = 'IGNORE';
223 local $SIG{TERM} = 'IGNORE';
224 local $SIG{TSTP} = 'IGNORE';
225 local $SIG{PIPE} = 'IGNORE';
227 my $oldAutoCommit = $FS::UID::AutoCommit;
228 local $FS::UID::AutoCommit = 0;
231 my $cust_bill = qsearchs('cust_bill', { 'invnum' => $self->invnum } )
232 or return "event $self->eventnum references nonexistant invoice $self->invnum";
234 warn "cust_pay_batch->retriable working with self of " . $self->paybatchnum . " and invnum of " . $self->invnum;
235 my @cust_bill_event =
236 sort { $a->part_bill_event->seconds <=> $b->part_bill_event->seconds }
238 $_->part_bill_event->eventcode =~ /\$cust_bill->batch_card/
239 && $_->status eq 'done'
242 $cust_bill->cust_bill_event;
243 # complain loudly if scalar(@cust_bill_event) > 1 ?
244 my $error = $cust_bill_event[0]->retriable;
246 # gah, even with transactions.
247 $dbh->commit if $oldAutoCommit; #well.
248 return "error marking invoice event retriable: $error";
257 There should probably be a configuration file with a list of allowed credit
262 L<FS::cust_main>, L<FS::Record>