diff options
author | Ivan Kohler <ivan@freeside.biz> | 2015-02-10 01:38:56 -0800 |
---|---|---|
committer | Ivan Kohler <ivan@freeside.biz> | 2015-02-10 01:38:56 -0800 |
commit | a4d4d3df88b33a6db30b565921f6d62efb252351 (patch) | |
tree | 0ddfa8fe885dfe6776a0c074aed9e1e0735a7cd7 | |
parent | 6615733676adb431ae48c78ce24758fe571614c1 (diff) |
multiple payment options, RT#23741
33 files changed, 1034 insertions, 1234 deletions
diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 2b959e6..4497916 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -2249,7 +2249,7 @@ and customer address. Include units.', 'section' => 'self-service', 'description' => 'Acceptable payment types for the signup server', 'type' => 'selectmultiple', - 'select_enum' => [ qw(CARD DCRD CHEK DCHK PREPAY PPAL BILL COMP) ], + 'select_enum' => [ qw(CARD DCRD CHEK DCHK PREPAY PPAL ) ], # BILL COMP) ], }, { @@ -2652,13 +2652,13 @@ and customer address. Include units.', 'section' => 'billing', 'description' => 'Available payment types.', 'type' => 'selectmultiple', - 'select_enum' => [ qw(CARD DCRD CHEK DCHK BILL CASH WEST MCRD MCHK PPAL COMP) ], + 'select_enum' => [ qw(CARD DCRD CHEK DCHK CASH WEST MCRD MCHK PPAL) ], }, { 'key' => 'payby-default', - 'section' => 'UI', - 'description' => 'Default payment type. HIDE disables display of billing information and sets customers to BILL.', + 'section' => 'deprecated', + 'description' => 'Deprecated; in 4.x there is no longer the concept of a single "payment type". Used to indicate the default payment type. HIDE disables display of billing information and sets customers to BILL.', 'type' => 'select', 'select_enum' => [ '', qw(CARD DCRD CHEK DCHK BILL CASH WEST MCRD PPAL COMP HIDE) ], }, diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 133b6d8..54a4680 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -1651,6 +1651,9 @@ sub tables_hashref { 'bill_locationnum', 'int', 'NULL', '', '', '', 'ship_locationnum', 'int', 'NULL', '', '', '', 'taxstatusnum', 'char', 'NULL', 32, '', '', + 'complimentary', 'char', 'NULL', 1, '', '', + 'po_number', 'varchar', 'NULL', $char_d, '', '', + 'invoice_attn', 'varchar', 'NULL', $char_d, '', '', ], 'primary_key' => 'custnum', 'unique' => [ [ 'agentnum', 'agent_custid' ] ], @@ -1699,7 +1702,7 @@ sub tables_hashref { 'columns' => [ 'custpaybynum', 'serial', '', '', '', '', 'custnum', 'int', '', '', '', '', - 'weight', 'int', '', '', '', '', + 'weight', 'int', 'NULL', '', '', '', 'payby', 'char', '', 4, '', '', 'payinfo', 'varchar', 'NULL', 512, '', '', 'cardtype', 'varchar', 'NULL', $char_d, '', '', diff --git a/FS/FS/Template_Mixin.pm b/FS/FS/Template_Mixin.pm index 95d001e..fe484a4 100644 --- a/FS/FS/Template_Mixin.pm +++ b/FS/FS/Template_Mixin.pm @@ -316,9 +316,6 @@ sub print_generic { unless $format =~ /^(latex|html|template)$/; my $cust_main = $self->cust_main || $self->prospect_main; - $cust_main->payname( $cust_main->first. ' '. $cust_main->getfield('last') ) - unless $cust_main->payname - && $cust_main->payby !~ /^(CARD|DCRD|CHEK|DCHK)$/; my $locale = $params{'locale'} || $cust_main->locale; @@ -565,9 +562,11 @@ sub print_generic { 'custnum' => $cust_main->display_custnum, 'prospectnum' => $cust_main->prospectnum, 'agent_custid' => &$escape_function($cust_main->agent_custid), - ( map { $_ => &$escape_function($cust_main->$_()) } qw( - payname company address1 address2 city state zip fax - )), + ( map { $_ => &$escape_function($cust_main->$_()) } + qw( company address1 address2 city state zip fax ) + ), + 'payname' => &$escape_function( $cust_main->invoice_attn + || $cust_main->contact_firstlast ), #global config 'ship_enable' => $conf->exists('invoice-ship_address'), @@ -655,10 +654,10 @@ sub print_generic { my @address = (); $invoice_data{'address'} = \@address; push @address, - $cust_main->payname. - ( ( $cust_main->payby eq 'BILL' ) && $cust_main->payinfo - ? " (P.O. #". $cust_main->payinfo. ")" - : '' + $invoice_data{'payname'}. + ( $cust_main->po_number + ? " (P.O. #". $cust_main->po_number. ")" + : '' ) ; push @address, $cust_main->company diff --git a/FS/FS/Upgrade.pm b/FS/FS/Upgrade.pm index d05b309..263be80 100644 --- a/FS/FS/Upgrade.pm +++ b/FS/FS/Upgrade.pm @@ -309,7 +309,10 @@ sub upgrade_data { tie my %hash, 'Tie::IxHash', - #cust_main (remove paycvv from history) + #payby conditions to new ones + 'part_event_condition' => [], + + #cust_main (remove paycvv from history, locations, cust_payby, etc) 'cust_main' => [], #contact -> cust_contact / prospect_contact diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index cd675f9..d38f3d0 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -76,6 +76,7 @@ use FS::Locales; use FS::upgrade_journal; use FS::sales; use FS::cust_payby; +use FS::contact; # 1 is mostly method/subroutine entry and options # 2 traces progress of some operations @@ -95,8 +96,6 @@ our $ucfirst_nowarn = 0; our @encrypted_fields = ('payinfo', 'paycvv'); sub nohistory_fields { ('payinfo', 'paycvv'); } -our @paytypes = ('', 'Personal checking', 'Personal savings', 'Business checking', 'Business savings'); - our $conf; #ask FS::UID to run this stuff for us later #$FS::UID::callback{'FS::cust_main'} = sub { @@ -331,7 +330,7 @@ invoicing_list destination to the newly-created svc_acct. Here's an example: $cust_main->insert( {}, [ $email, 'POST' ] ); Currently available options are: I<depend_jobnum>, I<noexport>, -I<tax_exemption> and I<prospectnum>. +I<tax_exemption>, I<prospectnum>, I<contact> and I<contact_params>. If I<depend_jobnum> is set, all provisioning jobs will have a dependancy on the supplied jobnum (they will not run until the specific job completes). @@ -351,6 +350,14 @@ If I<prospectnum> is set, moves contacts and locations from that prospect. If I<contact> is set to an arrayref of FS::contact objects, inserts those new contacts with this new customer. +If I<contact_params> is set to a hashref of CGI parameters (and I<contact> is +unset), inserts those new contacts with this new customer. Handles CGI +paramaters for an "m2" multiple entry field as passed by edit/cust_main.cgi + +If I<cust_payby_params> is set to a hashref o fCGI parameters, inserts those +new stored payment records with this new customer. Handles CGI parameters +for an "m2" multiple entry field as passed by edit/cust_main.cgi + =cut sub insert { @@ -378,7 +385,7 @@ sub insert { my $payby = ''; if ( $self->payby eq 'PREPAY' ) { - $self->payby('BILL'); + $self->payby(''); #'BILL'); $prepay_identifier = $self->payinfo; $self->payinfo(''); @@ -403,7 +410,7 @@ sub insert { } elsif ( $self->payby =~ /^(CASH|WEST|MCRD|MCHK|PPAL)$/ ) { $payby = $1; - $self->payby('BILL'); + $self->payby(''); #'BILL'); $amount = $self->paid; } @@ -557,8 +564,10 @@ sub insert { } - my $contact = delete $options{'contact'}; - if ( $contact ) { + warn " setting contacts\n" + if $DEBUG > 1; + + if ( my $contact = delete $options{'contact'} ) { foreach my $c ( @$contact ) { $c->custnum($self->custnum); @@ -570,6 +579,34 @@ sub insert { } + } elsif ( my $contact_params = delete $options{'contact_params'} ) { + + my $error = $self->process_o2m( 'table' => 'contact', + 'fields' => FS::contact->cgi_contact_fields, + 'params' => $contact_params, + ); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + + warn " setting cust_payby\n" + if $DEBUG > 1; + + if ( my $cust_payby_params = delete $options{'cust_payby_params'} ) { + + my $error = $self->process_o2m( + 'table' => 'cust_payby', + 'fields' => FS::cust_payby->cgi_cust_payby_fields, + 'params' => $cust_payby_params, + 'hash_callback' => \&FS::cust_payby::cgi_hash_callback, + ); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } warn " setting cust_main_exemption\n" @@ -1122,10 +1159,9 @@ sub delete { #cust_tax_adjustment in financials? #cust_pay_pending? ouch - #cust_recon? foreach my $table (qw( cust_main_invoice cust_main_exemption cust_tag cust_attachment contact - cust_location cust_main_note cust_tax_adjustment + cust_payby cust_location cust_main_note cust_tax_adjustment cust_pay_void cust_pay_batch queue cust_tax_exempt )) { foreach my $record ( qsearch( $table, { 'custnum' => $self->custnum } ) ) { @@ -1250,13 +1286,10 @@ sub replace { if $DEBUG; my $curuser = $FS::CurrentUser::CurrentUser; - if ( $self->payby eq 'COMP' - && $self->payby ne $old->payby - && ! $curuser->access_right('Complimentary customer') - ) - { - return "You are not permitted to create complimentary accounts."; - } + return "You are not permitted to create complimentary accounts." + if $self->complimentary eq 'Y' + && $self->complimentary ne $old->complimentary + && ! $curuser->access_right('Complimentary customer'); local($ignore_expired_card) = 1 if $old->payby =~ /^(CARD|DCRD)$/ @@ -1285,8 +1318,8 @@ sub replace { my $dbh = dbh; for my $l (qw(bill_location ship_location)) { - my $old_loc = $old->$l; - my $new_loc = $self->$l; + #my $old_loc = $old->$l; + my $new_loc = $self->$l or next; # find the existing location if there is one $new_loc->set('custnum' => $self->custnum); @@ -1403,21 +1436,19 @@ sub replace { } - if ( $self->payby =~ /^(CARD|CHEK|LECB)$/ - && ( ( $self->get('payinfo') ne $old->get('payinfo') - && $self->get('payinfo') !~ /^99\d{14}$/ - ) - || grep { $self->get($_) ne $old->get($_) } qw(paydate payname) - ) - ) - { + if ( my $cust_payby_params = delete $options{'cust_payby_params'} ) { - # card/check/lec info has changed, want to retry realtime_ invoice events - my $error = $self->retry_realtime; + my $error = $self->process_o2m( + 'table' => 'cust_payby', + 'fields' => FS::cust_payby->cgi_cust_payby_fields, + 'params' => $cust_payby_params, + 'hash_callback' => \&FS::cust_payby::cgi_hash_callback, + ); if ( $error ) { $dbh->rollback if $oldAutoCommit; return $error; } + } unless ( $import || $skip_fuzzyfiles ) { @@ -1555,6 +1586,8 @@ sub check { || $self->ut_flag('message_noemail') || $self->ut_enum('locale', [ '', FS::Locales->locales ]) || $self->ut_currencyn('currency') + || $self->ut_alphan('po_number') + || $self->ut_enum('complimentary', [ '', 'Y' ]) ; foreach (qw(company ship_company)) { @@ -1809,6 +1842,11 @@ sub check { } + return "You are not permitted to create complimentary accounts." + if ! $self->custnum + && $self->complimentary eq 'Y' + && ! $FS::CurrentUser->CurrentUser->access_right('Complimentary customer'); + if ( $self->paydate eq '' || $self->paydate eq '-' ) { return "Expiration date required" # shouldn't payinfo_check do this? @@ -1947,7 +1985,7 @@ sub cust_payby { qsearch({ 'table' => 'cust_payby', 'hashref' => { 'custnum' => $self->custnum }, - 'order_by' => 'ORDER BY weight ASC', + 'order_by' => "ORDER BY payby IN ('CARD','CHEK') DESC, weight ASC", }); } @@ -4816,18 +4854,31 @@ sub _upgrade_data { #class method while (my $cust_main = $search->fetch) { - my $cust_payby = new FS::cust_payby { - 'custnum' => $cust_main->custnum, - 'weight' => 1, - map { $_ => $cust_main->$_(); } @payfields - }; + unless ( $cust_main->payby =~ /^(BILL|COMP)$/ ) { - my $error = $cust_payby->insert; - die $error if $error; + my $cust_payby = new FS::cust_payby { + 'custnum' => $cust_main->custnum, + 'weight' => 1, + map { $_ => $cust_main->$_(); } @payfields + }; + + my $error = $cust_payby->insert; + die $error if $error; + + } + + $cust_main->complimentary('Y') if $cust_main->payby eq 'COMP'; + + $cust_main->invoice_attn( $cust_main->payname ) + if $cust_main->payby eq 'BILL' && $cust_main->payname; + $cust_main->po_number( $cust_main->payinfo ) + if $cust_main->payby eq 'BILL' && $cust_main->payinfo; $cust_main->setfield($_, '') foreach @payfields; - $error = $cust_main->replace; - die $error if $error; + my $error = $cust_main->replace; + die "Error upgradging payment information for custnum ". + $cust_main->custnum. ": $error" + if $error; }; diff --git a/FS/FS/cust_main/Location.pm b/FS/FS/cust_main/Location.pm index be375dd..3cb73ff 100644 --- a/FS/FS/cust_main/Location.pm +++ b/FS/FS/cust_main/Location.pm @@ -74,9 +74,11 @@ sub bill_location { $self->hashref->{bill_location} ||= FS::cust_location->by_key($self->bill_locationnum) # degraded mode--let the system keep running during upgrades - || FS::cust_location->new({ - map { $_ => $self->get($_) } @location_fields - }) + || ( $self->get('address1') + && FS::cust_location->new({ + map { $_ => $self->get($_) } @location_fields + }) + ); } =item ship_location @@ -89,9 +91,17 @@ sub ship_location { my $self = shift; $self->hashref->{ship_location} ||= FS::cust_location->by_key($self->ship_locationnum) - || FS::cust_location->new({ - map { $_ => $self->get('ship_'.$_) || $self->get($_) } @location_fields - }) + # degraded mode--let the system keep running during upgrades + || ( $self->get('ship_address1') + ? FS::cust_location->new({ + map { $_ => $self->get('ship_'.$_) } @location_fields + }) + : $self->get('address1') + ? FS::cust_location->new({ + map { $_ => $self->get($_) } @location_fields + }) + : '' + ); } diff --git a/FS/FS/cust_main/Search.pm b/FS/FS/cust_main/Search.pm index f0a7d41..097f2fb 100644 --- a/FS/FS/cust_main/Search.pm +++ b/FS/FS/cust_main/Search.pm @@ -608,14 +608,6 @@ listref of start date, end date listref of start date, end date -=item payby - -listref - -=item paydate_year - -=item paydate_month - =item current_balance listref (list returned by FS::UI::Web::parse_lt_gt($cgi, 'current_balance')) @@ -646,7 +638,6 @@ sub search { 'status' => '', 'address' => '', 'zip' => '', - 'paydate_year' => '', 'invoice_terms' => '', 'custbatch' => '', %$params @@ -911,40 +902,6 @@ sub search { } ### - # payby - ### - - if ( $params->{'payby'} ) { - - my @payby = ref( $params->{'payby'} ) - ? @{ $params->{'payby'} } - : ( $params->{'payby'} ); - - @payby = grep /^([A-Z]{4})$/, @payby; - my $in_payby = 'IN(' . join(',', map {"'$_'"} @payby) . ')'; - push @where, "EXISTS( SELECT 1 FROM cust_payby WHERE payby $in_payby ". - "AND cust_payby.custnum = cust_main.custnum)" - if @payby; - } - - ### - # paydate_year / paydate_month - ### - - if ( $params->{'paydate_year'} =~ /^(\d{4})$/ ) { - my $year = $1; - $params->{'paydate_month'} =~ /^(\d\d?)$/ - or die "paydate_year without paydate_month?"; - my $month = $1; - - push @where, - 'paydate IS NOT NULL', - "paydate != ''", - "CAST(paydate AS timestamp) < CAST('$year-$month-01' AS timestamp )" -; - } - - ### # invoice terms ### @@ -1134,7 +1091,6 @@ sub search { 'extra_headers' => \@extra_headers, 'extra_fields' => \@extra_fields, }; - #warn Data::Dumper::Dumper($sql_query); $sql_query; } diff --git a/FS/FS/cust_payby.pm b/FS/FS/cust_payby.pm index ad3d80a..a65a171 100644 --- a/FS/FS/cust_payby.pm +++ b/FS/FS/cust_payby.pm @@ -1,26 +1,23 @@ package FS::cust_payby; +use base qw( FS::payinfo_Mixin FS::cust_main_Mixin FS::Record ); use strict; -use base qw( FS::payinfo_Mixin FS::Record ); -use FS::UID; -use FS::Record qw( qsearchs ); #qsearch; -use FS::payby; -use FS::cust_main; use Business::CreditCard qw( validate cardtype ); +use FS::UID qw( dbh ); use FS::Msgcat qw( gettext ); +use FS::Record; #qw( qsearch qsearchs ); +use FS::payby; +use FS::cust_main; +use FS::banned_pay; -use vars qw( $conf @encrypted_fields - $ignore_expired_card $ignore_banned_card - $ignore_invalid_card - ); - -@encrypted_fields = ('payinfo', 'paycvv'); +our @encrypted_fields = ('payinfo', 'paycvv'); sub nohistory_fields { ('payinfo', 'paycvv'); } -$ignore_expired_card = 0; -$ignore_banned_card = 0; -$ignore_invalid_card = 0; +our $ignore_expired_card = 0; +our $ignore_banned_card = 0; +our $ignore_invalid_card = 0; +our $conf; install_callback FS::UID sub { $conf = new FS::Conf; #yes, need it for stuff below (prolly should be cached) @@ -141,15 +138,44 @@ otherwise returns false. =cut -# the insert method can be inherited from FS::Record +sub insert { + my $self = shift; -=item delete + local $SIG{HUP} = 'IGNORE'; + local $SIG{INT} = 'IGNORE'; + local $SIG{QUIT} = 'IGNORE'; + local $SIG{TERM} = 'IGNORE'; + local $SIG{TSTP} = 'IGNORE'; + local $SIG{PIPE} = 'IGNORE'; + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + my $error = $self->SUPER::insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } -Delete this record from the database. + if ( $self->payby =~ /^(CARD|CHEK)$/ ) { + # new auto card/check info, want to retry realtime_ invoice events + # (new customer? that's okay, they won't have any) + my $error = $self->cust_main->retry_realtime; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } -=cut + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + ''; -# the delete method can be inherited from FS::Record +} + +=item delete + +Delete this record from the database. =item replace OLD_RECORD @@ -158,7 +184,87 @@ returns the error, otherwise returns false. =cut -# the replace method can be inherited from FS::Record +sub replace { + my $self = shift; + + my $old = ( blessed($_[0]) && $_[0]->isa('FS::Record') ) + ? shift + : $self->replace_old; + + if ( length($old->paycvv) && $self->paycvv =~ /^\s*[\*x]*\s*$/ ) { + $self->paycvv($old->paycvv); + } + + if ( $self->payby =~ /^(CARD|DCRD)$/ + && ( $self->payinfo =~ /xx/ + || $self->payinfo =~ /^\s*N\/A\s+\(tokenized\)\s*$/ + ) + ) + { +warn $self->payinfo; +warn $old->payinfo; + $self->payinfo($old->payinfo); + + } elsif ( $self->payby =~ /^(CHEK|DCHK)$/ && $self->payinfo =~ /xx/ ) { + #fix for #3085 "edit of customer's routing code only surprisingly causes + #nothing to happen... + # this probably won't do the right thing when we don't have the + # public key (can't actually get the real $old->payinfo) + my($new_account, $new_aba) = split('@', $self->payinfo); + my($old_account, $old_aba) = split('@', $old->payinfo); + $new_account = $old_account if $new_account =~ /xx/; + $new_aba = $old_aba if $new_aba =~ /xx/; + $self->payinfo($new_account.'@'.$new_aba); + } + + local($ignore_expired_card) = 1 + if $old->payby =~ /^(CARD|DCRD)$/ + && $self->payby =~ /^(CARD|DCRD)$/ + && ( $old->payinfo eq $self->payinfo || $old->paymask eq $self->paymask ); + + local($ignore_banned_card) = 1 + if ( $old->payby =~ /^(CARD|DCRD)$/ && $self->payby =~ /^(CARD|DCRD)$/ + || $old->payby =~ /^(CHEK|DCHK)$/ && $self->payby =~ /^(CHEK|DCHK)$/ ) + && ( $old->payinfo eq $self->payinfo || $old->paymask eq $self->paymask ); + + local $SIG{HUP} = 'IGNORE'; + local $SIG{INT} = 'IGNORE'; + local $SIG{QUIT} = 'IGNORE'; + local $SIG{TERM} = 'IGNORE'; + local $SIG{TSTP} = 'IGNORE'; + local $SIG{PIPE} = 'IGNORE'; + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + my $error = $self->SUPER::replace($old); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + + if ( $self->payby =~ /^(CARD|CHEK)$/ + && ( ( $self->get('payinfo') ne $old->get('payinfo') + && $self->get('payinfo') !~ /^99\d{14}$/ + ) + || grep { $self->get($_) ne $old->get($_) } qw(paydate payname) + ) + ) + { + + # card/check/lec info has changed, want to retry realtime_ invoice events + my $error = $self->cust_main->retry_realtime; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + ''; + +} =item check @@ -174,7 +280,7 @@ sub check { my $error = $self->ut_numbern('custpaybynum') || $self->ut_foreign_key('custnum', 'cust_main', 'custnum') - || $self->ut_number('weight') + || $self->ut_numbern('weight') #encrypted #|| $self->ut_textn('payinfo') #encrypted #|| $self->ut_textn('paycvv') # || $self->ut_textn('paymask') #XXX something @@ -207,7 +313,7 @@ sub check { my $payinfo = $self->payinfo; $payinfo =~ s/\D//g; $payinfo =~ /^(\d{13,16}|\d{8,9})$/ - or return gettext('invalid_card'); # . ": ". $self->payinfo; + or return gettext('invalid_card'); #. ": ". $self->payinfo; $payinfo = $1; $self->payinfo($payinfo); validate($payinfo) @@ -308,52 +414,23 @@ sub check { } } - } elsif ( $self->payby eq 'LECB' ) { - - my $payinfo = $self->payinfo; - $payinfo =~ s/\D//g; - $payinfo =~ /^1?(\d{10})$/ or return 'invalid btn billing telephone number'; - $payinfo = $1; - $self->payinfo($payinfo); - $self->paycvv(''); - - } elsif ( $self->payby eq 'BILL' ) { - - $error = $self->ut_textn('payinfo'); - return "Illegal P.O. number: ". $self->payinfo if $error; - $self->paycvv(''); - - } elsif ( $self->payby eq 'COMP' ) { - - my $curuser = $FS::CurrentUser::CurrentUser; - if ( ! $self->custnum - && ! $curuser->access_right('Complimentary customer') - ) - { - return "You are not permitted to create complimentary accounts." - } - - $error = $self->ut_textn('payinfo'); - return "Illegal comp account issuer: ". $self->payinfo if $error; - $self->paycvv(''); - - } elsif ( $self->payby eq 'PREPAY' ) { - - my $payinfo = $self->payinfo; - $payinfo =~ s/\W//g; #anything else would just confuse things - $self->payinfo($payinfo); - $error = $self->ut_alpha('payinfo'); - return "Illegal prepayment identifier: ". $self->payinfo if $error; - return "Unknown prepayment identifier" - unless qsearchs('prepay_credit', { 'identifier' => $self->payinfo } ); - $self->paycvv(''); +# } elsif ( $self->payby eq 'PREPAY' ) { +# +# my $payinfo = $self->payinfo; +# $payinfo =~ s/\W//g; #anything else would just confuse things +# $self->payinfo($payinfo); +# $error = $self->ut_alpha('payinfo'); +# return "Illegal prepayment identifier: ". $self->payinfo if $error; +# return "Unknown prepayment identifier" +# unless qsearchs('prepay_credit', { 'identifier' => $self->payinfo } ); +# $self->paycvv(''); } if ( $self->paydate eq '' || $self->paydate eq '-' ) { return "Expiration date required" # shouldn't payinfo_check do this? - unless $self->payby =~ /^(BILL|PREPAY|CHEK|DCHK|LECB|CASH|WEST|MCRD|MCHK|PPAL)$/; + unless $self->payby =~ /^(CHEK|DCHK)$/; $self->paydate(''); } else { my( $m, $y ); @@ -400,6 +477,247 @@ sub check { $self->SUPER::check; } +sub _banned_pay_hashref { + my $self = shift; + + my %payby2ban = ( + 'CARD' => 'CARD', + 'DCRD' => 'CARD', + 'CHEK' => 'CHEK', + 'DCHK' => 'CHEK' + ); + + { + 'payby' => $payby2ban{$self->payby}, + 'payinfo' => $self->payinfo, + #don't ever *search* on reason! #'reason' => + }; +} + +=item paydate_mon_year + +Returns a two element list consisting of the paydate month and year. + +=cut + +sub paydate_mon_year { + my $self = shift; + + my $date = $self->paydate; # || '12-2037'; + + #false laziness w/elements/select-month_year.html + if ( $date =~ /^(\d{4})-(\d{1,2})-\d{1,2}$/ ) { #PostgreSQL date format + ( $2, $1 ); + } elsif ( $date =~ /^(\d{1,2})-(\d{1,2}-)?(\d{4}$)/ ) { + ( $1, $3 ); + } else { + warn "unrecognized expiration date format: $date"; + ( '', '' ); + } + +} + +=item realtime_bop + +=cut + +sub realtime_bop { + my( $self, %opt ) = @_; + + $opt{$_} = $self->$_() for qw( payinfo payname paydate ); + + if ( $self->locationnum ) { + my $cust_location = $self->cust_location; + $opt{$_} = $cust_location->$_() for qw( address1 address2 city state zip ); + } + + $self->cust_main->realtime_bop({ + 'method' => FS::payby->payby2bop( $self->payby ), + %opt, + }); + +} + +=item paytypes + +Returns a list of valid values for the paytype field (bank account type for +electronic check payment). + +=cut + +sub paytypes { + #my $class = shift; + + ('', 'Personal checking', 'Personal savings', 'Business checking', 'Business savings'); +} + +=item cgi_cust_payby_fields + +Returns the field names used in the web interface (including some pseudo-fields). + +=cut + +sub cgi_cust_payby_fields { + #my $class = shift; + [qw( payby payinfo paydate_month paydate_year paycvv payname weight + payinfo1 payinfo2 payinfo3 paytype paystate )]; +} + +=item cgi_hash_callback HASHREF + +Subroutine (not a class or object method). Processes a hash reference +of web interface contet (transfers the data from pseudo-fields to real fields). + +=cut + +sub cgi_hash_callback { + my $hashref = shift; + + my %noauto = ( + 'CARD' => 'DCRD', + 'CHEK' => 'DCHK', + ); + $hashref->{payby} = $noauto{$hashref->{payby}} + if ! $hashref->{weight} && exists $noauto{$hashref->{payby}}; + + if ( $hashref->{payby} =~ /^(CHEK|DCHK)$/ ) { + + unless ( grep $hashref->{$_}, qw( payinfo1 payinfo2 payinfo3 payname ) ) { + %$hashref = (); + return; + } + + $hashref->{payinfo} = $hashref->{payinfo1}. '@'; + $hashref->{payinfo} .= $hashref->{payinfo3}.'.' + if $conf->config('echeck-country') eq 'CA'; + $hashref->{payinfo} .= $hashref->{'payinfo2'}; + + $hashref->{payname} .= $hashref->{'payname_CHEK'}; + + } elsif ( $hashref->{payby} =~ /^(CARD|DCRD)$/ ) { + + unless ( grep $hashref->{$_}, qw( payinfo paycvv payname ) ) { + %$hashref = (); + return; + } + + } + + $hashref->{paydate}= $hashref->{paydate_month}. '-'. $hashref->{paydate_year}; + +} + +=item search_sql + +Class method. + +Returns a qsearch hash expression to search for parameters specified in HASHREF. +Valid paramters are: + +=over 4 + +=item payby + +listref + +=item paydate_year + +=item paydate_month + + +=back + +=cut + +sub search_sql { + my ($class, $params) = @_; + + my @where = (); + my $orderby; + + # initialize these to prevent warnings + $params = { + 'paydate_year' => '', + %$params + }; + + ### + # payby + ### + + if ( $params->{'payby'} ) { + + my @payby = ref( $params->{'payby'} ) + ? @{ $params->{'payby'} } + : ( $params->{'payby'} ); + + @payby = grep /^([A-Z]{4})$/, @payby; + my $in_payby = 'IN(' . join(',', map {"'$_'"} @payby) . ')'; + push @where, "cust_payby.payby $in_payby" + if @payby; + } + + ### + # paydate_year / paydate_month + ### + + if ( $params->{'paydate_year'} =~ /^(\d{4})$/ ) { + my $year = $1; + $params->{'paydate_month'} =~ /^(\d\d?)$/ + or die "paydate_year without paydate_month?"; + my $month = $1; + + push @where, + 'cust_payby.paydate IS NOT NULL', + "cust_payby.paydate != ''", + "CAST(cust_payby.paydate AS timestamp) < CAST('$year-$month-01' AS timestamp )" +; + } + ## + # setup queries, subs, etc. for the search + ## + + $orderby ||= 'ORDER BY custnum'; + + # here is the agent virtualization + push @where, + $FS::CurrentUser::CurrentUser->agentnums_sql(table => 'cust_main'); + + my $extra_sql = scalar(@where) ? ' WHERE '. join(' AND ', @where) : ''; + + my $addl_from = ' LEFT JOIN cust_main USING ( custnum ) '; + # always make address fields available in results + for my $pre ('bill_', 'ship_') { + $addl_from .= + ' LEFT JOIN cust_location AS '.$pre.'location '. + 'ON (cust_main.'.$pre.'locationnum = '.$pre.'location.locationnum) '; + } + + my $count_query = "SELECT COUNT(*) FROM cust_payby $addl_from $extra_sql"; + + my @select = ( 'cust_payby.*', + #'cust_main.custnum', + # there's a good chance that we'll need these + 'cust_main.bill_locationnum', + 'cust_main.ship_locationnum', + FS::UI::Web::cust_sql_fields($params->{'cust_fields'}), + ); + + my $select = join(', ', @select); + + my $sql_query = { + 'table' => 'cust_payby', + 'select' => $select, + 'addl_from' => $addl_from, + 'hashref' => {}, + 'extra_sql' => $extra_sql, + 'order_by' => $orderby, + 'count_query' => $count_query, + }; + $sql_query; + +} + =back =head1 BUGS diff --git a/FS/FS/o2m_Common.pm b/FS/FS/o2m_Common.pm index d237bef..4f6d2e7 100644 --- a/FS/FS/o2m_Common.pm +++ b/FS/FS/o2m_Common.pm @@ -103,6 +103,7 @@ sub process_o2m { map { $_ => $opt{'params'}->{$add_param."_$_"} } @{ $opt{'fields'} } ); + &{ $opt{'hash_callback'} }( \%hash ) if $opt{'hash_callback'}; #next unless grep { $_ =~ /\S/ } values %hash; my $new_obj = "FS::$table"->new( { %$hashref, %hash } ); @@ -117,6 +118,7 @@ sub process_o2m { my %hash = map { $_ => $opt{'params'}->{$add_param."_$_"} } @{ $opt{'fields'} }; + &{ $opt{'hash_callback'} }( \%hash ) if $opt{'hash_callback'}; next unless grep { $_ =~ /\S/ } values %hash; my $add_obj = "FS::$table"->new( { %$hashref, %hash } ); diff --git a/FS/FS/part_event/Action/cust_bill_realtime_lec.pm b/FS/FS/part_event/Action/cust_bill_realtime_lec.pm deleted file mode 100644 index cd03ddc..0000000 --- a/FS/FS/part_event/Action/cust_bill_realtime_lec.pm +++ /dev/null @@ -1,28 +0,0 @@ -package FS::part_event::Action::cust_bill_realtime_lec; - -use strict; -use base qw( FS::part_event::Action ); - -sub description { - #'Run phone bill ("LEC") billing with a <a href="http://420.am/business-onlinepayment/">Business::OnlinePayment</a> realtime gateway'; - 'Run phone bill ("LEC") billing with a Business::OnlinePayment realtime gateway'; -} - -sub deprecated { 1; } - -sub eventtable_hashref { - { 'cust_bill' => 1 }; -} - -sub default_weight { 30; } - -sub do_action { - my( $self, $cust_bill ) = @_; - - #my $cust_main = $self->cust_main($cust_bill); - my $cust_main = $cust_bill->cust_main; - - $cust_bill->realtime_lec; -} - -1; diff --git a/FS/FS/part_event/Condition/has_cust_payby_auto.pm b/FS/FS/part_event/Condition/has_cust_payby_auto.pm new file mode 100644 index 0000000..edfb7ec --- /dev/null +++ b/FS/FS/part_event/Condition/has_cust_payby_auto.pm @@ -0,0 +1,43 @@ +package FS::part_event::Condition::has_cust_payby_auto; + +use strict; +use Tie::IxHash; +use FS::payby; + +use base qw( FS::part_event::Condition ); + +sub description { + 'Customer has automatic payment information'; +} + +tie my %payby, 'Tie::IxHash', FS::payby->cust_payby2shortname; +delete $payby{'DCRD'}; +delete $payby{'DCHK'}; + +sub option_fields { + ( + 'payby' => { + label => 'Has automatic payment info', + type => 'select', + options => [ keys %payby ], + option_labels => \%payby, + }, + ); +} + +sub condition { + my( $self, $object ) = @_; + + my $cust_main = $self->cust_main($object); + + scalar( qsearch({ + 'table' => 'cust_payby', + 'hashref' => { 'custnum' => $cust_main->custnum, + 'payby' => $self->option('payby') + }, + 'order_by' => 'LIMIT 1', + }) ); + +} + +1; diff --git a/FS/FS/part_event/Condition/hasnt_cust_payby_auto.pm b/FS/FS/part_event/Condition/hasnt_cust_payby_auto.pm new file mode 100644 index 0000000..6655a63 --- /dev/null +++ b/FS/FS/part_event/Condition/hasnt_cust_payby_auto.pm @@ -0,0 +1,27 @@ +package FS::part_event::Condition::hasnt_cust_payby_auto; + +use strict; +use Tie::IxHash; + +use base qw( FS::part_event::Condition ); + +sub description { + 'Customer does not have automatic payment information'; +} + +sub condition { + my( $self, $object ) = @_; + + my $cust_main = $self->cust_main($object); + + ! scalar( qsearch({ + 'table' => 'cust_payby', + 'hashref' => { 'custnum' => $cust_main->custnum, + }, + 'extra_sql' => "AND payby IN ( 'CARD', 'CHEK' )", + 'order_by' => 'LIMIT 1', + }) ); + +} + +1; diff --git a/FS/FS/part_event/Condition/payby.pm b/FS/FS/part_event/Condition/payby.pm deleted file mode 100644 index 16bf480..0000000 --- a/FS/FS/part_event/Condition/payby.pm +++ /dev/null @@ -1,44 +0,0 @@ -package FS::part_event::Condition::payby; - -use strict; -use Tie::IxHash; -use FS::payby; - -use base qw( FS::part_event::Condition ); - -sub description { - #'customer payment types: '; - 'Customer payment type'; -} - -#something like this -tie my %payby, 'Tie::IxHash', FS::payby->cust_payby2longname; -sub option_fields { - ( - 'payby' => { - label => 'Customer payment type', - #type => 'select-multiple', - type => 'checkbox-multiple', - options => [ keys %payby ], - option_labels => \%payby, - }, - ); -} - -sub condition { - my( $self, $object ) = @_; - - my $cust_main = $self->cust_main($object); - - my $hashref = $self->option('payby') || {}; - $hashref->{ $cust_main->payby }; - -} - -sub condition_sql { - my( $self, $table ) = @_; - - 'cust_main.payby IN '. $self->condition_sql_option_option('payby'); -} - -1; diff --git a/FS/FS/part_event_condition.pm b/FS/FS/part_event_condition.pm index ac2ee82..200049d 100644 --- a/FS/FS/part_event_condition.pm +++ b/FS/FS/part_event_condition.pm @@ -354,6 +354,45 @@ sub order_conditions_sql { } +sub _upgrade_data { #class method + my ($class, %opts) = @_; + + foreach my $part_event_condition ( + qsearch('part_event_condition', { 'conditionname' => 'payby' } ) + ) { + + my $payby = $part_event_condition->option('payby'); + + if ( scalar( keys %$payby ) == 1 ) { + + if ( $payby->{'CARD'} ) { + + $part_event_condition->conditionname('has_cust_payby_auto'); + + } elsif ( $payby->{'CHEK'} ) { + + $part_event_condition->conditionname('has_cust_payby_auto'); + + } + + } elsif ( $payby->{'BILL'} && ! $payby->{'CARD'} && ! $payby->{'CHEK'} ) { + + $part_event_condition->conditionname('hasnt_cust_payby_auto'); + + } else { + + die 'Unable to automatically convert payby condition for event #'. + $part_event_condition->eventpart. "\n"; + + } + + my $error = $part_event_condition->replace; + die $error if $error; + + } + +} + =back =head1 BUGS diff --git a/FS/FS/payby.pm b/FS/FS/payby.pm index c4aa1b1..13423c4 100644 --- a/FS/FS/payby.pm +++ b/FS/FS/payby.pm @@ -5,7 +5,6 @@ use vars qw(%hash %payby2bop); use Tie::IxHash; use Business::CreditCard; - =head1 NAME FS::payby - Object methods for payment type records @@ -39,9 +38,8 @@ Payment types. =cut # paybys can be any/all of: -# - a customer payment type (cust_main.payby) +# - a customer saved payment type (cust_payby.payby) # - a payment or refund type (cust_pay.payby, cust_pay_batch.payby, cust_refund.payby) -# - an event type (part_bill_event.payby) tie %hash, 'Tie::IxHash', 'CARD' => { @@ -70,18 +68,6 @@ tie %hash, 'Tie::IxHash', cust_pay => 'CHEK', #this is a customer type only, payments are CHEK... realtime => 1, }, - #'LECB' => { - # tinyname => 'phone bill', - # shortname => 'Phone bill billing', - # longname => 'Phone bill billing', - # realtime => 1, - #}, - 'BILL' => { - tinyname => 'billing', - shortname => 'Billing', - payname => 'Check', - longname => 'Billing', - }, 'PPAL' => { tinyname => 'PayPal', shortname => 'PayPal', @@ -143,12 +129,6 @@ tie %hash, 'Tie::IxHash', longname => 'Wire transfer', cust_main => '', #not a customer type }, - 'COMP' => { - tinyname => 'comp', - shortname => 'Complimentary', - longname => 'Complimentary', - cust_pay => '', # (free) is depricated as a payment type in cust_pay - }, 'CBAK' => { tinyname => 'chargeback', shortname => 'Chargeback', @@ -234,6 +214,11 @@ sub cust_payby { grep { ! exists $hash{$_}->{cust_main} } $self->payby; } +sub cust_payby2shortname { + my $self = shift; + map { $_ => $hash{$_}->{shortname} } $self->cust_payby; +} + sub cust_payby2longname { my $self = shift; map { $_ => $hash{$_}->{longname} } $self->cust_payby; diff --git a/httemplate/edit/cust_main.cgi b/httemplate/edit/cust_main.cgi index da87bfc..f99cce2 100755 --- a/httemplate/edit/cust_main.cgi +++ b/httemplate/edit/cust_main.cgi @@ -1,8 +1,4 @@ -<& /elements/header.html, - $title, - '', - ' onUnload="myclose()"' #hmm, in billing.html -&> +<& /elements/header.html, $title, &> <& /elements/error.html &> @@ -60,7 +56,7 @@ </TABLE> </TD> </TR> -<TR><TD STYLE="height:40px"></TD></TR> +<TR><TD STYLE="height:14px"></TD></TR> <TR> <TD STYLE="width:650px"> <FONT CLASS="fsinnerbox-title"><% mt('Service address') |h %></FONT> @@ -105,16 +101,13 @@ function samechanged(what) { <BR> -<& cust_main/contacts_new.html, - 'cust_main' => $cust_main, -&> +<& cust_main/contacts_new.html, 'cust_main'=>$cust_main, &> %# billing info <& cust_main/billing.html, $cust_main, 'payinfo' => $payinfo, 'invoicing_list' => \@invoicing_list, &> -<BR> % my $ro_comments = $conf->exists('cust_main-use_comments')?'':'readonly'; % if (!$ro_comments || $cust_main->comments) { @@ -156,18 +149,6 @@ function samechanged(what) { <INPUT TYPE="hidden" NAME="usernum" VALUE="<% $cust_main->usernum %>"> -%# cust_main/bottomfixup.js -% foreach my $hidden ( -% 'payauto', 'billday', -% 'payinfo', 'payinfo1', 'payinfo2', 'payinfo3', 'paytype', -% 'payname', 'paystate', 'exp_month', 'exp_year', 'paycvv', -% 'paystart_month', 'paystart_year', 'payissue', -% 'payip', -% 'paid', -% ) { - <INPUT TYPE="hidden" NAME="<% $hidden %>" VALUE=""> -% } - <& cust_main/bottomfixup.html, 'custnum' => $custnum &> <BR> @@ -375,9 +356,6 @@ if ( $cgi->param('error') ) { } -my %keep = map { $_=>1 } qw( error tagnum lock_agentnum lock_pkgpart ); -$cgi->delete( grep { !$keep{$_} && $_ !~ /^tax_/ } $cgi->param ); - my $title = $custnum ? 'Edit Customer' : 'Add Customer'; $title = mt($title); $title .= ": ". $cust_main->name if $custnum; diff --git a/httemplate/edit/cust_main/billing.html b/httemplate/edit/cust_main/billing.html index fcd8f01..fa392bb 100644 --- a/httemplate/edit/cust_main/billing.html +++ b/httemplate/edit/cust_main/billing.html @@ -1,123 +1,7 @@ -%if ( $payby_default eq 'HIDE' ) { -% $cust_main->payby('BILL') unless $cust_main->payby; -% my $payby = $cust_main->payby; - - <INPUT TYPE="hidden" NAME="payby" VALUE="<% $payby %>"> - - <INPUT TYPE="hidden" NAME="<%$payby%>_payinfo" VALUE="<% $cust_main->paymask %>"> - -% foreach my $field (qw( payname paycvv paystart_month paystart_year payissue payip paytype paystate billday )) { - - <INPUT TYPE="hidden" NAME="<% $payby.'_'.$field %>" VALUE="<% $cust_main->get($field) %>"> - -% } - -% #false laziness w/elements/select-month_year.html & view/cust_main/billing.html -% my( $mon, $year ); -% my $date = $cust_main->paydate || '12-2037'; -% if ( $date =~ /^(\d{4})-(\d{1,2})-\d{1,2}$/ ) { #PostgreSQL date format -% ( $mon, $year ) = ( $2, $1 ); -% } elsif ( $date =~ /^(\d{1,2})-(\d{1,2}-)?(\d{4}$)/ ) { -% ( $mon, $year ) = ( $1, $3 ); -% } else { -% die "unrecognized expiration date format: $date"; -% } - - <INPUT TYPE="hidden" NAME="<%$payby%>_exp_month" VALUE="<% $mon %>"> - <INPUT TYPE="hidden" NAME="<%$payby%>_exp_year" VALUE="<% $year %>"> - - <INPUT TYPE="hidden" NAME="tax" VALUE="<% $cust_main->tax %>"> - - <INPUT TYPE="hidden" NAME="invoicing_list" VALUE="<% join(', ', @invoicing_list) %>"> - -% } else { -% % my $r = qq!<font color="#ff0000">*</font> !; - <BR><FONT CLASS="fsinnerbox-title"><% mt('Billing information') |h %></FONT> - <% &ntable("#cccccc") %> - - <TR> - <TD ALIGN="right" WIDTH="200"><%$r%><% mt('Billing type') |h %></TD> - <SCRIPT> - var mywindow = -1; - function myopen(filename,windowname,properties) { - myclose(); - mywindow = window.open(filename,windowname,properties); - } - function myclose() { - if ( mywindow != -1 ) - mywindow.close(); - mywindow = -1; - } - - var achwindow = -1; - function achopen(filename,windowname,properties) { - achclose(); - achwindow = window.open(filename,windowname,properties); - } - function achclose() { - if ( achwindow != -1 ) - achwindow.close(); - achwindow = -1; - } - - function card_changed(what) { - if ( - what.form.payinfo.value.substring(0, 4) == '4093' - || what.form.payinfo.value.substring(0, 4) == '4911' - || what.form.payinfo.value.substring(0, 4) == '4936' - || what.form.payinfo.value.substring(0, 6) == '564132' - || what.form.payinfo.value.substring(0, 2) == '63' - || what.form.payinfo.value.substring(0, 2) == '67' - ) - { - what.form.paystart_month.disabled = false; - what.form.paystart_year.disabled = false; - what.form.payissue.disabled = false; - what.form.paystart_month.style.backgroundColor = '#ffffff'; - what.form.paystart_year.style.backgroundColor = '#ffffff'; - what.form.payissue.style.backgroundColor = '#ffffff'; - document.getElementById('paystart_label').style.color = '#000000'; - document.getElementById('payissue_label').style.color = '#000000'; - } else { - what.form.paystart_month.disabled = true; - what.form.paystart_year.disabled = true; - what.form.payissue.disabled = true; - what.form.paystart_month.style.backgroundColor = '#dddddd'; - what.form.paystart_year.style.backgroundColor = '#dddddd'; - what.form.payissue.style.backgroundColor = '#dddddd'; - document.getElementById('paystart_label').style.color = '#999999'; - document.getElementById('payissue_label').style.color = '#999999'; - } - return true; - } - - function init_payauto_changed(){ - var f = document.getElementById('CARD_payauto'); - if(f != null) payauto_changed(f); - f = document.getElementById('CHEK_payauto'); - if(f != null) payauto_changed(f); - } - - function payauto_changed(payauto_field){ - var select = (payauto_field.name == 'CARD_payauto') ? 'CARD_billday' : 'CHEK_billday'; - var span = document.getElementById('td_'+select); - select = document.getElementById(select); - if (span == null || select == null) return; - if(payauto_field.checked) { - span.style.color = '#000000'; - select.disabled = false; - } - else { - span.style.color = '#999999'; - select.disabled = true; - //why? select.selectedIndex = 0; - } - } - function tax_changed(what) { var num = document.getElementById(what.id + '_num'); if ( what.checked ) { @@ -129,321 +13,10 @@ </SCRIPT> - <& /elements/init_overlib.html &> - -% my $payby = $cust_main->payby; -% my $paytype = $cust_main->paytype; -% my( $account, $aba ) = split('@', $payinfo); -% my $branch = ''; -% ($branch,$aba) = split('\.',$aba) -% if $conf->config('echeck-country') eq 'CA'; -% -% my $disabled = 'DISABLED style="background-color: #dddddd"'; -% my $text_disabled = 'style="color: #999999"'; -% -% if ( $payby =~ /^(CARD|DCRD)$/ && cardtype($payinfo) =~ /^(Switch|Solo)$/ ) { -% $disabled = 'style="background-color: #ffffff"'; -% $text_disabled = 'style="color: #000000";' -% } -% -% my $disable_payauto = $conf->exists('disable_payauto_default'); -% my $CARD_payauto_checked = $payby eq 'DCRD' ? '' -% : $payby eq 'CARD' ? 'CHECKED' -% : $disable_payauto ? '' : 'CHECKED'; -% my $CHEK_payauto_checked = $payby eq 'DCHK' ? '' -% : $payby eq 'CHEK' ? 'CHECKED' -% : $disable_payauto ? '' : 'CHECKED'; -% -% sub billday_options { -% my $curr_value = shift; -% my $ret = ''; -% for my $billday ( 1 .. 28 ) { -% my $sel = ''; -% $sel = "SELECTED='SELECTED'" if $curr_value == $billday; -% $ret .= "<OPTION VALUE='$billday' $sel>$billday</OPTION>"; -% } -% $ret; -% } -% -% my $card_billday_style = $payby eq 'CARD' ? '' : 'style="color: #999999"'; -% my $chek_billday_style = $payby eq 'CHEK' ? '' : 'style="color: #999999"'; -% my $card_billday_select_disabled = $payby eq 'CARD' ? '' : 'DISABLED'; -% my $chek_billday_select_disabled = $payby eq 'CHEK' ? '' : 'DISABLED'; -% -% #false laziness w/view/cust_main/billing.html and misc/payment.cgi -% my $routing_label = $conf->config('echeck-country') eq 'US' -% ? 'ABA/Routing number' -% : 'Routing number'; -% my $routing_size = $conf->config('echeck-country') eq 'CA' ? 4 : 10; -% my $routing_maxlength = $conf->config('echeck-country') eq 'CA' ? 3 : 9; -% -% -% my %payby = ( -% -% 'CARD' => -% -% '<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 HEIGHT=192>'. -% -% qq!<TR><TD ALIGN="right" WIDTH="200">${r}!.emt('Card number').qq! </TD>!. -% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="CARD_payinfo" VALUE="!. ( $payby =~ /^(CARD|DCRD)$/ ? $payinfo : '' ). qq!" MAXLENGTH=19 onChange="card_changed(this)" onKeyUp="card_changed(this)"></TD></TR>!. -% -% qq!<TR><TD ALIGN="right" WIDTH="200">${r}!.emt('Expiration').qq! </TD>!. -% '<TD WIDTH="408">'. -% -% include('/elements/select-month_year.html', -% 'prefix' => 'CARD_exp', -% 'selected_date' => -% ( $payby =~ /^(CARD|DCRD)$/ ? $cust_main->paydate : '' ), -% ). -% -% '</TD></TR>'. -% -% qq!<TR><TD ALIGN="right" WIDTH="200">!.emt('CVV2').qq! !. -% -% qq!(<A HREF="javascript:void(0);" onClick="overlib( OLiframeContent('../docs/cvv2.html', 480, 352, 'cvv2_popup' ), CAPTION, 'CVV2 Help', STICKY, AUTOSTATUSCAP, CLOSECLICK, DRAGGABLE ); return false;">!.emt('help').qq!</A>)!. -% qq!</TD>!. -% '<TD WIDTH="408"><INPUT TYPE="text" NAME="CARD_paycvv" VALUE="'. ( $payby =~ /^(CARD|DCRD)$/ && !$cust_main->is_encrypted($cust_main->paycvv) ? $cust_main->paycvv : '' ). '" SIZE=4 MAXLENGTH=4>'. -% -% qq!<TR><TD ALIGN="right" WIDTH="200"><SPAN ID="paystart_label" $text_disabled>!.emt('Start date').qq! </SPAN></TD>!. -% '<TD WIDTH="408">'. -% -% include('/elements/select-month_year.html', -% 'prefix' => 'CARD_paystart', -% 'disabled' => $disabled, -% 'empty_option' => 1, -% 'start_year' => 2000, -% 'end_year' => (localtime())[5] + 1900, -% 'selected_date' => ( -% ( $payby =~ /^(CARD|DCRD)$/ -% && cardtype($payinfo) =~ /^(Switch|Solo)$/ ) -% ? $cust_main->paystart_month. '-'. -% $cust_main->paystart_year -% : '' -% ) -% ). -% -% qq!<SPAN ID="payissue_label" $text_disabled>!.emt('or Issue number').qq! </SPAN>!. -% '<INPUT TYPE="text" NAME="CARD_payissue" VALUE="'. ( $payby =~ /^(CARD|DCRD)$/ ? $cust_main->payissue : '' ). qq!" SIZE=3 MAXLENGTH=2 $disabled></TD></TR>!. -% -% qq!<TR><TD ALIGN="right" WIDTH="200">${r}!.emt('Exact name on card').qq! </TD>!. -% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="CARD_payname" VALUE="!. ( $payby =~ /^(CARD|DCRD)$/ ? $cust_main->payname : '' ). qq!"></TD></TR>!. -% -% qq!<TR><TD COLSPAN=2 WIDTH="608">!. -% qq!<INPUT TYPE="checkbox" onchange="payauto_changed(this);" ID="CARD_payauto" NAME="CARD_payauto" $CARD_payauto_checked> !. -% emt('Charge future payments to this [_1] automatically','credit card').'</TD></TR>'. -% -% ( $conf->exists('cust_main-select-billday') ? -% qq!<TR><TD ALIGN="RIGHT" id="td_CARD_billday" $card_billday_style> -% Charge on this day of each month</TD><TD> -% <SELECT id="CARD_billday" $card_billday_select_disabled NAME="CARD_billday">! -% . billday_options($cust_main->billday) . qq!</SELECT> </TD></TR>! -% : '' -% ). -% -% '</TABLE>', -% -% 'CHEK' => -% -% '<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 HEIGHT=192>'. -% -% qq!<TR><TD ALIGN="right" WIDTH="200">${r}!.emt('Account number').qq! </TD>!. -% qq!<TD><INPUT TYPE="text" SIZE=12 NAME="CHEK_payinfo1" VALUE="!. ( $payby =~ /^(CHEK|DCHK)$/ ? $account : '' ). '"></TD>'. -% qq!<TD ALIGN="right">!.emt('Type').qq!</TD><TD><SELECT NAME="CHEK_paytype">!. -% join('', map { qq!<OPTION VALUE="$_" !.($paytype eq $_ ? 'SELECTED' : '').">$_</OPTION>" } @FS::cust_main::paytypes). -% qq!</SELECT></TD></TR>!. -% -% qq!<TR><TD ALIGN="right" WIDTH="200">${r}!.emt($routing_label).qq! </TD>!. -% qq!<TD COLSPAN="3" WIDTH="408"><INPUT TYPE="text" SIZE=$routing_size MAXLENGTH=$routing_maxlength NAME="CHEK_payinfo2" VALUE="!. ( $payby =~ /^(CHEK|DCHK)$/ ? $aba : '' ). qq!"> !. -% qq!(<A HREF="javascript:void(0);" onClick="overlib( OLiframeContent('../docs/ach.html', 380, 240, 'ach_popup' ), CAPTION, 'ACH Help', STICKY, AUTOSTATUSCAP, CLOSECLICK, DRAGGABLE ); return false;">!.emt('help').qq!</A>)!. -% qq!</TD></TR>!. -% -% qq!<INPUT TYPE="hidden" NAME="CHEK_exp_month" VALUE="12">!. -% qq!<INPUT TYPE="hidden" NAME="CHEK_exp_year" VALUE="2037">!. -% -% ( $conf->config('echeck-country') eq 'CA' ? -% qq!<TR><TD ALIGN="right">$r !.emt('Branch number').qq!</TD><TD COLSPAN="3"> -% <INPUT TYPE="text" name="CHEK_payinfo3" VALUE="$branch" SIZE=6 MAXLENGTH=5></TD></TR>! : '' ). -% -% qq!<TR><TD ALIGN="right" WIDTH="200">${r}!.emt('Bank name').qq! </TD>!. -% qq!<TD COLSPAN="3" WIDTH="408"><INPUT TYPE="text" NAME="CHEK_payname" VALUE="!. ( $payby =~ /^(CHEK|DCHK)$/ ? $cust_main->payname : '' ). qq!"></TD></TR>!. -% ( $conf->exists('show_bankstate') ? -% qq!<TR><TD ALIGN="right" WIDTH="200">$paystate_label</TD>!. -% qq!<TD COLSPAN="3" WIDTH="408">!. -% include('/elements/select-state.html', -% 'empty' => emt('(choose)'), -% 'state' => $cust_main->paystate, -% 'country' => $cust_main->country, -% 'prefix' => 'CHEK_pay', -% ). "</TD></TR>" -% : '<INPUT TYPE="hidden" NAME="CHEK_paystate" VALUE="'. -% $cust_main->paystate. '">' -% ). -% -% -% qq!<TR><TD COLSPAN=4 WIDTH="608">!. -% qq!<INPUT TYPE="checkbox" onchange="payauto_changed(this);" ID="CHEK_payauto" NAME="CHEK_payauto" $CHEK_payauto_checked> !. -% emt('Charge future payments to this [_1] automatically','electronic check').'</TD></TR>'. -% -% ( $conf->exists('cust_main-select-billday') ? -% qq!<TR><TD ALIGN="RIGHT" id="td_CHEK_billday" $chek_billday_style> -% Charge on this day of each month</TD><TD> -% <SELECT id="CHEK_billday" $chek_billday_select_disabled NAME="CHEK_billday">! -% . billday_options($cust_main->billday) . qq!</SELECT> </TD></TR>! -% : '' -% ). -% -% '</TABLE>', -% -% 'LECB' => -% -% '<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 HEIGHT=192>'. -% -% qq!<TR><TD ALIGN="right" WIDTH="200">${r}!.emt('Phone number').qq! </TD>!. -% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="LECB_payinfo" VALUE="!. ( $payby eq 'LECB' ? $cust_main->payinfo : '' ). qq!" MAXLENGTH=15 SIZE=16></TD></TR>!. -% -% qq!<INPUT TYPE="hidden" NAME="LECB_exp_month" VALUE="12">!. -% qq!<INPUT TYPE="hidden" NAME="LECB_exp_year" VALUE="2037">!. -% qq!<INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!. -% -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% -% '</TABLE>', -% -% 'BILL' => -% -% '<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 HEIGHT=192>'. -% -% qq!<TR><TD ALIGN="right" WIDTH="200">!.emt('P.O.').qq! </TD>!. -% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="BILL_payinfo" VALUE="!. ( $payby eq 'BILL' ? $cust_main->payinfo : '' ). qq!"></TD></TR>!. -% -% qq!<INPUT TYPE="hidden" NAME="BILL_exp_month" VALUE="12">!. -% qq!<INPUT TYPE="hidden" NAME="BILL_exp_year" VALUE="2037">!. -% -% qq!<TR><TD ALIGN="right" WIDTH="200">!.emt('Attention').qq! </TD>!. -% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="BILL_payname" VALUE="!. encode_entities( $payby eq 'BILL' ? $cust_main->payname : '' ). qq!"></TD></TR>!. -% -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% -% '</TABLE>', -% -% 'COMP' => -% -% '<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 HEIGHT=192>'. -% -% qq!<TR><TD ALIGN="right" WIDTH="200">${r}!.emt('Approved by').qq! </TD>!. -% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="COMP_payinfo" VALUE=""></TD></TR>!. -% -% qq!<TR><TD ALIGN="right" WIDTH="200">${r}!.emt('Expiration').qq! </TD>!. -% '<TD WIDTH="408">'. -% -% include('/elements/select-month_year.html', -% 'prefix' => 'COMP_exp', -% 'selected_date' => -% ( $payby eq 'COMP' ? $cust_main->paydate : '' ), -% ). -% -% '</TD></TR>'. -% -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% -% '</TABLE>', -% -% 'CASH' => -% -% '<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 HEIGHT=192>'. -% -% qq!<TR><TD ALIGN="right" WIDTH="200">${r}!.emt('Amount').qq! </TD>!. -% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="CASH_paid" VALUE="!. ( $payby eq 'CASH' ? $cust_main->paid : '' ). qq!"></TD></TR>!. -% -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% -% '</TABLE>', -% -% 'WEST' => -% -% '<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 HEIGHT=192>'. -% -% qq!<TR><TD ALIGN="right" WIDTH="200">${r}!.emt('Amount').qq! </TD>!. -% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="WEST_paid" VALUE="!. ( $payby eq 'WEST' ? $cust_main->paid : '' ). qq!"></TD></TR>!. -% -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% -% '</TABLE>', -% -% 'MCRD' => -% -% '<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 HEIGHT=192>'. -% -% qq!<TR><TD ALIGN="right" WIDTH="200">${r}!.emt('Amount').qq! </TD>!. -% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="MCRD_paid" VALUE="!. ( $payby eq 'MCRD' ? $cust_main->paid : '' ). qq!"></TD></TR>!. -% -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% '<TR><TD> </TD></TR>'. -% -% '</TABLE>', -% -% ); -% -% #this should use FS::payby -% my @allopt = qw( CARD CHEK LECB BILL CASH WEST MCRD COMP ); -% -% my %allopt = map { $_ => FS::payby->shortname($_) } @allopt; -% -% if ( $cust_main->custnum ) { -% #don't offer CASH/WEST/MCRD initial payment types when editing customer -% delete $allopt{$_} for qw(CASH WEST MCRD); -% } -% -% my @options = grep exists( $allopt{$_} ), @payby; -% -% my %payby2option = ( -% ( map { $_ => $_ } @options ), -% 'DCRD' => 'CARD', -% 'DCHK' => 'CHEK', -% ); - - <TD WIDTH="408"> - <& /elements/selectlayers.html, - 'field' => 'payby', - 'curr_value' => $payby2option{$payby || $payby_default || $payby[0] }, - 'options' => \@options, - 'labels' => \%allopt, - 'html_between' => '</TD></TR></TABLE>', - 'layer_callback' => sub { my $layer = shift; $payby{$layer}; }, - 'onchange' => 'init_payauto_changed();', - &> + <BR><FONT CLASS="fsinnerbox-title"><% mt('Billing information') |h %></FONT> <% &ntable("#cccccc") %> - <TR><TD> </TD></TR> - % my $curuser = $FS::CurrentUser::CurrentUser; % my @exempt_groups = grep /\S/, $conf->config('tax-cust_exempt-groups'); % if ( $conf->exists('cust_class-tax_exempt') @@ -490,18 +63,6 @@ </TD> </TR> - <TR> - <TD WIDTH="608" COLSPAN="2"><INPUT TYPE="checkbox" NAME="invoicing_list_FAX" VALUE="FAX" <% - - ( grep { $_ eq 'FAX' } @invoicing_list ) - ? 'CHECKED' - : '' - - %>> <% mt('Fax invoices') |h %> - - </TD> - </TR> - % } <TR> @@ -544,6 +105,26 @@ % } <TR> + <TD ALIGN="right" WIDTH="200"><% mt('Charge card/e-check on this day of the month') |h %> </TD> + <TD> + <SELECT NAME="billday"> + <% billday_options($cust_main->billday) %> + </SELECT> + </TD> + </TR> + +% sub billday_options { +% my $curr_value = shift; +% my $ret = ''; +% for my $billday ( 1 .. 28 ) { +% my $sel = ''; +% $sel = "SELECTED='SELECTED'" if $curr_value == $billday; +% $ret .= "<OPTION VALUE='$billday' $sel>$billday</OPTION>"; +% } +% $ret; +% } + + <TR> <TD ALIGN="right" WIDTH="200"><% mt('Invoice terms') |h %> </TD> <TD WIDTH="408"> <& /elements/select-terms.html, @@ -673,27 +254,17 @@ function toggle(obj) { % } </TABLE> + <BR> - <% $r %><% mt('required fields') |h %> -% } - -<script type="text/javascript"> - init_payauto_changed(); -</script> - -<%once> - -my $paystate_label = FS::Msgcat::_gettext('paystate'); -$paystate_label = 'Bank state' if $paystate_label =~/^paystate$/; + <FONT CLASS="fsinnerbox-title"><% mt('Payment information') |h %></FONT> + <& cust_payby.html, 'cust_main'=>$cust_main, &> -</%once> <%init> my( $cust_main, %options ) = @_; my @invoicing_list = @{ $options{'invoicing_list'} }; my $payinfo = $options{'payinfo'}; my $conf = new FS::Conf; -my $payby_default = $conf->config('payby-default'); my $money_char = $conf->config('money_char') || '$'; diff --git a/httemplate/edit/cust_main/bottomfixup.js b/httemplate/edit/cust_main/bottomfixup.js index 6a9deb9..97816aa 100644 --- a/httemplate/edit/cust_main/bottomfixup.js +++ b/httemplate/edit/cust_main/bottomfixup.js @@ -5,7 +5,7 @@ my $conf = new FS::Conf; my $company_latitude = $conf->config('company_latitude'); my $company_longitude = $conf->config('company_longitude'); -my @fixups = ('copy_payby_fields', 'standardize_locations'); +my @fixups = ('standardize_locations'); push @fixups, 'confirm_censustract_bill', 'confirm_censustract_ship' if $conf->exists('cust_main-require_censustract'); @@ -51,55 +51,12 @@ function do_submit() { document.CustomerForm.submit(); } -function copy_payby_fields() { - var layervars = new Array( - 'payauto', 'billday', - 'payinfo', 'payinfo1', 'payinfo2', 'payinfo3', 'paytype', - 'payname', 'paystate', 'exp_month', 'exp_year', 'paycvv', - 'paystart_month', 'paystart_year', 'payissue', - 'payip', - 'paid' - ); - - var cf = document.CustomerForm; - var payby = cf.payby.options[cf.payby.selectedIndex].value; - for ( f=0; f < layervars.length; f++ ) { - var field = layervars[f]; - copyelement( cf.elements[payby + '_' + field], - cf.elements[field] - ); - } - submit_continue(); -} - <& /elements/standardize_locations.js, 'callback' => 'submit_continue();', 'billship' => 1, 'with_census' => 1, # no with_firm, apparently &> -function copyelement(from, to) { - if ( from == undefined ) { - to.value = ''; - } else if ( from.type == 'select-one' ) { - to.value = from.options[from.selectedIndex].value; - //alert(from + " (" + from.type + "): " + to.name + " => (" + from.selectedIndex + ") " + to.value); - } else if ( from.type == 'checkbox' ) { - if ( from.checked ) { - to.value = from.value; - } else { - to.value = ''; - } - } else { - if ( from.value == undefined ) { - to.value = ''; - } else { - to.value = from.value; - } - } - //alert(from + " (" + from.type + "): " + to.name + " => " + to.value); -} - % # the value in pre+'censustract' is the confirmed censustract (either from % # the previous saved record, or from address standardization (if the backend % # supports it), or from an aborted previous submit. only need to reconfirm diff --git a/httemplate/edit/cust_main/contact.html b/httemplate/edit/cust_main/contact.html deleted file mode 100644 index c2ebb09..0000000 --- a/httemplate/edit/cust_main/contact.html +++ /dev/null @@ -1,171 +0,0 @@ -<TABLE CLASS="fsinnerbox"> - -<TR> - <TH ALIGN="right"><%$r%><% mt('Contact name (last, first)') |h %></TH> - <TD COLSPAN=7> - <INPUT TYPE="text" NAME="<%$pre%>last" VALUE="<% $cust_main->get($pre.'last') |h %>" onChange="<% $onchange %>" <%$disabled%> <%$style%>> , - <INPUT TYPE="text" NAME="<%$pre%>first" VALUE="<% $cust_main->get($pre.'first') |h %>" onChange="<% $onchange %>" <%$disabled%> <%$style%>> - </TD> -% if ( $conf->exists('show_ss') && !$pre ) { - - <TD ALIGN="right"><% mt('SS#') |h %></TD> - <TD><INPUT TYPE="text" NAME="ss" VALUE="<% $opt{ss} %>" SIZE=11></TD> -% } elsif ( !$pre ) { - - <TD><INPUT TYPE="hidden" NAME="ss" VALUE="<% $opt{ss} %>"></TD> -% } -</TR> - -% if ( $conf->exists('cust-email-high-visibility') && !$pre ) { - <TR> - <TD ALIGN="right" WIDTH="200"> - <% $conf->exists('cust_main-require_invoicing_list_email', $agentnum) - ? $r : '' %>Email address(es) - </TD> - <TD bgcolor="#FFFF00"> - <INPUT TYPE="text" NAME="invoicing_list" VALUE="<% join(', ', grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list ) %>"> - </TD> - </TR> -% } - -% unless ( $conf->exists('cust-edit-alt-field-order') ) { #standard order - - <& company &> - <& location &> - <& phones &> - <& fax &> - -% } else { #alternate field order - - <& phones &> - <& location &> - <& fax &> - <& company &> - -% } - -% if ( $conf->exists('show_stateid') && !$pre ) { - -<TR> - <TD ALIGN="right"><% $stateid_label %></TD> - <TD><INPUT TYPE="text" NAME="stateid" VALUE="<% $opt{stateid} %>" SIZE=12 onChange="<% $onchange %>" <%$disabled%> <%$style%>></TD> - <TD ALIGN="right"><% $stateid_state_label %></TD> - <TD><& /elements/select-state.html, - 'state' => $cust_main->stateid_state, - 'country' => $cust_main->country, - 'prefix' => 'stateid_', - 'onchange' => $onchange, - 'disabled' => $disabled, - 'style' => \@style, - &> - </TD> -</TR> -% } elsif ( !$pre ) { - - <TD><INPUT TYPE="hidden" NAME="stateid" VALUE="<% $opt{stateid} %>"></TD> - <TD><INPUT TYPE="hidden" NAME="stateid_state" VALUE="<% $cust_main->stateid_state %>"></TD> -% } - -</TABLE> -<%$r%><% mt('required fields') |h %><BR> - -<%def company> -% my $display = ($cust_main->residential_commercial eq 'Commercial') -% ? '' : 'none'; - <TR ID="<%$pre%>company_row" STYLE="display:<%$display%>"> - <TD ALIGN="right"><% mt('Company') |h %></TD> - <TD COLSPAN=7> - <INPUT TYPE="text" NAME="<%$pre%>company" ID="<%$pre%>company" VALUE="<% $cust_main->get($pre.'company') |h %>" SIZE=60 onChange="<% $onchange %>" <%$disabled%> <%$style%>> - </TD> - </TR> -</%def> - -<%def location> - <& /elements/location.html, - 'prefix' => $pre, - 'object' => $cust_main, - 'onchange' => $onchange, - 'disabled' => $disabled, - 'style' => \@style, - 'same_checked' => $opt{'same_checked'}, - 'geocode' => $opt{'geocode'}, - 'censustract' => $opt{'censustract'}, - &> -</%def> - -<%def phones> - <& /elements/tr-cust_main-phones.html, - 'prefix' => $pre, - 'cust_main' => $cust_main, - 'onchange' => $onchange, - 'disabled' => $disabled, - 'style' => $style, - &> -</%def> - -<%def fax> - <TR> - <TD ALIGN="right"><% mt('Fax') |h %></TD> - <TD COLSPAN=5> - <INPUT TYPE="text" NAME="<%$pre%>fax" VALUE="<% $cust_main->get($pre.'fax') %>" SIZE=12 onChange="<% $onchange %>" <%$disabled%> <%$style%>> - </TD> - </TR> -</%def> - -<%once> - -my $r = qq!<font color="#ff0000">*</font> !; - -</%once> -<%shared> - -my( %opt, $cust_main, $pre, $onchange, $disabled, @style, $style ); - -</%shared> -<%init> - -%opt = @_; -$cust_main = $opt{'cust_main'}; -$pre = $opt{'pre'}; -$onchange = $opt{'onchange'}; -$disabled = $opt{'disabled'}; -@style = ( $opt{'style'} ? @{ $opt{'style'} } : () ); - -$style = scalar(@style) ? 'STYLE="'. join(';', @style). '"' : ''; - -my $conf = new FS::Conf; - -foreach (qw(ss stateid)) { - $opt{$_} = $cust_main->masked($_) unless exists $opt{$_}; -} - -#false laziness with ship state -my $countrydefault = $conf->config('countrydefault') || 'US'; -$cust_main->set($pre.'country', $countrydefault ) - unless $cust_main->get($pre.'country'); - -my $statedefault = $conf->config('statedefault') - || ($countrydefault eq 'US' ? 'CA' : ''); -$cust_main->set($pre.'state', $statedefault ) - unless $cust_main->get($pre.'state') - || $cust_main->get($pre.'country') ne $countrydefault; - -$cust_main->set('stateid_state', $cust_main->state ) - unless $pre || $cust_main->get('stateid_state'); - -$opt{geocode} ||= $cust_main->get('geocode'); - -$opt{censustract} ||= $cust_main->censustract; - -my $stateid_label = FS::Msgcat::_gettext('stateid') =~ /^(stateid)?$/ - ? 'Driver’s License' - : FS::Msgcat::_gettext('stateid') || 'Driver’s License'; -my $stateid_state_label = FS::Msgcat::_gettext('stateid_state') =~ /^(stateid_state)?$/ - ? 'Driver’s License State' - : FS::Msgcat::_gettext('stateid_state') || 'Driver’s License State'; - -my @invoicing_list = $cust_main->invoicing_list; - -my $agentnum = $cust_main->agentnum if $cust_main->custnum; - -</%init> diff --git a/httemplate/edit/cust_main/contacts_new.html b/httemplate/edit/cust_main/contacts_new.html index 0ab02b4..9ccb45f 100644 --- a/httemplate/edit/cust_main/contacts_new.html +++ b/httemplate/edit/cust_main/contacts_new.html @@ -1,10 +1,9 @@ <DIV ID="contacts_div" STYLE="display:<% $display %>"> -<BR> <FONT CLASS="fsinnerbox-title">Contacts</FONT> <% include('/edit/elements/edit.html', 'embed' => $opt{cust_main}, 'table' => 'cust_main', - 'labels' => { 'contactnum' => 'Contact', + 'labels' => { 'contactnum' => '', #'Contact', #'locationnum' => ' ', }, 'fields' => [ @@ -14,7 +13,7 @@ 'custnum' => $opt{cust_main}->custnum, 'm2m_method' => 'cust_contact', 'm2m_dstcol' => 'contactnum', - 'm2_label' => 'Contact', + 'm2_label' => ' ', #'Contact', 'm2_error_callback' => $m2_error_callback, }, ], diff --git a/httemplate/edit/cust_main/cust_payby.html b/httemplate/edit/cust_main/cust_payby.html new file mode 100644 index 0000000..cf0ada9 --- /dev/null +++ b/httemplate/edit/cust_main/cust_payby.html @@ -0,0 +1,56 @@ +<% include('/edit/elements/edit.html', + 'embed' => $opt{cust_main}, + 'tablenum' => 1, + 'table' => 'cust_main', + 'labels' => { 'custpaybynum' => '', + #'locationnum' => ' ', + }, + 'fields' => [ + { 'field' => 'custpaybynum', + 'type' => 'cust_payby', + 'colspan' => 6, + #'custnum' => $opt{cust_main}->custnum, + 'm2m_method' => 'cust_payby', + 'm2m_dstcol' => 'custpaybynum', + 'm2_label' => ' ', + 'm2_error_callback' => $m2_error_callback, + }, + ], + 'agent_virt' => 1, + ) +%> +</DIV> +<%init> + +my %opt = @_; + +my $m2_error_callback = sub { + my($cgi, $object) = @_; + + #process_o2m fields in process/cust_main-cust_payby.html + my $fields = FS::cust_payby->cgi_cust_payby_fields; + my @gfields = ( '', map "_$_", grep $_ !~ /^(payby|paydate_)/, @$fields ); + + map { + if ( /^custpaybynum(\d+)$/ ) { + my $num = $1; + if ( grep $cgi->param("custpaybynum$num$_"), @gfields ) { + my %hash = ( + 'custpaybynum' => scalar($cgi->param("custpaybynum$num")), + map { $_ => scalar($cgi->param("custpaybynum${num}_$_")) } + @$fields, + ); + FS::cust_payby::cgi_hash_callback( \%hash ); + FS::cust_payby->new( \%hash ); + } else { + (); + } + } else { + (); + } + } + $cgi->param; +}; + +</%init> + diff --git a/httemplate/edit/elements/edit.html b/httemplate/edit/elements/edit.html index 4d5beee..5a7920b 100644 --- a/httemplate/edit/elements/edit.html +++ b/httemplate/edit/elements/edit.html @@ -118,6 +118,8 @@ Example: # display, no <FORM>, no hidden fields for table name or primary key, no # display of primary key, no submit button, no html_foot, no footer) 'embed' => $object, #need to pass the object + 'tablenum' => 4, #need to specify a table number when using multiple + #embedded edits on a page (and m2 stuff) #don't show the primary key label and value 'no_pkey_display' => 1, @@ -256,7 +258,7 @@ Example: % } -% my $tablenum = 0; +% my $tablenum = $opt{'tablenum'} || 0; <TABLE ID="TableNumber<% $tablenum++ %>" BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0> % my $g_row = 0; diff --git a/httemplate/edit/process/cust_main.cgi b/httemplate/edit/process/cust_main.cgi index 82ec50c..52a2608 100755 --- a/httemplate/edit/process/cust_main.cgi +++ b/httemplate/edit/process/cust_main.cgi @@ -29,29 +29,6 @@ $cgi->param('tax','') unless defined $cgi->param('tax'); $cgi->param('refnum', (split(/:/, ($cgi->param('refnum'))[0] ))[0] ); -my $payby = $cgi->param('payby'); - -my %noauto = ( - 'CARD' => 'DCRD', - 'CHEK' => 'DCHK', -); -$payby = $noauto{$payby} - if ! $cgi->param('payauto') && exists $noauto{$payby}; - -$cgi->param('payby', $payby); - -if ( $payby ) { - if ( $payby eq 'CHEK' || $payby eq 'DCHK' ) { - my $payinfo = $cgi->param('payinfo1'). '@'; - $payinfo .= $cgi->param('payinfo3').'.' - if $conf->config('echeck-country') eq 'CA'; - $payinfo .= $cgi->param('payinfo2'); - $cgi->param('payinfo',$payinfo); - } - $cgi->param('paydate', - $cgi->param( 'exp_month' ). '-'. $cgi->param( 'exp_year' ) ); -} - my @invoicing_list = split( /\s*\,\s*/, $cgi->param('invoicing_list') ); push @invoicing_list, 'POST' if $cgi->param('invoicing_list_POST'); push @invoicing_list, 'FAX' if $cgi->param('invoicing_list_FAX'); @@ -177,6 +154,9 @@ if ( $curuser->access_right('Edit customer tax exemptions') ) { }; } +$options{'contact_params'} = scalar($cgi->Vars); +$options{'cust_payby_params'} = scalar($cgi->Vars); + #perhaps this stuff should go to cust_main.pm if ( $new->custnum eq '' or $duplicate_of ) { @@ -304,34 +284,12 @@ if ( $new->custnum eq '' or $duplicate_of ) { my $old = qsearchs( 'cust_main', { 'custnum' => $new->custnum } ); $error ||= "Old record not found!" unless $old; - if ( length($old->paycvv) && $new->paycvv =~ /^\s*\*+\s*$/ ) { - $new->paycvv($old->paycvv); - } if ($new->ss =~ /xx/) { $new->ss($old->ss); } if ($new->stateid =~ /^xxx/) { $new->stateid($old->stateid); } - if ( $new->payby =~ /^(CARD|DCRD)$/ - && ( $new->payinfo =~ /xx/ - || $new->payinfo =~ /^\s*N\/A\s+\(tokenized\)\s*$/ - ) - ) - { - $new->payinfo($old->payinfo); - - } elsif ( $new->payby =~ /^(CHEK|DCHK)$/ && $new->payinfo =~ /xx/ ) { - #fix for #3085 "edit of customer's routing code only surprisingly causes - #nothing to happen... - # this probably won't do the right thing when we don't have the - # public key (can't actually get the real $old->payinfo) - my($new_account, $new_aba) = split('@', $new->payinfo); - my($old_account, $old_aba) = split('@', $old->payinfo); - $new_account = $old_account if $new_account =~ /xx/; - $new_aba = $old_aba if $new_aba =~ /xx/; - $new->payinfo($new_account.'@'.$new_aba); - } if ( ! $conf->exists('cust_main-edit_signupdate') or ! $new->signupdate ) { @@ -353,13 +311,4 @@ if ( $new->custnum eq '' or $duplicate_of ) { } -unless ( $error ) { #XXX i should be transactional... all in the insert - # or replace call - - $error = $new->process_o2m( 'table' => 'contact', - 'fields' => FS::contact->cgi_contact_fields, - 'params' => scalar($cgi->Vars), - ); -} - </%init> diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html index 5f6921c..7d5d4f3 100644 --- a/httemplate/elements/menu.html +++ b/httemplate/elements/menu.html @@ -127,6 +127,7 @@ $report_customers{'Advanced customer reports'} = [ $fsurl. 'search/report_cust_m if ( $curuser->access_right('List contacts') ) { $report_customers{'separator'} = ''; $report_customers{'Customer contacts'} = [ $fsurl. 'search/report_contact.html?link=cust_main' ]; + $report_customers{'Customer stored payment information'} = [ $fsurl. 'search/report_cust_payby.html' ]; } tie my %report_invoices_open, 'Tie::IxHash', diff --git a/httemplate/elements/tr-coords.html b/httemplate/elements/tr-coords.html index 3248dc2..5ac5ed4 100644 --- a/httemplate/elements/tr-coords.html +++ b/httemplate/elements/tr-coords.html @@ -1,6 +1,6 @@ <TR> <TD ALIGN="right"><% mt('Latitude') |h %></TD> - <TD COLSPAN=5> + <TD COLSPAN=7> <FONT STYLE="background-color: #ffffff; border: 1px solid #ffffff"><% $latitude %></FONT> <% mt('Longitude') |h %> <FONT STYLE="background-color: #ffffff; border: 1px solid #ffffff"><% $longitude %></FONT> diff --git a/httemplate/search/cust_main.html b/httemplate/search/cust_main.html index 503e782..672c201 100755 --- a/httemplate/search/cust_main.html +++ b/httemplate/search/cust_main.html @@ -42,7 +42,7 @@ my %search_hash = (); #scalars my @scalars = qw ( agentnum salesnum status address city county state zip country - paydate_year paydate_month invoice_terms + invoice_terms no_censustract with_geocode with_email tax no_tax POST no_POST custbatch usernum cancelled_pkgs @@ -58,7 +58,7 @@ for my $param ( @scalars ) { } #lists -for my $param (qw( classnum refnum payby tagnum pkg_classnum )) { +for my $param (qw( classnum refnum tagnum pkg_classnum )) { $search_hash{$param} = [ $cgi->param($param) ]; } diff --git a/httemplate/search/cust_payby.html b/httemplate/search/cust_payby.html new file mode 100644 index 0000000..140391b --- /dev/null +++ b/httemplate/search/cust_payby.html @@ -0,0 +1,94 @@ +<& elements/search.html, + 'title' => emt('Customer stored payment information results'), + 'menubar' => $menubar, + 'name' => emt('cards or bank accounts'), #?? + 'query' => $sql_query, + 'count_query' => $count_query, + 'header' => [ @headers, + FS::UI::Web::cust_header( + $cgi->param('cust_fields') + ), + ], + 'fields' => [ + @fields, + \&FS::UI::Web::cust_fields, + ], + 'color' => [ + ( map '', @fields ), + FS::UI::Web::cust_colors(), + ], + 'style' => [ + ( map '', @fields ), + FS::UI::Web::cust_styles(), + ], + 'align' => [ + ( map '', @fields ), + FS::UI::Web::cust_aligns(), + ], + 'links' => [ + ( map '', @fields ), + ( map { $_ ne 'Cust. Status' ? $link : '' } + FS::UI::Web::cust_header( + $cgi->param('cust_fields') + ) + ), + ], +&> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Advanced customer search'); + +my %search_hash = (); + +my @scalars = qw ( + paydate_year paydate_month +); + +for my $param ( @scalars ) { + $search_hash{$param} = scalar( $cgi->param($param) ) + if length($cgi->param($param)); +} + +#lists +for my $param (qw( payby )) { + $search_hash{$param} = [ $cgi->param($param) ]; +} + +### +# etc +### + +my $sql_query = FS::cust_payby->search_sql(\%search_hash); +my $count_query = delete($sql_query->{'count_query'}); + +my @headers = ( 'Payment information', + ); + +my @fields = ( sub { my $cust_payby = shift; + FS::payby->shortname( $cust_payby->payby ). ' '. + $cust_payby->paymask; + } + ); + +my $link = [ "${p}view/cust_main.cgi?", 'custnum' ]; + +### +# email links +### + +my $menubar = []; + +#XXX TODO +#if ( $FS::CurrentUser::CurrentUser->access_right('Bulk send customer notices') ) { +# +# my $uri = new URI; +# $uri->query_form( \%search_hash ); +# my $query = $uri->query; +# +# push @$menubar, emt('Email a notice to these customers') => +# "${p}misc/email-customers.html?table=cust_main&$query", +# +#} + +</%init> diff --git a/httemplate/search/report_cust_main.html b/httemplate/search/report_cust_main.html index cacb7de..ba7c99a 100755 --- a/httemplate/search/report_cust_main.html +++ b/httemplate/search/report_cust_main.html @@ -194,43 +194,6 @@ <TH CLASS="background" COLSPAN=2 ALIGN="left"><FONT SIZE="+1"><% mt('Billing search options') |h %></FONT></TH> </TR> - <& /elements/tr-select-payby.html, - 'payby_type' => 'cust', - 'multiple' => 1, - 'all_selected' => 1, - &> - - <TR> - <TD ALIGN="right"><% mt('Payment expiration before') |h %></TD> - <TD> - <SELECT NAME="paydate_month" DISABLED> -% foreach my $month ( 1 .. 12 ) { - <OPTION VALUE="<% $month %>"><% $month %></OPTION> -% } - </SELECT> - / - <SELECT NAME="paydate_year" onChange="paydate_year_changed(this);"> - <OPTION VALUE=""></OPTION> -% my $lastyear = (localtime(time))[5] + 1899; -% foreach my $year ( $lastyear .. $lastyear+12 ) { - <OPTION VALUE="<% $year %>"><% $year %></OPTION> -% } - </SELECT> - </TD> - </TR> - - <SCRIPT TYPE="text/javascript"> - function paydate_year_changed(what) { - var value = what.options[what.selectedIndex].value; - var month_select = what.form.paydate_month; - if ( value == '' ) { - month_select.disabled = true; - } else { - month_select.disabled = false; - } - } - </SCRIPT> - % my @exempt_groups = grep /\S/, $conf->config('tax-cust_exempt-groups'); % unless ( @exempt_groups ) { diff --git a/httemplate/search/report_cust_payby.html b/httemplate/search/report_cust_payby.html new file mode 100644 index 0000000..81a8270 --- /dev/null +++ b/httemplate/search/report_cust_payby.html @@ -0,0 +1,57 @@ +<& /elements/header.html, mt('Customer stored payment infomation report') &> + +<FORM ACTION="cust_payby.html" METHOD="GET"> + + <TABLE BGCOLOR="#cccccc" CELLSPACING=0> + + <& /elements/tr-select-payby.html, + 'payby_type' => 'cust', + 'multiple' => 1, + 'all_selected' => 1, + &> + + <TR> + <TD ALIGN="right"><% mt('Payment expiration before') |h %></TD> + <TD> + <SELECT NAME="paydate_month" DISABLED> +% foreach my $month ( 1 .. 12 ) { + <OPTION VALUE="<% $month %>"><% $month %></OPTION> +% } + </SELECT> + / + <SELECT NAME="paydate_year" onChange="paydate_year_changed(this);"> + <OPTION VALUE=""></OPTION> +% my $lastyear = (localtime(time))[5] + 1899; +% foreach my $year ( $lastyear .. $lastyear+12 ) { + <OPTION VALUE="<% $year %>"><% $year %></OPTION> +% } + </SELECT> + </TD> + </TR> + + <SCRIPT TYPE="text/javascript"> + function paydate_year_changed(what) { + var value = what.options[what.selectedIndex].value; + var month_select = what.form.paydate_month; + if ( value == '' ) { + month_select.disabled = true; + } else { + month_select.disabled = false; + } + } + </SCRIPT> + + </TABLE> + +<BR> +<INPUT TYPE="submit" VALUE="<% mt('Get Report') |h %>"> + +</FORM> + +<& /elements/footer.html &> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Advanced customer search'); + +</%init> diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi index d18c7f7..081b96b 100755 --- a/httemplate/view/cust_main.cgi +++ b/httemplate/view/cust_main.cgi @@ -169,14 +169,12 @@ function areyousure(href, message) { <TABLE BORDER=0> <TR> <TD VALIGN="top"> - <& cust_main/contacts.html, $cust_main &> + <& cust_main/misc.html, $cust_main &> + <BR><& cust_main/contacts.html, $cust_main &> </TD> <TD VALIGN="top" STYLE="padding-left: 54px"> - <& cust_main/misc.html, $cust_main &> -% if ( $conf->config('payby-default') ne 'HIDE' ) { - <BR><& cust_main/billing.html, $cust_main &> -% } - + <& cust_main/billing.html, $cust_main &> + <BR><& cust_main/cust_payby.html, $cust_main &> </TD> </TR> <TR> @@ -281,9 +279,7 @@ function areyousure(href, message) { % if ( $view eq 'payment_history' || $view eq 'jumbo' ) { -% if ( $conf->config('payby-default') ne 'HIDE' ) { - <& cust_main/payment_history.html, $cust_main &> -% } +<& cust_main/payment_history.html, $cust_main &> % } @@ -352,8 +348,7 @@ if ( $conf->config('ticket_system') ) { } $views{emt('Quotations')} = 'quotations'; $views{emt('Packages')} = 'packages'; -$views{emt('Payment History')} = 'payment_history' - unless $conf->config('payby-default' eq 'HIDE'); +$views{emt('Payment History')} = 'payment_history'; $views{emt('Change History')} = 'change_history' if $curuser->access_right('View customer history'); $views{$conf->config('cust_main-custom_title') || emt('Custom')} = 'custom' diff --git a/httemplate/view/cust_main/billing.html b/httemplate/view/cust_main/billing.html index 64ec591..f1125c0 100644 --- a/httemplate/view/cust_main/billing.html +++ b/httemplate/view/cust_main/billing.html @@ -32,165 +32,25 @@ % } % if ( $conf->exists('cust_main-select-billday') -% && ($cust_main->payby eq 'CARD' || $cust_main->payby eq 'CHEK') ) { -<TR> - <TD ALIGN="right"><% mt('Billing day of month') |h %></TD> - <TD BGCOLOR="#ffffff"><% $cust_main->billday %> - </TD> -</TR> -% } - -<TR> - <TD ALIGN="right"><% mt('Billing type') |h %></TD> - <TD BGCOLOR="#ffffff"> -% if ( $cust_main->payby eq 'CARD' || $cust_main->payby eq 'DCRD' ) { - -% my $autodemand = $cust_main->payby eq 'CARD' ? 'automatic' : 'on-demand'; - <% mt("Credit card ([_1])",$autodemand) |h %> - </TD> -</TR> -<TR> - <TD ALIGN="right"><% mt('Card number') |h %></TD> - <TD BGCOLOR="#ffffff"><% $cust_main->paymask %></TD> -</TR> -% -%#false laziness w/elements/select-month_year.html & edit/cust_main/billing.html -%my( $mon, $year ); -%my $date = $cust_main->paydate || '12-2037'; -%if ( $date =~ /^(\d{4})-(\d{1,2})-\d{1,2}$/ ) { #PostgreSQL date format -% ( $mon, $year ) = ( $2, $1 ); -%} elsif ( $date =~ /^(\d{1,2})-(\d{1,2}-)?(\d{4}$)/ ) { -% ( $mon, $year ) = ( $1, $3 ); -%} else { -% warn "unrecognized expiration date format: $date"; -% ( $mon, $year ) = ( '', '' ); -%} -% - -<TR> - <TD ALIGN="right"><% mt('Expiration') |h %></TD> - <TD BGCOLOR="#ffffff"><% "$mon/$year" %></TD> -</TR> -% if ( $cust_main->paystart_month ) { - - <TR> - <TD ALIGN="right"><% mt('Start date') |h %></TD> - <TD BGCOLOR="#ffffff"><% $cust_main->paystart_month. '/'. $cust_main->paystart_year %> - </TR> -% } elsif ( $cust_main->payissue ) { - - <TR> - <TD ALIGN="right"><% mt('Issue #') |h %></TD> - <TD BGCOLOR="#ffffff"><% $cust_main->payissue %> - </TR> -% } - - -<TR> - <TD ALIGN="right"><% mt('Name on card') |h %></TD> - <TD BGCOLOR="#ffffff"><% $cust_main->payname %></TD> -</TR> -% } elsif ( $cust_main->payby eq 'CHEK' || $cust_main->payby eq 'DCHK') { -% my( $account, $aba ) = split('@', $cust_main->paymask ); -% my $branch = ''; -% ($branch,$aba) = split('\.',$aba) if $conf->config('echeck-country') eq 'CA'; - - -% my $autodemand = $cust_main->payby eq 'CHEK' ? 'automatic' : 'on-demand'; - <% mt("Electronic check ([_1])",$autodemand) |h %> - </TD> -</TR> - -% #false laziness w/edit/cust_main/billing.html and misc/payment.cgi -% my $routing_label = $conf->config('echeck-country') eq 'US' -% ? 'ABA/Routing number' -% : 'Routing number'; - -<TR> - <TD ALIGN="right"><% mt($routing_label) |h %></TD> - <TD BGCOLOR="#ffffff"><% $aba %></TD> -</TR> - -% if ( $conf->config('echeck-country') eq 'CA' ) { -<TR> - <TD ALIGN="right"><% mt('Branch number') |h %></TD> - <TD BGCOLOR="#ffffff"><% $branch %></TD> -<TR> -% } - - <TD ALIGN="right"><% mt('Account number') |h %></TD> - <TD BGCOLOR="#ffffff"><% $account %></TD> -</TR> -<TR> - <TD ALIGN="right"><% mt('Account type') |h %></TD> - <TD BGCOLOR="#ffffff"><% $cust_main->paytype %></TD> -</TR> -<TR> - <TD ALIGN="right"><% mt('Bank name') |h %></TD> - <TD BGCOLOR="#ffffff"><% $cust_main->payname %></TD> -</TR> -% if ( $conf->exists('show_bankstate') ) { -<TR> - <TD ALIGN="right"><% $paystate_label %></TD> - <TD BGCOLOR="#ffffff"><% $cust_main->paystate || ' ' %></TD> -</TR> +% && qsearch({ 'table' => 'cust_payby', +% 'hashref' => { 'custnum' => $cust_main->custnum, }, +% 'extra_sql' => "AND payby IN ( 'CARD', 'CHEK' )", +% 'order_by' => 'LIMIT 1', +% }) +% ) +% { + <TR> + <TD ALIGN="right"><% mt('Payment day of month') |h %></TD> + <TD BGCOLOR="#ffffff"><% $cust_main->billday %> + </TD> + </TR> % } -% } elsif ( $cust_main->payby eq 'LECB' ) { -% $cust_main->payinfo =~ /^(\d{3})(\d{3})(\d{4})$/; -% my $payinfo = "$1-$2-$3"; - - <% mt('Phone bill billing') |h %> - </TD> -</TR> -<TR> - <TD ALIGN="right"><% mt('Phone number') |h %></TD> - <TD BGCOLOR="#ffffff"><% $payinfo %></TD> -</TR> -% } elsif ( $cust_main->payby eq 'BILL' ) { - - <% mt('Billing') |h %> - </TD> -</TR> -% if ( $cust_main->payinfo ) { - -<TR> - <TD ALIGN="right"><% mt('P.O.') |h %></TD> - <TD BGCOLOR="#ffffff"><% $cust_main->payinfo %></TD> -</TR> -% } - -<TR> - <TD ALIGN="right"><% mt('Attention') |h %></TD> - <TD BGCOLOR="#ffffff"><% $cust_main->payname |h %></TD> -</TR> -% } elsif ( $cust_main->payby eq 'COMP' ) { - - <% mt('Complimentary') |h %> - </TD> -</TR> -<TR> - <TD ALIGN="right"><% mt('Authorized by') |h %></TD> - <TD BGCOLOR="#ffffff"><% $cust_main->payinfo %></TD> -</TR> -% -%#false laziness w/above etc. -%my( $mon, $year ); -%my $date = $cust_main->paydate || '12-2037'; -%if ( $date =~ /^(\d{4})-(\d{1,2})-\d{1,2}$/ ) { #PostgreSQL date format -% ( $mon, $year ) = ( $2, $1 ); -%} elsif ( $date =~ /^(\d{1,2})-(\d{1,2}-)?(\d{4}$)/ ) { -% ( $mon, $year ) = ( $1, $3 ); -%} else { -% warn "unrecognized expiration date format: $date"; -% ( $mon, $year ) = ( '', '' ); -%} -% - -<TR> - <TD ALIGN="right"><% mt('Expiration') |h %></TD> - <TD BGCOLOR="#ffffff"><% "$mon/$year" %></TD> -</TR> +% if ( $cust_main->po_number ) { + <TR> + <TD ALIGN="right"><% mt('Purchase Order #') |h %></TD> + <TD BGCOLOR="#ffffff"><% $cust_main->po_number %></TD> + </TR> % } % my $yes = emt('yes'); @@ -230,13 +90,13 @@ <TR> <TD ALIGN="right"><% mt('Postal mail invoices') |h %></TD> <TD BGCOLOR="#ffffff"> - <% ( grep { $_ eq 'POST' } @invoicing_list ) ? $yes : $no %> - </TD> -</TR> -<TR> - <TD ALIGN="right"><% mt('Fax invoices') |h %></TD> - <TD BGCOLOR="#ffffff"> - <% ( grep { $_ eq 'FAX' } @invoicing_list ) ? $yes : $no %> + <% ( grep { $_ eq 'POST' } @invoicing_list ) + ? $yes. ( $cust_main->invoice_attn + ? ', attn: '. $cust_main->invoice_attn + : '' + ) + : $no + %> </TD> </TR> <TR> @@ -336,12 +196,6 @@ </TABLE> -<%once> - -my $paystate_label = FS::Msgcat::_gettext('paystate'); -$paystate_label = 'Bank state' if $paystate_label =~/^paystate$/; - -</%once> <%init> my( $cust_main ) = @_; diff --git a/httemplate/view/cust_main/cust_payby.html b/httemplate/view/cust_main/cust_payby.html new file mode 100644 index 0000000..3ebb055 --- /dev/null +++ b/httemplate/view/cust_main/cust_payby.html @@ -0,0 +1,133 @@ +% if ( @cust_payby ) { + + <FONT CLASS="fsinnerbox-title"><% mt('Payment information') |h %></FONT> + <TABLE CLASS="fsinnerbox"> + +% my $num = 0; +% foreach my $cust_payby ( @cust_payby ) { + +% #one line per piece of info? maybe, but just getting something working +% # for now + +% if ( $cust_payby->payby eq 'CARD' || $cust_payby->payby eq 'DCRD' ) { + +% my $auto = $cust_payby->payby eq 'CARD' ? 'automatic' : 'on-demand'; + <TR> + <TD COLSPAN=2 ALIGN="center" BGCOLOR="#ffffff"> + <% mt("Credit card ([_1])",$auto) |h %> + </TD> + </TR> + <TR> + <TD ALIGN="right"><% mt('Card number') |h %></TD> + <TD BGCOLOR="#ffffff"><% $cust_payby->paymask %></TD> + </TR> + +% my( $mon, $year ) = $cust_payby->paydate_mon_year; + <TR> + <TD ALIGN="right"><% mt('Expiration') |h %></TD> + <TD BGCOLOR="#ffffff"><% "$mon/$year" %></TD> + </TR> + +% if ( $cust_payby->paystart_month ) { + <TR> + <TD ALIGN="right"><% mt('Start date') |h %></TD> + <TD BGCOLOR="#ffffff"><% $cust_payby->paystart_month. '/'. $cust_payby->paystart_year %> + </TR> +% } elsif ( $cust_payby->payissue ) { + <TR> + <TD ALIGN="right"><% mt('Issue #') |h %></TD> + <TD BGCOLOR="#ffffff"><% $cust_payby->payissue %> + </TR> +% } + + <TR> + <TD ALIGN="right"><% mt('Name on card') |h %></TD> + <TD BGCOLOR="#ffffff"><% $cust_payby->payname %></TD> + </TR> + +% } elsif ( $cust_payby->payby eq 'CHEK' || $cust_payby->payby eq 'DCHK') { + +% my $auto = $cust_payby->payby eq 'CHEK' ? 'automatic' : 'on-demand'; +% +% my( $account, $aba ) = split('@', $cust_payby->paymask ); +% my $branch = ''; +% ($branch,$aba) = split('\.',$aba) +% if $conf->config('echeck-country') eq 'CA'; + + <TR> + <TD COLSPAN=2 ALIGN="center" BGCOLOR="#ffffff"> + <% mt("Electronic check ([_1])",$auto) |h %> + </TD> + </TR> + +% #false laziness w/edit/cust_main/billing.html and misc/payment.cgi +% my $routing_label = $conf->config('echeck-country') eq 'US' +% ? 'ABA/Routing number' +% : 'Routing number'; + <TR> + <TD ALIGN="right"><% mt($routing_label) |h %></TD> + <TD BGCOLOR="#ffffff"><% $aba %></TD> + </TR> + +% if ( $conf->config('echeck-country') eq 'CA' ) { + <TR> + <TD ALIGN="right"><% mt('Branch number') |h %></TD> + <TD BGCOLOR="#ffffff"><% $branch %></TD> + </TR> +% } + + <TR> + <TD ALIGN="right"><% mt('Account number') |h %></TD> + <TD BGCOLOR="#ffffff"><% $account %></TD> + </TR> + <TR> + <TD ALIGN="right"><% mt('Account type') |h %></TD> + <TD BGCOLOR="#ffffff"><% $cust_payby->paytype %></TD> + </TR> + <TR> + <TD ALIGN="right"><% mt('Bank name') |h %></TD> + <TD BGCOLOR="#ffffff"><% $cust_payby->payname %></TD> + </TR> + +% if ( $conf->exists('show_bankstate') ) { + <TR> + <TD ALIGN="right"><% $paystate_label %></TD> + <TD BGCOLOR="#ffffff"><% $cust_payby->paystate || ' ' %></TD> + </TR> +% } + +% } else { + <TR> + <TD COLSPAN="2"><FONT COLOR="#FF0000"> + Unknown cust_pay.payby <% $cust_payby->payby %> + </FONT></TD> + </TR> +% } + +% unless ( $num++ == $#cust_payby ) { + <TR> + <TD COLSPAN="2"></TD> + </TR> + <TR> + <TD COLSPAN="2" STYLE="border-top: 1px solid black; padding:2px"></TD> + </TR> +% } + +% } + + </TABLE> + +% } +<%once> + +my $paystate_label = FS::Msgcat::_gettext('paystate'); +$paystate_label = 'Bank state' if $paystate_label =~/^paystate$/; + +</%once> +<%init> + +my( $cust_main ) = @_; +my $conf = new FS::Conf; +my @cust_payby = $cust_main->cust_payby; + +</%init> diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index 9a2332b..9098511 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -92,9 +92,7 @@ if ( el ) el.scrollIntoView(true); <& /elements/order_pkg_link.html, 'cust_main'=>$cust_main &> % } -% if ( $curuser->access_right('One-time charge') -% && $conf->config('payby-default') ne 'HIDE' -% ) { +% if ( $curuser->access_right('One-time charge') ) { <% $s++ ? ' | ' : '' %> <& /elements/one_time_charge_link.html, 'custnum'=>$cust_main->custnum &> % } |