Merge branch 'master' of git.freeside.biz:/home/git/freeside
authorIvan Kohler <ivan@freeside.biz>
Wed, 18 Nov 2015 01:00:06 +0000 (17:00 -0800)
committerIvan Kohler <ivan@freeside.biz>
Wed, 18 Nov 2015 01:00:06 +0000 (17:00 -0800)
1  2 
FS/FS/ClientAPI/MyAccount.pm

@@@ -61,7 -61,8 +61,7 @@@ use vars qw( @cust_main_editable_field
  @cust_main_editable_fields = qw(
    first last company daytime night fax mobile
    locale
 -  payby payinfo payname paystart_month paystart_year payissue payip
 -  ss paytype paystate stateid stateid_state
 +  ss stateid stateid_state
  );
  @location_editable_fields = qw(
    address1 address2 city county state zip country
@@@ -626,6 -627,8 +626,6 @@@ sub customer_info_short 
      $return{'last'} = $cust_main->get('last');
      $return{name}   = $cust_main->first. ' '. $cust_main->get('last');
  
 -    $return{payby} = $cust_main->payby;
 -
      #none of these are terribly expensive if we want 'em...
      for (@cust_main_editable_fields) {
        $return{$_} = $cust_main->get($_);
          if $cust_main->ship_locationnum;
      }
   
 -    if ( $cust_main->payby =~ /^(CARD|DCRD)$/ ) {
 -      $return{payinfo} = $cust_main->paymask;
 -      @return{'month', 'year'} = $cust_main->paydate_monthyear;
 -    }
 -    
      my @invoicing_list = $cust_main->invoicing_list;
      $return{'invoicing_list'} =
        join(', ', grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list );
  
    }
  
+   # this is here because this routine is called by both fs_ and ng_ main pages, where it appears
+   # it is not customer-specific, though it is only shown to authenticated customers
+   # it is not currently agent-specific, though at some point it might be
+   $return{'announcement'} = join(' ',$conf->config('selfservice-announcement')) || '';
    return { 'error'          => '',
             'custnum'        => $custnum,
             %return,
@@@ -748,8 -761,55 +753,8 @@@ sub edit_info 
    # but if it hasn't been passed in at all, leave ship_location alone--
    # DON'T change it to match bill_location.
  
 -  my $payby = '';
 -  if (exists($p->{'payby'})) {
 -    $p->{'payby'} =~ /^([A-Z]{4})$/
 -      or return { 'error' => "illegal_payby " . $p->{'payby'} };
 -    $payby = $1;
 -  }
 -
    my $conf = new FS::Conf;
  
 -  if ( $payby =~ /^(CARD|DCRD)$/ ) {
 -
 -    $new->paydate($p->{'year'}. '-'. $p->{'month'}. '-01');
 -
 -    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' );
 -
 -  } elsif ( $payby =~ /^(CHEK|DCHK)$/ ) {
 -
 -    my $payinfo;
 -    $p->{'payinfo1'} =~ /^([\dx]+)$/
 -      or return { 'error' => "illegal account number ". $p->{'payinfo1'} };
 -    my $payinfo1 = $1;
 -     $p->{'payinfo2'} =~ /^([\dx\.]+)$/ # . turned on by echeck-country CA ?
 -      or return { 'error' => "illegal ABA/routing number ". $p->{'payinfo2'} };
 -    my $payinfo2 = $1;
 -    $payinfo = $payinfo1. '@'. $payinfo2;
 -
 -    $new->payinfo( ($payinfo eq $cust_main->paymask)
 -                     ? $cust_main->payinfo
 -                     : $payinfo
 -                 );
 -
 -    $new->set( 'payby' => $p->{'auto'} ? 'CHEK' : 'DCHK' );
 -
 -  } elsif ( $payby =~ /^(BILL)$/ ) {
 -    #no-op
 -  } elsif ( $payby ) {  #notyet ready
 -    return { 'error' => "unknown payby $payby" };
 -  }
 -
    my @invoicing_list;
    if ( exists $p->{'invoicing_list'} || exists $p->{'postal_invoicing'} ) {
      #false laziness with httemplate/edit/process/cust_main.cgi
@@@ -845,30 -905,31 +850,30 @@@ sub payment_info 
  
    $return{balance} = $cust_main->balance; #XXX pkg-balances?
  
 -  $return{payname} = $cust_main->payname
 -                     || ( $cust_main->first. ' '. $cust_main->get('last') );
 -
    $return{$_} = $cust_main->bill_location->get($_) 
      for qw(address1 address2 city state zip);
  
 -  $return{payby} = $cust_main->payby;
 -  $return{stateid_state} = $cust_main->stateid_state;
 -
 -  if ( $cust_main->payby =~ /^(CARD|DCRD)$/ ) {
 -    $return{card_type} = cardtype($cust_main->payinfo);
 -    $return{payinfo} = $cust_main->paymask;
 -
 -    @return{'month', 'year'} = $cust_main->paydate_monthyear;
 -
 -  }
 -
 -  if ( $cust_main->payby =~ /^(CHEK|DCHK)$/ ) {
 -    my ($payinfo1, $payinfo2) = split '@', $cust_main->paymask;
 -    $return{payinfo1} = $payinfo1;
 -    $return{payinfo2} = $payinfo2;
 -    $return{paytype}  = $cust_main->paytype;
 -    $return{paystate} = $cust_main->paystate;
 -    $return{payname}  = $cust_main->payname;  # override 'first/last name' default from above, if any.  Is instution-name here.  (#15819)
 -  }
 +  #XXX look for stored cust_payby info
 +  #
 +  # $return{payname} = $cust_main->payname
 +  #                    || ( $cust_main->first. ' '. $cust_main->get('last') );
 +  #
 +  #if ( $cust_main->payby =~ /^(CARD|DCRD)$/ ) {
 +  #  $return{card_type} = cardtype($cust_main->payinfo);
 +  #  $return{payinfo} = $cust_main->paymask;
 +  #
 +  #  @return{'month', 'year'} = $cust_main->paydate_monthyear;
 +  #
 +  #}
 +  #
 +  #if ( $cust_main->payby =~ /^(CHEK|DCHK)$/ ) {
 +  #  my ($payinfo1, $payinfo2) = split '@', $cust_main->paymask;
 +  #  $return{payinfo1} = $payinfo1;
 +  #  $return{payinfo2} = $payinfo2;
 +  #  $return{paytype}  = $cust_main->paytype;
 +  #  $return{paystate} = $cust_main->paystate;
 +  #  $return{payname}  = $cust_main->payname; # override 'first/last name' default from above, if any.  Is instution-name here.  (#15819)
 +  #}
  
    if ( $conf->config('prepayment_discounts-credit_type') ) {
      #need to eval?
@@@ -1489,6 -1550,7 +1494,6 @@@ sub invoice_logo 
           };
  }
  
 -
  sub list_invoices {
    my $p = shift;
    my $session = _cache->get($p->{'session_id'})
            };
  }
  
 +sub list_payby {
 +  my $p = shift;
 +
 +  my($context, $session, $custnum) = _custoragent_session_custnum($p);
 +  return { 'error' => $session } if $context eq 'error';
 +
 +  my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
 +    or return { 'error' => "unknown custnum $custnum" };
 +
 +  return {
 +    'payby' => [ map {
 +                       my $cust_payby = $_;
 +                       +{
 +                          map { $_ => $cust_payby->$_ }
 +                            qw( custpaybynum weight payby paymask paydate
 +                                payname paystate paytype
 +                              )
 +                        };
 +                     }
 +                   $cust_main->cust_payby
 +               ],
 +  };
 +}
 +
 +sub insert_payby {
 +  my $p = shift;
 +
 +  my($context, $session, $custnum) = _custoragent_session_custnum($p);
 +  return { 'error' => $session } if $context eq 'error';
 +
 +  #XXX payinfo1 + payinfo2 for CHEK?
 +  #or take the opportunity to use separate, more well- named fields?
 +  # my $payinfo;
 +  # $p->{'payinfo1'} =~ /^([\dx]+)$/
 +  #   or return { 'error' => "illegal account number ". $p->{'payinfo1'} };
 +  # my $payinfo1 = $1;
 +  #  $p->{'payinfo2'} =~ /^([\dx\.]+)$/ # . turned on by echeck-country CA ?
 +  #   or return { 'error' => "illegal ABA/routing number ". $p->{'payinfo2'} };
 +  # my $payinfo2 = $1;
 +  # $payinfo = $payinfo1. '@'. $payinfo2;
 +
 +  my $cust_payby = new FS::cust_payby {
 +    'custnum' => $custnum,
 +    map { $_ => $p->{$_} } qw( weight payby payinfo paycvv paydate payname
 +                               paystate paytype payip 
 +                             ),
 +  };
 +
 +  my $error = $cust_payby->insert;
 +  if ( $error ) {
 +    return { 'error' => $error };
 +  } else {
 +    return { 'custpaybynum' => $cust_payby->custpaybynum };
 +  }
 +  
 +}
 +
 +sub delete_payby {
 +  my $p = shift;
 +
 +  my($context, $session, $custnum) = _custoragent_session_custnum($p);
 +  return { 'error' => $session } if $context eq 'error';
 +
 +  my $cust_payby = qsearchs('cust_payby', {
 +                              'custnum'      => $custnum,
 +                              'custpaybynum' => $p->{'custpaybynum'},
 +                           })
 +    or return { 'error' => 'unknown custpaybynum '. $p->{'custpaybynum'} };
 +
 +  return { 'error' => $cust_payby->delete };
 +
 +}
 +
  sub cancel {
    my $p = shift;
    my $session = _cache->get($p->{'session_id'})
@@@ -2514,36 -2503,39 +2519,36 @@@ sub order_recharge 
  sub _do_bop_realtime {
    my ($cust_main, $status, %opt) = @_;
  
 -    my $old_balance = $cust_main->balance;
 -
 -    my @cust_bill;
 -    my $bill_error = $cust_main->bill(
 -      'return_bill'   => \@cust_bill,
 -    );
 +  my $old_balance = $cust_main->balance;
  
 -    $bill_error ||= $cust_main->apply_payments_and_credits;
 +  my @cust_bill;
 +  my $bill_error = $cust_main->bill(
 +    'return_bill'   => \@cust_bill,
 +  );
  
 -    $bill_error ||= $cust_main->realtime_collect('selfservice' => 1)
 -      if $cust_main->payby =~ /^(CARD|CHEK)$/;
 +  $bill_error ||= $cust_main->apply_payments_and_credits;
  
 -    if (    $cust_main->balance > $old_balance
 -         && $cust_main->balance > 0
 -         && ( $cust_main->payby !~ /^(BILL|DCRD|DCHK)$/
 -                || $status eq 'suspended'
 -            )
 -       )
 -    {
 -      unless ( $opt{'no_invoice_void'} ) {
 +  $bill_error ||= $cust_main->realtime_collect('selfservice' => 1);
  
 -        #this used to apply a credit, but now we can void invoices...
 -        foreach my $cust_bill (@cust_bill) {
 -          my $voiderror = $cust_bill->void('automatic payment failed');
 -          warn "Error voiding cust bill after decline: $voiderror" if $voiderror;
 -        }
 +  if (    $cust_main->balance > $old_balance
 +       && $cust_main->balance > 0
 +       && ( $cust_main->has_cust_payby_auto || $status eq 'suspended' )
 +     )
 +  {
 +    unless ( $opt{'no_invoice_void'} ) {
  
 +      #this used to apply a credit, but now we can void invoices...
 +      foreach my $cust_bill (@cust_bill) {
 +        my $voiderror = $cust_bill->void('automatic payment failed');
 +        warn "Error voiding cust bill after decline: $voiderror" if $voiderror;
        }
  
 -      return { 'error' => '_decline', 'bill_error' => $bill_error };
      }
  
 -    '';
 +    return { 'error' => '_decline', 'bill_error' => $bill_error };
 +  }
 +
 +  '';
  }
  
  sub renew_info {
@@@ -2990,13 -2982,15 +2995,15 @@@ sub myaccount_passwd 
          )
      && ! $svc_acct->check_password($p->{'old_password'});
  
+     # should move password length checks into is_password_allowed
    $error = 'Password too short.'
      if length($p->{'new_password'}) < ($conf->config('passwordmin') || 6);
    $error = 'Password too long.'
      if length($p->{'new_password'}) > ($conf->config('passwordmax') || 8);
  
-   $svc_acct->set_password($p->{'new_password'});
-   $error ||= $svc_acct->replace();
+   $error ||= $svc_acct->is_password_allowed($p->{'new_password'})
+          ||  $svc_acct->set_password($p->{'new_password'})
+          ||  $svc_acct->replace();
  
    #regular pw change in self-service should change contact pw too, otherwise its
    #way too confusing.  hell its confusing they're separate at all, but alas.
@@@ -3275,8 -3269,9 +3282,9 @@@ sub process_reset_passwd 
  
    if ( $svc_acct ) {
  
-     $svc_acct->set_password($p->{'new_password'});
-     my $error = $svc_acct->replace();
+     my $error ||= $svc_acct->is_password_allowed($p->{'new_password'})
+               ||  $svc_acct->set_password($p->{'new_password'})
+               ||  $svc_acct->replace();
  
      return { %$info, 'error' => $error } if $error;