X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2FClientAPI%2FMyAccount.pm;h=b0ea736f865c80355d4ceb6b8fbe2eec2a671abd;hb=e50f2d69776ccaa4162c59cc4789ddd566be6df2;hp=8c6a5b8f76aeccacc8daea30561bf14ea001fe33;hpb=92cbc41959f36cb9e3d281b2dfb6a5ad587f5584;p=freeside.git diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index 8c6a5b8f7..b0ea736f8 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -48,6 +48,8 @@ use FS::msg_template; use FS::contact; use FS::cust_location; +use FS::ClientAPI::MyAccount::quotation; # just for code organization + $DEBUG = 0; $me = '[FS::ClientAPI::MyAccount]'; @@ -137,6 +139,7 @@ sub skin_info { 'logo' => scalar($conf->config_binary('logo.png', $agentnum )), ( map { $_ => join("\n", $conf->config("selfservice-$_", $agentnum ) ) } qw( head body_header body_footer company_address ) ), + 'money_char' => $conf->config("money_char") || '$', 'menu' => join("\n", $conf->config("ng_selfservice-menu", $agentnum ) ) || 'main.php Home @@ -247,16 +250,39 @@ sub login { 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; + my @svc_acct = qsearch( 'svc_acct', { 'username' => $p->{'username'}, + 'domsvc' => $svc_domain->svcnum, } + ); + + if ( $conf->exists('selfservice_server-login_svcpart') ) { + my @svcpart = $conf->config('selfservice_server-login_svcpart'); + @svc_acct = grep { my $svcpart = $_->cust_svc->svcpart; + scalar( grep( $_ eq $svcpart, @svcpart ) ); + } + @svc_acct; + } - if($conf->exists('selfservice_server-login_svcpart')) { - my @svcpart = $conf->config('selfservice_server-login_svcpart'); - my $svcpart = $svc_acct->cust_svc->svcpart; - return { error => 'Invalid user.' } - unless grep($_ eq $svcpart, @svcpart); + if ( $conf->exists('selfservice_server-primary_only') ) { + @svc_acct = + grep { + my $cust_svc = $_->cust_svc; + $cust_svc->cust_pkg->part_pkg->svcpart([qw( svc_acct svc_phone )]) + == $cust_svc->svcpart + } + @svc_acct; + } + + return { error => 'User not found.' } unless @svc_acct; + + #return { error => 'Multiple users.' } if scalar(@svc_acct) > 1; + + my $svc_acct = $svc_acct[0]; + + if ( $conf->exists('selfservice_server-login_svcpart') ) { + my @svcpart = $conf->config('selfservice_server-login_svcpart'); + my $svcpart = $svc_acct->cust_svc->svcpart; + return { error => 'Invalid user.' } + unless grep($_ eq $svcpart, @svcpart); } return { error => 'Incorrect password.' } @@ -441,11 +467,13 @@ sub customer_info { if ( $session->{'pkgnum'} ) { #XXX open invoices in the pkg-balances case } else { + $return{'money_char'} = $conf->config("money_char") || '$'; my @open = map { { - invnum => $_->invnum, - date => time2str("%b %o, %Y", $_->_date), - owed => $_->owed, + invnum => $_->invnum, + date => time2str("%b %o, %Y", $_->_date), + owed => $_->owed, + charged => $_->charged, }; } $cust_main->open_cust_bill; $return{open_invoices} = \@open; @@ -759,16 +787,16 @@ sub edit_info { if ( $new->payinfo eq $cust_main->paymask ) { $new->payinfo($cust_main->payinfo); + $new->paycvv( $p->{'paycvv'} || $cust_main->paycvv ); } else { $new->payinfo($p->{'payinfo'}); + return { 'error' => 'CVV2 is required' } + if ! $p->{'paycvv'} && $conf->exists('selfservice-onfile_require_cvv'); + $new->paycvv( $p->{'paycvv'} ) } $new->set( 'payby' => $p->{'auto'} ? 'CARD' : 'DCRD' ); - if ( $conf->exists('selfservice-onfile_require_cvv') ){ - return { 'error' => 'CVV2 is required' } unless $p->{'paycvv'}; - } - } elsif ( $payby =~ /^(CHEK|DCHK)$/ ) { my $payinfo; @@ -1552,25 +1580,31 @@ sub list_invoices { my @cust_bill = grep ! $_->hide, $cust_main->cust_bill; my $balance = 0; + my $invoices = [ + map { + #not super efficient, we also run cust_bill_pay/cust_credited inside owed + my @payments_and_credits = sort {$b->_date <=> $a->_date} ($_->cust_bill_pay,$_->cust_credited); + my $owed = $_->owed; + $balance += $owed; + +{ 'invnum' => $_->invnum, + '_date' => $_->_date, + 'date' => time2str("%b %o, %Y", $_->_date), + 'date_short' => time2str("%m-%d-%Y", $_->_date), + 'previous' => sprintf('%.2f', ($_->previous)[0]), + 'charged' => sprintf('%.2f', $_->charged), + 'owed' => sprintf('%.2f', $owed), + 'balance' => sprintf('%.2f', $balance), + 'lastpay' => @payments_and_credits + ? time2str("%b %o, %Y", $payments_and_credits[0]->_date) + : '', + } + } @cust_bill + ]; return { 'error' => '', 'balance' => $cust_main->balance, - 'invoices' => [ - map { - my $owed = $_->owed; - $balance += $owed; - +{ 'invnum' => $_->invnum, - '_date' => $_->_date, - 'date' => time2str("%b %o, %Y", $_->_date), - 'date_short' => time2str("%m-%d-%Y", $_->_date), - 'previous' => sprintf('%.2f', ($_->previous)[0]), - 'charged' => sprintf('%.2f', $_->charged), - 'owed' => sprintf('%.2f', $owed), - 'balance' => sprintf('%.2f', $balance), - } - } - @cust_bill - ], + 'money_char' => $conf->config("money_char") || '$', + 'invoices' => $invoices, 'legacy_invoices' => [ map { +{ 'legacyinvnum' => $_->legacyinvnum, @@ -1821,18 +1855,20 @@ sub list_svcs { } # no usage to hide here - } elsif ( $svcdb eq 'svc_phone' ) { + } elsif ( $svcdb eq 'svc_phone' or $svcdb eq 'svc_pbx' ) { if (!$hide_usage) { # could potentially show lots of things... $hash{'outbound'} = 1; $hash{'inbound'} = 0; - if ( $part_pkg->plan eq 'voip_inbound' ) { - $hash{'outbound'} = 0; - $hash{'inbound'} = 1; - } elsif ( $part_pkg->option('selfservice_inbound_format') - or $conf->config('selfservice-default_inbound_cdr_format') - ) { - $hash{'inbound'} = 1; + if ( $svcdb eq 'svc_phone' ) { + if ( $part_pkg->plan eq 'voip_inbound' ) { + $hash{'outbound'} = 0; + $hash{'inbound'} = 1; + } elsif ( $part_pkg->option('selfservice_inbound_format') + or $conf->config('selfservice-default_inbound_cdr_format') + ) { + $hash{'inbound'} = 1; + } } foreach (qw(inbound outbound)) { # hmm...we can't filter by status here, because there might @@ -2127,11 +2163,11 @@ sub _list_cdr_usage { # XXX CDR type support... # XXX any way to do a paged search on this? # we have to return the results all at once... - my($svc_phone, $begin, $end, %opt) = @_; + my($svc_x, $begin, $end, %opt) = @_; map [ $_->downstream_csv(%opt, 'keeparray' => 1) ], - $svc_phone->get_cdrs( - 'begin'=>$begin, - 'end'=>$end, + $svc_x->get_cdrs( + 'begin' => $begin, + 'end' => $end, 'disable_charged_party' => 1, %opt ); @@ -2139,9 +2175,7 @@ sub _list_cdr_usage { sub list_cdr_usage { my $p = shift; - _usage_details( \&_list_cdr_usage, $p, - 'svcdb' => 'svc_phone', - ); + _usage_details( \&_list_cdr_usage, $p ); } sub _usage_details { @@ -2158,17 +2192,17 @@ sub _usage_details { my $search = { 'svcnum' => $p->{'svcnum'} }; $search->{'agentnum'} = $session->{'agentnum'} if $context eq 'agent'; - my $svcdb = $opt{'svcdb'} || 'svc_acct'; - - my $svc_x = qsearchs( $svcdb, $search ); + my $cust_svc = qsearchs( 'cust_svc', $search ); return { 'error' => 'No service selected in list_svc_usage' } - unless $svc_x; + unless $cust_svc; - my $cust_pkg = $svc_x->cust_svc->cust_pkg; + my $svc_x = $cust_svc->svc_x; + my $svcdb = $svc_x->table; + my $cust_pkg = $cust_svc->cust_pkg; my $freq = $cust_pkg->part_pkg->freq; my %callback_opt; my $header = []; - if ( $svcdb eq 'svc_phone' ) { + if ( $svcdb eq 'svc_phone' or $svcdb eq 'svc_pbx' ) { my $format = ''; if ( $p->{inbound} ) { $format = $cust_pkg->part_pkg->option('selfservice_inbound_format') @@ -2398,26 +2432,26 @@ sub change_pkg { return { error=>"Can't change a suspended package", pkgnum=>$cust_pkg->pkgnum} if $cust_pkg->status eq 'suspended'; - my @newpkg; - my $error = FS::cust_pkg::order( $custnum, - [$p->{pkgpart}], - [$p->{pkgnum}], - \@newpkg, - ); + my $err_or_cust_pkg = $cust_pkg->change( 'pkgpart' => $p->{'pkgpart'}, + 'quantity' => $p->{'quantity'} || 1, + ); + + return { error=>$err_or_cust_pkg, pkgnum=>$cust_pkg->pkgnum } + unless ref($err_or_cust_pkg); if ( $conf->exists('signup_server-realtime') ) { my $bill_error = _do_bop_realtime( $cust_main, $status, 'no_credit'=>1 ); if ($bill_error) { - $newpkg[0]->suspend; + $err_or_cust_pkg->suspend; return $bill_error; } else { - $newpkg[0]->reexport; + $err_or_cust_pkg->reexport; } } else { - $newpkg[0]->reexport; + $err_or_cust_pkg->reexport; } return { error => '', pkgnum => $cust_pkg->pkgnum }; @@ -2631,11 +2665,12 @@ sub cancel_pkg { } sub provision_phone { - my $p = shift; - my @bulkdid; - @bulkdid = @{$p->{'bulkdid'}} if $p->{'bulkdid'}; + my $p = shift; + my @bulkdid; + @bulkdid = @{$p->{'bulkdid'}} if $p->{'bulkdid'}; - if($p->{'svcnum'} && $p->{'svcnum'} =~ /^\d+$/){ + #editing an existing phone number + if ( $p->{'svcnum'} && $p->{'svcnum'} =~ /^\d+$/ ) { my($context, $session, $custnum) = _custoragent_session_custnum($p); return { 'error' => $session } if $context eq 'error'; @@ -2652,8 +2687,8 @@ sub provision_phone { return { 'error' => $svc_phone->replace }; } -# single DID LNP - unless($p->{'lnp'}) { + # single DID LNP + unless ( $p->{'lnp'} ) { $p->{'lnp_desired_due_date'} = parse_datetime($p->{'lnp_desired_due_date'}); $p->{'lnp_status'} = "portingin"; return _provision( 'FS::svc_phone', @@ -2663,19 +2698,19 @@ sub provision_phone { $p, @_ ); - } + } -# single DID order - unless (scalar(@bulkdid)) { + # single DID order (the usual case) + unless (scalar(@bulkdid)) { return _provision( 'FS::svc_phone', [qw(phonenum countrycode)], [qw(phonenum countrycode)], $p, @_ ); - } + } -# bulk DID order case + # bulk DID order case my $error; foreach my $did ( @bulkdid ) { $did =~ s/[^0-9]//g; @@ -2695,6 +2730,21 @@ sub provision_phone { { 'bulkdid' => [ @bulkdid ], 'svc' => $error->{'svc'} } } +sub provision_pbx { + my $p = shift; + warn "provision_pbx called\n" + if $DEBUG; + + warn "provision_pbx calling _provision\n" + if $DEBUG; + _provision( 'FS::svc_pbx', + [qw(id title max_extensions max_simultaneous ip_addr)], + [qw(id title max_extensions max_simultaneous ip_addr)], + $p, + @_ + ); +} + sub provision_acct { my $p = shift; warn "provision_acct called\n" @@ -2733,6 +2783,15 @@ sub provision_external { ); } +sub provision_forward { + my $p = shift; + _provision( 'FS::svc_forward', + ['srcsvc','src','dstsvc','dst'], + [], + $p, + ); +} + sub _provision { my( $class, $fields, $return_fields, $p ) = splice(@_, 0, 4); warn "_provision called for $class\n" @@ -2760,6 +2819,9 @@ sub _provision { my $part_svc = qsearchs('part_svc', { 'svcpart' => $p->{'svcpart'} } ) or return { 'error' => "unknown svcpart $p->{'svcpart'}" }; + return { error=> 'svcpart '. $p->{'svcpart'}. " is not a $class definition" } + if $class ne 'FS::'. $part_svc->svcdb; + warn "creating $class record\n" if $DEBUG; my $svc_x = $class->new( { @@ -2767,9 +2829,21 @@ sub _provision { 'svcpart' => $p->{'svcpart'}, map { $_ => $p->{$_} } @$fields } ); + + my %insert_args = (); + #i shouldn't be a special case here (pass an option or something) + if ( $class eq 'FS::svc_phone' + && grep length($p->{$_}), @location_editable_fields + ) + { + $insert_args{'cust_location'} = new FS::cust_location { + map { $_ => $p->{$_} } @location_editable_fields + }; + } + warn "inserting $class record\n" if $DEBUG; - my $error = $svc_x->insert; + my $error = $svc_x->insert(%insert_args); unless ( $error ) { warn "finding inserted record for svcnum ". $svc_x->svcnum. "\n" @@ -2843,6 +2917,10 @@ sub part_svc_info { } } + if ($ret->{'svcdb'} eq 'svc_forward') { + $ret->{'forward_emails'} = {$cust_pkg->forward_emails()}; + } + $ret; }