X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=FS%2FFS%2FClientAPI%2FMyAccount.pm;h=099affabd12b846904b1c2c595f1dfa97ad906b6;hp=4d24a52634bc810b07c91d9a2a00cde4195eb09c;hb=3800ef16a8afab08bcec3f2f3c9ad7dc6657069d;hpb=67080890d17639954dac3131fe11f49717ef303d diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index 4d24a5263..099affabd 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -7,7 +7,7 @@ use Digest::MD5 qw(md5_hex); use Date::Format; use Business::CreditCard; use Time::Duration; -use FS::CGI qw(small_custview); #doh +use FS::UI::Web::small_custview qw(small_custview); #less doh use FS::UI::Web; use FS::UI::bytecount; use FS::Conf; @@ -17,6 +17,7 @@ use FS::Misc qw(card_types); use FS::ClientAPI_SessionCache; use FS::svc_acct; use FS::svc_domain; +use FS::svc_phone; use FS::svc_external; use FS::part_svc; use FS::cust_main; @@ -24,6 +25,7 @@ use FS::cust_bill; use FS::cust_main_county; use FS::cust_pkg; use FS::payby; +use FS::acct_rt_transaction; use HTML::Entities; #false laziness with FS::cust_main @@ -41,6 +43,7 @@ use vars qw( @cust_main_editable_fields ); ship_first ship_last ship_company ship_address1 ship_address2 ship_city ship_state ship_zip ship_country ship_daytime ship_night ship_fax payby payinfo payname paystart_month paystart_year payissue payip + ss paytype paystate stateid stateid_state ); use subs qw(_provision); @@ -55,28 +58,53 @@ sub _cache { sub login { my $p = shift; - my $svc_domain = qsearchs('svc_domain', { 'domain' => $p->{'domain'} } ) - or return { error => 'Domain '. $p->{'domain'}. ' not found' }; + my $conf = new FS::Conf; - my $svc_acct = qsearchs( 'svc_acct', { 'username' => $p->{'username'}, - 'domsvc' => $svc_domain->svcnum, } - ); - return { error => 'User not found.' } unless $svc_acct; + my $svc_x = ''; + if ( $p->{'domain'} eq 'svc_phone' + && $conf->exists('selfservice_server-phone_login') ) { - my $conf = new FS::Conf; - my $pkg_svc = $svc_acct->cust_svc->pkg_svc; - return { error => 'Only primary user may log in.' } - if $conf->exists('selfservice_server-primary_only') - && ( ! $pkg_svc || $pkg_svc->primary_svc ne 'Y' ); + my $svc_phone = qsearchs( 'svc_phone', { 'phonenum' => $p->{'username'} } ); + return { error => 'Number not found.' } unless $svc_phone; + + #XXX? + #my $pkg_svc = $svc_acct->cust_svc->pkg_svc; + #return { error => 'Only primary user may log in.' } + # if $conf->exists('selfservice_server-primary_only') + # && ( ! $pkg_svc || $pkg_svc->primary_svc ne 'Y' ); + + return { error => 'Incorrect PIN.' } + unless $svc_phone->check_pin($p->{'password'}); + + $svc_x = $svc_phone; + + } else { + + my $svc_domain = qsearchs('svc_domain', { 'domain' => $p->{'domain'} } ) + or return { error => 'Domain '. $p->{'domain'}. ' not found' }; + + my $svc_acct = qsearchs( 'svc_acct', { 'username' => $p->{'username'}, + 'domsvc' => $svc_domain->svcnum, } + ); + return { error => 'User not found.' } unless $svc_acct; - return { error => 'Incorrect password.' } - unless $svc_acct->check_password($p->{'password'}); + my $pkg_svc = $svc_acct->cust_svc->pkg_svc; + return { error => 'Only primary user may log in.' } + if $conf->exists('selfservice_server-primary_only') + && ( ! $pkg_svc || $pkg_svc->primary_svc ne 'Y' ); + + return { error => 'Incorrect password.' } + unless $svc_acct->check_password($p->{'password'}); + + $svc_x = $svc_acct; + + } my $session = { - 'svcnum' => $svc_acct->svcnum, + 'svcnum' => $svc_x->svcnum, }; - my $cust_pkg = $svc_acct->cust_svc->cust_pkg; + my $cust_pkg = $svc_x->cust_svc->cust_pkg; if ( $cust_pkg ) { my $cust_main = $cust_pkg->cust_main; $session->{'custnum'} = $cust_main->custnum; @@ -87,7 +115,8 @@ sub login { $session_id = md5_hex(md5_hex(time(). {}. rand(). $$)) } until ( ! defined _cache->get($session_id) ); #just in case - _cache->set( $session_id, $session, '1 hour' ); + my $timeout = $conf->config('selfservice-session_timeout') || '1 hour'; + _cache->set( $session_id, $session, $timeout ); return { 'error' => '', 'session_id' => $session_id, @@ -111,6 +140,14 @@ sub customer_info { return { 'error' => $session } if $context eq 'error'; my %return; + + my $conf = new FS::Conf; + if ($conf->exists('cust_main-require_address2')) { + $return{'require_address2'} = '1'; + }else{ + $return{'require_address2'} = ''; + } + if ( $custnum ) { #customer record my $search = { 'custnum' => $custnum }; @@ -131,7 +168,6 @@ sub customer_info { } $cust_main->open_cust_bill; $return{open_invoices} = \@open; - my $conf = new FS::Conf; $return{small_custview} = small_custview( $cust_main, $conf->config('countrydefault') ); @@ -152,11 +188,24 @@ sub customer_info { 0 < ( grep { $_ eq 'POST' } $cust_main->invoicing_list ); if (scalar($conf->config('support_packages'))) { - my $support = 0; + my @support_services = (); foreach ($cust_main->support_services) { - $support += $_->svc_x->seconds; + my $seconds = $_->svc_x->seconds; + my $time_remaining = (($seconds < 0) ? '-' : '' ). + int(abs($seconds)/3600)."h". + sprintf("%02d",(abs($seconds)%3600)/60)."m"; + my $cust_pkg = $_->cust_pkg; + my $pkgnum = ''; + my $pkg = ''; + $pkgnum = $cust_pkg->pkgnum if $cust_pkg; + $pkg = $cust_pkg->part_pkg->pkg if $cust_pkg; + push @support_services, { svcnum => $_->svcnum, + time => $time_remaining, + pkgnum => $pkgnum, + pkg => $pkg, + }; } - $return{support_time} = (($support < 0) ? '-' : '' ). int(abs($support)/3600)."h".sprintf("%02d",(abs($support)%3600)/60)."m"; + $return{support_services} = \@support_services; } } elsif ( $session->{'svcnum'} ) { #no customer record @@ -193,13 +242,46 @@ sub edit_info { $new->set( $_ => $p->{$_} ) foreach grep { exists $p->{$_} } @cust_main_editable_fields; - if ( $p->{'payby'} =~ /^(CARD|DCRD)$/ ) { + my $payby = ''; + if (exists($p->{'payby'})) { + $p->{'payby'} =~ /^([A-Z]{4})$/ + or return { 'error' => "illegal_payby " . $p->{'payby'} }; + $payby = $1; + } + + if ( $payby =~ /^(CARD|DCRD)$/ ) { + $new->paydate($p->{'year'}. '-'. $p->{'month'}. '-01'); + if ( $new->payinfo eq $cust_main->paymask ) { $new->payinfo($cust_main->payinfo); } else { - $new->paycvv($p->{'paycvv'}); + $new->payinfo($p->{'payinfo'}); } + + $new->set( 'payby' => $p->{'auto'} ? 'CARD' : 'DCRD' ); + + }elsif ( $payby =~ /^(CHEK|DCHK)$/ ) { + my $payinfo; + $p->{'payinfo1'} =~ /^([\dx]+)$/ + or return { 'error' => "illegal account number ". $p->{'payinfo1'} }; + my $payinfo1 = $1; + $p->{'payinfo2'} =~ /^([\dx]+)$/ + or return { 'error' => "illegal ABA/routing number ". $p->{'payinfo2'} }; + my $payinfo2 = $1; + $payinfo = $payinfo1. '@'. $payinfo2; + + if ( $payinfo eq $cust_main->paymask ) { + $new->payinfo($cust_main->payinfo); + } else { + $new->payinfo($payinfo); + } + + $new->set( 'payby' => $p->{'auto'} ? 'CHEK' : 'DCHK' ); + + }elsif ( $payby =~ /^(BILL)$/ ) { + } elsif ( $payby ) { #notyet ready + return { 'error' => "unknown payby $payby" }; } my @invoicing_list; @@ -250,6 +332,8 @@ sub payment_info { 'paytypes' => [ @FS::cust_main::paytypes ], + 'paybys' => [ $conf->config('signup_server-payby') ], + 'stateid_label' => FS::Msgcat::_gettext('stateid'), 'stateid_state_label' => FS::Msgcat::_gettext('stateid_state'), @@ -283,14 +367,14 @@ sub payment_info { if ( $cust_main->payby =~ /^(CARD|DCRD)$/ ) { $return{card_type} = cardtype($cust_main->payinfo); - $return{payinfo} = $cust_main->payinfo; + $return{payinfo} = $cust_main->paymask; @return{'month', 'year'} = $cust_main->paydate_monthyear; } if ( $cust_main->payby =~ /^(CHEK|DCHK)$/ ) { - my ($payinfo1, $payinfo2) = split '@', $cust_main->payinfo; + my ($payinfo1, $payinfo2) = split '@', $cust_main->paymask; $return{payinfo1} = $payinfo1; $return{payinfo2} = $payinfo2; $return{paytype} = $cust_main->paytype; @@ -340,21 +424,28 @@ sub process_payment { my $paycvv = ''; if ( $payby eq 'CHEK' || $payby eq 'DCHK' ) { - $p->{'payinfo1'} =~ /^(\d+)$/ + $p->{'payinfo1'} =~ /^([\dx]+)$/ or return { 'error' => "illegal account number ". $p->{'payinfo1'} }; my $payinfo1 = $1; - $p->{'payinfo2'} =~ /^(\d+)$/ + $p->{'payinfo2'} =~ /^([\dx]+)$/ or return { 'error' => "illegal ABA/routing number ". $p->{'payinfo2'} }; my $payinfo2 = $1; $payinfo = $payinfo1. '@'. $payinfo2; + + $payinfo = $cust_main->payinfo + if $cust_main->paymask eq $payinfo; } elsif ( $payby eq 'CARD' || $payby eq 'DCRD' ) { $payinfo = $p->{'payinfo'}; - $payinfo =~ s/\D//g; + $payinfo =~ s/[^\dx]//g; $payinfo =~ /^(\d{13,16})$/ or return { 'error' => gettext('invalid_card') }; # . ": ". $self->payinfo $payinfo = $1; + + $payinfo = $cust_main->payinfo + if $cust_main->paymask eq $payinfo; + validate($payinfo) or return { 'error' => gettext('invalid_card') }; # . ": ". $self->payinfo return { 'error' => gettext('unknown_card_type') } @@ -418,6 +509,15 @@ sub process_payment { } +sub process_payment_order_pkg { + my $p = shift; + + my $hr = process_payment($p); + return $hr if $hr->{'error'}; + + order_pkg($p); +} + sub process_prepay { my $p = shift; @@ -642,8 +742,48 @@ sub list_svcs { } +sub _list_svc_usage { + my($svc_acct, $begin, $end) = @_; + my @usage = (); + foreach my $part_export ( + map { qsearch ( 'part_export', { 'exporttype' => $_ } ) } + qw (sqlradius sqlradius_withdomain') + ) { + + push @usage, @ { $part_export->usage_sessions($begin, $end, $svc_acct) }; + } + (@usage); +} + sub list_svc_usage { - my $p = shift; + _usage_details(\&_list_svc_usage, @_); +} + +sub _list_support_usage { + my($svc_acct, $begin, $end) = @_; + my @usage = (); + foreach ( grep { $begin <= $_->_date && $_->_date <= $end } + qsearch('acct_rt_transaction', { 'svcnum' => $svc_acct->svcnum }) + ) { + push @usage, { 'seconds' => $_->seconds, + 'support' => $_->support, + '_date' => $_->_date, + 'id' => $_->transaction_id, + 'creator' => $_->creator, + 'subject' => $_->subject, + 'status' => $_->status, + 'ticketid' => $_->ticketid, + }; + } + (@usage); +} + +sub list_support_usage { + _usage_details(\&_list_support_usage, @_); +} + +sub _usage_details { + my ($callback, $p) = (shift,shift); my($context, $session, $custnum) = _custoragent_session_custnum($p); return { 'error' => $session } if $context eq 'error'; @@ -663,18 +803,8 @@ sub list_svc_usage { $p->{beginning} = $svc_acct->cust_svc->cust_pkg->last_bill; $p->{ending} = $end; } - my @usage = (); - foreach my $part_export ( - map { qsearch ( 'part_export', { 'exporttype' => $_ } ) } - qw (sqlradius sqlradius_withdomain') - ) { - - push @usage, @ { $part_export->usage_sessions($p->{beginning}, - $p->{ending}, - $svc_acct) - }; - } + my (@usage) = &$callback($svc_acct,$p->{beginning},$p->{ending}); #kinda false laziness with FS::cust_main::bill, but perhaps #we should really change this bit to DateTime and DateTime::Duration @@ -710,7 +840,6 @@ sub list_svc_usage { my $previous = timelocal_nocheck($psec,$pmin,$phour,$pmday,$pmon,$pyear); my $next = timelocal_nocheck($nsec,$nmin,$nhour,$nmday,$nmon,$nyear); - { 'error' => '', 'svcnum' => $p->{svcnum}, @@ -733,6 +862,7 @@ sub order_pkg { my $cust_main = qsearchs('cust_main', $search ) or return { 'error' => "unknown custnum $custnum" }; + my $status = $cust_main->status; #false laziness w/ClientAPI/Signup.pm my $cust_pkg = new FS::cust_pkg ( { @@ -804,7 +934,7 @@ sub order_pkg { my $conf = new FS::Conf; if ( $conf->exists('signup_server-realtime') ) { - my $bill_error = _do_bop_realtime( $cust_main ); + my $bill_error = _do_bop_realtime( $cust_main, $status ); if ($bill_error) { $cust_pkg->cancel('quiet'=>1); @@ -832,6 +962,7 @@ sub change_pkg { my $cust_main = qsearchs('cust_main', $search ) or return { 'error' => "unknown custnum $custnum" }; + my $status = $cust_main->status; my $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $p->{pkgnum} } ) or return { 'error' => "unknown package $p->{pkgnum}" }; @@ -845,7 +976,7 @@ sub change_pkg { my $conf = new FS::Conf; if ( $conf->exists('signup_server-realtime') ) { - my $bill_error = _do_bop_realtime( $cust_main ); + my $bill_error = _do_bop_realtime( $cust_main, $status ); if ($bill_error) { $newpkg[0]->suspend; @@ -873,6 +1004,7 @@ sub order_recharge { my $cust_main = qsearchs('cust_main', $search ) or return { 'error' => "unknown custnum $custnum" }; + my $status = $cust_main->status; my $cust_svc = qsearchs( 'cust_svc', { 'svcnum' => $p->{'svcnum'} } ) or return { 'error' => "unknown service " . $p->{'svcnum'} }; @@ -896,7 +1028,7 @@ sub order_recharge { my $conf = new FS::Conf; if ( $conf->exists('signup_server-realtime') && !$bill_error ) { - $bill_error = _do_bop_realtime( $cust_main ); + $bill_error = _do_bop_realtime( $cust_main, $status ); if ($bill_error) { return $bill_error; @@ -916,7 +1048,7 @@ sub order_recharge { } sub _do_bop_realtime { - my ($cust_main) = @_; + my ($cust_main, $status) = (shift, shift); my $old_balance = $cust_main->balance; @@ -926,10 +1058,14 @@ sub _do_bop_realtime { if ( $cust_main->balance > $old_balance && $cust_main->balance > 0 - && $cust_main->payby !~ /^(BILL|DCRD|DCHK)$/ ) { + && ( $cust_main->payby !~ /^(BILL|DCRD|DCHK)$/ ? + 1 : $status eq 'suspended' ) ) { #this makes sense. credit is "un-doing" the invoice + my $conf = new FS::Conf; $cust_main->credit( sprintf("%.2f", $cust_main->balance - $old_balance ), - 'self-service decline' ); + 'self-service decline', + 'reason_type' => $conf->config('signup_credit_type'), + ); $cust_main->apply_credits( 'order' => 'newest' ); return { 'error' => '_decline', 'bill_error' => $bill_error }; @@ -966,10 +1102,17 @@ sub provision_acct { if $p->{'_password'} ne $p->{'_password2'}; return { 'error' => gettext('empty_password') } unless length($p->{'_password'}); + + if ($p->{'domsvc'}) { + my %domains = domain_select_hash FS::svc_acct(map { $_ => $p->{$_} } + qw ( svcpart pkgnum ) ); + return { 'error' => gettext('invalid_domain') } + unless ($domains{$p->{'domsvc'}}); + } _provision( 'FS::svc_acct', - [qw(username _password)], - [qw(username _password)], + [qw(username _password domsvc)], + [qw(username _password domsvc)], $p, @_ );