have the UI use full country names, and state names outside the US...
[freeside.git] / FS / FS / cust_pay_void.pm
1 package FS::cust_pay_void; 
2 use strict;
3 use vars qw( @ISA );
4 use Business::CreditCard;
5 use FS::UID qw(getotaker);
6 use FS::Record qw(qsearchs dbh fields); # qsearch );
7 use FS::cust_pay;
8 #use FS::cust_bill;
9 #use FS::cust_bill_pay;
10 #use FS::cust_pay_refund;
11 #use FS::cust_main;
12
13 @ISA = qw( FS::Record );
14
15 =head1 NAME
16
17 FS::cust_pay_void - Object methods for cust_pay_void objects
18
19 =head1 SYNOPSIS
20
21   use FS::cust_pay_void;
22
23   $record = new FS::cust_pay_void \%hash;
24   $record = new FS::cust_pay_void { 'column' => 'value' };
25
26   $error = $record->insert;
27
28   $error = $new_record->replace($old_record);
29
30   $error = $record->delete;
31
32   $error = $record->check;
33
34 =head1 DESCRIPTION
35
36 An FS::cust_pay_void object represents a voided payment.  The following fields
37 are currently supported:
38
39 =over 4
40
41 =item paynum - primary key (assigned automatically for new payments)
42
43 =item custnum - customer (see L<FS::cust_main>)
44
45 =item paid - Amount of this payment
46
47 =item _date - specified as a UNIX timestamp; see L<perlfunc/"time">.  Also see
48 L<Time::Local> and L<Date::Parse> for conversion functions.
49
50 =item payby - `CARD' (credit cards), `CHEK' (electronic check/ACH),
51 `LECB' (phone bill billing), `BILL' (billing), `CASH' (cash),
52 `WEST' (Western Union), `MCRD' (Manual credit card), or `COMP' (free)
53
54 =item payinfo - card number, check #, or comp issuer (4-8 lowercase alphanumerics; think username), respectively
55
56 =item paybatch - text field for tracking card processing
57
58 =item closed - books closed flag, empty or `Y'
59
60 =item void_date
61
62 =item reason
63
64 =back
65
66 =head1 METHODS
67
68 =over 4 
69
70 =item new HASHREF
71
72 Creates a new payment.  To add the payment to the databse, see L<"insert">.
73
74 =cut
75
76 sub table { 'cust_pay_void'; }
77
78 =item insert
79
80 Adds this voided payment to the database.
81
82 =item unvoid 
83
84 "Un-void"s this payment: Deletes the voided payment from the database and adds
85 back a normal payment.
86
87 =cut
88
89 sub unvoid {
90   my $self = shift;
91
92   local $SIG{HUP} = 'IGNORE';
93   local $SIG{INT} = 'IGNORE';
94   local $SIG{QUIT} = 'IGNORE';
95   local $SIG{TERM} = 'IGNORE';
96   local $SIG{TSTP} = 'IGNORE';
97   local $SIG{PIPE} = 'IGNORE';
98
99   my $oldAutoCommit = $FS::UID::AutoCommit;
100   local $FS::UID::AutoCommit = 0;
101   my $dbh = dbh;
102
103   my $cust_pay = new FS::cust_pay ( {
104     map { $_ => $self->get($_) } fields('cust_pay')
105   } );
106   my $error = $cust_pay->insert;
107   if ( $error ) {
108     $dbh->rollback if $oldAutoCommit;
109     return $error;
110   }
111
112   $error = $self->delete;
113   if ( $error ) {
114     $dbh->rollback if $oldAutoCommit;
115     return $error;
116   }
117
118   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
119
120   '';
121
122 }
123
124 =item delete
125
126 Deletes this voided payment.  You probably don't want to use this directly; see
127 the B<unvoid> method to add the original payment back.
128
129 =item replace OLD_RECORD
130
131 Currently unimplemented.
132
133 =cut
134
135 sub replace {
136    return "Can't modify voided payments!";
137 }
138
139 =item check
140
141 Checks all fields to make sure this is a valid voided payment.  If there is an
142 error, returns the error, otherwise returns false.  Called by the insert
143 method.
144
145 =cut
146
147 sub check {
148   my $self = shift;
149
150   my $error =
151     $self->ut_numbern('paynum')
152     || $self->ut_numbern('custnum')
153     || $self->ut_money('paid')
154     || $self->ut_number('_date')
155     || $self->ut_textn('paybatch')
156     || $self->ut_enum('closed', [ '', 'Y' ])
157     || $self->ut_numbern('void_date')
158     || $self->ut_textn('reason')
159   ;
160   return $error if $error;
161
162   return "paid must be > 0 " if $self->paid <= 0;
163
164   return "unknown cust_main.custnum: ". $self->custnum
165     unless $self->invnum
166            || qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
167
168   $self->void_date(time) unless $self->void_date;
169
170   $self->payby =~ /^(CARD|CHEK|LECB|BILL|COMP|PREP|CASH|WEST|MCRD)$/
171     or return "Illegal payby";
172   $self->payby($1);
173
174   #false laziness with cust_refund::check
175   if ( $self->payby eq 'CARD' ) {
176     my $payinfo = $self->payinfo;
177     $payinfo =~ s/\D//g;
178     $self->payinfo($payinfo);
179     if ( $self->payinfo ) {
180       $self->payinfo =~ /^(\d{13,16})$/
181         or return "Illegal (mistyped?) credit card number (payinfo)";
182       $self->payinfo($1);
183       validate($self->payinfo) or return "Illegal credit card number";
184       return "Unknown card type" if cardtype($self->payinfo) eq "Unknown";
185     } else {
186       $self->payinfo('N/A');
187     }
188
189   } else {
190     $error = $self->ut_textn('payinfo');
191     return $error if $error;
192   }
193
194   $self->otaker(getotaker);
195
196   $self->SUPER::check;
197 }
198
199 =item cust_main
200
201 Returns the parent customer object (see L<FS::cust_main>).
202
203 =cut
204
205 sub cust_main {
206   my $self = shift;
207   qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
208 }
209
210 =item payinfo_masked
211
212 Returns a "masked" payinfo field with all but the last four characters replaced
213 by 'x'es.  Useful for displaying credit cards.
214
215 =cut
216
217 sub payinfo_masked {
218   my $self = shift;
219   my $payinfo = $self->payinfo;
220   'x'x(length($payinfo)-4). substr($payinfo,(length($payinfo)-4));
221 }
222
223 =back
224
225 =head1 BUGS
226
227 Delete and replace methods.
228
229 =head1 SEE ALSO
230
231 L<FS::cust_pay>, L<FS::Record>, schema.html from the base documentation.
232
233 =cut
234
235 1;
236