#this stuff is SG-specific (i.e. multi-customer company username hack) package FS::ClientAPI::SGNG; use strict; use vars qw( $cache $DEBUG ); use Time::Local qw(timelocal timelocal_nocheck); use Business::CreditCard; use FS::Record qw( qsearch qsearchs ); use FS::Conf; use FS::cust_main; use FS::cust_pkg; use FS::ClientAPI::MyAccount; #qw( payment_info process_payment ) $DEBUG = 0; sub _cache { $cache ||= new FS::ClientAPI_SessionCache( { 'namespace' => 'FS::ClientAPI::MyAccount', #yes, share session_ids } ); } sub ping { #my $p = shift; return { 'pong' => '1' }; } #this might almost be general-purpose sub decompify_pkgs { my $p = shift; my $session = _cache->get($p->{'session_id'}) or return { 'error' => "Can't resume session" }; #better error message my $custnum = $session->{'custnum'}; my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) or return { 'error' => "unknown custnum $custnum" }; return { 'error' => 'Not a complimentary customer' } unless $cust_main->payby eq 'COMP'; my $paydate = $cust_main->paydate =~ /^\S+$/ ? $cust_main->paydate : '2037-12-31'; my ($payyear,$paymonth,$payday) = split (/-/,$paydate); my $date = timelocal(0,0,0,$payday,--$paymonth,$payyear); foreach my $cust_pkg ( qsearch({ 'table' => 'cust_pkg', 'hashref' => { 'custnum' => $custnum, 'bill' => '', }, 'extra_sql' => ' AND '. FS::cust_pkg->active_sql, }) ) { $cust_pkg->set('bill', $date); my $error = $cust_pkg->replace; return { 'error' => $error } if $error; } return { 'error' => '' }; } #find old payment info # (should work just like MyAccount::payment_info, except returns previous info # too) # definitly sg-specific, no one else stores past customer records like this sub previous_payment_info { my $p = shift; my $session = _cache->get($p->{'session_id'}) or return { 'error' => "Can't resume session" }; #better error message my $payment_info = FS::ClientAPI::MyAccount::payment_info($p); my $custnum = $session->{'custnum'}; my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) or return { 'error' => "unknown custnum $custnum" }; #? return $payment_info if $cust_main->payby =~ /^(CARD|DCRD|CHEK|DCHK)$/; foreach my $prev_cust_main ( reverse _previous_cust_main( 'custnum' => $custnum, 'username' => $cust_main->company, 'with_payments' => 1, ) ) { next unless $prev_cust_main->payby =~ /^(CARD|DCRD|CHEK|DCHK)$/; if ( $prev_cust_main->payby =~ /^(CARD|DCRD)$/ ) { #card expired? my ($payyear,$paymonth,$payday) = split (/-/, $cust_main->paydate); my $expdate = timelocal_nocheck(0,0,0,1,$paymonth,$payyear); next if $expdate < time; } elsif ( $prev_cust_main->payby =~ /^(CHEK|DCHK)$/ ) { #any check? or just skip these in favor of cards? } return { %$payment_info, #$prev_cust_main->payment_info _cust_main_payment_info( $prev_cust_main ), 'previous_custnum' => $prev_cust_main->custnum, }; } #still nothing? return an error? return $payment_info; } #this is really FS::cust_main::payment_info, but here for now sub _cust_main_payment_info { my $self = shift; my %return = (); $return{balance} = $self->balance; $return{payname} = $self->payname || ( $self->first. ' '. $self->get('last') ); $return{$_} = $self->get($_) for qw(address1 address2 city state zip); $return{payby} = $self->payby; $return{stateid_state} = $self->stateid_state; if ( $self->payby =~ /^(CARD|DCRD)$/ ) { $return{card_type} = cardtype($self->payinfo); $return{payinfo} = $self->paymask; @return{'month', 'year'} = $self->paydate_monthyear; } if ( $self->payby =~ /^(CHEK|DCHK)$/ ) { my ($payinfo1, $payinfo2) = split '@', $self->paymask; $return{payinfo1} = $payinfo1; $return{payinfo2} = $payinfo2; $return{paytype} = $self->paytype; $return{paystate} = $self->paystate; } #doubleclick protection my $_date = time; $return{paybatch} = "webui-MyAccount-$_date-$$-". rand() * 2**32; %return; } #find old cust_main records (with payments) sub _previous_cust_main { #safety check! return nothing unless we're enabled explicitly return () unless FS::Conf->new->exists('sg-multicustomer_hack'); my %opt = @_; my $custnum = $opt{'custnum'}; my $username = $opt{'username'}; my %search = (); if ( $opt{'with_payments'} ) { $search{'extra_sql'} = ' AND 0 < ( SELECT COUNT(*) FROM cust_pay WHERE cust_pay.custnum = cust_main.custnum ) '; } qsearch( { 'table' => 'cust_main', 'hashref' => { 'company' => { op => 'ILIKE', value => $opt{'username'} }, 'custnum' => { op => '!=', value => $opt{'custnum'} }, }, 'order_by' => 'ORDER BY custnum', %search, } ); } #since we could be passing masked old CC data, need to look that up and #replace it (like regular process_payment does) w/info from old customer record sub previous_process_payment { my $p = shift; return FS::ClientAPI::MyAccount::process_payment($p) unless $p->{'previous_custnum'} && ( ( $p->{'payby'} =~ /^(CARD|DCRD)$/ && $p->{'payinfo'} =~ /x/i ) || ( $p->{'payby'} =~ /^(CHEK|DCHK)$/ && $p->{'payinfo1'} =~ /x/i ) ); my $session = _cache->get($p->{'session_id'}) or return { 'error' => "Can't resume session" }; #better error message my $custnum = $session->{'custnum'}; my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) or return { 'error' => "unknown custnum $custnum" }; #make sure this is really a previous custnum of this customer my @previous_cust_main = grep { $_->custnum == $p->{'previous_custnum'} } _previous_cust_main( 'custnum' => $custnum, 'username' => $cust_main->company, 'with_payments' => 1, ); my $previous_cust_main = $previous_cust_main[0]; #causes problems with old data w/old masking method #if $previous_cust_main->paymask eq $payinfo; if ( $p->{'payby'} =~ /^(CHEK|DCHK)$/ && $p->{'payinfo1'} =~ /x/i ) { ( $p->{'payinfo1'}, $p->{'payinfo2'} ) = split('@', $previous_cust_main->payinfo); } elsif ( $p->{'payby'} =~ /^(CARD|DCRD)$/ && $p->{'payinfo'} =~ /x/i ) { $p->{'payinfo'} = $previous_cust_main->payinfo; } FS::ClientAPI::MyAccount::process_payment($p); } sub previous_payment_info_renew_info { my $p = shift; my $renew_info = renew_info($p); my $payment_info = previous_payment_info($p); return { %$renew_info, %$payment_info, }; } sub previous_process_payment_order_pkg { my $p = shift; my $hr = previous_process_payment($p); return $hr if $hr->{'error'}; order_pkg($p); } sub previous_process_payment_change_pkg { my $p = shift; my $hr = previous_process_payment($p); return $hr if $hr->{'error'}; change_pkg($p); } sub previous_process_payment_order_renew { my $p = shift; my $hr = previous_process_payment($p); return $hr if $hr->{'error'}; order_renew($p); } 1;