X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2FClientAPI%2FMyAccount.pm;h=6948fcec3a6c2ba1b955beb045d20fe3107ab280;hb=43af0ec176ff2ad5c4ecd60a58145f8370cc39d7;hp=c82d3704328535c2d14c1d7bbadf6b3174f3b0cc;hpb=331de49c65b55d90ac9409930ba95013a10a8d0a;p=freeside.git diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index c82d37043..6948fcec3 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -20,6 +20,7 @@ use FS::Msgcat qw(gettext); use FS::Misc qw(card_types); use FS::Misc::DateTime qw(parse_datetime); use FS::ClientAPI_SessionCache; +use FS::cust_svc; use FS::svc_acct; use FS::svc_domain; use FS::svc_phone; @@ -74,7 +75,7 @@ sub skin_info { or die "no agentnum for custnum $custnum"; #} elsif ( $context eq 'agent' ) { - } elsif ( $p->{'agentnum'} =~ /^(\d+)$/ ) { + } elsif ( defined($p->{'agentnum'}) and $p->{'agentnum'} =~ /^(\d+)$/ ) { $agentnum = $1; } @@ -97,7 +98,7 @@ sub skin_info { $skin_info_cache_agent = { 'agentnum' => $agentnum, ( map { $_ => scalar( $conf->config($_, $agentnum) ) } - qw( company_name ) ), + qw( company_name date_format ) ), ( map { $_ => scalar( $conf->config("selfservice-$_", $agentnum ) ) } qw( body_bgcolor box_bgcolor text_color link_color vlink_color hlink_color alink_color @@ -295,6 +296,10 @@ sub access_info { $info->{'self_suspend_reason'} = $conf->config('selfservice-self_suspend_reason', $cust_main->agentnum); + $info->{'edit_ticket_subject'} = + $conf->exists('ticket_system-selfservice_edit_subject') && + $cust_main->edit_subject; + return { %$info, 'custnum' => $custnum, 'access_pkgnum' => $session->{'pkgnum'}, @@ -316,7 +321,12 @@ sub customer_info { }else{ $return{'require_address2'} = ''; } - + + if ( $FS::TicketSystem::system ) { + warn "$me customer_info: initializing ticket system\n" if $DEBUG; + FS::TicketSystem->init(); + } + if ( $custnum ) { #customer record my $search = { 'custnum' => $custnum }; @@ -330,7 +340,25 @@ sub customer_info { $return{balance} = $cust_main->balance; } - $return{tickets} = [ ($cust_main->tickets) ]; + my @tickets = $cust_main->tickets; + # unavoidable false laziness w/ httemplate/view/cust_main/tickets.html + if ( FS::TicketSystem->selfservice_priority ) { + my $dir = $conf->exists('ticket_system-priority_reverse') ? -1 : 1; + $return{tickets} = [ + sort { + ( + ($a->{'_selfservice_priority'} eq '') <=> + ($b->{'_selfservice_priority'} eq '') + ) || + ( $dir * + ($b->{'_selfservice_priority'} <=> $a->{'_selfservice_priority'}) + ) + } @tickets + ]; + } + else { + $return{tickets} = \@tickets; + } unless ( $session->{'pkgnum'} ) { my @open = map { @@ -391,6 +419,11 @@ sub customer_info { $return{discount_terms_hash} = { $cust_main->discount_terms_hash }; } + if ( $session->{'svcnum'} ) { + my $cust_svc = qsearchs('cust_svc', { 'svcnum' => $session->{'svcnum'} }); + $return{'svc_label'} = ($cust_svc->label)[1] if $cust_svc; + } + } elsif ( $session->{'svcnum'} ) { #no customer record my $svc_acct = qsearchs('svc_acct', { 'svcnum' => $session->{'svcnum'} } ) @@ -664,7 +697,7 @@ sub process_payment { if $cust_main->paymask eq $payinfo; $payinfo =~ s/\D//g; - $payinfo =~ /^(\d{13,16})$/ + $payinfo =~ /^(\d{13,16}|\d{8,9})$/ or return { 'error' => gettext('invalid_card') }; # . ": ". $self->payinfo $payinfo = $1; @@ -1041,6 +1074,10 @@ sub list_pkgs { if $context eq 'agent' && $conf->exists('agent-showpasswords') && $_->part_svc->svcdb eq 'svc_acct'; + $ref->{svchash} = { $_->svc_x->hash } if + $_->part_svc->svcdb eq 'svc_phone'; + $ref->{svchash}->{svcpart} = $_->part_svc->svcpart + if $_->part_svc->svcdb eq 'svc_phone'; # hack $ref; } $_->cust_svc ], @@ -1084,9 +1121,13 @@ sub list_svcs { #@svc_x = sort { $a->domain cmp $b->domain || $a->username cmp $b->username } # @svc_x; + my $conf = new FS::Conf; + { 'svcnum' => $session->{'svcnum'}, 'custnum' => $custnum, + 'date_format' => $conf->config('date_format') || '%m/%d/%Y', + 'view_usage_nodomain' => $conf->exists('selfservice-view_usage_nodomain'), 'svcs' => [ map { my $svc_x = $_->svc_x; @@ -1122,7 +1163,7 @@ sub list_svcs { # more... ); - } elsif ( $svcdb eq 'svc_phone' ) { + } elsif ( $svcdb eq 'svc_phone' || $svcdb eq 'svc_port' ) { %hash = ( %hash, ); @@ -1136,6 +1177,21 @@ sub list_svcs { } +sub port_graph { + my $p = shift; + _usage_details( \&_port_graph, $p, + 'svcdb' => 'svc_port', + ); +} + +sub _port_graph { + my($svc_port, $begin, $end) = @_; + my @usage = (); + my $pngOrError = $svc_port->graph_png( start=>$begin, end=> $end ); + push @usage, { 'png' => $pngOrError }; + (@usage); +} + sub _list_svc_usage { my($svc_acct, $begin, $end) = @_; my @usage = (); @@ -1177,8 +1233,8 @@ sub list_support_usage { sub _list_cdr_usage { my($svc_phone, $begin, $end) = @_; - map [ $_->downstream_csv('format' => 'default') ], #XXX config for format - $svc_phone->get_cdrs( 'begin'=>$begin, 'end'=>$end, ); + map [ $_->downstream_csv('format' => 'default', 'keeparray' => 1) ], #XXX config for format + $svc_phone->get_cdrs( 'begin'=>$begin, 'end'=>$end, ); } sub list_cdr_usage { @@ -1307,7 +1363,7 @@ sub order_pkg { 'svc_domain' => [ qw( domain ) ], 'svc_phone' => [ qw( phonenum pin sip_password phone_name ) ], 'svc_external' => [ qw( id title ) ], - 'svc_pbx' => [ qw( id name ) ], + 'svc_pbx' => [ qw( id title ) ], ); my $svc_x = "FS::$svcdb"->new( { @@ -1616,6 +1672,23 @@ sub provision_phone { my @bulkdid; @bulkdid = @{$p->{'bulkdid'}} if $p->{'bulkdid'}; + if($p->{'svcnum'} && $p->{'svcnum'} =~ /^\d+$/){ + my($context, $session, $custnum) = _custoragent_session_custnum($p); + return { 'error' => $session } if $context eq 'error'; + + my $svc_phone = qsearchs('svc_phone', { svcnum => $p->{'svcnum'} }); + return { 'error' => 'service not found' } unless $svc_phone; + return { 'error' => 'invalid svcnum' } + if $svc_phone && $svc_phone->cust_svc->cust_pkg->custnum != $custnum; + + $svc_phone->email($p->{'email'}) + if $svc_phone->email ne $p->{'email'} && $p->{'email'} =~ /^([\w\.\d@]+|)$/; + $svc_phone->forwarddst($p->{'forwarddst'}) + if $svc_phone->forwarddst ne $p->{'forwarddst'} + && $p->{'forwarddst'} =~ /^(\d+|)$/; + return { 'error' => $svc_phone->replace }; + } + # single DID LNP unless($p->{'lnp'}) { $p->{'lnp_desired_due_date'} = parse_datetime($p->{'lnp_desired_due_date'}); @@ -1778,7 +1851,7 @@ sub part_svc_info { my $conf = new FS::Conf; - return { + my $ret = { 'svc' => $part_svc->svc, 'svcdb' => $part_svc->svcdb, 'pkgnum' => $pkgnum, @@ -1797,6 +1870,17 @@ sub part_svc_info { }; + if ($p->{'svcnum'} && $p->{'svcnum'} =~ /^\d+$/ + && $ret->{'svcdb'} eq 'svc_phone') { + $ret->{'svcnum'} = $p->{'svcnum'}; + my $svc_phone = qsearchs('svc_phone', { svcnum => $p->{'svcnum'} }); + if ( $svc_phone && $svc_phone->cust_svc->cust_pkg->custnum == $custnum ) { + $ret->{'email'} = $svc_phone->email; + $ret->{'forwarddst'} = $svc_phone->forwarddst; + } + } + + $ret; } sub unprovision_svc { @@ -1890,13 +1974,13 @@ sub create_ticket { ); if ( ref($err_or_ticket) ) { - warn "$me create_ticket: sucessful: ". $err_or_ticket->id. "\n" + warn "$me create_ticket: successful: ". $err_or_ticket->id. "\n" if $DEBUG; return { 'error' => '', 'ticket_id' => $err_or_ticket->id, }; } else { - warn "$me create_ticket: unsucessful: $err_or_ticket\n" + warn "$me create_ticket: unsuccessful: $err_or_ticket\n" if $DEBUG; return { 'error' => $err_or_ticket }; } @@ -1990,62 +2074,135 @@ sub get_ticket { warn "$me get_ticket: initializing ticket system\n" if $DEBUG; FS::TicketSystem->init(); + return { 'error' => 'get_ticket configuration error' } + if $FS::TicketSystem::system ne 'RT_Internal'; + + # check existence and ownership as part of this + warn "$me get_ticket: fetching ticket\n" if $DEBUG; + my $rt_session = FS::TicketSystem->session(''); + my $Ticket = FS::TicketSystem->get_ticket_object( + $rt_session, + ticket_id => $p->{'ticket_id'}, + custnum => $custnum + ); + return { 'error' => 'ticket not found' } if !$Ticket; + + if ( length( $p->{'subject'} || '' ) ) { + # subject change + if ( $p->{'subject'} ne $Ticket->Subject ) { + my ($val, $msg) = $Ticket->SetSubject($p->{'subject'}); + return { 'error' => "unable to set subject: $msg" } if !$val; + } + } 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'}, - ); - + my @err_or_res = FS::TicketSystem->correspond_ticket( + $rt_session, + '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] ); + unless ( $err_or_res[0] != 0 && defined $err_or_res[2] ); } - warn "$me get_ticket: getting ticket\n" if $DEBUG; + warn "$me get_ticket: getting ticket history\n" if $DEBUG; my $err_or_ticket = FS::TicketSystem->get_ticket( - '', #create RT session based on FS CurrentUser (fs_selfservice) + $rt_session, 'ticket_id' => $p->{'ticket_id'}, ); - if ( ref($err_or_ticket) ) { + if ( !ref($err_or_ticket) ) { # there is no way this should ever happen + warn "$me get_ticket: unsuccessful: $err_or_ticket\n" + if $DEBUG; + return { 'error' => $err_or_ticket }; + } + + my @custs = @{$err_or_ticket->{'custs'}}; + my @txns = @{$err_or_ticket->{'txns'}}; + my @filtered_txns; + + # superseded by check in get_ticket_object + #return { 'error' => 'invalid ticket requested' } + #unless grep($_ eq $custnum, @custs); + + foreach my $txn ( @txns ) { + push @filtered_txns, $txn + if ($txn->{'type'} eq 'EmailRecord' + || $txn->{'type'} eq 'Correspond' + || $txn->{'type'} eq 'Create'); + } + + warn "$me get_ticket: successful: \n" + if $DEBUG; + return { 'error' => '', + 'transactions' => \@filtered_txns, + 'ticket_fields' => $err_or_ticket->{'fields'}, + 'ticket_id' => $p->{'ticket_id'}, + }; +} + +sub adjust_ticket_priority { + my $p = shift; + my($context, $session, $custnum) = _custoragent_session_custnum($p); + return { 'error' => $session } if $context eq 'error'; -# 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'}}; - my @filtered_txns; + warn "$me adjust_ticket_priority: initializing ticket system\n" if $DEBUG; + FS::TicketSystem->init; + my $ss_priority = FS::TicketSystem->selfservice_priority; - return { 'error' => 'no customer' } unless ( $custnum && scalar(@custs) ); + return { 'error' => 'adjust_ticket_priority configuration error' } + if $FS::TicketSystem::system ne 'RT_Internal' + or !$ss_priority; - return { 'error' => 'invalid ticket requested' } - unless grep($_ eq $custnum, @custs); + my $values = $p->{'values'}; #hashref, id => priority value + my %ticket_error; - foreach my $txn ( @txns ) { - push @filtered_txns, $txn - if ($txn->{'type'} eq 'EmailRecord' - || $txn->{'type'} eq 'Correspond' - || $txn->{'type'} eq 'Create'); + foreach my $id (keys %$values) { + warn "$me adjust_ticket_priority: fetching ticket $id\n" if $DEBUG; + my $Ticket = FS::TicketSystem->get_ticket_object('', + 'ticket_id' => $id, + 'custnum' => $custnum, + ); + if ( !$Ticket ) { + $ticket_error{$id} = 'ticket not found'; + next; + } + + # RT API stuff--would we gain anything by wrapping this in FS::TicketSystem? + # We're not going to implement it for RT_External. + my $old_value = $Ticket->FirstCustomFieldValue($ss_priority); + my $new_value = $values->{$id}; + next if $old_value eq $new_value; + + warn "$me adjust_ticket_priority: updating ticket $id\n" if $DEBUG; + + # AddCustomFieldValue works fine (replacing any existing value) if it's + # a single-valued custom field, which it should be. If it's not, you're + # doing something wrong. + my ($val, $msg); + if ( length($new_value) ) { + ($val, $msg) = $Ticket->AddCustomFieldValue( + Field => $ss_priority, + Value => $new_value, + ); + } + else { + ($val, $msg) = $Ticket->DeleteCustomFieldValue( + Field => $ss_priority, + Value => $old_value, + ); } - warn "$me get_ticket: sucessful: \n" - if $DEBUG; - return { 'error' => '', - 'transactions' => \@filtered_txns, - 'ticket_id' => $p->{'ticket_id'}, - }; - } else { - warn "$me create_ticket: unsucessful: $err_or_ticket\n" - if $DEBUG; - return { 'error' => $err_or_ticket }; + $ticket_error{$id} = $msg if !$val; + warn "$me adjust_ticket_priority: $id: $msg\n" if $DEBUG and !$val; } + return { 'error' => '', + 'ticket_error' => \%ticket_error, + %{ customer_info($p) } # send updated customer info back + } } - #-- sub _custoragent_session_custnum {