1 package FS::cust_pay_batch;
4 use vars qw( @ISA $DEBUG );
5 use FS::Record qw(dbh qsearch qsearchs);
7 use Business::CreditCard 0.28;
9 @ISA = qw( FS::Record FS::payinfo_Mixin );
11 # 1 is mostly method/subroutine entry and options
12 # 2 traces progress of some operations
13 # 3 is even more information including possibly sensitive data
18 FS::cust_pay_batch - Object methods for batch cards
22 use FS::cust_pay_batch;
24 $record = new FS::cust_pay_batch \%hash;
25 $record = new FS::cust_pay_batch { 'column' => 'value' };
27 $error = $record->insert;
29 $error = $new_record->replace($old_record);
31 $error = $record->delete;
33 $error = $record->check;
35 $error = $record->retriable;
39 An FS::cust_pay_batch object represents a credit card transaction ready to be
40 batched (sent to a processor). FS::cust_pay_batch inherits from FS::Record.
41 Typically called by the collect method of an FS::cust_main object. The
42 following fields are currently supported:
46 =item paybatchnum - primary key (automatically assigned)
48 =item batchnum - indentifies group in batch
50 =item payby - CARD/CHEK/LECB/BILL/COMP
54 =item exp - card expiration
58 =item invnum - invoice
60 =item custnum - customer
62 =item payname - name on card
90 Creates a new record. To add the record to the database, see L<"insert">.
92 Note that this stores the hash reference, not a distinct copy of the hash it
93 points to. You can ask the object for a copy with the I<hash> method.
97 sub table { 'cust_pay_batch'; }
101 Adds this record to the database. If there is an error, returns the error,
102 otherwise returns false.
106 Delete this record from the database. If there is an error, returns the error,
107 otherwise returns false.
109 =item replace OLD_RECORD
111 Replaces the OLD_RECORD with this one in the database. If there is an error,
112 returns the error, otherwise returns false.
116 Checks all fields to make sure this is a valid transaction. If there is
117 an error, returns the error, otherwise returns false. Called by the insert
126 $self->ut_numbern('paybatchnum')
127 || $self->ut_numbern('trancode') #deprecated
128 || $self->ut_money('amount')
129 || $self->ut_number('invnum')
130 || $self->ut_number('custnum')
131 || $self->ut_text('address1')
132 || $self->ut_textn('address2')
133 || $self->ut_text('city')
134 || $self->ut_textn('state')
137 return $error if $error;
139 $self->getfield('last') =~ /^([\w \,\.\-\']+)$/ or return "Illegal last name";
140 $self->setfield('last',$1);
142 $self->first =~ /^([\w \,\.\-\']+)$/ or return "Illegal first name";
145 $error = $self->payinfo_check();
146 return $error if $error;
148 if ( $self->exp eq '' ) {
149 return "Expiration date required"
150 unless $self->payby =~ /^(CHEK|DCHK|LECB|WEST)$/;
153 if ( $self->exp =~ /^(\d{4})[\/\-](\d{1,2})[\/\-](\d{1,2})$/ ) {
154 $self->exp("$1-$2-$3");
155 } elsif ( $self->exp =~ /^(\d{1,2})[\/\-](\d{2}(\d{2})?)$/ ) {
156 if ( length($2) == 4 ) {
157 $self->exp("$2-$1-01");
158 } elsif ( $2 > 98 ) { #should pry change to check for "this year"
159 $self->exp("19$2-$1-01");
161 $self->exp("20$2-$1-01");
164 return "Illegal expiration date";
168 if ( $self->payname eq '' ) {
169 $self->payname( $self->first. " ". $self->getfield('last') );
171 $self->payname =~ /^([\w \,\.\-\']+)$/
172 or return "Illegal billing name";
176 #we have lots of old zips in there... don't hork up batch results cause of em
177 $self->zip =~ /^\s*(\w[\w\-\s]{2,8}\w)\s*$/
178 or return "Illegal zip: ". $self->zip;
181 $self->country =~ /^(\w\w)$/ or return "Illegal country: ". $self->country;
184 #$error = $self->ut_zip('zip', $self->country);
185 #return $error if $error;
187 #check invnum, custnum, ?
194 Returns the customer (see L<FS::cust_main>) for this batched credit card
201 qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
206 Marks the corresponding event (see L<FS::cust_bill_event>) for this batched
207 credit card payment as retriable. Useful if the corresponding financial
208 institution account was declined for temporary reasons and/or a manual
211 Implementation details: For the named customer's invoice, changes the
212 statustext of the 'done' (without statustext) event to 'retriable.'
219 local $SIG{HUP} = 'IGNORE'; #Hmm
220 local $SIG{INT} = 'IGNORE';
221 local $SIG{QUIT} = 'IGNORE';
222 local $SIG{TERM} = 'IGNORE';
223 local $SIG{TSTP} = 'IGNORE';
224 local $SIG{PIPE} = 'IGNORE';
226 my $oldAutoCommit = $FS::UID::AutoCommit;
227 local $FS::UID::AutoCommit = 0;
230 my $cust_bill = qsearchs('cust_bill', { 'invnum' => $self->invnum } )
231 or return "event $self->eventnum references nonexistant invoice $self->invnum";
233 warn "cust_pay_batch->retriable working with self of " . $self->paybatchnum . " and invnum of " . $self->invnum;
234 my @cust_bill_event =
235 sort { $a->part_bill_event->seconds <=> $b->part_bill_event->seconds }
237 $_->part_bill_event->eventcode =~ /\$cust_bill->batch_card/
238 && $_->status eq 'done'
241 $cust_bill->cust_bill_event;
242 # complain loudly if scalar(@cust_bill_event) > 1 ?
243 my $error = $cust_bill_event[0]->retriable;
245 # gah, even with transactions.
246 $dbh->commit if $oldAutoCommit; #well.
247 return "error marking invoice event retriable: $error";
256 There should probably be a configuration file with a list of allowed credit
261 L<FS::cust_main>, L<FS::Record>