Merge branch 'master' of git.freeside.biz:/home/git/freeside
authorIvan Kohler <ivan@freeside.biz>
Tue, 2 Jul 2013 18:57:03 +0000 (11:57 -0700)
committerIvan Kohler <ivan@freeside.biz>
Tue, 2 Jul 2013 18:57:03 +0000 (11:57 -0700)
1  2 
FS/FS/ClientAPI/MyAccount.pm
FS/FS/Conf.pm
FS/FS/Schema.pm
FS/FS/cust_main.pm
fs_selfservice/FS-SelfService/SelfService.pm

@@@ -133,36 -133,6 +133,36 @@@ 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 ) ),
 +      'menu' => join("\n", $conf->config("ng_selfservice-menu", $agentnum ) ) ||
 +                'main.php Home
 +
 +                 services.php Services
 +                 services.php My Services
 +                 services_new.php Order a new service
 +
 +                 personal.php Profile
 +                 personal.php Personal Information
 +                 password.php Change Password
 +
 +                 payment.php Payments
 +                 payment_cc.php Credit Card Payment
 +                 payment_ach.php Electronic Check Payment
 +                 payment_paypal.php PayPal Payment
 +                 payment_webpay.php Webpay Payments
 +
 +                 usage.php Usage
 +                 usage_data.php Data usage
 +                 usage_cdr.php Call usage
 +
 +                 tickets.php Help Desk
 +                 tickets.php Open Tickets
 +                 tickets_resolved.php Resolved Tickets
 +                 ticket_create.php Create a new ticket
 +
 +                 docs.php FAQs
 +
 +                 logout.php Logout
 +                ',
      };
  
      _cache->set("skin_info_cache_agent$agentnum", $skin_info_cache_agent);
@@@ -379,6 -349,8 +379,8 @@@ sub access_info 
        $conf->exists('ticket_system-selfservice_edit_subject') && 
        $cust_main->edit_subject;
  
+   $info->{'timeout'} = $conf->config('selfservice-timeout') || 3600;
    return { %$info,
             'custnum'       => $custnum,
             'access_pkgnum' => $session->{'pkgnum'},
@@@ -395,29 -367,58 +397,29 @@@ sub customer_info 
    my %return;
  
    my $conf = new FS::Conf;
 -  if ($conf->exists('cust_main-require_address2')) {
 -    $return{'require_address2'} = '1';
 -  }else{
 -    $return{'require_address2'} = '';
 -  }
 +  $return{'require_address2'} = $conf->exists('cust_main-require_address2');
  
 -  if ( $FS::TicketSystem::system ) {
 -    warn "$me customer_info: initializing ticket system\n" if $DEBUG;
 -    FS::TicketSystem->init();
 -  }
 +#  if ( $FS::TicketSystem::system ) {
 +#    warn "$me customer_info: initializing ticket system\n" if $DEBUG;
 +#    FS::TicketSystem->init();
 +#  }
   
    if ( $custnum ) { #customer record
  
 +    %return = ( %return, %{ customer_info_short($p) } );
 +
 +    #redundant with customer_info_short, but we need it for several things below
      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" };
  
 -    $return{display_custnum} = $cust_main->display_custnum;
 +    my $list_tickets = list_tickets($p);
 +    $return{'tickets'} = $list_tickets->{'tickets'};
  
 -    if ( $session->{'pkgnum'} ) { 
 -      $return{balance} = $cust_main->balance_pkgnum( $session->{'pkgnum'} );
 -      #next_bill_date from cust_pkg?
 +    if ( $session->{'pkgnum'} ) {
 +      #XXX open invoices in the pkg-balances case
      } else {
 -      $return{balance} = $cust_main->balance;
 -      $return{next_bill_date} = $cust_main->next_bill_date;
 -      $return{next_bill_date_pretty} =
 -        $return{next_bill_date} ? time2str('%m/%d/%Y', $return{next_bill_date} )
 -                                : '(none)';
 -    }
 -
 -    my @tickets = $cust_main->tickets;
 -    # unavoidable false laziness w/ httemplate/view/cust_main/tickets.html
 -    if ( $FS::TicketSystem::system && 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 {
                         {
                           invnum => $_->invnum,
          time2str('%m/%d/%Y', $return{'last_invoice_date'} );
      }
  
 -    $return{countrydefault} = scalar($conf->config('countrydefault'));
 -
 +    #customer_info_short always has nobalance on..
      $return{small_custview} =
        small_custview( $cust_main,
                        $return{countrydefault},
                        ( $session->{'pkgnum'} ? 1 : 0 ), #nobalance
                      );
  
 -    $return{name} = $cust_main->first. ' '. $cust_main->get('last');
 -
      $return{has_ship_address} = $cust_main->has_ship_address;
      $return{status} = $cust_main->status;
      $return{statuscolor} = $cust_main->statuscolor;
  
 -    for (@cust_main_editable_fields) {
 -      $return{$_} = $cust_main->get($_);
 -    }
 -
 -    for (@location_editable_fields) {
 -      $return{$_} = $cust_main->bill_location->get($_);
 -      $return{'ship_'.$_} = $cust_main->ship_location->get($_);
 -    }
 -    $return{has_ship_address} = $cust_main->has_ship_address;
      # compatibility: some places in selfservice use this to determine
      # if there's a ship address
      if ( $return{has_ship_address} ) {
        $return{ship_first} = $cust_main->first;
      }
  
 -    if ( $cust_main->payby =~ /^(CARD|DCRD)$/ ) {
 -      $return{payinfo} = $cust_main->paymask;
 -      @return{'month', 'year'} = $cust_main->paydate_monthyear;
 -    }
 -
 -    $return{'invoicing_list'} =
 -      join(', ', grep { $_ !~ /^(POST|FAX)$/ } $cust_main->invoicing_list );
 -    $return{'postal_invoicing'} =
 -      0 < ( grep { $_ eq 'POST' } $cust_main->invoicing_list );
 -
      if (scalar($conf->config('support_packages'))) {
        my @support_services = ();
        foreach ($cust_main->support_services) {
        $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;
 -      $return{'svcnum'} = $session->{'svcnum'};
 -    }
 -
    } elsif ( $session->{'svcnum'} ) { #no customer record
  
      my $svc_acct = qsearchs('svc_acct', { 'svcnum' => $session->{'svcnum'} } )
@@@ -517,17 -546,6 +519,17 @@@ sub customer_info_short 
  
      $return{display_custnum} = $cust_main->display_custnum;
  
 +    if ( $session->{'pkgnum'} ) { 
 +      $return{balance} = $cust_main->balance_pkgnum( $session->{'pkgnum'} );
 +      #next_bill_date from cust_pkg?
 +    } else {
 +      $return{balance} = $cust_main->balance;
 +      $return{next_bill_date} = $cust_main->next_bill_date;
 +      $return{next_bill_date_pretty} =
 +        $return{next_bill_date} ? time2str('%m/%d/%Y', $return{next_bill_date} )
 +                                : '(none)';
 +    }
 +
      $return{countrydefault} = scalar($conf->config('countrydefault'));
  
      $return{small_custview} =
        @return{'month', 'year'} = $cust_main->paydate_monthyear;
      }
      
 +    my @invoicing_list = $cust_main->invoicing_list;
      $return{'invoicing_list'} =
 -      join(', ', grep { $_ !~ /^(POST|FAX)$/ } $cust_main->invoicing_list );
 -    #$return{'postal_invoicing'} =
 -    #  0 < ( grep { $_ eq 'POST' } $cust_main->invoicing_list );
 +      join(', ', grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list );
 +    $return{'postal_invoicing'} =
 +      0 < ( grep { $_ eq 'POST' } @invoicing_list );
  
      if ( $session->{'svcnum'} ) {
        my $cust_svc = qsearchs('cust_svc', { 'svcnum' => $session->{'svcnum'} });
@@@ -830,7 -847,7 +832,7 @@@ sub payment_info 
  
        'save_unchecked' => $conf->exists('selfservice-save_unchecked'),
  
-       'credit_card_surcharge_percentage' => $conf->config('credit-card-surcharge-percentage'),
+       'credit_card_surcharge_percentage' => scalar($conf->config('credit-card-surcharge-percentage')),
      };
  
    }
@@@ -1252,6 -1269,50 +1254,50 @@@ sub realtime_collect 
    return { 'error' => '', amount => $amount, %$error };
  }
  
+ sub start_thirdparty {
+   my $p = shift;
+   my $session = _cache->get($p->{'session_id'})
+     or return { 'error' => "Can't resume session" }; #better error message
+   my $custnum = $session->{'custnum'};
+   my $cust_main = FS::cust_main->by_key($custnum);
+   
+   my $amount = $p->{'amount'}
+     or return { error => 'no amount' };
+   my $result = $cust_main->create_payment(
+     'method'      => $p->{'method'},
+     'amount'      => $p->{'amount'},
+     'pkgnum'      => $session->{'pkgnum'},
+     'session_id'  => $p->{'session_id'},
+   );
+   
+   if ( ref($result) ) { # hashref or error
+     return $result;
+   } else {
+     return { error => $result };
+   }
+ }
+ sub finish_thirdparty {
+   my $p = shift;
+   my $session_id = delete $p->{'session_id'};
+   my $session = _cache->get($session_id)
+     or return { 'error' => "Can't resume session" };
+   my $custnum = $session->{'custnum'};
+   my $cust_main = FS::cust_main->by_key($custnum);
+   if ( $p->{_cancel} ) {
+     # customer backed out of making a payment
+     return $cust_main->cancel_payment( $session_id );
+   }
+   my $result = $cust_main->execute_payment( $session_id, %$p );
+   if ( ref($result) ) {
+     return $result;
+   } else {
+     return { error => $result };
+   }
+ }
  sub process_payment_order_pkg {
    my $p = shift;
  
@@@ -1570,9 -1631,8 +1616,9 @@@ sub list_pkgs 
                            my $primary_cust_svc = $_->primary_cust_svc;
                            +{ $_->hash,
                              $_->part_pkg->hash,
 -                            pkg_label => $_->pkg_locale,
 -                            status => $_->status,
 +                            pkg_label   => $_->pkg_locale,
 +                            status      => $_->status,
 +                            statuscolor => $_->statuscolor,
                              part_svc =>
                                [ map { $_->hashref }
                                    grep { $_->selfservice_access ne 'hidden' }
                    ],
      'small_custview' =>
        small_custview( $cust_main, $conf->config('countrydefault') ),
 +    'date_format' => $conf->config('date_format') || '%m/%d/%Y',
    };
  
  }
@@@ -2913,59 -2972,13 +2959,59 @@@ sub process_reset_passwd 
  
  }
  
 +sub list_tickets {
 +  my $p = shift;
 +  my($context, $session, $custnum) = _custoragent_session_custnum($p);
 +  return { 'error' => $session } if $context eq 'error';
 +
 +  my @tickets = ();
 +  if ( $session->{'pkgnum'} ) { 
 +
 +    #tickets for specific service with pkg-balances on
 +    my $cust_pkg = qsearchs('cust_pkg', { 'custnum' => $custnum,
 +                                          'pkgnum'  => $session->{'pkgnum'} })
 +                     or return { 'error' => 'unknown package' };
 +    foreach my $cust_svc ( $cust_pkg->cust_svc ) {
 +      push @tickets, $cust_svc->tickets( $p->{status} );
 +    }
 +
 +  } else {
 +
 +    my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
 +      or return { 'error' => "unknown custnum $custnum" };
 +
 +    @tickets = $cust_main->tickets( $p->{status} );
 +  }
 +
 +  # unavoidable false laziness w/ httemplate/view/cust_main/tickets.html
 +  if ( $FS::TicketSystem::system && FS::TicketSystem->selfservice_priority ) {
 +    my $conf = new FS::Conf;
 +    my $dir = $conf->exists('ticket_system-priority_reverse') ? -1 : 1;
 +    +{ tickets => [ 
 +         sort { 
 +           (
 +             ($a->{'_selfservice_priority'} eq '') <=>
 +             ($b->{'_selfservice_priority'} eq '')
 +           ) ||
 +           ( $dir * 
 +             ($b->{'_selfservice_priority'} <=> $a->{'_selfservice_priority'})
 +           )
 +         } @tickets
 +       ]
 +    };
 +  } else {
 +    +{ tickets => \@tickets };
 +  }
 +
 +}
 +
  sub create_ticket {
    my $p = shift;
    my($context, $session, $custnum) = _custoragent_session_custnum($p);
    return { 'error' => $session } if $context eq 'error';
  
 -  warn "$me create_ticket: initializing ticket system\n" if $DEBUG;
 -  FS::TicketSystem->init();
 +#  warn "$me create_ticket: initializing ticket system\n" if $DEBUG;
 +#  FS::TicketSystem->init();
  
    my $conf = new FS::Conf;
    my $queue = $p->{'queue'}
@@@ -3080,10 -3093,10 +3126,10 @@@ sub get_ticket 
    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();
 -  return { 'error' => 'get_ticket configuration error' }
 -    if $FS::TicketSystem::system ne 'RT_Internal';
 +#  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;
@@@ -3155,8 -3168,8 +3201,8 @@@ sub adjust_ticket_priority 
    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;
 +#  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' }
diff --combined FS/FS/Conf.pm
@@@ -2272,6 -2272,12 +2272,12 @@@ and customer address. Include units.'
    },
  
    {
+     'key'         => 'selfservice-timeout',
+     'section'     => 'self-service',
+     'description' => 'Timeout for the self-service login cookie, in seconds.  Defaults to 1 hour.',
+   },
+   {
      'key'         => 'backend-realtime',
      'section'     => 'billing',
      'description' => 'Run billing for backend signups immediately.',
    {
      'key'         => 'batchconfig-eft_canada',
      'section'     => 'billing',
-     'description' => 'Configuration for EFT Canada batching, four lines: 1. SFTP username, 2. SFTP password, 3. Transaction code, 4. Number of days to delay process date.',
+     'description' => 'Configuration for EFT Canada batching, four lines: 1. SFTP username, 2. SFTP password, 3. Transaction code, 4. Number of days to delay process date.  If you are using separate per-agent batches (batch-spoolagent), you must set this option separately for each agent, as the global setting will be ignored.',
      'type'        => 'textarea',
      'per_agent'   => 1,
    },
    },
  
    {
 +    'key'         => 'ng_selfservice-menu',
 +    'section'     => 'self-service',
 +    'description' => 'Custom menu for the next-generation self-service interface.  Each line is in the format "link Label", for example "main.php Home".  Sub-menu items are listed on subsequent lines.  Blank lines terminate the submenu.', #more docs/examples would be helpful
 +    'type'        => 'textarea',
 +  },
 +
 +  {
      'key'         => 'signup-no_company',
      'section'     => 'self-service',
      'description' => "Don't display a field for company name on signup.",
diff --combined FS/FS/Schema.pm
@@@ -1576,6 -1576,9 +1576,9 @@@ sub tables_hashref 
          #'cust_balance', @money_type,            '', '',
          'paynum',       'int',     'NULL',  '', '', '',
          'jobnum',    'bigint',     'NULL',  '', '', '', 
+         'invnum',       'int',     'NULL',  '', '', '',
+         'manual',       'char',    'NULL',   1, '', '',
+         'discount_term','int',     'NULL',  '', '', '',
        ],
        'primary_key' => 'paypendingnum',
        'unique'      => [ [ 'payunique' ] ],
          'lnp_other_provider_account', 'varchar', 'NULL', $char_d, '', '',
          'lnp_reject_reason',          'varchar', 'NULL', $char_d, '', '',
          'sms_carrierid',                  'int', 'NULL',      '', '', '',
 -        'sms_account',                'varchar', 'NULL',      '', '', '',
 +        'sms_account',                'varchar', 'NULL', $char_d, '', '',
          'max_simultaneous',               'int', 'NULL',      '', '', '',
        ],
        'primary_key' => 'svcnum',
diff --combined FS/FS/cust_main.pm
@@@ -6,6 -6,7 +6,7 @@@ use base qw( FS::cust_main::Packages FS
               FS::cust_main::NationalID
               FS::cust_main::Billing FS::cust_main::Billing_Realtime
               FS::cust_main::Billing_Discount
+              FS::cust_main::Billing_ThirdParty
               FS::cust_main::Location
               FS::otaker_Mixin FS::payinfo_Mixin FS::cust_main_Mixin
               FS::geocode_Mixin FS::Quotable_Mixin
@@@ -4135,17 -4136,14 +4136,17 @@@ sub cust_statuscolor 
    __PACKAGE__->statuscolors->{$self->cust_status};
  }
  
 -=item tickets
 +=item tickets [ STATUS ]
  
  Returns an array of hashes representing the customer's RT tickets.
  
 +An optional status (or arrayref or hashref of statuses) may be specified.
 +
  =cut
  
  sub tickets {
    my $self = shift;
 +  my $status = ( @_ && $_[0] ) ? shift : '';
  
    my $num = $conf->config('cust_main-max_tickets') || 10;
    my @tickets = ();
    if ( $conf->config('ticket_system') ) {
      unless ( $conf->config('ticket_system-custom_priority_field') ) {
  
 -      @tickets = @{ FS::TicketSystem->customer_tickets($self->custnum, $num) };
 +      @tickets = @{ FS::TicketSystem->customer_tickets( $self->custnum,
 +                                                        $num,
 +                                                        undef,
 +                                                        $status,
 +                                                      )
 +                  };
  
      } else {
  
            @{ FS::TicketSystem->customer_tickets( $self->custnum,
                                                   $num - scalar(@tickets),
                                                   $priority,
 +                                                 $status,
                                                 )
             };
        }
@@@ -86,7 -86,6 +86,7 @@@ $socket .= '.'.$tag if defined $tag && 
    'reset_passwd'              => 'MyAccount/reset_passwd',
    'check_reset_passwd'        => 'MyAccount/check_reset_passwd',
    'process_reset_passwd'      => 'MyAccount/process_reset_passwd',
 +  'list_tickets'              => 'MyAccount/list_tickets',
    'create_ticket'             => 'MyAccount/create_ticket',
    'get_ticket'                => 'MyAccount/get_ticket',
    'adjust_ticket_priority'    => 'MyAccount/adjust_ticket_priority',
    'call_time'                 => 'PrepaidPhone/call_time',
    'call_time_nanpa'           => 'PrepaidPhone/call_time_nanpa',
    'phonenum_balance'          => 'PrepaidPhone/phonenum_balance',
+   'start_thirdparty'          => 'MyAccount/start_thirdparty',
+   'finish_thirdparty'         => 'MyAccount/finish_thirdparty',
  );
  @EXPORT_OK = (
    keys(%autoload),