X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=FS%2FFS%2FClientAPI%2FMyAccount.pm;h=ecabe31c79d0f80913b89a6605ff40d1b96b8ee8;hp=181c994c4d20da4acfb11c954c67a8c1e8016127;hb=d6741df87df9e3352d7ae47a02d0e3f46154fef9;hpb=aaace663fe7ff34479a707f3976c32010e4a1845 diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index 181c994c4..ecabe31c7 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -32,6 +32,9 @@ use FS::payby; use FS::acct_rt_transaction; use HTML::Entities; use FS::TicketSystem; +use Text::CSV_XS; +use IO::Scalar; +use Spreadsheet::WriteExcel; $DEBUG = 0; $me = '[FS::ClientAPI::MyAccount]'; @@ -234,6 +237,28 @@ sub logout { } } +sub payment_gateway { + # internal use only + # takes a cust_main and a cust_payby entry, returns the payment_gateway + my $conf = new FS::Conf; + my $cust_main = shift; + my $cust_payby = shift; + my $gatewaynum = $conf->config('selfservice-payment_gateway'); + if ( $gatewaynum ) { + my $pg = qsearchs('payment_gateway', { gatewaynum => $gatewaynum }); + die "configured gatewaynum $gatewaynum not found!" if !$pg; + return $pg; + } + else { + return '' if ! FS::payby->realtime($cust_payby); + my $pg = $cust_main->agent->payment_gateway( + 'method' => FS::payby->payby2bop($cust_payby), + 'nofatal' => 1 + ); + return $pg; + } +} + sub access_info { my $p = shift; @@ -259,18 +284,11 @@ sub access_info { my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) or return { 'error' => "unknown custnum $custnum" }; - $info->{hide_payment_fields} = - [ - map { my $pg = ''; - if ( FS::payby->realtime($_) ) { - $pg = $cust_main->agent->payment_gateway( - 'method' => FS::payby->payby2bop($_), - 'nofatal' => 1, - ); - } - $pg && $pg->gateway_namespace eq 'Business::OnlineThirdPartyPayment'; - } - @{ $info->{cust_paybys} } + $info->{'hide_payment_fields'} = [ + map { + my $pg = payment_gateway($cust_main, $_); + $pg && $pg->gateway_namespace eq 'Business::OnlineThirdPartyPayment'; + } @{ $info->{cust_paybys} } ]; $info->{'self_suspend_reason'} = @@ -529,18 +547,11 @@ sub payment_info { my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) or return { 'error' => "unknown custnum $custnum" }; - $return{hide_payment_fields} = - [ - map { my $pg = ''; - if ( FS::payby->realtime($_) ) { - $pg = $cust_main->agent->payment_gateway( - 'method' => FS::payby->payby2bop($_), - 'nofatal' => 1, - ); - } - $pg && $pg->gateway_namespace eq 'Business::OnlineThirdPartyPayment'; - } - @{ $return{cust_paybys} } + $return{'hide_payment_fields'} = [ + map { + my $pg = payment_gateway($cust_main, $_); + $pg && $pg->gateway_namespace eq 'Business::OnlineThirdPartyPayment'; + } @{ $return{cust_paybys} } ]; $return{balance} = $cust_main->balance; #XXX pkg-balances? @@ -689,6 +700,7 @@ sub process_payment { 'paycvv' => $paycvv, 'pkgnum' => $session->{'pkgnum'}, 'discount_term' => $discount_term, + 'selfservice' => 1, map { $_ => $p->{$_} } @{ $payby2fields{$payby} } ); return { 'error' => $error } if $error; @@ -743,18 +755,27 @@ sub realtime_collect { my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) or return { 'error' => "unknown custnum $custnum" }; + my $amount; + if ( $p->{'amount'} ) { + $amount = $p->{'amount'}; + } + elsif ( $session->{'pkgnum'} ) { + $amount = $cust_main->balance_pkgnum( $session->{'pkgnum'} ); + } + else { + $amount = $cust_main->balance; + } + my $error = $cust_main->realtime_collect( 'method' => $p->{'method'}, + 'amount' => $amount, 'pkgnum' => $session->{'pkgnum'}, 'session_id' => $p->{'session_id'}, 'apply' => 1, + 'selfservice'=> 1, ); return { 'error' => $error } unless ref( $error ); - my $amount = $session->{'pkgnum'} - ? $cust_main->balance_pkgnum( $session->{'pkgnum'} ) - : $cust_main->balance; - return { 'error' => '', amount => $amount, %$error }; } @@ -955,6 +976,7 @@ sub list_pkgs { 'small_custview' => small_custview( $cust_main, $conf->config('countrydefault') ), 'wholesale_view' => 1, + 'login_svcpart' => [ $conf->config('selfservice_server-login_svcpart') ], 'date_format' => $conf->config('date_format') || '%m/%d/%Y', }; } @@ -1406,7 +1428,7 @@ sub _do_bop_realtime { my $bill_error = $cust_main->bill || $cust_main->apply_payments_and_credits - || $cust_main->realtime_collect; + || $cust_main->realtime_collect('selfservice' => 1); if ( $cust_main->balance > $old_balance && $cust_main->balance > 0 @@ -1544,6 +1566,20 @@ sub cancel_pkg { } +sub provision_phone { + my $p = shift; + my @bulkdid = @{$p->{'bulkdid'}}; + unless (scalar(@bulkdid)) { + return _provision( 'FS::svc_phone', + [qw(phonenum countrycode)], + [qw(phonenum countrycode)], + $p, + @_ + ); + } +#XXX: finish bulk orders +} + sub provision_acct { my $p = shift; warn "provision_acct called\n" @@ -1789,6 +1825,140 @@ sub create_ticket { } +sub did_report { + my $p = shift; + my($context, $session, $custnum) = _custoragent_session_custnum($p); + return { 'error' => $session } if $context eq 'error'; + + return { error => 'requested format not implemented' } + unless ($p->{'format'} eq 'csv' || $p->{'format'} eq 'xls'); + + my $conf = new FS::Conf; + my $age_threshold = 0; + $age_threshold = time() - $conf->config('selfservice-recent-did-age') + if ($p->{'recentonly'} && $conf->exists('selfservice-recent-did-age')); + + my $search = { 'custnum' => $custnum }; + $search->{'agentnum'} = $session->{'agentnum'} if $context eq 'agent'; + my $cust_main = qsearchs('cust_main', $search ) + or return { 'error' => "unknown custnum $custnum" }; + +# does it make more sense to just run one sql query for this instead of all the +# insanity below? would increase performance greately for large data sets? + my @svc_phone = (); + foreach my $cust_pkg ( $cust_main->ncancelled_pkgs ) { + my @part_svc = $cust_pkg->part_svc; + foreach my $part_svc ( @part_svc ) { + if($part_svc->svcdb eq 'svc_phone'){ + my @cust_pkg_svc = @{$part_svc->cust_pkg_svc}; + foreach my $cust_pkg_svc ( @cust_pkg_svc ) { + push @svc_phone, $cust_pkg_svc->svc_x + if $cust_pkg_svc->date_inserted >= $age_threshold; + } + } + } + } + + my $csv; + my $xls; + my($xls_r,$xls_c) = (0,0); + my $xls_workbook; + my $content = ''; + my @fields = qw( countrycode phonenum pin sip_password phone_name ); + if($p->{'format'} eq 'csv') { + $csv = new Text::CSV_XS { 'always_quote' => 1, + 'eol' => "\n", + }; + return { 'error' => 'Unable to create CSV' } unless $csv->combine(@fields); + $content .= $csv->string; + } + elsif($p->{'format'} eq 'xls') { + my $XLS1 = new IO::Scalar \$content; + $xls_workbook = Spreadsheet::WriteExcel->new($XLS1) + or return { 'error' => "Error opening .xls file: $!" }; + $xls = $xls_workbook->add_worksheet('DIDs'); + foreach ( @fields ) { + $xls->write(0,$xls_c++,$_); + } + $xls_r++; + } + + foreach my $svc_phone ( @svc_phone ) { + my @cols = map { $svc_phone->$_ } @fields; + if($p->{'format'} eq 'csv') { + return { 'error' => 'Unable to create CSV' } + unless $csv->combine(@cols); + $content .= $csv->string; + } + elsif($p->{'format'} eq 'xls') { + $xls_c = 0; + foreach ( @cols ) { + $xls->write($xls_r,$xls_c++,$_); + } + $xls_r++; + } + } + + $xls_workbook->close() if $p->{'format'} eq 'xls'; + + { content => $content, format => $p->{'format'}, }; +} + +sub get_ticket { + my $p = shift; + my($context, $session, $custnum) = _custoragent_session_custnum($p); + return { 'error' => $session } if $context eq 'error'; + + warn "$me get_ticket: initializing ticket system\n" if $DEBUG; + FS::TicketSystem->init(); + + if(length($p->{'reply'})) { +# currently this allows anyone to correspond on any ticket as fs_selfservice +# probably bad... + my @err_or_res = FS::TicketSystem->correspond_ticket( + '', #create RT session based on FS CurrentUser (fs_selfservice) + 'ticket_id' => $p->{'ticket_id'}, + 'content' => $p->{'reply'}, + ); + + return { 'error' => 'unable to reply to ticket' } + unless ( $err_or_res[0] != 0 && defined $err_or_res[2] ); + } + + warn "$me get_ticket: getting ticket\n" if $DEBUG; + my $err_or_ticket = FS::TicketSystem->get_ticket( + '', #create RT session based on FS CurrentUser (fs_selfservice) + 'ticket_id' => $p->{'ticket_id'}, + ); + + if ( ref($err_or_ticket) ) { + +# since we're bypassing the RT security/permissions model by always using +# fs_selfservice as the RT user (as opposed to a requestor, which we +# can't do since we want all tickets linked to a cust), we check below whether +# the requested ticket was actually linked to this customer + my @custs = @{$err_or_ticket->{'custs'}}; + my @txns = @{$err_or_ticket->{'txns'}}; + + return { 'error' => 'no customer' } unless ( $custnum && scalar(@custs) ); + + return { 'error' => 'invalid ticket requested' } + unless grep($_ eq $custnum, @custs); + + warn "$me get_ticket: sucessful: \n" + if $DEBUG; + return { 'error' => '', + 'transactions' => \@txns, + 'ticket_id' => $p->{'ticket_id'}, + }; + } else { + warn "$me create_ticket: unsucessful: $err_or_ticket\n" + if $DEBUG; + return { 'error' => $err_or_ticket }; + } +} + + #-- sub _custoragent_session_custnum {