1 #this stuff is SG-specific (i.e. multi-customer company username hack)
3 package FS::ClientAPI::SGNG;
6 use vars qw( $cache $DEBUG );
7 use Time::Local qw(timelocal timelocal_nocheck);
8 use Business::CreditCard;
9 use FS::Record qw( qsearch qsearchs );
13 use FS::ClientAPI::MyAccount; #qw( payment_info process_payment )
18 $cache ||= new FS::ClientAPI_SessionCache( {
19 'namespace' => 'FS::ClientAPI::MyAccount', #yes, share session_ids
26 return { 'pong' => '1' };
30 #this might almost be general-purpose
34 my $session = _cache->get($p->{'session_id'})
35 or return { 'error' => "Can't resume session" }; #better error message
37 my $custnum = $session->{'custnum'};
39 my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
40 or return { 'error' => "unknown custnum $custnum" };
42 return { 'error' => 'Not a complimentary customer' }
43 unless $cust_main->payby eq 'COMP';
46 $cust_main->paydate =~ /^\S+$/ ? $cust_main->paydate : '2037-12-31';
48 my ($payyear,$paymonth,$payday) = split (/-/,$paydate);
50 my $date = timelocal(0,0,0,$payday,--$paymonth,$payyear);
52 foreach my $cust_pkg (
53 qsearch({ 'table' => 'cust_pkg',
54 'hashref' => { 'custnum' => $custnum,
57 'extra_sql' => ' AND '. FS::cust_pkg->active_sql,
60 $cust_pkg->set('bill', $date);
61 my $error = $cust_pkg->replace;
62 return { 'error' => $error } if $error;
65 return { 'error' => '' };
69 #find old payment info
70 # (should work just like MyAccount::payment_info, except returns previous info
72 # definitly sg-specific, no one else stores past customer records like this
73 sub previous_payment_info {
76 my $session = _cache->get($p->{'session_id'})
77 or return { 'error' => "Can't resume session" }; #better error message
79 my $payment_info = FS::ClientAPI::MyAccount::payment_info($p);
81 my $custnum = $session->{'custnum'};
83 my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
84 or return { 'error' => "unknown custnum $custnum" };
87 return $payment_info if $cust_main->payby =~ /^(CARD|DCRD|CHEK|DCHK)$/;
89 foreach my $prev_cust_main (
90 reverse _previous_cust_main( 'custnum' => $custnum,
91 'username' => $cust_main->company,
96 next unless $prev_cust_main->payby =~ /^(CARD|DCRD|CHEK|DCHK)$/;
98 if ( $prev_cust_main->payby =~ /^(CARD|DCRD)$/ ) {
101 my ($payyear,$paymonth,$payday) = split (/-/, $cust_main->paydate);
103 my $expdate = timelocal_nocheck(0,0,0,1,$paymonth,$payyear);
105 next if $expdate < time;
107 } elsif ( $prev_cust_main->payby =~ /^(CHEK|DCHK)$/ ) {
109 #any check? or just skip these in favor of cards?
113 return { %$payment_info,
114 #$prev_cust_main->payment_info
115 _cust_main_payment_info( $prev_cust_main ),
116 'previous_custnum' => $prev_cust_main->custnum,
121 #still nothing? return an error?
122 return $payment_info;
126 #this is really FS::cust_main::payment_info, but here for now
127 sub _cust_main_payment_info {
132 $return{balance} = $self->balance;
134 $return{payname} = $self->payname
135 || ( $self->first. ' '. $self->get('last') );
137 $return{$_} = $self->get($_) for qw(address1 address2 city state zip);
139 $return{payby} = $self->payby;
140 $return{stateid_state} = $self->stateid_state;
142 if ( $self->payby =~ /^(CARD|DCRD)$/ ) {
143 $return{card_type} = cardtype($self->payinfo);
144 $return{payinfo} = $self->paymask;
146 @return{'month', 'year'} = $self->paydate_monthyear;
150 if ( $self->payby =~ /^(CHEK|DCHK)$/ ) {
151 my ($payinfo1, $payinfo2) = split '@', $self->paymask;
152 $return{payinfo1} = $payinfo1;
153 $return{payinfo2} = $payinfo2;
154 $return{paytype} = $self->paytype;
155 $return{paystate} = $self->paystate;
159 #doubleclick protection
161 $return{paybatch} = "webui-MyAccount-$_date-$$-". rand() * 2**32;
167 #find old cust_main records (with payments)
168 sub _previous_cust_main {
170 #safety check! return nothing unless we're enabled explicitly
171 return () unless FS::Conf->new->exists('sg-multicustomer_hack');
174 my $custnum = $opt{'custnum'};
175 my $username = $opt{'username'};
178 if ( $opt{'with_payments'} ) {
179 $search{'extra_sql'} =
180 ' AND 0 < ( SELECT COUNT(*) FROM cust_pay
181 WHERE cust_pay.custnum = cust_main.custnum
187 'table' => 'cust_main',
188 'hashref' => { 'company' => { op => 'ILIKE', value => $opt{'username'} },
189 'custnum' => { op => '!=', value => $opt{'custnum'} },
191 'order_by' => 'ORDER BY custnum',
197 #since we could be passing masked old CC data, need to look that up and
198 #replace it (like regular process_payment does) w/info from old customer record
199 sub previous_process_payment {
202 return FS::ClientAPI::MyAccount::process_payment($p)
203 unless $p->{'previous_custnum'}
204 && ( ( $p->{'payby'} =~ /^(CARD|DCRD)$/ && $p->{'payinfo'} =~ /x/i )
205 || ( $p->{'payby'} =~ /^(CHEK|DCHK)$/ && $p->{'payinfo1'} =~ /x/i )
208 my $session = _cache->get($p->{'session_id'})
209 or return { 'error' => "Can't resume session" }; #better error message
211 my $custnum = $session->{'custnum'};
213 my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
214 or return { 'error' => "unknown custnum $custnum" };
216 #make sure this is really a previous custnum of this customer
217 my @previous_cust_main =
218 grep { $_->custnum == $p->{'previous_custnum'} }
219 _previous_cust_main( 'custnum' => $custnum,
220 'username' => $cust_main->company,
221 'with_payments' => 1,
224 my $previous_cust_main = $previous_cust_main[0];
226 #causes problems with old data w/old masking method
227 #if $previous_cust_main->paymask eq $payinfo;
229 if ( $p->{'payby'} =~ /^(CHEK|DCHK)$/ && $p->{'payinfo1'} =~ /x/i ) {
230 ( $p->{'payinfo1'}, $p->{'payinfo2'} ) =
231 split('@', $previous_cust_main->payinfo);
232 } elsif ( $p->{'payby'} =~ /^(CARD|DCRD)$/ && $p->{'payinfo'} =~ /x/i ) {
233 $p->{'payinfo'} = $previous_cust_main->payinfo;
236 FS::ClientAPI::MyAccount::process_payment($p);
240 sub previous_payment_info_renew_info {
242 my $renew_info = renew_info($p);
243 my $payment_info = previous_payment_info($p);
244 return { %$renew_info,
249 sub previous_process_payment_order_pkg {
252 my $hr = previous_process_payment($p);
253 return $hr if $hr->{'error'};
258 sub previous_process_payment_change_pkg {
261 my $hr = previous_process_payment($p);
262 return $hr if $hr->{'error'};
267 sub previous_process_payment_order_renew {
270 my $hr = previous_process_payment($p);
271 return $hr if $hr->{'error'};