X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;ds=sidebyside;f=FS%2FFS%2FClientAPI%2FMyAccount.pm;h=014434a052e777268cf95b4604b8dcdf18bb9164;hb=c58b5c1cef23066263aae5c506824310866ef64b;hp=ecabe31c79d0f80913b89a6605ff40d1b96b8ee8;hpb=d6741df87df9e3352d7ae47a02d0e3f46154fef9;p=freeside.git diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index ecabe31c7..014434a05 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -18,6 +18,7 @@ use FS::Conf; use FS::Record qw(qsearch qsearchs dbh); use FS::Msgcat qw(gettext); use FS::Misc qw(card_types); +use FS::Misc::DateTime qw(parse_datetime); use FS::ClientAPI_SessionCache; use FS::svc_acct; use FS::svc_domain; @@ -73,7 +74,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; } @@ -96,7 +97,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 @@ -294,6 +295,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'}, @@ -315,7 +320,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 }; @@ -532,6 +542,8 @@ sub payment_info { 'show_paystate' => $conf->exists('show_bankstate'), 'save_unchecked' => $conf->exists('selfservice-save_unchecked'), + + 'credit_card_surcharge_percentage' => $conf->config('credit-card-surcharge-percentage'), }; } @@ -637,6 +649,7 @@ sub process_payment { #false laziness w/process/payment.cgi my $payinfo; my $paycvv = ''; + my $paynum = ''; if ( $payby eq 'CHEK' || $payby eq 'DCHK' ) { $p->{'payinfo1'} =~ /^([\dx]+)$/ @@ -698,6 +711,7 @@ sub process_payment { 'payname' => $payname, 'paybatch' => $paybatch, #this doesn't actually do anything 'paycvv' => $paycvv, + 'paynum_ref' => \$paynum, 'pkgnum' => $session->{'pkgnum'}, 'discount_term' => $discount_term, 'selfservice' => 1, @@ -740,7 +754,46 @@ sub process_payment { } } - return { 'error' => '' }; + my $receipt_html = ''; + if($paynum) { + # currently supported for realtime CC only; send receipt data to SS + my $cust_pay = qsearchs('cust_pay', { 'paynum' => $paynum } ); + if($cust_pay) { + $receipt_html = qq! + + + + + + + + + + + + + + + + + + + + + + + + + +
Payment#! . $cust_pay->paynum . qq!
Date! . + time2str("%a %b %o, %Y %r", $cust_pay->_date) + . qq!
Amount! . $cust_pay->paid . qq!
Payment method! . $cust_pay->payby_name .' #'. $cust_pay->paymask + . qq!
+!; + } + } + + return { 'error' => '', 'receipt_html' => $receipt_html, }; } @@ -978,6 +1031,7 @@ sub list_pkgs { 'wholesale_view' => 1, 'login_svcpart' => [ $conf->config('selfservice_server-login_svcpart') ], 'date_format' => $conf->config('date_format') || '%m/%d/%Y', + 'lnp' => $conf->exists('svc_phone-lnp'), }; } @@ -1039,9 +1093,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; @@ -1077,7 +1135,7 @@ sub list_svcs { # more... ); - } elsif ( $svcdb eq 'svc_phone' ) { + } elsif ( $svcdb eq 'svc_phone' || $svcdb eq 'svc_port' ) { %hash = ( %hash, ); @@ -1091,6 +1149,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 = (); @@ -1132,8 +1205,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 { @@ -1270,7 +1343,7 @@ sub order_pkg { map { $_ => $p->{$_} } @{$fields{$svcdb}} } ); - if ( $svcdb eq 'svc_acct' ) { + if ( $svcdb eq 'svc_acct' && exists($p->{"snarf_machine1"}) ) { my @acct_snarf; my $snarfnum = 1; while ( length($p->{"snarf_machine$snarfnum"}) ) { @@ -1300,7 +1373,7 @@ sub order_pkg { tie my %hash, 'Tie::RefHash'; %hash = ( $cust_pkg => \@svc ); #msgcat - $error = $cust_main->order_pkgs( \%hash, '', 'noexport' => 1 ); + $error = $cust_main->order_pkgs( \%hash, 'noexport' => 1 ); return { 'error' => $error } if $error; my $conf = new FS::Conf; @@ -1568,7 +1641,23 @@ sub cancel_pkg { sub provision_phone { my $p = shift; - my @bulkdid = @{$p->{'bulkdid'}}; + my @bulkdid; + @bulkdid = @{$p->{'bulkdid'}} if $p->{'bulkdid'}; + +# 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', + [qw(lnp_desired_due_date lnp_other_provider + lnp_other_provider_account phonenum countrycode lnp_status)], + [qw(phonenum countrycode)], + $p, + @_ + ); + } + +# single DID order unless (scalar(@bulkdid)) { return _provision( 'FS::svc_phone', [qw(phonenum countrycode)], @@ -1577,7 +1666,25 @@ sub provision_phone { @_ ); } -#XXX: finish bulk orders + +# bulk DID order case + my $error; + foreach my $did ( @bulkdid ) { + $did =~ s/[^0-9]//g; + $error = _provision( 'FS::svc_phone', + [qw(phonenum countrycode)], + [qw(phonenum countrycode)], + { + 'pkgnum' => $p->{'pkgnum'}, + 'svcpart' => $p->{'svcpart'}, + 'phonenum' => $did, + 'countrycode' => $p->{'countrycode'}, + 'session_id' => $p->{'session_id'}, + } + ); + return $error if ($error->{'error'} && length($error->{'error'}) > 1); + } + { 'bulkdid' => [ @bulkdid ], 'svc' => $error->{'svc'} } } sub provision_acct { @@ -1811,13 +1918,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 }; } @@ -1911,53 +2018,134 @@ 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) ) { - -# 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'}}; + 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 }; + } - return { 'error' => 'no customer' } unless ( $custnum && scalar(@custs) ); + my @custs = @{$err_or_ticket->{'custs'}}; + my @txns = @{$err_or_ticket->{'txns'}}; + my @filtered_txns; - return { 'error' => 'invalid ticket requested' } - unless grep($_ eq $custnum, @custs); + # superseded by check in get_ticket_object + #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 }; + 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'; + + warn "$me adjust_ticket_priority: initializing ticket system\n" if $DEBUG; + FS::TicketSystem->init; + my $ss_priority = FS::TicketSystem->selfservice_priority; + + return { 'error' => 'adjust_ticket_priority configuration error' } + if $FS::TicketSystem::system ne 'RT_Internal' + or !$ss_priority; + + my $values = $p->{'values'}; #hashref, id => priority value + my %ticket_error; + + 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, + ); + } + + $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 + } +} #--